Skip to content
dionisggr edited this page Feb 21, 2021 · 3 revisions

Flickshare App

The Flickshare App is directed for anyone who really has a hard time finding suggestions on what to watch next! The app allows users to create an account and custom lists of movie interests, which may then be used to generated a list of suggestions and store them for coming back to it later.

This API stop represents a way for the app to communicate with the list of users, movie lists and movies. The user data contains full name, email, username, password and admin privileges. The list data contains a name and an associated user.


API URL:

https://cryptic-badlands-24275.herokuapp.com/ - (Landing)

Client Live

(Pending)

Client GitHub:

https://github.com/dionisggr/flickshare-client/


User Stories

  • As a prospective user
    • I am landed in the Welcome Page
    • I can see the week's top movie suggestions per category
    • I can navigate to the Register and Login pages
  • As a registered user
    • I can create and name a list
    • I can search for a movie to select for a list
    • I can search, edit and delete my list
    • I can browse my friends' top public lists
    • I can send friends movie suggestions
    • I can like movies in lists
    • I can dislike movie suggestions directed to me
    • I can select a movie to learn more details about it
  • As an Admin
    • I can see, edit and delete users
    • I can see, edit and delete movies
    • I can see, edit and delete lists
    • I can reset likes in movies
    • I can reset suggestion algorithms for users

Technology

  • Front-End:
  • Back-End: Javascript, Node.js, Express.js, Knex.js, PostgreSQL, Mocha, Chai, Supertest, Nodemon, Postgrator, Dotenv, JWT, Bcrypt, Morgan, XSS, CORS, Helmet, HTML5, CI scripts
  • Development Environment: Heroku, DBeaver, Postman

Functionality

The app's functionality includes:

  • Every User
    • May create an account
    • May browse public suggestion lists
    • May read full movie information
  • Registered User
    • May edit and delete their account
    • May create, edit and delete their lists
    • May generate suggestions from other lists
    • May search for any movie
  • Admin
    • May see a list of all users
      • May create, edit and delete any user
    • May see a list of all lists
      • May create, edit and delete any list

Front-End Structure

  • Index.js - (stateless)
    • App.js - (stateful)
      • Header.js - (stateless)
      • MainMenu.js - (stateless)
      • Register.js - (stateless)
      • Login.js - (stateless)
      • WelcomePage.js - (stateful)
        • Login.js - (stateful)
        • Register.js - (stateful)
      • Lists.js - (stateful)
      • List.js - (stateful)
      • Suggestions.js - (stateful)
      • Movie.js - (stateful)
        • MoviePreview.js - (stateful)
          • MovieOptions.js - (stateful)
      • MovieSearch.js - (stateful)
      • Admin.js - (stateful)
        • Users.js - (stateful)
      • User.js - (stateful)
        • UserPreview.js - (stateless)
      • UserEdit.js - (stateful)
      • Error.js - (stateless)
      • ErrorBoundary.js - (stateful)
      • Footer.js - (stateless)

Back-End Structure

  • Users (database table)
    • user_id (integer, auto-generated)
    • first_name (text, not null)
    • last_name (text, not null)
    • email (text, unique)
    • username (text, unique)
    • password (text, hashed)
    • admin (boolean, default false)
  • Lists (database table)
    • list_id (integer, auto-generated)
    • name (text, not null)
    • user_id (integer, optional)
  • Movies (database table)
    • movie_id (integer, auto-generated)
    • name (text, not null)
    • tmdb_id (integer, id from tmdb API)
    • description (text, maximum 150 characters)
    • release_date (text, not date)
    • popularity (numeric, decimal)
    • poster (text, poster image URL)
    • avg_vote (numeric)
    • vote_count (integer)
  • List Movies (database table)
    • list_id (references lists.list_id)
    • movie_id (references movies.movie_id)

API Documentation

Endpoints that require Authentication

Closed endpoints that require a valid username and password to be included in the header body of the request.

Login

  • Step 1: (Generate JSON Web Token)
    • POST /api/login
      • 'Admin' credentials
        • Username: admin
        • Password: password
  • Step 2: <Use generated JSON Web Token (3 hrs)>
  • Step 3 (Optional): Refresh JSON Web Token
    • POST /api/token

Endpoints that require Authorization

Closed endpoints that require a valid JSON Web Token to be inlcuded in the header 'Authorization' of the request.

// Add to request header
headers: {'Authorization': 'Bearer <JSON Web Token>'}

If sending content through request body (POST), don't forget to add the following in the headers:

// Add to request header
headers" {'Content-Type': 'application/json'}

User related

Each endpoint manipulates information related to users.

Get Users

URL: /api/users
Method: GET
Auth required: Yes

  • Bearer my-secret-admin
Success Response

Code: 200 OK
Content example

[
  {
    "username": "dschrute",
    "first_name": "Dwight",
    "last_name": "Schrute",
    "email": "schrutefarms@creedmail.com",
    "admin": false
  },
      
  ...
]

Create User (Register)

URL: /api/users
Method: POST
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

  {
  "username": "rhoward",
  "password": "password",
  "first_name": "Ryan",
  "last_name": "Howard",
  "email": "commited@wuphf.com",
  "admin": false
}
Name Type In Description
username string header Unique username
password string header User password
first_name string header First name of user
last_name string header Last name of user
email string header User email
admin boolean header Admin privileges
Success Reponse

Code: 201 Created
Content example

{
  "user_id": 4
  "username": "rhoward",
  "first_name": "Ryan",
  "last_name": "Howard",
  "email": "commited@wuphf.com",
  "admin": false
}

Edit User

URL: /users/:userID
Method: PATCH
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

{
  // All optional, at least one required.
  "username": "rhoward",
  "first_name": "Ryan",
  "last_name": "Kapoor", // Edited
  "email": "taken@wuphf.com", // Edited
  "admin": false
}
Name Type In Description
user integer path User ID
username string header Unique username
first_name string header First name of user
last_name string header Last name of user
email string header User email
admin boolean header Admin privileges
Success Reponse

Code: 201 Created (Resource updated successfully, and refreshes.)
Content example

{
  "user_id": 4
  "username": "rhoward",
  "first_name": "Ryan",
  "last_name": "Kapoor",
  "email": "taken@wuphf.com",
  "admin": false
}
Notes

All values will be necessary in Update due to previous empty field validation


Delete User

URL: /users/:user
Method: DELETE
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token> (Generated at Login. See above for instructions)
Name Type In Description
user integer path User ID
Success Reponse

Code: 301 Moved Permanently
Content example

<No Content>

List related

Each endpoint manipulates information of general and user lists.

Movie related

Each endpoint manipulates information related to movie data.

Get All Movies

URL: /api/movies
Method: GET
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Success Reponse

Code: 200 OK
Content example

[
  {
    "movie_id": 1,
    "name": "Man of Steel",
    "description": "Come on, it's Man of Steel.",
    "tmdb_id": 99999,
    "releaste_date": 2013,
    "popularity": 987.72
    "avg_vote": 7.4,
    "vote_count": 9,876
    "poster": "https://image.tmdb.org/t/p/original/manofsteel.jpg",
  },
      
  ...
]

Get Movie

URL: /api/movies/:movie
Method: GET
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Success Reponse

Code: 200 OK
Content example

[
  {
    "movie_id": 1,
    "name": "Man of Steel",
    "description": "Come on, it's Man of Steel.",
    "tmdb_id": 99999,
    "releaste_date": 2013,
    "popularity": 987.72
    "avg_vote": 7.4,
    "vote_count": 9,876
    "poster": "https://image.tmdb.org/t/p/original/manofsteel.jpg",
  },
      
  ...
]

Add Movie to Database

URL: /api/movies
Method: POST
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

{
  "name": "The Dark Knight",
  "description": "No description necessary.",
  "tmdb_id": 99998,
  "release_date": 2008,
  "popularity": 985.27
  "avg_vote": 6.9,
  "vote_count": 8,517
  "poster": "https://image.tmdb.org/t/p/original/thedarkknight.jpg"
}
Name Type In Description
name string header Name of project
description string header Description of project
tmdb_id string header Languages/Tools required
release_date string header Project Phase
popularity string header Project Phase status
avg_vote string header Creator of project
vote_count string header Date created
poster boolean header Accepts collaboration
Success Reponse

Code: 201 Created
Content example

{
  "movie_id": 2,
  "name": "The Dark Knight",
  "description": "No description necessary.",
  "tmdb_id": 99998,
  "releaste_date": 2008,
  "popularity": 985.27
  "avg_vote": 6.9,
  "vote_count": 8,517
  "poster": "https://image.tmdb.org/t/p/original/thedarkknight.jpg"
}

Add Movie to List

URL: /api/movies/lists/:list
Method: POST
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

{
  "movie_id": 1
}
Name Type In Description
list integer path List ID
movie_id integer header Movie ID
Success Reponse

Code: 201 Created
Content example

<No Content>


Delete Movie

URL: /api/movies/:movie
Method: DELETE
Auth required: Yes

  • Bearer my-secret-admin
Name Type In Description
movie integer path Movie ID
Success Reponse

Code: 301 Moved Permanently
Content example

<No Content>


Delete List Movie

URL: /api/movies/:movie/lists/:list
Method: DELETE
Auth required: Yes

  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Name Type In Description
movie integer path Movie ID
list integer path List ID
Success Reponse

Code: 301 Moved Permanently
Content example

<No Content>

Movie-List related

Each endpoint manipulates information related to the movies in lists.

Get All Lists

URL: /api/lists
Method: GET
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Success Response

Code: 200 OK
Content example

[
    {
    "list_id": "1",
    "name": "Admin list",
    "user_id": 1,
    "movies": [...]
  },
  {
    "list_id": "2",
    "name": "Top Rated",
    "user_id": null,
    "movies": [...]
  }
      
  ...
]

Get Main Lists

URL: /api/lists/main
Method: GET
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Success Response

Code: 200 OK
Content example

[
    {
    "list_id": "2",
    "name": "Top Rated",
    "user_id": null,
    "movies": [...]
  },
  {
    "list_id": "3",
    "name": "Popular",
    "user_id": null,
    "movies": [...]
  }
      
  ...
]

Create List

URL: /api/lists
Method: POST
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

{
  "name": "New List Name",
  "user_id": 1  // Optional
}
Name Type In Description
name string header Name of list
user_id integer header Description of list
Success Response

Code: 201 Created
Content example

{
  "list_id": 3,
  "name": "New List Name",
  "user_id": 1
}

Edit List

URL: /api/lists/:list
Method: PATCH
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

{
  "name": "New Name"
}
Name Type In Description
list integer path List ID
name string header Name of list
Success Response

Code: 201 Created (Resource updated successfully, and refreshes.)
Content example

{
  "list_id": 3,
  "name": "New Name",
  "user_id": 2
}
Notes

All values will be necessary in Update due to previous empty field validation


Delete List

URL: /api/lists/:list
Method: DELETE
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Name Type In Description
list integer path LIst ID
Success Response

Code: 301 Moved Permanently
Content example

<No Content>

Access / Token related

Each endpoint manipulates information related access / token management.

Login

URL: /api/login
Method: POST
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin

####### Request Body

{
  "username": "admin",
  "password": "password",
}
Name Type In Description
username string header Unique username
password string header User password
Success Response

Code: 200 OK
Content example

{
  "flickshareToken": &lt;JSON Web Token&gt;
}

Refresh Token

URL: /api/token
Method: GET
Auth required: Yes

  • Bearer <JSON Web Token>
Success Response

Code: 200 OK
Content example

{
  "flickshareToken": &lt;JSON Web Token&gt;
}

Registration

URL: /api/users
Method: POST
Auth required: Yes

  • Bearer my-secret-key
  • Bearer my-secret-admin
  • Bearer <JSON Web Token>
Request Body

Requires headers: {'Content-Type': 'application/json'}

{
  "username": "rhoward",
  "password": "password",
  "first_name": "Ryan",
  "last_name": "Howard",
  "email": "commited@wuphf.com",
  "admin": false
}
Name Type In Description
username string header Unique username
password string header User password
first_name string header First name of user
last_name string header Last name of user
email string header User email
admin string header Admin privileges
Success Response

Code: 201 Created
Content example

[
  {
    "user_id": "4"
    "username": "rhoward",
    "first_name": "Ryan",
    "last_name": "Howard",
    "email": "commited@wuphf.com",
    "admin": false
  },
  
  ...
]

Admin related

Each endpoint manipulates information related to all data, only able to be accessed by an Admin user. Admins can manipulate all previous endpoints as well.


Screenshots

Landing Page


Development Roadmap

This is v1.0 of the app, but future enhancements are expected to include:

  • Implementation of movie likes
  • Implementation of list likes
  • Sending movie-list suggestions
  • Copy other user's lists

Local Dev Set Up

Start a database server with pg_ctl start.

If using user admin:

mv example.env .env
createdb -U admin flickshare
createdb -U admin flickshare-test

If your admin user has a password be sure to set it in .env for all appropriate fields. Or if using a different user, update appropriately.

npm install
npm run migrate
env MIGRATION_DB_NAME=flickshare-test npm run migrate

To start the application, use npm start. Tests will run automatically.
Alternatively, to run development mode, use npm run dev. Tests will not run.

To seed the database: psql -U admin -d flickshare -f ./seeds/seed.flickshare.sql.

And npm test should work at this point.

Configuring Postgres

For tests involving time to run properly, configure your Postgres database to run in the UTC timezone.

  1. Locate the postgresql.conf file for your Postgres installation.
    1. E.g. for an OS X, Homebrew install: /usr/local/var/postgres/postgresql.conf
    2. E.g. on Windows, maybe: C:\Program Files\PostgreSQL\11.2\data\postgresql.conf
    3. E.g on Ubuntu 18.04 probably: '/etc/postgresql/10/main/postgresql.conf'
  2. Find the timezone line and set it to UTC:
# - Locale and Formatting -

datestyle = 'iso, mdy'
#intervalstyle = 'postgres'
timezone = 'UTC'
#timezone_abbreviations = 'Default'     # Select the set of available time zone