Compare commits
37 commits
meal-check
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7255ccebfd | ||
![]() |
02eb9b4220 | ||
![]() |
59266eb865 | ||
![]() |
fb2dd9032b | ||
![]() |
97f072ddb8 | ||
![]() |
cf725a2206 | ||
![]() |
0f4ef0b690 | ||
![]() |
b0a1e142cd | ||
![]() |
c73184060c | ||
![]() |
29cdcf1899 | ||
![]() |
3c40553b45 | ||
![]() |
36bb39a8a0 | ||
![]() |
fa55e10e5b | ||
![]() |
35c0197a40 | ||
![]() |
1857e15791 | ||
![]() |
f6b03460d9 | ||
![]() |
8a94de44c0 | ||
![]() |
3dff046e84 | ||
![]() |
0b3480dd52 | ||
![]() |
b7ca654bf1 | ||
![]() |
c47a46c204 | ||
![]() |
3a41dc6559 | ||
![]() |
9dd8c98c51 | ||
![]() |
fa6a9ee148 | ||
![]() |
6b48c30395 | ||
![]() |
476966bef5 | ||
![]() |
24384b2a35 | ||
![]() |
f1640493ec | ||
![]() |
9144ad89b0 | ||
![]() |
cd5e58fa59 | ||
![]() |
02b5ffa481 | ||
![]() |
6ba1313ea6 | ||
![]() |
f82aa08085 | ||
![]() |
a2e640f8f7 | ||
![]() |
18a1dcb0d1 | ||
![]() |
c863b4064f | ||
![]() |
b2c8f3a77a |
43 changed files with 3451 additions and 1300 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,7 +1,6 @@
|
||||||
resumes*/
|
resumes*/
|
||||||
resumes*.zip
|
resumes*.zip
|
||||||
config_hackWPI.py
|
config_hackWPI.py
|
||||||
config.py
|
|
||||||
admin/*.json
|
admin/*.json
|
||||||
admin/*.csv
|
admin/*.csv
|
||||||
|
|
||||||
|
@ -13,6 +12,8 @@ goathacks/config.py
|
||||||
sqldmp
|
sqldmp
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
|
||||||
### Bower ###
|
### Bower ###
|
||||||
bower_components
|
bower_components
|
||||||
|
|
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,4 +1,4 @@
|
||||||
[submodule "goathacks/templates/home"]
|
[submodule "goathacks/templates/home"]
|
||||||
path = goathacks/templates/home
|
path = goathacks/templates/home
|
||||||
url = https://github.com/WPI-ACM/Hack-WPI-Static
|
url = https://github.com/WPI-ACM/Hack-WPI-Static
|
||||||
branch = 2023-dev
|
branch = master
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -32,8 +32,14 @@ daemon:
|
||||||
@echo "--- STARTING UWSGI DAEMON ---"
|
@echo "--- STARTING UWSGI DAEMON ---"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo ""
|
@echo ""
|
||||||
source .venv/bin/activate && flask run
|
source .venv/bin/activate && flask --debug run
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "--- STARTING UWSGI DAEMON ---"
|
@echo "--- STARTING UWSGI DAEMON ---"
|
||||||
|
|
||||||
|
post_upgrade: upgrade_env run_migrations
|
||||||
|
# Make sure a tmp directory exists
|
||||||
|
@mkdir -p acmsite/tmp
|
||||||
|
# Create upload directory
|
||||||
|
@mkdir -p acmsite/uploads
|
||||||
|
|
||||||
|
|
30
config.py
Normal file
30
config.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from dotenv import load_dotenv, dotenv_values
|
||||||
|
|
||||||
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
load_dotenv(os.path.join(basedir, '.env'))
|
||||||
|
|
||||||
|
class Config():
|
||||||
|
TESTING = dotenv_values().get("TESTING") or False
|
||||||
|
DEBUG = dotenv_values().get("DEBUG") or False
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URI = dotenv_values().get("SQLALCHEMY_DATABASE_URI") or "postgresql://localhost/goathacks"
|
||||||
|
|
||||||
|
MAX_BEFORE_WAITLIST = int(dotenv_values().get("MAX_BEFORE_WAITLIST") or 1)
|
||||||
|
MCE_API_KEY = dotenv_values().get("MCE_API_KEY")
|
||||||
|
SECRET_KEY = dotenv_values().get("SECRET_KEY") or "bad-key-change-me"
|
||||||
|
|
||||||
|
UPLOAD_FOLDER = dotenv_values().get("UPLOAD_FOLDER") or "./uploads/"
|
||||||
|
|
||||||
|
DISCORD_LINK = dotenv_values().get("DISCORD_LINK") or None
|
||||||
|
|
||||||
|
# Mail server settings
|
||||||
|
MAIL_SERVER = dotenv_values().get("MAIL_SERVER") or "localhost"
|
||||||
|
MAIL_PORT = dotenv_values().get("MAIL_PORT") or 25
|
||||||
|
MAIL_USE_TLS = dotenv_values().get("MAIL_USE_TLS") or False
|
||||||
|
MAIL_USE_SSL = dotenv_values().get("MAIL_USE_SSL") or False
|
||||||
|
MAIL_USERNAME = dotenv_values().get("MAIL_USERNAME") or "dummy"
|
||||||
|
MAIL_PASSWORD = dotenv_values().get("MAIL_PASSWORD") or "dummy"
|
||||||
|
MAIL_DEFAULT_SENDER = dotenv_values().get("MAIL_DEFAULT_SENDER") or "GoatHacks Team <hack@wpi.edu>"
|
||||||
|
MAIL_SUPPRESS_SEND = dotenv_values().get("MAIL_SUPPRESS_SEND") or TESTING
|
|
@ -5,8 +5,13 @@ from flask_login import LoginManager
|
||||||
from flask_assets import Bundle, Environment
|
from flask_assets import Bundle, Environment
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from flask_mail import Mail, email_dispatched
|
from flask_mail import Mail, email_dispatched
|
||||||
|
from flask_bootstrap import Bootstrap5
|
||||||
|
from flask_font_awesome import FontAwesome
|
||||||
from flask_qrcode import QRcode
|
from flask_qrcode import QRcode
|
||||||
|
|
||||||
|
from config import Config
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
db = SQLAlchemy()
|
db = SQLAlchemy()
|
||||||
migrate = Migrate()
|
migrate = Migrate()
|
||||||
|
@ -14,12 +19,14 @@ login = LoginManager()
|
||||||
environment = Environment()
|
environment = Environment()
|
||||||
cors = CORS()
|
cors = CORS()
|
||||||
mail = Mail()
|
mail = Mail()
|
||||||
|
bootstrap = Bootstrap5()
|
||||||
|
font_awesome = FontAwesome()
|
||||||
qrcode = QRcode()
|
qrcode = QRcode()
|
||||||
|
|
||||||
def create_app():
|
def create_app(config_class=Config):
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
app.config.from_pyfile("config.py")
|
app.config.from_object(config_class)
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
migrate.init_app(app, db)
|
migrate.init_app(app, db)
|
||||||
|
@ -27,7 +34,9 @@ def create_app():
|
||||||
environment.init_app(app)
|
environment.init_app(app)
|
||||||
cors.init_app(app)
|
cors.init_app(app)
|
||||||
mail.init_app(app)
|
mail.init_app(app)
|
||||||
|
bootstrap.init_app(app)
|
||||||
qrcode.init_app(app)
|
qrcode.init_app(app)
|
||||||
|
font_awesome.init_app(app)
|
||||||
|
|
||||||
scss = Bundle('css/style.scss', filters='scss',
|
scss = Bundle('css/style.scss', filters='scss',
|
||||||
output='css/style.css')
|
output='css/style.css')
|
||||||
|
@ -75,6 +84,10 @@ def create_app():
|
||||||
def index():
|
def index():
|
||||||
return render_template("home/index.html")
|
return render_template("home/index.html")
|
||||||
|
|
||||||
|
@app.route("/index2.html")
|
||||||
|
def index2():
|
||||||
|
return render_template("home/index2.html")
|
||||||
|
|
||||||
# homepage assets
|
# homepage assets
|
||||||
@app.route("/assets/<path:path>")
|
@app.route("/assets/<path:path>")
|
||||||
def assets(path):
|
def assets(path):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import Blueprint, jsonify, redirect, render_template, request, url_for
|
from flask import Blueprint, current_app, jsonify, redirect, render_template, request, url_for
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from flask_mail import Message
|
from flask_mail import Message
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@ bp = Blueprint("admin", __name__, url_prefix="/admin")
|
||||||
from goathacks import db, mail as app_mail
|
from goathacks import db, mail as app_mail
|
||||||
from goathacks.admin import events
|
from goathacks.admin import events
|
||||||
|
|
||||||
@bp.route("/")
|
# Helper function for admin.home and admin.admin_list to render list of users.
|
||||||
@login_required
|
# This function was abstracted to promote code reuse.
|
||||||
def home():
|
def render_user_list(admin_list):
|
||||||
if not current_user.is_admin:
|
if not current_user.is_admin:
|
||||||
return redirect(url_for("dashboard.home"))
|
return redirect(url_for("dashboard.home"))
|
||||||
male_count = 0
|
male_count = 0
|
||||||
|
@ -21,7 +21,10 @@ def home():
|
||||||
waitlist_count = 0
|
waitlist_count = 0
|
||||||
total_count = 0
|
total_count = 0
|
||||||
shirt_count = {'XS': 0, 'S': 0, 'M': 0, 'L': 0, 'XL': 0}
|
shirt_count = {'XS': 0, 'S': 0, 'M': 0, 'L': 0, 'XL': 0}
|
||||||
hackers = db.session.execute(db.select(User)).scalars().all()
|
if(admin_list):
|
||||||
|
hackers = db.session.execute(db.select(User).where(User.is_admin)).scalars().all()
|
||||||
|
else:
|
||||||
|
hackers = db.session.execute(db.select(User).where(User.is_admin == False)).scalars().all()
|
||||||
schools = {}
|
schools = {}
|
||||||
|
|
||||||
for h in hackers:
|
for h in hackers:
|
||||||
|
@ -55,6 +58,17 @@ def home():
|
||||||
female_count=female_count, nb_count=nb_count,
|
female_count=female_count, nb_count=nb_count,
|
||||||
check_in_count=check_in_count, schools=schools)
|
check_in_count=check_in_count, schools=schools)
|
||||||
|
|
||||||
|
@bp.route("/")
|
||||||
|
@login_required
|
||||||
|
def home():
|
||||||
|
return render_user_list(False) # list users (not admins)
|
||||||
|
|
||||||
|
@bp.route("/admin_list")
|
||||||
|
@login_required
|
||||||
|
def admin_list():
|
||||||
|
return render_user_list(True) # list users (admins)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/mail")
|
@bp.route("/mail")
|
||||||
@login_required
|
@login_required
|
||||||
def mail():
|
def mail():
|
||||||
|
@ -62,8 +76,20 @@ def mail():
|
||||||
return redirect(url_for("dashboard.home"))
|
return redirect(url_for("dashboard.home"))
|
||||||
|
|
||||||
total_count = len(db.session.execute(db.select(User)).scalars().all())
|
total_count = len(db.session.execute(db.select(User)).scalars().all())
|
||||||
|
api_key = current_app.config["MCE_API_KEY"]
|
||||||
|
|
||||||
return render_template("mail.html", NUM_HACKERS=total_count)
|
return render_template("mail.html", NUM_HACKERS=total_count,
|
||||||
|
MCE_API_KEY=api_key)
|
||||||
|
|
||||||
|
@bp.route("/users")
|
||||||
|
@login_required
|
||||||
|
def users():
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return redirect(url_for("dashboard.home"))
|
||||||
|
|
||||||
|
users = User.query.all()
|
||||||
|
|
||||||
|
return render_template("users.html", users=users)
|
||||||
|
|
||||||
@bp.route("/send", methods=["POST"])
|
@bp.route("/send", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import flask
|
import flask
|
||||||
from flask import Response, render_template, redirect, request, url_for, flash
|
from flask import Response, render_template, redirect, request, url_for, flash, current_app
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from goathacks.admin import bp, forms
|
from goathacks.admin import bp, forms
|
||||||
from goathacks import db
|
from goathacks import db
|
||||||
from goathacks.models import Event
|
from goathacks.models import Event
|
||||||
|
|
||||||
import io, qrcode
|
import io, qrcode, datetime
|
||||||
import qrcode.image.pure
|
import qrcode.image.pure
|
||||||
|
|
||||||
@bp.route("/events")
|
@bp.route("/events")
|
||||||
|
@ -16,7 +16,86 @@ def list_events():
|
||||||
|
|
||||||
events = Event.query.all()
|
events = Event.query.all()
|
||||||
|
|
||||||
return render_template("events/list.html", events=events)
|
form = forms.EventForm()
|
||||||
|
|
||||||
|
return render_template("events/list.html", events=events, form=form)
|
||||||
|
|
||||||
|
@bp.route("/event/<int:id>/delete")
|
||||||
|
@login_required
|
||||||
|
def delete_event(id):
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return {"status": "error", "message": "Unauthorized"}
|
||||||
|
|
||||||
|
event = Event.query.filter_by(id=id).first()
|
||||||
|
|
||||||
|
if event is None:
|
||||||
|
return {"status": "error", "message": "Invalid event ID"}
|
||||||
|
|
||||||
|
db.session.delete(event)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return {"status": "success"}
|
||||||
|
|
||||||
|
@bp.route("/event/<int:id>")
|
||||||
|
@login_required
|
||||||
|
def event(id):
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return {"status": "error", "message": "Unauthorized"}
|
||||||
|
|
||||||
|
event = Event.query.filter_by(id=id).first()
|
||||||
|
|
||||||
|
if event is None:
|
||||||
|
return {"status": "error", "message": "Invalid event ID"}
|
||||||
|
|
||||||
|
return event.create_json()
|
||||||
|
|
||||||
|
@bp.route("/event/<int:id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def update_create_event(id):
|
||||||
|
if not current_user.is_admin:
|
||||||
|
flash("Unauthorized")
|
||||||
|
return redirect(url_for("dashboard.home"))
|
||||||
|
|
||||||
|
name = request.form.get('name')
|
||||||
|
description = request.form.get('description')
|
||||||
|
location = request.form.get('location')
|
||||||
|
start_day = request.form.get('start_day')
|
||||||
|
start_time = request.form.get('start_time')
|
||||||
|
end_day = request.form.get('end_day')
|
||||||
|
end_time = request.form.get('end_time')
|
||||||
|
start = datetime.datetime.combine(datetime.date.fromisoformat(start_day),
|
||||||
|
datetime.time.fromisoformat(start_time))
|
||||||
|
end = datetime.datetime.combine(datetime.date.fromisoformat(end_day),
|
||||||
|
datetime.time.fromisoformat(end_time))
|
||||||
|
category = request.form.get("category")
|
||||||
|
|
||||||
|
if id == 0:
|
||||||
|
# new event
|
||||||
|
e = Event(
|
||||||
|
name=name,
|
||||||
|
description=description,
|
||||||
|
location=location,
|
||||||
|
start_time=start,
|
||||||
|
category=category,
|
||||||
|
end_time=end)
|
||||||
|
db.session.add(e)
|
||||||
|
db.session.commit()
|
||||||
|
current_app.logger.info(f"{current_user} is creating a new event: {e.name}")
|
||||||
|
else:
|
||||||
|
e = Event.query.filter_by(id=id).first()
|
||||||
|
if e is None:
|
||||||
|
return {"status": "error", "message": "Invalid event ID"}
|
||||||
|
e.name = name
|
||||||
|
e.description = description
|
||||||
|
e.location = location
|
||||||
|
e.start_time = start
|
||||||
|
e.end_time = end
|
||||||
|
e.category=category
|
||||||
|
db.session.commit()
|
||||||
|
current_app.logger.info(f"{current_user} is updating an existing event: {e.name}")
|
||||||
|
|
||||||
|
|
||||||
|
return redirect(url_for("admin.list_events"))
|
||||||
|
|
||||||
@bp.route("/events/events.json")
|
@bp.route("/events/events.json")
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, DateTimeField, SubmitField, TextAreaField
|
from wtforms import StringField, DateField, TimeField, SubmitField, TextAreaField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
class EventForm(FlaskForm):
|
class EventForm(FlaskForm):
|
||||||
name = StringField("Name", validators=[DataRequired()])
|
name = StringField("Name", validators=[DataRequired()])
|
||||||
description = TextAreaField("Description")
|
description = TextAreaField("Description")
|
||||||
location = StringField("Location", validators=[DataRequired()])
|
location = StringField("Location", validators=[DataRequired()])
|
||||||
start_time = DateTimeField("Start Time", validators=[DataRequired()])
|
start_day = DateField("Start Day", validators=[DataRequired()])
|
||||||
end_time = DateTimeField("End Time", validators=[DataRequired()])
|
start_time = TimeField("Start Time", validators=[DataRequired()])
|
||||||
|
end_day = DateField("End Day", validators=[DataRequired()])
|
||||||
|
end_time = TimeField("End Time", validators=[DataRequired()])
|
||||||
category = StringField("Category")
|
category = StringField("Category")
|
||||||
submit = SubmitField("Submit")
|
submit = SubmitField("Submit")
|
||||||
|
|
|
@ -9,6 +9,8 @@ from goathacks.registration import bp
|
||||||
from goathacks import db, mail
|
from goathacks import db, mail
|
||||||
from goathacks.models import User
|
from goathacks.models import User
|
||||||
|
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
gr = AppGroup("user")
|
gr = AppGroup("user")
|
||||||
|
|
||||||
@gr.command('create')
|
@gr.command('create')
|
||||||
|
@ -21,8 +23,10 @@ gr = AppGroup("user")
|
||||||
@click.option("--school", prompt=True)
|
@click.option("--school", prompt=True)
|
||||||
@click.option("--phone", prompt=True)
|
@click.option("--phone", prompt=True)
|
||||||
@click.option("--gender", prompt=True)
|
@click.option("--gender", prompt=True)
|
||||||
|
@click.option("--country", prompt=True)
|
||||||
|
@click.option("--age", prompt=True)
|
||||||
def create_user(email, first_name, last_name, password, school, phone, gender,
|
def create_user(email, first_name, last_name, password, school, phone, gender,
|
||||||
admin):
|
admin,age, country):
|
||||||
"""
|
"""
|
||||||
Creates a user
|
Creates a user
|
||||||
"""
|
"""
|
||||||
|
@ -46,7 +50,9 @@ def create_user(email, first_name, last_name, password, school, phone, gender,
|
||||||
school=school,
|
school=school,
|
||||||
phone=phone,
|
phone=phone,
|
||||||
gender=gender,
|
gender=gender,
|
||||||
is_admin=admin
|
is_admin=admin,
|
||||||
|
country=country,
|
||||||
|
age=age
|
||||||
)
|
)
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -122,3 +128,56 @@ def drop_user(email, confirm):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(f"Dropped {user.first_name}'s registration")
|
click.echo(f"Dropped {user.first_name}'s registration")
|
||||||
|
|
||||||
|
@gr.command("list")
|
||||||
|
def list_users():
|
||||||
|
"""
|
||||||
|
Gets a list of all users
|
||||||
|
"""
|
||||||
|
users = User.query.all()
|
||||||
|
|
||||||
|
def make_table_content(user):
|
||||||
|
return [user.email, f"{user.first_name} {user.last_name}", user.waitlisted, user.is_admin]
|
||||||
|
|
||||||
|
table = map(make_table_content, users)
|
||||||
|
|
||||||
|
print(tabulate(table, headers=["Email", "Name", "Waitlisted", "Admin"]))
|
||||||
|
|
||||||
|
|
||||||
|
@gr.command("autopromote")
|
||||||
|
def autopromote_users():
|
||||||
|
"""
|
||||||
|
Runs through and automatically promotes users up to the waitlist limit
|
||||||
|
"""
|
||||||
|
WAITLIST_LIMIT = current_app.config['MAX_BEFORE_WAITLIST']
|
||||||
|
num_confirmed = db.session.query(User).filter(User.waitlisted == False).count()
|
||||||
|
click.echo(f"Got {num_confirmed} confirmed attendees")
|
||||||
|
num_waitlisted = db.session.query(User).filter(User.waitlisted == True).count()
|
||||||
|
click.echo(f"Got {num_waitlisted} waitlisted attendees")
|
||||||
|
|
||||||
|
num_to_promote = WAITLIST_LIMIT - num_confirmed
|
||||||
|
|
||||||
|
if num_to_promote > num_waitlisted:
|
||||||
|
num_to_promote = num_waitlisted
|
||||||
|
|
||||||
|
click.echo(f"About to promote {str(num_to_promote)} attendees from waitlist")
|
||||||
|
|
||||||
|
users = db.session.query(User).filter(User.waitlisted == True).all()
|
||||||
|
|
||||||
|
num_promoted = 0
|
||||||
|
num_to_promote_orig = num_to_promote
|
||||||
|
|
||||||
|
for u in users:
|
||||||
|
if num_to_promote > 0:
|
||||||
|
click.echo(f"Attempting to promote {u.email} ({u.id})")
|
||||||
|
u.waitlisted = False
|
||||||
|
db.session.commit()
|
||||||
|
msg = Message("Waitlist Promotion")
|
||||||
|
msg.add_recipient(u.email)
|
||||||
|
msg.sender = ("GoatHacks Team", "hack@wpi.edu")
|
||||||
|
msg.body = render_template("emails/waitlist_promotion.txt", user=u)
|
||||||
|
mail.send(msg)
|
||||||
|
num_promoted += 1
|
||||||
|
num_to_promote -= 1
|
||||||
|
|
||||||
|
click.echo(f"Promoted {num_promoted}/{num_to_promote_orig} attendees off the waitlist!")
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
SQLALCHEMY_DATABASE_URI="postgresql://localhost/goathacks"
|
|
||||||
MAX_BEFORE_WAITLIST=1
|
|
||||||
SECRET_KEY="bad-key-change-me"
|
|
||||||
|
|
||||||
UPLOAD_FOLDER="./uploads/"
|
|
||||||
|
|
||||||
|
|
||||||
# Mail settings
|
|
||||||
MAIL_SERVER="localhost"
|
|
||||||
MAIL_PORT=25
|
|
||||||
MAIL_USE_TLS=False
|
|
||||||
MAIL_USE_SSL=False
|
|
||||||
MAIL_USERNAME="dummy"
|
|
||||||
MAIL_PASSWORD="dummy"
|
|
||||||
MAIL_DEFAULT_SENDER="GoatHacks Team <hack@wpi.edu>"
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import Blueprint, current_app, flash, jsonify, render_template, request
|
from flask import Blueprint, current_app, flash, jsonify, redirect, render_template, request, url_for
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ def home():
|
||||||
current_user.accomodations = request.form.get('accomodations')
|
current_user.accomodations = request.form.get('accomodations')
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Updated successfully")
|
flash("Updated successfully")
|
||||||
|
else:
|
||||||
|
form = forms.ShirtAndAccomForm(obj=current_user)
|
||||||
return render_template("dashboard.html", form=form, resform=resform)
|
return render_template("dashboard.html", form=form, resform=resform)
|
||||||
|
|
||||||
@bp.route("/resume", methods=["POST"])
|
@bp.route("/resume", methods=["POST"])
|
||||||
|
@ -45,9 +47,17 @@ def resume():
|
||||||
filename = current_user.first_name.lower() + '_' + current_user.last_name.lower() + '_' + str(
|
filename = current_user.first_name.lower() + '_' + current_user.last_name.lower() + '_' + str(
|
||||||
current_user.id) + '.' + resume.filename.split('.')[-1].lower()
|
current_user.id) + '.' + resume.filename.split('.')[-1].lower()
|
||||||
filename = secure_filename(filename)
|
filename = secure_filename(filename)
|
||||||
|
if not os.path.exists(current_app.config['UPLOAD_FOLDER']):
|
||||||
|
try:
|
||||||
|
os.makedirs(current_app.config['UPLOAD_FOLDER'])
|
||||||
|
except Exception:
|
||||||
|
flash("Error saving resume. Contact acm-sysadmin@wpi.edu")
|
||||||
|
return redirect(url_for("dashboard.home"))
|
||||||
resume.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))
|
resume.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))
|
||||||
return 'Resume uploaded! <a href="/dashboard">Return to dashboard</a>'
|
flash("Resume uploaded!")
|
||||||
return "Something went wrong. If this keeps happening, contact hack@wpi.edu for assistance"
|
return redirect(url_for("dashboard.home"))
|
||||||
|
flash("Something went wrong. If this keeps happening, contact hack@wpi.edu for assistance")
|
||||||
|
return redirect(url_for("dashboard.home"))
|
||||||
|
|
||||||
|
|
||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from flask_wtf.file import FileField, FileRequired, FileAllowed
|
from flask_wtf.file import FileField, FileRequired, FileAllowed
|
||||||
from wtforms import RadioField, TextAreaField
|
from wtforms import SelectField, TextAreaField, SubmitField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
class ShirtAndAccomForm(FlaskForm):
|
class ShirtAndAccomForm(FlaskForm):
|
||||||
shirt_size = RadioField("Shirt size", choices=["XS", "S", "M", "L", "XL",
|
shirt_size = SelectField("Shirt size", choices=["XS", "S", "M", "L", "XL",
|
||||||
"None"],
|
"None"],
|
||||||
validators=[DataRequired()])
|
validators=[DataRequired()])
|
||||||
accomodations = TextAreaField("Special needs and/or Accomodations")
|
accomodations = TextAreaField("Special needs and/or Accomodations")
|
||||||
|
submit = SubmitField("Save")
|
||||||
|
|
||||||
class ResumeForm(FlaskForm):
|
class ResumeForm(FlaskForm):
|
||||||
resume = FileField("Resume", validators=[FileRequired(),
|
resume = FileField("Resume", validators=[FileRequired(),
|
||||||
FileAllowed(['pdf', 'docx', 'doc',
|
FileAllowed(['pdf', 'docx', 'doc',
|
||||||
'txt', 'rtf'],
|
'txt', 'rtf'],
|
||||||
"Documents only!")])
|
"Documents only!")])
|
||||||
|
|
||||||
|
submit = SubmitField("Submit")
|
||||||
|
|
|
@ -20,7 +20,13 @@ class User(db.Model, UserMixin):
|
||||||
school = Column(String, nullable=True)
|
school = Column(String, nullable=True)
|
||||||
phone = Column(String, nullable=True)
|
phone = Column(String, nullable=True)
|
||||||
gender = Column(String, nullable=True)
|
gender = Column(String, nullable=True)
|
||||||
|
newsletter = Column(Boolean, nullable=False, default=False)
|
||||||
|
country = Column(String, nullable=False)
|
||||||
|
age = Column(Integer, nullable=False)
|
||||||
|
dietary_restrictions = Column(String, nullable=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.first_name} {self.last_name} ({self.email})"
|
||||||
def create_json_output(lis):
|
def create_json_output(lis):
|
||||||
hackers = []
|
hackers = []
|
||||||
|
|
||||||
|
@ -48,7 +54,7 @@ def user_loader(user_id):
|
||||||
@login.unauthorized_handler
|
@login.unauthorized_handler
|
||||||
def unauth():
|
def unauth():
|
||||||
flash("Please login first")
|
flash("Please login first")
|
||||||
return redirect(url_for("registration.register"))
|
return redirect(url_for("registration.login"))
|
||||||
|
|
||||||
|
|
||||||
class PwResetRequest(db.Model):
|
class PwResetRequest(db.Model):
|
||||||
|
@ -73,18 +79,21 @@ class Event(db.Model):
|
||||||
events = []
|
events = []
|
||||||
|
|
||||||
for e in lis:
|
for e in lis:
|
||||||
events.append({
|
events.append(e.create_json())
|
||||||
'id': e.id,
|
|
||||||
'name': e.name,
|
|
||||||
'description': e.description,
|
|
||||||
'location': e.location,
|
|
||||||
'start': e.start_time,
|
|
||||||
'end': e.end_time,
|
|
||||||
'category': e.category
|
|
||||||
})
|
|
||||||
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
|
def create_json(self):
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"name": self.name,
|
||||||
|
"description": self.description,
|
||||||
|
"location": self.location,
|
||||||
|
"start_time": self.start_time.isoformat(),
|
||||||
|
"end_time": self.end_time.isoformat(),
|
||||||
|
"category": self.category
|
||||||
|
}
|
||||||
|
|
||||||
def get_checkins(self):
|
def get_checkins(self):
|
||||||
checkins = EventCheckins.query.filter_by(event_id=self.id).all()
|
checkins = EventCheckins.query.filter_by(event_id=self.id).all()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from flask import Blueprint, abort, config, current_app, flash, redirect, render_template, request, url_for
|
from flask import Blueprint, abort, config, current_app, flash, redirect, render_template, request, url_for
|
||||||
import flask_login
|
import flask_login
|
||||||
from flask_login import current_user
|
from flask_login import current_user, login_required
|
||||||
from goathacks.registration.forms import LoginForm, PwResetForm, RegisterForm, ResetForm
|
from goathacks.registration.forms import LoginForm, PwResetForm, RegisterForm, ResetForm
|
||||||
from werkzeug.security import check_password_hash, generate_password_hash
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
from flask_mail import Message
|
from flask_mail import Message
|
||||||
|
@ -30,7 +30,10 @@ def register():
|
||||||
school = request.form.get('school')
|
school = request.form.get('school')
|
||||||
phone = request.form.get('phone_number')
|
phone = request.form.get('phone_number')
|
||||||
gender = request.form.get('gender')
|
gender = request.form.get('gender')
|
||||||
|
country = request.form.get('country')
|
||||||
|
age = request.form.get('age')
|
||||||
|
dietary_restrictions = request.form.get('dietary_restrictions')
|
||||||
|
newsletter = request.form.get('newsletter')
|
||||||
|
|
||||||
if password == password_c:
|
if password == password_c:
|
||||||
# Passwords match!
|
# Passwords match!
|
||||||
|
@ -51,7 +54,11 @@ def register():
|
||||||
waitlisted=waitlisted,
|
waitlisted=waitlisted,
|
||||||
school=school,
|
school=school,
|
||||||
phone=phone,
|
phone=phone,
|
||||||
gender=gender
|
gender=gender,
|
||||||
|
country=country,
|
||||||
|
age=age,
|
||||||
|
dietary_restrictions=dietary_restrictions,
|
||||||
|
newsletter=newsletter
|
||||||
)
|
)
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -97,6 +104,13 @@ def login():
|
||||||
|
|
||||||
return render_template("login.html", form=form)
|
return render_template("login.html", form=form)
|
||||||
|
|
||||||
|
@bp.route("/logout")
|
||||||
|
@login_required
|
||||||
|
def logout():
|
||||||
|
flask_login.logout_user()
|
||||||
|
flash("See you later!")
|
||||||
|
return redirect(url_for("registration.login"))
|
||||||
|
|
||||||
@bp.route("/reset", methods=["GET", "POST"])
|
@bp.route("/reset", methods=["GET", "POST"])
|
||||||
def reset():
|
def reset():
|
||||||
form = ResetForm(request.form)
|
form = ResetForm(request.form)
|
||||||
|
|
249
goathacks/registration/countries.csv
Normal file
249
goathacks/registration/countries.csv
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
United States of America,US,USA,840,ISO 3166-2:US,Americas,Northern America,"",019,021,""
|
||||||
|
Afghanistan,AF,AFG,004,ISO 3166-2:AF,Asia,Southern Asia,"",142,034,""
|
||||||
|
Åland Islands,AX,ALA,248,ISO 3166-2:AX,Europe,Northern Europe,"",150,154,""
|
||||||
|
Albania,AL,ALB,008,ISO 3166-2:AL,Europe,Southern Europe,"",150,039,""
|
||||||
|
Algeria,DZ,DZA,012,ISO 3166-2:DZ,Africa,Northern Africa,"",002,015,""
|
||||||
|
American Samoa,AS,ASM,016,ISO 3166-2:AS,Oceania,Polynesia,"",009,061,""
|
||||||
|
Andorra,AD,AND,020,ISO 3166-2:AD,Europe,Southern Europe,"",150,039,""
|
||||||
|
Angola,AO,AGO,024,ISO 3166-2:AO,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Anguilla,AI,AIA,660,ISO 3166-2:AI,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Antarctica,AQ,ATA,010,ISO 3166-2:AQ,"","","","","",""
|
||||||
|
Antigua and Barbuda,AG,ATG,028,ISO 3166-2:AG,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Argentina,AR,ARG,032,ISO 3166-2:AR,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Armenia,AM,ARM,051,ISO 3166-2:AM,Asia,Western Asia,"",142,145,""
|
||||||
|
Aruba,AW,ABW,533,ISO 3166-2:AW,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Australia,AU,AUS,036,ISO 3166-2:AU,Oceania,Australia and New Zealand,"",009,053,""
|
||||||
|
Austria,AT,AUT,040,ISO 3166-2:AT,Europe,Western Europe,"",150,155,""
|
||||||
|
Azerbaijan,AZ,AZE,031,ISO 3166-2:AZ,Asia,Western Asia,"",142,145,""
|
||||||
|
Bahamas,BS,BHS,044,ISO 3166-2:BS,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Bahrain,BH,BHR,048,ISO 3166-2:BH,Asia,Western Asia,"",142,145,""
|
||||||
|
Bangladesh,BD,BGD,050,ISO 3166-2:BD,Asia,Southern Asia,"",142,034,""
|
||||||
|
Barbados,BB,BRB,052,ISO 3166-2:BB,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Belarus,BY,BLR,112,ISO 3166-2:BY,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Belgium,BE,BEL,056,ISO 3166-2:BE,Europe,Western Europe,"",150,155,""
|
||||||
|
Belize,BZ,BLZ,084,ISO 3166-2:BZ,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Benin,BJ,BEN,204,ISO 3166-2:BJ,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Bermuda,BM,BMU,060,ISO 3166-2:BM,Americas,Northern America,"",019,021,""
|
||||||
|
Bhutan,BT,BTN,064,ISO 3166-2:BT,Asia,Southern Asia,"",142,034,""
|
||||||
|
"Bolivia, Plurinational State of",BO,BOL,068,ISO 3166-2:BO,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
"Bonaire, Sint Eustatius and Saba",BQ,BES,535,ISO 3166-2:BQ,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Bosnia and Herzegovina,BA,BIH,070,ISO 3166-2:BA,Europe,Southern Europe,"",150,039,""
|
||||||
|
Botswana,BW,BWA,072,ISO 3166-2:BW,Africa,Sub-Saharan Africa,Southern Africa,002,202,018
|
||||||
|
Bouvet Island,BV,BVT,074,ISO 3166-2:BV,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Brazil,BR,BRA,076,ISO 3166-2:BR,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
British Indian Ocean Territory,IO,IOT,086,ISO 3166-2:IO,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Brunei Darussalam,BN,BRN,096,ISO 3166-2:BN,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Bulgaria,BG,BGR,100,ISO 3166-2:BG,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Burkina Faso,BF,BFA,854,ISO 3166-2:BF,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Burundi,BI,BDI,108,ISO 3166-2:BI,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Cabo Verde,CV,CPV,132,ISO 3166-2:CV,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Cambodia,KH,KHM,116,ISO 3166-2:KH,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Cameroon,CM,CMR,120,ISO 3166-2:CM,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Canada,CA,CAN,124,ISO 3166-2:CA,Americas,Northern America,"",019,021,""
|
||||||
|
Cayman Islands,KY,CYM,136,ISO 3166-2:KY,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Central African Republic,CF,CAF,140,ISO 3166-2:CF,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Chad,TD,TCD,148,ISO 3166-2:TD,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Chile,CL,CHL,152,ISO 3166-2:CL,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
China,CN,CHN,156,ISO 3166-2:CN,Asia,Eastern Asia,"",142,030,""
|
||||||
|
Christmas Island,CX,CXR,162,ISO 3166-2:CX,Oceania,Australia and New Zealand,"",009,053,""
|
||||||
|
Cocos (Keeling) Islands,CC,CCK,166,ISO 3166-2:CC,Oceania,Australia and New Zealand,"",009,053,""
|
||||||
|
Colombia,CO,COL,170,ISO 3166-2:CO,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Comoros,KM,COM,174,ISO 3166-2:KM,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Congo,CG,COG,178,ISO 3166-2:CG,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
"Congo, Democratic Republic of the",CD,COD,180,ISO 3166-2:CD,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Cook Islands,CK,COK,184,ISO 3166-2:CK,Oceania,Polynesia,"",009,061,""
|
||||||
|
Costa Rica,CR,CRI,188,ISO 3166-2:CR,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Côte d'Ivoire,CI,CIV,384,ISO 3166-2:CI,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Croatia,HR,HRV,191,ISO 3166-2:HR,Europe,Southern Europe,"",150,039,""
|
||||||
|
Cuba,CU,CUB,192,ISO 3166-2:CU,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Curaçao,CW,CUW,531,ISO 3166-2:CW,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Cyprus,CY,CYP,196,ISO 3166-2:CY,Asia,Western Asia,"",142,145,""
|
||||||
|
Czechia,CZ,CZE,203,ISO 3166-2:CZ,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Denmark,DK,DNK,208,ISO 3166-2:DK,Europe,Northern Europe,"",150,154,""
|
||||||
|
Djibouti,DJ,DJI,262,ISO 3166-2:DJ,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Dominica,DM,DMA,212,ISO 3166-2:DM,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Dominican Republic,DO,DOM,214,ISO 3166-2:DO,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Ecuador,EC,ECU,218,ISO 3166-2:EC,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Egypt,EG,EGY,818,ISO 3166-2:EG,Africa,Northern Africa,"",002,015,""
|
||||||
|
El Salvador,SV,SLV,222,ISO 3166-2:SV,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Equatorial Guinea,GQ,GNQ,226,ISO 3166-2:GQ,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Eritrea,ER,ERI,232,ISO 3166-2:ER,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Estonia,EE,EST,233,ISO 3166-2:EE,Europe,Northern Europe,"",150,154,""
|
||||||
|
Eswatini,SZ,SWZ,748,ISO 3166-2:SZ,Africa,Sub-Saharan Africa,Southern Africa,002,202,018
|
||||||
|
Ethiopia,ET,ETH,231,ISO 3166-2:ET,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Falkland Islands (Malvinas),FK,FLK,238,ISO 3166-2:FK,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Faroe Islands,FO,FRO,234,ISO 3166-2:FO,Europe,Northern Europe,"",150,154,""
|
||||||
|
Fiji,FJ,FJI,242,ISO 3166-2:FJ,Oceania,Melanesia,"",009,054,""
|
||||||
|
Finland,FI,FIN,246,ISO 3166-2:FI,Europe,Northern Europe,"",150,154,""
|
||||||
|
France,FR,FRA,250,ISO 3166-2:FR,Europe,Western Europe,"",150,155,""
|
||||||
|
French Guiana,GF,GUF,254,ISO 3166-2:GF,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
French Polynesia,PF,PYF,258,ISO 3166-2:PF,Oceania,Polynesia,"",009,061,""
|
||||||
|
French Southern Territories,TF,ATF,260,ISO 3166-2:TF,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Gabon,GA,GAB,266,ISO 3166-2:GA,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Gambia,GM,GMB,270,ISO 3166-2:GM,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Georgia,GE,GEO,268,ISO 3166-2:GE,Asia,Western Asia,"",142,145,""
|
||||||
|
Germany,DE,DEU,276,ISO 3166-2:DE,Europe,Western Europe,"",150,155,""
|
||||||
|
Ghana,GH,GHA,288,ISO 3166-2:GH,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Gibraltar,GI,GIB,292,ISO 3166-2:GI,Europe,Southern Europe,"",150,039,""
|
||||||
|
Greece,GR,GRC,300,ISO 3166-2:GR,Europe,Southern Europe,"",150,039,""
|
||||||
|
Greenland,GL,GRL,304,ISO 3166-2:GL,Americas,Northern America,"",019,021,""
|
||||||
|
Grenada,GD,GRD,308,ISO 3166-2:GD,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Guadeloupe,GP,GLP,312,ISO 3166-2:GP,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Guam,GU,GUM,316,ISO 3166-2:GU,Oceania,Micronesia,"",009,057,""
|
||||||
|
Guatemala,GT,GTM,320,ISO 3166-2:GT,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Guernsey,GG,GGY,831,ISO 3166-2:GG,Europe,Northern Europe,"",150,154,""
|
||||||
|
Guinea,GN,GIN,324,ISO 3166-2:GN,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Guinea-Bissau,GW,GNB,624,ISO 3166-2:GW,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Guyana,GY,GUY,328,ISO 3166-2:GY,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Haiti,HT,HTI,332,ISO 3166-2:HT,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Heard Island and McDonald Islands,HM,HMD,334,ISO 3166-2:HM,Oceania,Australia and New Zealand,"",009,053,""
|
||||||
|
Holy See,VA,VAT,336,ISO 3166-2:VA,Europe,Southern Europe,"",150,039,""
|
||||||
|
Honduras,HN,HND,340,ISO 3166-2:HN,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Hong Kong,HK,HKG,344,ISO 3166-2:HK,Asia,Eastern Asia,"",142,030,""
|
||||||
|
Hungary,HU,HUN,348,ISO 3166-2:HU,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Iceland,IS,ISL,352,ISO 3166-2:IS,Europe,Northern Europe,"",150,154,""
|
||||||
|
India,IN,IND,356,ISO 3166-2:IN,Asia,Southern Asia,"",142,034,""
|
||||||
|
Indonesia,ID,IDN,360,ISO 3166-2:ID,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
"Iran, Islamic Republic of",IR,IRN,364,ISO 3166-2:IR,Asia,Southern Asia,"",142,034,""
|
||||||
|
Iraq,IQ,IRQ,368,ISO 3166-2:IQ,Asia,Western Asia,"",142,145,""
|
||||||
|
Ireland,IE,IRL,372,ISO 3166-2:IE,Europe,Northern Europe,"",150,154,""
|
||||||
|
Isle of Man,IM,IMN,833,ISO 3166-2:IM,Europe,Northern Europe,"",150,154,""
|
||||||
|
Israel,IL,ISR,376,ISO 3166-2:IL,Asia,Western Asia,"",142,145,""
|
||||||
|
Italy,IT,ITA,380,ISO 3166-2:IT,Europe,Southern Europe,"",150,039,""
|
||||||
|
Jamaica,JM,JAM,388,ISO 3166-2:JM,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Japan,JP,JPN,392,ISO 3166-2:JP,Asia,Eastern Asia,"",142,030,""
|
||||||
|
Jersey,JE,JEY,832,ISO 3166-2:JE,Europe,Northern Europe,"",150,154,""
|
||||||
|
Jordan,JO,JOR,400,ISO 3166-2:JO,Asia,Western Asia,"",142,145,""
|
||||||
|
Kazakhstan,KZ,KAZ,398,ISO 3166-2:KZ,Asia,Central Asia,"",142,143,""
|
||||||
|
Kenya,KE,KEN,404,ISO 3166-2:KE,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Kiribati,KI,KIR,296,ISO 3166-2:KI,Oceania,Micronesia,"",009,057,""
|
||||||
|
"Korea, Democratic People's Republic of",KP,PRK,408,ISO 3166-2:KP,Asia,Eastern Asia,"",142,030,""
|
||||||
|
"Korea, Republic of",KR,KOR,410,ISO 3166-2:KR,Asia,Eastern Asia,"",142,030,""
|
||||||
|
Kuwait,KW,KWT,414,ISO 3166-2:KW,Asia,Western Asia,"",142,145,""
|
||||||
|
Kyrgyzstan,KG,KGZ,417,ISO 3166-2:KG,Asia,Central Asia,"",142,143,""
|
||||||
|
Lao People's Democratic Republic,LA,LAO,418,ISO 3166-2:LA,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Latvia,LV,LVA,428,ISO 3166-2:LV,Europe,Northern Europe,"",150,154,""
|
||||||
|
Lebanon,LB,LBN,422,ISO 3166-2:LB,Asia,Western Asia,"",142,145,""
|
||||||
|
Lesotho,LS,LSO,426,ISO 3166-2:LS,Africa,Sub-Saharan Africa,Southern Africa,002,202,018
|
||||||
|
Liberia,LR,LBR,430,ISO 3166-2:LR,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Libya,LY,LBY,434,ISO 3166-2:LY,Africa,Northern Africa,"",002,015,""
|
||||||
|
Liechtenstein,LI,LIE,438,ISO 3166-2:LI,Europe,Western Europe,"",150,155,""
|
||||||
|
Lithuania,LT,LTU,440,ISO 3166-2:LT,Europe,Northern Europe,"",150,154,""
|
||||||
|
Luxembourg,LU,LUX,442,ISO 3166-2:LU,Europe,Western Europe,"",150,155,""
|
||||||
|
Macao,MO,MAC,446,ISO 3166-2:MO,Asia,Eastern Asia,"",142,030,""
|
||||||
|
Madagascar,MG,MDG,450,ISO 3166-2:MG,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Malawi,MW,MWI,454,ISO 3166-2:MW,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Malaysia,MY,MYS,458,ISO 3166-2:MY,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Maldives,MV,MDV,462,ISO 3166-2:MV,Asia,Southern Asia,"",142,034,""
|
||||||
|
Mali,ML,MLI,466,ISO 3166-2:ML,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Malta,MT,MLT,470,ISO 3166-2:MT,Europe,Southern Europe,"",150,039,""
|
||||||
|
Marshall Islands,MH,MHL,584,ISO 3166-2:MH,Oceania,Micronesia,"",009,057,""
|
||||||
|
Martinique,MQ,MTQ,474,ISO 3166-2:MQ,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Mauritania,MR,MRT,478,ISO 3166-2:MR,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Mauritius,MU,MUS,480,ISO 3166-2:MU,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Mayotte,YT,MYT,175,ISO 3166-2:YT,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Mexico,MX,MEX,484,ISO 3166-2:MX,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
"Micronesia, Federated States of",FM,FSM,583,ISO 3166-2:FM,Oceania,Micronesia,"",009,057,""
|
||||||
|
"Moldova, Republic of",MD,MDA,498,ISO 3166-2:MD,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Monaco,MC,MCO,492,ISO 3166-2:MC,Europe,Western Europe,"",150,155,""
|
||||||
|
Mongolia,MN,MNG,496,ISO 3166-2:MN,Asia,Eastern Asia,"",142,030,""
|
||||||
|
Montenegro,ME,MNE,499,ISO 3166-2:ME,Europe,Southern Europe,"",150,039,""
|
||||||
|
Montserrat,MS,MSR,500,ISO 3166-2:MS,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Morocco,MA,MAR,504,ISO 3166-2:MA,Africa,Northern Africa,"",002,015,""
|
||||||
|
Mozambique,MZ,MOZ,508,ISO 3166-2:MZ,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Myanmar,MM,MMR,104,ISO 3166-2:MM,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Namibia,NA,NAM,516,ISO 3166-2:NA,Africa,Sub-Saharan Africa,Southern Africa,002,202,018
|
||||||
|
Nauru,NR,NRU,520,ISO 3166-2:NR,Oceania,Micronesia,"",009,057,""
|
||||||
|
Nepal,NP,NPL,524,ISO 3166-2:NP,Asia,Southern Asia,"",142,034,""
|
||||||
|
"Netherlands, Kingdom of the",NL,NLD,528,ISO 3166-2:NL,Europe,Western Europe,"",150,155,""
|
||||||
|
New Caledonia,NC,NCL,540,ISO 3166-2:NC,Oceania,Melanesia,"",009,054,""
|
||||||
|
New Zealand,NZ,NZL,554,ISO 3166-2:NZ,Oceania,Australia and New Zealand,"",009,053,""
|
||||||
|
Nicaragua,NI,NIC,558,ISO 3166-2:NI,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Niger,NE,NER,562,ISO 3166-2:NE,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Nigeria,NG,NGA,566,ISO 3166-2:NG,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Niue,NU,NIU,570,ISO 3166-2:NU,Oceania,Polynesia,"",009,061,""
|
||||||
|
Norfolk Island,NF,NFK,574,ISO 3166-2:NF,Oceania,Australia and New Zealand,"",009,053,""
|
||||||
|
North Macedonia,MK,MKD,807,ISO 3166-2:MK,Europe,Southern Europe,"",150,039,""
|
||||||
|
Northern Mariana Islands,MP,MNP,580,ISO 3166-2:MP,Oceania,Micronesia,"",009,057,""
|
||||||
|
Norway,NO,NOR,578,ISO 3166-2:NO,Europe,Northern Europe,"",150,154,""
|
||||||
|
Oman,OM,OMN,512,ISO 3166-2:OM,Asia,Western Asia,"",142,145,""
|
||||||
|
Pakistan,PK,PAK,586,ISO 3166-2:PK,Asia,Southern Asia,"",142,034,""
|
||||||
|
Palau,PW,PLW,585,ISO 3166-2:PW,Oceania,Micronesia,"",009,057,""
|
||||||
|
"Palestine, State of",PS,PSE,275,ISO 3166-2:PS,Asia,Western Asia,"",142,145,""
|
||||||
|
Panama,PA,PAN,591,ISO 3166-2:PA,Americas,Latin America and the Caribbean,Central America,019,419,013
|
||||||
|
Papua New Guinea,PG,PNG,598,ISO 3166-2:PG,Oceania,Melanesia,"",009,054,""
|
||||||
|
Paraguay,PY,PRY,600,ISO 3166-2:PY,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Peru,PE,PER,604,ISO 3166-2:PE,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Philippines,PH,PHL,608,ISO 3166-2:PH,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Pitcairn,PN,PCN,612,ISO 3166-2:PN,Oceania,Polynesia,"",009,061,""
|
||||||
|
Poland,PL,POL,616,ISO 3166-2:PL,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Portugal,PT,PRT,620,ISO 3166-2:PT,Europe,Southern Europe,"",150,039,""
|
||||||
|
Puerto Rico,PR,PRI,630,ISO 3166-2:PR,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Qatar,QA,QAT,634,ISO 3166-2:QA,Asia,Western Asia,"",142,145,""
|
||||||
|
Réunion,RE,REU,638,ISO 3166-2:RE,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Romania,RO,ROU,642,ISO 3166-2:RO,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Russian Federation,RU,RUS,643,ISO 3166-2:RU,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Rwanda,RW,RWA,646,ISO 3166-2:RW,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Saint Barthélemy,BL,BLM,652,ISO 3166-2:BL,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
"Saint Helena, Ascension and Tristan da Cunha",SH,SHN,654,ISO 3166-2:SH,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Saint Kitts and Nevis,KN,KNA,659,ISO 3166-2:KN,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Saint Lucia,LC,LCA,662,ISO 3166-2:LC,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Saint Martin (French part),MF,MAF,663,ISO 3166-2:MF,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Saint Pierre and Miquelon,PM,SPM,666,ISO 3166-2:PM,Americas,Northern America,"",019,021,""
|
||||||
|
Saint Vincent and the Grenadines,VC,VCT,670,ISO 3166-2:VC,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Samoa,WS,WSM,882,ISO 3166-2:WS,Oceania,Polynesia,"",009,061,""
|
||||||
|
San Marino,SM,SMR,674,ISO 3166-2:SM,Europe,Southern Europe,"",150,039,""
|
||||||
|
Sao Tome and Principe,ST,STP,678,ISO 3166-2:ST,Africa,Sub-Saharan Africa,Middle Africa,002,202,017
|
||||||
|
Saudi Arabia,SA,SAU,682,ISO 3166-2:SA,Asia,Western Asia,"",142,145,""
|
||||||
|
Senegal,SN,SEN,686,ISO 3166-2:SN,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Serbia,RS,SRB,688,ISO 3166-2:RS,Europe,Southern Europe,"",150,039,""
|
||||||
|
Seychelles,SC,SYC,690,ISO 3166-2:SC,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Sierra Leone,SL,SLE,694,ISO 3166-2:SL,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Singapore,SG,SGP,702,ISO 3166-2:SG,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Sint Maarten (Dutch part),SX,SXM,534,ISO 3166-2:SX,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Slovakia,SK,SVK,703,ISO 3166-2:SK,Europe,Eastern Europe,"",150,151,""
|
||||||
|
Slovenia,SI,SVN,705,ISO 3166-2:SI,Europe,Southern Europe,"",150,039,""
|
||||||
|
Solomon Islands,SB,SLB,090,ISO 3166-2:SB,Oceania,Melanesia,"",009,054,""
|
||||||
|
Somalia,SO,SOM,706,ISO 3166-2:SO,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
South Africa,ZA,ZAF,710,ISO 3166-2:ZA,Africa,Sub-Saharan Africa,Southern Africa,002,202,018
|
||||||
|
South Georgia and the South Sandwich Islands,GS,SGS,239,ISO 3166-2:GS,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
South Sudan,SS,SSD,728,ISO 3166-2:SS,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Spain,ES,ESP,724,ISO 3166-2:ES,Europe,Southern Europe,"",150,039,""
|
||||||
|
Sri Lanka,LK,LKA,144,ISO 3166-2:LK,Asia,Southern Asia,"",142,034,""
|
||||||
|
Sudan,SD,SDN,729,ISO 3166-2:SD,Africa,Northern Africa,"",002,015,""
|
||||||
|
Suriname,SR,SUR,740,ISO 3166-2:SR,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Svalbard and Jan Mayen,SJ,SJM,744,ISO 3166-2:SJ,Europe,Northern Europe,"",150,154,""
|
||||||
|
Sweden,SE,SWE,752,ISO 3166-2:SE,Europe,Northern Europe,"",150,154,""
|
||||||
|
Switzerland,CH,CHE,756,ISO 3166-2:CH,Europe,Western Europe,"",150,155,""
|
||||||
|
Syrian Arab Republic,SY,SYR,760,ISO 3166-2:SY,Asia,Western Asia,"",142,145,""
|
||||||
|
"Taiwan, Province of China",TW,TWN,158,ISO 3166-2:TW,,,,,,
|
||||||
|
Tajikistan,TJ,TJK,762,ISO 3166-2:TJ,Asia,Central Asia,"",142,143,""
|
||||||
|
"Tanzania, United Republic of",TZ,TZA,834,ISO 3166-2:TZ,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Thailand,TH,THA,764,ISO 3166-2:TH,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Timor-Leste,TL,TLS,626,ISO 3166-2:TL,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Togo,TG,TGO,768,ISO 3166-2:TG,Africa,Sub-Saharan Africa,Western Africa,002,202,011
|
||||||
|
Tokelau,TK,TKL,772,ISO 3166-2:TK,Oceania,Polynesia,"",009,061,""
|
||||||
|
Tonga,TO,TON,776,ISO 3166-2:TO,Oceania,Polynesia,"",009,061,""
|
||||||
|
Trinidad and Tobago,TT,TTO,780,ISO 3166-2:TT,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Tunisia,TN,TUN,788,ISO 3166-2:TN,Africa,Northern Africa,"",002,015,""
|
||||||
|
Türkiye,TR,TUR,792,ISO 3166-2:TR,Asia,Western Asia,"",142,145,""
|
||||||
|
Turkmenistan,TM,TKM,795,ISO 3166-2:TM,Asia,Central Asia,"",142,143,""
|
||||||
|
Turks and Caicos Islands,TC,TCA,796,ISO 3166-2:TC,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Tuvalu,TV,TUV,798,ISO 3166-2:TV,Oceania,Polynesia,"",009,061,""
|
||||||
|
Uganda,UG,UGA,800,ISO 3166-2:UG,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Ukraine,UA,UKR,804,ISO 3166-2:UA,Europe,Eastern Europe,"",150,151,""
|
||||||
|
United Arab Emirates,AE,ARE,784,ISO 3166-2:AE,Asia,Western Asia,"",142,145,""
|
||||||
|
United Kingdom of Great Britain and Northern Ireland,GB,GBR,826,ISO 3166-2:GB,Europe,Northern Europe,"",150,154,""
|
||||||
|
United States Minor Outlying Islands,UM,UMI,581,ISO 3166-2:UM,Oceania,Micronesia,"",009,057,""
|
||||||
|
Uruguay,UY,URY,858,ISO 3166-2:UY,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Uzbekistan,UZ,UZB,860,ISO 3166-2:UZ,Asia,Central Asia,"",142,143,""
|
||||||
|
Vanuatu,VU,VUT,548,ISO 3166-2:VU,Oceania,Melanesia,"",009,054,""
|
||||||
|
"Venezuela, Bolivarian Republic of",VE,VEN,862,ISO 3166-2:VE,Americas,Latin America and the Caribbean,South America,019,419,005
|
||||||
|
Viet Nam,VN,VNM,704,ISO 3166-2:VN,Asia,South-eastern Asia,"",142,035,""
|
||||||
|
Virgin Islands (British),VG,VGB,092,ISO 3166-2:VG,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Virgin Islands (U.S.),VI,VIR,850,ISO 3166-2:VI,Americas,Latin America and the Caribbean,Caribbean,019,419,029
|
||||||
|
Wallis and Futuna,WF,WLF,876,ISO 3166-2:WF,Oceania,Polynesia,"",009,061,""
|
||||||
|
Western Sahara,EH,ESH,732,ISO 3166-2:EH,Africa,Northern Africa,"",002,015,""
|
||||||
|
Yemen,YE,YEM,887,ISO 3166-2:YE,Asia,Western Asia,"",142,145,""
|
||||||
|
Zambia,ZM,ZMB,894,ISO 3166-2:ZM,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
||||||
|
Zimbabwe,ZW,ZWE,716,ISO 3166-2:ZW,Africa,Sub-Saharan Africa,Eastern Africa,002,202,014
|
|
|
@ -1,8 +1,13 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import BooleanField, PasswordField, SelectField, StringField, SubmitField, widgets
|
from wtforms import BooleanField, IntegerField, PasswordField, SelectField, StringField, SubmitField, widgets
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
import os
|
||||||
|
|
||||||
class RegisterForm(FlaskForm):
|
class RegisterForm(FlaskForm):
|
||||||
|
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
|
||||||
|
schools_list = open(os.path.join(__location__, 'schools.txt')).read().split("\n")
|
||||||
|
countries_list = open(os.path.join(__location__, 'countries.csv')).read().split("\n")
|
||||||
|
|
||||||
email = StringField("Email", validators=[DataRequired()])
|
email = StringField("Email", validators=[DataRequired()])
|
||||||
first_name = StringField("Preferred First Name",
|
first_name = StringField("Preferred First Name",
|
||||||
validators=[DataRequired()])
|
validators=[DataRequired()])
|
||||||
|
@ -10,12 +15,18 @@ class RegisterForm(FlaskForm):
|
||||||
password = PasswordField("Password", validators=[DataRequired()])
|
password = PasswordField("Password", validators=[DataRequired()])
|
||||||
password_confirm = PasswordField("Confirm Password",
|
password_confirm = PasswordField("Confirm Password",
|
||||||
validators=[DataRequired()])
|
validators=[DataRequired()])
|
||||||
school = StringField("School/University", validators=[DataRequired()])
|
school = SelectField("School", choices=[(school, school) for school in schools_list], widget=widgets.Select())
|
||||||
phone_number = StringField("Phone number", validators=[DataRequired()])
|
phone_number = StringField("Phone number", validators=[DataRequired()])
|
||||||
|
age = IntegerField("Age", validators=[DataRequired()])
|
||||||
|
dietary_restrictions = StringField("Dietary Restrictions (Optional)")
|
||||||
gender = SelectField("Gender", choices=[("F", "Female"), ("M", "Male"),
|
gender = SelectField("Gender", choices=[("F", "Female"), ("M", "Male"),
|
||||||
("NB", "Non-binary/Other")],
|
("NB", "Non-binary/Other")],
|
||||||
widget=widgets.Select())
|
widget=widgets.Select())
|
||||||
|
country = SelectField("Country", choices=[(country.split(",")[0], country.split(",")[0]) for country in countries_list], widget=widgets.Select())
|
||||||
|
newsletter = BooleanField("Subscribe to the MLH newsletter?")
|
||||||
agree_coc = BooleanField("I confirm that I have read and agree to the Code of Conduct", validators=[DataRequired()])
|
agree_coc = BooleanField("I confirm that I have read and agree to the Code of Conduct", validators=[DataRequired()])
|
||||||
|
logistics = BooleanField("I authorize you to share my application/registration with Major League Hacking for event administration, ranking, and MLH administration in-line with the MLH privacy policy.I further agree to the terms of both the MLH Contest Terms and Conditions and the MLH Privacy Policy.", validators=[DataRequired()])
|
||||||
|
|
||||||
submit = SubmitField("Register")
|
submit = SubmitField("Register")
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
class LoginForm(FlaskForm):
|
||||||
|
|
2225
goathacks/registration/schools.txt
Normal file
2225
goathacks/registration/schools.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,185 +1,18 @@
|
||||||
@font-face {
|
.navbar-dark, .modal-header, .table-header {
|
||||||
font-family: "Krungthep";
|
background-color: #974355;
|
||||||
src: url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.eot");
|
color: #FFFFFF;
|
||||||
src: url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.eot?#iefix") format("embedded-opentype"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.woff2") format("woff2"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.woff") format("woff"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.ttf") format("truetype"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.svg#Krungthep") format("svg");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
.modal-header, .table-header {
|
||||||
height: 100%;
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #003049;
|
min-height: 100vh;
|
||||||
font-family: 'Montserrat', sans-serif;
|
background-color: #000000;
|
||||||
font-size: 1.1rem;
|
|
||||||
color: #eee;
|
|
||||||
position: relative;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
line-height: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: row;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#goat {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-collapse {
|
|
||||||
color: #26a69a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-container {
|
|
||||||
min-height: 380px;
|
|
||||||
line-height: 0;
|
|
||||||
height: auto;
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-container .section {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 992px) {
|
|
||||||
.parallax-container .section {
|
|
||||||
top: 40%;
|
|
||||||
}
|
|
||||||
#index-banner .section {
|
|
||||||
top: 10%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
|
||||||
.parallax-container .section {
|
|
||||||
height: auto;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
#index-banner .section {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#tagline {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
#event-info {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
#registration-banner {
|
|
||||||
min-height: 100px;
|
|
||||||
max-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#registration-banner .section {
|
|
||||||
top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-block {
|
|
||||||
padding: 0 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-block .material-icons {
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax img {
|
|
||||||
display: inherit;
|
|
||||||
max-width: 200%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mlh-trust-badge {
|
|
||||||
display: block;
|
|
||||||
max-width: 100px;
|
|
||||||
min-width: 60px;
|
|
||||||
position: fixed;
|
|
||||||
right: 50px;
|
|
||||||
top: 0;
|
|
||||||
width: 10%;
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
line-height: normal !important;
|
|
||||||
font-family: "Jost", sans-serif;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
.navbar-brand {
|
|
||||||
} */
|
|
||||||
.footer-nav {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
form input {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form input[type="submit"] {
|
|
||||||
background: #26a69a;
|
|
||||||
border-radius: 10px;
|
|
||||||
border-color: #26a69a;
|
|
||||||
}
|
|
||||||
|
|
||||||
form input[type="radio"] {
|
|
||||||
padding-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form input[type="checkbox"]:checked {
|
|
||||||
visibility: visible;
|
|
||||||
left: unset;
|
|
||||||
position: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
form label {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
padding-right: 10px;
|
|
||||||
padding-left: 25px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
form select {
|
|
||||||
display: unset;
|
|
||||||
background: #974355;
|
|
||||||
max-width: 11rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flashes {
|
|
||||||
list-style-type: none;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
width: 80%;
|
|
||||||
justify-content: center;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
background-color: #26a69a;
|
|
||||||
padding: 0.2rem;
|
|
||||||
font-size: large;
|
|
||||||
color: #eee;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,184 +1,21 @@
|
||||||
$color-bg: #003049;
|
$color-nav-bg: #974355;
|
||||||
$color-fg: #eee;
|
$color-bg: #000000;
|
||||||
$color-section-bg: #974355;
|
|
||||||
$color-accent: #26a69a;
|
|
||||||
@font-face {font-family: "Krungthep"; src: url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.eot"); src: url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.eot?#iefix") format("embedded-opentype"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.woff2") format("woff2"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.woff") format("woff"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.ttf") format("truetype"), url("//db.onlinewebfonts.com/t/736cf5b08b01082a3645e14038868e20.svg#Krungthep") format("svg"); }
|
|
||||||
|
|
||||||
html {
|
.navbar-dark, .modal-header, .table-header {
|
||||||
height: 100%;
|
background-color: $color-nav-bg;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header, .table-header {
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
background-color: $color-bg;
|
background-color: $color-bg;
|
||||||
font-family: 'Montserrat', sans-serif;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
color: $color-fg;
|
|
||||||
position: relative;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
|
||||||
line-height: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: row;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#goat {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-collapse {
|
|
||||||
color: $color-accent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.parallax-container {
|
|
||||||
min-height: 380px;
|
|
||||||
line-height: 0;
|
|
||||||
height: auto;
|
|
||||||
color: rgba(255,255,255,.9);
|
|
||||||
}
|
|
||||||
.parallax-container .section {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width : 992px) {
|
|
||||||
.parallax-container .section {
|
|
||||||
top: 40%;
|
|
||||||
}
|
|
||||||
#index-banner .section {
|
|
||||||
top: 10%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width : 600px) {
|
|
||||||
.parallax-container .section {
|
|
||||||
height: auto;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
#index-banner .section {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#tagline {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
#event-info {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
#registration-banner {
|
|
||||||
min-height: 100px;
|
|
||||||
max-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#registration-banner .section{
|
|
||||||
top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-block {
|
|
||||||
padding: 0 15px;
|
|
||||||
}
|
|
||||||
.icon-block .material-icons {
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax img {
|
|
||||||
display: inherit;
|
|
||||||
max-width: 200%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mlh-trust-badge {
|
|
||||||
display: block;
|
|
||||||
max-width: 100px;
|
|
||||||
min-width: 60px;
|
|
||||||
position: fixed;
|
|
||||||
right: 50px;
|
|
||||||
top: 0;
|
|
||||||
width: 10%;
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
line-height: normal !important;
|
|
||||||
font-family: "Jost", sans-serif;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
.navbar-brand {
|
|
||||||
} */
|
|
||||||
|
|
||||||
.footer-nav {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Forms
|
|
||||||
label {
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
form {
|
|
||||||
input {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
input[type="submit"] {
|
|
||||||
background: $color-accent;
|
|
||||||
border-radius: 10px;
|
|
||||||
border-color: $color-accent;
|
|
||||||
}
|
|
||||||
input[type="radio"] {
|
|
||||||
padding-right: 5px;
|
|
||||||
}
|
|
||||||
input[type="checkbox"]:checked {
|
|
||||||
visibility: visible;
|
|
||||||
left: unset;
|
|
||||||
position: unset;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
padding-right: 10px;
|
|
||||||
padding-left: 25px !important;
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
display: unset;
|
|
||||||
background: $color-section-bg;
|
|
||||||
max-width: 11rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flashed messages
|
|
||||||
.flashes {
|
|
||||||
list-style-type: none;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
width: 80%;
|
|
||||||
justify-content: center;
|
|
||||||
border: 1px solid $color-fg;
|
|
||||||
background-color: $color-accent;
|
|
||||||
padding: 0.2rem;
|
|
||||||
font-size: large;
|
|
||||||
color: $color-fg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
BIN
goathacks/static/img/banner.png
Normal file
BIN
goathacks/static/img/banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 KiB |
BIN
goathacks/static/img/logo.png
Normal file
BIN
goathacks/static/img/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
2
goathacks/static/js/jquery-3.6.3.min.js
vendored
Normal file
2
goathacks/static/js/jquery-3.6.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
39
goathacks/templates/admin-layout.html
Normal file
39
goathacks/templates/admin-layout.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block navbar %}
|
||||||
|
<nav class="navbar navbar-dark mb-4 navbar-expand-lg">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#navbarSupportedContent"
|
||||||
|
aria-controls="navbarSupportedContent"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-label="Toggle
|
||||||
|
navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-header">
|
||||||
|
<a class="navbar-brand" href="{{ url_for('admin.home') }}">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.png')}}"
|
||||||
|
alt="Logo" width="35" height="35" class="d-inline-block
|
||||||
|
align-text-middle mx-2">GoatHacks Admin</a>
|
||||||
|
</div>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="nav navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
{{ render_nav_item('admin.home', 'User List')}}
|
||||||
|
{{ render_nav_item('admin.admin_list', 'Admin List')}}
|
||||||
|
{{ render_nav_item('admin.list_events', 'Event List')}}
|
||||||
|
{{ render_nav_item('admin.mail', 'Bulk Mail Tool')}}
|
||||||
|
</ul>
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
{{ render_nav_item('dashboard.home', '<- Back To Site') }}
|
||||||
|
{{ render_nav_item('registration.logout', 'Logout') }}
|
||||||
|
{% else %}
|
||||||
|
{{ render_nav_item('registration.register', 'Registration') }}
|
||||||
|
{{ render_nav_item('registration.login', 'Login') }}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
|
@ -1,213 +1,29 @@
|
||||||
<head>
|
{% extends 'admin-layout.html' %}
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>Hack @ WPI</title>
|
|
||||||
<link rel="icon" href="../static/favicon.png" type="image/png">
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href="https://opensource.keycdn.com/fontawesome/4.7.0/font-awesome.min.css" integrity="sha384-dNpIIXE8U05kAbPhy3G1cz+yZmTzA6CY8Vg/u2L9xRnHjJiAK76m2BIEaSEV+/aU" crossorigin="anonymous">
|
|
||||||
<!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]--><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
|
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{{super()}}
|
||||||
<script src="http://www.kryogenix.org/code/browser/sorttable/sorttable.js"></script>
|
<script src="http://www.kryogenix.org/code/browser/sorttable/sorttable.js"></script>
|
||||||
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.4.3.js"></script>
|
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.4.3.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js"></script>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css">
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
|
||||||
<script src="{{url_for('static', filename='js/admin.js')}}"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
|
<script src="{{url_for('static', filename='js/admin.js')}}"></script>
|
||||||
</head>
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
<style>
|
<div class="card text-center">
|
||||||
.table-striped > tbody > tr:nth-of-type(odd) {
|
<div class="card-body">
|
||||||
background-color: rgba(255, 255, 255, 0.15);
|
<h1 class="h3 mb-3 fw-normal">Registered Users</h1>
|
||||||
}
|
<table id="hackers" class="table table-striped">
|
||||||
|
<thead>
|
||||||
.table-hover > tbody > tr:hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sorttable_nosort):after {
|
|
||||||
content: " \25B4\25BE"
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
max-width: 500px;
|
|
||||||
max-height: 500px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="contact-section" style="height: auto; background-repeat: repeat; background-size: contain;">
|
|
||||||
<div class="container-fluid" style="margin-left: 3%; margin-right: 3%;">
|
|
||||||
<div class="row" style="margin-top: 10%;">
|
|
||||||
<h5>JSON object of users from MLH (Including dropped applications):</h5>
|
|
||||||
<p><a href="{{ mlh_url }}"><b>Do NOT share this URL.</b></a></p>
|
|
||||||
<h5>Get registered hackers only:</h5>
|
|
||||||
<p><a href="{{url_for('admin.hackers')}}">JSON</a> <a
|
|
||||||
href="{{url_for('admin.hackers_csv')}}">CSV</a></p>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h2 style="">Gender:</h2>
|
|
||||||
<canvas id="genderCanvas" width="400" height="400"></canvas>
|
|
||||||
<script>
|
|
||||||
let genderCtx = document.getElementById('genderCanvas')
|
|
||||||
let genderChart = new Chart(genderCtx, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: {
|
|
||||||
labels: ['Female', 'Male', 'Non-Binary/Other'],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: [{{ female_count }}, {{ male_count }}, {{ nb_count }}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
title: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
labels: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h2 style="">Schools:</h2>
|
|
||||||
<canvas id="schoolCanvas" width="400" height="400"></canvas>
|
|
||||||
<script>
|
|
||||||
let schoolNames = []
|
|
||||||
let schoolNums = []
|
|
||||||
|
|
||||||
{% for school in schools %}
|
|
||||||
schoolNames.push('{{ school }}')
|
|
||||||
schoolNums.push({{ schools[school] }})
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
let schoolCtx = document.getElementById('schoolCanvas')
|
|
||||||
let schoolChart = new Chart(schoolCtx, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: {
|
|
||||||
labels: schoolNames,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: schoolNums
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
title: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
labels: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h2 style="">Majors:</h2>
|
|
||||||
<canvas id="majorCanvas" width="400" height="400"></canvas>
|
|
||||||
<script>
|
|
||||||
let majorNames = []
|
|
||||||
let majorNums = []
|
|
||||||
|
|
||||||
{% for major in majors %}
|
|
||||||
majorNames.push('{{ major }}')
|
|
||||||
majorNums.push({{ majors[major] }})
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
let majorCtx = document.getElementById('majorCanvas')
|
|
||||||
let majorChart = new Chart(majorCtx, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: {
|
|
||||||
labels: majorNames,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: majorNums
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
title: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
labels: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" style="">
|
|
||||||
<h2 style="">Counts:</h2>
|
|
||||||
<table id="counts" class="table table-striped table-hover table-condensed sortable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Total</th>
|
|
||||||
<th>Attendees</th>
|
|
||||||
<th>Waitlist</th>
|
|
||||||
<th>Checked In</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{ total_count }}</td>
|
|
||||||
<td>{{ (total_count - waitlist_count) }}</td>
|
|
||||||
<td>{{ waitlist_count }}</td>
|
|
||||||
<td>{{ check_in_count }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2 style="margin-top: 2%;">Shirts:</h2>
|
|
||||||
<table id="shirts" class="table table-striped table-hover table-condensed sortable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>XXS</th>
|
|
||||||
<th>XS</th>
|
|
||||||
<th>S</th>
|
|
||||||
<th>M</th>
|
|
||||||
<th>L</th>
|
|
||||||
<th>XL</th>
|
|
||||||
<th>XXL</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{ shirt_count['XXS'] }}</td>
|
|
||||||
<td>{{ shirt_count['XS'] }}</td>
|
|
||||||
<td>{{ shirt_count['S'] }}</td>
|
|
||||||
<td>{{ shirt_count['M'] }}</td>
|
|
||||||
<td>{{ shirt_count['L'] }}</td>
|
|
||||||
<td>{{ shirt_count['XL'] }}</td>
|
|
||||||
<td>{{ shirt_count['XXL'] }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2 style="margin-top: 2%;">Hackers:</h2>
|
|
||||||
<table id="hackers" class="table table-striped table-hover table-condensed sortable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Options</th>
|
<th>Options</th>
|
||||||
<th>Checked In?</th>
|
<th>Checked In?</th>
|
||||||
<th>Waitlisted?</th>
|
<th>Waitlisted?</th>
|
||||||
<th>Admin</th>
|
<th>Admin</th>
|
||||||
<th>MLH ID</th>
|
<th>User ID</th>
|
||||||
<th>Time Registered</th>
|
<th>Registration Time</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Phone</th>
|
<th>Phone</th>
|
||||||
|
@ -215,66 +31,64 @@
|
||||||
<th>Special</th>
|
<th>Special</th>
|
||||||
<th>School</th>
|
<th>School</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for hacker in hackers %}
|
{% for hacker in hackers %}
|
||||||
<tr id="{{ hacker.id }}-row">
|
<tr id="{{hacker.id}}-row">
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="dropdown">
|
||||||
<a href="#" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"><span
|
<a href="#" class="btn btn-primary dropdown-toggle"
|
||||||
|
data-bs-toggle="dropdown"><span
|
||||||
class="caret"></span></a>
|
class="caret"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% if not hacker.checked_in %}
|
{% if not hacker.checked_in %}
|
||||||
<li><a class="check_in" id="{{ hacker.id }}-check_in" href="#">Check In</a>
|
<li><a class="dropdown-item check_in" id="{{
|
||||||
</li>
|
hacker.id}}-check_in"
|
||||||
{% endif %}
|
href="#">Check
|
||||||
{% if hacker.waitlisted and not hacker.checked_in %}
|
In</a></li>
|
||||||
<li><a class="promote_from_waitlist"
|
{% endif %}
|
||||||
id="{{ hacker['id'] }}-promote_from_waitlist"
|
{% if hacker.waitlisted and not
|
||||||
href="#">Promote From Waitlist</a></li>
|
hacker.checked_in %}
|
||||||
{% endif %}
|
<li><a class="dropdown-item
|
||||||
<li class="divider"></li>
|
promote_from_waitlist" id="{{
|
||||||
{% if not hacker.checked_in %}
|
hacker.id}}-promote_from_waitlist"
|
||||||
<li><a class="drop" id="{{ hacker['id'] }}-drop" href="#">Drop Application</a>
|
href="#">Promote From
|
||||||
</li>
|
Waitlist</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if hacker.is_admin %}
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li><a class="demote_admin" id="{{ hacker['id'] }}-demote_admin" href="#">Demote
|
{% if not hacker.checked_in %}
|
||||||
Admin</a>
|
<li><a class="dropdown-item drop"
|
||||||
</li>
|
id="{{hacker.id}}-drop"
|
||||||
{% else %}
|
href="#">Drop Registration</a></li>
|
||||||
<li><a class="promote_admin" id="{{ hacker['id'] }}-promote_admin" href="#">Promote
|
{% endif %}
|
||||||
Admin</a>
|
{% if hacker.is_admin %}
|
||||||
</li>
|
<li><a class="dropdown-item demote_admin"
|
||||||
{% endif %}
|
id="{{hacker.id}}-demote_admin"
|
||||||
</ul>
|
href="#">Demote Admin</a></li>
|
||||||
</div>
|
{% else %}
|
||||||
</td>
|
<li><a class="dropdown-item promote_admin"
|
||||||
<td id="{{ hacker['id'] }}-checked_in">{{ hacker['checked_in'] }}</td>
|
id="{{hacker.id}}-promote_admin"
|
||||||
<td id="{{ hacker['id'] }}-waitlisted">{{ hacker['waitlisted'] }}</td>
|
href="#">Promote Admin</a></li>
|
||||||
<td>{{ hacker.is_admin }}</td>
|
{% endif %}
|
||||||
<td>{{ hacker['id'] }}</td>
|
</ul>
|
||||||
<td>{{ hacker['last_login'] }}</td>
|
</div>
|
||||||
<td>{{ hacker['email'] }}</td>
|
</td>
|
||||||
<td>{{ hacker['first_name'] + ' ' + hacker['last_name'] }}</td>
|
<td id="{{hacker.id}}-checked_in">{{ hacker.checked_in }}</td>
|
||||||
<td>{{ hacker['phone'] }}</td>
|
<td id="{{hacker.id}}-waitlisted">{{ hacker.waitlisted }}</td>
|
||||||
<td>{{ hacker['shirt_size'] }}</td>
|
<td>{{ hacker.is_admin }}</td>
|
||||||
<td>{{ hacker['accomodations'] }}</td>
|
<td>{{ hacker.id }}</td>
|
||||||
<td>{{ hacker['school'] }}</td>
|
<td>{{ hacker.last_login }}</td>
|
||||||
</tr>
|
<td>{{ hacker.email }}</td>
|
||||||
|
<td>{{ hacker.first_name + ' ' + hacker.last_name }}</td>
|
||||||
|
<td>{{ hacker.phone }}</td>
|
||||||
|
<td>{{ hacker.shirt_size }}</td>
|
||||||
|
<td>{{ hacker.accomodations }}</td>
|
||||||
|
<td>{{ hacker.school }}</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<script>
|
|
||||||
$(document).ready(() => {
|
|
||||||
setTimeout('let myTh = document.getElementsByTagName("th")[14]; sorttable.innerSortFunction.apply(myTh, []); sorttable.innerSortFunction.apply(myTh, []);', 50)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
|
||||||
<script src="../static/js/jquery.easing.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
{% include 'header.html' %}
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
{% with messages = get_flashed_messages() %}
|
|
||||||
{% if messages %}
|
|
||||||
<ul class="flashed-content">
|
|
||||||
{% for m in messages %}
|
|
||||||
<li class="message">{{ m }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
This content block is still being worked on!
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% include 'footer.html' %}
|
|
44
goathacks/templates/bootstrap-base.html
Normal file
44
goathacks/templates/bootstrap-base.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
{% from 'bootstrap5/nav.html' import render_nav_item %}
|
||||||
|
{% from 'bootstrap5/utils.html' import render_messages %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
{% if title %}
|
||||||
|
<title>{{ title }} - GoatHacks</title>
|
||||||
|
{% else %}
|
||||||
|
<title>GoatHacks</title>
|
||||||
|
{% endif %}
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
{{ bootstrap.load_css() }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Your page content -->
|
||||||
|
{% block navbar %}{% endblock %}
|
||||||
|
|
||||||
|
<!-- Your page content -->
|
||||||
|
<div class="container">
|
||||||
|
<div id="outerAlerts">
|
||||||
|
{{ render_messages(container=False, dismissible=True, dismiss_animate=True) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block app_content %}{% endblock %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<!-- Optional JavaScript -->
|
||||||
|
{{ bootstrap.load_js() }}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -1,101 +1,56 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
{% from 'bootstrap5/form.html' import render_field %}
|
||||||
|
|
||||||
{% block content %}
|
{% block app_content %}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js"></script>
|
<div class="card text-center">
|
||||||
<script>
|
<div class="card-body">
|
||||||
function drop(id) {
|
<h1 class="h2 mb-3 fw-normal">Hi {{current_user.first_name}}!</h1>
|
||||||
if(window.confirm("Are you sure you wish to drop your application? This cannot be undone. (patiently wait after clicking the button)")) {
|
{% if current_user.waitlisted %}
|
||||||
window.location.href = "/admin/drop/" + id;
|
<h4 class="h3 mb-3 fw-normal">You're currently waitlisted. If space
|
||||||
}
|
opens up, we'll let you know!</h4>
|
||||||
}
|
{% else %}
|
||||||
|
<h4>You are fully registered! We look forward to seeing you!</h4>
|
||||||
function resumeChange() {
|
|
||||||
let val = document.getElementById('resume').value;
|
|
||||||
val = val.split(/\\|\//gi).slice(-1)[0]
|
|
||||||
document.getElementById('filename').setAttribute('value', val);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="contact-section" style="height: 100%;">
|
|
||||||
<div class="container">
|
|
||||||
<div class="row center justify-content-center" style="margin-top: 10%;">
|
|
||||||
<h1>Hi {{ current_user.first_name }}!</h1>
|
|
||||||
{% if current_user.waitlisted %}
|
|
||||||
<h2>You are waitlisted, if space opens up we will let you know</h2>
|
|
||||||
{% else %}
|
|
||||||
<h2>You are fully registered! We look forward to seeing you!</h2>
|
|
||||||
Let us know if you have any questions by sending them to <a href="mailto:hack@wpi.edu">hack@wpi.edu</a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
Forgot to upload your resume while registering? No worries, submit it below.
|
|
||||||
</div>
|
|
||||||
<div class="row center justify-content-center">
|
|
||||||
<h5>Make sure to join the Discord and enter your shirt size below!</h5>
|
|
||||||
<p>(Please note that due to COVID-19 constraints, we can't guarantee that all participants will receive Hack@WPI t-shirts this year but we are trying to find a way!)</p>
|
|
||||||
<a href="https://discord.gg/G3pseHPRNv" style="margin: 5px;"
|
|
||||||
class="btn btn-lg btn-primary btn-invert">Discord</a>
|
|
||||||
</div>
|
|
||||||
<div class="row center justify-content-center" style="background-color: #974355; padding: 20; margin-left: 20; margin-right: 20; border-radius: 5px;">
|
|
||||||
<form method="post">
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
<br>
|
|
||||||
<p><b>Optional Info:</b></p>
|
|
||||||
<div>
|
|
||||||
<p>Shirt Size (Currently selected: {{current_user.shirt_size}})</p>
|
|
||||||
{% for subfield in form.shirt_size %}
|
|
||||||
{{subfield}}{{subfield.label}}
|
|
||||||
{% endfor %}
|
|
||||||
<p>Special Needs/Accommodations:</p>
|
|
||||||
<input type="text" name="accomodations"
|
|
||||||
id="special_needs" value="{{ current_user.accomodations }}">
|
|
||||||
</div>
|
|
||||||
<br><br>
|
|
||||||
<input name="save" class="btn btn-lg btn-primary btn-invert" type="submit" value="Save"/>
|
|
||||||
<br><br><br>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="row center justify-content-center">
|
|
||||||
<form method="post" action="{{url_for('dashboard.resume')}}" enctype="multipart/form-data">
|
|
||||||
{{ resform.csrf_token }}
|
|
||||||
<p><b>If you'd like, add your resume to send to sponsors... </b></p>
|
|
||||||
<div class="file-field input-field">
|
|
||||||
<div class="btn">
|
|
||||||
<span>File</span>
|
|
||||||
<input id="resume" name="resume" type="file" oninput="resumeChange()"/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="file-path-wrapper white-text">
|
|
||||||
<input disabled id="filename" class="file-path validate white-text" type="text">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input name="submit" class="btn btn-lg btn-primary btn-invert" type="submit" value="Submit"/>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
{% if current_user.is_admin %}
|
|
||||||
<br>
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<a href="/admin"><p class="btn">Admin Dashboard</p></a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br>
|
|
||||||
|
<p class="card-text">Let us know if you have any questions by sending
|
||||||
|
them to <a href="mailto:hack@wpi.edu">hack@wpi.edu</a></p>
|
||||||
|
|
||||||
|
{% if not current_user.waitlisted and config['DISCORD_LINK'] %}
|
||||||
|
<p>Make sure to join our Discord to get the latest updates!</p>
|
||||||
|
<button type="button" class="btn btn-primary mb-3"><a href="{{ config['DISCORD_LINK']
|
||||||
|
}}" class="link-light">Discord</a></button>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row center justify-content-center">
|
||||||
|
<form method="post">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
<p><b>Optional Info</b></p>
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.shirt_size(class="form-control", selected=current_user.shirt_size) }}
|
||||||
|
{{ form.shirt_size.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.accomodations(class="form-control") }}
|
||||||
|
{{ form.accomodations.label() }}
|
||||||
|
</div>
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<div class="row center justify-content-center">
|
||||||
|
<form method="post" action="{{url_for('dashboard.resume')}}"
|
||||||
|
enctype="multipart/form-data">
|
||||||
|
{{ resform.csrf_token() }}
|
||||||
|
<p><b>If you'd like, add your resume to send to
|
||||||
|
sponsors...</b></p>
|
||||||
|
<div class="form mb-3 required">
|
||||||
|
{{ resform.resume(class="form-control") }}
|
||||||
|
</div>
|
||||||
|
{{ render_field(resform.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<center><a onclick="drop('{{current_user.id}}')" id="drop-link"><p class="btn">Drop Application if you can't make it :(</p></a></center>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
let errColor = '#E74C3C'
|
|
||||||
|
|
||||||
$(document).ready(() => {
|
|
||||||
$('#drop-link').click((e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
let id = {{ id }}
|
|
||||||
drop(id)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'admin-layout.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block app_content %}
|
||||||
|
<div class="card text-center">
|
||||||
|
|
||||||
<div style="height: 100%; color: white;">
|
<div style="height: 100%;">
|
||||||
<h2>Events</h2>
|
<h2>Events</h2>
|
||||||
Get a JSON readout of events <a href="{{ url_for('admin.events_json')
|
Get a JSON readout of events <a href="{{ url_for('admin.events_json')
|
||||||
}}">here</a>
|
}}">here</a>
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
<th>Category</th>
|
<th>Category</th>
|
||||||
<th>Checked in</th>
|
<th>Checked in</th>
|
||||||
<th>QR Code</th>
|
<th>QR Code</th>
|
||||||
<th><a href="{{url_for('admin.new_event')}}">New</a></th>
|
<th><a href="#editModal" data-bs-toggle="modal" data-id="0">New</a></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -33,11 +34,166 @@
|
||||||
<td>{{ event.get_checkins()|length }}</td>
|
<td>{{ event.get_checkins()|length }}</td>
|
||||||
<td><a href='{{ url_for("admin.qrcode_event", id=event.id)
|
<td><a href='{{ url_for("admin.qrcode_event", id=event.id)
|
||||||
}}'>QR Code</a></td>
|
}}'>QR Code</a></td>
|
||||||
<td><a href="{{url_for('admin.edit_event', id=event.id)}}">Edit</a></td>
|
<td><a href="#editModal" data-bs-toggle="modal" data-id="{{ event.id}}" >Edit</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal" id="editModal" tabindex="-1" aria-labelledby="editModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="editModalLabel">Event</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<form class="form" id="edit-form" action="/admin/events/0" role="form" method="post">
|
||||||
|
<div class="modal-body">
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.name(class="form-control") }}
|
||||||
|
{{ form.name.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
{{ form.description(class="form-control") }}
|
||||||
|
{{ form.description.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.location(class="form-control") }}
|
||||||
|
{{ form.location.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
{{ form.category(class="form-control") }}
|
||||||
|
{{ form.category.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.start_day(class="form-control") }}
|
||||||
|
{{ form.start_day.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.start_time(class="form-control") }}
|
||||||
|
{{ form.start_time.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.end_day(class="form-control") }}
|
||||||
|
{{ form.end_day.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.end_time(class="form-control") }}
|
||||||
|
{{ form.end_time.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger" data-id="0" id="delete">Delete</button>
|
||||||
|
<button type="submit" class="btn btn-primary" id="edit-save">Save changes</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery-3.6.3.min.js') }}" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<script charset="utf-8">
|
||||||
|
const editButton = document.getElementById("edit-save")
|
||||||
|
|
||||||
|
$('#delete').on("click", (event) => {
|
||||||
|
if (window.confirm("Delete this event?")) {
|
||||||
|
console.log("Got OK")
|
||||||
|
deleteButton = document.getElementById("delete")
|
||||||
|
id = deleteButton.dataset.id
|
||||||
|
$.get(`/admin/event/${id}/delete`, (data) => {
|
||||||
|
if (data.status == "error") {
|
||||||
|
window.alert(`Error: ${data.message}`)
|
||||||
|
} else {
|
||||||
|
window.alert("Success")
|
||||||
|
}
|
||||||
|
location.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$('#editModal').on('show.bs.modal', function(event) {
|
||||||
|
var modal = $(this)
|
||||||
|
modal.find('#name').val('')
|
||||||
|
modal.find('#location').val('')
|
||||||
|
modal.find('#description').val('')
|
||||||
|
modal.find('#start_day').val('')
|
||||||
|
modal.find('#start_time').val('')
|
||||||
|
modal.find('#end_day').val('')
|
||||||
|
modal.find('#end_time').val('')
|
||||||
|
|
||||||
|
var button = $(event.relatedTarget)
|
||||||
|
var name,description,loc,start_time,start_day,end_time,end_day
|
||||||
|
id = button.data('id')
|
||||||
|
|
||||||
|
saveButton = document.getElementById("edit-save")
|
||||||
|
saveButton.dataset.id = id
|
||||||
|
|
||||||
|
deleteButton = document.getElementById("delete")
|
||||||
|
deleteButton.dataset.id = id
|
||||||
|
|
||||||
|
editForm = document.getElementById("edit-form")
|
||||||
|
editForm.action = "/admin/event/" + id
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
$.get(`/admin/event/${id}`, (data) => {
|
||||||
|
|
||||||
|
if (data.status == "error") {
|
||||||
|
// This is a new event, do nothing!
|
||||||
|
} else {
|
||||||
|
name = data.name,
|
||||||
|
description = data.description,
|
||||||
|
loc = data.location,
|
||||||
|
category = data.category
|
||||||
|
|
||||||
|
start = new Date(data.start_time)
|
||||||
|
|
||||||
|
var day = ("0" + start.getDate()).slice(-2);
|
||||||
|
var month = ("0" + (start.getMonth() + 1)).slice(-2);
|
||||||
|
|
||||||
|
start_day = start.getFullYear()+"-"+(month)+"-"+(day);
|
||||||
|
start_time = `${start.getHours()}:${padTwoDigits(start.getMinutes())}`
|
||||||
|
end = new Date(data.end_time)
|
||||||
|
|
||||||
|
var day = ("0" + end.getDate()).slice(-2);
|
||||||
|
var month = ("0" + (end.getMonth() + 1)).slice(-2);
|
||||||
|
|
||||||
|
end_day = end.getFullYear()+"-"+(month)+"-"+(day);
|
||||||
|
end_time = `${end.getHours()}:${padTwoDigits(end.getMinutes())}`
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.find('#name').val(name)
|
||||||
|
modal.find('#location').val(loc)
|
||||||
|
modal.find('#description').val(description)
|
||||||
|
modal.find('#start_day').val(start_day)
|
||||||
|
modal.find('#start_time').val(start_time)
|
||||||
|
modal.find('#end_day').val(end_day)
|
||||||
|
modal.find('#end_time').val(end_time)
|
||||||
|
modal.find('#category').val(category)
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function padTwoDigits(num) {
|
||||||
|
return num.toString().padStart(2, '0')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'admin-layout.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block app_content %}
|
||||||
|
<div class="card text-center">
|
||||||
<div style="height: 100%;">
|
<div style="height: 100%;">
|
||||||
<div id="registration-banner" class="parallax-container valign-wrapper">
|
<div id="registration-banner" class="parallax-container valign-wrapper">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
|
@ -9,30 +10,39 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section" style="background-color: #974355; padding: 20px;">
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{{ form.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
<div>
|
<div class="form-floating mb-3 required">
|
||||||
{{ form.name}}<br/> {{ form.name.label }}
|
{{ form.name(class="form-control") }}
|
||||||
|
{{ form.name.label }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="form-floating mb-3">
|
||||||
{{ form.description}}<br/>{{form.description.label}}
|
{{ form.description(class="form-control") }}
|
||||||
|
{{form.description.label}}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="form-floating mb-3 required">
|
||||||
{{ form.location}}<br/>{{form.location.label}}
|
{{ form.location(class="form-control")}}
|
||||||
|
{{form.location.label}}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="row">
|
||||||
{{form.start_time}}<br/>{{form.start_time.label}}
|
<div class="col">
|
||||||
|
<div class="form mb-3 required">
|
||||||
|
{{form.start_time(class="form-control")}}
|
||||||
|
{{form.start_time.label}}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
{{form.end_time}}<br/>{{form.end_time.label}}
|
<div class="col">
|
||||||
|
<div class="form mb-3 required">
|
||||||
|
{{form.end_time(class="form-control")}}
|
||||||
|
{{form.end_time.label}}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
{{form.category}}<br/>{{form.category.label}}
|
</div>
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{form.category(class="form-control")}}
|
||||||
|
{{form.category.label}}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
{{form.submit}}
|
{{form.submit}}
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<!-- A hack to make sure the footer bar shows-->
|
|
||||||
<div style="height: 100px"></div>
|
|
||||||
<nav class="navbar navbar-inverse footer-nav" style= "margin-top: 30px">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="navbar-header">
|
|
||||||
</div>
|
|
||||||
<ul class="nav justify-content-end">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="mailto:hack@wpi.edu?subject=[Hackathon]">Contact Us</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,45 +0,0 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
|
||||||
<link href="../static/css/materialize.min.css" rel="stylesheet">
|
|
||||||
{% assets 'scss' %}
|
|
||||||
<link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
|
|
||||||
{% endassets %}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
nav {
|
|
||||||
background-color: #F5665B;
|
|
||||||
border-color: #E7E4C6;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<nav class="navbar navbar-inverse sticky-top navbar-expand">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<a class="navbar-brand" href="/">Goathacks</a>
|
|
||||||
</div>
|
|
||||||
<ul class="nav justify-content-end">
|
|
||||||
<!-- <li class="nav-item">
|
|
||||||
{% if registration_open or registration_open is not defined %}
|
|
||||||
<a class="nav-link active" href="/register">Register</a>
|
|
||||||
{% else %}
|
|
||||||
<a class="nav-link active disabled" href="#">Registration is closed</a>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="../static/assets/Hack@WPI-SponsorshipInformation-2020.pdf">Sponsorship Packet</a>
|
|
||||||
</li> -->
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="https://hack.wpi.edu/conduct/conduct.pdf">Code of Conduct</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit fba594664faeb8b6056462a0f8bc79a0d21a3768
|
Subproject commit db2a7a865f9b3865fa2180b1b53b1c2d2640be81
|
|
@ -1,195 +0,0 @@
|
||||||
{% include 'header.html' %}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
hr {
|
|
||||||
margin-top: 2rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
width: 70%;
|
|
||||||
border-width: 10px;
|
|
||||||
border-color: #F5665B;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
h4 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
h5 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
h6 {
|
|
||||||
text-align: center;
|
|
||||||
margin-right: 100px;
|
|
||||||
margin-left: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.main-logo {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sponsors {
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sponsors > div {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sponsors > div:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.sponsors img {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 40px;
|
|
||||||
/* Hack to fix overflow of bose logo*/
|
|
||||||
max-width: calc(100% - 10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-sponsors img{
|
|
||||||
max-height: 90px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.silver-sponsors img {
|
|
||||||
max-height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
.x{
|
|
||||||
background-color: #E7E4C6;
|
|
||||||
margin-right: 100px;
|
|
||||||
margin-left: 100px;
|
|
||||||
color: black;
|
|
||||||
border-radius: 50px 50px 50px 50px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
padding-top:10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snow-banner {
|
|
||||||
background-color: red;
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<div class="snow-banner">
|
|
||||||
<b>Attention!</b> Due to the road conditions, we have delayed the schedule by an hour. We will still have live presentations, but submissions have been extended until 9am, and judging will take place at 10am.
|
|
||||||
</div>
|
|
||||||
<!--Logo + Date+ Hosted By -->
|
|
||||||
<div class="container">
|
|
||||||
<div class="row center main-logo">
|
|
||||||
<img src="../static/img/hackwpilogo.png" alt="logo" style='height: 100%; width: 100%; object-fit: contain'/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--"Hackathon for all students" -->
|
|
||||||
<hr/>
|
|
||||||
<h2> A HACKATHON FOR ALL COLLEGE STUDENTS </h2>
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<!--Location -->
|
|
||||||
<h3> WPI Campus Center </h3>
|
|
||||||
<h4>100 Institute Road</h4>
|
|
||||||
<h4> Worcester, MA 01609</h4>
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Sponsors for 2020 -->
|
|
||||||
<h2> OUR SPONSORS FOR 2020 </h2>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="row center sponsors">
|
|
||||||
<div class="title-sponsors">
|
|
||||||
<img class="logo" src="../static/img/logos/bose.png"></div>
|
|
||||||
<div class="platinum-sponsors">
|
|
||||||
<h1>WPI Computer Science Department</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gold-sponsors">
|
|
||||||
<img class="logo" src="../static/img/logos/iboss.png" style = "height: 150px">
|
|
||||||
<img class="logo" src="../static/img/logos/kronos.png" style = "height: 75px">
|
|
||||||
<img class="logo" src="../static/img/logos/paytronix.png" style = "height: 30px">
|
|
||||||
<img class="logo" src="../static/img/logos/abbvie.png" style = "height: 60px">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="silver-sponsors">
|
|
||||||
<img class="logo" src="../static/img/logos/carbonblack.png" >
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bronze-sponsors">
|
|
||||||
<img class="logo" src="../static/img/logos/wakefly.png" style = "height: 70px">
|
|
||||||
<img class="logo" src="../static/img/logos/amazon.png" style = "height: 70px">
|
|
||||||
<img class="logo" src="../static/img/logos/everquote.png" style = "height: 35px">
|
|
||||||
<img class="logo" src="../static/img/logos/synopses.png" style = "height: 20px">
|
|
||||||
<img class="logo" src="../static/img/logos/boozallenhamilton.png" style = "height: 35px">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--FAQs -->
|
|
||||||
<hr/>
|
|
||||||
<div class = "x">
|
|
||||||
<h2> FAQs </h2>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>Who can attend?</h4>
|
|
||||||
<h6> Our event is open to any college student! You don’t need any experience to participate. However, due to legal issues, anyone under 18 must have a legal guardian present and cannot win prizes </h6>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>What is the max team size?</h4>
|
|
||||||
<h6>The maximum is 5 people per team. Minimum is 1 :P</h6>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>What are the awards for?</h4>
|
|
||||||
<h6>The categories this year are: </h6>
|
|
||||||
<h6>Best Overall Project
|
|
||||||
<h6>Best Game </h6>
|
|
||||||
<h6>Best Software </h6>
|
|
||||||
<h6>Best Hardware </h6>
|
|
||||||
<h6>Company Favorite </h6>
|
|
||||||
<h6>Best Use of the Bose API/SDK </h6>
|
|
||||||
<h6>Best Meme </h6>
|
|
||||||
<h6>Best Rookie </h6>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>What should I bring?</h4>
|
|
||||||
<h6>Bring devices, chargers, sleeping bags, toiletries, basically anything you need to be comfortable. We will provide showers at certain time slots during the weekend. Food will also be provided.</h6>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>What if I don't have a team?</h4>
|
|
||||||
<h6>You don’t need a team to register! We will have a team formation session right after the opening ceremony for those who would like to work with a team. If you prefer to stay solo, that’s also great. </h6>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>How should I prepare beforehand?</h4>
|
|
||||||
<h6>Make sure you have travel plans in place, especially in case of random snowfalls. Unfortunately, we do not provide travel reimbursements.
|
|
||||||
It’s also nice to have an idea in mind beforehand. However, we ask that you do not bring any pre-made materials to keep the competition fair. </h6>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "FAQ">
|
|
||||||
<h4>What is the schedule?</h4>
|
|
||||||
<h6><a href = 'https://docs.google.com/spreadsheets/d/1FSh2UfZwoMwXlgrKnKjnQg2okEcLDVCP30khnPdM1H0/edit?usp=sharing' style= "color: blue">Here it is!</a> Keep in mind that this is tentative. </h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% include 'footer.html' %}
|
|
56
goathacks/templates/layout.html
Normal file
56
goathacks/templates/layout.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{% extends 'bootstrap-base.html' %}
|
||||||
|
|
||||||
|
{% block html_attribs %} lang="en"{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}{% if title %}{{ title }} - GoatHacks{% else %}GoatHacks{%
|
||||||
|
endif %}{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{{super()}}
|
||||||
|
{{ font_awesome.load_css() }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{{super()}}
|
||||||
|
{% assets 'scss' %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
|
||||||
|
{% endassets %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block navbar %}
|
||||||
|
<nav class="navbar navbar-dark mb-4 navbar-expand-lg">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#navbarSupportedContent"
|
||||||
|
aria-controls="navbarSupportedContent"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-label="Toggle
|
||||||
|
navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-header">
|
||||||
|
<a class="navbar-brand" href="{{ url_for('registration.register') }}">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.png')}}"
|
||||||
|
alt="Logo" width="35" height="35" class="d-inline-block
|
||||||
|
align-text-middle mx-2">GoatHacks</a>
|
||||||
|
</div>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="nav navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
{{ render_nav_item('registration.register', 'Home')}}
|
||||||
|
</ul>
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
{{ render_nav_item('dashboard.home', 'Dashboard') }}
|
||||||
|
{% if current_user.is_admin %}
|
||||||
|
{{ render_nav_item('admin.home', 'Admin Dash') }}
|
||||||
|
{% endif %}
|
||||||
|
{{ render_nav_item('registration.logout', 'Logout') }}
|
||||||
|
{% else %}
|
||||||
|
{{ render_nav_item('registration.register', 'Registration') }}
|
||||||
|
{{ render_nav_item('registration.login', 'Login') }}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
|
@ -1,34 +1,34 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
{% from 'bootstrap5/form.html' import render_field %}
|
||||||
|
|
||||||
{% block content %}
|
{% block app_content %}
|
||||||
<div style="height: 100%;">
|
<div class="card text-center">
|
||||||
<div id="registration-banner" class="parallax-container valign-wrapper">
|
<div class="card-body">
|
||||||
<div class="section">
|
<img class="mb-4" src="{{ url_for('static', filename='img/banner.png')
|
||||||
<h3 class="header-center text-darken-2">Login</h3>
|
}}" alt="GoatHacks 2024 Banner">
|
||||||
|
<h1 class="h3 mb-3 fw-normal">Welcome back to GoatHacks!</h1>
|
||||||
|
<p class="card-text">If you've already registered, please use this page
|
||||||
|
to access your participant dashboard. Otherwise, please use the <a
|
||||||
|
href="{{
|
||||||
|
url_for('registration.register')
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
registration</a> page to register!</p>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<form action="" method="post" class="form" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.email(class="form-control") }}
|
||||||
|
{{ form.email.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.password(class="form-control") }}
|
||||||
|
{{ form.password.label() }}
|
||||||
|
</div>
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
|
||||||
<div class="section" style="background-color: #974355; padding: 20px;">
|
|
||||||
<form method="post">
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
<div>
|
|
||||||
{{form.email}}<br/>{{ form.email.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.password}}<br/>{{form.password.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.submit}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<span><p><em>Don't have an account? <a
|
|
||||||
href="{{url_for('registration.register')}}">Register
|
|
||||||
here</a>.</em></p></span>
|
|
||||||
|
|
||||||
<span><p><em>Forgot your password? Head over <a
|
|
||||||
href="{{url_for('registration.reset')}}">here</a>
|
|
||||||
to reset it.</em></p></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
<!DOCTYPE html>
|
{% extends 'admin-layout.html' %}
|
||||||
<html lang="en">
|
|
||||||
<head>
|
{% block head %}
|
||||||
<title>🍪CookieMailer</title>
|
{{super()}}
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<meta name="description" content="" />
|
<meta name="description" content="" />
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
|
||||||
<meta name="theme-color" content="">
|
<meta name="theme-color" content="">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/mail.css" />
|
|
||||||
<script src="https://cdn.tiny.cloud/1/{{MCE_API_KEY}}/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script></head>
|
<script src="https://cdn.tiny.cloud/1/{{MCE_API_KEY}}/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script></head>
|
||||||
<body>
|
{% endblock %}
|
||||||
<div id="loader"></div>
|
{% block app_content %}
|
||||||
<div class="container">
|
<div class="card">
|
||||||
<div class="row">
|
<div class="card-body">
|
||||||
<div id="root" class="col">
|
<h1 class="h3 mb-3 fw-normal">🍪CookieMailer</h1>
|
||||||
<h2>🍪CookieMailer</h2>
|
|
||||||
<label for="recipients">To: </label>
|
<label for="recipients">To: </label>
|
||||||
<br/>
|
<br/>
|
||||||
<select id="recipients" name="recipients">
|
<select class="form-control" id="recipients" name="recipients">
|
||||||
<option value="admin">Test Email (SysAdmin)</option>
|
<option value="admin">Test Email (SysAdmin)</option>
|
||||||
<option value="org">Test Email (Organizers)</option>
|
<option value="org">Test Email (Organizers)</option>
|
||||||
<!-- <option value="wpi">WPI Only</option> -->
|
<!-- <option value="wpi">WPI Only</option> -->
|
||||||
|
@ -26,7 +23,8 @@
|
||||||
<br/>
|
<br/>
|
||||||
<label for="subject">Subject: </label>
|
<label for="subject">Subject: </label>
|
||||||
<br/>
|
<br/>
|
||||||
<input id="subject" name="subject" width="100%" type="text" value="Hack@WPI" />
|
<input class="form-control" id="subject" name="subject" width="100%"
|
||||||
|
type="text" value="GoatHacks -- " />
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<textarea id="content" name="content">
|
<textarea id="content" name="content">
|
||||||
|
@ -40,7 +38,7 @@
|
||||||
</textarea>
|
</textarea>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<input type="button" onClick="send()" value="Send"/>
|
<input class="btn btn-primary" type="button" onClick="send()" value="Send"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,6 +75,7 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
if((rec != "all" && window.confirm("Send test email?")) || (rec == "all" && window.confirm("Send email to {{NUM_HACKERS}} recipients?"))) {
|
if((rec != "all" && window.confirm("Send test email?")) || (rec == "all" && window.confirm("Send email to {{NUM_HACKERS}} recipients?"))) {
|
||||||
|
console.log(`Sending email to ${rec}`)
|
||||||
fetch('/admin/send', {method: 'POST', body: JSON.stringify(body), headers: headers}).then(async (res) => {
|
fetch('/admin/send', {method: 'POST', body: JSON.stringify(body), headers: headers}).then(async (res) => {
|
||||||
window.alert(await res.text());
|
window.alert(await res.text());
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
@ -96,6 +95,7 @@
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div style="height: 100%;">
|
|
||||||
<div id="registration-banner" class="parallax-container valign-wrapper">
|
|
||||||
<div class="section">
|
|
||||||
<h3 class="header-center text-darken-2">Reset Password</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="section" style="background-color: #974355; padding: 20px;">
|
|
||||||
<form method="post">
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
<div>
|
|
||||||
{{form.password}}<br/>{{form.password.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.password_confirm}}<br/>{{form.password_confirm.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.submit}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,24 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div style="height: 100%">
|
|
||||||
<div id="registration-banner" class="parallax-container valign-wrapper">
|
|
||||||
<div class="section">
|
|
||||||
<h3 class="header-center text-darken-2">Reset Password</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="section" style="background-color: #974355; padding: 20px;">
|
|
||||||
<form method="post">
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
<div>
|
|
||||||
{{ form.email }}<br/>{{ form.email.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.submit}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,58 +1,112 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
{% from 'bootstrap5/form.html' import render_field %}
|
||||||
|
|
||||||
{% block content %}
|
{% block app_content %}
|
||||||
<div style="height: 100%;">
|
<div class="card text-center">
|
||||||
<div id="registration-banner" class="parallax-container valign-wrapper">
|
<div class="card-body">
|
||||||
<div class="section">
|
<img class="mb-4" src="{{ url_for('static', filename='img/banner.png')
|
||||||
<h3 class="header-center text-darken-2">Registration</h3>
|
}}" alt="GoatHacks Banner">
|
||||||
|
<h1 class="h3 mb-3 fw-normal">Welcome to GoatHacks!</h1>
|
||||||
|
<p class="card-text">Please use this page to register for this year's
|
||||||
|
Hackathon. Accounts from prior years are not carried over!</p>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<form action="" method="post" class="form" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.email(class="form-control") }}
|
||||||
|
{{ form.email.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.password(class="form-control") }}
|
||||||
|
{{ form.password.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.password_confirm(class="form-control") }}
|
||||||
|
{{ form.password_confirm.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.first_name(class="form-control") }}
|
||||||
|
{{ form.first_name.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.last_name(class="form-control") }}
|
||||||
|
{{ form.last_name.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.school(class="form-control") }}
|
||||||
|
{{ form.school.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.country(class="form-control") }}
|
||||||
|
{{ form.country.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.phone_number(class="form-control") }}
|
||||||
|
{{ form.phone_number.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.age(class="form-control") }}
|
||||||
|
{{ form.age.label() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3 required">
|
||||||
|
{{ form.gender(class="form-control") }}
|
||||||
|
{{ form.gender.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
{{ form.dietary_restrictions(class="form-control") }}
|
||||||
|
{{ form.dietary_restrictions.label() }}
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-3 required">
|
||||||
|
{{ form.agree_coc }}
|
||||||
|
I confirm that I have read and agree to the <a href="https://static.mlh.io/docs/mlh-code-of-conduct.pdf" target="_blank">MLH Code of Conduct</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-3 required">
|
||||||
|
{{ form.logistics }}
|
||||||
|
I authorize you to share my application/registration with Major League Hacking
|
||||||
|
for event administration, ranking, and MLH administration in-line with the MLH
|
||||||
|
privacy policy. I further agree to the terms of both the <a
|
||||||
|
href="https://github.com/MLH/mlh-policies/blob/main/contest-terms.md">MLH
|
||||||
|
Contest Terms
|
||||||
|
and
|
||||||
|
Conditions</a>
|
||||||
|
and the <a
|
||||||
|
href="https://github.com/MLH/mlh-policies/blob/main/privacy-policy.md">MLH
|
||||||
|
Privacy
|
||||||
|
Policy</a>.
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
{{ form.newsletter }}
|
||||||
|
Subscribe to the MLH newsletter?
|
||||||
|
</div>
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
|
||||||
<div class="section" style="background-color: #974355; padding: 20px;">
|
|
||||||
<form method="post">
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
<div>
|
|
||||||
{{ form.email}}<br/> {{ form.email.label }}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{ form.password}}<br/>{{form.password.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{ form.password_confirm}}<br/>{{form.password_confirm.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.first_name}}<br/>{{form.first_name.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.last_name}}<br/>{{form.last_name.label}}
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
<h3>Miscellaneous Information</h3>
|
|
||||||
<div>
|
|
||||||
{{form.phone_number}}<br/>{{form.phone_number.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.school}}<br/>{{form.school.label}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.gender.label}}{{form.gender}}
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
<div>
|
|
||||||
<label for="agree_coc">I confirm that I have read and agree to the
|
|
||||||
Code of Conduct</label>
|
|
||||||
<input type="checkbox" id="agree_coc" name="agree_coc">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{form.submit}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<span><p><em>You may also want to <a
|
|
||||||
href="{{url_for('registration.login')}}">
|
|
||||||
log in</a>.</em></p></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
{% include 'header.html' %}
|
|
||||||
<link href="../static/css/materialize.min.css" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
a{
|
|
||||||
color: skyblue;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
function resumeChange() {
|
|
||||||
let val = document.getElementById('resume').value;
|
|
||||||
val = val.split(/\\|\//gi).slice(-1)[0]
|
|
||||||
document.getElementById('filename').setAttribute('value', val);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div style="height: 100%;">
|
|
||||||
<div id="registration-banner" class="parallax-container valign-wrapper">
|
|
||||||
<div class="section">
|
|
||||||
<h3 class="header center text-darken-2">Registration</h3>
|
|
||||||
</div>
|
|
||||||
<div class="parallax"><img src="../static/img/background1.jpg" alt="background"></div>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="container">
|
|
||||||
<Center><h2>Hi {{ name }}, just a few more steps!</h2></Center>
|
|
||||||
<div class="section" style="background-color: #974355; padding: 20px;">
|
|
||||||
<form method="post" action="/register" enctype="multipart/form-data">
|
|
||||||
<div>
|
|
||||||
<p><b>If you'd like, add your resume to send to sponsors... </b></p>
|
|
||||||
<div class="file-field input-field">
|
|
||||||
<div class="btn">
|
|
||||||
<span>File</span>
|
|
||||||
<input id="resume" name="resume" type="file" oninput="resumeChange()"/>
|
|
||||||
</div>
|
|
||||||
<div class="file-path-wrapper white-text">
|
|
||||||
<input disabled id="filename" class="file-path validate white-text" type="text">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p><i>No worries if you don't have one on hand, you can come back and upload it later via the Hack@WPI dashboard!</i></p>
|
|
||||||
<p>Please take a moment to review the following policies and check all the boxes below so we can finalize your registration:</p>
|
|
||||||
<p>
|
|
||||||
<center><a href="/tos">Hack@WPI's Terms and Conditions</a></center>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<center><a href="https://github.com/MLH/mlh-policies/blob/master/data-sharing.md">MLH's Data Sharing Notice</a></center>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<center><a href="https://mlh.io/privacy">MLH's Privacy Policy</a></center>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<center><a href="https://github.com/MLH/mlh-policies/blob/master/prize-terms-and-conditions/contest-terms.md">MLH's
|
|
||||||
Contest Terms and Conditions</a></center>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<center><a href="https://static.mlh.io/docs/mlh-code-of-conduct.pdf">MLH's Code of Conduct</a></center>
|
|
||||||
</p>
|
|
||||||
<br>
|
|
||||||
<input type="checkbox" name="tos" id="checkboxid" required><label for="checkboxid"><b style="color:white;">*I have read and agree to the Hack@WPI Terms and Conditions</b></label>
|
|
||||||
<input type="checkbox" name="mlh1" id="checkboxid1" required><label for="checkboxid1"><b style="color:white;">*I have read and agree to the MLH Code of Conduct</b></label>
|
|
||||||
<input type="checkbox" name="mlh2" id="checkboxid2" required><label for="checkboxid2"><b style="color:white;">*I authorize you to share my application/registration information with Major League Hacking for event administration, ranking, and MLH administration in-line with the MLH Privacy Policy. I further agree to the terms of both the MLH Contest Terms and Conditions and the MLH Privacy Policy.</b></label>
|
|
||||||
<input type="checkbox" name="mlh3" id="checkboxid3" required><label for="checkboxid3"><b style="color:white;">*I authorize MLH to send me pre- and post-event information emails, which contain free credit and opportunities from their partners.</b></label>
|
|
||||||
<input type="checkbox" name="mlh3" id="checkboxid4" required><label for="checkboxid4"><b style="color:white;">*I understand that in-person participation is limited to WPI students that are part of the testing protocol only.</b></label>
|
|
||||||
<br><br>
|
|
||||||
<center><input name="submit" class="btn btn-lg btn-primary btn-invert" type="submit" value="Submit"/></center>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include 'footer.html' %}
|
|
|
@ -1,16 +0,0 @@
|
||||||
{% include 'header.html' %}
|
|
||||||
<link href="../static/css/materialize.min.css" rel="stylesheet">
|
|
||||||
<div style="margin: 16px">
|
|
||||||
<p>
|
|
||||||
I agree to hold harmless the organizers of HACK@WPI and WPI’s Chapter of the Association of Computing Machinery (ACM) from any and all claims, lawsuits, demands, causes of action, liability, loss, damage and/or injury of any kind whatsoever (including without limitation all claims for monetary loss, property damager, equitable relief, personal injury and/or wrongful death), whether brought by an individual or other entity. The indemnification applies to and includes, without limitation, the payment of all penalties, fines, judgments, awards, decrees, attorneys’ fees, and related costs or expenses, and any reimbursements to ACM for all legal fees, expenses, and costs incurred by it.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
I also acknowledge the organizers of HACK@WPI will be recording the event using video, photographs, audio recordings, and other media and give them permission to use said media in marketing/promotional materials.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- This is stupid but it works -->
|
|
||||||
<div style="position: absolute; bottom: 0; width: 100%;">
|
|
||||||
{% include 'footer.html' %}
|
|
||||||
</div>
|
|
38
migrations/versions/f5b70c6e73eb_.py
Normal file
38
migrations/versions/f5b70c6e73eb_.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: f5b70c6e73eb
|
||||||
|
Revises: 858e0d45876f
|
||||||
|
Create Date: 2024-10-31 13:04:48.500263
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f5b70c6e73eb'
|
||||||
|
down_revision = '858e0d45876f'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('newsletter', sa.Boolean(), nullable=False))
|
||||||
|
batch_op.add_column(sa.Column('country', sa.String(), nullable=False))
|
||||||
|
batch_op.add_column(sa.Column('age', sa.Integer(), nullable=False))
|
||||||
|
batch_op.add_column(sa.Column('dietary_restrictions', sa.String(), nullable=True))
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||||
|
batch_op.drop_column('dietary_restrictions')
|
||||||
|
batch_op.drop_column('age')
|
||||||
|
batch_op.drop_column('country')
|
||||||
|
batch_op.drop_column('newsletter')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
|
@ -9,7 +9,7 @@ Flask-Login==0.6.2
|
||||||
Flask-Migrate==4.0.0
|
Flask-Migrate==4.0.0
|
||||||
Flask-SQLAlchemy==3.0.2
|
Flask-SQLAlchemy==3.0.2
|
||||||
Flask-WTF==1.0.1
|
Flask-WTF==1.0.1
|
||||||
greenlet==2.0.1
|
greenlet
|
||||||
itsdangerous==2.1.2
|
itsdangerous==2.1.2
|
||||||
Jinja2==3.1.2
|
Jinja2==3.1.2
|
||||||
Mako==1.2.4
|
Mako==1.2.4
|
||||||
|
@ -19,7 +19,11 @@ psycopg2==2.9.5
|
||||||
pynvim==0.4.3
|
pynvim==0.4.3
|
||||||
python-dotenv==0.21.0
|
python-dotenv==0.21.0
|
||||||
SQLAlchemy==1.4.44
|
SQLAlchemy==1.4.44
|
||||||
uWSGI==2.0.21
|
uWSGI
|
||||||
Werkzeug==2.2.2
|
Werkzeug==2.2.2
|
||||||
WTForms==3.0.1
|
WTForms==3.0.1
|
||||||
ulid
|
ulid
|
||||||
|
bootstrap-flask
|
||||||
|
Font-Awesome-Flask
|
||||||
|
tabulate
|
||||||
|
markupsafe
|
||||||
|
|
Loading…
Add table
Reference in a new issue