Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Commit

Permalink
Adding app code
Browse files Browse the repository at this point in the history
  • Loading branch information
IcyMidnight committed May 25, 2015
1 parent e207272 commit c904a2b
Show file tree
Hide file tree
Showing 14 changed files with 492 additions and 0 deletions.
16 changes: 16 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

from coreapi import CoreAPI

#from flaskext.mysql import MySQL

app = Flask(__name__)
app.config.from_object('config')

CoreAPI.check_app(app)
coreapi = CoreAPI(app)

db = SQLAlchemy(app)

from app import controllers, models
161 changes: 161 additions & 0 deletions app/controllers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
from binascii import unhexlify
from hashlib import sha256
from datetime import datetime

from braveapi.client import API
from ecdsa.keys import SigningKey, VerifyingKey
from ecdsa.curves import NIST256p

from flask import render_template, flash, redirect, url_for, abort, request, jsonify, session, g
from app import app, coreapi, db, models
from .forms import ConfirmStanding, SearchStanding
from .coreapi import CoreAPI, CoreSession

import cgi


CHECK_LOGIN_EXCLUDE_ENDPOINTS = ['authorize', 'authorized']
@app.before_request
def check_login():
if request.endpoint not in CHECK_LOGIN_EXCLUDE_ENDPOINTS:
if 'token' in session:
core_session = coreapi.get_session(session['token'])
# TODO: check perms here
g.core_session = core_session
g.user = core_session.get_user()
else:
return redirect('/authorize')

@app.route('/session_info')
def session_info():
if g.core_session:
return jsonify(g.core_session.info)
return "No active session"

@app.route('/perm_info')
def perm_info():
return "View: {0}<br/>Edit: {1}<br/>core.application.create: {2}" \
.format(g.core_session.has_view_perm(), g.core_session.has_edit_perm(), g.core_session.has_perm('core.application.create'))


@app.route('/')
@app.route('/standings')
def index():
standings = models.Standing.query.all()

return render_template("standings.html",
title='Standings',
user=g.user,
standings=standings)

@app.route('/add_standing', methods=['GET', 'POST'])
def add_standing():

form = SearchStanding()
if form.validate_on_submit():

if form.entity_type.data == 'alliance':
flash('alliance')
else:
flash('corp')
preview_form = ConfirmStanding()
return render_template('standing_add_preview.html',
form = preview_form,
entity_type = form.entity_type.data,
standing = form.standing.data,
entity_id = 'id',
corporation_name = 'corp name',
corporation_ticker = 'corp ticker',
alliance_name = 'alliance name',
alliance_ticker = 'alliance ticker')
if form.errors:
for field_name, field_errors in form.errors.items():
flash(u"Error in %s: %s" % (form[field_name].label.text, "<br>".join(field_errors)))
return render_template('standing_add_search.html',
title='Add Standing',
form=form)


@app.route('/do_edit_standing', methods=['GET', 'POST'])
def do_edit_standing():
form = ConfirmStanding()
if form.validate_on_submit():
if form.entity_type == 'alliance':
flash('alliance')
models.Standing.query.filter_by()
else:
flash('corp')


if form.errors:
for field_name, field_errors in form.errors.items():
flash(u"Error in %s: %s" % (form[field_name].label.text, "<br>".join(field_errors)))
return redirect('/add_standing')

# Perform the initial API call and direct the user.
@app.route('/authorize')
def authorize():
api = coreapi.get_api()

# Build Success/Failure Redirect URLs
success = str("http://"+app.config['SERVER_NAME']+url_for('authorized'))
failure = str("http://"+app.config['SERVER_NAME']+url_for('fail'))

# Make the authentication call to the CORE Service
result = api.core.authorize(success=success, failure=failure)

print result.__repr__()

if 'location' in result:
# Redirect based on the authentication request validity
return redirect(result.location)
else:
return 'Error authorizing app: {0}'.format(result.message)


# Root URI
@app.route('/authorized')
def authorized():
# Perform the initial API call and direct the user.

api = coreapi.get_api()

# Build Success/Failure Redirect URLs
token = request.args.get('token', '')

if not token:
abort(401)

session['token'] = token

return redirect('/session_info')


# Root URI
@app.route('/fail')
def fail():
abort(401)

@app.route('/logout')
@app.route('/ciao')
def logout():
session.pop('token', None)
return "Logged out"

@app.route('/posts')
def posts():
user = {'nickname': 'Miguel'} # fake user
posts = [ # fake array of posts
{
'author': {'nickname': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'nickname': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template("index.html",
title='Home',
user=user,
posts=posts)
95 changes: 95 additions & 0 deletions app/coreapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# CORE_ENDPOINT: Url of the CORE API server your connecting to. Must not have a trailing '/', usually points to /api on the deployed domain
# CORE_APP_ID: The ID of your registered application on the application management page in Core
# CORE_PRIVATE_KEY: Your applications Private ECDSA Key as generated in the check_app(app) function
# CORE_CORE_PUBLIC_KEY: The Core API server's Public ECDSA Key, printed in HEX on the application management page.

import textwrap

from binascii import unhexlify
from hashlib import sha256

from ecdsa.keys import SigningKey, VerifyingKey
from ecdsa.curves import NIST256p

from braveapi.client import API

class CoreAPI:
required_config_variables_ = ['CORE_ENDPOINT', 'CORE_APP_ID', 'CORE_PRIVATE_KEY', \
'CORE_CORE_PUBLIC_KEY', 'CORE_VIEW_PERMISSION', 'CORE_EDIT_PERMISSION']

def __init__(self, app):
self.endpoint = app.config['CORE_ENDPOINT']
self.app_id = app.config['CORE_APP_ID']
self.private_key_string = app.config['CORE_PRIVATE_KEY']
self.core_public_key_string = app.config['CORE_CORE_PUBLIC_KEY']

self.private_key = SigningKey.from_string(unhexlify(self.private_key_string), curve=NIST256p, hashfunc=sha256)
self.core_public_key = VerifyingKey.from_string(unhexlify(self.core_public_key_string), curve=NIST256p, hashfunc=sha256)

self.view_perm = app.config['CORE_VIEW_PERMISSION']
self.edit_perm = app.config['CORE_EDIT_PERMISSION']

@staticmethod
def check_app(app):
try:
for var in CoreAPI.required_config_variables_:
app.config[var]
except KeyError as e:
private = SigningKey.generate(NIST256p, hashfunc=sha256)

error_message = "\n================================================================================\n"

error_message += "Core Service API identity, public, or private key missing.\n\n"

error_message += "Here's a new private key; update the api.private setting to reflect this.\n" + \
"%s \n\n" % private.to_string().encode('hex')

error_message += "Here's that key's public key; this is what you register with Core.\n" + \
"%s \n\n" % private.get_verifying_key().to_string().encode('hex')

error_message += textwrap.fill("After registering, make sure to populate all of the following in config.py: {0}" \
.format(", ".join(CoreAPI.required_config_variables_)))

error_message += "\n================================================================================\n\n"

print error_message
raise

def get_api(self):
return API(self.endpoint, self.app_id, self.private_key, self.core_public_key)

def get_session(self, token):
info = self.get_api().core.info(token=token)
return CoreSession(self, info)

def check_logged_in(self):
return


class CoreSession:
def __init__(self, coreapi, info):
self.info = info
self.coreapi = coreapi

def has_perm(self, perm):
return perm in self.info.perms

def has_view_perm(self):
return self.has_perm(self.coreapi.view_perm)

def has_edit_perm(self):
return self.has_perm(self.coreapi.edit_perm)

def get_user(self):
alliance = None
if 'alliance' in self.info:
alliance = self.info.alliance.name
return User(self.info.character.name,
self.info.corporation.name,
alliance)

class User:
def __init__(self, character, corporation, alliance):
self.character = character
self.corporation = corporation
self.alliance = alliance
21 changes: 21 additions & 0 deletions app/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from flask.ext.wtf import Form
from wtforms import StringField, BooleanField, RadioField, SubmitField, HiddenField
from wtforms.validators import DataRequired

class SearchStanding(Form):
entity_type = RadioField('Entity Type',
choices=[('alliance', 'Alliance'), ('corporation', 'Corporation')],
default='alliance',
validators=[DataRequired()])
search_text = StringField('Search', validators=[DataRequired()])
standing = RadioField('Standing',
choices=[('+10', '+10'), ('+5', '+5'), ('+2.5', '+2.5'), ('+1.1', '+1.1'), ('0', '0'), ('-5', '-5'), ('-10', '-10')],
default='+2.5',
validators=[DataRequired()])
add_by_id = SubmitField('Add By Id')
add_by_name = SubmitField('Add By Name')
add_by_ticker = SubmitField('Add By Ticker')

class ConfirmStanding(Form):
entity_type = HiddenField('Entity Type', validators=[DataRequired()])
standing = HiddenField('Search', validators=[DataRequired()])
48 changes: 48 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from app import db

class Character(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(1024), index=True, unique=True)
corporation_id = db.Column(db.Integer, db.ForeignKey('corporation.id'))
alliance_id = db.Column(db.Integer, db.ForeignKey('alliance.id'))

class Corporation(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(1024), index=True, unique=True)
ticker = db.Column(db.String(1024), index=True, unique=True)
alliance_id = db.Column(db.Integer, db.ForeignKey('alliance.id'))
characters = db.relationship('Character', backref='corporation', lazy='dynamic')
standings = db.relationship('Standing', backref='corporation', lazy='dynamic')

class Alliance(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(1024), index=True, unique=True)
ticker = db.Column(db.String(1024), index=True, unique=True)
characters = db.relationship('Character', backref='alliance', lazy='dynamic')
corporations = db.relationship('Corporation', backref='alliance', lazy='dynamic')
standings = db.relationship('Standing', backref='alliance', lazy='dynamic')

class Standing(db.Model):
id = db.Column(db.Integer, primary_key=True)
standing = db.Column(db.String(16), index=True)
corporation_id = db.Column(db.Integer, db.ForeignKey('corporation.id'))
alliance_id = db.Column(db.Integer, db.ForeignKey('alliance.id'))
creator_id = db.Column(db.Integer, db.ForeignKey('character.id'))
editor_id = db.Column(db.Integer, db.ForeignKey('character.id'))

class StandingChange(db.Model):
id = db.Column(db.Integer, primary_key=True)
corporation_id = db.Column(db.Integer, db.ForeignKey('corporation.id'))
alliance_id = db.Column(db.Integer, db.ForeignKey('alliance.id'))
date = db.Column(db.DateTime)
character_name = db.Column(db.String(1024))
character_corporation_name = db.Column(db.String(1024))
character_corporation_ticker = db.Column(db.String(1024))
character_alliance_name = db.Column(db.String(1024))
character_alliance_ticker = db.Column(db.String(1024))

def find_or_create_corporation_standing(corporation_eve_id, character_eve_id):
standing = self.query.filter_by(corporation_id = corpororation_eve_id).first()
if not standing:
standing = self.__class__()

47 changes: 47 additions & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<html>
<head>
{% if title %}
<title>{{ title }} - standings</title>
{% else %}
<title>standings</title>
{% endif %}

<link href="/static/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/static/css/bootstrap-responsive.min.css" rel="stylesheet">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/static/css/base.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">
<strong>HERO</strong>
<small>Standings</small>
</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="/add_standing">Add</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="/logout">Log out</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
{% include 'flash.html' %}
{% block content %}{% endblock %}
</div>
</body>
</html>
Loading

0 comments on commit c904a2b

Please sign in to comment.