Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • hodorsec/hodor-backend
  • Vasanth/hodor-webapp
  • skamath/hodor-backend
  • techtocore/hodor-backend
4 results
Select Git revision
Show changes
Commits on Source (31)
Showing
with 413 additions and 2669 deletions
# Personal virtualenv
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# 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
.static_storage/
.media/
local_settings.py
# Flask stuff:
migrations/
.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
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# Personal Virtualenv
.hodor/
# For IDE
# Jetbrains folders
.idea/
# Stupid pyc files
.pyc
migrations/
### Contributing to this repo
* Fork the repository
* Clone your fork using `https://git.amrita.edu/<your_username>/hodor-webapp`
* Clone your fork using `https://git.amrita.edu/<your_username>/hodor-backend`
* Make a new branch with your changes using `git branch -b <branch_name>`. For
instance, if you are working on adding tests, you should do something like `git branch -b add_tests`.
* Send in a pull-request.
* Make your desired changes.
* Stage changes to git using `git add <filenames>`
* Commit your changes using `git commit -m "<A brief summary of your work>"`
* Push to your fork and the new branch you created like : `git push <url_of_fork> <branch_name>`
* Go to GitLab and send a merge-request!
More instructions coming soon :)
\ No newline at end of file
......@@ -3,10 +3,21 @@
The web application for the Hodor Project
## Quickstart
* Install postgresql database. The installation will depend on your operating system and distribution.
* Clone the repo using `git clone https://git.amrita.edu/hodorsec/hodor-webapp`
* Create a virtualenv and activate it.
* After activating it, `pip install -r requirements.txt` to install dependencies.
* Create a virtualenv (see below for instructions) and activate it.
* After activating it, `pip install --user -r requirements.txt` to
install dependencies.
* To initialize the database, run the following:
```bash
python manage.py db init
python manage.py db migrate
```
This will create a folder called `migrations` in the working environment. In most cases, you do not need to care about what's in there.
* `./runserver.py` to run the app.
* Navigate to `http://127.0.0.1:8080` to watch it in action!
## Virtualenv instructions
* To create a virtual environment, type in `virtualenv <env_name>`.
* After it initializes, execute `source <env_name>/bin/activate` to activate the virtualenv.
# -*- coding: utf-8 -*-
__version__ = '0.1'
from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension
app = Flask('hodor')
app.config['SECRET_KEY'] = 'random'
app.debug = True
toolbar = DebugToolbarExtension(app)
from hodor.controllers import *
# app/__init__.py
import os
import sys
import time
from termcolor import colored
from flask_api import FlaskAPI
from flask_sqlalchemy import SQLAlchemy
from instance.config import app_config
# initialize sql-alchemy
db = SQLAlchemy()
from hodor.models import * # noqa
# TODO: Don't forget to change when in production
config_name = 'development'
application = FlaskAPI(__name__, instance_relative_config=True)
application.config.from_object(app_config[config_name])
application.config.from_pyfile('config.py')
application.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(application)
application.config['SECRET_KEY'] = 'blehblehbleh'
# Delay the application launch to get the user attention if running in
# testing mode
if config_name != 'production' and not os.getenv('SKIP_COUNT'):
for x in range(0, 5):
sys.stdout.write(colored("\rYou are not running the server in production mode. " +
"App will run in {} seconds..".format(5-x), 'red'))
sys.stdout.flush()
time.sleep(1)
print(colored("\n\nRunning app in {} mode..".format(config_name), 'yellow'))
# This disables the HTML API renderer for flask_api when called through
# browsers.
if config_name == 'production':
application.config['DEFAULT_RENDERERS'] = [
'flask.ext.api.renderers.JSONRenderer',
]
app = application
from hodor.controllers import * # noqa
# -*- coding: utf-8 -*-
from hodor import app
from flask import render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
class CreateForm(FlaskForm):
text = StringField('name', validators=[DataRequired()])
@app.route('/')
def start():
return render_template('index/index.html')
# -*- coding: utf-8 -*-
from hodor import app
from flask import request, jsonify, abort, make_response
from hodor.models.user import User
from sqlalchemy.exc import IntegrityError
def _extract_required_fields(user):
filtered_user = dict()
'''
This can be done by directly dumping the dictionary but there's always
a risk of data leak.So, we pick what we need to give out out of the API
'''
filtered_user['username'] = user.username
filtered_user['first_name'] = user.first_name
filtered_user['last_name'] = user.last_name
filtered_user['email'] = user.email
filtered_user['verified_account'] = user.verified_account
return filtered_user
#########################################
# Get all the user from the database #
#########################################
@app.route('/users', methods=['GET', 'POST'])
def get_all_users():
# TODO: Authentication for calling this API endpoint. Admin only.
"""
This function iterates the database to find all users and returns as JSON
:return: Response Code
"""
response = dict()
response['status'] = 200
response['data'] = []
for user in User.get_all():
'''Here, we pass the raw user object to extract only what we need
to _extract_required_vars to filter it'''
response['data'].append(_extract_required_fields(user))
return response
################################################
# Get a specific the user from the database #
################################################
@app.route('/user/<user_slug>', methods=['GET'])
def get_user_by_username(user_slug):
# TODO: Authentication for calling this API endpoint. Admin only.
"""
This function iterates the database to find all users and returns as JSON
:return: Response Code
"""
check_username = str(user_slug).strip()
get_user = User.query.filter_by(username=check_username).first()
if get_user:
requested_user = _extract_required_fields(get_user)
return make_response(jsonify(status=200, data=requested_user), 200)
else:
return make_response(jsonify(status=404, msg="No such user found in database"), 404)
#########################################
# Register a user to database #
#########################################
@app.route('/users/new', methods=['POST'])
def add_new_user():
"""
This function adds a new user
:return: Response Code
"""
newuser = {}
if request.method == "POST":
try:
newuser['username'] = str(request.data.get('username').strip())
newuser['first_name'] = str(request.data.get('first_name').strip())
newuser['last_name'] = str(request.data.get('last_name').strip())
newuser['email'] = str(request.data.get('email').strip())
newuser['password'] = str(request.data.get('password').strip())
newuser['verification_code'] = str(request.data.get(
'verification_code').strip())
except Exception as e:
print(e)
abort(500)
user = User(**newuser)
user.save()
return make_response(jsonify(status=201, msg="User {} successfully added".format(user.username) +
"to database"), 201)
#################################################
# Check for an existing user in the database #
#################################################
@app.route('/users/check', methods=['POST'])
def check_for_existing_user():
errors = []
# If the username field is passed, check the username field.
if request.data.get('username'):
check_username = str(request.data.get('username').strip())
user_check_user = User.query.filter_by(username=check_username).first()
if user_check_user:
errors.append({
'field': 'username',
'error': '{} is taken'.format(check_username)
})
del user_check_user
# If the email field is set, check for duplicate email
if request.data.get('email'):
check_email = str(request.data.get('email').strip())
user_check_email = User.query.filter_by(email=check_email).first()
if user_check_email:
errors.append({
'field': 'email',
'error': '{} exists in the database'.format(check_email)
})
if errors:
return make_response(jsonify(status=400, err=errors), 400)
else:
return jsonify(
status=200,
msg="ok"
)
################################################
# Handle Integrity Exceptions in API #
################################################
@app.errorhandler(IntegrityError)
def handle_sql_assertion_error(err):
try:
'''
err.orig.args is from the DBAPIError class of SQLAlchemy. It usually
contains the original error message.
The below is an attempt to clean up the message and only return the
relevant part to API
'''
try:
errmsg = err.orig.args[0].split('\n')[1][9:]
except IndexError:
errmsg = err.orig.args[0].split('\n')
except IndexError:
errmsg = err.orig.args[0]
return make_response(jsonify(status=400, msg=errmsg), 400)
@app.route('/print', methods=['GET', 'POST'])
def printer():
form = {'hello': 'user'}
return form
# coding=utf-8
# -*- coding: utf-8 -*-
from hodor import db
class Challenges(db.Model):
__tablename__= 'challenges'
# Data variables for each challenge
id = db.Column(db.String(32), primary_key=True, unique=True, nullable=False)
name = db.Column(db.String(32), nullable=False)
points = db.Column(db.Integer, nullable=False)
description = db.Column(db.String(2048), nullable=False)
hints = db.Column(db.String(512), nullable=False)
@staticmethod
def save(self):
db.session.add(self)
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
def get_all():
return Challenges.query.all()
# -*- coding: utf-8 -*-
from flask import flash
class Printer(object):
def show_string(self, text):
if text == '':
flash("You didn't enter any text to flash")
else:
flash(text + "!!!")
# -*- coding: utf-8 -*-
from hodor import db
from sqlalchemy import inspect
from sqlalchemy_utils import PasswordType
class User(db.Model):
__tablename__ = 'users'
# Values entered by the user
username = db.Column(db.String(32), primary_key=True, nullable=False)
first_name = db.Column(db.String(32), nullable=False)
last_name = db.Column(db.String(32), nullable=False)
email = db.Column(db.String(64), unique=True, nullable=False)
country = db.Column(db.String(64))
avatar_url = db.Column(db.String(256))
'''PasswordType is an awesome function. To check for passwords later,
you can just do user['password'] == 'plaintext' for a boolean response.'''
password = db.Column(PasswordType(
schemes=[
'pbkdf2_sha512',
'md5_crypt'
],
deprecated=['md5_crypt']
), nullable=False)
# Platform values
disabled = db.Column(db.Boolean, default=False)
verified_account = db.Column(db.Boolean, default=False)
verification_code = db.Column(db.String(32), nullable=False)
def __unicode__(self):
return unicode(self.username)
def save(self):
print type(self)
print self.email
db.session.add(self)
db.session.commit()
@staticmethod
def get_all():
return User.query.all()
def get_all_dict(self):
return {c.key: getattr(self, c.key)
for c in inspect(self).mapper.column_attrs}
def delete(self):
db.session.delete(self)
db.session.commit()
def __repr__(self):
return "<User: {}>".format(self.name)
html {
background-color: #111111 !important;
}
body {
height: 100%;
background-color: #111111 !important;
height: 99vh;
position: relative;
}
canvas {
display:block;
position: fixed;
}
li {
list-style:none !important;
}
.container-fluid{
height: 100%;
}
.nav-hodor {
float: left !important;
}
.content {
height: 99vh !important;
max-height: 90% !important;
}
.img-block {
display: inline-block;
}
/* --------------------------------
Primary style
-------------------------------- */
html * {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
font-size: 100%;
font-family: "PT Sans", sans-serif;
color: #505260;
background-color: #fff;
}
a {
color: #2f889a;
text-decoration: none;
}
img {
max-width: 100%;
}
input, textarea {
font-family: "PT Sans", sans-serif;
font-size: 16px;
font-size: 1rem;
}
input::-ms-clear, textarea::-ms-clear {
display: none;
}
/* --------------------------------
Main components
-------------------------------- */
header[role=banner] {
position: relative;
height: 50px;
background: #343642;
}
header[role=banner] #cd-logo {
float: left;
margin: 4px 0 0 5%;
/* reduce logo size on mobile and make sure it is left aligned with the transform-origin property */
-webkit-transform-origin: 0 50%;
-moz-transform-origin: 0 50%;
-ms-transform-origin: 0 50%;
-o-transform-origin: 0 50%;
transform-origin: 0 50%;
-webkit-transform: scale(0.8);
-moz-transform: scale(0.8);
-ms-transform: scale(0.8);
-o-transform: scale(0.8);
transform: scale(0.8);
}
header[role=banner] #cd-logo img {
display: block;
}
header[role=banner]::after {
/* clearfix */
content: '';
display: table;
clear: both;
}
@media only screen and (min-width: 768px) {
header[role=banner] {
height: 80px;
}
header[role=banner] #cd-logo {
margin: 20px 0 0 5%;
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
}
.main-nav {
float: right;
margin-right: 5%;
width: 44px;
height: 100%;
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/148866/cd-icon-menu.svg") no-repeat center center;
cursor: pointer;
}
.main-nav ul {
position: absolute;
top: 0;
left: 0;
width: 100%;
-webkit-transform: translateY(-100%);
-moz-transform: translateY(-100%);
-ms-transform: translateY(-100%);
-o-transform: translateY(-100%);
transform: translateY(-100%);
}
.main-nav ul.is-visible {
-webkit-transform: translateY(50px);
-moz-transform: translateY(50px);
-ms-transform: translateY(50px);
-o-transform: translateY(50px);
transform: translateY(50px);
}
.main-nav a {
display: block;
height: 50px;
line-height: 50px;
padding-left: 5%;
background: #292a34;
border-top: 1px solid #3b3d4b;
color: #FFF;
}
@media only screen and (min-width: 768px) {
.main-nav {
width: auto;
height: auto;
background: none;
cursor: auto;
}
.main-nav ul {
position: static;
width: auto;
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-ms-transform: translateY(0);
-o-transform: translateY(0);
transform: translateY(0);
line-height: 80px;
}
.main-nav ul.is-visible {
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-ms-transform: translateY(0);
-o-transform: translateY(0);
transform: translateY(0);
}
.main-nav li {
display: inline-block;
margin-left: 1em;
}
.main-nav li:nth-last-child(2) {
margin-left: 2em;
}
.main-nav a {
display: inline-block;
height: auto;
line-height: normal;
background: transparent;
}
.main-nav a.cd-signin, .main-nav a.cd-signup {
padding: .6em 1em;
border: 1px solid rgba(255, 255, 255, 0.6);
border-radius: 50em;
}
.main-nav a.cd-signup {
background: #2f889a;
border: none;
}
}
/* --------------------------------
xsigin/signup popup
-------------------------------- */
.cd-user-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(52, 54, 66, 0.9);
z-index: 3;
overflow-y: auto;
cursor: pointer;
visibility: hidden;
opacity: 0;
-webkit-transition: opacity 0.3s 0, visibility 0 0.3s;
-moz-transition: opacity 0.3s 0, visibility 0 0.3s;
transition: opacity 0.3s 0, visibility 0 0.3s;
}
.cd-user-modal.is-visible {
visibility: visible;
opacity: 1;
-webkit-transition: opacity 0.3s 0, visibility 0 0;
-moz-transition: opacity 0.3s 0, visibility 0 0;
transition: opacity 0.3s 0, visibility 0 0;
}
.cd-user-modal.is-visible .cd-user-modal-container {
-webkit-transform: translateY(0);
-moz-transform: translateY(0);
-ms-transform: translateY(0);
-o-transform: translateY(0);
transform: translateY(0);
}
.cd-user-modal-container {
position: relative;
width: 90%;
max-width: 600px;
background: #FFF;
margin: 3em auto 4em;
cursor: auto;
border-radius: 0.25em;
-webkit-transform: translateY(-30px);
-moz-transform: translateY(-30px);
-ms-transform: translateY(-30px);
-o-transform: translateY(-30px);
transform: translateY(-30px);
-webkit-transition-property: -webkit-transform;
-moz-transition-property: -moz-transform;
transition-property: transform;
-webkit-transition-duration: 0.3s;
-moz-transition-duration: 0.3s;
transition-duration: 0.3s;
}
.cd-user-modal-container .cd-switcher::after {
clear: both;
content: "";
display: table;
}
.cd-user-modal-container .cd-switcher li {
width: 50%;
float: left;
text-align: center;
}
.cd-user-modal-container .cd-switcher li:first-child a {
border-radius: .25em 0 0 0;
}
.cd-user-modal-container .cd-switcher li:last-child a {
border-radius: 0 .25em 0 0;
}
.cd-user-modal-container .cd-switcher a {
display: block;
width: 100%;
height: 50px;
line-height: 50px;
background: #d2d8d8;
color: #809191;
}
.cd-user-modal-container .cd-switcher a.selected {
background: #FFF;
color: #505260;
}
@media only screen and (min-width: 600px) {
.cd-user-modal-container {
margin: 4em auto;
}
.cd-user-modal-container .cd-switcher a {
height: 70px;
line-height: 70px;
}
}
.cd-form {
padding: 1.4em;
}
.cd-form .fieldset {
position: relative;
margin: 1.4em 0;
}
.cd-form .fieldset:first-child {
margin-top: 0;
}
.cd-form .fieldset:last-child {
margin-bottom: 0;
}
.cd-form label {
font-size: 14px;
font-size: 0.875rem;
}
.cd-form label.image-replace {
/* replace text with an icon */
display: inline-block;
position: absolute;
left: 15px;
top: 50%;
bottom: auto;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
transform: translateY(-50%);
height: 20px;
width: 20px;
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
color: transparent;
text-shadow: none;
background-repeat: no-repeat;
background-position: 50% 0;
}
.cd-form label.cd-username {
background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/148866/cd-icon-username.svg");
}
.cd-form label.cd-email {
background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/148866/cd-icon-email.svg");
}
.cd-form label.cd-password {
background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/148866/cd-icon-password.svg");
}
.cd-form input {
margin: 0;
padding: 0;
border-radius: 0.25em;
}
.cd-form input.full-width {
width: 100%;
}
.cd-form input.has-padding {
padding: 12px 20px 12px 50px;
}
.cd-form input.has-border {
border: 1px solid #d2d8d8;
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
.cd-form input.has-border:focus {
border-color: #343642;
box-shadow: 0 0 5px rgba(52, 54, 66, 0.1);
outline: none;
}
.cd-form input.has-error {
border: 1px solid #d76666;
}
.cd-form input[type=password] {
/* space left for the HIDE button */
padding-right: 65px;
}
.cd-form input[type=submit] {
padding: 16px 0;
cursor: pointer;
background: #2f889a;
color: #FFF;
font-weight: bold;
border: none;
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
.no-touch .cd-form input[type=submit]:hover, .no-touch .cd-form input[type=submit]:focus {
background: #3599ae;
outline: none;
}
.cd-form .hide-password {
display: inline-block;
position: absolute;
right: 0;
top: 0;
padding: 6px 15px;
border-left: 1px solid #d2d8d8;
top: 50%;
bottom: auto;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
transform: translateY(-50%);
font-size: 14px;
font-size: 0.875rem;
color: #343642;
}
.cd-form .cd-error-message {
display: inline-block;
position: absolute;
left: -5px;
bottom: -35px;
background: rgba(215, 102, 102, 0.9);
padding: .8em;
z-index: 2;
color: #FFF;
font-size: 13px;
font-size: 0.8125rem;
border-radius: 0.25em;
/* prevent click and touch events */
pointer-events: none;
visibility: hidden;
opacity: 0;
-webkit-transition: opacity 0.2s 0, visibility 0 0.2s;
-moz-transition: opacity 0.2s 0, visibility 0 0.2s;
transition: opacity 0.2s 0, visibility 0 0.2s;
}
.cd-form .cd-error-message::after {
/* triangle */
content: '';
position: absolute;
left: 22px;
bottom: 100%;
height: 0;
width: 0;
border-bottom: 8px solid rgba(215, 102, 102, 0.9);
border-left: 8px solid transparent;
border-right: 8px solid transparent;
}
.cd-form .cd-error-message.is-visible {
opacity: 1;
visibility: visible;
-webkit-transition: opacity 0.2s 0, visibility 0 0;
-moz-transition: opacity 0.2s 0, visibility 0 0;
transition: opacity 0.2s 0, visibility 0 0;
}
@media only screen and (min-width: 600px) {
.cd-form {
padding: 2em;
}
.cd-form .fieldset {
margin: 2em 0;
}
.cd-form .fieldset:first-child {
margin-top: 0;
}
.cd-form .fieldset:last-child {
margin-bottom: 0;
}
.cd-form input.has-padding {
padding: 16px 20px 16px 50px;
}
.cd-form input[type=submit] {
padding: 16px 0;
}
}
.cd-form-message {
padding: 1.4em 1.4em 0;
font-size: 14px;
font-size: 0.875rem;
line-height: 1.4;
text-align: center;
}
@media only screen and (min-width: 600px) {
.cd-form-message {
padding: 2em 2em 0;
}
}
.cd-form-bottom-message {
position: absolute;
width: 100%;
left: 0;
bottom: -30px;
text-align: center;
font-size: 14px;
font-size: 0.875rem;
}
.cd-form-bottom-message a {
color: #FFF;
text-decoration: underline;
}
.cd-close-form {
/* form X button on top right */
display: block;
position: absolute;
width: 40px;
height: 40px;
right: 0;
top: -40px;
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/148866/cd-icon-close.svg") no-repeat center center;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
@media only screen and (min-width: 1170px) {
.cd-close-form {
display: none;
}
}
#cd-login, #cd-signup, #cd-reset-password {
display: none;
}
#cd-login.is-selected, #cd-signup.is-selected, #cd-reset-password.is-selected {
display: block;
}
.abs {
position: absolute;
text-align: center;
width: 100%;
height: 90%;
z-index: 1;
}
#caption {
height: fit-content;
z-index: 1;
margin-right: auto;
margin-left: auto;
margin-top: 4em;
font-family: Lato, sans-serif;
font-weight: 100;
font-size : 70px;
color: white;
}
#subtitle {
z-index: 1;
height: fit-content;
width: fit-content;
margin-left: auto;
margin-right: auto;
margin-top: 18em;
font-family: Lato, sans-serif;
font-size : 20px;
color: white;
}
#logo {
z-index: 1;
margin-right: auto;
margin-left: auto;
margin-top: 6em;
color: white;
}
#version {
z-index: 1;
font-size: 40px;
color: orange;
font-weight: 300;
}
#more {
height: 8%;
margin-right: auto;
margin-left: auto;
margin-top: 30em;
color: white;
z-index: 1;
}
hodor/static/img/hodor.png

82.8 KiB

/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
particlesJS.load('particles-js', '/static/particles.json', function() {
console.log('callback - particles.js config loaded');
});
/*! modernizr 3.5.0 (Custom Build) | MIT *
* https://modernizr.com/download/?-input-setclasses !*/
!function(e,n,t){function s(e,n){return typeof e===n}function a(){var e,n,t,a,o,i,f;for(var c in r)if(r.hasOwnProperty(c)){if(e=[],n=r[c],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t<n.options.aliases.length;t++)e.push(n.options.aliases[t].toLowerCase());for(a=s(n.fn,"function")?n.fn():n.fn,o=0;o<e.length;o++)i=e[o],f=i.split("."),1===f.length?Modernizr[f[0]]=a:(!Modernizr[f[0]]||Modernizr[f[0]]instanceof Boolean||(Modernizr[f[0]]=new Boolean(Modernizr[f[0]])),Modernizr[f[0]][f[1]]=a),l.push((a?"":"no-")+f.join("-"))}}function o(e){var n=c.className,t=Modernizr._config.classPrefix||"";if(u&&(n=n.baseVal),Modernizr._config.enableJSClass){var s=new RegExp("(^|\\s)"+t+"no-js(\\s|$)");n=n.replace(s,"$1"+t+"js$2")}Modernizr._config.enableClasses&&(n+=" "+t+e.join(" "+t),u?c.className.baseVal=n:c.className=n)}function i(){return"function"!=typeof n.createElement?n.createElement(arguments[0]):u?n.createElementNS.call(n,"http://www.w3.org/2000/svg",arguments[0]):n.createElement.apply(n,arguments)}var l=[],r=[],f={_version:"3.5.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){r.push({name:e,fn:n,options:t})},addAsyncTest:function(e){r.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=f,Modernizr=new Modernizr;var c=n.documentElement,u="svg"===c.nodeName.toLowerCase(),p=i("input"),m="autocomplete autofocus list placeholder max min multiple pattern required step".split(" "),d={};Modernizr.input=function(n){for(var t=0,s=n.length;s>t;t++)d[n[t]]=!!(n[t]in p);return d.list&&(d.list=!(!i("datalist")||!e.HTMLDataListElement)),d}(m),a(),o(l),delete f.addTest,delete f.addAsyncTest;for(var g=0;g<Modernizr._q.length;g++)Modernizr._q[g]();e.Modernizr=Modernizr}(window,document);
jQuery(document).ready(function($){
var $form_modal = $('.cd-user-modal'),
$form_login = $form_modal.find('#cd-login'),
$form_signup = $form_modal.find('#cd-signup'),
$form_forgot_password = $form_modal.find('#cd-reset-password'),
$form_modal_tab = $('.cd-switcher'),
$tab_login = $form_modal_tab.children('li').eq(0).children('a'),
$tab_signup = $form_modal_tab.children('li').eq(1).children('a'),
$forgot_password_link = $form_login.find('.cd-form-bottom-message a'),
$back_to_login_link = $form_forgot_password.find('.cd-form-bottom-message a'),
$main_nav = $('.hodor-nav');
//open modal
$main_nav.on('click', function(event){
if( $(event.target).is($main_nav) ) {
// on mobile open the submenu
$(this).children('ul').toggleClass('is-visible');
} else {
// on mobile close submenu
$main_nav.children('ul').removeClass('is-visible');
//show modal layer
$form_modal.addClass('is-visible');
//show the selected form
( $(event.target).is('.cd-signup') ) ? signup_selected() : login_selected();
}
});
//close modal
$('.cd-user-modal').on('click', function(event){
if( $(event.target).is($form_modal) || $(event.target).is('.cd-close-form') ) {
$form_modal.removeClass('is-visible');
}
});
//close modal when clicking the esc keyboard button
$(document).keyup(function(event){
if(event.which=='27'){
$form_modal.removeClass('is-visible');
}
});
//switch from a tab to another
$form_modal_tab.on('click', function(event) {
event.preventDefault();
( $(event.target).is( $tab_login ) ) ? login_selected() : signup_selected();
});
//hide or show password
$('.hide-password').on('click', function(){
var $this= $(this),
$password_field = $this.prev('input');
( 'password' == $password_field.attr('type') ) ? $password_field.attr('type', 'text') : $password_field.attr('type', 'password');
( 'Hide' == $this.text() ) ? $this.text('Show') : $this.text('Hide');
//focus and move cursor to the end of input field
$password_field.putCursorAtEnd();
});
//show forgot-password form
$forgot_password_link.on('click', function(event){
event.preventDefault();
forgot_password_selected();
});
//back to login from the forgot-password form
$back_to_login_link.on('click', function(event){
event.preventDefault();
login_selected();
});
function login_selected(){
$form_login.addClass('is-selected');
$form_signup.removeClass('is-selected');
$form_forgot_password.removeClass('is-selected');
$tab_login.addClass('selected');
$tab_signup.removeClass('selected');
}
function signup_selected(){
$form_login.removeClass('is-selected');
$form_signup.addClass('is-selected');
$form_forgot_password.removeClass('is-selected');
$tab_login.removeClass('selected');
$tab_signup.addClass('selected');
}
function forgot_password_selected(){
$form_login.removeClass('is-selected');
$form_signup.removeClass('is-selected');
$form_forgot_password.addClass('is-selected');
}
//REMOVE THIS - it's just to show error messages
$form_login.find('input[type="submit"]').on('click', function(event){
event.preventDefault();
$form_login.find('input[type="email"]').toggleClass('has-error').next('span').toggleClass('is-visible');
});
$form_signup.find('input[type="submit"]').on('click', function(event){
event.preventDefault();
$form_signup.find('input[type="email"]').toggleClass('has-error').next('span').toggleClass('is-visible');
});
//IE9 placeholder fallback
//credits http://www.hagenburger.net/BLOG/HTML5-Input-Placeholder-Fix-With-jQuery.html
if(!Modernizr.input.placeholder){
$('[placeholder]').focus(function() {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
}
}).blur(function() {
var input = $(this);
if (input.val() == '' || input.val() == input.attr('placeholder')) {
input.val(input.attr('placeholder'));
}
}).blur();
$('[placeholder]').parents('form').submit(function() {
$(this).find('[placeholder]').each(function() {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
}
})
});
}
});
//credits https://css-tricks.com/snippets/jquery/move-cursor-to-end-of-textarea-or-input/
jQuery.fn.putCursorAtEnd = function() {
return this.each(function() {
// If this function exists...
if (this.setSelectionRange) {
// ... then use it (Doesn't work in IE)
// Double the length because Opera is inconsistent about whether a carriage return is one character or two. Sigh.
var len = $(this).val().length * 2;
this.setSelectionRange(len, len);
} else {
// ... otherwise replace the contents with itself
// (Doesn't work in Google Chrome)
$(this).val($(this).val());
}
});
};
\ No newline at end of file
This diff is collapsed.
{
"particles": {
"number": {
"value": 50,
"density": {
"enable": true,
"value_area": 800
}
},
"color": {
"value": "#ffc400"
},
"shape": {
"type": "circle",
"stroke": {
"width": 0,
"color": "#000000"
},
"polygon": {
"nb_sides": 5
},
"image": {
"src": "img/github.svg",
"width": 100,
"height": 100
}
},
"opacity": {
"value": 0.5,
"random": false,
"anim": {
"enable": false,
"speed": 1,
"opacity_min": 0.1,
"sync": false
}
},
"size": {
"value": 3,
"random": true,
"anim": {
"enable": true,
"speed": 10,
"size_min": 0.1,
"sync": false
}
},
"line_linked": {
"enable": true,
"distance": 150,
"color": "#ffffff",
"opacity": 0.4,
"width": 1
},
"move": {
"enable": true,
"speed": 5,
"direction": "none",
"random": true,
"straight": false,
"out_mode": "bounce",
"bounce": false,
"attract": {
"enable": true,
"rotateX": 600,
"rotateY": 1200
}
}
},
"interactivity": {
"detect_on": "window",
"events": {
"onhover": {
"enable": false,
"mode": "repulse"
},
"onclick": {
"enable": true,
"mode": "repulse"
},
"resize": true
},
"modes": {
"grab": {
"distance": 400,
"line_linked": {
"opacity": 1
}
},
"bubble": {
"distance": 400,
"size": 40,
"duration": 2,
"opacity": 8,
"speed": 3
},
"repulse": {
"distance": 200,
"duration": 0.4
},
"push": {
"particles_nb": 4
},
"remove": {
"particles_nb": 2
}
}
},
"retina_detect": true
}
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<script src="{{ url_for('static', filename='js/particles.js') }}"></script>
<script src="{{ url_for('static', filename='js/modals.js') }}"></script>
<script>
particlesJS.load('particles-js', '/static/particles.json', function() {
console.log('callback - particles.js config loaded');
});
</script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Lato:300,100" rel="stylesheet">
<title> Hodor Security Training</title>
</head>
<body>
{% include 'layout/navigation.html' %}
<div id="particles-js" class="container-fluid content">
<div class="row text-center abs">
<img id="logo" src="{{ url_for('static', filename='img/hodor.png') }}" width="150" height="180">
</div>
<div class="row text-center abs">
<h2 id="caption"> Hodor <span id="version">v.0.0.1 alpha</span></h2>
</div>
<div class="row text-center abs">
<pre id="subtitle"> Hodor is an open-sourced, cyber-security training and practice platform designed for beginners.
Hodor is currently in alpha development stage
</pre>
</div>
<div class="row text-center abs">
<button id="more" class="btn btn-outline-danger">Know More</button>
</div>
</div>
</body>
</html>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark justify-content-between hodor-nav" style="background-color:#101010;">
<div class="container-fluid">
<div class="row">
<a class="navbar-brand nav-hodor float-sm-left" href="#">
<img src="{{ url_for('static', filename='img/hodor.png') }}" width="25" class="d-inline-block align-top" alt="">
Hodor Project
</a>
</div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarText">
<ul class="nav navbar-nav mr-auto"></ul> <!-- Stupid Bootstrap -->
<ul class="nav navbar-nav">
<span class="navbar-text">
<!-- TO DO: Change Guest to a variable -->
Welcome, <span style="font-weight: bolder; color: white;"> Guest</span>
</span>
<ul class="nav-item">
<button class="btn btn-outline-success my-2 my-sm-0 mr-3 cd-signin" >Sign In</button>
<button class="btn btn-outline-info my-2 my-sm-0 mr-3 cd-signup" >Register</button>
</ul>
</ul>
</div>
</div>
</nav>
<!-- Navigation Ends here -->
<div class="cd-user-modal"> <!-- this is the entire modal form, including the background -->
<div class="cd-user-modal-container"> <!-- this is the container wrapper -->
<ul class="cd-switcher">
<li><a href="#0">Sign in</a></li>
<li><a href="#0">New account</a></li>
</ul>
<div id="cd-login"> <!-- log in form -->
<form class="cd-form">
<p class="fieldset">
<label class="image-replace cd-email" for="signin-email">E-mail</label>
<input class="full-width has-padding has-border" id="signin-email" required type="email" placeholder="E-mail">
<span class="cd-error-message">Invalid E-mail</span>
</p>
<p class="fieldset">
<label class="image-replace cd-password" for="signin-password">Password</label>
<input class="full-width has-padding has-border" id="signin-password" required type="text" placeholder="Password">
<a href="#0" class="hide-password">Hide</a>
<span class="cd-error-message">Hmm, that doesn't look right!</span>
</p>
<p class="fieldset">
<input type="checkbox" id="remember-me" checked>
<label for="remember-me">Remember me</label>
</p>
<p class="fieldset">
<input class="full-width" type="submit" value="Login">
</p>
</form>
<p class="cd-form-bottom-message"><a href="#0">Forgot your password?</a></p>
</div> <!-- cd-login -->
<div id="cd-signup"> <!-- sign up form -->
<form class="cd-form">
<p class="fieldset">
<label class="image-replace cd-username" for="signup-username">Username</label>
<input class="full-width has-padding has-border" id="signup-username" required type="text" placeholder="Username">
<span class="cd-error-message">Error message here!</span>
</p>
<p class="fieldset">
<label class="image-replace cd-email" for="signup-email">E-mail</label>
<input class="full-width has-padding has-border" id="signup-email" required type="email" placeholder="E-mail">
<span class="cd-error-message">Error message here!</span>
</p>
<p class="fieldset">
<label class="image-replace cd-password" for="signup-password">Password</label>
<input class="full-width has-padding has-border" id="signup-password" type="text" required placeholder="Password">
<a href="#0" class="hide-password">Hide</a>
<span class="cd-error-message">Error message here!</span>
</p>
<p class="fieldset">
<input type="checkbox" required id="accept-terms">
<label for="accept-terms">I agree to the <a href="#0">Terms</a></label>
</p>
<p class="fieldset">
<input class="full-width has-padding" type="submit" value="Create account">
</p>
</form>
<!-- <a href="#0" class="cd-close-form">Close</a> -->
</div> <!-- cd-signup -->
<div id="cd-reset-password"> <!-- reset password form -->
<p class="cd-form-message">Lost your password? Please enter your email address. You will receive a link to create a new password.</p>
<form class="cd-form">
<p class="fieldset">
<label class="image-replace cd-email" for="reset-email">E-mail</label>
<input class="full-width has-padding has-border" id="reset-email" type="email" placeholder="E-mail">
<span class="cd-error-message">Error message here!</span>
</p>
<p class="fieldset">
<input class="full-width has-padding" type="submit" value="Reset password">
</p>
</form>
<p class="cd-form-bottom-message"><a href="#0">Back to log-in</a></p>
</div> <!-- cd-reset-password -->
<a href="#0" class="cd-close-form">Close</a>
</div> <!-- cd-user-modal-container -->
</div> <!-- cd-user-modal -->
<div class="area">
</div>
<nav class="main-menu">
<div>
<ul>
<li>
<div style="color: white">
<i class="fa fa-user fa-2x"></i>
<span class="nav-text">
Sachin S. Kamath
<button style="padding-left: 20px; margin-top: 10px; font-size: 12px"class="btn btn-outline-success"> Edit Profile </button>
</span>
</div>
</li>
<ul>
</div>
<ul>
<li>
<a href="#">
<i class="fa fa-home fa-2x"></i>
<span class="nav-text">
Dashboard
</span>
</a>
</li>
<li class="has-subnav">
<a href="#">
<i class="fa fa-laptop fa-2x"></i>
<span class="nav-text">
Learn
</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-bar-chart-o fa-2x"></i>
<span class="nav-text">
Leaderboards
</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-flag fa-2x"></i>
<span class="nav-text">
Capture the Flag
</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-info fa-2x"></i>
<span class="nav-text">
Documentation and Help
</span>
</a>
</li>
</ul>
<ul class="logout">
<li class="text">
<a href="#">
<i style="color: #d9534f !important;" class="fa fa-power-off fa-2x"></i>
<span class="nav-text">
Logout
</span>
</a>
</li>
</ul>
</nav>
# -*- coding: utf-8 -*-