Skip to content

Commit

Permalink
Refactor: organize application as a package (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
angela-tran authored Sep 7, 2022
2 parents ac6d520 + fd1c915 commit 06037dd
Show file tree
Hide file tree
Showing 18 changed files with 266 additions and 236 deletions.
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
FLASK_APP=eligibility_server/app.py
ELIGIBILITY_SERVER_SETTINGS=../config/sample.py
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ jobs:

- name: Test with pytest
run: |
python setup.py
flask init-db
coverage run -m pytest
coverage report -m
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ __pycache__/
.env
config/*
!config/sample.py
eligibility_server.egg-info
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY bin/ bin/
COPY eligibility_server/ eligibility_server/
COPY *.py .
COPY README.md .

# install source as a package
RUN pip install -e .

# start app
ENTRYPOINT ["/bin/bash"]
Expand Down
2 changes: 1 addition & 1 deletion bin/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ set -eux

# run database migrations

python setup.py
flask init-db
9 changes: 4 additions & 5 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ Once you clone the repository locally, open it within VS Code, which will prompt
2. Start the `eligibility-server` Flask app and database with `F5`
3. Now you can run tests from the container.

Starting the Dev Container will run `bin/init.sh`, which runs `setup.py` and starts the Flask app. The `setup.py` script creates the database and imports and saves users
based on the configured settings.
Starting the Dev Container will run `bin/init.sh`, which runs a command to initialize the database. More specifically, it creates the database and imports and saves users based on the configured settings.

## Run tests

Expand All @@ -80,16 +79,16 @@ The test suite runs against every pull request via a GitHub Action.

In testing the database, you may need to teardown the database and restart a database from scratch.

The teardown script removes all users and drops the database. To tear down the database, run:
The command below will remove all users and drop the database:

```bash
python teardown.py
flask drop-db
```

To set up the database with a new import file or other configuration variables, after making any new environment variable changes, run:

```bash
python setup.py
flask init-db
```

## Run and develop the Documentation
Expand Down
19 changes: 4 additions & 15 deletions eligibility_server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

from flask import Flask, jsonify, make_response
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from flask.logging import default_handler

from .verify import Verify
from .keypair import get_server_public_key
from eligibility_server import db
from eligibility_server.verify import Verify
from eligibility_server.keypair import get_server_public_key

app = Flask(__name__)
app.config.from_object("eligibility_server.settings")
Expand Down Expand Up @@ -74,18 +74,7 @@ def internal_server_error(error):
api = Api(app)
api.add_resource(Verify, "/verify")

db = SQLAlchemy(app)


class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
sub = db.Column(db.String, unique=True, nullable=False)
name = db.Column(db.String, unique=True, nullable=False)
types = db.Column(db.String, unique=False, nullable=False)

def __repr__(self):
return "<User %r>" % self.sub

db.init_app(app)

if __name__ == "__main__":
app.run(host=app.config["HOST"], debug=app.config["DEBUG_MODE"], port="8000") # nosec
62 changes: 0 additions & 62 deletions eligibility_server/database.py

This file was deleted.

17 changes: 17 additions & 0 deletions eligibility_server/db/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import logging

from flask_sqlalchemy import SQLAlchemy

logger = logging.getLogger(__name__)


db = SQLAlchemy()


def init_app(app):
db.init_app(app)

from .setup import init_db_command, drop_db_command

app.cli.add_command(init_db_command)
app.cli.add_command(drop_db_command)
11 changes: 11 additions & 0 deletions eligibility_server/db/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from eligibility_server.db import db


class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
sub = db.Column(db.String, unique=True, nullable=False)
name = db.Column(db.String, unique=True, nullable=False)
types = db.Column(db.String, unique=False, nullable=False)

def __repr__(self):
return "<User %r>" % self.sub
95 changes: 95 additions & 0 deletions eligibility_server/db/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import csv
import json

import click
from flask import current_app
from flask_sqlalchemy import inspect

from eligibility_server.db.models import db, User


@click.command("init-db")
def init_db_command():
with current_app.app_context():
inspector = inspect(db.engine)

if inspector.get_table_names():
click.echo("Tables already exist.")
if User.query.count() == 0:
import_users()
else:
click.echo("User table already has data.")
else:
click.echo("Creating table...")
db.create_all()
click.echo("Table created.")

import_users()


def import_users():
"""
Imports user data to be added to database and saves user to database
Users can be imported from either a JSON file or CSV file, as configured
with settings. CSV files take extra setting configurations:
CSV_DELIMITER, CSV_NEWLINE, CSV_QUOTING, CSV_QUOTECHAR
"""

file_path = current_app.config["IMPORT_FILE_PATH"]
click.echo(f"Importing users from {file_path}")

file_format = file_path.split(".")[-1]

if file_format == "json":
with open(file_path) as file:
data = json.load(file)["users"]
for user in data:
save_users(user, data[user][0], str(data[user][1]))
elif file_format == "csv":
with open(file_path, newline=current_app.config["CSV_NEWLINE"], encoding="utf-8") as file:
data = csv.reader(
file,
delimiter=current_app.config["CSV_DELIMITER"],
quoting=int(current_app.config["CSV_QUOTING"]),
quotechar=current_app.config["CSV_QUOTECHAR"],
)
for user in data:
save_users(user[0], user[1], user[2])
else:
click.echo(f"Warning: File format is not supported: {file_format}")

click.echo(f"Users added: {User.query.count()}")


def save_users(sub: str, name: str, types: str):
"""
Add users to the database User table
@param sub - User's sub
@param name - User's name
@param types - Types of eligibilities, in a stringified list
"""

item = User(sub=sub, name=name, types=types)
db.session.add(item)
db.session.commit()


@click.command("drop-db")
def drop_db_command():
with current_app.app_context():
inspector = inspect(db.engine)

if inspector.get_table_names():
try:
click.echo(f"Users to be deleted: {User.query.count()}")
User.query.delete()
db.session.commit()
except Exception as e:
click.echo("Failed to query for Users", e)

db.drop_all()
click.echo("Database dropped.")
else:
click.echo("Database does not exist.")
2 changes: 1 addition & 1 deletion eligibility_server/keypair.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from jwcrypto import jwk
import requests

from . import app
from eligibility_server import app


logger = logging.getLogger(__name__)
Expand Down
Loading

0 comments on commit 06037dd

Please sign in to comment.