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
  • hodorsec/hodor-backend
  • Vasanth/hodor-webapp
  • skamath/hodor-backend
  • techtocore/hodor-backend
4 results
Select Git revision
Loading items
Show changes

Commits on Source 15

...@@ -57,7 +57,7 @@ coverage.xml ...@@ -57,7 +57,7 @@ coverage.xml
local_settings.py local_settings.py
# Flask stuff: # Flask stuff:
instance/ migrations/
.webassets-cache .webassets-cache
# Scrapy stuff: # Scrapy stuff:
......
### Contributing to this repo ### Contributing to this repo
* Fork the repository * 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 * 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`. 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,18 @@ ...@@ -3,10 +3,18 @@
The web application for the Hodor Project The web application for the Hodor Project
## Quickstart ## 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` * Clone the repo using `git clone https://git.amrita.edu/hodorsec/hodor-webapp`
* Create a virtualenv (see below for instructions) and activate it. * Create a virtualenv (see below for instructions) and activate it.
* After activating it, `pip install --user -r requirements.txt` to * After activating it, `pip install --user -r requirements.txt` to
install dependencies. 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. * `./runserver.py` to run the app.
* Navigate to `http://127.0.0.1:8080` to watch it in action! * Navigate to `http://127.0.0.1:8080` to watch it in action!
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# app/__init__.py # app/__init__.py
import os
import sys
import time import time
from termcolor import colored from termcolor import colored
import sys
from flask_api import FlaskAPI from flask_api import FlaskAPI
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
# local import
from instance.config import app_config from instance.config import app_config
# initialize sql-alchemy # initialize sql-alchemy
...@@ -21,9 +21,13 @@ application.config.from_object(app_config[config_name]) ...@@ -21,9 +21,13 @@ application.config.from_object(app_config[config_name])
application.config.from_pyfile('config.py') application.config.from_pyfile('config.py')
application.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False application.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(application) db.init_app(application)
application.config['SECRET_KEY'] = 'blehblehbleh'
# Delay the application launch to get the user attention if running in
# testing mode
# Delay the application launch to get the user attention if running in testing mode if config_name != 'production' and not os.getenv('SKIP_COUNT'):
if config_name != 'production':
for x in range(0, 5): for x in range(0, 5):
sys.stdout.write(colored("\rYou are not running the server in production mode. " + sys.stdout.write(colored("\rYou are not running the server in production mode. " +
"App will run in {} seconds..".format(5-x), 'red')) "App will run in {} seconds..".format(5-x), 'red'))
...@@ -32,7 +36,8 @@ if config_name != 'production': ...@@ -32,7 +36,8 @@ if config_name != 'production':
print(colored("\n\nRunning app in {} mode..".format(config_name), 'yellow')) print(colored("\n\nRunning app in {} mode..".format(config_name), 'yellow'))
# This disables the HTML API renderer for flask_api when called through browsers. # This disables the HTML API renderer for flask_api when called through
# browsers.
if config_name == 'production': if config_name == 'production':
application.config['DEFAULT_RENDERERS'] = [ application.config['DEFAULT_RENDERERS'] = [
'flask.ext.api.renderers.JSONRenderer', 'flask.ext.api.renderers.JSONRenderer',
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from hodor import app from hodor import app
from flask import jsonify from flask import request, jsonify, abort, make_response
from hodor.models.user import User
from sqlalchemy.exc import IntegrityError
@app.route('/') def _extract_required_fields(user):
def start(): filtered_user = dict()
return jsonify({'hello': 'world'}) '''
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']) @app.route('/print', methods=['GET', 'POST'])
......
# -*- 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 -*- # -*- coding: utf-8 -*-
from hodor import db from hodor import db
from sqlalchemy import inspect
from sqlalchemy_utils import PasswordType
class User(db.Model): class User(db.Model):
__tablename__ = 'users' __tablename__ = 'users'
# Values entered by the user # Values entered by the user
username = db.Column(db.String(32), primary_key=True) username = db.Column(db.String(32), primary_key=True, nullable=False)
first_name = db.Column(db.String(32), nullable=False) first_name = db.Column(db.String(32), nullable=False)
last_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) email = db.Column(db.String(64), unique=True, nullable=False)
password = db.Column(db.String(64), 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 # Platform values
disabled = db.Column(db.Boolean, default=False) disabled = db.Column(db.Boolean, default=False)
...@@ -20,11 +33,9 @@ class User(db.Model): ...@@ -20,11 +33,9 @@ class User(db.Model):
def __unicode__(self): def __unicode__(self):
return unicode(self.username) return unicode(self.username)
def __init__(self, name):
"""initialize with name."""
self.name = name
def save(self): def save(self):
print type(self)
print self.email
db.session.add(self) db.session.add(self)
db.session.commit() db.session.commit()
...@@ -32,6 +43,10 @@ class User(db.Model): ...@@ -32,6 +43,10 @@ class User(db.Model):
def get_all(): def get_all():
return User.query.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): def delete(self):
db.session.delete(self) db.session.delete(self)
db.session.commit() db.session.commit()
......
# -*- coding: utf-8 -*-
# coding=utf-8
# 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
from flask_script import Manager # class for handling a set of commands from flask_script import Manager # class for handling a set of commands
from flask_migrate import Migrate, MigrateCommand from flask_migrate import Migrate, MigrateCommand
from hodor import db, create_app from hodor import db, app
app = create_app(config_name='development')
migrate = Migrate(app, db) migrate = Migrate(app, db)
manager = Manager(app) manager = Manager(app)
......
...@@ -3,3 +3,10 @@ Flask-WTF ...@@ -3,3 +3,10 @@ Flask-WTF
Jinja2 Jinja2
Flask-DebugToolbar Flask-DebugToolbar
flask_api flask_api
termcolor
flask_sqlalchemy
sqlalchemy_utils
SQLAlchemy
flask_script
flask_migrate
passlib
\ No newline at end of file