Initial Commit
824
.gitignore
vendored
Normal file
|
@ -0,0 +1,824 @@
|
||||||
|
config_hackWPI.py
|
||||||
|
config.py
|
||||||
|
# Created by https://www.gitignore.io/api/web,vim,git,macos,linux,bower,grunt,python,pycharm,windows,eclipse,webstorm,intellij,jetbrains,virtualenv,visualstudio,visualstudiocode
|
||||||
|
|
||||||
|
### Bower ###
|
||||||
|
bower_components
|
||||||
|
.bower-cache
|
||||||
|
.bower-registry
|
||||||
|
.bower-tmp
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
|
||||||
|
.metadata
|
||||||
|
bin/
|
||||||
|
tmp/
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.settings/
|
||||||
|
.loadpath
|
||||||
|
.recommenders
|
||||||
|
|
||||||
|
# Eclipse Core
|
||||||
|
.project
|
||||||
|
|
||||||
|
# External tool builders
|
||||||
|
.externalToolBuilders/
|
||||||
|
|
||||||
|
# Locally stored "Eclipse launch configurations"
|
||||||
|
*.launch
|
||||||
|
|
||||||
|
# PyDev specific (Python IDE for Eclipse)
|
||||||
|
*.pydevproject
|
||||||
|
|
||||||
|
# CDT-specific (C/C++ Development Tooling)
|
||||||
|
.cproject
|
||||||
|
|
||||||
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
# Java annotation processor (APT)
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# PDT-specific (PHP Development Tools)
|
||||||
|
.buildpath
|
||||||
|
|
||||||
|
# sbteclipse plugin
|
||||||
|
.target
|
||||||
|
|
||||||
|
# Tern plugin
|
||||||
|
.tern-project
|
||||||
|
|
||||||
|
# TeXlipse plugin
|
||||||
|
.texlipse
|
||||||
|
|
||||||
|
# STS (Spring Tool Suite)
|
||||||
|
.springBeans
|
||||||
|
|
||||||
|
# Code Recommenders
|
||||||
|
.recommenders/
|
||||||
|
|
||||||
|
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||||
|
.cache-main
|
||||||
|
.scala_dependencies
|
||||||
|
.worksheet
|
||||||
|
|
||||||
|
### Git ###
|
||||||
|
*.orig
|
||||||
|
|
||||||
|
### grunt ###
|
||||||
|
# Grunt usually compiles files inside this directory
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Grunt usually preprocesses files such as coffeescript, compass... inside the .tmp directory
|
||||||
|
.tmp/
|
||||||
|
|
||||||
|
### Intellij ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
### Intellij Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
.idea/sonarlint
|
||||||
|
|
||||||
|
### JetBrains ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
|
||||||
|
### JetBrains Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
*.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### PyCharm ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
|
||||||
|
### PyCharm Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
.hypothesis/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# dotenv
|
||||||
|
.env
|
||||||
|
|
||||||
|
# virtualenv
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-v][a-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
# session
|
||||||
|
Session.vim
|
||||||
|
# temporary
|
||||||
|
.netrwhist
|
||||||
|
# auto-generated tag files
|
||||||
|
tags
|
||||||
|
|
||||||
|
### VirtualEnv ###
|
||||||
|
# Virtualenv
|
||||||
|
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
|
||||||
|
[Bb]in
|
||||||
|
[Ii]nclude
|
||||||
|
[Ll]ib
|
||||||
|
[Ll]ib64
|
||||||
|
[Ll]ocal
|
||||||
|
[Ss]cripts
|
||||||
|
pyvenv.cfg
|
||||||
|
pip-selfcheck.json
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
### Web ###
|
||||||
|
*.asp
|
||||||
|
*.cer
|
||||||
|
*.csr
|
||||||
|
*.htm
|
||||||
|
*.jsp
|
||||||
|
*.php
|
||||||
|
*.rss
|
||||||
|
*.xhtml
|
||||||
|
|
||||||
|
### WebStorm ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
|
||||||
|
### WebStorm Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
### VisualStudio ###
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
**/Properties/launchSettings.json
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp_proj
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush
|
||||||
|
.cr/
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/web,vim,git,macos,linux,bower,grunt,python,pycharm,windows,eclipse,webstorm,intellij,jetbrains,virtualenv,visualstudio,visualstudiocode
|
||||||
|
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
.hypothesis/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# IPython Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# dotenv
|
||||||
|
.env
|
||||||
|
|
||||||
|
# virtualenv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Kevin Bohinski
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
20
README.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Hack@WPI 2018 Website
|
||||||
|
Used chronicel's registration system as a base but removed the need of mailchimp.
|
||||||
|
|
||||||
|
Rest is from their repo:
|
||||||
|
|
||||||
|
## Setup:
|
||||||
|
- Clone repo
|
||||||
|
- `pip3 install -r requirements.txt`
|
||||||
|
- Fill in all config files!
|
||||||
|
- Database:
|
||||||
|
```sh
|
||||||
|
python3
|
||||||
|
```
|
||||||
|
```python
|
||||||
|
from flask_app import db
|
||||||
|
db.create_all()
|
||||||
|
```
|
||||||
|
- Automatic waitlist management setup: Setup your favorite cron like tool to run `python3 manage_waitlist.py` nightly!
|
||||||
|
- `python3 flask_app.py`
|
||||||
|
- 🎉 🔥 🙌 💃 👌 💯
|
BIN
admin.png
Normal file
After Width: | Height: | Size: 529 KiB |
1
dependency_ubuntu
Normal file
|
@ -0,0 +1 @@
|
||||||
|
sudo apt-get install python-mysqldb
|
540
flask_app.py
Normal file
|
@ -0,0 +1,540 @@
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import smtplib
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from flask import Flask, render_template, redirect, url_for, request, session, jsonify
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from mailchimp3 import MailChimp
|
||||||
|
from pubnub.pnconfiguration import PNConfiguration
|
||||||
|
from pubnub.pubnub import PubNub
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
|
from config_hackWPI import api_keys, WAITLIST_LIMIT, HACKATHON_TIME, ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_pyfile('config.py')
|
||||||
|
|
||||||
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
pnconfig = PNConfiguration()
|
||||||
|
|
||||||
|
pnconfig.publish_key = api_keys['pubnub']['pub']
|
||||||
|
pnconfig.subscribe_key = api_keys['pubnub']['sub']
|
||||||
|
pnconfig.ssl = True
|
||||||
|
|
||||||
|
pn = PubNub(pnconfig)
|
||||||
|
|
||||||
|
|
||||||
|
class Hacker(db.Model):
|
||||||
|
__tablename__ = 'hackers'
|
||||||
|
|
||||||
|
mlh_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
registration_time = db.Column(db.Integer)
|
||||||
|
checked_in = db.Column(db.Boolean)
|
||||||
|
waitlisted = db.Column(db.Boolean)
|
||||||
|
admin = db.Column(db.Boolean)
|
||||||
|
first_name = db.Column(db.String(100))
|
||||||
|
last_name = db.Column(db.String(100))
|
||||||
|
email = db.Column(db.String(100))
|
||||||
|
|
||||||
|
|
||||||
|
class AutoPromoteKeys(db.Model):
|
||||||
|
__tablename__ = 'AutoPromoteKeys'
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
key = db.Column(db.String(4096))
|
||||||
|
val = db.Column(db.String(4096))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def root():
|
||||||
|
print("Someone visited!.")
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/register', methods=['GET', 'POST'])
|
||||||
|
def register():
|
||||||
|
if request.method == 'GET':
|
||||||
|
# Register a hacker...
|
||||||
|
if is_logged_in() and db.session.query(
|
||||||
|
db.exists().where(Hacker.mlh_id == session['mymlh']['id'])).scalar():
|
||||||
|
# Already logged in, take them to dashboard
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
|
if request.args.get('code') is None:
|
||||||
|
# Get info from MyMLH
|
||||||
|
return redirect(
|
||||||
|
'https://my.mlh.io/oauth/authorize?client_id=' + api_keys['mlh']['client_id'] + '&redirect_uri=' +
|
||||||
|
api_keys['mlh'][
|
||||||
|
'callback'] + '&response_type=code&scope=email+phone_number+demographics+birthday+education+event')
|
||||||
|
|
||||||
|
if is_logged_in():
|
||||||
|
return render_template('register.html', name=session['mymlh']['first_name'])
|
||||||
|
|
||||||
|
code = request.args.get('code')
|
||||||
|
oauth_redirect = requests.post(
|
||||||
|
'https://my.mlh.io/oauth/token?client_id=' + api_keys['mlh']['client_id'] + '&client_secret=' +
|
||||||
|
api_keys['mlh'][
|
||||||
|
'secret'] + '&code=' + code + '&redirect_uri=' + api_keys['mlh'][
|
||||||
|
'callback'] + '&grant_type=authorization_code')
|
||||||
|
|
||||||
|
if oauth_redirect.status_code == 200:
|
||||||
|
access_token = json.loads(oauth_redirect.text)['access_token']
|
||||||
|
user_info_request = requests.get('https://my.mlh.io/api/v2/user.json?access_token=' + access_token)
|
||||||
|
if user_info_request.status_code == 200:
|
||||||
|
user = json.loads(user_info_request.text)['data']
|
||||||
|
session['mymlh'] = user
|
||||||
|
if db.session.query(db.exists().where(Hacker.mlh_id == user['id'])).scalar():
|
||||||
|
# User already exists in db, log them in
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
|
return render_template('register.html', name=user['first_name'])
|
||||||
|
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
if not is_logged_in() or db.session.query(
|
||||||
|
db.exists().where(Hacker.mlh_id == session['mymlh']['id'])).scalar():
|
||||||
|
# Request flow == messed up somehow, restart them
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
if 'resume' not in request.files:
|
||||||
|
# No file?
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
resume = request.files['resume']
|
||||||
|
if resume.filename == '':
|
||||||
|
resume = False
|
||||||
|
# No file selected
|
||||||
|
#return redirect(url_for('register'))
|
||||||
|
|
||||||
|
if resume and not allowed_file(resume.filename):
|
||||||
|
resume = False
|
||||||
|
#return jsonify(
|
||||||
|
# {'status': 'error', 'action': 'register',
|
||||||
|
# 'more_info': 'Invalid file type... Accepted types are txt pdf doc docx and rtf...'})
|
||||||
|
|
||||||
|
if resume and allowed_file(resume.filename):
|
||||||
|
# Good file!
|
||||||
|
filename = session['mymlh']['first_name'].lower() + '_' + session['mymlh']['last_name'].lower() + '_' + str(
|
||||||
|
session['mymlh']['id']) + '.' + resume.filename.split('.')[-1].lower()
|
||||||
|
filename = secure_filename(filename)
|
||||||
|
resume.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
|
||||||
|
|
||||||
|
# Determine if hacker should be placed on waitlist
|
||||||
|
waitlist = False
|
||||||
|
if db.session.query(Hacker).count() + 1 > WAITLIST_LIMIT:
|
||||||
|
print(session['mymlh']['first_name'] + " put on waitlist.")
|
||||||
|
waitlist = True
|
||||||
|
else:
|
||||||
|
print(session['mymlh']['first_name'] + " put on registered.")
|
||||||
|
|
||||||
|
first_name = session['mymlh']['first_name']
|
||||||
|
last_name = session['mymlh']['last_name']
|
||||||
|
email = session['mymlh']['email']
|
||||||
|
|
||||||
|
# Add the user to the database
|
||||||
|
print(Hacker(mlh_id=session['mymlh']['id'], registration_time=int(time.time()),
|
||||||
|
checked_in=False, waitlisted=waitlist, admin=False))
|
||||||
|
db.session.add(
|
||||||
|
Hacker(mlh_id=session['mymlh']['id'], registration_time=int(time.time()),
|
||||||
|
checked_in=False, waitlisted=waitlist, admin=False,
|
||||||
|
first_name=first_name, last_name=last_name, email=email))
|
||||||
|
db.session.commit()
|
||||||
|
print(session['mymlh']['first_name'] + " put on database successfully.")
|
||||||
|
|
||||||
|
# Send a welcome email
|
||||||
|
msg = 'Hey ' + session['mymlh']['first_name'] + '\n\n'
|
||||||
|
msg += 'Thanks for applying to Hack@WPI!\n'
|
||||||
|
if waitlist:
|
||||||
|
msg += 'Sorry! We have hit our registration capacity. You have been placed on the waitlist.\n'
|
||||||
|
msg += 'We will let you know if space opens up.\n'
|
||||||
|
else:
|
||||||
|
msg += 'You are fully registered! We will send you more info closer to the hackathon.\n'
|
||||||
|
send_email(session['mymlh']['email'], 'Hack@WPI - Thanks for applying', msg)
|
||||||
|
|
||||||
|
pn.publish().channel('hackWPI-admin').message({'action': 'new_user'}).sync()
|
||||||
|
|
||||||
|
# Finally, send them to their dashboard
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin', methods=['GET'])
|
||||||
|
def admin():
|
||||||
|
# Displays total registration information...
|
||||||
|
# As Firebase could not be used with MyMLH, use PubNub to simulate the realtime database...
|
||||||
|
|
||||||
|
if not is_admin():
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
waitlist_count = 0
|
||||||
|
total_count = 0
|
||||||
|
check_in_count = 0
|
||||||
|
shirt_count = {'xs': 0, 's': 0, 'm': 0, 'l': 0, 'xl': 0, }
|
||||||
|
male_count = 0
|
||||||
|
female_count = 0
|
||||||
|
schools = {}
|
||||||
|
majors = {}
|
||||||
|
|
||||||
|
mlh_info = get_mlh_users()
|
||||||
|
|
||||||
|
hackers = []
|
||||||
|
|
||||||
|
result = db.session.query(Hacker)
|
||||||
|
|
||||||
|
for hacker in mlh_info:
|
||||||
|
obj = result.filter(Hacker.mlh_id == hacker['id']).one_or_none()
|
||||||
|
|
||||||
|
if obj is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if obj.waitlisted:
|
||||||
|
waitlist_count += 1
|
||||||
|
|
||||||
|
if obj.checked_in:
|
||||||
|
check_in_count += 1
|
||||||
|
|
||||||
|
if hacker['gender'] == 'Male':
|
||||||
|
male_count += 1
|
||||||
|
else:
|
||||||
|
female_count += 1
|
||||||
|
|
||||||
|
total_count += 1
|
||||||
|
|
||||||
|
if hacker['school']['name'] not in schools:
|
||||||
|
schools[hacker['school']['name']] = 1
|
||||||
|
else:
|
||||||
|
schools[hacker['school']['name']] += 1
|
||||||
|
|
||||||
|
if hacker['major'] not in majors:
|
||||||
|
majors[hacker['major']] = 1
|
||||||
|
else:
|
||||||
|
majors[hacker['major']] += 1
|
||||||
|
|
||||||
|
shirt_count[hacker['shirt_size'].split(' - ')[1].lower()] += 1
|
||||||
|
|
||||||
|
hackers.append({
|
||||||
|
'checked_in': obj.checked_in,
|
||||||
|
'waitlisted': obj.waitlisted,
|
||||||
|
'admin': obj.admin,
|
||||||
|
'registration_time': obj.registration_time,
|
||||||
|
'id': hacker['id'],
|
||||||
|
'email': hacker['email'],
|
||||||
|
'first_name': hacker['first_name'],
|
||||||
|
'last_name': hacker['last_name'],
|
||||||
|
'phone_number': hacker['phone_number'],
|
||||||
|
'dietary_restrictions': hacker['dietary_restrictions'],
|
||||||
|
'special_needs': hacker['special_needs'],
|
||||||
|
'school': hacker['school']
|
||||||
|
})
|
||||||
|
|
||||||
|
return render_template('admin.html', hackers=hackers, total_count=total_count, waitlist_count=waitlist_count,
|
||||||
|
check_in_count=check_in_count, shirt_count=shirt_count, female_count=female_count,
|
||||||
|
male_count=male_count, schools=schools, majors=majors,
|
||||||
|
mlh_url='https://my.mlh.io/api/v2/users.json?client_id=' + api_keys['mlh'][
|
||||||
|
'client_id'] + '&secret=' + api_keys['mlh'][
|
||||||
|
'secret'])
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/change_admin', methods=['GET'])
|
||||||
|
def change_admin():
|
||||||
|
# Promote or drop a given hacker to/from admin status...
|
||||||
|
if not is_admin():
|
||||||
|
return jsonify({'status': 'error', 'action': 'modify_permissions',
|
||||||
|
'more_info': 'You do not have permissions to perform this action...'})
|
||||||
|
|
||||||
|
if request.args.get('mlh_id') is None or request.args.get('action') is None:
|
||||||
|
return jsonify({'status': 'error', 'action': 'change_admin', 'more_info': 'Missing required field...'})
|
||||||
|
|
||||||
|
valid_actions = ['promote', 'demote']
|
||||||
|
if request.args.get('action') not in valid_actions:
|
||||||
|
return jsonify({'status': 'error', 'action': 'change_admin', 'more_info': 'Invalid action...'})
|
||||||
|
|
||||||
|
if request.args.get('action') == 'promote':
|
||||||
|
db.session.query(Hacker).filter(Hacker.mlh_id == request.args.get('mlh_id')).update({'admin': True})
|
||||||
|
elif request.args.get('action') == 'demote':
|
||||||
|
db.session.query(Hacker).filter(Hacker.mlh_id == request.args.get('mlh_id')).update({'admin': False})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
pn.publish().channel('hackWPI-admin').message(
|
||||||
|
{'status': 'success', 'action': 'change_admin:' + request.args.get('action'), 'more_info': '',
|
||||||
|
'id': request.args.get('mlh_id')}).sync()
|
||||||
|
|
||||||
|
return jsonify({'status': 'success', 'action': 'change_admin:' + request.args.get('action'), 'more_info': '',
|
||||||
|
'id': request.args.get('mlh_id')})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/check_in', methods=['GET'])
|
||||||
|
def check_in():
|
||||||
|
# Check in a hacker...
|
||||||
|
if not is_admin():
|
||||||
|
return jsonify({'status': 'error', 'action': 'check_in',
|
||||||
|
'more_info': 'You do not have permissions to perform this action...'})
|
||||||
|
|
||||||
|
if request.args.get('mlh_id') is None:
|
||||||
|
return jsonify({'status': 'error', 'action': 'check_in', 'more_info': 'Missing required field...'})
|
||||||
|
|
||||||
|
# See if hacker was already checked in...
|
||||||
|
checked_in = db.session.query(Hacker.checked_in).filter(
|
||||||
|
Hacker.mlh_id == request.args.get('mlh_id')).one_or_none()
|
||||||
|
|
||||||
|
print(db.session.query(Hacker.checked_in).filter(Hacker.mlh_id == request.args.get('mlh_id')))
|
||||||
|
print(checked_in)
|
||||||
|
if checked_in and checked_in[0]:
|
||||||
|
return jsonify({'status': 'error', 'action': 'check_in', 'more_info': 'Hacker already checked in!'})
|
||||||
|
|
||||||
|
# Update db...
|
||||||
|
db.session.query(Hacker).filter(Hacker.mlh_id == request.args.get('mlh_id')).update({'checked_in': True})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
mlh_info = get_mlh_user(request.args.get('mlh_id'))
|
||||||
|
|
||||||
|
# Send a welcome email...
|
||||||
|
msg = 'Hey ' + mlh_info['first_name'] + ',\n\n'
|
||||||
|
msg += 'Thanks for checking in!\n'
|
||||||
|
msg += 'We will start shortly, please check your dashboard for updates!\n'
|
||||||
|
send_email(mlh_info['email'], 'HackWPI - Thanks for checking in', msg)
|
||||||
|
|
||||||
|
pn.publish().channel('hackWPI-admin').message(
|
||||||
|
{'status': 'success', 'action': 'check_in', 'more_info': '',
|
||||||
|
'id': request.args.get('mlh_id')}).sync()
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{'status': 'success', 'action': 'check_in', 'more_info': '', 'id': request.args.get('mlh_id')})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/drop', methods=['GET'])
|
||||||
|
def drop():
|
||||||
|
# Drop a hacker's registration...
|
||||||
|
if request.args.get('mlh_id') is None:
|
||||||
|
return jsonify({'status': 'error', 'action': 'drop', 'more_info': 'Missing required field...'})
|
||||||
|
|
||||||
|
if not is_admin() and not is_self(request.args.get('mlh_id')):
|
||||||
|
return jsonify({'status': 'error', 'action': 'drop',
|
||||||
|
'more_info': 'You do not have permissions to perform this action...'})
|
||||||
|
|
||||||
|
row = db.session.query(Hacker.checked_in, Hacker.waitlisted).filter(
|
||||||
|
Hacker.mlh_id == request.args.get('mlh_id')).one_or_none()
|
||||||
|
|
||||||
|
if row is None:
|
||||||
|
return jsonify({'status': 'error', 'action': 'drop',
|
||||||
|
'more_info': 'Could not find hacker...'})
|
||||||
|
|
||||||
|
(checked_in, waitlisted) = row
|
||||||
|
|
||||||
|
if checked_in:
|
||||||
|
return jsonify({'status': 'error', 'action': 'drop', 'more_info': 'Cannot drop, already checked in...'})
|
||||||
|
|
||||||
|
mlh_info = get_mlh_user(request.args.get('mlh_id'))
|
||||||
|
print(mlh_info['first_name'] + " trying to drop.")
|
||||||
|
|
||||||
|
|
||||||
|
# Delete from db...
|
||||||
|
row = db.session.query(Hacker).filter(Hacker.mlh_id == request.args.get('mlh_id')).first()
|
||||||
|
db.session.delete(row)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
# Delete resume...
|
||||||
|
for ext in ALLOWED_EXTENSIONS:
|
||||||
|
filename = mlh_info['first_name'].lower() + '_' + mlh_info['last_name'].lower() + '_' + request.args.get(
|
||||||
|
'mlh_id') + '.' + ext
|
||||||
|
try:
|
||||||
|
os.remove(app.config['UPLOAD_FOLDER'] + '/' + filename)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Send a goodbye email...
|
||||||
|
msg = 'Dear ' + mlh_info['first_name'] + ',\n\n'
|
||||||
|
msg += 'Your application was dropped, sorry to see you go.\n'
|
||||||
|
send_email(mlh_info['email'], 'Hack@WPI - Application Dropped', msg)
|
||||||
|
|
||||||
|
pn.publish().channel('hackWPI-admin').message(
|
||||||
|
{'status': 'success', 'action': 'drop', 'more_info': '', 'id': request.args.get('mlh_id')}).sync()
|
||||||
|
|
||||||
|
if is_self(request.args.get('mlh_id')):
|
||||||
|
session.clear()
|
||||||
|
|
||||||
|
print(mlh_info['first_name'] + " dropped successfully.")
|
||||||
|
return jsonify({'status': 'success', 'action': 'drop', 'more_info': '', 'id': request.args.get('mlh_id')})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/promote_from_waitlist', methods=['GET'])
|
||||||
|
def promote_from_waitlist():
|
||||||
|
# Promote a hacker from the waitlist...
|
||||||
|
if request.args.get('mlh_id') is None:
|
||||||
|
return jsonify({'status': 'error', 'action': 'promote_from_waitlist', 'more_info': 'Missing required field...'})
|
||||||
|
|
||||||
|
(key, val) = get_auto_promote_keys()
|
||||||
|
|
||||||
|
if request.args.get(key) is None:
|
||||||
|
if not is_admin():
|
||||||
|
return jsonify({'status': 'error', 'action': 'promote_from_waitlist',
|
||||||
|
'more_info': 'You do not have permissions to perform this action...'})
|
||||||
|
else:
|
||||||
|
if request.args.get(key) != val:
|
||||||
|
return jsonify({'status': 'error', 'action': 'promote_from_waitlist',
|
||||||
|
'more_info': 'Invalid auto promote keys...'})
|
||||||
|
|
||||||
|
(checked_in, waitlisted) = db.session.query(Hacker.checked_in, Hacker.waitlisted).filter(
|
||||||
|
Hacker.mlh_id == request.args.get('mlh_id')).one_or_none()
|
||||||
|
|
||||||
|
if checked_in:
|
||||||
|
return jsonify(
|
||||||
|
{'status': 'error', 'action': 'promote_from_waitlist',
|
||||||
|
'more_info': 'Cannot promote, already checked in...'})
|
||||||
|
|
||||||
|
if not waitlisted:
|
||||||
|
return jsonify(
|
||||||
|
{'status': 'error', 'action': 'promote_from_waitlist',
|
||||||
|
'more_info': 'Cannot promote, user is not waitlisted...'})
|
||||||
|
|
||||||
|
# Update db...
|
||||||
|
db.session.query(Hacker).filter(Hacker.mlh_id == request.args.get('mlh_id')).update({'waitlisted': False})
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
mlh_info = get_mlh_user(request.args.get('mlh_id'))
|
||||||
|
|
||||||
|
# Send a welcome email...
|
||||||
|
msg = 'Dear ' + mlh_info['first_name'] + ',\n\n'
|
||||||
|
msg += 'You are off the waitlist!\n'
|
||||||
|
msg += 'Room has opened up, and you are now welcome to come, we look forward to seeing you!\n'
|
||||||
|
msg += 'If you cannot make it, please remove yourself at hack.wpi.edu\dashboard.\n'
|
||||||
|
send_email(mlh_info['email'], "Hack@WPI - You're off the Waitlist!", msg)
|
||||||
|
|
||||||
|
pn.publish().channel('hackWPI-admin').message(
|
||||||
|
{'status': 'success', 'action': 'promote_from_waitlist', 'more_info': '',
|
||||||
|
'id': request.args.get('mlh_id')}).sync()
|
||||||
|
|
||||||
|
print(mlh_info['first_name'] + "is off the waitlist!")
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{'status': 'success', 'action': 'promote_from_waitlist', 'more_info': '', 'id': request.args.get('mlh_id')})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/dashboard', methods=['GET'])
|
||||||
|
def dashboard():
|
||||||
|
# Display's a hacker's options...
|
||||||
|
if not is_logged_in():
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
return render_template('dashboard.html', name=session['mymlh']['first_name'], id=session['mymlh']['id'],
|
||||||
|
admin=is_admin())
|
||||||
|
|
||||||
|
|
||||||
|
def is_logged_in():
|
||||||
|
if session is None:
|
||||||
|
return False
|
||||||
|
if 'mymlh' not in session:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def is_admin():
|
||||||
|
if not is_logged_in():
|
||||||
|
return False
|
||||||
|
user_admin = db.session.query(Hacker.admin).filter(Hacker.mlh_id == session['mymlh']['id']).one_or_none()
|
||||||
|
if user_admin is None:
|
||||||
|
return False
|
||||||
|
if not user_admin[0]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def is_self(mlh_id):
|
||||||
|
mlh_id = int(mlh_id)
|
||||||
|
if not is_logged_in():
|
||||||
|
return False
|
||||||
|
if session['mymlh']['id'] != mlh_id:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def send_email(to, subject, body):
|
||||||
|
print("Email sent to: " + to)
|
||||||
|
body += '\nPlease let your friends know about the event as well!.\n'
|
||||||
|
body += 'To update your status, you can go to hack.wpi.edu/dashboard\n'
|
||||||
|
body += '\nThanks Again!\nThe HackWPI Team\nhttps://twitter.com/hackwpi?lang=en'
|
||||||
|
|
||||||
|
server = smtplib.SMTP('smtp.gmail.com', 587)
|
||||||
|
server.starttls()
|
||||||
|
sender = api_keys['smtp_email']['user']
|
||||||
|
server.login(sender, api_keys['smtp_email']['pass'])
|
||||||
|
|
||||||
|
msg = _create_MIMEMultipart(subject, sender, to, body)
|
||||||
|
|
||||||
|
server.send_message(msg)
|
||||||
|
print("Sucess! (Email to " + to)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_MIMEMultipart(subject, sender, to, body):
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg['Subject'] = subject
|
||||||
|
msg['From'] = sender
|
||||||
|
if type(to) == list:
|
||||||
|
msg['To'] = ", ".join(to)
|
||||||
|
else:
|
||||||
|
msg['To'] = to
|
||||||
|
msg.attach(MIMEText(body, 'plain'))
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def get_mlh_user(mlh_id):
|
||||||
|
if not isinstance(mlh_id, int):
|
||||||
|
mlh_id = int(mlh_id)
|
||||||
|
req = requests.get(
|
||||||
|
'https://my.mlh.io/api/v2/users.json?client_id=' + api_keys['mlh']['client_id'] + '&secret=' + api_keys['mlh'][
|
||||||
|
'secret'])
|
||||||
|
if req.status_code == 200:
|
||||||
|
hackers = req.json()['data']
|
||||||
|
for hacker in hackers:
|
||||||
|
if hacker['id'] == mlh_id:
|
||||||
|
return hacker
|
||||||
|
|
||||||
|
|
||||||
|
def get_mlh_users():
|
||||||
|
req = requests.get(
|
||||||
|
'https://my.mlh.io/api/v2/users.json?client_id=' + api_keys['mlh']['client_id'] + '&secret=' + api_keys['mlh'][
|
||||||
|
'secret'])
|
||||||
|
if req.status_code == 200:
|
||||||
|
return req.json()['data']
|
||||||
|
|
||||||
|
|
||||||
|
def gen_new_auto_promote_keys(n=50):
|
||||||
|
key = new_key(n)
|
||||||
|
val = new_key(n)
|
||||||
|
db.session.add(AutoPromoteKeys(key=key, val=val))
|
||||||
|
db.session.commit()
|
||||||
|
return (key, val)
|
||||||
|
|
||||||
|
|
||||||
|
def get_auto_promote_keys():
|
||||||
|
row = db.session.query(AutoPromoteKeys).one_or_none()
|
||||||
|
if row is not None:
|
||||||
|
db.session.delete(row)
|
||||||
|
db.session.commit()
|
||||||
|
return (row.key, row.val)
|
||||||
|
else:
|
||||||
|
return ('', '')
|
||||||
|
|
||||||
|
|
||||||
|
def new_key(n):
|
||||||
|
return ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(n))
|
||||||
|
|
||||||
|
|
||||||
|
def allowed_file(filename):
|
||||||
|
return '.' in filename and \
|
||||||
|
filename.split('.')[-1].lower() in ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='0.0.0.0', port=80)
|
BIN
hacker.png
Normal file
After Width: | Height: | Size: 122 KiB |
54
manage_waitlist.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import requests
|
||||||
|
from flask_app import db, Hacker, send_email, gen_new_auto_promote_keys
|
||||||
|
from config_hackWPI import WAITLIST_LIMIT
|
||||||
|
|
||||||
|
num_attendees = db.session.query(Hacker).filter(Hacker.waitlisted == False).count()
|
||||||
|
num_waitlisted = db.session.query(Hacker).filter(Hacker.waitlisted == True).count()
|
||||||
|
num_to_promote = WAITLIST_LIMIT - num_attendees
|
||||||
|
|
||||||
|
if num_to_promote > num_waitlisted:
|
||||||
|
num_to_promote = num_waitlisted
|
||||||
|
|
||||||
|
num_to_promote_copy = num_to_promote
|
||||||
|
num_promoted = 0
|
||||||
|
errs = []
|
||||||
|
|
||||||
|
mlh_ids = db.session.query(Hacker.mlh_id).filter(Hacker.waitlisted == True).order_by(Hacker.registration_time)
|
||||||
|
|
||||||
|
for id in mlh_ids:
|
||||||
|
if num_to_promote > 0:
|
||||||
|
print('Attempting to promote: ' + str(id[0]))
|
||||||
|
(key, val) = gen_new_auto_promote_keys()
|
||||||
|
url = 'http://75.136.89.196:5000/promote_from_waitlist' + '?mlh_id=' + str(id[0]) + '&' + key + '=' + val
|
||||||
|
print(url)
|
||||||
|
req = requests.get(url)
|
||||||
|
if req.status_code == 500:
|
||||||
|
errs.append('Server 500')
|
||||||
|
if not req.status_code == 200 or not req.json()['status'] == 'success':
|
||||||
|
print(req.status_code)
|
||||||
|
errs.append(req.json())
|
||||||
|
|
||||||
|
num_promoted += 1
|
||||||
|
num_to_promote -= 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
print('\n')
|
||||||
|
|
||||||
|
msg = 'Hi, here is your daily waitlist report:\n'
|
||||||
|
msg += '\nBefore Promotion:\n'
|
||||||
|
msg += ' Reg Cap: ' + str(WAITLIST_LIMIT) + '\n'
|
||||||
|
msg += ' Num Attendees: ' + str(num_attendees) + '\n'
|
||||||
|
msg += ' Num Waitlisted: ' + str(num_waitlisted) + '\n'
|
||||||
|
msg += ' Num to Promote: ' + str(num_to_promote_copy) + '\n'
|
||||||
|
msg += '\nAfter Promotion:\n'
|
||||||
|
msg += ' Num Promoted (Attempted): ' + str(num_promoted) + '\n'
|
||||||
|
msg += ' Error Count: ' + str(len(errs)) + '\n'
|
||||||
|
msg += ' Num To Promote: ' + str(num_to_promote) + '\n'
|
||||||
|
msg += '\nPromotion Error Messages:\n'
|
||||||
|
msg += ' ' + str(errs) + '\n'
|
||||||
|
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
send_email('hack@wpi.edu', 'HackWPI - Daily Waitlist Report!', msg)
|
||||||
|
send_email('bkayastha@wpi.edu', 'HackWPI - Daily Waitlist Report!', msg)
|
BIN
options.png
Normal file
After Width: | Height: | Size: 15 KiB |
7
requirements.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Flask==0.12
|
||||||
|
Flask_SQLAlchemy==2.1
|
||||||
|
mailchimp3==2.0.7
|
||||||
|
pubnub==4.0.6
|
||||||
|
requests==2.13.0
|
||||||
|
Werkzeug==0.11.15
|
||||||
|
python_dateutil==2.6.0
|
BIN
resumes/binam_kayastha_42001.pdf
Normal file
BIN
resumes/hack_wpi_78137.pdf
Normal file
BIN
static/assets/MinorParticipationWaiverHACKTCNJ2017.doc.docx
Normal file
16
static/css/materialize.min.css
vendored
Normal file
100
static/css/style.css
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/* Custom Stylesheet */
|
||||||
|
/**
|
||||||
|
* Use this file to override Materialize files so you can update
|
||||||
|
* the core Materialize files in the future
|
||||||
|
*
|
||||||
|
* Made By MaterializeCSS.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
nav ul a,
|
||||||
|
nav .brand-logo {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo-container {
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
height: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-collapse {
|
||||||
|
color: #26a69a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-button {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-container {
|
||||||
|
min-height: 380px;
|
||||||
|
line-height: 0;
|
||||||
|
height: auto;
|
||||||
|
color: rgba(255,255,255,.9);
|
||||||
|
}
|
||||||
|
.parallax-container .section {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.page-footer {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.parallax img {
|
||||||
|
display: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
#mlh-trust-badge {
|
||||||
|
display: block;
|
||||||
|
max-width: 100px;
|
||||||
|
min-width: 60px;
|
||||||
|
position: fixed;
|
||||||
|
right: 50px;
|
||||||
|
top: 0;
|
||||||
|
width: 10%;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
BIN
static/favicon.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
1
static/img/HackWPILogo.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 2755 1817" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><g><g><path d="M657.652,341.71l113.155,0l0,507.021l-113.155,0l0,-199.471l-201.648,0l0,199.471l-113.155,0l0,-507.021l113.155,0l0,211.803l201.648,0l0,-211.803Z" style="fill:#505050;fill-rule:nonzero;"/><path d="M1256.79,848.731l-47.148,-109.528l-212.528,0l-47.148,109.528l-120.408,0l219.056,-507.021l109.528,0l219.057,507.021l-120.409,0Zm-153.049,-356.147l-63.831,147.246l126.937,0l-63.106,-147.246Z" style="fill:#505050;fill-rule:nonzero;"/><path d="M1668.79,748.633c55.61,0 101.066,-22.003 136.366,-66.007l72.535,74.711c-57.544,64.798 -125.365,97.197 -203.461,97.197c-78.096,0 -142.41,-24.662 -192.943,-73.986c-50.533,-49.324 -75.8,-111.583 -75.8,-186.778c0,-75.195 25.75,-137.938 77.25,-188.229c51.5,-50.291 114.485,-75.436 188.955,-75.436c83.173,0 152.807,31.673 208.901,95.021l-70.359,79.789c-35.784,-44.489 -80.273,-66.733 -133.465,-66.733c-42.554,0 -78.942,13.903 -109.165,41.708c-30.223,27.805 -45.335,65.282 -45.335,112.429c0,47.148 14.265,84.987 42.796,113.518c28.53,28.531 63.105,42.796 103.725,42.796Z" style="fill:#505050;fill-rule:nonzero;"/><path d="M1966.91,341.71l113.155,0l0,208.176l191.492,-208.176l139.993,0l-201.647,224.134c17.408,24.178 49.565,69.271 96.471,135.278c46.906,66.007 81.965,115.21 105.176,147.609l-132.014,0l-148.697,-200.197l-50.774,56.578l0,143.619l-113.155,0l0,-507.021Z" style="fill:#505050;fill-rule:nonzero;"/><path d="M767.849,1341.5c11.25,0 21.146,-8.959 29.688,-26.875c8.541,-17.917 12.812,-40.417 12.812,-67.5c0,-58.75 -16.875,-107.396 -50.625,-145.938c-33.75,-38.542 -78.958,-57.812 -135.625,-57.812c-56.667,0 -104.375,20.208 -143.125,60.625c-38.75,40.416 -58.125,88.854 -58.125,145.312c0,56.458 18.229,103.438 54.688,140.938c36.458,37.5 81.562,56.25 135.312,56.25c42.083,0 79.167,-15.417 111.25,-46.25l25.625,44.375c-16.667,14.583 -37.917,26.354 -63.75,35.312c-25.833,8.958 -50.208,13.438 -73.125,13.438c-69.583,0 -127.812,-23.23 -174.687,-69.688c-46.875,-46.458 -70.313,-104.583 -70.313,-174.375c0,-69.792 24.688,-129.375 74.063,-178.75c49.375,-49.375 108.854,-74.062 178.437,-74.062c69.583,0 127.708,23.75 174.375,71.25c46.667,47.5 70,106.666 70,177.5c0,45.833 -9.479,82.604 -28.437,110.312c-18.959,27.708 -43.855,41.563 -74.688,41.563c-15.833,0 -30.312,-4.792 -43.437,-14.375c-13.125,-9.584 -22.188,-21.667 -27.188,-36.25c-22.917,29.583 -51.979,44.375 -87.187,44.375c-35.209,0 -65.834,-13.334 -91.875,-40c-26.042,-26.667 -39.063,-60.521 -39.063,-101.563c0,-41.042 11.771,-75.625 35.313,-103.75c23.541,-28.125 54.479,-42.187 92.812,-42.187c12.917,0 25.208,2.812 36.875,8.437c11.667,5.625 20,11.146 25,16.563l8.125,8.125l0,-25.625l78.125,0l0,199.375c0,20.833 6.25,31.25 18.75,31.25Zm-112.812,-146.25c-11.042,-13.75 -25.521,-20.625 -43.438,-20.625c-17.917,0 -32.187,6.875 -42.812,20.625c-10.625,13.75 -15.938,30.729 -15.938,50.937c0,20.208 5.313,37.813 15.938,52.813c10.625,15 25.104,22.5 43.437,22.5c18.333,0 32.813,-7.188 43.438,-21.563c10.625,-14.375 15.937,-31.979 15.937,-52.812c0,-20.834 -5.521,-38.125 -16.562,-51.875Z" style="fill:#505050;fill-rule:nonzero;"/><path d="M1197.16,1277.95l89.943,-291.591l118.233,0l89.218,291.591l100.824,-291.591l122.584,0l-176.985,507.021l-84.141,0l-110.979,-352.521l-110.254,352.521l-84.14,0l-176.986,-507.021l122.584,0l100.099,291.591Z" style="fill:#ff3633;fill-rule:nonzero;"/><path d="M2127.43,1031.69c35.542,30.223 53.313,76.646 53.313,139.268c0,62.622 -18.255,108.44 -54.764,137.454c-36.51,29.014 -92.241,43.521 -167.194,43.521l-67.457,0l0,141.444l-113.155,0l0,-507.021l179.162,0c77.854,0 134.552,15.111 170.095,45.334Zm-83.053,199.472c13.54,-15.233 20.31,-37.477 20.31,-66.732c0,-29.256 -8.826,-50.05 -26.476,-62.381c-17.65,-12.331 -45.092,-18.496 -82.327,-18.496l-64.556,0l0,170.457l76.161,0c37.719,0 63.348,-7.616 76.888,-22.848Z" style="fill:#ff3633;fill-rule:nonzero;"/><rect x="2269.23" y="986.358" width="113.155" height="507.021" style="fill:#ff3633;fill-rule:nonzero;"/></g><path d="M2714.7,1776.83l-2675,0l0,-1737.5l2675,0l0,1737.5Zm-2583.33,-1645.83l0,1554.17l2491.67,0l0,-1554.17l-2491.67,0Z" style="fill:#505050;"/></g></svg>
|
After Width: | Height: | Size: 4.3 KiB |
BIN
static/img/background1.jpg
Normal file
After Width: | Height: | Size: 4.7 MiB |
BIN
static/img/background2.png
Normal file
After Width: | Height: | Size: 1.7 MiB |
BIN
static/img/background3.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
static/img/contact_bg.png
Executable file
After Width: | Height: | Size: 415 KiB |
BIN
static/img/cosponsors.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
static/img/cosponsors.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
static/img/cover.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
static/img/hackwpi_longlogo.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
static/img/sponsors.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
190
static/js/admin.js
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
let pn = new PubNub({
|
||||||
|
publishKey: '',
|
||||||
|
subscribeKey: '',
|
||||||
|
ssl: true
|
||||||
|
})
|
||||||
|
|
||||||
|
pn.subscribe({
|
||||||
|
channels: ['hackWPI-admin']
|
||||||
|
})
|
||||||
|
|
||||||
|
pn.addListener({
|
||||||
|
message: (msg) => {
|
||||||
|
msg = msg.message
|
||||||
|
console.log(msg)
|
||||||
|
const id = msg.id
|
||||||
|
if (msg.action === 'check_in') {
|
||||||
|
document.getElementById(id + '-check_in').outerHTML = ''
|
||||||
|
document.getElementById(id + '-checked_in').innerHTML = 'True'
|
||||||
|
} else if (msg.action === 'drop') {
|
||||||
|
document.getElementById(id + '-row').outerHTML = ''
|
||||||
|
} else if (msg.action === 'promote_from_waitlist') {
|
||||||
|
document.getElementById(id + '-promote_from_waitlist').outerHTML = ''
|
||||||
|
document.getElementById(id + '-waitlisted').innerHTML = 'False'
|
||||||
|
} else if (msg.action === 'new_user' || msg.action === 'refresh' || msg.action.split(':')[0] === 'change_admin') {
|
||||||
|
window.location.reload(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let successColor = '#18BC9C'
|
||||||
|
let errColor = '#E74C3C'
|
||||||
|
|
||||||
|
$(document).ready(() => {
|
||||||
|
let timeout = setTimeout("window.location.reload(true);", 300000)
|
||||||
|
|
||||||
|
const resetTimeout = () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
timeout = setTimeout("window.location.reload(true);", 300000)
|
||||||
|
}
|
||||||
|
|
||||||
|
$('a.check_in').click((e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let id = e.target.id.split('-')[0]
|
||||||
|
console.log('check in ' + id)
|
||||||
|
checkIn(id)
|
||||||
|
})
|
||||||
|
$('a.drop').click((e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let id = e.target.id.split('-')[0]
|
||||||
|
console.log('drop ' + id)
|
||||||
|
drop(id)
|
||||||
|
})
|
||||||
|
$('a.demote_admin').click((e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let id = e.target.id.split('-')[0]
|
||||||
|
console.log('demote admin ' + id)
|
||||||
|
changeAdmin(id, 'demote')
|
||||||
|
})
|
||||||
|
$('a.promote_admin').click((e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let id = e.target.id.split('-')[0]
|
||||||
|
console.log('promote admin ' + id)
|
||||||
|
changeAdmin(id, 'promote')
|
||||||
|
})
|
||||||
|
$('a.promote_from_waitlist').click((e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let id = e.target.id.split('-')[0]
|
||||||
|
console.log('promote waitlist ' + id)
|
||||||
|
promoteFromWaitlist(id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const promoteFromWaitlist = (id) => {
|
||||||
|
swal({
|
||||||
|
title: 'Promote hacker ' + id + ' off the waitlist?',
|
||||||
|
text: 'Are you sure you wish to promote this hacker off the waitlist?',
|
||||||
|
type: 'info',
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
confirmButtonText: 'Yes, promote!',
|
||||||
|
confirmButtonColor: successColor
|
||||||
|
}, () => {
|
||||||
|
$.get('/promote_from_waitlist?mlh_id=' + id, (data) => {
|
||||||
|
let title = ''
|
||||||
|
let msg = ''
|
||||||
|
let type = ''
|
||||||
|
if (data.status === 'success') {
|
||||||
|
title = 'Promoted!'
|
||||||
|
msg = 'The hacker was successfully promoted off the waitlist!'
|
||||||
|
type = 'success'
|
||||||
|
} else {
|
||||||
|
title = 'Error!'
|
||||||
|
msg = JSON.stringify(data)
|
||||||
|
type = 'error'
|
||||||
|
}
|
||||||
|
swal(title, msg, type)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeAdmin = (id, action) => {
|
||||||
|
swal({
|
||||||
|
title: 'Modify:' + action + ' admin prviliges on hacker ' + id + ' ?',
|
||||||
|
text: 'Are you sure you wish to modify:' + action + ' this hacker\'s administrative privileges?',
|
||||||
|
type: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
confirmButtonText: 'Yes, ' + action + '!',
|
||||||
|
confirmButtonColor: errColor
|
||||||
|
}, () => {
|
||||||
|
$.get('/change_admin?mlh_id=' + id + '&action=' + action, (data) => {
|
||||||
|
let title = ''
|
||||||
|
let msg = ''
|
||||||
|
let type = ''
|
||||||
|
if (data.status === 'success') {
|
||||||
|
title = 'Modified!'
|
||||||
|
msg = 'The hacker\'s administrative privileges have been modified:' + action + '!'
|
||||||
|
type = 'success'
|
||||||
|
} else {
|
||||||
|
title = 'Error!'
|
||||||
|
msg = JSON.stringify(data)
|
||||||
|
type = 'error'
|
||||||
|
}
|
||||||
|
swal({title: title, msg: msg, type: type}, () => window.location.reload(true))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const drop = (id) => {
|
||||||
|
swal({
|
||||||
|
title: 'Drop hacker ' + id + ' ?',
|
||||||
|
text: 'Are you sure you wish to drop this hacker\'s application?',
|
||||||
|
type: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
confirmButtonText: 'Yes, drop!',
|
||||||
|
confirmButtonColor: errColor
|
||||||
|
}, () => {
|
||||||
|
$.get('/drop?mlh_id=' + id, (data) => {
|
||||||
|
let title = ''
|
||||||
|
let msg = ''
|
||||||
|
let type = ''
|
||||||
|
if (data.status === 'success') {
|
||||||
|
title = 'Dropped!'
|
||||||
|
msg = 'The hacker\'s application was successfully dropped!'
|
||||||
|
type = 'success'
|
||||||
|
} else {
|
||||||
|
title = 'Error!'
|
||||||
|
msg = JSON.stringify(data)
|
||||||
|
type = 'error'
|
||||||
|
}
|
||||||
|
swal(title, msg, type)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkIn = (id) => {
|
||||||
|
swal({
|
||||||
|
title: 'Check in hacker ' + id + ' ?',
|
||||||
|
text: 'Are you sure you wish to check in this hacker?',
|
||||||
|
type: 'info',
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
confirmButtonText: 'Yes, check in!',
|
||||||
|
confirmButtonColor: successColor
|
||||||
|
}, () => {
|
||||||
|
$.get('/check_in?mlh_id=' + id, (data) => {
|
||||||
|
let title = ''
|
||||||
|
let msg = ''
|
||||||
|
let type = ''
|
||||||
|
if (data.status === 'success') {
|
||||||
|
title = 'Checked in!'
|
||||||
|
msg = 'The hacker was checked in!'
|
||||||
|
type = 'success'
|
||||||
|
} else {
|
||||||
|
title = 'Error!'
|
||||||
|
msg = JSON.stringify(data)
|
||||||
|
type = 'error'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === 'success' && data.action === 'check_in' && data.minor === true) {
|
||||||
|
msg += '\nATTENTION:\nHacker is a minor, please ensure they have the minor consent form!'
|
||||||
|
}
|
||||||
|
|
||||||
|
swal(title, msg, type)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
4
static/js/jquery-2.2.4.min.js
vendored
Normal file
1
static/js/jquery.easing.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],function($){return factory($)})}else if(typeof module==="object"&&typeof module.exports==="object"){exports=factory(require("jquery"))}else{factory(jQuery)}})(function($){$.easing.jswing=$.easing.swing;var pow=Math.pow,sqrt=Math.sqrt,sin=Math.sin,cos=Math.cos,PI=Math.PI,c1=1.70158,c2=c1*1.525,c3=c1+1,c4=2*PI/3,c5=2*PI/4.5;function bounceOut(x){var n1=7.5625,d1=2.75;if(x<1/d1){return n1*x*x}else if(x<2/d1){return n1*(x-=1.5/d1)*x+.75}else if(x<2.5/d1){return n1*(x-=2.25/d1)*x+.9375}else{return n1*(x-=2.625/d1)*x+.984375}}$.extend($.easing,{def:"easeOutQuad",swing:function(x){return $.easing[$.easing.def](x)},easeInQuad:function(x){return x*x},easeOutQuad:function(x){return 1-(1-x)*(1-x)},easeInOutQuad:function(x){return x<.5?2*x*x:1-pow(-2*x+2,2)/2},easeInCubic:function(x){return x*x*x},easeOutCubic:function(x){return 1-pow(1-x,3)},easeInOutCubic:function(x){return x<.5?4*x*x*x:1-pow(-2*x+2,3)/2},easeInQuart:function(x){return x*x*x*x},easeOutQuart:function(x){return 1-pow(1-x,4)},easeInOutQuart:function(x){return x<.5?8*x*x*x*x:1-pow(-2*x+2,4)/2},easeInQuint:function(x){return x*x*x*x*x},easeOutQuint:function(x){return 1-pow(1-x,5)},easeInOutQuint:function(x){return x<.5?16*x*x*x*x*x:1-pow(-2*x+2,5)/2},easeInSine:function(x){return 1-cos(x*PI/2)},easeOutSine:function(x){return sin(x*PI/2)},easeInOutSine:function(x){return-(cos(PI*x)-1)/2},easeInExpo:function(x){return x===0?0:pow(2,10*x-10)},easeOutExpo:function(x){return x===1?1:1-pow(2,-10*x)},easeInOutExpo:function(x){return x===0?0:x===1?1:x<.5?pow(2,20*x-10)/2:(2-pow(2,-20*x+10))/2},easeInCirc:function(x){return 1-sqrt(1-pow(x,2))},easeOutCirc:function(x){return sqrt(1-pow(x-1,2))},easeInOutCirc:function(x){return x<.5?(1-sqrt(1-pow(2*x,2)))/2:(sqrt(1-pow(-2*x+2,2))+1)/2},easeInElastic:function(x){return x===0?0:x===1?1:-pow(2,10*x-10)*sin((x*10-10.75)*c4)},easeOutElastic:function(x){return x===0?0:x===1?1:pow(2,-10*x)*sin((x*10-.75)*c4)+1},easeInOutElastic:function(x){return x===0?0:x===1?1:x<.5?-(pow(2,20*x-10)*sin((20*x-11.125)*c5))/2:pow(2,-20*x+10)*sin((20*x-11.125)*c5)/2+1},easeInBack:function(x){return c3*x*x*x-c1*x*x},easeOutBack:function(x){return 1+c3*pow(x-1,3)+c1*pow(x-1,2)},easeInOutBack:function(x){return x<.5?pow(2*x,2)*((c2+1)*2*x-c2)/2:(pow(2*x-2,2)*((c2+1)*(x*2-2)+c2)+2)/2},easeInBounce:function(x){return 1-bounceOut(1-x)},easeOutBounce:bounceOut,easeInOutBounce:function(x){return x<.5?(1-bounceOut(1-2*x))/2:(1+bounceOut(2*x-1))/2}})});
|
6478
static/js/materialize.js
vendored
Normal file
10
static/js/materialize.min.js
vendored
Normal file
272
templates/admin.html
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
<head>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<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://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">
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
|
||||||
|
<script src="../static/js/admin.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.table-striped > tbody > tr:nth-of-type(odd) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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%;">
|
||||||
|
<h2><a href="{{ mlh_url }}">Get JSON object of users from MLH. <b>Do NOT share this URL.</b></a></h2>
|
||||||
|
</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'],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: [{{ female_count }}, {{ male_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>XS</th>
|
||||||
|
<th>S</th>
|
||||||
|
<th>M</th>
|
||||||
|
<th>L</th>
|
||||||
|
<th>XL</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<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>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2 style="margin-top: 2%;">Hackers:</h2>
|
||||||
|
<table id="hackers" class="table table-striped table-hover table-condensed sortable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Options</th>
|
||||||
|
<th>Checked In?</th>
|
||||||
|
<th>Waitlisted?</th>
|
||||||
|
<th>Admin</th>
|
||||||
|
<th>MLH ID</th>
|
||||||
|
<th>Time Registered</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Phone</th>
|
||||||
|
<th>Diet</th>
|
||||||
|
<th>Special</th>
|
||||||
|
<th>School</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for hacker in hackers %}
|
||||||
|
<tr id="{{ hacker['id'] }}-row">
|
||||||
|
<td>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="#" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"><span
|
||||||
|
class="caret"></span></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
{% if not hacker['checked_in'] %}
|
||||||
|
<li><a class="check_in" id="{{ hacker['id'] }}-check_in" href="#">Check In</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if hacker['waitlisted'] and not hacker['checked_in'] %}
|
||||||
|
<li><a class="promote_from_waitlist"
|
||||||
|
id="{{ hacker['id'] }}-promote_from_waitlist"
|
||||||
|
href="#">Promote From Waitlist</a></li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="divider"></li>
|
||||||
|
{% if not hacker['checked_in'] %}
|
||||||
|
<li><a class="drop" id="{{ hacker['id'] }}-drop" href="#">Drop Application</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if hacker['admin'] %}
|
||||||
|
<li><a class="demote_admin" id="{{ hacker['id'] }}-demote_admin" href="#">Demote
|
||||||
|
Admin</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li><a class="promote_admin" id="{{ hacker['id'] }}-promote_admin" href="#">Promote
|
||||||
|
Admin</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td id="{{ hacker['id'] }}-checked_in">{{ hacker['checked_in'] }}</td>
|
||||||
|
<td id="{{ hacker['id'] }}-waitlisted">{{ hacker['waitlisted'] }}</td>
|
||||||
|
<td>{{ hacker['admin'] }}</td>
|
||||||
|
<td>{{ hacker['id'] }}</td>
|
||||||
|
<td>{{ hacker['registration_time'] }}</td>
|
||||||
|
<td>{{ hacker['email'] }}</td>
|
||||||
|
<td>{{ hacker['first_name'] + ' ' + hacker['last_name'] }}</td>
|
||||||
|
<td>{{ hacker['phone_number'] }}</td>
|
||||||
|
<td>{{ hacker['dietary_restrictions'] }}</td>
|
||||||
|
<td>{{ hacker['special_needs'] }}</td>
|
||||||
|
<td>{{ hacker['school']['name'] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
77
templates/dashboard.html
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
{% include 'header.html' %}
|
||||||
|
<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">
|
||||||
|
|
||||||
|
<div class="contact-section" style="height: 100%;">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row" style="margin-top: 10%;">
|
||||||
|
<h1>Hi {{ name }}!</h1>
|
||||||
|
{% if waitlisted %}
|
||||||
|
<h1>You are waitlisted, if space opens up we ill let you know...</h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>You are fully registered! We look forward to seeing you!</h1>
|
||||||
|
{% endif %}
|
||||||
|
<br>
|
||||||
|
<h2>Here are your available actions... </h2>
|
||||||
|
<a href="#" id="drop-link"><p>Drop Application :(</p></a>
|
||||||
|
{% if admin %}
|
||||||
|
<a href="/admin"><p>Admin Dashboard</p></a>
|
||||||
|
{% endif %}
|
||||||
|
Please sit tight, while we improve the UI of this page :P
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let errColor = '#E74C3C'
|
||||||
|
|
||||||
|
$(document).ready(() => {
|
||||||
|
$('#drop-link'
|
||||||
|
).click((e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let id = {{ id }}
|
||||||
|
drop(id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const drop = (id) =>
|
||||||
|
{
|
||||||
|
swal({
|
||||||
|
title: 'Drop your application?',
|
||||||
|
text: 'Are you sure you wish to drop your application? This cannot be undone. (patiently wait after clicking the button)',
|
||||||
|
type: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
confirmButtonText: 'Yes, drop!',
|
||||||
|
confirmButtonColor: errColor
|
||||||
|
}, () => {
|
||||||
|
$.get('/drop?mlh_id=' + id, (data) => {
|
||||||
|
let title = ''
|
||||||
|
let msg = ''
|
||||||
|
let type = ''
|
||||||
|
if (data.status === 'success'
|
||||||
|
)
|
||||||
|
{
|
||||||
|
title = 'Dropped!'
|
||||||
|
msg = 'Your application was successfully dropped!'
|
||||||
|
type = 'success'
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = 'Error!'
|
||||||
|
msg = JSON.stringify(data)
|
||||||
|
type = 'error'
|
||||||
|
}
|
||||||
|
swal(title, msg, type)
|
||||||
|
if (data.status === 'success') {
|
||||||
|
setTimeout(() => {window.location = '/'
|
||||||
|
},
|
||||||
|
5000
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% include 'footer.html' %}
|
6
templates/footer.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<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-2.2.4.min.js"></script>
|
||||||
|
<script src="../static/js/jquery.easing.min.js"></script>
|
||||||
|
<script src="../static/js/materialize.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
27
templates/header.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="description" content="HackTCNJ">
|
||||||
|
<meta name="author" content="bohinsk1@tcnj.edu">
|
||||||
|
<title>Hack @ WPI</title>
|
||||||
|
<link rel="icon" href="../static/favicon.png" type="image/png">
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||||
|
<link href="../static/css/materialize.min.css" rel="stylesheet">
|
||||||
|
<link href="../static/css/style.css" rel="stylesheet">
|
||||||
|
<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>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="white" role="navigation" style="height: 80px">
|
||||||
|
<div class="nav-wrapper container">
|
||||||
|
<a id="logo-container" href="#" class="red-text text-darken-4 brand-logo">
|
||||||
|
<img src="../static/img/hackwpi_longlogo.png" alt="hack@WPI" height="100%">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<a id="mlh-trust-badge" style="display:block;max-width:100px;min-width:60px;position:fixed;right:50px;top:0;width:10%;z-index:10000" href="https://mlh.io/seasons/na-2018/events?utm_source=na-2018&utm_medium=TrustBadge&utm_campaign=na-2018&utm_content=black" target="_blank"><img src="https://s3.amazonaws.com/logged-assets/trust-badge/2018/black.svg" alt="Major League Hacking 2018 Hackathon Season" style="width:100%"></a>
|
||||||
|
</nav>
|
||||||
|
{% include 'footer.html' %}
|
164
templates/index.html
Executable file
|
@ -0,0 +1,164 @@
|
||||||
|
{% include 'header.html' %}
|
||||||
|
<link href="../static/css/materialize.min.css" rel="stylesheet">
|
||||||
|
<div>
|
||||||
|
<div id="index-banner" class="parallax-container valign-wrapper">
|
||||||
|
<div class="section no-pad-bot">
|
||||||
|
<div class="container">
|
||||||
|
<br><br>
|
||||||
|
<h2 class="header center red-text text-darken-2">Learn. Hack. Compete.</h2>
|
||||||
|
<div class="row center">
|
||||||
|
<h5 class="header col s12 light">An open for all WPI Hackathon, for both hardware and software!</h5>
|
||||||
|
</div>
|
||||||
|
<div class="row center">
|
||||||
|
<h5 class="header col s6 m5 light" style="margin-top:0; float: left; display: block">
|
||||||
|
<i class="small material-icons">today</i> Jan. 12 - 14th
|
||||||
|
</h5>
|
||||||
|
<h5 class="header col s6 m5 light" style="margin-top:0; float: right; display: block">
|
||||||
|
<i class="small material-icons">room</i> WPI Odeum
|
||||||
|
</h5>
|
||||||
|
<!--<%= link_to "Registration", "/pages/registration",
|
||||||
|
class: "col s12 m2 btn-large waves-effect waves-light red darken-1",
|
||||||
|
style: "float: left; display: inline-block" %>-->
|
||||||
|
<!--<%= link_to 'Click here to apply!'.html_safe, questionnaires_path,
|
||||||
|
class: "col s12 m2 btn-large waves-effect waves-light red darken-1",
|
||||||
|
style: "float: left; display: inline-block" %>-->
|
||||||
|
<a class="col s12 m2 btn-large waves-effect waves-light red darken-1"
|
||||||
|
style= "float: left; display: inline-block; text-decoration: none;"
|
||||||
|
href= "/register">Register Here!</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row center" style="margin:0">
|
||||||
|
<a id="cocbutton" class="sub-button col s6 push-s3 m2 push-m5 btn waves-effect waves-light grey darken-1"
|
||||||
|
href="https://static.mlh.io/docs/mlh-code-of-conduct.pdf" data-mode="1" target="_blank">MLH Code</a>
|
||||||
|
</div>
|
||||||
|
<div class="row center">
|
||||||
|
<div class="col s12 m6">
|
||||||
|
<a class="sub-button col s6 push-s3 m4 push-m4 btn waves-effect waves-light grey darken-1"
|
||||||
|
href="" data-mode="1" target="_blank">Slack Chatroom (TBA)</a>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 m6">
|
||||||
|
<a class="sub-button col s6 push-s3 m4 push-m4 btn waves-effect waves-light grey darken-1"
|
||||||
|
href="" data-mode="1" target="_blank">Devpost Link (TBA)</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="parallax"><img src="../static/img/background1.jpg" alt="background image"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<!-- Icpathon Section -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12 m4">
|
||||||
|
<div class="icon-block">
|
||||||
|
<h2 class="center brown-text"><i class="material-icons">grade</i></h2>
|
||||||
|
<h5 class="center">Learn</h5>
|
||||||
|
<p class="light">Participate in the workshops taught by experienced students and learn everything you need to take your project from idea to reality. Ask currently employed Mentors for help when needed.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col s12 m4">
|
||||||
|
<div class="icon-block">
|
||||||
|
<h2 class="center brown-text"><i class="material-icons">settings</i></h2>
|
||||||
|
<h5 class="center">Hack</h5>
|
||||||
|
<p class="light">Work all weekend long to build and hack your project together. We provide food, snacks, drinks, and entertainment; everything you need to stay focused and have fun for the whole event.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col s12 m4">
|
||||||
|
<div class="icon-block">
|
||||||
|
<h2 class="center brown-text"><i class="material-icons">group</i></h2>
|
||||||
|
<h5 class="center">Compete</h5>
|
||||||
|
<p class="light">Present your project at the end of the hackathon to our panel of judges, and win various prizes! Grand prizes are available for the top three teams, the best overall, the best software, and the best hardware project. Additionally, smaller prizes will also be available for various categories.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="parallax-container valign-wrapper">
|
||||||
|
<div class="section no-pad-bot">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row center">
|
||||||
|
<img src="../static/img/cosponsors.png" alt="cosponsors" style='height: 100%; width: 100%; object-fit: contain'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="parallax">
|
||||||
|
<img src="../static/img/background2.png" alt="background image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="section">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12 center" style="margin-top: -40px; margin-bottom: -50px;">
|
||||||
|
<div class="icon-block">
|
||||||
|
<h1 class="center brown-text"><strong>⬆</strong></h1>
|
||||||
|
<h5 class="center">Organizing Club</h5>
|
||||||
|
<p class="light">Hack @ WPI is run by the local ACM chapter. The event would not be possible without their support!</p>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<h5 class="center">Sponsoring Companies</h5>
|
||||||
|
<p class="light">Hack @ WPI is proud to announce that the companies below are all part of making the event a reality.</p>
|
||||||
|
<h1 class="center brown-text"><strong>⬇</strong></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="parallax-container valign-wrapper">
|
||||||
|
<div class="section no-pad-bot">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row center">
|
||||||
|
<img src="../static/img/sponsors.png" alt="sponsors" class="responsive-img">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="parallax">
|
||||||
|
<img src="../static/img/background3.png" alt="background" >
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="page-footer red darken-2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<h5 class="white-text">Interested in Sponsoring or Co-Sponsoring?</h5>
|
||||||
|
<div class="col l6 s12">
|
||||||
|
<p class="grey-text text-lighten-4">For any inquiries regarding sponsoring the event as a company or co-sponsoring the event as an on campus club, please email <a class="white-text" href="mailto:hack@wpi.edu?subject=[Hackathon]" target="_top"><u>hack@wpi.edu</u></a>, and we will happily discuss it with you!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<h4 class="white-text">FAQ</h4>
|
||||||
|
<div class="col l6 s6">
|
||||||
|
<h5 class="white-text">When does registration close?</h5>
|
||||||
|
<p class="grey-text text-lighten-4">Registration officially closes on Monday, January 10th, 11:59pm.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col l6 s6">
|
||||||
|
<h5 class="white-text">Will there be travel reimbursements?</h5>
|
||||||
|
<p class="grey-text text-lighten-4">We are attempting to partner with some nearby schools to run a bus from there's to ours, but may not have the budget. If you're interested in providing a bus to our hackathon, let us know. At the moment we cannot provide travel reimburstments.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col l6 s6">
|
||||||
|
<h5 class="white-text">How do I know I'm registered?</h5>
|
||||||
|
<p class="grey-text text-lighten-4">You should be automatically notified whether or not you're registered. If you're on the waitlist and a spot opens, you will get an email saying you got in.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col l6 s6">
|
||||||
|
<h5 class="white-text">I am officially registered but now I want to unregister, how do I do that?</h5>
|
||||||
|
<p class="grey-text text-lighten-4">Go to hack.wpi.edu/dashboard, there is a link on the bottom to drop your registration</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-copyright">
|
||||||
|
<div class="container">
|
||||||
|
For issues, please contact <a class="white-text" href="mailto:acm@wpi.edu?subject=[Site]" target="_top"><u>acm@wpi.edu</u></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
{% include 'footer.html' %}
|
43
templates/register.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{% include 'header.html' %}
|
||||||
|
<link href="../static/css/materialize.min.css" rel="stylesheet">
|
||||||
|
<div style="height: 100%;">
|
||||||
|
<div id="registration-banner" class="parallax-container valign-wrapper">
|
||||||
|
<div class="section">
|
||||||
|
<h2 class="header center red-text text-darken-2">Registration</h2>
|
||||||
|
</div>
|
||||||
|
<div class="parallax"><img src="../static/img/background1.jpg" alt="background"></div>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<a id="mlh-trust-badge" href="https://mlh.io/seasons/na-2017/events?utm_source=na-2017&utm_medium=TrustBadge&utm_campaign=na-2017&utm_content=black" target="_blank"><img src="https://s3.amazonaws.com/logged-assets/trust-badge/2017/black.svg" alt="Major League Hacking 2017 Hackathon Season" style="width:100%"></a>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Hi {{ name }}, thanks for logging in with MyMLH!</h1>
|
||||||
|
<h2>If you'd like, add your resume to send to sponsors... </h2>
|
||||||
|
<div class="section">
|
||||||
|
<form method="post" action="/register" enctype="multipart/form-data">
|
||||||
|
<div class="file-field input-field">
|
||||||
|
<div class="btn">
|
||||||
|
<span>File</span>
|
||||||
|
<input id="resume" name="resume" type="file"/>
|
||||||
|
</div>
|
||||||
|
<div class="file-path-wrapper">
|
||||||
|
<input class="file-path validate" type="text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>By registering & attending, you agree to the following policies:</p>
|
||||||
|
<p><a href="https://github.com/MLH/mlh-policies/blob/master/data-sharing.md">MLH's Data Sharing
|
||||||
|
Notice</a>
|
||||||
|
</p>
|
||||||
|
<p><a href="https://mlh.io/privacy">MLH's Privacy Policy</a></p>
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/MLH/mlh-policies/blob/master/prize-terms-and-conditions/contest-terms.md">MLH's
|
||||||
|
Contest Terms and Conditions</a></p>
|
||||||
|
<p><a href="https://static.mlh.io/docs/mlh-code-of-conduct.pdf">MLH's Code of Conduct</a></p>
|
||||||
|
<br>
|
||||||
|
<input type="checkbox" id="checkboxid" required><label for="checkboxid">Do you agree with MLH Rules?</label><br>
|
||||||
|
<input name="submit" class="btn btn-lg btn-primary btn-invert" type="submit" value="Submit"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'footer.html' %}
|