Skip to content

Commit fd7c78e

Browse files
authored
Merge pull request #114 from ComputerScienceHouse/develop
Packet version 3.1.1
2 parents 87d6fb3 + c6e9231 commit fd7c78e

22 files changed

+493
-347
lines changed

README.md

Lines changed: 94 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,113 @@
1-
CSH Web Packet
2-
==============
1+
# CSH Web Packet
32

43
[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/)
54
[![Build Status](https://travis-ci.org/ComputerScienceHouse/packet.svg?branch=develop)](https://travis-ci.org/ComputerScienceHouse/packet)
65

7-
Web Packet is used by CSH to facilitate the evaluations of our members and keep track of packet signatures on the web
6+
Packet is used by CSH to facilitate the freshmen packet portion of our introductory member evaluation process. This is
7+
the second major iteration of packet on the web. The first version was
8+
[Tal packet](https://github.com/TalCohen/CSHWebPacket).
89

9-
Authorization
10-
-------------
10+
## Setup
11+
**Requires Python 3.6 or newer.**
1112

12-
Authentication happens via pyOIDC with CSH SSO, authenticating as the user who is viewing the page.
13-
We have two different realms, and the site changes depending which realm is in use.
13+
To get the server working you'll just need the Python dependencies and some secrets. There will be some UI issues due
14+
to missing assets though. To solve that you'll want to set up the front end dependencies or download a copy of the
15+
current assets from prod.
1416

15-
The server uses heavy caching via lru_cache to speed up the results as much as possible
17+
Alternatively, you can set up a Docker container using `Dockerfile`. This is what's used in prod so it's the most
18+
reliable method.
1619

17-
Setup
18-
------
20+
### Python dependencies
21+
Use `pip3 install -r requirements.txt` to install the required python dependencies. A
22+
[venv](https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments) is *highly*
23+
recommended.
1924

20-
For local development setup follow these steps:
25+
If 1 or more of the packages fail to install the likely issue is missing header files for the libraries with native C
26+
components. See the contents of `Dockerfile` for the Linux packages that you'll need. On windows it's a bit more of a
27+
pain. Try using [WSL](https://docs.microsoft.com/en-us/windows/wsl/about) or finding a pre-compiled wheel from a
28+
trustworthy source.
2129

22-
1. ```pip install -r requirements.txt```
23-
2. `Create config.py` or set environment variables
24-
- Several of these variables require keys and information, please reach out to an RTP for testing information
25-
3. Run `wsgi.py`
30+
### Frontend dependencies
31+
To build any of the frontend dependencies you're going to need [node](https://nodejs.org/),
32+
[npm](https://www.npmjs.com/get-npm), and [yarn](https://yarnpkg.com/).
2633

34+
Make sure your system is also capable of building with [Sass](https://sass-lang.com/). To download all node
35+
dependencies run.
36+
```bash
37+
yarn install
38+
```
39+
40+
Following the install, you should be able to run `gulp`
41+
```bash
42+
gulp production
43+
```
44+
45+
If it doesn't work for some reason, you may have to globally install gulp through npm
46+
```bash
47+
npm install -g gulp
48+
```
49+
50+
### Secrets and configuration
51+
Packet supports 2 primary configuration methods:
52+
1. Environment variables - See `config.env.py` for the expected names and default values.
53+
2. Pyfile config - Create a `config.py` file in the root directory of the project and set variables to override the
54+
values in `config.env.py`.
55+
56+
Both methods can be used at the same time, though Pyfile config will take priority over environment variables.
57+
58+
**Required configuration values:**
59+
* `SQLALCHEMY_DATABASE_URI` - Must be set to a valid [SQLAlchemy DB URI](http://flask-sqlalchemy.pocoo.org/2.3/config/#connection-uri-format).
60+
A dev database for the project is hosted by CSH. Contact a current maintainer of packet for the details.
61+
* `LDAP_BIND_DN` - Must point to a valid CSH account on LDAP. Use the form
62+
`uid={username},cn=users,cn=accounts,dc=csh,dc=rit,dc=edu`.
63+
* `LDAP_BIND_PASS` - The password for that CSH account.
64+
* `SECRET_KEY` - Use a sufficiently long random string here. The `flask create-secret` command can generate a good one
65+
for you.
66+
* `OIDC_CLIENT_SECRET` - Required to use CSH auth. Contact a current maintainer of packet for the details.
2767

28-
Commands
29-
--------
68+
To switch between OIDC realms you'll need to set the modify the following values:
69+
* `OIDC_CLIENT_SECRET` - Unique to each realm. Again, contact a current maintainer of packet for the details.
70+
* `OIDC_ISSUER` - The OIDC issuer URL.
71+
* `REALM` - Set to `"csh"` or `"intro"` depending on the realm you want.
3072

31-
The flask CLI provides all the methods needed to setup a packet and a packet season
73+
By default `OIDC_ISSUER` and `REALM` are configured for the CSH members realm.
3274

75+
## Usage
76+
To run packet using the flask dev server use this command:
77+
```bash
78+
python3 wsgi.py
3379
```
34-
create-packets Creates a new packet season for each of the freshmen in the given CSV.
35-
create-secret Generates a securely random token.
36-
db Perform database migrations.
37-
ldap-sync Updates the upper and misc sigs in the DB to match ldap.
38-
sync-freshmen Updates the freshmen entries in the DB to match the given CSV.
39-
fetch-results Fetches and prints the results from a given packet season.
80+
The Flask debug mode flag can be set using via the config system explained above.
81+
82+
Alternative you can run it through [gunicorn](https://gunicorn.org/) using this command:
83+
```bash
84+
gunicorn -b :8000 packet:app --access-logfile -
85+
```
86+
87+
### CLI
88+
Packet makes use of the Flask CLI for exposing functionality to devs and admins. This is primarily designed to be used
89+
locally with the target DB set via the server's config values.
90+
91+
To use the CLI just set the project up as normal and then run the `flask` command in the project's root directory.
92+
It'll automatically load up the app and show you a list of available commands. For more details on a particular command
93+
use the help flag like this:
94+
```bash
95+
flask {command} --help
4096
```
4197

42-
Code Standards
43-
------------
98+
**WARNING:** Be sure to double check which DB you're pointed at when using one of the admin or DB commands.
4499

45-
Use Pylint to ensure your code follows standards. Commits will be pylinted by Travis CI, if your
46-
build fails you must fix whatever it tells you is wrong before it will be merged.
100+
All DB commands are from the `Flask-Migrate` library and are used to configure DB migrations through Alembic. See their
101+
docs [here](https://flask-migrate.readthedocs.io/en/latest/) for details.
102+
103+
## Code standards
104+
This project is configured to use Pylint. Commits will be pylinted by Travis CI and if the score drops your build will
105+
fail blocking you from merging. To make your life easier just run it before making a PR.
106+
107+
To run pylint use this command:
108+
```bash
109+
pylint packet
110+
```
47111

48-
To check locally, run ```pylint packet```
112+
All python files should have a top-level docstring explaining the contents of the file and complex functions should
113+
have docstrings explaining any non-obvious portions.

config.env.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"""
2+
Default configuration settings and environment variable based configuration logic
3+
See the readme for more information
4+
"""
5+
16
from os import environ
27

38
# Flask config
@@ -7,6 +12,9 @@
712
SERVER_NAME = environ.get("PACKET_SERVER_NAME", IP + ":" + PORT)
813
SECRET_KEY = environ.get("PACKET_SECRET_KEY", "PLEASE_REPLACE_ME")
914

15+
# Logging config
16+
LOG_LEVEL = environ.get("PACKET_LOG_LEVEL", "INFO")
17+
1018
# OpenID Connect SSO config
1119
REALM = environ.get("PACKET_REALM", "csh")
1220

@@ -21,3 +29,6 @@
2129
# LDAP config
2230
LDAP_BIND_DN = environ.get("PACKET_LDAP_BIND_DN", None)
2331
LDAP_BIND_PASS = environ.get("PACKET_LDAP_BIND_PASS", None)
32+
33+
# Slack URL for pushing to #general
34+
SLACK_WEBHOOK_URL = environ.get("PACKET_SLACK_URL", None)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Remove essays
2+
3+
Revision ID: fe83600ef3fa
4+
Revises: 0eeabc7d8f74
5+
Create Date: 2018-10-22 21:55:15.257440
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'fe83600ef3fa'
14+
down_revision = '0eeabc7d8f74'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.drop_column('packet', 'info_events')
22+
op.drop_column('packet', 'info_eboard')
23+
op.drop_column('packet', 'info_achieve')
24+
# ### end Alembic commands ###
25+
26+
27+
def downgrade():
28+
# ### commands auto generated by Alembic - please adjust! ###
29+
op.add_column('packet', sa.Column('info_achieve', sa.TEXT(), autoincrement=False, nullable=True))
30+
op.add_column('packet', sa.Column('info_eboard', sa.TEXT(), autoincrement=False, nullable=True))
31+
op.add_column('packet', sa.Column('info_events', sa.TEXT(), autoincrement=False, nullable=True))
32+
# ### end Alembic commands ###

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"title": "CSH Packet",
33
"name": "csh-packet",
4-
"version": "3.1.0",
5-
"description": "A webpacket for CSH",
4+
"version": "3.1.1",
5+
"description": "A web app implementation of the CSH introductory packet.",
66
"bugs": {
77
"url": "https://github.com/ComputerScienceHouse/packet/issues",
88
"email": "[email protected]"
99
},
1010
"license": "MIT",
11-
"author": "Devin Matte",
1211
"contributors": [
13-
"Devin Matte (https://devinmatte.com/)"
12+
"Devin Matte (https://devinmatte.com/)",
13+
"Joel Eager (https://github.com/JoelEager)"
1414
],
1515
"repository": {
1616
"type": "git",

packet/__init__.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,41 @@
11
"""
2-
The application setup and initialization code lives here.
2+
The application setup and initialization code lives here
33
"""
44

55
import os
6+
import logging
7+
import json
68

79
import csh_ldap
810
from flask import Flask
911
from flask_migrate import Migrate
1012
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
1113
from flask_sqlalchemy import SQLAlchemy
1214

13-
from ._version import __version__
14-
1515
app = Flask(__name__)
1616

1717
# Load default configuration and any environment variable overrides
18-
app.config.from_pyfile(os.path.join(os.getcwd(), "config.env.py"))
18+
_root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
19+
app.config.from_pyfile(os.path.join(_root_dir, "config.env.py"))
1920

2021
# Load file based configuration overrides if present
21-
if os.path.exists(os.path.join(os.getcwd(), "config.py")):
22-
app.config.from_pyfile(os.path.join(os.getcwd(), "config.py"))
22+
_pyfile_config = os.path.join(_root_dir, "config.py")
23+
if os.path.exists(_pyfile_config):
24+
app.config.from_pyfile(_pyfile_config)
25+
26+
# Fetch the version number from the npm package file
27+
with open(os.path.join(_root_dir, "package.json")) as package_file:
28+
app.config["VERSION"] = json.load(package_file)["version"]
2329

24-
app.config["VERSION"] = __version__
30+
# Logger configuration
31+
logging.getLogger().setLevel(app.config["LOG_LEVEL"])
32+
app.logger.info("Launching packet v" + app.config["VERSION"])
33+
app.logger.info("Using the {} realm".format(app.config["REALM"]))
2534

2635
# Initialize the extensions
2736
db = SQLAlchemy(app)
2837
migrate = Migrate(app, db)
38+
app.logger.info("SQLAlchemy pointed at " + repr(db.engine.url))
2939

3040
auth = OIDCAuthentication(app, issuer=app.config["OIDC_ISSUER"], client_registration_info={
3141
"client_id": app.config["OIDC_CLIENT_ID"],
@@ -36,6 +46,8 @@
3646
# LDAP
3747
_ldap = csh_ldap.CSHLDAP(app.config["LDAP_BIND_DN"], app.config["LDAP_BIND_PASS"])
3848

49+
app.logger.info("OIDCAuth and LDAP configured")
50+
3951
# pylint: disable=wrong-import-position
4052
from . import models
4153
from . import context_processors
@@ -46,3 +58,5 @@
4658
from .routes import upperclassmen
4759
else:
4860
from .routes import freshmen
61+
62+
app.logger.info("Routes registered")

packet/_version.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)