Please note that this README file outlines the backend development of this application; if you require info on frontend development please navigate to the README for moonshot
Moonshot (stylised completely in lowercase) is a web application built for the sharing and discussion around amateur astrophotography. This site has been designed to allow imagined users and visitors the ability to view photos uploaded by registered users of the site; registered users will also be able to create a personal profile and 'star' (that is, like) and comment on other users' posts.
LIVE LINK to API
LIVE LINK to Application
Note: to open links in a new tab, hold CTRL + Click
- Introduction
- Strategy
- Scope
- Structure
- Skeleton
- Surface
- Testing
- Deployment
- Credits & Acknowledgements
The site is aimed at helping users to easily upload their personal photos of the night sky alongside relevant info such as what the photo shows, where/when it was taken, and what equipment was used. It also aims to give users the ability to view, star, and comment on the photos uploaded by other users of the site. This backend site models these details so they can be controlled by a superuser and also be utilised by the user via the frontend components.
This project was developed with 6 milestones (epics) in mind. From each of these milestones a number of dev goals and user stories were created, each one given a prioritisation using the MoSCoW method. The detail of these milestones, goals, and stories implemented in the final project is outlined below; further detail regarding sprints, MoSCoW designation and acceptance criteria (covered under Structure) are included on the GitHub Projects Kanban Board created for the project.
- 1.1 - Dev Goal: set up Django REST and its supporting libraries via the IDE in order for API development to begin
- 1.2 - User Story: as a Site Admin I want to be able to create and edit User Profiles so I can control user permissions on the frontend
- 1.3 - User Story: as a Site Admin I want to be able to review and edit Equipment Profiles for users so I can details on the frontend
- 1.4 - User Story: as a Site Admin I want to be able to review and edit Photo uploads so I can allow and control images on the frontend
- 1.5 - User Story: as a Site Admin I want to be able to review and edit Comments for so I can allow and control comments on the frontend
- 1.6 - User Story: as a Site Admin I want to be able to review and edit Star ratings (photo ratings) by users so I can allow and control star ratings on the frontend
- 1.7 - User Story: as a Site Admin I want to have access to search and filtering tools on the backend so I can find and edit particular data more easily
- 1.8 - Dev Goal: create an early API deployment to Heroku to ensure all is working from the very start and allow continuous testing throughout production
- 2.1 - Dev Goal: set up ReactJS and its supporting libraries via the IDE and create an early deployment to Heroku in for frontend development to begin and to ensure all is working from the very start
- 2.2 - User Story: as a Site Visitor/User I want access to navigation links at the top of every page so I can easily move between different areas of the site
- 2.3 - User Story: as a Site Visitor I want to easily access a sign up page so I can become a registered user and upload my own content/directly participate with other users of the site
- 2.4 - User Story: as a Site User I want to easily access a sign in page so I can use the full functionality of the site
- 3.1 - User Story: as a Site User I want view additional navigational links so that I can access those areas of the site only available to registered users
- 3.2 - User Story: as a Site User I want to remain logged in to the site until I choose otherwise so that my experience is not interrupted by having to continuously re-enter my username and password
- 3.3 - User Story: as a Site Visitor/User I want have a clear indication as to whether or not I am logged in/logged out so I can easily discern if I need to sign up/sign in before accessing certain pages
- 3.4 - User Story: as a Site User I want to be able to sign out from my account so that I know my account cannot be accessed by unauthorised persons
- 4.1 - User Story: as a Site User I want to be able to upload my own astrological photos to the site so that they are shared on the home page and commented on/upvoted by others
- 4.2 - User Story: as a Site User I want to include specific details such as keywords, date, time, location etc. with my uploaded photos so that those details can be displayed alongside the photo for the benefit of other users
- 4.3 - User Story: as a Site User I want to be able to update the details of any photo I have added so that I can correct mistakes or add new information if required
- 4.4 - User Story: as a Site User I want to be able to delete any photo I have added so that I can remove my photos from the site if I so desire
- 4.5 - Dev Goal: write defensive code to prevent anyone from accessing the ability to update/delete posts which were not specifically uploaded by them
- 5.1 - User Story: as a Site Visitor/User I want to view all user photos from the home page so I can see the latest content when first accessing the site
- 5.2 - User Story: as a Site User I want to be able to continuously scroll through photos so that I don't have to navigate between and reload multiple pages
- 5.3 - User Story: as a Site User I want to be able to search photos with keywords (title, feature, user, etc.) so I can view content specifically related to those keywords
- 5.4 - User Story: as a Site User I want to be able to select an individual photo from the feed so I can view details, comments, and upvotes directly associated with that photo
- 5.5 - User Story: as a Site User I want to be able to access a personalised profile page so that I can add an avatar, personal bio and equipment details
- 6.1 User Story: as a Site User I want to be able to upvote other users photos so that I can show my appreciation for their photography
- 6.2 User Story: as a Site User I want to be able to comment on other users photos so that I can ask questions and/or start a discussion about the photo
- 6.3 - User Story: as a Site User I want to view a feed of those photos I've upvoted so I have easy access to those posts I've shown a particular interest in
- 6.4 - User Story: as a Site User I want to view a feed of those photos I've commented on so I have easy access to posts where I am involved in a discussion thread
Using these milestones, goals, and stories to guide my thinking, the following was planned as the Scope of the project:
- Responsive Design:
- Resizing on all devices from 320px upwards (consideration for 280px+ also given)
- Toggle menu for navbar links at smaller sizes
- Home page displaying the latest uploads and links appropriate to logged-out/in status (for * see below):
- Home (available to all users)
- Sign Up (logged-out)
- Sign In (logged-out)
- Upload (logged-in)
- Profile* (logged-in)
- Gear* (logged-in)
- Account* (logged-in)
- Sign Out* (logged-in)
- Features appearing on the site as appropriate:
- Gallery with 'masonry' layout for photo feeds (Home, Profile)
- Infinite scroll on photo feeds (Home, Profile)
- Ability to search for photos using filters/search bar (Home signed-in, Profile)
- Ability to star (like)/comment on other users' photos
- User avatar appearing in navbar
- Pages marked * above in dropdown menu when viewed on medium/large screens
- Stylised 404 page
With Strategy and Scope now in place, focus shifted to setting acceptance criteria for each of the above, thereby informing exactly what features to include as part of the project. These acceptance criteria were added to each Dev Goal and User Story on the aforementioned Kanban board to act as an insurance that task would be completed to the fullest extent needed.
Hovering over a reference (Ref) number below will display a description of that Dev Goal/User Story while clicking the link will return you to the relevant Milestone section of this document.
Milestone | Ref | Type | Acceptance Criteria/Features |
---|---|---|---|
API | 1.1 | Dev Goal |
|
API | 1.2 | User Story |
|
API | 1.3 | User Story |
|
API | 1.4 | User Story |
|
API | 1.5 | User Story |
|
API | 1.6 | User Story |
|
API | 1.7 | User Story |
|
API | 1.8 | Dev Goal |
|
Navigation | 2.1 | Dev Goal |
|
Navigation | 2.2 | User Story |
|
Navigation | 2.3 | User Story |
|
Navigation | 2.4 | User Story |
|
Access | 3.1 | User Story |
|
Access | 3.2 | User Story |
|
Access | 3.3 | User Story |
|
Access | 3.4 | Dev Goal |
|
Photos | 4.1 | User Story |
|
Photos | 4.2 | User Story |
|
Photos | 4.3 | User Story |
|
Photos | 4.4 | User Story |
|
Photos | 4.5 | Dev Goal |
|
Pages | 5.1 | User Story |
|
Pages | 5.2 | User Story |
|
Pages | 5.3 | User Story |
|
Pages | 5.4 | User Story |
|
Pages | 5.5 | User Story |
|
Interaction | 6.1 | User Story |
|
Interaction | 6.2 | User Story |
|
Interaction | 6.3 | User Story |
|
Interaction | 6.4 | User Story |
|
Now that specific features had been decided upon, a database model was designed to give guidance as to how these features would relate to one another at the backend.
The structure was designed on the basis of exposing endpoints in the django-rest-allauth to handle authentication with the User model, while the other models would be linked to this and completely coded by myself.
The diagram below shows the relationship of various tables within the project. The models on the left, User Profile and Equipment Profile as set up to automatically create an instance whenever a user signs up/is created via the User model. The models on the right create instances whenever the admin/user specifically creates them, the Photo model being capable of have numerous instance associated with one User and the Stars/Comments likewise in relation to the Photo model.
With the database design now in place, actual models for the site could now be coded using the Django REST framework and the dj-rest-auth
packages using the criteria listed above to inform the process.
Each of the following implementations was added in response to the user stories and acceptance criteria above, details of which are provided below each feature heading for easy reference.
The initial page of the API displays a brief welcome message confirming connected with the site and its name. This page is accessed via https://moonshot-api-ff76437bf02f.herokuapp.com
• 1.2 - User Story: as a Site Admin I want to be able to create and edit User Profiles so I can control user permissions on the frontend
• 2.3 - User Story: as a Site Visitor I want to easily access a sign up page so I can become a registered user and upload my own content/directly participate with other users of the site
• 2.4 - User Story: as a Site User I want to easily access a sign in page so I can use the full functionality of the site
• 3.4 - User Story: as a Site User I want to be able to sign out from my account so that I know my account cannot be accessed by unauthorised persons
- The User model is accessed by appending '/admin/auth/user/' to the main API url and requires admin privileges to access
- User model functionality is handled by dj-rest-auth and so models, serializers, views etc. apepar directly as folders within this application
- When a User model instance is created a directly associated User Profile and Equipment Profile instance is also created with identical 'id' values
• 1.2 - User Story: as a Site Admin I want to be able to create and edit User Profiles so I can control user permissions on the frontend
• 1.7 - User Story: as a Site Admin I want to have access to search and filtering tools on the backend so I can find and edit particular data more easily
• 5.5 - User Story: as a Site User I want to be able to access a personalised profile page so that I can add an avatar, personal bio, and equipment details
- A User Profile model instance is created automatically whenever a user signs up/is created using the User model
- The User Profile model is accessed by appending '/user-profiles/' to the main API url; an individual record of this model is accessed by also appending the relevant id
- User Profile admin access is achieved by appending '/admin/user_profiles/' to the main API url, but requires admin privileges to access
- The model uses GET and PUT views to list and update user profiles respectively
- In addition to those shown in the diagram above, 'is_owner' and 'photo_upload_count' fields have been added to the model through use of a serializer
- A default avatar is added to every User profile by means of connection to the Cloudinary API
- Ordering fields have been added to the model to allow ordering by 'created_at' and 'photo_upload_count'
- Search fields have been added to the model to allow searching of associated username and name attributes
• 1.3 - User Story: as a Site Admin I want to be able to review and edit Equipment Profiles for users so I can details on the frontend
• 1.7 - User Story: as a Site Admin I want to have access to search and filtering tools on the backend so I can find and edit particular data more easily
• 5.5 - User Story: as a Site User I want to be able to access a personalised profile page so that I can add an avatar, personal bio, and equipment details
- An Equipment Profile model instance is created automatically whenever a user signs up/is created using the User model
- The Equipment Profile model is accessed by appending '/equipment-profiles/' to the main API url; an individual record of this model is accessed by also appending the relevant id
- Equipment Profile admin access is achieved by appending '/admin/equipment_profiles/' to the main API url, but requires admin privileges to access
- The model uses GET and PUT views to list and update equipment profiles respectively
- In addition to those fields shown in the diagram above, an 'is_owner' field has been added to the model through use of a serializer
- Filters have been added to allow filtering by user
- Ordering fields have been added to the model to allow ordering by 'created_at'
- Search fields have been added to the model to allow searching of associated username, main lens, main camera, and other equipment attributes
• 1.4 - User Story: as a Site Admin I want to be able to review and edit Photo uploads so I can allow and control images on the frontend
• 1.7 - User Story: as a Site Admin I want to have access to search and filtering tools on the backend so I can find and edit particular data more easily
• 4.1 - User Story: as a Site User I want to be able to upload my own astrological photos to the site so that they are shared on the home page and commented on/upvoted by others
• 4.2 - User Story: as a Site User I want to include specific details such as keywords, date, time, location etc. with my uploaded photos so that those details can be displayed alongside the photo for the benefit of other users
• 4.3 - User Story: as a Site User I want to be able to update the details of any photo I have added so that I can correct mistakes or add new information if required
• 4.4 - User Story: as a Site User I want to be able to delete any photo I have added so that I can remove my photos from the site if I so desire
• 4.5 - Dev Goal: write defensive code to prevent anyone from accessing the ability to update/delete posts which were not specifically uploaded by them
• 5.3 - User Story: as a Site User I want to be able to search photos with keywords (title, feature, user, etc.) so I can view content specifically related to those keywords
• 5.4 - User Story: as a Site User I want to be able to select an individual photo from the feed so I can view details, comments, and upvotes directly associated with that photo
- The Photo model is accessed by appending '/photos/' to the main API url; an individual record of this model is accessed by also appending the relevant id
- Photo admin access is achieved by appending '/admin/photos/' to the main API url, but requires admin privileges to access
- The model uses GET, POST, PUT and DELETE views to list, create, update and delete photos respectively
- Variables have been added to the 'main_feature' field to limit permitted values
- In addition to those shown in the diagram above, 'user', 'user_avatar', 'is_owner', 'star_id', 'star_count' and 'comment_count' fields have been added to the model through use of a serializer
- Image validation has also been added via the serializer to ensure that photos are less than 4MB in size and les than 7096px in width/height
- Filters have been added to the model to allow filtering by users, main features, associated profiles, and stars/comments associated with a particular photo instance
- Ordering fields have been added to the model to allow ordering by 'created_at', 'star_count' and 'comment_count'
- Search fields have been added to the model to allow searching of users, titles, main features, descriptions, and locations
• 1.5 - User Story: as a Site Admin I want to be able to review and edit Comments for so I can allow and control comments on the frontend
• 1.7 - User Story: as a Site Admin I want to have access to search and filtering tools on the backend so I can find and edit particular data more easily
• 6.2 User Story: as a Site User I want to be able to comment on other users photos so that I can ask questions and/or start a discussion about the photo
• 6.4 - User Story: as a Site User I want to view a feed of those photos I've commented on so I have easy access to posts where I am involved in a discussion thread
- The Comment model is accessed by appending '/comments/' to the main API url; an individual record of this model is accessed by also appending the relevant id
- Comment admin access is achieved by appending '/admin/comments/' to the main API url, but requires admin privileges to access
- The model uses GET, POST, PUT and DELETE views to list, create, update and delete comments respectively
- In addition to those shown in the diagram above, 'user_id', 'user_avatar' and 'is_owner' fields have been added to the model through use of a serializer
- Filters have been added to the model to allow filtering by associated users and photos
- Ordering fields have been added to the model to allow ordering by 'created_at'
- Search fields have been added to the model to allow searching of associated usernames and content
• 1.6 - User Story: as a Site Admin I want to be able to review and edit Star ratings (photo ratings) by users so I can allow and control star ratings on the frontend
• 1.7 - User Story: as a Site Admin I want to have access to search and filtering tools on the backend so I can find and edit particular data more easily
• 6.1 User Story: as a Site User I want to be able to upvote other users photos so that I can show my appreciation for their photography
• 6.3 - User Story: as a Site User I want to view a feed of those photos I've upvoted so I have easy access to those posts I've shown a particular interest in
- The Star model is accessed by appending '/stars/' to the main API url; an individual record of this model is accessed by also appending the relevant id
- Star admin access is achieved by appending '/admin/stars/' to the main API url, but requires admin privileges to access
- The model uses GET, POST, PUT and DELETE views to list, create, update and delete stars respectively
The following features have been identified as long-term goals which bring value to the UX; however, they have not been implemented at this stage as they would require a significant time investment, thereby delaying vital other features of the site, or a level of programming knowledge which I haven't yet developed.
- Following/unfollowing other users: requires a new model at the backend and extensive work on the frontend which was not within the time capabilities of the initial project
In order to code and design these features and components the following technologies were utilised:
- Dependencies
- asgiref==3.3.4
- cloudinary==1.25.0
- dj-rest-auth==2.1.9
- dj-database-url==0.5.0
- Django==3.2.4
- django-allauth==0.44.0
- django-cloudinary-storage==0.3.0
- django-cors-headers==4.3.0
- django-filter==2.4.0
- djangorestframework==3.12.4
- djangorestframework-simplejwt==4.7.2
- gunicorn==20.1.0
- oauthlib==3.1.1
- Pillow==9.2.0
- psycopg2-binary==2.9.9
- PyJWT==2.1.0
- python3-openid==3.2.0
- pytz==2021.1
- requests==2.31
- requests-oauthlib==1.3.0
- sqlparse==0.4.1
- urllib3==1.26.15
- Django REST Framework
- Used as main toolkit for building the API
- Python
- Used as the main coding language in the backend development of this project
- Django Allauth
- Used for sign up/in/out authentication
- ElephantSQL
- Used as the database hosting service
- Cloudinary & Pillow
- Used to host and process image files contained within the User Profile and Photo models
- Heroku
- Used as the cloud-based deployment platform for this project
- Gitpod used to code the site and transfer files between the editor and the repository
- GitHub used to store the files for this project
- Cacoo used to develop the wireframe models for the site design
- Lucid Chart used to create the database diagram
- Google Fonts used to style the text throughout the site
- Coolors used to help create the colour scheme
- React Icons used to display the icons used throughout the site
- React Toastify used to create the success/uploading/error pop-ups throughout the site
- Infinite Scroll used to prevent pagination of photo pages and allow continuous browsing of content
- Responsive Masonary used to create a responsive gallery layout of images on photo feed pages
- Moment used to correctly format date and time values on Photo Detail pages
- Markdown Table Generator used to create tables for documentation
- PowerPoint, MS Paint, and the Windows Photo app used to produce image files for documentation
- Code Institute course materials and walkthrough projects provided many reference points for implementing features of this project
- Resources used are directly referenced within code where appropriate
Manual and automated testing undertaken for this project can be viewed in the separate TESTING.md file (Use CTRL + Click to this or any of the following links in a new tab/window). You can also navigate to a specific area of the file by selecting one of the headings below:
This site was deployed to and is currently hosted on the Heroku platform. The steps for deploying to Heroku, using ElephantSQL as the database host, are as follows:
- Navigate to Cloudinary and create an account/log in
- Navigate to 'Programmable Media' and then 'Dashboard'
- Copy the value called 'API environment variable'
- Navigate to ElephantSQL and create an account/log in
- Click 'Create New Instance' in the top right
- Enter an Instance/Database name, choose a Plan (free version will suffice) then click 'Select Region'
- Select a region from the dropdown, click 'Review' and then 'Create instance'
- Return to the dashboard and click on the instance name
- In the URL section click the copy icon to copy the database URL
- In the backend repo navigate to/create a file named 'env.py'
- Add the following code, replacing
<mycloudinaryurl>
with your personal link from Cloudinary,<mydatabaseurl>
with the URL copied from ElephantSQL and,<mykey>
with a string of your choice then save the file:import os os.environ['CLOUDINARY_URL']=<mycloudinaryurl> os.environ["DATABASE_URL"]=<mydatabaseurl> os.environ["SECRET_KEY"]=<mykey>
- Open 'settings.py' and replace any current instance of the SECRET_KEY variable with:
SECRET_KEY = os.environ.get('SECRET_KEY')
- Replace the DATABASES variable with
DATABASES = { 'default': dj_database_url.parse(os.environ.get("DATABASE_URL")) }
- Save the file then run
python manage.py migrate
in the terminal - Commit and push these changes to the repository
- Navigate to Heroku and create an account/log in
- Click 'New' in the top right and select 'Create New App'
- Enter an App name (must be unique), choose a region, and then click 'Create app'
- Select 'Settings' in the menu bar
- Click 'Reveal Config Vars' and add the following:
- CLOUDINARY_URL: the CLOUDINARY_URL copied from Cloudinary
- DATABASE_URL: the DATABASE_URL copied from ElephantSQL
- SECRET_KEY: The SECRET_KEY string you created
- PORT: 8000 - Click 'Deploy' in the menu bar tab then 'GitHub' under 'Deployment method'
- Select the repository you want to deploy and click 'Connect'
- Scroll down and click 'Deploy Branch' to complete the process (note the deployed URL)
-
In the project workspace, navigate to/create a file named 'Procfile' (remember the capital 'P') and add the code
web: serve -s build
-
Install axios (if not already done) using the command
npm install axios
and create a folder/file called axios/axiosDefaults under src -
Add the following code, replacing
<myapiurl>
with the deployed API URL from step 23: ``` JSX import axios from 'axios';axios.defaults.baseURL = ''; axios.defaults.headers.post['Content-Type'] = 'multipart/form-data'; axios.defaults.withCredentials = true;
export const axiosReq = axios.create(); export const axiosRes = axios.create(); ```
-
Import this file to App.js before saving, committing and pushing changes to repo
- Navigate to Heroku and log in
- Click 'New' in the top right and select 'Create New App'
- Enter an App name (must be unique), choose a region, and then click 'Create app'
- Click 'Deploy' in the menu bar tab then 'GitHub' under 'Deployment method'
- Select the repository you want to deploy and click 'Connect'
- Scroll down and click 'Deploy Branch' to complete the process
- Login to/create your GitHub account
- Navigate to the moonshot GitHub Repository: https://github.com/ndsurgenor/moonshot
- Towards the top right, under the main banner, click 'Fork'
- Adjust the form fields if desired, then click 'Create fork' to finish Repeat these steps for the moonshot repo if required, as described in backend README
- Login to/create your GitHub account
- Navigate to the moonshot Repository: https://github.com/ndsurgenor/moonshot
- Click the '<> Code' dropdown button and ensure 'HTTPS' is selected
- Click the copy icon (two overlapped squares) beside the repository URL
- Open your local IDE and create a new project, ensuring git is installed
- Run
git clone copied-git-url
in the terminal to finish Repeat these steps for the moonshot repo if required, as described in backend README
- README.md and TESTING.md structure/outline adapted from Asia Wi
- Many thanks to my Code Institute tutor Daisy McGirr for her guidance, support, and strong effort in helping me to build this project