| |
@@ -1,23 +1,17 @@
|
| |
- from __future__ import print_function, unicode_literals
|
| |
+ from __future__ import unicode_literals
|
| |
|
| |
import datetime
|
| |
- import functools
|
| |
import json
|
| |
import logging
|
| |
import os
|
| |
- import six
|
| |
- from six.moves.urllib import parse as urlparse
|
| |
|
| |
import flask
|
| |
import flask.json
|
| |
import munch
|
| |
|
| |
from flask.ext.oidc import OpenIDConnect
|
| |
- import requests
|
| |
|
| |
import hubs.models
|
| |
- import hubs.widgets
|
| |
- import hubs.stream
|
| |
|
| |
import datanommer.models
|
| |
|
| |
@@ -36,11 +30,6 @@
|
| |
|
| |
logging.basicConfig()
|
| |
|
| |
- # TODO - put this in config so we can migrate to pagure
|
| |
- # TODO - instead of 'develop', use the version from pkg_resources to figure out
|
| |
- # the right tag to link people to. AGPL ftw.
|
| |
- SOURCE_URL = 'https://pagure.io/fedora-hubs/blob/develop/f' # /hubs/widgets/badges.py'
|
| |
-
|
| |
app.config.from_object('hubs.default_config')
|
| |
if 'HUBS_CONFIG' in os.environ:
|
| |
app.config.from_envvar('HUBS_CONFIG')
|
| |
@@ -54,6 +43,10 @@
|
| |
session = hubs.models.init(fedmsg_config['hubs.sqlalchemy.uri'])
|
| |
datanommer.models.init(fedmsg_config['datanommer.sqlalchemy.uri'])
|
| |
|
| |
+ @app.before_request
|
| |
+ def store_db():
|
| |
+ flask.g.db = session
|
| |
+
|
| |
|
| |
class CustomJSONEncoder(flask.json.JSONEncoder):
|
| |
def default(self, o):
|
| |
@@ -69,24 +62,6 @@
|
| |
app.json_encoder = CustomJSONEncoder
|
| |
|
| |
|
| |
- def authenticated():
|
| |
- """ Utility function checking if the current auth is set or not."""
|
| |
- return hasattr(flask.g, 'auth') \
|
| |
- and flask.g.auth is not None \
|
| |
- and flask.g.auth.logged_in
|
| |
-
|
| |
-
|
| |
- def is_safe_url(target):
|
| |
- """ Checks that the target url is safe and sending to the current
|
| |
- website not some other malicious one.
|
| |
- """
|
| |
- ref_url = urlparse.urlparse(flask.request.host_url)
|
| |
- test_url = urlparse.urlparse(
|
| |
- urlparse.urljoin(flask.request.host_url, target))
|
| |
- return test_url.scheme in ('http', 'https') and \
|
| |
- ref_url.netloc == test_url.netloc
|
| |
-
|
| |
-
|
| |
@app.template_filter('commas')
|
| |
def commas(numeric):
|
| |
return "{:,.2f}".format(numeric)
|
| |
@@ -98,490 +73,10 @@
|
| |
session.remove()
|
| |
|
| |
|
| |
- @app.route('/')
|
| |
- def index():
|
| |
- if not authenticated():
|
| |
- return flask.redirect(flask.url_for('login'))
|
| |
-
|
| |
- return flask.redirect(flask.url_for('stream', name=flask.g.auth.nickname))
|
| |
-
|
| |
-
|
| |
- @app.route('/groups')
|
| |
- def groups():
|
| |
- if not authenticated():
|
| |
- return flask.redirect(flask.url_for('login'))
|
| |
-
|
| |
- # Get the list of promoted and non-promoted group hubs from the DB
|
| |
- promoted_names = app.config.get('PROMOTED_GROUPS')
|
| |
- groups = hubs.models.Hub.all_group_hubs(session)
|
| |
- promoted = [g for g in groups if g.name in promoted_names]
|
| |
- secondary = [g for g in groups if g.name not in promoted_names]
|
| |
-
|
| |
- name_of_the_month = app.config.get('HUB_OF_THE_MONTH')
|
| |
- hub_of_the_month = hubs.models.Hub.by_name(session, name_of_the_month)
|
| |
-
|
| |
- return flask.render_template(
|
| |
- 'groups.html',
|
| |
- promoted=promoted,
|
| |
- secondary=secondary,
|
| |
- hub_of_the_month=hub_of_the_month,
|
| |
- session=session,
|
| |
- )
|
| |
-
|
| |
-
|
| |
- @app.route('/<name>')
|
| |
- @app.route('/<name>/')
|
| |
- def hub(name):
|
| |
- hub = get_hub(session, name)
|
| |
- return flask.render_template(
|
| |
- 'hubs.html', hub=hub, session=session, edit=False)
|
| |
-
|
| |
-
|
| |
- @app.route('/<name>/json/')
|
| |
- @app.route('/<name>/json')
|
| |
- def hub_json(name):
|
| |
- hub = get_hub(session, name)
|
| |
- response = flask.jsonify(hub.__json__(session))
|
| |
- # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
|
| |
- return response
|
| |
-
|
| |
-
|
| |
- @app.route('/<name>/edit/', methods=['GET', 'POST'])
|
| |
- @app.route('/<name>/edit', methods=['GET', 'POST'])
|
| |
- def hub_edit(name):
|
| |
- if flask.request.method == 'POST':
|
| |
- return hub_edit_post(name)
|
| |
- else:
|
| |
- return hub_edit_get(name)
|
| |
-
|
| |
-
|
| |
- def hub_edit_get(name):
|
| |
- hub = get_hub(session, name)
|
| |
- return flask.render_template(
|
| |
- 'hubs.html', hub=hub, session=session, edit=True)
|
| |
-
|
| |
-
|
| |
- def hub_edit_post(name):
|
| |
- hub = get_hub(session, name)
|
| |
- is_js = flask.request.form.get('js', False)
|
| |
-
|
| |
- error = False
|
| |
-
|
| |
- # Check the input submitted
|
| |
- # Right side
|
| |
- r_widget_ids = [
|
| |
- w.strip().replace('widget-', '')
|
| |
- for w in flask.request.form.getlist('right_widgets[]')
|
| |
- if w.strip()
|
| |
- ]
|
| |
- try:
|
| |
- r_widget_ids = [int(w) for w in r_widget_ids]
|
| |
- except:
|
| |
- flask.flash('Invalid widget identifiers submitted', 'error')
|
| |
- error = True
|
| |
-
|
| |
- r_indexes = [
|
| |
- i.strip() for i in flask.request.form.getlist('right_indexes[]')
|
| |
- if i.strip()
|
| |
- ]
|
| |
-
|
| |
- try:
|
| |
- r_indexes = [int(i) for i in r_indexes]
|
| |
- except:
|
| |
- if not is_js:
|
| |
- flask.flash('Invalid indexes submitted', 'error')
|
| |
- error = True
|
| |
-
|
| |
- if len(r_widget_ids) != len(r_indexes):
|
| |
- if not is_js:
|
| |
- flask.flash(
|
| |
- 'The number of indexes and the number of widgets are not of '
|
| |
- 'the same length', 'error')
|
| |
- error = True
|
| |
-
|
| |
- # Left side
|
| |
- l_widget_ids = [
|
| |
- w.strip().replace('widget-', '')
|
| |
- for w in flask.request.form.getlist('left_widgets[]')
|
| |
- if w.strip()
|
| |
- ]
|
| |
- try:
|
| |
- l_widget_ids = [int(w) for w in l_widget_ids]
|
| |
- except:
|
| |
- flask.flash('Invalid widget identifiers submitted', 'error')
|
| |
- error = True
|
| |
-
|
| |
- l_indexes = [
|
| |
- i.strip() for i in flask.request.form.getlist('left_indexes[]')
|
| |
- if i.strip()
|
| |
- ]
|
| |
-
|
| |
- try:
|
| |
- l_indexes = [int(i) for i in l_indexes]
|
| |
- except:
|
| |
- if not is_js:
|
| |
- flask.flash('Invalid indexes submitted', 'error')
|
| |
- error = True
|
| |
-
|
| |
- if len(l_widget_ids) != len(l_indexes):
|
| |
- if not is_js:
|
| |
- flask.flash(
|
| |
- 'The number of indexes and the number of widgets are not of '
|
| |
- 'the same length', 'error')
|
| |
- error = True
|
| |
-
|
| |
- # If all good, update the database
|
| |
- if not error:
|
| |
- for cnt, wid in enumerate(r_widget_ids):
|
| |
- widget = hubs.models.Widget.get(session, wid)
|
| |
- if widget.index != r_indexes[cnt]:
|
| |
- widget.index = r_indexes[cnt]
|
| |
- session.add(widget)
|
| |
- for cnt, wid in enumerate(l_widget_ids):
|
| |
- widget = hubs.models.Widget.get(session, wid)
|
| |
- if widget.index != l_indexes[cnt]:
|
| |
- widget.index = l_indexes[cnt]
|
| |
- session.add(widget)
|
| |
- hub.last_edited = datetime.datetime.utcnow()
|
| |
- session.add(hub)
|
| |
- try:
|
| |
- session.commit()
|
| |
- except Exception as err:
|
| |
- error = True
|
| |
- if not is_js:
|
| |
- flask.flash(
|
| |
- 'Could not save your changes to the database '
|
| |
- 'if the error persists, please warn an admin',
|
| |
- 'error')
|
| |
- if is_js:
|
| |
- if error:
|
| |
- flask.abort(400)
|
| |
- else:
|
| |
- return ('ok', 200)
|
| |
- else:
|
| |
- return flask.redirect(flask.url_for('hub', name=name))
|
| |
-
|
| |
-
|
| |
- @app.route('/<name>/add/', methods=['GET', 'POST'])
|
| |
- @app.route('/<name>/add', methods=['GET', 'POST'])
|
| |
- def hub_add_widgets(name):
|
| |
- if flask.request.method == 'POST':
|
| |
- return hub_add_widget_post(name)
|
| |
- else:
|
| |
- return hub_add_widget_get(name)
|
| |
-
|
| |
-
|
| |
- @app.route('/<name>/add/<widget_name>/', methods=['GET'])
|
| |
- @app.route('/<name>/add/<widget_name>', methods=['GET'])
|
| |
- def hub_add_widget(name, widget_name):
|
| |
- hub = get_hub(session, name)
|
| |
- side = str(flask.request.args.get('position')).lower()
|
| |
- if side not in ['right', 'left']:
|
| |
- flask.abort(400, 'Invalid position provided')
|
| |
-
|
| |
- widget = None
|
| |
- w_name = None
|
| |
- for widgt in hubs.widgets.registry:
|
| |
- if hubs.widgets.registry[widgt].position in ['both', side] \
|
| |
- and widgt == widget_name:
|
| |
- w_name = widgt
|
| |
- widget = hubs.widgets.registry[widgt]
|
| |
-
|
| |
- return flask.render_template(
|
| |
- 'add_widget.html',
|
| |
- hub=hub,
|
| |
- widget=widget,
|
| |
- widget_name=w_name,
|
| |
- side=side,
|
| |
- url_to=flask.url_for('hub_add_widgets', name=name),
|
| |
- )
|
| |
-
|
| |
-
|
| |
- def hub_add_widget_get(name):
|
| |
- hub = get_hub(session, name)
|
| |
- side = str(flask.request.args.get('position')).lower()
|
| |
- if side not in ['right', 'left']:
|
| |
- flask.abort(400, 'Invalid position provided')
|
| |
-
|
| |
- widgets = [
|
| |
- widget
|
| |
- for widget in hubs.widgets.registry
|
| |
- if hubs.widgets.registry[widget].position in ['both', side]
|
| |
- ]
|
| |
- return flask.render_template(
|
| |
- 'add_widget.html',
|
| |
- hub=hub,
|
| |
- widgets=widgets,
|
| |
- side=side,
|
| |
- )
|
| |
-
|
| |
-
|
| |
- def hub_add_widget_post(name):
|
| |
- widget_name = flask.request.form.get('widget_name')
|
| |
- position = flask.request.form.get('position', '').lower()
|
| |
- if not widget_name:
|
| |
- flask.abort(400, 'Invalid request sent')
|
| |
- if widget_name not in hubs.widgets.registry:
|
| |
- flask.abort(404, 'Unknown widget called')
|
| |
-
|
| |
- hub = get_hub(session, name)
|
| |
-
|
| |
- widget = widget = hubs.models.Widget(
|
| |
- plugin=widget_name, index=-1, left=position == 'left')
|
| |
- error = False
|
| |
- config = {}
|
| |
- for arg in widget.module.data.widget_arguments:
|
| |
- val = flask.request.form.get(arg.name)
|
| |
- if not val:
|
| |
- flask.flash(
|
| |
- 'You must provide a value for: %s' % arg.name, 'error')
|
| |
- error = True
|
| |
- break
|
| |
- try:
|
| |
- arg.validator(session, val)
|
| |
- config[arg.name] = val
|
| |
- except Exception as err:
|
| |
- flask.flash('Invalid data provided, error: %s' % err, 'error')
|
| |
- error = True
|
| |
- if not error:
|
| |
- widget.hub = hub
|
| |
- widget.config = config
|
| |
- try:
|
| |
- session.add(widget)
|
| |
- session.flush()
|
| |
- widget.hub.last_edited = datetime.datetime.utcnow()
|
| |
- session.commit()
|
| |
- except Exception as err:
|
| |
- print(err)
|
| |
- flask.flash(
|
| |
- 'Could not save the configuration to the database '
|
| |
- 'if the error persists, please warn an admin',
|
| |
- 'error')
|
| |
-
|
| |
- return flask.render_template(
|
| |
- 'hubs.html', hub=hub, session=session, edit=True)
|
| |
-
|
| |
-
|
| |
- @app.route('/<hub>/<int:idx>/')
|
| |
- @app.route('/<hub>/<int:idx>')
|
| |
- def widget_render(hub, idx):
|
| |
- widget = get_widget(session, hub, idx)
|
| |
- return widget.render(session) # , edit=False)
|
| |
- # was blocking all widgets from working, sorry!
|
| |
-
|
| |
-
|
| |
- @app.route('/<hub>/<int:idx>/json')
|
| |
- @app.route('/<hub>/<int:idx>/json/')
|
| |
- def widget_json(hub, idx):
|
| |
- widget = get_widget(session, hub, idx)
|
| |
- response = flask.jsonify(widget.__json__(session))
|
| |
- # TODO -- modify headers with response.headers['X-fedora-hubs-wat'] = 'foo'
|
| |
- return response
|
| |
-
|
| |
-
|
| |
- @app.route('/<hub>/<int:idx>/edit/', methods=['GET', 'POST'])
|
| |
- @app.route('/<hub>/<int:idx>/edit', methods=['GET', 'POST'])
|
| |
- def widget_edit(hub, idx):
|
| |
- if flask.request.method == 'POST':
|
| |
- return widget_edit_post(hub, idx)
|
| |
- else:
|
| |
- return widget_edit_get(hub, idx)
|
| |
-
|
| |
-
|
| |
- def widget_edit_get(hub, idx):
|
| |
- widget = get_widget(session, hub, idx)
|
| |
- return flask.render_template(
|
| |
- 'edit.html',
|
| |
- hub=hub,
|
| |
- widget=widget,
|
| |
- url_to=flask.url_for('widget_edit', hub=hub, idx=idx)
|
| |
- )
|
| |
-
|
| |
-
|
| |
- def widget_edit_post(hub, idx):
|
| |
- widget = get_widget(session, hub, idx)
|
| |
- error = False
|
| |
- config = {}
|
| |
- for arg in widget.module.data.widget_arguments:
|
| |
- val = flask.request.form.get(arg.name)
|
| |
- if not val:
|
| |
- flask.flash(
|
| |
- 'You must provide a value for: %s' % arg.name, 'error')
|
| |
- error = True
|
| |
- break
|
| |
- try:
|
| |
- val = arg.validator(session, val)
|
| |
- config[arg.name] = val
|
| |
- except Exception as err:
|
| |
- flask.flash('Invalid data provided, error: %s' % err, 'error')
|
| |
- error = True
|
| |
- if not error:
|
| |
- cur_config = widget.config
|
| |
- cur_config.update(config)
|
| |
- widget.config = cur_config
|
| |
- widget.hub.last_edited = datetime.datetime.utcnow()
|
| |
- session.add(widget)
|
| |
- try:
|
| |
- session.commit()
|
| |
- except Exception as err:
|
| |
- flask.flash(
|
| |
- 'Could not save the configuration to the database '
|
| |
- 'if the error persists, please warn an admin',
|
| |
- 'error')
|
| |
- return flask.redirect(flask.url_for('hub', name=hub))
|
| |
-
|
| |
-
|
| |
- @app.route('/<hub>/<int:idx>/delete/', methods=['POST'])
|
| |
- @app.route('/<hub>/<int:idx>/delete', methods=['POST'])
|
| |
- def widget_edit_delete(hub, idx):
|
| |
- ''' Remove a widget from a hub. '''
|
| |
- widget = get_widget(session, hub, idx)
|
| |
- session.delete(widget)
|
| |
- try:
|
| |
- session.commit()
|
| |
- except Exception as err:
|
| |
- flask.flash(
|
| |
- 'Could not delete this widget from this hub in the database '
|
| |
- 'if the error persists, please warn an admin',
|
| |
- 'error')
|
| |
- return flask.redirect(flask.url_for('hub_edit', name=hub))
|
| |
-
|
| |
-
|
| |
- @app.route('/source/<name>/')
|
| |
- @app.route('/source/<name>')
|
| |
- def widget_source(name):
|
| |
- from hubs.widgets import registry
|
| |
- base = '/hubs/'
|
| |
- fname = ''
|
| |
-
|
| |
- try:
|
| |
- fname = base + registry[name].__file__.split(base)[-1]
|
| |
- except KeyError:
|
| |
- flask.abort(404)
|
| |
-
|
| |
- fname = fname.replace('.pyc', '.py')
|
| |
- return flask.redirect(SOURCE_URL + fname)
|
| |
-
|
| |
-
|
| |
# Set up OpenIDConnect
|
| |
OIDC = OpenIDConnect(app, credentials_store=flask.session )
|
| |
|
| |
|
| |
- @app.route('/login/', methods=('GET', 'POST'))
|
| |
- @app.route('/login', methods=('GET', 'POST'))
|
| |
- @OIDC.require_login
|
| |
- def login():
|
| |
- default = flask.url_for('index')
|
| |
- next_url = flask.request.args.get('next', default)
|
| |
- if is_safe_url(next_url):
|
| |
- return_point = next_url
|
| |
- else:
|
| |
- return_point = default
|
| |
-
|
| |
- hubs.models.User.get_or_create(
|
| |
- session, username=flask.g.auth.nickname, fullname=flask.g.auth.fullname)
|
| |
-
|
| |
- return flask.redirect(return_point)
|
| |
-
|
| |
-
|
| |
- @app.route('/logout/')
|
| |
- @app.route('/logout')
|
| |
- def logout():
|
| |
- next_url = flask.url_for('index')
|
| |
- if 'next' in flask.request.values: # pragma: no cover
|
| |
- if is_safe_url(flask.request.args['next']):
|
| |
- next_url = flask.request.values['next']
|
| |
-
|
| |
- if next_url == flask.url_for('login'): # pragma: no cover
|
| |
- next_url = flask.url_for('index')
|
| |
-
|
| |
- if authenticated():
|
| |
- OIDC.logout()
|
| |
- flask.session.auth = None
|
| |
- flask.flash('You have been logged out')
|
| |
-
|
| |
- return flask.redirect(next_url)
|
| |
-
|
| |
-
|
| |
- def login_required(function):
|
| |
- """ Flask decorator to restrict access to logged-in users. """
|
| |
-
|
| |
- @functools.wraps(function)
|
| |
- def decorated_function(*args, **kwargs):
|
| |
- """ Decorated function, actually does the work. """
|
| |
- if not authenticated():
|
| |
- flask.flash('Login required', 'errors')
|
| |
- return flask.redirect(flask.url_for(
|
| |
- 'login', next=flask.request.url))
|
| |
-
|
| |
- return function(*args, **kwargs)
|
| |
-
|
| |
- return decorated_function
|
| |
-
|
| |
- @app.route('/<name>/stream')
|
| |
- @app.route('/<name>/stream/')
|
| |
- @login_required
|
| |
- def stream(name):
|
| |
- hub = get_hub(session, name)
|
| |
- saved = hubs.models.SavedNotification.by_username(session, name)
|
| |
- saved = [n.__json__() for n in saved]
|
| |
-
|
| |
- stream = hubs.stream.Stream()
|
| |
- actions = stream.get_json()
|
| |
-
|
| |
- return flask.render_template(
|
| |
- 'stream.html',
|
| |
- hub=hub,
|
| |
- saved=json.dumps(saved),
|
| |
- actions=actions
|
| |
- )
|
| |
-
|
| |
-
|
| |
- @app.route('/<user>/notifications', methods=['GET', 'POST'])
|
| |
- @app.route('/<user>/notifications/', methods=['GET', 'POST'])
|
| |
- @login_required
|
| |
- def notifications(user):
|
| |
- if flask.request.method == 'GET':
|
| |
- notifications = hubs.models.SavedNotification.by_username(session, user)
|
| |
- notifications = [n.__json__() for n in notifications]
|
| |
- return flask.jsonify(notifications)
|
| |
-
|
| |
- if flask.request.method == 'POST':
|
| |
- data = flask.request.get_json()
|
| |
- user = hubs.models.User.by_username(session, user)
|
| |
- if not user:
|
| |
- return flask.abort(400)
|
| |
- try:
|
| |
- markup = data['markup']
|
| |
- link = data['link']
|
| |
- icon = data['secondary_icon']
|
| |
- dom_id = data['dom_id']
|
| |
- except:
|
| |
- return flask.abort(400)
|
| |
- notification = hubs.models.SavedNotification(
|
| |
- username=user.username,
|
| |
- markup=markup,
|
| |
- link=link,
|
| |
- secondary_icon=icon,
|
| |
- dom_id=dom_id
|
| |
- )
|
| |
- session.add(notification)
|
| |
- session.commit()
|
| |
- return flask.jsonify(
|
| |
- dict(notification=notification.__json__(), success=True)
|
| |
- )
|
| |
-
|
| |
- @app.route('/<user>/notifications/<int:idx>', methods=['DELETE'])
|
| |
- @app.route('/<user>/notifications/<int:idx>/', methods=['DELETE'])
|
| |
- @login_required
|
| |
- def delete_notifications(user, idx):
|
| |
- notification = session.query(hubs.models.SavedNotification).filter_by(idx=idx).first()
|
| |
- if not notification:
|
| |
- return flask.abort(400)
|
| |
- session.delete(notification)
|
| |
- session.commit()
|
| |
- return flask.jsonify(dict(status_code=200))
|
| |
-
|
| |
@app.before_request
|
| |
def check_auth():
|
| |
flask.session.permanent = True
|
| |
@@ -610,223 +105,4 @@
|
| |
flask.g.auth = munch.Munch(logged_in=False)
|
| |
|
| |
|
| |
- def get_hub(session, name):
|
| |
- """ Utility shorthand to get a hub and 404 if not found. """
|
| |
- hub = session.query(hubs.models.Hub) \
|
| |
- .filter(hubs.models.Hub.name == name) \
|
| |
- .first()
|
| |
-
|
| |
- if not hub:
|
| |
- flask.abort(404)
|
| |
-
|
| |
- return hub
|
| |
-
|
| |
-
|
| |
- @app.route('/visit/<visited_hub>/', methods=['GET', 'POST'])
|
| |
- @app.route('/visit/<visited_hub>', methods=['GET', 'POST'])
|
| |
- @login_required
|
| |
- def increment_counter(visited_hub):
|
| |
- nickname = flask.g.auth.nickname
|
| |
-
|
| |
- if str(visited_hub) != str(nickname):
|
| |
- try:
|
| |
- vc = hubs.models.VisitCounter.get_or_create(session=session,
|
| |
- username=nickname,
|
| |
- visited_hub=visited_hub)
|
| |
- except ValueError: # this should never trip
|
| |
- # flask will 405 if visited_hub is blank
|
| |
- # @login_required forces flask.g.auth to be sets
|
| |
- flask.abort(404)
|
| |
- if flask.request.method == 'POST':
|
| |
- vc.increment_visits(session=session,
|
| |
- username=nickname,
|
| |
- visited_hub=visited_hub)
|
| |
-
|
| |
- return flask.jsonify({'count': vc.count})
|
| |
-
|
| |
- elif flask.request.method == 'GET':
|
| |
- return flask.jsonify({'count': vc.count})
|
| |
- else:
|
| |
- return flask.abort(403)
|
| |
-
|
| |
-
|
| |
- def get_widget(session, hub, idx):
|
| |
- """ Utility shorthand to get a widget and 404 if not found. """
|
| |
- try:
|
| |
- idx = int(idx)
|
| |
- except (TypeError, ValueError):
|
| |
- flask.abort(404)
|
| |
-
|
| |
- hub = get_hub(session, hub)
|
| |
-
|
| |
- for widget in hub.widgets:
|
| |
- if widget.idx == idx:
|
| |
- return widget
|
| |
-
|
| |
- flask.abort(404)
|
| |
-
|
| |
-
|
| |
- # Here are a bunch of API methods that should probably be broken out into
|
| |
- # their own file
|
| |
- @app.route('/api/hub/<hub>/subscribe', methods=['POST'])
|
| |
- @login_required
|
| |
- def hub_subscribe(hub):
|
| |
- hub = get_hub(session, hub)
|
| |
- user = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- hub.subscribe(session, user)
|
| |
- session.commit()
|
| |
- return flask.redirect(flask.url_for('hub', name=hub.name))
|
| |
-
|
| |
-
|
| |
- @app.route('/api/hub/<hub>/unsubscribe', methods=['POST'])
|
| |
- @login_required
|
| |
- def hub_unsubscribe(hub):
|
| |
- hub = get_hub(session, hub)
|
| |
- user = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- try:
|
| |
- hub.unsubscribe(session, user)
|
| |
- except KeyError:
|
| |
- return flask.abort(400)
|
| |
- session.commit()
|
| |
- return flask.redirect(flask.url_for('hub', name=hub.name))
|
| |
-
|
| |
-
|
| |
- @app.route('/api/hub/<hub>/star', methods=['POST'])
|
| |
- @login_required
|
| |
- def hub_star(hub):
|
| |
- hub = get_hub(session, hub)
|
| |
- user = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- hub.subscribe(session, user, role='stargazer')
|
| |
- session.commit()
|
| |
- return flask.redirect(flask.url_for('hub', name=hub.name))
|
| |
-
|
| |
-
|
| |
- @app.route('/api/hub/<hub>/unstar', methods=['POST'])
|
| |
- @login_required
|
| |
- def hub_unstar(hub):
|
| |
- hub = get_hub(session, hub)
|
| |
- user = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- try:
|
| |
- hub.unsubscribe(session, user, role='stargazer')
|
| |
- except KeyError:
|
| |
- return flask.abort(400)
|
| |
- session.commit()
|
| |
- return flask.redirect(flask.url_for('hub', name=hub.name))
|
| |
-
|
| |
-
|
| |
- @app.route('/api/hub/<hub>/join', methods=['POST'])
|
| |
- @login_required
|
| |
- def hub_join(hub):
|
| |
- hub = get_hub(session, hub)
|
| |
- user = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- hub.subscribe(session, user, role='member')
|
| |
- session.commit()
|
| |
- return flask.redirect(flask.url_for('hub', name=hub.name))
|
| |
-
|
| |
-
|
| |
- @app.route('/api/hub/<hub>/leave', methods=['POST'])
|
| |
- @login_required
|
| |
- def hub_leave(hub):
|
| |
- hub = get_hub(session, hub)
|
| |
- user = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- try:
|
| |
- hub.unsubscribe(session, user, role='member')
|
| |
- except KeyError:
|
| |
- return flask.abort(400)
|
| |
- session.commit()
|
| |
- return flask.redirect(flask.url_for('hub', name=hub.name))
|
| |
-
|
| |
-
|
| |
- @app.route('/plus_plus/<user>/status', methods=['GET'])
|
| |
- def plus_plus_status(user):
|
| |
- receiver = hubs.models.User.by_username(session, user)
|
| |
- if not receiver:
|
| |
- return 'User does not exist', 403
|
| |
- pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
|
| |
- req = None
|
| |
- try:
|
| |
- req = requests.get(pp_url)
|
| |
- except:
|
| |
- flask.abort(500)
|
| |
- if req.status_code == 200:
|
| |
- return flask.jsonify(req.json())
|
| |
- else:
|
| |
- return req.text, req.status_code
|
| |
-
|
| |
-
|
| |
- def plus_plus_update_bool_helper(val):
|
| |
- if isinstance(val, bool):
|
| |
- return val
|
| |
- elif isinstance(val, six.string_types):
|
| |
- fmt_str = str(val).replace("'", "").replace('"', '').lower()
|
| |
- return fmt_str in ("yes", "true", "t", "1")
|
| |
- else:
|
| |
- raise ValueError
|
| |
-
|
| |
-
|
| |
- @app.route('/plus_plus/<user>/update', methods=['POST'])
|
| |
- @login_required
|
| |
- def plus_plus_update(user):
|
| |
- receiver = hubs.models.User.by_username(session, user)
|
| |
-
|
| |
- if not receiver:
|
| |
- return 'User does not exist', 403
|
| |
-
|
| |
- if user == flask.g.auth.nickname:
|
| |
- return 'You may not modify your own karma.', 403
|
| |
-
|
| |
- if 'decrement' not in flask.request.form \
|
| |
- and 'increment' not in flask.request.form:
|
| |
- return "You must set 'decrement' or 'increment' " \
|
| |
- "with a boolean value in the body", 403
|
| |
-
|
| |
- update = 'increment' if 'increment' in flask.request.form else 'decrement'
|
| |
-
|
| |
- update_bool_val = plus_plus_update_bool_helper(flask.request.form[update])
|
| |
- pp_url = app.config['PLUS_PLUS_URL'] + str(receiver.username)
|
| |
- sender = hubs.models.User.by_username(session, flask.g.auth.nickname)
|
| |
- pp_token = app.config['PLUS_PLUS_TOKEN']
|
| |
- auth_header = {'Authorization': 'token {}'.format(pp_token)}
|
| |
- data = {'sender': sender.username, update: update_bool_val}
|
| |
- req = None
|
| |
- try:
|
| |
- req = requests.post(url=pp_url, headers=auth_header, data=data)
|
| |
- except:
|
| |
- flask.abort(500)
|
| |
-
|
| |
- if req.status_code == 200:
|
| |
- return flask.jsonify(req.json())
|
| |
- else:
|
| |
- return req.text, req.status_code
|
| |
-
|
| |
-
|
| |
- #
|
| |
- # Add widget-specific routes
|
| |
- #
|
| |
-
|
| |
- def _widget_view_decorator(func):
|
| |
- """
|
| |
- This internal decorator will edit the view function arguments.
|
| |
-
|
| |
- It will:
|
| |
- - remove the hub name and the widget primary key
|
| |
- - add the database session and the widget instance
|
| |
- """
|
| |
- @functools.wraps(func)
|
| |
- def inner(*args, **kwargs):
|
| |
- hubname = kwargs.pop("hub")
|
| |
- widgetidx = kwargs.pop("idx")
|
| |
- widget = get_widget(session, hubname, widgetidx)
|
| |
- return func(session, widget, *args, **kwargs)
|
| |
- return inner
|
| |
-
|
| |
- for widget in session.query(hubs.models.Widget):
|
| |
- for params in getattr(widget.module, 'ROUTES', []):
|
| |
- params["rule"] = "/<hub>/<int:idx>/widget/" \
|
| |
- + params["rule"].lstrip("/")
|
| |
- if not params.get("endpoint"):
|
| |
- params["endpoint"] = params["view_func_name"]
|
| |
- params["endpoint"] = "%s_%s" % (widget.plugin, params["endpoint"])
|
| |
- params["view_func"] = _widget_view_decorator(
|
| |
- getattr(widget.module, params.pop("view_func_name")))
|
| |
- app.add_url_rule(**params)
|
| |
+ import hubs.views
|
| |
Fixes #305