authenticate first, ask for micropub authorization later

This commit is contained in:
Kyle Mahan 2015-02-07 12:25:03 -08:00
parent 254b0ac5b6
commit c70f527ec7
11 changed files with 215 additions and 62 deletions

View file

@ -1,18 +1 @@
Flask==0.10.1
Flask-Login==0.2.11
Flask_Micropub==0.1.4
Flask-SQLAlchemy==2.0
Jinja2==2.7.3
MarkupSafe==0.23
SQLAlchemy==0.9.8
Werkzeug==0.9.6
beautifulsoup4==4.3.2
bleach==1.4.1
celery==3.1.17
feedparser==5.1.3
html5lib==0.999
itsdangerous==0.24
-e git+git@github.com:kylewm/mf2py.git#egg=mf2py
mf2util==0.1.4
redis==2.10.3
requests==2.5.1
-e .

15
setup.py Normal file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env python
from distutils.core import setup
setup(name='Woodwind',
version='1.0.0',
description='Stream-style indieweb reader',
author='Kyle Mahan',
author_email='kyle@kylewm.com',
url='https://indiewebcamp.com/Woodwind',
packages=['woodwind'],
install_requires=[
'Flask', 'Flask-Login', 'Flask-Micropub', 'Flask-SQLAlchemy',
'beautifulsoup4', 'bleach', 'celery', 'feedparser', 'html5lib',
'mf2py', 'mf2util', 'redis', 'requests'])

View file

@ -12,7 +12,6 @@ bleach.ALLOWED_ATTRIBUTES.update({
})
users_to_feeds = db.Table(
'users_to_feeds', db.Model.metadata,
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), index=True),
@ -21,6 +20,7 @@ users_to_feeds = db.Table(
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
url = db.Column(db.String(256))
domain = db.Column(db.String(256))
micropub_endpoint = db.Column(db.String(512))
access_token = db.Column(db.String(512))

View file

@ -369,6 +369,15 @@ header, main {
header {
margin-bottom: 1em; }
ul#navigation {
list-style-type: none;
margin: 0;
padding: 0;
float: right; }
ul#navigation li {
display: inline-block;
padding: 3px; }
.pager {
text-align: center;
margin: 1em 0; }
@ -404,8 +413,19 @@ article {
font-size: 1.2em;
font-weight: bold; }
form textarea {
width: 90%; }
label {
font-weight: bold;
display: block; }
textarea, input[type="text"], input[type="url"] {
width: 100%;
margin: 0.25em 0; }
button {
padding: 0.25em; }
form {
margin: 1em 0; }
@media only screen and (max-width: 800px) {
article header img {

View file

@ -1,6 +1,6 @@
{
"version": 3,
"mappings": "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",
"mappings": "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",
"sources": ["normalize.scss","style.scss"],
"names": [],
"file": "style.css"

View file

@ -30,6 +30,18 @@ header {
margin-bottom: 1em;
}
ul#navigation {
list-style-type: none;
margin: 0;
padding: 0;
float: right;
li {
display: inline-block;
padding: 3px;
}
}
.pager {
text-align: center;
margin: 1em 0;
@ -44,7 +56,6 @@ header {
}
}
article {
margin-bottom: 2em;
box-shadow: $box-shadow;
@ -79,10 +90,22 @@ article {
}
}
label {
font-weight: bold;
display: block;
}
textarea, input[type="text"], input[type="url"] {
width: 100%;
margin: 0.25em 0 ;
}
button {
padding: 0.25em;
}
form {
textarea {
width: 90%;
}
margin: 1em 0;
}
@media only screen and (max-width: 800px) {

View file

@ -5,23 +5,38 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Woodwind</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"/>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
{% block head %}{% endblock %}
</head>
<body>
<header>
<h1 class="h-x-app">Woodwind</h1>
{% if current_user.is_authenticated() %}
<div class="logged-in">{{ current_user.domain }}
<ul id="navigation">
<li>
<a href="{{ url_for('.index') }}">Home</a>
</li>
<li>
<a href="{{ url_for('.feeds') }}">Feeds</a>
</li>
<li>
<a href="{{ url_for('.settings') }}">Settings</a>
</li>
<li>
{{ current_user.domain }}
(<a href="{{ url_for('.logout') }}">Logout</a>)
</div>
</li>
</ul>
<h1 class="h-x-app">Woodwind</h1>
{% else %}
<form action="{{ url_for('.login') }}" method="GET">
<h1 class="h-x-app">Woodwind</h1>
<form action="{{ url_for('.login') }}" method="POST">
<input type="text" name="me" placeholder="mydomain.com" />
<input type="hidden" name="next" placeholder="{{ request.path }}" />
<button type="submit">Login</button>
</form>
{% endif %}
{% block header %}{% endblock %}
{% for message in get_flashed_messages() %}
<div class="flash">{{ message | safe }}</div>

View file

@ -1,14 +1,12 @@
{% extends "base.jinja2" %}
{% block head %}
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="{{url_for('static', filename='feed.js')}}"></script>
{% endblock head %}
{% block header %}
{% if current_user.is_authenticated() %}
<form action="{{ url_for('.subscribe') }}" method="POST">
<input type="url" id="origin" name="origin" placeholder="Feed URL" />
<button type="submit" id="subscribe">Subscribe</button>
<input type="url" id="origin" name="origin" placeholder="Subscribe to URL" />
</form>
{% endif %}
{% endblock header %}

View file

@ -1,14 +1,24 @@
{% extends "base.jinja2" %}
{% block header %}
{% if current_user.is_authenticated() %}
<form action="{{ url_for('.subscribe') }}" method="POST">
<input type="url" id="origin" name="origin" placeholder="Subscribe to URL" />
</form>
{% endif %}
{% endblock header %}
{% block body %}
{% for feed in feeds %}
<div>
<article>
<form style="display:inline"
action="{{ url_for('.edit_feed') }}" method="POST">
<input type="hidden" name="id" value="{{ feed.id }}"/>
<input type="text" name="name" style="width:25%" value="{{ feed.name }}"/>
<input type="text" name="feed" style="width:25%" value="{{ feed.feed }}"/>
<label>Name</label>
<input type="text" name="name" value="{{ feed.name }}"/>
<label>URL</label>
<input type="text" name="feed" value="{{ feed.feed }}"/>
<button type="submit">Save</button>
</form>
<form style="display:inline;"
@ -21,8 +31,7 @@
<input type="hidden" name="id" value="{{ feed.id }}"/>
<button type="submit">Delete</button>
</form>
</div>
</article>
{% endfor %}
{% endblock body %}

View file

@ -0,0 +1,46 @@
{% extends "base.jinja2" %}
{% block body %}
<main>
<!-- reply via micropub -->
{% if current_user.micropub_endpoint or current_user.access_token %}
<form>
<label>Micropub Endpoint</label>
<input type="text" value="{{ current_user.micropub_endpoint }}" readonly />
<label>Access Token</label>
<input type="text" value="{{ current_user.access_token }}" readonly />
</form>
<form action="{{ url_for('.authorize') }}" method="POST">
<button type="submit">
Reauthorize Micropub
</button>
<input type="hidden" name="next" value="{{ request.path }}" />
</form>
<form action="{{ url_for('.deauthorize') }}" method="POST">
<button type="submit">Revoke Credentials</button>
<input type="hidden" name="next" value="{{ request.path }}" />
</form>
{% else %}
<form action="{{ url_for('.authorize') }}" method="POST">
<button type="submit">
Authorize Micropub
</button>
<input type="hidden" name="next" value="{{ request.path }}" />
</form>
{% endif %}
<!-- reply via indie-config -->
<!-- configure endpoints manually -->
</main>
{% endblock body %}

View file

@ -36,9 +36,17 @@ def install():
@views.route('/feeds')
@flask_login.login_required
def feeds():
feeds = flask_login.current_user.feeds
return flask.render_template('feeds.jinja2', feeds=feeds)
sorted_feeds = sorted(feeds, key=lambda f: f.name and f.name.lower())
return flask.render_template('feeds.jinja2', feeds=sorted_feeds)
@views.route('/settings')
@flask_login.login_required
def settings():
return flask.render_template('settings.jinja2')
@views.route('/update_feed')
@ -81,19 +89,17 @@ def logout():
return flask.redirect(flask.url_for('.index'))
@views.route('/login')
@views.route('/login', methods=['GET', 'POST'])
def login():
me = flask.request.args.get('me')
if me:
return micropub.authorize(
me, flask.url_for('.login_callback', _external=True),
next_url=flask.request.args.get('next'),
scope='post')
if flask.request.method == 'POST':
return micropub.authenticate(
flask.request.form.get('me'),
next_url=flask.request.form.get('next'))
return flask.render_template('login.jinja2')
@views.route('/login-callback')
@micropub.authorized_handler
@micropub.authenticated_handler
def login_callback(resp):
if not resp.me:
flask.flash(cgi.escape('Login error: ' + resp.error))
@ -109,14 +115,50 @@ def login_callback(resp):
user.domain = domain
db.session.add(user)
user.url = resp.me
db.session.commit()
flask_login.login_user(user, remember=True)
return flask.redirect(resp.next_url or flask.url_for('.index'))
@views.route('/authorize', methods=['POST'])
@flask_login.login_required
def authorize():
return micropub.authorize(
me=flask_login.current_user.url,
next_url=flask.request.form.get('next'),
scope='post')
@views.route('/micropub-callback')
@micropub.authorized_handler
def micropub_callback(resp):
if not resp.me or resp.error:
flask.flash(cgi.escape('Authorize error: ' + resp.error))
return flask.redirect(flask.url_for('.login'))
domain = urllib.parse.urlparse(resp.me).netloc
user = load_user(domain)
if not user:
flask.flash(cgi.escape('Unknown user for domain: ' + domain))
return flask.redirect(flask.url_for('.login'))
user.micropub_endpoint = resp.micropub_endpoint
user.access_token = resp.access_token
db.session.commit()
flask_login.login_user(user, remember=True)
return flask.redirect(resp.next_url or flask.url_for('.index'))
@views.route('/deauthorize', methods=['POST'])
@flask_login.login_required
def deauthorize():
flask_login.current_user.micropub_endpoint = None
flask_login.current_user.access_token = None
db.session.commit()
return flask.redirect(flask.request.form.get('next')
or flask.url_for('.index'))
@login_mgr.user_loader
def load_user(domain):
return User.query.filter_by(domain=domain).first()
@ -156,7 +198,8 @@ def add_subscription(origin, feed_url, type):
if not feed:
if type == 'html':
flask.current_app.logger.debug('mf2py parsing %s', feed_url)
parsed = mf2util.interpret_feed(mf2py.parse(url=feed_url), feed_url)
parsed = mf2util.interpret_feed(
mf2py.Parse(url=feed_url).to_dict(), feed_url)
name = parsed.get('name')
if not name or len(name) > 140:
p = urllib.parse.urlparse(origin)
@ -215,7 +258,8 @@ def find_possible_feeds(origin):
'type': 'xml',
})
hfeed = mf2util.interpret_feed(mf2py.parse(doc=resp.text), origin)
hfeed = mf2util.interpret_feed(
mf2py.Parser(doc=resp.text).to_dict(), origin)
if hfeed.get('entries'):
feeds.append({
'origin': origin,