Skip to content

Commit

Permalink
Merge pull request #240 from cubingusa/python3
Browse files Browse the repository at this point in the history
Rewrite website with python3
  • Loading branch information
timreyn authored Feb 24, 2022
2 parents c325e8a + 391b93b commit 0bd74a9
Show file tree
Hide file tree
Showing 345 changed files with 5,792 additions and 7,639 deletions.
5 changes: 5 additions & 0 deletions .env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ENV=DEV
WCA_CLIENT_ID='example-application-id'
WCA_CLIENT_SECRET='example-secret'
WCA_HOST='https://staging.worldcubeassociation.org'
SESSION_SECRET_KEY='12340987'
12 changes: 12 additions & 0 deletions .gcloudignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
^(.*/)?#.*#$
^(.*/)?.*~$
^(.*/)?.*\.py[co]$
^(.*/)?\..*$
external/bootstrap
__pycache__/
/src/
/lib/
.git/
.gitignore
env/
.env.dev
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@
*.swp
lib/*
.sass-cache/
src/static/css/
.local_storage/
env/

# Compiled CSS.
app/static/css/
src/static/css/

# Saved DB exports.
exports/
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,52 @@
You will need to install the following:
* [Google App Engine Python SDK](https://cloud.google.com/appengine/docs/flexible/python/download)
* [pip](https://pip.pypa.io/en/stable/)
* [sass](https://sass-lang.com/install)
* [virtualenv](https://virtualenv.pypa.io/en/latest/installation.html)

## Running app locally

If this is your first time running the CubingUSA website locally, follow the instructions in `doc/deploy.sh` to set up your local development server.

You can run the app locally by running the following two shell commands:
### sass

Run
```sh
./run_sass.sh
./dev_app.sh
```
This command will keep running, and watch for updates to the scss files.

### Setup Cloud Datastore

We use Google Cloud Datastore, which you will need to run locally. Run the command
```sh
gcloud beta emulators datastore start
```

### Run the app

Run the following commands in the same terminal:

Enable the virtualenv:
```sh
source env/bin/activate
```
Install python dependencies:
```sh
pip install -r requirements.txt
```
Configure the app to use the local datastore:
```sh
$(gcloud beta emulators datastore env-init)
```
Run the app:
```sh
gunicorn -b :8083 app:app
```

You can use the `ADMIN_WCA_ID` environment variable to make yourself an admin:
```sh
ADMIN_WCA_ID=2005REYN01 gunicorn -b :8083 app:app
```

## Deploying to staging
Expand Down
38 changes: 0 additions & 38 deletions admin.py

This file was deleted.

28 changes: 0 additions & 28 deletions admin.yaml

This file was deleted.

39 changes: 6 additions & 33 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
runtime: python27
api_version: 1
threadsafe: true
skip_files:
- ^(.*/)?#.*#$
- ^(.*/)?.*~$
- ^(.*/)?.*\.py[co]$
- ^(.*/)?\..*$
- external/bootstrap
- src/scss
runtime: python39
entrypoint: gunicorn -b :$PORT app:app

libraries:
- name: webapp2
version: latest
env_variables:
ENV: "PROD"
WCA_HOST: "https://www.worldcubeassociation.org"

handlers:
- url: /_ah/queue/deferred
script: google.appengine.ext.deferred.deferred.application
login: admin
- url: /static
static_dir: src/static
secure: always
- url: /scheduling
script: scheduling.app
secure: always
- url: /scheduling/.*
script: scheduling.app
secure: always
- url: /nationals/.*
script: nationals.app
secure: always
- url: /nationals
script: nationals.app
secure: always
- url: /.*
script: cubingusa.app
secure: always
script: auto
62 changes: 62 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import datetime
import logging
import os
import sys

from authlib.integrations.flask_client import OAuth
from dotenv import load_dotenv
from flask import Flask
import google.cloud.logging

from app.lib.secrets import get_secret

if os.path.exists('.env.dev'):
load_dotenv('.env.dev')

if os.environ.get('ENV') == 'PROD':
client = google.cloud.logging.Client()
client.setup_logging()
elif os.environ.get('ENV') == 'DEV' and 'gunicorn' in sys.argv[0]:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)


app = Flask(__name__)
app.secret_key = get_secret('SESSION_SECRET_KEY')
app.permanent_session_lifetime = datetime.timedelta(days=7)

wca_host = os.environ.get('WCA_HOST')
oauth = OAuth(app)
oauth.register(
name='wca',
client_id=get_secret('WCA_CLIENT_ID'),
client_secret=get_secret('WCA_CLIENT_SECRET'),
access_token_url=wca_host + '/oauth/token',
access_token_params=None,
authorize_url=wca_host + '/oauth/authorize',
authorize_params=None,
api_base_url=wca_host + '/api/v0/',
client_kwargs={'scope': 'public email'},
)

from app.handlers.admin import bp as admin_bp
from app.handlers.auth import create_bp as create_auth_bp
from app.handlers.champions_table import bp as champions_table_bp
from app.handlers.nationals import bp as nationals_bp
from app.handlers.regional import bp as regional_bp
from app.handlers.state_rankings import bp as state_rankings_bp
from app.handlers.static import bp as static_bp
from app.handlers.user import bp as user_bp

app.register_blueprint(admin_bp)
app.register_blueprint(create_auth_bp(oauth))
app.register_blueprint(champions_table_bp)
app.register_blueprint(nationals_bp)
app.register_blueprint(regional_bp)
app.register_blueprint(state_rankings_bp)
app.register_blueprint(static_bp)
app.register_blueprint(user_bp)
10 changes: 10 additions & 0 deletions app/handlers/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from flask import Blueprint

from app.handlers.admin.edit_championships import bp as edit_championships_bp
from app.handlers.admin.edit_users import bp as edit_users_bp
from app.handlers.admin.states import bp as states_bp

bp = Blueprint('admin', __name__, url_prefix='/admin')
bp.register_blueprint(edit_championships_bp)
bp.register_blueprint(edit_users_bp)
bp.register_blueprint(states_bp)
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
from google.appengine.ext import ndb
from flask import abort, Blueprint, redirect, render_template
from google.cloud import ndb

from src import common
from src.handlers.admin.admin_base import AdminBaseHandler
from src.jinja import JINJA_ENVIRONMENT
from src.models.championship import Championship
from src.models.region import Region
from src.models.state import State
from src.models.user import Roles
from src.models.wca.competition import Competition
from src.models.wca.country import Country
from app.lib import auth
from app.lib import common
from app.models.championship import Championship
from app.models.region import Region
from app.models.state import State
from app.models.user import Roles
from app.models.wca.competition import Competition
from app.models.wca.country import Country

class AddChampionshipHandler(AdminBaseHandler):
def get(self, competition_id, championship_type):
bp = Blueprint('edit_championships', __name__)
client = ndb.Client()

@bp.route('/add_championship/<competition_id>/<championship_type>')
def add_championship(competition_id, championship_type):
with client.context():
me = auth.user()
if not me or not me.HasAnyRole(Roles.AdminRoles()):
abort(403)
competition = Competition.get_by_id(competition_id)
if championship_type == 'national':
championship_id = Championship.NationalsId(competition.year)
Expand All @@ -33,19 +40,28 @@ def get(self, competition_id, championship_type):
championship.competition = competition.key
championship.put()
# TODO: if we changed a championship we should update champions and eligibilities.
self.redirect_to('edit_championships')
return redirect('/admin/edit_championships')


class DeleteChampionshipHandler(AdminBaseHandler):
def get(self, championship_id):
@bp.route('/delete_championship/<championship_id>')
def delete_championship(championship_id):
with client.context():
me = auth.user()
if not me or not me.HasAnyRole(Roles.AdminRoles()):
abort(403)
championship = Championship.get_by_id(championship_id)
championship.key.delete()
# TODO: if we changed a championship we should update champions and eligibilities.
self.redirect_to('edit_championships')
return redirect('/admin/edit_championships')


@bp.route('/edit_championships')
def edit_championships():
with client.context():
me = auth.user()
if not me or not me.HasAnyRole(Roles.AdminRoles()):
abort(403)

class EditChampionshipsHandler(AdminBaseHandler):
def get(self):
all_us_competitions = (
Competition.query(Competition.country == ndb.Key(Country, 'USA'))
.order(Competition.name)
Expand All @@ -65,21 +81,15 @@ def get(self):
.order(Championship.state)
.order(-Championship.year)
.fetch())
print len(national_championships), len(regional_championships), len(state_championships)

states = State.query().fetch()
regions = Region.query().fetch()

template = JINJA_ENVIRONMENT.get_template('admin/edit_championships.html')
self.response.write(template.render({
'c': common.Common(self),
'all_us_competitions': all_us_competitions,
'national_championships': national_championships,
'regional_championships': regional_championships,
'state_championships': state_championships,
'states': states,
'regions': regions,
}))

def PermittedRoles(self):
return Roles.AdminRoles()
return render_template('admin/edit_championships.html',
c = common.Common(),
all_us_competitions = all_us_competitions,
national_championships = national_championships,
regional_championships = regional_championships,
state_championships = state_championships,
states = states,
regions = regions)
Loading

0 comments on commit 0bd74a9

Please sign in to comment.