Skip to content

ibuttimer/TeamPicker

Repository files navigation

TeamPicker

Motivation

The purpose of TeamPicker is to provide an application that enables the management of sports teams. Following registration, a manager must create a team during setup. Subsequently, players may register and must select a team during setup. Managers may then configure matches against other teams, and make their team selection from the list of players registered with their team. Following selection, players may confirm their availability. Please see Usage for additional details.

Getting Started

Reference Application

A reference application is hosted on Heroku and may be accessed at https://teampicker-fswd.herokuapp.com/.

See Pre-configured users for a list of users that have already been set up. See Additional users for details on adding new users, and Usage for details of application functionality.

Application Layout

The application structure is as follows:

├─ README.md            - this file
├─ API.md               - API specification
├─ requirements.txt     - the dependencies to be installed, see Install dependencies
├─ teampicker.py        - main script
├─ Procfile             - commands that are executed by the app on startup
├─ runtime.txt          - python runtime version
├─ src                  - backend application code
│  └─ team_picker       - application code 
│     │  ├─ auth        - authentication code
│     │  ├─ controllers - controllers for processing API requests
│     │  ├─ forms       - flask-wtf forms
│     │  ├─ models      - database ORM models
│     │  ├─ public      - javascript, css etc. files for UI
│     │  ├─ services    - service layer interfacing between controllers and database
│     │  ├─ templates   - jinja templates
│     │  └─ util        - miscellaneous application code
│     ├─ __init__.py    - application code 
│     └─ constants.py   - application constants 
├─ test                 - test scripts
│  └─ postman           - Postman collection
├─ instance             - application instance folder, to store configurations etc. outside of version control 
└─ migrations           - Flask-Migarate versions folder, to store database configurations 

API

The API documentation is available in API.md.

Installing Dependencies

Python

Follow instructions to install the latest version of python for your platform in the python docs

Virtual Environment

It is recommended that a virtual environment be used for development purposes. Please see Creating a virtual environment for details.

Terminal Window

The following instructions are intended to be executed from a terminal window in the project root folder, in which the virtual environment is activated.

Key Dependencies
  • Flask is a lightweight backend microservices framework. Flask is required to handle requests and responses.
  • SQLAlchemy, Flask-SQLAlchemy and Flask-Migrate are libraries to provide database management and connectivity.
  • python-jose JavaScript Object Signing and Encryption for JWTs. Useful for encoding, decoding, and verifying JWTs.
  • Authlib and auth0-python provide authentication and management functionality via the Auth0 service.
  • Jinja templating engine.
  • Bootstrap framework.
  • jQuery JavaScript library.
Authorisation Dependencies

The details of the authorisation configuration on Auth0 are as follows:

TeamPicker Auth0 Application

The main TeamPicker application on Auth0 is a Regular web application.

TeamPicker M2M Auth0 Application

There is also a Machine to Machine application, TeamPicker M2M, which is authorised to request access tokens for the TeamPicker API and the Auth0 Management API, by executing a client credentials exchange. TeamPicker M2M is used to assign roles to newly registered users.

TeamPicker Auth0 API

The following are the details of the Auth0 API:

Permission Description TeamManager
Role
TeamPlayer
Role
delete:match Delete a match
delete:own-user Delete personal user
get:match Get a match
get:own-user Read personal user
get:role Read a role
get:team Read a team
get:user Read a user
patch:match Update a match
patch:own-match Update personal info for match
patch:own-user Update personal user
patch:team Update a team
patch:user Update a user
post:match Create a match
post:team Create a team
post:user Create a user

Database schema

The following database schema has been implemented:

Database schema

Install dependencies

Run the following command in a Terminal Window:

> pip3 install -r requirements.txt

Also see Using requirements files.

Application Configuration

The application utilises environments variables, or a combination of configuration files and environments variables to specify the application configuration. There are three methods of configuring the application:

Database Configuration

The database configuration must be set in one of three different ways. In order of precedence they are:

  1. Set the DB_URI variable to a Connection URI.

  2. Set the DB_URI_ENV_VAR variable to the name of an environment variable which is set to a Connection URI.

    E.g. A typical use case is with a Heroku Postgres add-on which adds a DATABASE_URL environment variable that contains the database URI.

  3. Set the DB_DIALECT,DB_DRIVER,DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT and DB_DATABASE variables from which a Connection URI is created.

.env file
  • The configuration file should follow the format specified by sample.env.

For example, to configure the application to use:

  • an SQLite database file database.db in the instance folder
Create .env file
  1. Copy the file sample.env and save as .env, in the project root folder.

  2. Edit the new file to set the required database and authentication configuration.

    DB_DIALECT = sqlite
    DB_DATABASE = database.db
    DB_INSTANCE_RELATIVE_CONFIG = True
    
    # Authentication related settings:
    AUTH0_DOMAIN = udacity-fsnd.auth0.com
    ALGORITHMS = ['RS256']
    AUTH0_AUDIENCE = dev
    ...
    

    Please see sample.env for additional information.

    If variables are used in values, ensure they are surrounded with { and }, like ${VAR_TO_EXPAND}, as bare variables such as VAR_TO_EXPAND are not expanded.

    If a variable is defined in both .env and as a system environment variable, the system environment variable has precedence.

Setting environment variables

Depending on the operations system, environment variables are set differently:

For Linux and Mac:                  For Windows:                    For PowerShell:
$ export VARIABLE_NAME=value        > set VARIABLE_NAME=value       > $Env:VARIABLE_NAME=value
Configuration file
  • The configuration file should follow the format specified by sample-config.py.
  • The environment variables determine which configuration file to load.
    • APP_CONFIG_PATH

      Configuration file path.

    • INST_REL_CONFIG

      Flag indicating if instance_relative_config is relative to the instance folder. A setting of f, false, n, no or 0 is evaluated as False, otherwise the setting will be evaluated according to it's truthy value.

Ensure there is no .env file in the project root folder or any parent folders, otherwise an unexpected configuration may result.

For example, to configure the application to use:

  • a configuration file config.py located in the instance folder, and
  • an SQLite database file database.db in the instance folder
Create configuration file
  1. Copy the file sample-config.py and save as config.py, in the instance folder.

  2. Edit the new file to set the required database and authentication configuration.

    DB_DIALECT = 'sqlite'
    DB_DATABASE = 'database.db'
    DB_INSTANCE_RELATIVE_CONFIG = True
    
    # Authentication related settings:
    AUTH0_DOMAIN = 'udacity-fsnd.auth0.com'
    ALGORITHMS = ['RS256']
    AUTH0_AUDIENCE = 'dev'
    ...

    Please see sample-config.py for additional information.

    As the configuration file is a python script, standard python string formatting may be used.

  3. Set the environment variables, APP_CONFIG_PATH and INST_REL_CONFIG appropriately.

    Variable Value
    APP_CONFIG_PATH config.py
    INST_REL_CONFIG true
    See Setting environment variables.
Environment variables

Environment variables corresponding to the keys in sample.env and sample-config.py should be set as appropriate.

An appropriately updated copy of the bash script sample.env.sh may be used to set the environment variables.

For example, to configure the application to use:

  • an SQLite database file database.db in the instance folder

    Set environment variables:

    Variable Value
    INST_REL_CONFIG true
    DB_DIALECT sqlite
    DB_DATABASE database.db
    DB_INSTANCE_RELATIVE_CONFIG True
    AUTH0_DOMAIN udacity-fsnd.auth0.com
    ALGORITHMS ['RS256']
    AUTH0_AUDIENCE dev
    See Setting environment variables.

For convenience, the location of the instance folder has been hardcoded to instance, as the default location determined by Flask varies depending on whether the application or test scripts are running. Please see Instance Folders for further information.

Application Arguments

The application supports a number of arguments:

usage: TeamPicker [-h] [-idb] [-pt] [-ga GENERATE_API]

optional arguments:
  -h, --help            show this help message and exit
  -idb, --initdb        Initialise the database, default no
  -pt, --postman_test   Disable server-side sessions, default no
  -ga GENERATE_API, --generate_api GENERATE_API
                        Generate API Markdown documentation, as specified file

Depending on the run method, these arguments must be passed as commandline arguments (Run using script), or as a dictionary (Run using Flask).

Environment variable equivalents of command line arguments have precedence over command line arguments.

Initialise the database (--initdb)

When specified the database will be initialised before use, resulting on the removal of all data.

The environment variable equivalent is INIT_DB_ARG.

This operation should not be confused with Database Migration which updates the database schema.

As Gunicorn has no inter-worker method of communication to coordinate the database initialisation, there must be only one worker when initialising the database. Gunicorn uses the WEB_CONCURRENCY environment variable as the default value for the number of workers. If not set, Heroku provides a WEB_CONCURRENCY value depending on the dyno size.
Therefore, the WEB_CONCURRENCY environment variable should be set to 1 when utilising --initdb or INIT_DB_ARG on Heroku.

Disable server-side sessions (--postman_test)

When specified, server-side sessions will be disabled. This setting is necessary when running Postman requests and using a JWT from a user logged-in on a browser in the Postman application.

The environment variable equivalent is POSTMAN_TEST_ARG, however it should not be used on Heroku.

Generate API markdown (--generate_api)

When specified, an API template Markdown document detailing all the application routes will be generated using the specified filename.

The environment variable equivalent is GENERATE_API_ARG, however it should not be used on Heroku.

The API Markdown documentation file will be generated in the instance folder.

Database Migration

Once the application is configured for a blank database, as specified in Application Configuration, the database must be prepared for the application as follows:

Database Initialisation

Once the database has been migrated, it may be re-initialised by specifying the Initialise the database (--initdb) application argument. When running as a script:

> python teampicker.py --initdb

or passed via the FLASK_APP environment variable.

  FLASK_APP=src.team_picker:create_app({"initdb":True})

Run the application

The application can be run using the flask command or directly by running the script.

Once an appropriate configuration has been created as per Application Configuration, from a Terminal Window, run the following commands:

For Linux and Mac:                                For Windows:
$ cd /path/to/project                             > cd \path\to\project

Set python path

Set environment variables:

Variable Value
PYTHONPATH /path/to/project/src
See Setting environment variables.

Run using script

From a Terminal Window, run the following commands:

> python teampicker.py

Run using flask

Set environment variables:

Variable Value
FLASK_APP src.team_picker:create_app({})
See Setting environment variables.

From a Terminal Window, run the following commands:

> flask run 

See Run The Application for other operating systems.

Run in debug mode

Note: To run with debug mode enabled specify the --debug option

> flask run --debug 

Test

Unit Test

A number of unit tests are available in the test folder. The tests are performed against an in-memory sqlite database.

From a Terminal Window, run the following commands to run all tests:

For Linux and Mac:                            For Windows:
$ cd /path/to/project/test                    > cd \path\to\project\test

Set python path, see Set python path.

> python -m test_all

Alternatively, to run tests individually:

Test Command
Roles database tests python -m test_roles
Teams database tests python -m test_teams
Users database tests python -m test_users
Matches database tests python -m test_matches
Users UI tests python -m test_user_setup_ui
Matches UI tests python -m test_match_ui

Application Operation

Once the application has been set up as outlined in Getting Started, functionality can be verified locally. A number of Pre-configured users are available on the Auth0 service as a convenience, however these users need to be configured in the application database before use. User setup using Postman allows the swift completion of the setup of the Pre-configured users. Alternatively, they may be setup using the process outlined in Additional users.

Pre-configured users

The following users have been pre-configured on the Auth0 service:

Email Password First name Surname Role Team
m1@team1.com Manager1! Manny Uno Manager Team 1
p1@team1.com Player1! Patrik Einer Player "
p2@team1.com Player2! Pat Ceann Player "
p3@team1.com Player3! Patrice Un Player "
m2@team2.com Manager2! Manfred Dos Manager Team 2
j1@team2.com Player1! Johann Zwei Player "
j2@team2.com Player2! Sean Do Player "
j3@team2.com Player3! Jean Deux Player "
m3@team3.com Manager3! Mildred Tres Manager Team 3
s1@team3.com Player1! Joanna Drei Player "
s2@team3.com Player2! Dearbhla Triur Player "
s3@team3.com Player3! Jean Trois Player "

The Auth0 login credentials are the specified email and password. The first name, surname, role and team are suggestions.

User setup using Postman

To expedite the setup of these users on a new database, the Postman collection Udacity FSWD TeamPicker.postman_collection.json is available. The manager user's data is available in managers.json, and player's in players.json.

The application must be started with Disable server-side sessions option.

When running as a script:

> python teampicker.py --postman_test

or passed via the FLASK_APP environment variable.

  FLASK_APP=src.team_picker:create_app({"postman_test":True})
Setup managers
  • Load Udacity FSWD TeamPicker.postman_collection.json into Postman.
  • Open the collection and select the collection Variables tab. Set the run_mode variable to iteration, and save if necessary.
  • Select the manager setup folder from the collection.
  • Click the Run button to open the Collection Runner.
  • Click the Select file button, then browse to and select the managers.json file.
  • Click the Run Udacity FSWD TeamPicker button, to run the requests.
  • All the folder requests will run 3 times, once for each manager.

The requests should be run in the listed order. Failure to do so will result in incorrect user setup.

Setup players

Follow the same procedure as for Setup managers, except for using the player setup folder from the collection, and the players.json data file. All the folder requests will run 9 times, once for each player.

Please see Running collections with data files for more information.

Individual requests in Postman collection

In order to send individual requests from Udacity FSWD TeamPicker.postman_collection.json rather than the running in the listed order:

  • Load Udacity FSWD TeamPicker.postman_collection.json into Postman.
  • Open the collection and select the collection Variables tab. Set the run_mode variable to individual.
  • Set the username,password,firstname,surname,role_name and team_name appropriately in order to pass response tests.
  • Save the collection variable changes.

Additional users

Additional users may be added as required.

  • On the application home screen, click the Login or sign-up button.
  • Select the Sign up link, and enter a username (email address) and password, and click Register.
  • Authorise the application to access the user's new account.
  • Enter a name and surname, and select a role on the Create user screen, and click Create.
  • Manager's must enter a team name on the Create team screen.
  • Player's must select an existing team on the Set team screen.

Usage

The functionality available depends on the user's role.

Role functionality

Functionality Manager Player
Login
Logout
List matches
Search matches
Create/update matches
Make match selections
View match selections
Confirm match selections

Login

On the application home screen, click the Login or sign-up button, and enter username and password. Notifications for any actions which the user needs to perform are displayed on the Home screen, e.g., if a player need to confirm availability for a match.

Logout

Click the Logout button on the top navigation bar.

List matches

Click Matches on the top navigation bar, and select List from the dropdown menu. All the matches for the user's team will be listed.

Search matches

Click Matches on the top navigation bar, and select Search Match from the dropdown menu. Enter search criteria based on opposition and/or date. All the matches for the user's team satisfying the criteria will be listed.

Create/update matches

Create matches

Click Matches on the top navigation bar, and select New Match from the dropdown menu. The match venue, opposition and start time must be entered.

Update matches

Click Edit button corresponding to the match in the matches listing. The match venue, opposition, start time, score and final result values may be updated.

Make match selections

Click Selections button corresponding to the match in the matches listing. A list of all players registered for the manager's team will be displayed. Click on the Selected checkbox to change their selected status.

View match selections

Click Selections button corresponding to the match in the matches listing. A list of all players registered for the user's team will be displayed, including the confirmation status of any who have confirmed their availability.

Confirm match selections

Click Selections button corresponding to the match in the matches listing. A list of all players registered for the player's team will be displayed. In the event the player has been selected for the match, they can confirm their availability by clicking on the Confirm, Unsure or Not available buttons.

JWT

Click JWT on the top navigation bar, to display the JWT token for the currently logged-in user.