Added snippet admin and profile editing
This commit is contained in:
parent
aa79c72ae0
commit
d87cbff134
14 changed files with 228 additions and 40 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
31
flask_website/templates/general/change_openid.html
Normal file
31
flask_website/templates/general/change_openid.html
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<style type=text/css>
|
||||
h1 { background-image: url(/static/login.png); }
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block title %}Change OpenID{% endblock %}
|
||||
{% block body %}
|
||||
<h2>Change OpenID</h2>
|
||||
<form action="" method=post>
|
||||
<p>
|
||||
You can the OpenID used to log into this website. Right
|
||||
now your OpenID identity is
|
||||
<a href="{{ g.user.openid }}">{{ g.user.openid|displayopenid }}</a>
|
||||
<p>
|
||||
OpenID URL:
|
||||
<input type=text name=openid class=openid size=26>
|
||||
<input type=hidden name=next value="{{ next }}">
|
||||
<input type=submit value=Change>
|
||||
<input type=submit name=cancel value=Cancel>
|
||||
<p>
|
||||
Alternatively you can directly link your profile with one
|
||||
of the common id providers:
|
||||
<ul>
|
||||
<li><a href=?provider=aol>AOL</a>
|
||||
<li><a href=?provider=google>Google</a>
|
||||
<li><a href=?provider=yahoo>Yahoo</a>
|
||||
</ul>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
@ -11,7 +11,8 @@
|
|||
<form action="{{ url_for('general.first_login') }}" method=post>
|
||||
<p>
|
||||
This is your first login on this website. You are about to sign
|
||||
in with the following OpenID: <a href="{{ openid }}">{{ openid }}</a>
|
||||
in with the following OpenID: <a href="{{ openid }}">{{
|
||||
openid|displayopenid }}</a>
|
||||
<p>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
{% endblock %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block body %}
|
||||
<form action="{{ url_for('general.login') }}" method=post>
|
||||
<form action="" method=post>
|
||||
<p>
|
||||
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 @@
|
|||
<input type=text name=openid class=openid size=30>
|
||||
<input type=hidden name=next value="{{ next }}">
|
||||
<input type=submit value=Login>
|
||||
<p>
|
||||
Alternatively you can directly sign in by clicking on one of
|
||||
the providers here in case you don't know the identity URL:
|
||||
<ul>
|
||||
<li><a href=?provider=aol>AOL</a>
|
||||
<li><a href=?provider=google>Google</a>
|
||||
<li><a href=?provider=yahoo>Yahoo</a>
|
||||
</ul>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
|||
27
flask_website/templates/general/profile.html
Normal file
27
flask_website/templates/general/profile.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<style type=text/css>
|
||||
h1 { background-image: url(/static/login.png); }
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block title %}Profile{% endblock %}
|
||||
{% block body %}
|
||||
<form action="" method=post>
|
||||
<p>
|
||||
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.
|
||||
<dl class=formlist>
|
||||
<dt>Name:
|
||||
<dd><input type=text name=name value="{{ name }}" size=30>
|
||||
<dt>OpenID:
|
||||
<dd>
|
||||
<span class=disabled>{{ g.user.openid|displayopenid }}</span>
|
||||
(<a href="{{ url_for('change_openid') }}">change</a>)
|
||||
</dl>
|
||||
<p>
|
||||
<input type=submit value="Update profile">
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
{% block head %}
|
||||
<title>{% block title %}Welcome{% endblock %} | Flask (A Python Microframework)</title>
|
||||
<meta charset=utf-8>
|
||||
<link rel=stylesheet type=text/css href="/static/style.css">
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('.static', filename='style.css') }}">
|
||||
<script type=text/javascript
|
||||
src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -11,11 +11,11 @@
|
|||
<h1><span>{{ self.title() }}</span></h1>
|
||||
{% endblock %}
|
||||
<p class=nav>
|
||||
<a href=/>overview</a> //
|
||||
<a href=/docs/>documentation</a> //
|
||||
<a href=/mailinglist/>mailinglist</a> //
|
||||
<a href=/snippets/>snippets</a> //
|
||||
<a href=/extensions/>extensions</a>
|
||||
<a href="{{ url_for('general.index') }}">overview</a> //
|
||||
<a href="{{ url_for('documentation.index') }}">documentation</a> //
|
||||
<a href="{{ url_for('mailinglist.index') }}">mailinglist</a> //
|
||||
<a href="{{ url_for('snippets.index') }}">snippets</a> //
|
||||
<a href="{{ url_for('extensions.index') }}">extensions</a>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<p class=message>{{ message }}
|
||||
{% endfor %}
|
||||
|
|
@ -23,8 +23,11 @@
|
|||
<p class=footer>
|
||||
© Copyright 2010 by <a href=http://lucumr.pocoo.org/>Armin Ronacher</a> //
|
||||
{% if g.user %}
|
||||
<a href=/logout/ title="logged in as {{ g.user.name }} [{{ g.user.openid }}]">logout</a>
|
||||
<a href="{{ url_for('general.profile') }}">profile</a> /
|
||||
<a href="{{ url_for('general.logout') }}" title="signed in as {{
|
||||
g.user.name }} [{{ g.user.openid }}]{% if g.user.is_admin
|
||||
%} - Administrator{% endif %}">sign out</a>
|
||||
{% else %}
|
||||
<a href=/login/>login</a>
|
||||
<a href="{{ url_for('general.login') }}">sign in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
|||
22
flask_website/templates/snippets/edit_comment.html
Normal file
22
flask_website/templates/snippets/edit_comment.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{% extends "snippets/layout.html" %}
|
||||
{% block title %}Edit Comment {{ comment.title }}{% endblock %}
|
||||
{% block body %}
|
||||
<h2>Edit Comment</h2>
|
||||
<script type=text/javascript>
|
||||
$(function() {
|
||||
$('input[name="delete"]').click(function() {
|
||||
if (!confirm("Do you really want to delete this comment?\n\n" +
|
||||
"THIS CANNOT BE UNDONE!"))
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<form action="" method=post>
|
||||
<p>Title: <input type=text name=title value="{{ form.title }}" size=30>
|
||||
<p><textarea name=text cols=40 rows=8>{{ form.text }}</textarea>
|
||||
<p>
|
||||
<input type=submit value="Update Comment">
|
||||
<input type=submit name=delete value="Delete">
|
||||
<input type=submit name=cancel value="Cancel">
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
@ -8,7 +8,9 @@
|
|||
<p>
|
||||
You're signed in as “<span title="{{ g.user.openid }}">{{ g.user.name
|
||||
}}</span>”. You can <a href="{{ url_for('general.logout')
|
||||
}}">sign out</a> here after you're done if you want.
|
||||
}}">sign out</a> here after you're done if you want. If you want to
|
||||
change your OpenID login or display name, head over to the
|
||||
<a href="{{ url_for('general.profile') }}">profile</a>.
|
||||
{% else %}
|
||||
<p>
|
||||
In order to add snippets to this page or to add comments, all you need
|
||||
|
|
@ -24,10 +26,6 @@
|
|||
<li><a href="{{ category.url }}">{{ category.name }}</a> ({{ category.count }})
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if g.user.is_admin %}
|
||||
<p>
|
||||
<a href="{{ url_for('manage_categories') }}">manage categories</a>
|
||||
{% endif %}
|
||||
{% if recent %}
|
||||
<h2>Recently Added</h2>
|
||||
<ul>
|
||||
|
|
@ -37,4 +35,10 @@
|
|||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if g.user.is_admin %}
|
||||
<h2>Admin Tools</h2>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('manage_categories') }}">Manage categories</a>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
with <code>#!python</code>, <code>#!html+jinja</code> or any other
|
||||
<a href="http://pygments.org/docs/lexers">Pygments lexer name</a>.
|
||||
<form action="" method=post>
|
||||
<dl>
|
||||
<dl class=formlist>
|
||||
<dt>Title:
|
||||
<dd><input type=text name=title value="{{ request.form.title }}" size=40>
|
||||
<dt>Category:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<p class=snippet-author>By {{ snippet.author.name }}
|
||||
filed in <a href="{{ snippet.category.url }}">{{ snippet.category.name }}</a>
|
||||
{% if snippet.author == g.user or g.user.is_admin %}
|
||||
(<a href="{{ url_for('snippets.edit', id=snippet.id) }}">edit</a>)
|
||||
(<a href="{{ url_for('edit', id=snippet.id) }}">edit</a>)
|
||||
{% endif %}
|
||||
{{ snippet.rendered_body }}
|
||||
{% if snippet.comments or g.user %}
|
||||
|
|
@ -23,6 +23,9 @@
|
|||
{{ comment.title or "Comment" }}
|
||||
by {{ comment.author.name }}
|
||||
on {{ comment.pub_date.strftime('%Y-%m-%d @ %H:%M') }}
|
||||
{% if g.user.is_admin %}
|
||||
(<a href="{{ url_for('edit_comment', id=comment.id) }}">edit</a>)
|
||||
{% endif %}
|
||||
<div class=body>{{ comment.rendered_text }}</div></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
@ -30,7 +33,7 @@
|
|||
{% if g.user %}
|
||||
<div id=add-comment>
|
||||
<h2>Add Comment</h2>
|
||||
<form action=#add-comment method=post>
|
||||
<form action="" method=post>
|
||||
<p>Title: <input type=text name=title value="{{ request.form.title }}" size=30>
|
||||
<p><textarea name=text cols=40 rows=8>{{ request.form.text }}</textarea>
|
||||
<p><input type=submit value="Add Comment">
|
||||
|
|
|
|||
|
|
@ -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('/')
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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/<int:id>/', 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/<int:id>/', methods=['GET', 'POST'])
|
||||
@requires_login
|
||||
def edit(id):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue