doneth.at/app/api.py

88 lines
2.4 KiB
Python

from pathlib import PosixPath
from flask import Blueprint, abort, render_template, redirect
from flask.helpers import url_for
from flask_login import current_user, login_required
from flask_restful import Api, Resource
from flask_wtf.form import FlaskForm
from wtforms.fields import SubmitField, StringField
from wtforms.validators import DataRequired, ValidationError
from .db import APIKey, db
blueprint = Blueprint('api', __name__)
api = Api()
def init_app(app):
api.init_app(app)
def colon_checker(form, field):
if ":" in field.data:
raise ValidationError('Field cannot contain colons')
class NewKeyForm(FlaskForm):
app_name = StringField('App name', validators=[
colon_checker, DataRequired()])
description = StringField('Description', validators=[
colon_checker, DataRequired()])
submit = SubmitField('Create')
@blueprint.route('/api/manage/keys', methods=['GET', 'POST'])
@login_required
def key_list():
apps = [a[0] for a in db.session.query(APIKey.app_name).filter(
APIKey.user == current_user).group_by(APIKey.app_name).all()]
keys = {app_name: APIKey.query.filter(
APIKey.user_id == current_user.id, APIKey.app_name == app_name).all() for app_name in apps}
form = NewKeyForm()
if form.validate_on_submit():
key = APIKey.create(current_user, form.app_name.data,
form.description.data)
return render_template('api/manage/key_list.html', form=NewKeyForm(), apps=sorted(apps), keys=keys, created_key=key)
return render_template('api/manage/key_list.html', form=form, apps=sorted(apps), keys=keys)
class DeleteForm(FlaskForm):
submit = SubmitField('Delete')
@blueprint.route('/api/manage/keys/<key_id>/delete', methods=['GET', 'POST'])
@login_required
def key_delete(key_id):
k = APIKey.query.get_or_404(key_id)
if k.user_id != current_user.id:
abort(403)
back_url = url_for('api.key_list')
form = DeleteForm()
if form.validate_on_submit():
db.session.delete(k)
db.session.commit()
return redirect(back_url)
return render_template('api/manage/key_delete.html', form=form, key=k, cancel=back_url)
def r(resource, endpoint: str): api.add_resource(
resource, str(PosixPath('/api/v1') / endpoint))
s = {'success': True}
def e(err): return {'success': False, 'error': err}
class Version(Resource):
def get(self):
return s | {'version': 'v1'}
r(Version, '')