]> git.openstreetmap.org Git - osqa.git/commitdiff
Closing OSQA 35. Give admins and moderators an easy way to award karma points.
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Fri, 14 May 2010 23:58:15 +0000 (23:58 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Fri, 14 May 2010 23:58:15 +0000 (23:58 +0000)
New user management interface.

git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@284 0cfe37f9-358a-4d5e-be75-b63607b5c754

16 files changed:
forum/actions/user.py
forum/forms.py
forum/skins/default/media/js/osqa.user.js [new file with mode: 0644]
forum/skins/default/media/style/style.css
forum/skins/default/media/style/user.css [new file with mode: 0644]
forum/skins/default/templates/auth/auth_settings.html
forum/skins/default/templates/user.html
forum/skins/default/templates/users/info.html
forum/skins/default/templates/users/menu.html [new file with mode: 0644]
forum/skins/default/templates/users/moderation.html [deleted file]
forum/skins/default/templates/users/tabs.html
forum/templatetags/user_tags.py
forum/urls.py
forum/views/auth.py
forum/views/decorators.py
forum/views/users.py

index 1ceae09af5cda1a83ef2d7ffb3f0539f1d24e957..aef541a1bb02abe2744b8572099f3e03c3e366cc 100644 (file)
@@ -23,6 +23,25 @@ class EditProfileAction(ActionProxy):
             'profile_link': self.hyperlink(self.user.get_profile_url(), _('profile')),
         }
 
+class BonusRepAction(ActionProxy):
+    def process_data(self, value):
+        self._value = value
+
+    def repute_users(self):
+        self.repute(self.user, self._value)
+        self.user.message_set.create(message=_("Congratulations, you have been awarded an extra %s reputation points.") % self._value +
+                                     '<br />%s' % self.extra.get('message', _('Thank you')))
+        
+    def describe(self, viewer=None):
+        value = self.extra.get('value', _('unknown'))
+        message = self.extra.get('message', '')
+
+        return _("%(user)s %(was_were)s awarded %(value)s reputation points: %(message)s") % {
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+            'was_were': self.viewer_or_user_verb(viewer, self.user, _('were'), _('was')),
+            'value': value, 'message': message
+        }
+
 class AwardAction(ActionProxy):
     def process_data(self, badge, trigger):
         self.__dict__['_badge'] = badge
index 509c1255dd5578aebce63017f75789f8756d97fe..b54d65b1d133b03b70f5db84dc0ae06ede96b8b7 100644 (file)
@@ -251,3 +251,7 @@ class SubscriptionSettingsForm(forms.Form):
     notify_comments = forms.BooleanField(required=False, initial=False)
     notify_accepted = forms.BooleanField(required=False, initial=False)
 
+
+class AwardPointsForm(forms.Form):
+    points = forms.IntegerField(min_value=1, initial=50, label=_('Points to award'))
+    message = forms.CharField(widget=forms.Textarea(), label=_('Message'), required=False)
diff --git a/forum/skins/default/media/js/osqa.user.js b/forum/skins/default/media/js/osqa.user.js
new file mode 100644 (file)
index 0000000..4a168a2
--- /dev/null
@@ -0,0 +1,90 @@
+
+function show_dialog (html, extra_class, pos, dim, yes, no_text) {
+    $dialog = $('<div class="dialog ' + extra_class + '" style="width: 1px; height: 1px;">'
+             + '<div class="dialog-content">' + html + '</div><div class="dialog-buttons">'
+            + '<button class="dialog-no">' + no_text + '</button>'
+            + '<button class="dialog-yes">' + yes.text + '</button>'
+            + '</div></div>');
+
+    $('body').append($dialog);
+
+    $dialog.css({
+        top: pos.y,
+        left: pos.x
+    });
+
+    $dialog.animate({
+        top: "-=" + (dim.h / 2),
+        left: "-=" + (dim.w / 2),
+        width: dim.w,
+        height: dim.h
+    }, 200, function() {
+        $dialog.find('.dialog-no').click(function() {
+            $dialog.fadeOut('fast');
+        });
+        $dialog.find('.dialog-yes').click(function() {
+            yes.callback($dialog);
+        });
+    });
+
+}
+
+
+$().ready(function() {
+    var $dropdown = $('#user-menu-dropdown');
+
+    $('#user-menu').click(function(){
+        $('.dialog').fadeOut('fast');
+        $dropdown.slideToggle('fast');        
+    });
+
+    $('.confirm').each(function() {
+        var $link = $(this);
+
+        $link.click(function(e) {
+            $dropdown.slideUp('fast');
+            var html = messages.confirm;
+
+            show_dialog(html, 'confirm', {x: e.pageX, y: e.pageY}, {w: 200, h: 100}, {
+                text: messages.yes,
+                callback: function() {
+                    window.location = $link.attr('href');
+                }
+            }, messages.no);
+
+            return false;
+        });
+    });
+
+    $('#award-rep-points').click(function(e) {
+        $dropdown.slideUp('fast');
+
+        var html = '<table><tr><th>' + messages.points + '</th><td><input type="text" id="points-to-award" value="1" /></td></tr>'
+                + '<tr><th>' + messages.message + '</th><td><textarea id="award-message"></textarea></td></tr></table>';
+
+        show_dialog(html, 'award-rep-points', {x: e.pageX, y: e.pageY}, {w: 300, h: 125}, {
+            text: messages.award,
+            callback: function($dialog) {
+                var $points_input = $('#points-to-award');
+                var _points = parseInt($points_input.val());
+
+                if(!isNaN(_points)) {
+                    $dialog.fadeOut('fast');
+                    var _message = $('#award-message').val();
+                    $.post($('#award-rep-points').attr('href'), {points: _points, message: _message}, function(data) {
+                        if (data.success) {
+                            $('#user-reputation').css('background', 'yellow');
+                            $('#user-reputation').html(data.reputation);
+
+                            $('#user-reputation').animate({ backgroundColor: "transparent" }, 1000);
+                            
+                        }
+                    }, 'json')
+                }
+            }
+        }, messages.cancel);
+
+
+        return false;
+    });
+});
\ No newline at end of file
index b2653d34c4d7ba48c22fa6fff61d743e0316a1c1..360e47757b4b0f5369192dd37e1161402ff8bfe9 100644 (file)
@@ -1375,4 +1375,18 @@ div.comment-tools a:hover {
 .moderation #action_status {
        font-weight: bold;
        text-align: center;
+}
+
+.moderation-table input[type=text], .moderation-table textarea {
+    width: 150px;
+    max-height: 50px;
+}
+
+.moderation-table th {
+    vertical-align: top;
+    text-align: left;
+}
+
+.moderation-table-footer {
+    text-align: right;
 }
\ No newline at end of file
diff --git a/forum/skins/default/media/style/user.css b/forum/skins/default/media/style/user.css
new file mode 100644 (file)
index 0000000..5804226
--- /dev/null
@@ -0,0 +1,110 @@
+#user-menu-container {
+    position: relative;
+    text-align: right;
+}
+
+#user-menu {
+    cursor: pointer;
+    height: 1em;
+    font-size: 120%;
+    font-weight: bold;
+    color: #3060A8;
+}
+
+#user-menu-dropdown, div.dialog {
+    position: absolute;
+    background-color: #B6C4E2;
+    -moz-border-radius: 5px;
+    -webkit-border-radius: 5px;
+    -moz-box-shadow: 2px 2px 5px #3060A8;
+    -webkit-box-shadow: 2px 2px 5px #3060A8;
+}
+
+div.dialog .dialog-buttons {
+    margin: 0px;
+    height: 25px;
+    text-align: center;
+    position: absolute;
+    bottom: 0px;
+    left: 0px;
+    width: 100%;
+}
+
+.dialog-yes, .dialog-no {
+    margin: 0 3px 5px 3px;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+    background-color: #3060A8;
+    color: white;
+    height: 20px;
+    line-height: 20px;
+    font-weight: bold;
+    border: 0;
+}
+
+div.dialog.confirm {
+    text-align: center;
+    line-height: 75px;
+    font-size: 140%;
+    font-weight: bold;
+}
+
+div.dialog.award-rep-points table {
+    margin: auto;
+    margin-top: 8px;
+}
+
+div.dialog.award-rep-points table th {
+    text-align: left;
+}
+
+div.dialog.award-rep-points table input, div.dialog.award-rep-points table textarea {
+    width: 150px;
+    max-height: 35px;
+}
+
+#user-menu-dropdown {
+    display: none;
+    right: 0px;
+    top: 1.5em;
+    text-align: left;
+    list-style-type: none;
+}
+
+#user-menu-dropdown li.item {
+    padding: 4px 8px 4px 8px;
+     -moz-border-radius: 5px;
+    -webkit-border-radius: 5px;
+}
+
+#user-menu-dropdown li.item a {
+    color: inherit;
+    white-space: nowrap;
+    text-decoration: none;
+}
+
+#user-menu-dropdown li.separator {
+    text-align: center;
+    padding: 10px 0 4px 0;
+    font-size: 120%;
+    font-weight: bold;
+}
+
+#user-menu-dropdown li.item:hover {
+    background-color: #3060A8;
+    color: white;
+}
+
+#user-menu-dropdown span {
+    margin-right: 4px;
+    float: left;
+    width: 16px;
+    height: 16px;
+}
+
+.user-auth { background: url('/m/default/media/images/user-sprite.png') no-repeat 0 0; }
+.user-award_rep { background: url('/m/default/media/images/user-sprite.png') no-repeat 0 -17px; }
+.user-edit { background: url('/m/default/media/images/user-sprite.png') no-repeat 0 -34px; }
+.user-moderator { background: url('/m/default/media/images/user-sprite.png') no-repeat 0 -51px; }
+.user-subscriptions { background: url('/m/default/media/images/user-sprite.png') no-repeat 0 -68px; }
+.user-superuser { background: url('/m/default/media/images/user-sprite.png') no-repeat 0 -85px; }
index e19a10cc1c7d3e1eee100825185d2114595c0feb..3e3200772aa1ffa2d90a07e14d2175291a382258 100644 (file)
@@ -1,10 +1,10 @@
-{% extends "base.html" %}
+{% extends "user.html" %}
 <!-- changepw.html -->
 {% load i18n %}
 {% block head %}{% endblock %}
 {% block title %}{% spaceless %}{% trans "Authentication settings" %}{% endspaceless %}{% endblock %}
-{% block content %}
-<div class="headNormal">{% trans "Authentication settings" %}</div>
+{% block usercontent %}
+<h2>{% trans "Authentication settings" %}</h2>
 {% if auth_keys %}
     <p class="message">{% blocktrans %}These are the external authentication providers currently associated with your account.{% endblocktrans %}</p>
     <div>
@@ -16,7 +16,7 @@
 {% if not auth_keys %}
     <p class="message">{% blocktrans %}You currently have no external authentication provider associated with your account.{% endblocktrans %}</p>
 {% endif %}
-{% ifequal user request.user %}
+{% ifequal view_user request.user %}
     <input type="button" class="submit" value="{% trans "Add new provider" %}" onclick="window.location='{% url user_add_external_provider %}'" />
 {% endifequal %}
 {% if has_password %}
index 5ff0d80946f27c86bbecbc2dfe28e0dde9f98e84..263f91f58cf521daa38223e130b1dd7c30824cf2 100644 (file)
@@ -3,6 +3,8 @@
 {% load extra_tags %}
 {% load extra_filters %}
 {% load humanize %}
+{% load smart_if %}
+
 {% block title %}{% spaceless %}{{ page_title }}{% endspaceless %}{% endblock %}
 {% block forestyle%}
     <style type="text/css">
        </style>
 {% endblock %}
 {% block forejs %}
-    {% if request.user.is_superuser %}
+    {% if request.user.is_superuser or request.user == view_user %}
         <script type='text/javascript' src='{% media  "/media/js/jquery.form.js" %}'></script>
+        <script type="text/javascript">google.load("jquery", "1.4.2");google.load("jqueryui", "1.8.1");</script>
+        <script src="{% media "/media/js/osqa.user.js" %}" type="text/javascript"></script>
+
+        <link rel="stylesheet" href="http://jquery-ui.googlecode.com/svn/tags/latest/themes/base/jquery-ui.css" type="text/css" media="all" />
+        <link rel="stylesheet" href="http://static.jquery.com/ui/css/demo-docs-theme/ui.theme.css" type="text/css" media="all" />
+        <link rel="stylesheet" type="text/css" media="screen" href="{% media "/media/style/user.css" %}"/>
     {% endif %}
     <script type="text/javascript">
         var viewUserID = {{view_user.id}};
index 08f006f589971f20563a629fd07e6a7a44a69bf4..efe2b43822f03f5a24f8655f43085cda30ee32d2 100644 (file)
@@ -6,6 +6,7 @@
 {% load i18n %}
 {% load markup %}
 {% load user_tags %}
+
 <div id="subheader" class="headUser">
     {{view_user.username}}
 </div>
                 </tr>
                 <tr>
                     <td align="center">
-                        <div class="scoreNumber">{{view_user.reputation|intcomma}}</div>
+                        <div class="scoreNumber" id="user-reputation">{{view_user.reputation|intcomma}}</div>
                         <p><b style="color:#777;">{% trans "reputation" %}</b></p>
                     </td>
                 </tr>
             </table>
         </td>
         <td width="360" style="vertical-align: top;">
+        {% if can_view_private %}{% user_menu request.user view_user %}{% endif %}
             <table class="user-details">
-                {% if view_user != request.user and request.user.is_superuser %}
-                <tr>
-                    <td class="moderation" align="left" colspan="2">
-                        {% user_moderation request.user view_user %}
-                    </td>
-                </tr>
-                {% endif %}
-                {% if can_view_private %}
-                <tr>
-                    <td class="user-profile-tool-links" align="left" colspan="2">
-                        {% joinitems using ' | ' %}
-                            <span class="user-edit-link"><a href="{% url edit_user id=view_user.id %}">{% trans "update profile" %}</a></span>
-                        {% separator %}
-                            <a href="{% url user_authsettings id=view_user.id %}">{% trans "authentication settings" %}</a>
-                        {% endjoinitems %}
-                    </td>
-                </tr>  
-                {% endif %}
                 <tr>
                     <th colspan="2" align="left"><h3>{% trans "Registered user" %}</h3></th>
                 </tr>
diff --git a/forum/skins/default/templates/users/menu.html b/forum/skins/default/templates/users/menu.html
new file mode 100644 (file)
index 0000000..06ff4b3
--- /dev/null
@@ -0,0 +1,96 @@
+{% load i18n %}\r
+{% load smart_if %}\r
+\r
+<script type="text/javascript">\r
+var messages = {\r
+    username: '{{ user.username }}}',\r
+    confirm: "{% trans "Are you sure?" %}",\r
+    yes: "{% trans "Yes" %}",\r
+    no: "{% trans "No" %}",\r
+    points: "{% trans "Points to award:" %}",\r
+    message: "{% trans "Message:" %}",\r
+    award: "{% trans "Award" %}",\r
+    cancel: "{% trans "Cancel" %}"\r
+}\r
+</script>\r
+\r
+<div id="user-menu-container">\r
+    <span id="user-menu">{% trans "User tools" %} &#9660;</span>\r
+    <ul id="user-menu-dropdown">\r
+        <li class="item"><span class="user-edit"></span><a href="{% url edit_user id=user.id %}">{% trans "edit profile" %}</a></li>\r
+        <li class="item"><span class="user-auth"></span><a href="{% url user_authsettings id=user.id %}">{% trans "authentication settings" %}</a></li>\r
+        <li class="item"><span class="user-subscriptions"></span><a href="{% url user_subscriptions id=user.id %}">{% trans "email notification settings" %}</a></li>\r
+        {% ifnotequal user viewer %}\r
+            {% if viewer.is_superuser %}\r
+            <li class="separator">{% trans "Moderation tools" %}</li>\r
+            <li class="item"><span class="user-award_rep"></span><a href="{% url user_award_points id=user.id %}" id="award-rep-points">{% trans "reputation bonus" %}</a></li>\r
+                {% if not user.is_superuser %}\r
+                    {% if not user.is_staff %}\r
+                    <li class="item"><span class="user-moderator"></span>\r
+                        <a class="confirm" href="{% url user_powers id=user.id,action="grant",status="staff" %}">{% trans "grant moderator status" %}</a>\r
+                    </li>\r
+                    {% else %}\r
+                    <li class="item"><span class="user-moderator"></span>\r
+                        <a class="confirm" href="{% url user_powers id=user.id,action="remove",status="staff" %}">{% trans "remove moderator status" %}</a>\r
+                    </li>\r
+                    {% endif %}\r
+                    <li class="item"><span class="user-superuser"></span>\r
+                        <a class="confirm" href="{% url user_powers id=user.id,action="grant",status="super" %}">{% trans "grant super user status" %}</a>\r
+                    </li>\r
+                {% else %}\r
+                    {% ifequal viewer.id 1 %}\r
+                    <li class="item"><span class="user-superuser"></span>\r
+                        <a class="confirm" href="{% url user_powers id=user.id,action="remove",status="super" %}">{% trans "remove super user status" %}</a>\r
+                    </li>\r
+                    {% endifequal %}\r
+                {% endif %}\r
+            {% endif %}\r
+        {% endifnotequal %}\r
+    </ul>\r
+</div>\r
+\r
+{% comment %}\r
+<h3>{% trans "Moderation tools" %}</h3>\r
+<p><a href="#" id="point-award-action">{% trans "Reputation bonus" %}</a></p>\r
+<form action="" method="POST">\r
+    <table style="display: none" id="award-points-table" class="moderation-table">\r
+    {{ awardform.as_table }}\r
+    <tr><td colspan="2" class="moderation-table-footer"><input type="submit" id="award-points-submit" value="{% trans "Send" %}" /></td></tr>\r
+    </table>    \r
+</form>\r
+<script>\r
+    $(function() {\r
+        $('#point-award-action').click(function() {\r
+            $('#award-points-table').slideToggle('slow');\r
+        });\r
+\r
+        $('#award-points-submit').click(function() {\r
+            $('#award-points-table').find('.error').remove();\r
+            var $points_input = $('#award-points-table').find('input[type=text]');\r
+            var points = parseInt($points_input.val());\r
+\r
+            if (isNaN(points) || points < 1) {\r
+                $points_input.before('<p class="error">{% trans "Sorry but that\'s not a valid input" %}</p>');\r
+                return false;\r
+            }\r
+\r
+            $.post('{% url user_award_points id=user.id %}')\r
+        });\r
+    });\r
+</script>\r
+{% if not user.is_superuser %}\r
+<p><a href="{% url user_powers id=user.id,action="grant",status="super" %}">{% trans "Grant super user status" %}</a></p>\r
+    {% if not user.is_staff %}\r
+    <p><a href="{% url user_powers id=user.id,action="grant",status="staff" %}">{% trans "Grant moderator status" %}</a></p>\r
+    {% else %}\r
+    <p><a href="{% url user_powers id=user.id,action="remove",status="staff" %}" class="">{% trans "Remove moderator status" %}</a></p>\r
+    {% endif %}\r
+{% else %}\r
+    {% ifequal moderator.id 1 %}\r
+        {% ifnotequal user.id 1 %}\r
+            <p><a href="{% url user_powers id=user.id,action="remove",status="super" %}">{% trans "Remove super user status" %}</a></p>\r
+        {% endifnotequal %}\r
+    {% endifequal %}\r
+{% endif %}\r
+\r
+{% endcomment %}\r
diff --git a/forum/skins/default/templates/users/moderation.html b/forum/skins/default/templates/users/moderation.html
deleted file mode 100644 (file)
index 8def633..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{% load i18n %}\r
-\r
-<h3>{% trans "Moderation tools" %}</h3>\r
-<p><a href="#" class="ajax-command">{% trans "Reputation bonus" %}</a></p>\r
-{% if not user.is_superuser %}\r
-<p><a href="{% url user_powers id=user.id,action="grant",status="super" %}">{% trans "Grant super user status" %}</a></p>\r
-    {% if not user.is_staff %}\r
-    <p><a href="{% url user_powers id=user.id,action="grant",status="staff" %}">{% trans "Grant moderator status" %}</a></p>\r
-    {% else %}\r
-    <p><a href="{% url user_powers id=user.id,action="remove",status="staff" %}" class="">{% trans "Remove moderator status" %}</a></p>\r
-    {% endif %}\r
-{% else %}\r
-    {% ifequal moderator.id 1 %}\r
-        {% ifnotequal user.id 1 %}\r
-            <p><a href="{% url user_powers id=user.id,action="remove",status="super" %}">{% trans "Remove super user status" %}</a></p>\r
-        {% endifnotequal %}\r
-    {% endifequal %}\r
-{% endif %}\r
index 78d0c333ca7c6e324d973b41c0742b33930c45c9..1815c24cefa72846810a28ee59565940f495907f 100644 (file)
         <a id="favorites" {% ifequal tab_name "favorites" %}class="on"{% endifequal %} 
                        title="{% trans "questions that user selected as his/her favorite" %}"
                        href="{% url user_favorites id=view_user.id,slug=user_slug %}">{% trans "favorites" %}</a>
-        {% if can_view_private %}
-        <a id="email_subscriptions" {% ifequal tab_name "subscriptions" %}class="on"{% endifequal %} 
-                       title="{% trans "email subscription settings" %}" 
-                       href="{% url user_subscriptions id=view_user.id,slug=user_slug %}">{% trans "subscriptions" %}</a>
-        {% endif %}  
     </div>
 </div>
 {% endwith %}
index d69c1bc50575d64bc53e2759a3cbe946c2b0fb90..27535f6d383f483e659f84699b92f7c1d5f8b055 100644 (file)
@@ -1,6 +1,7 @@
 from django import template\r
 from django.utils.translation import ugettext as _\r
 from django.utils.safestring import mark_safe\r
+from forum.forms import AwardPointsForm\r
 import logging\r
 \r
 register = template.Library()\r
@@ -54,7 +55,7 @@ def activity_item(parser, token):
     return ActivityNode(activity, viewer)\r
 \r
 \r
-@register.inclusion_tag('users/moderation.html')\r
-def user_moderation(moderator, user):\r
-    return dict(moderator=moderator, user=user)\r
+@register.inclusion_tag('users/menu.html')\r
+def user_menu(request, user):\r
+    return dict(viewer=request.user, user=user)\r
 \r
index c808bb8375c0becd109c59b6fcc2fa80dd9ec680..c173bcf740f538bd32eadd10e10d35334be9c786 100644 (file)
@@ -94,8 +94,9 @@ urlpatterns += patterns('',
 
     url(r'^%s$' % _('users/'),app.users.users, name='users'),
     url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')), app.users.edit_user, name='edit_user'),
+    url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('award/')), app.users.award_points, name='user_award_points'),
     url(r'^%s(?P<id>\d+)/%s(?P<action>[a-z]+)/(?P<status>[a-z]+)/$' % (_('users/'), _('powers/')), app.users.user_powers, name='user_powers'),
-    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('subscriptions/')), app.users.user_subscriptions, name='user_subscriptions'),
+    url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('subscriptions/')), app.users.user_subscriptions, name='user_subscriptions'),
     url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('favorites/')), app.users.user_favorites, name='user_favorites'),
     url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('reputation/')), app.users.user_reputation, name='user_reputation'),
     url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('votes/')), app.users.user_votes, name='user_votes'),
index 23059e2f7a11fda1f919047d5d732225bc6d6e94..6b7f5d1703f64d53f45660e15c8febab0895bbc2 100644 (file)
@@ -304,7 +304,8 @@ def auth_settings(request, id):
         })
 
     return render_to_response('auth/auth_settings.html', {
-        'user': user_,
+        'view_user': user_,
+        "can_view_private": (user_ == request.user) or request.user.is_superuser,
         'form': form,
         'has_password': user_.has_usable_password(),
         'auth_keys': auth_keys_list,
index f9929ffacde158b7175c91f441d139f160e02853..90bb2b2a89820423bb988f1efb8fcda580001558 100644 (file)
@@ -75,8 +75,8 @@ def command(func):
 \r
             response['success'] = True\r
         except Exception, e:\r
-            #import sys, traceback\r
-            #traceback.print_exc(file=sys.stdout)\r
+            import sys, traceback\r
+            traceback.print_exc(file=sys.stdout)\r
 \r
             if isinstance(e, CommandException):\r
                 response = {\r
index 3e624ea8a2c9df51bd218084617a2189aaa43229..6818974213892e49704d58e4ee536d971003e584 100644 (file)
@@ -17,7 +17,7 @@ from forum.forms import *
 from forum.utils.html import sanitize_html\r
 from datetime import date\r
 import decorators\r
-from forum.actions import EditProfileAction, FavoriteAction\r
+from forum.actions import EditProfileAction, FavoriteAction, BonusRepAction\r
 \r
 import time\r
 \r
@@ -133,6 +133,24 @@ def user_powers(request, id, action, status):
     return HttpResponseRedirect(user.get_profile_url())\r
 \r
 \r
+@decorators.command\r
+def award_points(request, id):\r
+    if (not request.POST) and request.POST.get('points', None):\r
+        raise decorators.CommandException(_("Invalid request type"))\r
+\r
+    if not request.user.is_superuser:\r
+        raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
+\r
+    user = get_object_or_404(User, id=id)\r
+    points = int(request.POST['points'])\r
+\r
+    extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
+\r
+    BonusRepAction(user=user, extra=extra).save(data=dict(value=points))\r
+\r
+    return dict(reputation=user.reputation)\r
+\r
+\r
 def user_view(template, tab_name, tab_description, page_title, private=False):\r
     def decorator(fn):\r
         def decorated(request, id, slug=None):\r