This lab shall take you through the initial steps of your project.

Firstly you shall need a github organization for your group. You can have a member create one from the github homepage.

Select the free option then complete the organization setup at the next step.

After the organization is created you can navigate to the teams tab and invite your group members.

Next create your repository from the flask mvc template under your organization.

In your repository's setting you navigate to the collaborators section and ensure your group members are added with write access.

It's a good idea to deploy code as soon as possible so you can know when future code commits break your deployed application. Next login to render.com and follow the same deployment steps as covered in the deployment lab.

Software projects should be planned. Good planning and documentation can ensure all the developers are on the same page with respect to requirements, specifications and design decisions made by the team.

The remainder of the lab will be on the following case study.

Problem Description

A game store wishes to allow customers to rent games from each other.

Solution Description

A web app to manage rentals, make rentals and handle returns and payments.

Features

  1. User Account
  2. View Game Catalog
  3. Borrow games, limited to collateral
  4. Submit games for rental

After the minimal viable product is decided on, wireframing is a good step to take next to visualize the product. The following UI design was done using excalidraw. Note only a low fidelity prototype is required. Wireframe diagrams only.

Next your model design should be created based on the requirements of the problem. It should encapsulate features, constraints and business rules of the application.

MVP Features

A listing is a copy of a game submitted to the pool, it has a customer owner and can be rented multiple times once returned between rentals. Owners can control the price of their listing.

After your model implementation starts, you can plan a minimal list of controllers to implement that will cover the main features of the application. At this time it is good to acknowledge any assumptions, business rules and constraints as they will directly affect how certain implementations are made.

Business Rules

Constraints

Considerations and limitations of the operating environment of the client that would directly impact the solution.

Assumptions/Feasibility

General technologically agnostic requirements that must be met for the solution to be feasible.

Implementation

Finally the list of controllers are as follows. Note auth.login() is the package path to the login() function defined in /controllers/auth.py.

Feature

Controller

Description

User Account

auth.login(username, password)

Authenticates a user

user.create_customer(username, password)

Creates a customer

user.create_staff(username, password)

Creates a staff member

Game Rental Catalogue

listing.get_avaiable_listings()

Gets all available game listings

Borrow Game

rentals.rent_game(userId, listingid)

Updates a given listing to unavailable and creates a rental for the given user

Submit Games for rental

listing.list_game(userId, gameId, condition, price)

Creates a game listing by a given user

Log Payment

payments.create_rental_payment(userId, rentalId, amount)

Creates a payment for a specified rental and user

Return Rental

rentals.return_rental(rentalId)

Updates the return date of a given rental and updates the corresponding listing to available and create a rental payment including any late fees

After models and controllers are planned you can then proceed to create a gitpod workspace from your repo to begin adding implementation.

You can view the code for this project at the following link

Game Rental App Repo

Note how the models are implemented according to the specification.

Next, various controllers were implemented.

Note how for most models there is a controller with the same name, this would also happen for views. for e.g as there is a models/user.py you can expect there will be a user controller (controllers/user.py) as well as a collection of routes in a user view (views/user.py).

The implementation of auth.login is shown below.

controllers/auth.py

from flask_login import login_user
from App.models import User, Staff, Customer


def login(username, password):
   staff = Staff.query.filter_by(username=username).first()
   if staff and staff.check_password(password):
       return staff
   customer = Customer.query.filter_by(username=username).first()
   if customer and customer.check_password(password):
       return customer
   return None

In this particular project there is the Staff and Customer user class so the login controller would need to query both tables.

controllers/user.py

def create_staff(username, password):
    newuser = Staff(username=username, password=password)
    try:
        db.session.add(newuser)
        db.session.commit()
        return newuser
    except:
        return None

def create_customer(username, password):
    newuser = Customer(username=username, password=password)
    try:
        db.session.add(newuser)
        db.session.commit()
        return newuser
    except:
        return None

def get_staff(id):
    return Staff.query.get(id)

def get_customer(id):
    return Customer.query.get(id)

We also create a get_staff()/ get_customer() to test our create controllers.

Often teams may choose to split up work between controllers and view logic, thus it is ideal to be able to test a controller without needing to wait on UI code.

Using cli commands is a great way to achieve this.If you look into the wsgi.py file you will see the following commands for creating and printing a list of customer objects.

/wsgi.py

from App.controllers import ( 
  create_customer, 
  get_all_customers 
)

#...

customer_cli = AppGroup('customer', help='User object commands') 

# Then define the command and any parameters and annotate it with the group (@)
@customer_cli.command("create", help="Creates a customer")
@click.argument("username", default="rob")
@click.argument("password", default="robpass")
def create_user_command(username, password):
    create_customer(username, password)
    print(f'{username} created!')

# this command will be : flask user create bob bobpass

@customer_cli.command("list", help="Lists customers in the database")
def list_user_command():
    print(get_all_customers())

app.cli.add_command(customer_cli) # add the group to the cli

From there we can test the controllers by invoking the corresponding commands.

From here the UI team members can confidently reuse these controllers in their views.

In the same wsgi.py file you should also see commands for creating and listing listings. We can use the get_all_listings() controller in our index view route to implement the first page of the application.

views/index.py

from flask import Blueprint, redirect, render_template, request, send_from_directory

index_views = Blueprint('index_views', __name__, template_folder='../templates')
from App.controllers import (get_all_listings)

@index_views.route('/', methods=['GET'])
def index_page():
    listings = get_all_listings()
    return render_template('index.html', listings=listings)

After creating some listings on the cli we can see them rendered on our index page according to our wireframe design.

These changes can then be pushed to a branch, reviewed and merged to main so that the changes can finally be seen on the deployed production application.

Thus concludes the lab, good luck in your projects!