Skip to content

Commit 514842d

Browse files
committed
barebones structure with asynctasks and db
1 parent 77d3b9b commit 514842d

18 files changed

+308
-0
lines changed

MANIFEST.in

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
recursive-include recastfrontend/templates *
2+
recursive-include recastfrontend/static *
3+
recursive-include recastfrontend/resources *

recastfrontend/__init__.py

Whitespace-only changes.

recastfrontend/admincli.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import click
2+
import IPython
3+
import os
4+
5+
@click.group()
6+
def admincli():
7+
pass
8+
9+
@admincli.command()
10+
@click.option('--config','-c')
11+
def dbshell(config):
12+
if config:
13+
os.environ['RECASTCONTROLCENTER_CONFIG'] = config
14+
from recastfrontend.server import app
15+
with app.app_context():
16+
from recastfrontend.server import db
17+
import recastfrontend.models as models
18+
print "models and db modules are available"
19+
IPython.embed()
20+
21+
@admincli.command()
22+
@click.option('--config','-c')
23+
def create_db(config):
24+
if config:
25+
os.environ['RECASTCONTROLCENTER_CONFIG'] = config
26+
from recastfrontend.server import app
27+
with app.app_context():
28+
from recastfrontend.server import db
29+
db.create_all()
30+
click.secho('created database at: {}'.format(db.engine.url), fg = 'green')

recastfrontend/asynctasks.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from celery import shared_task
2+
3+
@shared_task
4+
def hello_world():
5+
print "hello world"

recastfrontend/celeryapp.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from celery import Celery
2+
app = Celery('frontendcelery')
3+
app.config_from_object('recastfrontend.celeryconfig')

recastfrontend/celeryconfig.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from recastfrontend.frontendconfig import config as frontendconf
2+
3+
BROKER_URL = 'redis://' + frontendconf['HOSTNAME']
4+
CELERY_RESULT_BACKEND = "redis"
5+
CELERY_REDIS_HOST = frontendconf['HOSTNAME']
6+
CELERY_REDIS_PORT = 6379
7+
CELERY_REDIS_DB = 0
8+
CELERY_TRACK_STARTED = True

recastfrontend/database.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from flask.ext.sqlalchemy import SQLAlchemy
2+
db = SQLAlchemy()

recastfrontend/flaskconfig.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from recastfrontend.frontendconfig import config as frontendconf
2+
3+
DEBUG = True
4+
SECRET_KEY = 'some_secret'
5+
SQLALCHEMY_DATABASE_URI = 'sqlite:///'+frontendconf['DBPATH']

recastfrontend/frontendcli.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import click
2+
import os
3+
4+
@click.group()
5+
def frontendcli():
6+
pass
7+
8+
@frontendcli.command()
9+
@click.option('--config','-c')
10+
def server(config):
11+
if config:
12+
os.environ['RECASTCONTROLCENTER_CONFIG'] = config
13+
from server import app
14+
app.run(host='0.0.0.0',port = 5000)

recastfrontend/frontendconfig.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import os
2+
import pkg_resources
3+
import yaml
4+
5+
def default_config():
6+
return yaml.load(open(pkg_resources.resource_filename('recastfrontend','resources/defaultconfig.yaml')))
7+
8+
9+
def mk_config():
10+
the_config = default_config()
11+
if os.environ.has_key('RECASTCONTROLCENTER_CONFIG'):
12+
custom_config = yaml.load(open(os.environ['RECASTCONTROLCENTER_CONFIG']))
13+
the_config.update(**custom_config)
14+
return the_config
15+
16+
config = mk_config()

recastfrontend/models.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from database import db
2+
3+
class User(db.Model):
4+
__tablename__ = 'users'
5+
id = db.Column(db.Integer, primary_key=True)
6+
name = db.Column(db.String, nullable=False)
7+
email = db.Column(db.String, nullable=False, unique=False)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ORCID_APPID: 'ORCID_APPID'
2+
ORCID_REDIRECT_URI: 'ORCID_REDIRECT_URI'
3+
ORCID_SECRET: 'ORCID_SECRET'
4+
HOSTNAME: 'localhost'
5+
CELERYAPP: 'recastfrontend.celeryapp'
6+
FLASKCONFIG: 'recastfrontend.flaskconfig'
7+
DBPATH: 'database.db'

recastfrontend/server.py

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import json
2+
import requests
3+
import importlib
4+
import asynctasks
5+
6+
7+
8+
from flask import Flask, redirect, jsonify, session, request, url_for, render_template
9+
from flask.ext import login as login
10+
from frontendconfig import config as frontendconf
11+
from database import db
12+
import recastfrontend.models as dbmodels
13+
14+
celeryapp = importlib.import_module(frontendconf['CELERYAPP']).app
15+
16+
ORCID_APPID = frontendconf['ORCID_APPID']
17+
ORCID_REDIRECT_URI = frontendconf['ORCID_REDIRECT_URI']
18+
ORCID_SECRET = frontendconf['ORCID_SECRET']
19+
20+
21+
class User(login.UserMixin):
22+
def __init__(self,**kwargs):
23+
self.orcid = kwargs.get('orcid','no-orcid')
24+
self.fullname = kwargs.get('fullname','no-name')
25+
def get_id(self):
26+
return self.orcid
27+
def name(self):
28+
return self.fullname
29+
30+
def create_app():
31+
app = Flask(__name__)
32+
app.config.from_object(frontendconf['FLASKCONFIG'])
33+
db.init_app(app)
34+
return app
35+
36+
app = create_app()
37+
38+
login_manager = login.LoginManager()
39+
login_manager.init_app(app)
40+
41+
@app.route("/")
42+
def home():
43+
all_users = dbmodels.User.query.all()
44+
celeryapp.set_current()
45+
asynctasks.hello_world.delay()
46+
return render_template('home.html', user_data = all_users)
47+
48+
@app.route("/about")
49+
def about():
50+
return render_template('about.html')
51+
52+
53+
@app.route('/login')
54+
def login_user():
55+
if not request.args.has_key('code'):
56+
return redirect('https://orcid.org/oauth/authorize?client_id={}&response_type=code&scope=/authenticate&redirect_uri={}&show_login=true'.format(
57+
ORCID_APPID,
58+
ORCID_REDIRECT_URI
59+
))
60+
61+
auth_code = request.args.get('code')
62+
data = {'client_id':ORCID_APPID,'client_secret':ORCID_SECRET,'grant_type':'authorization_code','code':auth_code}
63+
64+
r = requests.post('https://pub.orcid.org/oauth/token', data = data)
65+
login_details = json.loads(r.content)
66+
67+
user = User(orcid = login_details['orcid'], fullname = login_details['name'], authenticated = True)
68+
login.login_user(user)
69+
70+
return redirect(url_for('home'))
71+
72+
73+
@app.route("/logout")
74+
@login.login_required
75+
def logout():
76+
login.logout_user()
77+
return redirect('/')
78+
79+
@login_manager.user_loader
80+
def load_user(userid):
81+
r = requests.get('http://pub.orcid.org/v1.2/{}/orcid-profile'.format(userid), headers = {'Accept':'application/json'})
82+
login_bio = json.loads(r.content)['orcid-profile']['orcid-bio']
83+
return User(orcid = userid, fullname = '{} {}'.format(login_bio['personal-details']['given-names']['value'],login_bio['personal-details']['family-name']['value']))
84+
85+
@login_manager.unauthorized_handler
86+
def unauthorized():
87+
return redirect(url_for('login_user'))
88+
89+
@app.route("/profile")
90+
@login.login_required
91+
def profile():
92+
return render_template('profile.html')

recastfrontend/templates/about.html

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{% extends "base.html" %}
2+
3+
{% block container %}
4+
about...
5+
{% endblock %}

recastfrontend/templates/base.html

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<!-- jQuery -->
5+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
6+
7+
<!-- Latest compiled and minified CSS -->
8+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
9+
10+
<!-- Latest compiled and minified JavaScript -->
11+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
12+
13+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
14+
15+
</head>
16+
17+
<body>
18+
19+
20+
<header>
21+
<nav class="navbar navbar-default" role="navigation">
22+
<div class="container-fluid">
23+
<!-- Brand and toggle get grouped for better mobile display -->
24+
<div class="navbar-header">
25+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#recast-navigation" aria-expanded="false">
26+
<span class="sr-only">Toggle navigation</span>
27+
<span class="icon-bar"></span>
28+
<span class="icon-bar"></span>
29+
<span class="icon-bar"></span>
30+
</button>
31+
<a class="navbar-brand" href="/">RECAST</a>
32+
</div>
33+
34+
<!-- Collect the nav links, forms, and other content for toggling -->
35+
<div class="collapse navbar-collapse" id="recast-navigation">
36+
<ul class="nav navbar-nav">
37+
<li><a href="/">Home</a></li>
38+
<li><a href="/about">About</a></li>
39+
<li><a href="/">Analysis Catalogue</a></li>
40+
<li><a href="/">Recast Requests</a></li>
41+
</ul>
42+
<ul class="nav navbar-nav navbar-right">
43+
{% if current_user and not current_user.is_anonymous() %}
44+
<li><a href="{{url_for('profile')}}">{{current_user.name()}}</a></li>
45+
<li><a href="/logout">(Logout)</a></li>
46+
{% else %}
47+
<li><a href="/login">Login</a></li>
48+
{% endif %}
49+
</ul>
50+
</div><!-- /.navbar-collapse -->
51+
</div><!-- /.container-fluid -->
52+
</nav>
53+
</header>
54+
55+
<div class="container-fluid">
56+
{% block container %}
57+
{% endblock %}
58+
</div>
59+
60+
</body>
61+
</html>

recastfrontend/templates/home.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends "base.html" %}
2+
3+
{% block container %}
4+
5+
All Users
6+
<ul>
7+
{% for user in user_data %}
8+
<li>{{user.name}}: {{user.email}}</li>
9+
{% endfor %}
10+
</ul>
11+
12+
{% endblock %}

recastfrontend/templates/profile.html

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{% extends "base.html" %}
2+
3+
{% block container %}
4+
profile page for user: {{current_user.name()}}
5+
6+
<ul>
7+
<li>Basic User info from ORCID</li>
8+
<li>all my analysis subscriptions</li>
9+
<li>all my request subscriptions</li>
10+
</ul>
11+
{% endblock %}

setup.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from setuptools import setup, find_packages
2+
3+
setup(
4+
name = 'recast-newfrontend',
5+
description = 'new frontend for the RECAST project',
6+
url = 'https://github.com/lukasheinrich/recast-newfrontend',
7+
author = 'Lukas Heinrich',
8+
author_email = '[email protected]',
9+
packages=find_packages(),
10+
include_package_data = True,
11+
install_requires = [
12+
'Flask',
13+
'Flask-Login',
14+
'Flask-SQLAlchemy',
15+
'click',
16+
'pyyaml',
17+
'celery',
18+
'redis',
19+
'IPython'
20+
],
21+
entry_points = {
22+
'console_scripts': [
23+
'recast-frontend = recastfrontend.frontendcli:frontendcli',
24+
'recast-frontend-admin = recastfrontend.admincli:admincli',
25+
]
26+
},
27+
)

0 commit comments

Comments
 (0)