Skip to content

Commit

Permalink
Merge pull request #114 from ComputerScienceHouse/develop
Browse files Browse the repository at this point in the history
Packet version 3.1.1
  • Loading branch information
devinmatte authored Nov 5, 2018
2 parents 87d6fb3 + c6e9231 commit fd7c78e
Show file tree
Hide file tree
Showing 22 changed files with 493 additions and 347 deletions.
123 changes: 94 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,113 @@
CSH Web Packet
==============
# CSH Web Packet

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

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

Authorization
-------------
## Setup
**Requires Python 3.6 or newer.**

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

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

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

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

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

Make sure your system is also capable of building with [Sass](https://sass-lang.com/). To download all node
dependencies run.
```bash
yarn install
```

Following the install, you should be able to run `gulp`
```bash
gulp production
```

If it doesn't work for some reason, you may have to globally install gulp through npm
```bash
npm install -g gulp
```

### Secrets and configuration
Packet supports 2 primary configuration methods:
1. Environment variables - See `config.env.py` for the expected names and default values.
2. Pyfile config - Create a `config.py` file in the root directory of the project and set variables to override the
values in `config.env.py`.

Both methods can be used at the same time, though Pyfile config will take priority over environment variables.

**Required configuration values:**
* `SQLALCHEMY_DATABASE_URI` - Must be set to a valid [SQLAlchemy DB URI](http://flask-sqlalchemy.pocoo.org/2.3/config/#connection-uri-format).
A dev database for the project is hosted by CSH. Contact a current maintainer of packet for the details.
* `LDAP_BIND_DN` - Must point to a valid CSH account on LDAP. Use the form
`uid={username},cn=users,cn=accounts,dc=csh,dc=rit,dc=edu`.
* `LDAP_BIND_PASS` - The password for that CSH account.
* `SECRET_KEY` - Use a sufficiently long random string here. The `flask create-secret` command can generate a good one
for you.
* `OIDC_CLIENT_SECRET` - Required to use CSH auth. Contact a current maintainer of packet for the details.

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

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

## Usage
To run packet using the flask dev server use this command:
```bash
python3 wsgi.py
```
create-packets Creates a new packet season for each of the freshmen in the given CSV.
create-secret Generates a securely random token.
db Perform database migrations.
ldap-sync Updates the upper and misc sigs in the DB to match ldap.
sync-freshmen Updates the freshmen entries in the DB to match the given CSV.
fetch-results Fetches and prints the results from a given packet season.
The Flask debug mode flag can be set using via the config system explained above.

Alternative you can run it through [gunicorn](https://gunicorn.org/) using this command:
```bash
gunicorn -b :8000 packet:app --access-logfile -
```

### CLI
Packet makes use of the Flask CLI for exposing functionality to devs and admins. This is primarily designed to be used
locally with the target DB set via the server's config values.

To use the CLI just set the project up as normal and then run the `flask` command in the project's root directory.
It'll automatically load up the app and show you a list of available commands. For more details on a particular command
use the help flag like this:
```bash
flask {command} --help
```

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

Use Pylint to ensure your code follows standards. Commits will be pylinted by Travis CI, if your
build fails you must fix whatever it tells you is wrong before it will be merged.
All DB commands are from the `Flask-Migrate` library and are used to configure DB migrations through Alembic. See their
docs [here](https://flask-migrate.readthedocs.io/en/latest/) for details.

## Code standards
This project is configured to use Pylint. Commits will be pylinted by Travis CI and if the score drops your build will
fail blocking you from merging. To make your life easier just run it before making a PR.

To run pylint use this command:
```bash
pylint packet
```

To check locally, run ```pylint packet```
All python files should have a top-level docstring explaining the contents of the file and complex functions should
have docstrings explaining any non-obvious portions.
11 changes: 11 additions & 0 deletions config.env.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
Default configuration settings and environment variable based configuration logic
See the readme for more information
"""

from os import environ

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

# Logging config
LOG_LEVEL = environ.get("PACKET_LOG_LEVEL", "INFO")

# OpenID Connect SSO config
REALM = environ.get("PACKET_REALM", "csh")

Expand All @@ -21,3 +29,6 @@
# LDAP config
LDAP_BIND_DN = environ.get("PACKET_LDAP_BIND_DN", None)
LDAP_BIND_PASS = environ.get("PACKET_LDAP_BIND_PASS", None)

# Slack URL for pushing to #general
SLACK_WEBHOOK_URL = environ.get("PACKET_SLACK_URL", None)
32 changes: 32 additions & 0 deletions migrations/versions/fe83600ef3fa_remove_essays.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Remove essays
Revision ID: fe83600ef3fa
Revises: 0eeabc7d8f74
Create Date: 2018-10-22 21:55:15.257440
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'fe83600ef3fa'
down_revision = '0eeabc7d8f74'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('packet', 'info_events')
op.drop_column('packet', 'info_eboard')
op.drop_column('packet', 'info_achieve')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('packet', sa.Column('info_achieve', sa.TEXT(), autoincrement=False, nullable=True))
op.add_column('packet', sa.Column('info_eboard', sa.TEXT(), autoincrement=False, nullable=True))
op.add_column('packet', sa.Column('info_events', sa.TEXT(), autoincrement=False, nullable=True))
# ### end Alembic commands ###
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"title": "CSH Packet",
"name": "csh-packet",
"version": "3.1.0",
"description": "A webpacket for CSH",
"version": "3.1.1",
"description": "A web app implementation of the CSH introductory packet.",
"bugs": {
"url": "https://github.com/ComputerScienceHouse/packet/issues",
"email": "evals@csh.rit.edu"
},
"license": "MIT",
"author": "Devin Matte",
"contributors": [
"Devin Matte (https://devinmatte.com/)"
"Devin Matte (https://devinmatte.com/)",
"Joel Eager (https://github.com/JoelEager)"
],
"repository": {
"type": "git",
Expand Down
28 changes: 21 additions & 7 deletions packet/__init__.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
"""
The application setup and initialization code lives here.
The application setup and initialization code lives here
"""

import os
import logging
import json

import csh_ldap
from flask import Flask
from flask_migrate import Migrate
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
from flask_sqlalchemy import SQLAlchemy

from ._version import __version__

app = Flask(__name__)

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

# Load file based configuration overrides if present
if os.path.exists(os.path.join(os.getcwd(), "config.py")):
app.config.from_pyfile(os.path.join(os.getcwd(), "config.py"))
_pyfile_config = os.path.join(_root_dir, "config.py")
if os.path.exists(_pyfile_config):
app.config.from_pyfile(_pyfile_config)

# Fetch the version number from the npm package file
with open(os.path.join(_root_dir, "package.json")) as package_file:
app.config["VERSION"] = json.load(package_file)["version"]

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

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

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

app.logger.info("OIDCAuth and LDAP configured")

# pylint: disable=wrong-import-position
from . import models
from . import context_processors
Expand All @@ -46,3 +58,5 @@
from .routes import upperclassmen
else:
from .routes import freshmen

app.logger.info("Routes registered")
1 change: 0 additions & 1 deletion packet/_version.py

This file was deleted.

Loading

0 comments on commit fd7c78e

Please sign in to comment.