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
Loading items

Target

Select target project
0 results Searching
Select Git revision
Loading items
Show changes

Commits on Source 39

27 files
+ 524
183
Compare changes
  • Side-by-side
  • Inline

Files

+111 −2
Original line number Diff line number Diff line
# Personal virtualenv
.hodor
# 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/

# Jetbrains folders
.idea/
migrations/

CONTRIBUTING.md

0 → 100644
+12 −0
Original line number Diff line number Diff line
### Contributing to this repo

* Fork the repository
* 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`.
* 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!

LICENSE

0 → 100644
+21 −0
Original line number Diff line number Diff line
MIT License

Copyright (c) 2017 Hodor Security Project

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.

README.markdown

deleted100644 → 0
+0 −19
Original line number Diff line number Diff line
A simple boilerplate application following the MVC pattern using Flask micro python framework.
It basically here to be my base skeleton for new python web applications

Demo : http://flask-mvc-salimane.herokuapp.com/

Dependencies :
	
	git clone git://github.com/salimane/flask-mvc.git
	cd flask-mvc
    	if you have old version of project: pip uninstall -r requirements.txt
	pip install -r requirements.txt

To run:

    python runserver.py


[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/salimane/flask-mvc/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

README.md

0 → 100644
+23 −0
Original line number Diff line number Diff line
# Hodor WebApp

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 (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.
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
__version__ = '0.1'
from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension
app = Flask('project')
app.config['SECRET_KEY'] = 'random'
app.debug = True
toolbar = DebugToolbarExtension(app)
from project.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

hodor/controllers/printer.py

deleted100644 → 0
+0 −26
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
from project 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('printer/index.html')


@app.route('/print', methods=['GET', 'POST'])
def printer():
    form = CreateForm(request.form)
    if request.method == 'POST' and form.validate():
        from project.models.Printer import Printer
        printer = Printer()
        printer.show_string(form.text.data)
        return render_template('printer/index.html')
    return render_template('printer/print.html', form=form)
+155 −0
Original line number Diff line number Diff line
# -*- 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

hodor/models/Printer.py

deleted100644 → 0
+0 −11
Original line number Diff line number Diff line
# -*- 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 + "!!!")
+26 −0
Original line number Diff line number Diff line
# -*- 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()

hodor/models/user.py

0 → 100644
+55 −0
Original line number Diff line number Diff line
# -*- 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)

hodor/static/css/style.css

deleted100644 → 0
+0 −71
Original line number Diff line number Diff line
body {
    font-family: sans-serif;
    background: #eee;
}

a,h1,h2 {
    color: #377BA8;
}

h1,h2 {
    font-family: 'Georgia', serif;
    margin: 0;
}

h1 {
    border-bottom: 2px solid #eee;
}

h2 {
    font-size: 1.2em;
}

.page {
    margin: 2em auto;
    width: 35em;
    border: 5px solid #ccc;
    padding: 0.8em;
    background: white;
}

.entries {
    list-style: none;
    margin: 0;
    padding: 0;
}

.entries li {
    margin: 0.8em 1.2em;
}

.entries li h2 {
    margin-left: -1em;
}

.add-entry {
    font-size: 0.9em;
    border-bottom: 1px solid #ccc;
}

.add-entry dl {
    font-weight: bold;
}

.metanav {
    text-align: right;
    font-size: 0.8em;
    padding: 0.3em;
    margin-bottom: 1em;
    background: #fafafa;
}

.flash {
    background: #CEE5F5;
    padding: 0.5em;
    border: 1px solid #AACBE2;
}

.error {
    background: #F0D6D6;
    padding: 0.5em;
}
 No newline at end of file
+0 −22
Original line number Diff line number Diff line
<!doctype html>
    <head>
        <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
        <title>Flask-MVC</title>
    </head>
    <body>    
        <a style="text-align:center" href="{{ url_for('start') }}">Home</a>
        <a style="text-align:center" href="http://salimane.com">About</a>
        <div class="page">
            <h1>Flask MVC Boilerplate</h1>
            {% for message in get_flashed_messages() %}
                <div class="flash">{{ message }}</div>
            {% endfor %}
            {% macro render_error(field) %}
                {% if field.errors %}
                    {% for error in field.errors %}<span class='error'>{{ error }}</span>{% endfor %}
                {% endif %}
            {% endmacro %}
            {% block body %}{% endblock %}
        </div>
    </body>
</html>
+0 −8
Original line number Diff line number Diff line
{% extends "layout/layout.html" %}
{% block body %}
    <ul> 
        <p>
            <a href="{{ url_for('printer') }}">Click here to print!</a>
        </p>
    </ul>
{% endblock %}
+0 −10
Original line number Diff line number Diff line
{% extends "layout/layout.html" %}
{% block body %}
    <form action="{{ url_for('printer') }}" method="post">
        {{ form.csrf_token }}
        <dl>
            <dd>{{ form.text.label }} {{ form.text(size=20) }} {{ render_error(form.text) }}</dd>
            <dd><input type="submit" value="Flash"/></dd>
        </dl>
    </form>
{% endblock %}

hodor/tests/user.py

0 → 100644
+1 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-

instance/__init__.py

0 → 100644
+1 −0
Original line number Diff line number Diff line
# coding=utf-8

instance/config.py

0 → 100644
+48 −0
Original line number Diff line number Diff line
# coding=utf-8
import os


class Config(object):
    """Parent configuration class."""
    DEBUG = False
    CSRF_ENABLED = True
    TESTING = False
    SECRET = os.getenv('SECRET')
    SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL')


class DevelopmentConfig(Config):
    """Configurations for Development."""
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/hodor_test'
    SECRET = "ChangeThisStringIfYouWant"
    TESTING = True


class TestingConfig(Config):
    """Configurations for Testing, with a separate test database."""
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/test_db'
    DEBUG = True
    SECRET = 'ChangeMeMaybe'


class StagingConfig(Config):
    """Configurations for Staging."""
    DEBUG = True


class ProductionConfig(Config):
    """Configurations for Production."""
    DEBUG = False
    TESTING = False
    SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/hodor_prod'
    SECRET = "TODO: ChangeMeInProduction"


app_config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'staging': StagingConfig,
    'production': ProductionConfig,
}
 No newline at end of file

manage.py

0 → 100644
+12 −0
Original line number Diff line number Diff line
from flask_script import Manager # class for handling a set of commands
from flask_migrate import Migrate, MigrateCommand
from hodor import db, app


migrate = Migrate(app, db)
manager = Manager(app)

manager.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manager.run()
+3 −6
Original line number Diff line number Diff line
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from project import app
#!/bin/env python
from hodor import app

if __name__ == '__main__':
    port = int(os.environ.get("PORT", 8080))
    app.run('0.0.0.0', port=port)
    app.run()