diff --git a/flask_website/__init__.py b/flask_website/__init__.py index 5246a6ee..4fdb5aef 100644 --- a/flask_website/__init__.py +++ b/flask_website/__init__.py @@ -24,6 +24,8 @@ def remove_db_session(response): db_session.remove() return response +app.add_url_rule('/docs/', endpoint='documentation.index', build_only=True) + from flask_website.views.general import general from flask_website.views.mailinglist import mailinglist from flask_website.views.snippets import snippets @@ -38,3 +40,4 @@ from flask_website import utils app.jinja_env.filters['datetimeformat'] = utils.format_datetime app.jinja_env.filters['timedeltaformat'] = utils.format_timedelta +app.jinja_env.filters['displayopenid'] = utils.display_openid diff --git a/flask_website/static/style.css b/flask_website/static/style.css index 6a492d8d..365f1b51 100644 --- a/flask_website/static/style.css +++ b/flask_website/static/style.css @@ -44,9 +44,13 @@ td input { border: none; padding: 0; } input, textarea, select { border: 1px solid black; padding: 2px; background: white; font-family: 'Georgia', serif; font-size: 17px; color: #004B6B; } textarea { width: 99%; } -input[type="submit"] { background: #DEEBF3; border-color: #004B6B; } +input[type="submit"] { background: #DEEBF3; border-color: #004B6B; + cursor: pointer; } +input[name="delete"]:hover { background: #A50000; color: white; + border-color: #860000; } input.openid { background: url(openid.png) no-repeat 4px center; padding-left: 26px; } +.formlist dt { color: #004B6B; margin: 8px 0; } /* snippets */ .snippet-author { margin: 0 0 20px 0; font-size: 0.9em; } diff --git a/flask_website/templates/general/change_openid.html b/flask_website/templates/general/change_openid.html new file mode 100644 index 00000000..bcdf1723 --- /dev/null +++ b/flask_website/templates/general/change_openid.html @@ -0,0 +1,31 @@ +{% extends "layout.html" %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block title %}Change OpenID{% endblock %} +{% block body %} +

Change OpenID

+
+

+ You can the OpenID used to log into this website. Right + now your OpenID identity is + {{ g.user.openid|displayopenid }} +

+ OpenID URL: + + + + +

+ Alternatively you can directly link your profile with one + of the common id providers: +

+
+{% endblock %} diff --git a/flask_website/templates/general/first_login.html b/flask_website/templates/general/first_login.html index 69452e58..da7086dd 100644 --- a/flask_website/templates/general/first_login.html +++ b/flask_website/templates/general/first_login.html @@ -11,7 +11,8 @@

This is your first login on this website. You are about to sign - in with the following OpenID: {{ openid }} + in with the following OpenID: {{ + openid|displayopenid }}

Before you can use this site we need a name for you. This is what will be displayed next to all of your public contributions to this diff --git a/flask_website/templates/general/login.html b/flask_website/templates/general/login.html index 3ada0f0f..05c9119e 100644 --- a/flask_website/templates/general/login.html +++ b/flask_website/templates/general/login.html @@ -7,7 +7,7 @@ {% endblock %} {% block title %}Login{% endblock %} {% block body %} - +

For some of the features on this site (such as creating snippets or adding comments) you have to be signed in. You don't need to @@ -18,5 +18,13 @@ +

+ Alternatively you can directly sign in by clicking on one of + the providers here in case you don't know the identity URL: +

{% endblock %} diff --git a/flask_website/templates/general/profile.html b/flask_website/templates/general/profile.html new file mode 100644 index 00000000..38374124 --- /dev/null +++ b/flask_website/templates/general/profile.html @@ -0,0 +1,27 @@ +{% extends "layout.html" %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block title %}Profile{% endblock %} +{% block body %} +
+

+ Here you can change the profile information used for this + website. Please keep in mind that you can only have one + OpenID identity linked to this account, if you change it + the old one will no longer be able to sign in. +

+
Name: +
+
OpenID: +
+ {{ g.user.openid|displayopenid }} + (change) +
+

+ +

+{% endblock %} diff --git a/flask_website/templates/layout.html b/flask_website/templates/layout.html index 668470b9..9342725b 100644 --- a/flask_website/templates/layout.html +++ b/flask_website/templates/layout.html @@ -2,7 +2,7 @@ {% block head %} {% block title %}Welcome{% endblock %} | Flask (A Python Microframework) - + {% endblock %} @@ -11,11 +11,11 @@

{{ self.title() }}

{% endblock %}

{{ message }} {% endfor %} @@ -23,8 +23,11 @@

Edit Comment

+ +
+

Title: +

+

+ + + +

+{% endblock %} diff --git a/flask_website/templates/snippets/index.html b/flask_website/templates/snippets/index.html index a0658678..3237a84e 100644 --- a/flask_website/templates/snippets/index.html +++ b/flask_website/templates/snippets/index.html @@ -8,7 +8,9 @@

You're signed in as “{{ g.user.name }}”. You can sign out here after you're done if you want. + }}">sign out here after you're done if you want. If you want to + change your OpenID login or display name, head over to the + profile. {% else %}

In order to add snippets to this page or to add comments, all you need @@ -24,10 +26,6 @@

  • {{ category.name }} ({{ category.count }}) {% endfor %} - {% if g.user.is_admin %} -

    - manage categories - {% endif %} {% if recent %}

    Recently Added

    {% endif %} + {% if g.user.is_admin %} +

    Admin Tools

    + + {% endif %} {% endblock %} diff --git a/flask_website/templates/snippets/new.html b/flask_website/templates/snippets/new.html index 4f929d36..d8d82f43 100644 --- a/flask_website/templates/snippets/new.html +++ b/flask_website/templates/snippets/new.html @@ -17,7 +17,7 @@ with #!python, #!html+jinja or any other Pygments lexer name.
    -
    +
    Title:
    Category: diff --git a/flask_website/templates/snippets/show.html b/flask_website/templates/snippets/show.html index e75f2021..11357edb 100644 --- a/flask_website/templates/snippets/show.html +++ b/flask_website/templates/snippets/show.html @@ -9,7 +9,7 @@

    By {{ snippet.author.name }} filed in {{ snippet.category.name }} {% if snippet.author == g.user or g.user.is_admin %} - (edit) + (edit) {% endif %} {{ snippet.rendered_body }} {% if snippet.comments or g.user %} @@ -23,14 +23,17 @@ {{ comment.title or "Comment" }} by {{ comment.author.name }} on {{ comment.pub_date.strftime('%Y-%m-%d @ %H:%M') }} + {% if g.user.is_admin %} + (edit) + {% endif %}

    {{ comment.rendered_text }}
  • {% endfor %} - {% endif %} + {% endif %} {% if g.user %}

    Add Comment

    - +

    Title:

    diff --git a/flask_website/utils.py b/flask_website/utils.py index 19d24d6c..56d0750a 100644 --- a/flask_website/utils.py +++ b/flask_website/utils.py @@ -133,3 +133,12 @@ def format_timedelta(delta, granularity='second', threshold=.85): rv += u's' return rv return u'' + + +def display_openid(openid): + if not openid: + return '' + rv = openid + if rv.startswith(('http://', 'https://')): + rv = rv.split('/', 2)[-1] + return rv.rstrip('/') diff --git a/flask_website/views/general.py b/flask_website/views/general.py index 188a5efa..94ec05ee 100644 --- a/flask_website/views/general.py +++ b/flask_website/views/general.py @@ -1,6 +1,8 @@ from flask import Module, render_template, session, redirect, url_for, \ request, flash, g, Response +from flaskext.openid import COMMON_PROVIDERS from flask_website import oid, twitter +from flask_website.utils import requires_login from flask_website.database import db_session, User general = Module(__name__) @@ -30,28 +32,20 @@ def logout(): def login(): if g.user is not None: return redirect(url_for('general.index')) - if request.method == 'POST': - openid = request.values.get('openid') - if openid: - return oid.try_login(openid, ask_for=['fullname', 'nickname']) + if reassign and 'cancel' in request.form: + flash(u'Cancelled. The OpenID was not changed.') + return redirect(oid.get_next_url()) + openid = request.values.get('openid') + if not openid: + openid = COMMON_PROVIDERS.get(request.args.get('provider')) + if openid: + return oid.try_login(openid, ask_for=['fullname', 'nickname']) error = oid.fetch_error() if error: flash(u'Error: ' + error) return render_template('general/login.html', next=oid.get_next_url()) -@oid.after_login -def create_or_login(resp): - session['openid'] = resp.identity_url - user = User.query.filter_by(openid=resp.identity_url).first() - if user is not None: - flash(u'Successfully signed in') - g.user = user - return redirect(oid.get_next_url()) - return redirect(url_for('first_login', next=oid.get_next_url(), - name=resp.fullname or resp.nickname)) - - @general.route('/first-login/', methods=['GET', 'POST']) def first_login(): if g.user is not None or 'openid' not in session: @@ -68,3 +62,55 @@ def first_login(): return render_template('general/first_login.html', next=oid.get_next_url(), openid=session['openid']) + + +@general.route('/profile/', methods=['GET', 'POST']) +@requires_login +def profile(): + name = g.user.name + if request.method == 'POST': + name = request.form['name'].strip() + if not name: + flash(u'Error: a name is required') + else: + g.user.name = name + db_session.commit() + flash(u'User profile updated') + return redirect(url_for('index')) + return render_template('general/profile.html', name=name) + + +@general.route('/profile/change-openid/', methods=['GET', 'POST']) +@requires_login +@oid.loginhandler +def change_openid(): + if request.method == 'POST': + if 'cancel' in request.form: + flash(u'Cancelled. The OpenID was not changed.') + return redirect(oid.get_next_url()) + openid = request.values.get('openid') + if not openid: + openid = COMMON_PROVIDERS.get(request.args.get('provider')) + if openid: + return oid.try_login(openid) + error = oid.fetch_error() + if error: + flash(u'Error: ' + error) + return render_template('general/change_openid.html', + next=oid.get_next_url()) + + +@oid.after_login +def create_or_login(resp): + session['openid'] = resp.identity_url + user = g.user or User.query.filter_by(openid=resp.identity_url).first() + if user is None: + return redirect(url_for('first_login', next=oid.get_next_url(), + name=resp.fullname or resp.nickname)) + if user.openid != resp.identity_url: + user.openid = resp.identity_url + db_session.commit() + flash(u'OpenID identity changed') + else: + flash(u'Successfully signed in') + return redirect(oid.get_next_url()) diff --git a/flask_website/views/snippets.py b/flask_website/views/snippets.py index 4ee9da03..0d8eca7d 100644 --- a/flask_website/views/snippets.py +++ b/flask_website/views/snippets.py @@ -32,7 +32,7 @@ def new(): else: title = request.form['title'] body = request.form['body'] - if not body: + if body: flash(u'Error: you have to enter a snippet') else: category = Category.query.get(category_id) @@ -55,9 +55,7 @@ def show(id): if request.method == 'POST': title = request.form['title'] text = request.form['text'] - if not text: - flash(u'Error: the text is required') - else: + if text: db_session.add(Comment(snippet, g.user, title, text)) db_session.commit() flash(u'Your comment was added') @@ -65,6 +63,35 @@ def show(id): return render_template('snippets/show.html', snippet=snippet) +@snippets.route('/comments//', methods=['GET', 'POST']) +@requires_admin +def edit_comment(id): + comment = Comment.query.get(id) + if comment is None: + abort(404) + form = dict(title=comment.title, text=comment.text) + if request.method == 'POST': + if 'delete' in request.form: + db_session.delete(comment) + db_session.commit() + flash(u'Comment was deleted.') + return redirect(comment.snippet.url) + elif 'cancel' in request.form: + return redirect(comment.snippet.url) + form['title'] = request.form['title'] + form['text'] = request.form['text'] + if not form['text']: + flash(u'Error: comment text is required.') + else: + comment.title = form['title'] + comment.text = form['text'] + db_session.commit() + flash(u'Comment was updated.') + return redirect(comment.snippet.url) + return render_template('snippets/edit_comment.html', form=form, + comment=comment) + + @snippets.route('/edit//', methods=['GET', 'POST']) @requires_login def edit(id):