Permalink
Browse files

Merge pull request #23 from kopf/admin

Fixes #11 Implement admin actions
  • Loading branch information...
2 parents 5371fa5 + 85edb3a commit 98a0e9582d5cdad77828be21f54ebbf76963ccc8 @kopf committed May 13, 2012
View
@@ -32,6 +32,9 @@ def make_map(config):
map.connect('/browse/tags/{tag}', controller='browse', action='tags')
map.connect('/browse/tags/{tag}/page/{page}', controller='browse', action='tags')
+ map.connect('/browse/unapproved', controller='browse', action='unapproved')
+ map.connect('/browse/unapproved/page/{page}', controller='browse', action='unapproved')
+
map.connect('/browse/random', controller='browse', action='random')
map.connect('/browse/{ref_id}', controller='browse', action='view_one')
@@ -46,7 +49,8 @@ def make_map(config):
map.connect('/login', controller='account', action='login')
map.connect('/logout', controller='account', action='logout')
- map.connect('/api/vote/{direction}/{quote_id}', controller='vote', action='vote')
+ map.connect('/api/v1/approve/{quote_id}', controller='api_v1', action='approve')
+ map.connect('/api/v1/vote/{direction}/{quote_id}', controller='api_v1', action='vote')
map.connect('/', controller='home', action='main')
@@ -11,7 +11,23 @@
log = logging.getLogger(__name__)
-class VoteController(BaseController):
+class ApiV1Controller(BaseController):
+
+ @jsonify
+ def approve(self, quote_id):
+ authorize()
+ if not h.is_admin():
+ abort(401)
+ if request.environ['REQUEST_METHOD'] == 'POST':
+ quote = db.query(Quote).filter(Quote.id == quote_id).first()
+ user = h.get_current_user()
+ if not quote:
+ return {'msg': 'Invalid quote ID',
+ 'status': 'error'}
+ quote.approved = 1
+ db.commit()
+ return {'msg': 'Quote approved',
+ 'status': 'success'}
@jsonify
def vote(self, direction, quote_id):
@@ -7,6 +7,7 @@
import webhelpers.paginate as paginate
from porick.lib.base import BaseController, render
+import porick.lib.helpers as h
from porick.model import db, Quote, QuoteToTag, Tag
log = logging.getLogger(__name__)
@@ -74,6 +75,15 @@ def view_one(self, ref_id):
c.page = 'browse'
return render(self._get_template_name())
+ def unapproved(self, page=1):
+ if not h.is_admin():
+ h.add_message('You must be an admin to perform that action.', 'error')
+ return render('/blank.mako')
+ quotes = db.query(Quote).order_by(Quote.score).filter(Quote.approved == 0).all()
+ c.paginator = self._create_paginator(quotes, page)
+ c.page = 'unapproved'
+ return render(self._get_template_name())
+
def _generate_tagcloud(self):
retval = {}
for tag in db.query(Tag).all():
View
@@ -42,3 +42,9 @@ def check_if_voted(quote):
for assoc in quote.voters:
if assoc.user.username == c.username:
return assoc.direction
+
+def is_admin():
+ return c.logged_in and c.user_level == 1
+
+def show_approval_buttons():
+ return c.page == 'unapproved' and is_admin()
View
@@ -33,10 +33,17 @@ body {
.well {
padding: 10px 18px 18px 18px !important;
}
+.paginator_container {
+ float: left;
+ position: relative;
+ left: 50%;
+}
.pagination {
border-left: 1px solid #DDD;
- width: 390px;
margin: 6px auto 12px auto !important;
+ float: left;
+ position: relative;
+ left: -50%;
}
.pagination .bootstrap_style {
float: left;
@@ -46,7 +53,17 @@ body {
border: 1px solid #DDD;
border-left-width: 0;
}
-
+.approve {
+ font-family: 'WebSymbolsRegular';
+ font-size: 15px;
+ cursor: pointer;
+}
+.approve.approved {
+ color: green !important;
+}
+.metadata .date {
+ font-size: 11px;
+}
.quote .votes {
float: left;
display: block;
@@ -0,0 +1,20 @@
+function setupApproveClickHandlers() {
+ /**
+ * Assign click handlers to all approve buttons.
+ */
+ $('.approve').click(function() {
+ var quote_id = $(this).data('quote_id');
+ var button = $(this);
+ $.ajax({
+ url: '/api/v1/approve/' + quote_id,
+ type: 'POST',
+ success: function(data, status, jqXHR){
+ button.addClass(data['status'] + ' approved');
+ if(data['status'] === 'success') {
+ button.parent().parent().parent().fadeOut('slow');
+ }
+ }
+ });
+ });
+}
+
@@ -24,7 +24,7 @@ function setupVoteClickHandlers() {
function castVote(quote_id, direction, button) {
$.ajax({
- url: '/api/vote/' + direction + '/' + quote_id,
+ url: '/api/v1/vote/' + direction + '/' + quote_id,
type: 'PUT',
success: function(data, status, jqXHR){
$(button).addClass(data['status'] + ' voted');
@@ -35,7 +35,7 @@ function castVote(quote_id, direction, button) {
function annulVote(quote_id, direction, button) {
$.ajax({
- url: '/api/vote/' + direction + '/' + quote_id,
+ url: '/api/v1/vote/' + direction + '/' + quote_id,
type: 'DELETE',
success: function(data, status, jqXHR){
$(button).removeClass('success error voted');
View
@@ -70,11 +70,20 @@
## You should usually overwrite this one and " - Porick" will get appended
<%def name="head_title()">Porick</%def>
-<%def name="side_text()">
+<%def name="side_text(capitalize=False)">
% if c.page == 'tags' and 'tag_filter' in c.__dict__:
- tag: ${c.tag_filter}
+ % if capitalize:
+ Tag:
+ % else:
+ tag:
+ % endif
+ ${c.tag_filter}
% else:
- ${c.page}
+ % if capitalize:
+ ${c.page.capitalize()}
+ % else:
+ ${c.page}
+ % endif
% endif
</%def>
@@ -110,6 +119,11 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">${c.username} <b class="caret"></b></a>
<ul class="dropdown-menu">
+ % if h.is_admin():
+ <li class="nav-header">Admin</li>
+ <li><a href="${h.url(controller='browse', action='unapproved')}">Unapproved Quotes</a></li>
+ <li class="divider"></li>
+ % endif
<li><a href="#">Preferences</a></li>
<li class="divider"></li>
<li><a href="${h.url(controller='account', action='logout')}">Log out</a></li>
@@ -0,0 +1,7 @@
+<%inherit file="base.mako"/>
+
+<%def name="body_content()">
+</%def>
+
+<%def name="side_text()">
+</%def>
@@ -1,10 +1,16 @@
<%inherit file="browse.mako"/>
<%def name="custom_js()">
+ % if h.show_approval_buttons():
+ <script type="text/javascript" src="/js/approval.js"></script>
+ % endif
<script type="text/javascript" src="/js/voting.js"></script>
<script type="text/javascript">
$(document).ready(function() {
setupVoteClickHandlers();
+ % if h.show_approval_buttons():
+ setupApproveClickHandlers();
+ % endif
});
</script>
</%def>
@@ -1,10 +1,10 @@
<%inherit file="base.mako"/>
<%def name="head_title()">
- % if not c.page == 'tags':
- ${c.page.capitalize()} Quotes
+ % if 'search' in c.page or c.page == 'tags':
+ ${self.side_text(capitalize=True)}
% else:
- Browse Quotes
+ ${c.page.capitalize()} Quotes
% endif
</%def>
@@ -30,8 +30,12 @@
<div class="well quote">
${self.insert_vote_buttons(quote)}
<ul class="metadata">
- <li><a href="${h.url(controller='browse', action='view_one', ref_id=quote.id)}">${quote.submitted}</a></li>
- <li class="top_right nomargin"></li>
+ <li><a href="${h.url(controller='browse', action='view_one', ref_id=quote.id)}" class="date">${quote.submitted.strftime("%d. %B %Y %I:%M%p")}</a></li>
+ <li class="top_right nomargin">
+ % if h.show_approval_buttons():
+ <div class="approve" data-quote_id="${quote.id}">/</div>
+ % endif
+ </li>
</ul>
${self.insert_quote_body(quote)}
</div>
@@ -71,10 +75,14 @@
</%def>
<%def name="display_pagination()">
- <div class="pagination">
- ${c.paginator.pager(curpage_attr={'class': 'bootstrap_style'},
- dotdot_attr={'class': 'bootstrap_style'},
- symbol_previous='&#171;',
- symbol_next='&#187;')}
- </div>
+ % if c.paginator.page_count > 1:
+ <div class="paginator_container">
+ <div class="pagination">
+ ${c.paginator.pager(curpage_attr={'class': 'bootstrap_style'},
+ dotdot_attr={'class': 'bootstrap_style'},
+ symbol_previous='&#171;',
+ symbol_next='&#187;')}
+ </div>
+ </div>
+ % endif
</%def>

0 comments on commit 98a0e95

Please sign in to comment.