Assisting users in attracting unicorns
Emits a sound wave that attracts unicorns*. It also features a store with items that can assist in attracting unicorns. However, the core of the website is the User Suggestions app. Users can submit suggestions for new features and bug fixes. They can also comment on, and upvote, other users’ feature suggestions. Admins have a separate page for each suggestion, where they can set the suggestion’s priority level, assigned admin, estimated completion date, and more. The User Suggestions app also features voting cycles. Whichever feature suggestion has the most votes at the end of the voting cycle is declared the winner. The website also has its own currency: Coins. Users can spend coins on submitting, upvoting, and promoting feature suggestions. They can also earn coins for free, e.g. by referring a new user to the website.
*Sound wave is fictitious. So are unicorns (probably).
The website is built using a Django framework. It has four apps: Accounts, Market, User Suggestions, and Unicorn App. Data are saved as objects, and are accessible and editable via a Django admin page. Django handles authentication, including password resets. Voting cycles are determined by the estimated completion date of the previous voting cycle’s winner. When that date hits, a new winner is declared and a new voting cycle begins. This logic, along with most of the website, is written in Python3. The cart and current user’s coins are both saved as context processors. This allows them to be used across templates, including the base template which all other templates inherit from. Whether or not coins are enabled is determined by a Boolean value in the project settings.py file. Python if/else statements determine how the project functions depending on this setting.
The goal of the UX was to make submitting suggestions (and otherwise engaging in the user suggestions process) simple for non-technical users. The GitHub issue tracker for example, is very robust, but is designed for users with significant technical expertise. However, initial user stories suggested that having a bare-bone suggestion form, e.g. a standard textbox, could also be problematic for non-technical users. For these users, it would be easier to submit a screenshot than to try to describe their issue using only text. Therefore, it was decided that CK Editor would be used instead of a textbox. CK Editor allows actions such as uploading images, while still being easy to use. The CK Editor toolbar was customised to only have basic features which almost all computer users would be familiar with. As the default setting for uploading images in CKEditor is quite complex, CK Editor’s Easy Image plugin was also added. As users are more likely to forget their username than their email, a custom user class was created in Django so that users sign in using their email, rather than their username. Another focus of the UX design was making navigating and sorting through suggestions easy. For this, a sorting option was added in the form of a dropdown button menu (so that they fit on all devices). It uses four easy-to-understand sorting options: Newest, Oldest, Most Commented, and Most Popular. User stories also brought up the potential issue of repeat suggestions. This is especially true for bug fixes, where a user could post a bug that has already been posted if they don’t quickly see this other post. To combat this, a search box was added to the suggestions homepage, allowing users to filter suggestions by specific words. This enables users to quickly and easily check if others have posted a similar bug. Users were also given the option to flag suggestions as duplicates
The website needed to be focused on getting users to engage in the user suggestions process, as this is the core of its business model. Therefore, information about user suggestions features heavily on the website’s homepage. For users who aren’t logged in, the homepage sub-header provides information about user suggestions. These users and logged in users both see information about user suggestions at the page footer. The rest of the page content takes up less than 100 viewport width (the exact amount is device-dependent), so this information is always visible to the user. This means that regular users are reminded of it every time they visit the website to emit the unicorn-attracting sound wave. A main reason for adding coins was to encourage users to engage with paid features without initially spending any money, with the aim that this will make them more likely to buy coins once they run out. Users are given coins upon signup. They are also rewarded coins for referring additional users to the site. Furthermore, they have their coins refunded if their feature suggestion wins, along with some extra coins depending on how many votes it got. This should encourage more users to post feature suggestions. One issue raised by user stories was that users could suggest a feature that may be very demanding to implement. Users without sufficient technical knowledge might upvote a feature, not knowing that it could take months to implement, when in reality they would prefer that time is spent on developing several smaller features. To counteract this, the admin’s estimated time to complete a suggestion is displayed on the public page for each suggestion. Another potential issue that was raised in user stories was the advantage in posting your suggestion early. If one suggestion has enough votes that its victory seems inevitable, it discourages other users from either upvoting or submitting other suggestions. This is why voting cycles were implemented. At the start of each voting cycle, all suggestions are equal. Users are given the option of delaying their submission, having it automatically posted when the new voting cycle begins.
- A User Suggestions section where users can suggest, upvote, and comment on bug fixes and feature suggestions
- A voting cycle that when triggered on a specified date, automatically counts votes, determines a winner, edits backend values, posts new data, and sets a new end date
- A store with cart functionality and Stripe integration
- An internal currency that users can earn for free or purchase from the store
- A page for visualizing up-to-date suggestions data
- Ability to flag suggestions and comments and an admin page for dealing with these. The admin page automatically saves the admin who resolved the flag
- Admins can navigate to a specific comment that was flagged
- A userpage for each user that displays their past submissions, votes, and purchase history
- Users can be redirected to buy more coins if they don’t have enough to make a feature suggestion. The minimum number of coins needed to make the purchase is suggested to the user. The user’s current form values are saved in the session cache and restored after the purchase is complete
- A rich-text editor with custom, simplified features for posting comments and suggestions
- Users can pay to promote a feature suggestion, making it appear at the top of the suggestions page. The end date for this promotion is automatically determined and displayed to the user once they have set a start date and number of days for their promotion
- A suggestion’s admin page displays the full URL for the GitHub tree assigned to that suggestion. This automatically updates when an admin changes the ‘GitHub Tree’ field.
- Whatever the users determine!
Unit tests are designed to work on the full Unicorn Attractor project. Some of the unit tests for individual apps require models from other apps to work. Furthermore, all apps require a COINS_ENABLED Boolean value saved in your project settings. Aside from that, the apps are stand-alone, except for where specified below.
Accounts deals with user accounts. This includes creating accounts, authenticating logins, and resetting passwords.
- Required data from other apps
- If COINS_ENABLED is set to false, then the Accounts app is completely stand alone. However, you will need to clear the references to other apps from your imports. If it is set as true, coins are added to a user’s account when they sign up. They can also get extra coins for referring users.
Market includes the store, cart, and coins functionality.
- Required data from other apps
- Many of the models, for example Usercoins, require a user object to connect to via a foreign key. By default, this is imported from the models file in an accounts app
- Connecting a UserCoinsHistory object to a Suggestion object via a foreign key is optional. However, if you don’t intend to import the UserSuggestions app, you should clear the Suggestions object from your imports
User Suggestions includes functionality to post suggestions, comment on these suggestions, flag items, and manage the voting cycle for feature suggestions
- Required data from other apps
- If COINS_ENABLED is set to false, the app does not require any data from the Market app. However, you will need to clear these references from your imports.
- Most models require a user object to connect to via a foreign key. By default, this is imported from the models file in an accounts app
Unicorn App brings together elements from the other three apps. It hosts the homepage and the userpages
- Required data from other apps
- The app is heavily reliant on data from all three other apps
- Django
- The website is a Django project made up of four Django apps
- For handling user accounts and authentication
- To unit test functions
- For modelling data
- To render HTML templates and include Python programming within these templates. This includes inserting python variables into JavaScript scripts
- To trigger functions on GET or POST requests
- For binding functions to URLs
- Python3
- HTML , CSS and SCSS
- To structure and style the web app content
- CSS was written in SCSS and compiled into styles.css
- SQLite
- Used as the application database
- Bootstrap
- Used in conjunction with HTML and CSS to develop the website style
- For implementing the responsive, grid-based website layout
- Bootstrap components used includes cards, tables, and the navbar
- Matplotlib
- For creating the charts on the view data page
- JavaScript and jQuery
- JQuery used to hide or show particular buttons based on a user’s form values
- For filtering suggestions using the searchbox
- To calculate and display additional data to the user depending on their current form values
- For navigating to specific tabs on the suggestions homepage
- Django Countries
- For providing country choices on the delivery address form
- CKEditor
- CKEditor for Django is the rich-text editor used when posting suggestions and comments
- Easy Image plugin used to simplify the process of uploading images to the rich-text editor
- Stripe
- For processing credit card payments
- Stripe JavaScript file manages payment modal and verifying payments, ensuring that sensitive information is never posted on the app’s forms
- Amazon S3
- For storing and reading static files. This includes CSS, JavaScript, Django admin, and CKEditor files
- For storing and reading media files, such as store item images
- Travis CI
- For continuous testing. Build tests are seen at the displayed of this readme
- Heroku
- The live version of the web app is hosted on Heroku
- For saving configuration variables that should remain hidden from GitHub. This includes secret keys for Amazon AWS and Stripe
- Clone or download this GitHub repository using the ‘Clone or Download’ button found on the main GitHub repository page. Alternatively, initialize git and pull the GitHub repository as a remote
- If you wish, you can download just the individual Accounts, User Suggestions, or Market apps for use in your project. Aside from the dependencies on other apps listed in the Project Apps section of this readme, you also need to import many of the configurations found in this project’s settings.py file. The exact configuration depends on which combination of apps you intend to import
- Open the project directory using an integrated development environment (IDE) software application, such as Eclipse or Visual Code Studio
- Ensure you have Python3 and Django installed on your computer (or online IDE). Install it if you do not. How you should do this depends on which operating system you are using. See the Python Documentation for instructions on installing Python3, and the Django documentation for installing Django. The versions of Django and Python currently used in this project are found in the requirements file
- Install any other dependencies listed in the requirements file that are not already installed. It is recommended that you use your IDE to automate this
- Some features require variables that are hidden from the GitHub repository. To use these features, you will need to set these as environmental values. The simplest way to do this is to create an env.py file (that name is listed in the project .gitignore file, and will therefore remain hidden from git). Import os into that file. Then, set the values by entering
os.environ.setdefault("<key>", "<value>”)
. These values will then be imported where needed in the settings.py file. The values that you may need to set are:
- SECRET_KEY
- The project secret key
- AWS_SECRET_ACCESS_KEY and AWS_ACCESS_KEY_ID
- Required to post to the S3 bucket
- These are unique to the S3 bucket used on this project. If you wish to post data to S3 (e.g. new product images or JavaScript files), then you will need to use your own S3 bucket
- You will still be able to read all S3 files without these keys. By clicking the following links, you can also download the project SCSS, CSS and JavaScript files. This will allow you to edit them as you see fit
- EMAIL_ADDRESS and EMAIL_PASSWORD
- A valid Gmail email address and password
- Required for sending password reset and referral emails. The emails will be sent from this account
- STRIPE_PUBLISHABLE and STRIPE_SECRET
- Publishable and secret Stripe keys
- Required for Stripe functionality
- Available when you create a Stripe account
- CLOUDSERVICES_TOKENURL
- For saving images uploaded using CKEditor
- If you wish to save these images, you will also need to change the cloudServices_uploadUrl in the settings.py file so that it links to your account
- CKEditor Cloud Services is only required for the Easy Images plugin. If you remove this plugin, you will not need these values
- Add your computer/IDE as an allowed host in the settings.py file
- You are good to go! Remember to set DEBUG=True when working on the project. You can run the project by entering
python3 ~/workspace/manage.py runserver $<IP>:$<PORT>"
in your terminal
Unit tests are found in the tests directory of each app. Each tests file uses its own mock database, and do not relate to the project database in any way (except for using the same Django models). Because of this, they are appropriate unit tests regardless of what database you are using. They are, however, designed to test individual functions with relation to their functionality for the entire UnicornAttractor website. Therefore, some tests rely on models imported from different apps (e.g. testing User Suggestions relies on the User model from the Accounts app).
To run these unit tests, enter the following into the project terminal:
python3 manage.py test
The app is hosted on Heroku. The code uses the default GitHub master branch. The code found on GitHub is the same code used on the live Heroku app. Changes made to the master branch on GitHub are automatically pushed to Heroku. The only data used in Heroku not visible on GitHub are the secret config variables detailed in the contributing section of this readme, and the static and media files hosted on S3
- The sources for all non-original code are displayed in comments above the relevant code
- PyCharm software was used for separating out the python code into separate files. Therefore, much of the code for importing functions from python files within the project directory was generated using PyCharm
- The code for registering the custom user class in the Accounts Admin.py file is from the Django documentation
- The custom user class in accounts/models.py is based on code from FOMFUS. The basic structure of this code is followed, with minor customisations to suit the needs of the project
- Two lines of code in the login_user() function are from The Net Ninja. They are identified in the function docstring
- The cart.py code is largely taken from muva. The cart.add and cart.remove functions are significantly edited as the original code did not function correctly. Other changes from the source are mostly simple name changes to match the variables of the project. Completely original code is identified by comments
- Code for processing Stripe payments is from the Stripe documentation
- The StoreItem class is taken from the Code Institute e-commerce project. The delivery_required, is_coins and coins_amount fields are original code
- Code in the Delivery class for automatically setting other current_delivery_method values to false when one’s value is set to true is taken from Adam on stackoverflow and edited to reflect the project variables. Added is the condition of only changing the current_delivery_method values of that user. This code is also used in the SuggestionAdminPage class
- The code that fixes the bug where tests crash because unit tests can’t use the messages middleware is from Tarsis Azevedo on stackoverflow. It is used throughout the various tests files and identified in the comments
- The code that enables unit testing session attributes is from Mark L on stackoverflow.com. It is used throughout the testing files and identified in the comments
- The code in the base.html template for displaying Django messages as a bootstrap alert is from simpleisbetterthancomplex. The foundations of the password_reset_done template are also from simpleisbetterthancomplex
- The code in the project settings for using AWS is from the Code Institute e-commerce project
- The project settings code that enables testing for Matplotlib functions in Travis is from Sylhare on stackoverflow
- The code in usersuggestions/data_visualization.py for specifying minor and major tick mark intervals is from the Matplotlib website
- The code in usersuggestions/data_visualization.py for saving plots to S3 is taken from Aidan Feldman on stackoverflow. The code is adjusted to fit projects structure and data
- The SuggestionAdminPageForm initialization code that only allows admin users to be assigned to a suggestion is from neil.millikin on stackoverflow
- The line of code used throughout the tests files that force logs in a user is from WeizhongTu on stackoverflow
- The sound wave gif seen by logged in users on the home page is taken from tenor
- The JPG used to represent coins in the store is from futuristicraft
- All icons used on the site are from Material Design
- The unicorn image used in the background of the home page header is taken from stickpng