]> git.openstreetmap.org Git - osqa.git/commitdiff
New optional admin interface, and closing OSQA 253.
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Thu, 13 May 2010 13:19:20 +0000 (13:19 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Thu, 13 May 2010 13:19:20 +0000 (13:19 +0000)
git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@254 0cfe37f9-358a-4d5e-be75-b63607b5c754

20 files changed:
forum/actions/user.py
forum/models/action.py
forum/settings/__init__.py
forum/settings/basic.py
forum/settings/forms.py
forum/settings/sidebar.py
forum/skins/default/media/style/admin.css
forum/skins/default/media/style/djstyle_admin.css [new file with mode: 0644]
forum/skins/default/templates/auth/signin.html
forum/skins/default/templates/auth/signup.html [deleted file]
forum/skins/default/templates/osqaadmin/base.html
forum/skins/default/templates/osqaadmin/dashboard.html [new file with mode: 0644]
forum/skins/default/templates/osqaadmin/djstyle_base.html [new file with mode: 0644]
forum/skins/default/templates/osqaadmin/graph.html [new file with mode: 0644]
forum/skins/default/templates/osqaadmin/set.html
forum/skins/default/templates/osqaadmin/statistics.html [new file with mode: 0644]
forum/skins/default/templates/users/votes.html
forum/urls.py
forum/views/admin.py
tmp/README [new file with mode: 0644]

index 0e894ba0260136e0be08177e88ca2836b9d3bdb8..74771a6463fca174b7087a0155127edb814d9340 100644 (file)
@@ -3,13 +3,25 @@ from django.db.models import F
 from forum.models.action import ActionProxy
 from forum.models import Award
 from forum import settings
+from forum.settings import APP_SHORT_NAME
 
 class UserJoinsAction(ActionProxy):
     def repute_users(self):
         self.repute(self.user, int(settings.INITIAL_REP))
 
+    def describe(self, viewer=None):
+        return _("%(user)s as joined the %(app_name)s Q&A community") % {
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+            'app_name': APP_SHORT_NAME,
+        }
+
 class EditProfileAction(ActionProxy):
-    pass
+    def describe(self, viewer=None):
+        return _("%(user)s edited %(hes_or_your)s %(profile_link)s") % {
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+            'hes_or_your': self.viewer_or_user_verb(viewer, self.user, _('your'), _('hes')),
+            'profile_link': self.hyperlink(self.user.get_profile_url(), _('profile')),
+        }
 
 class AwardAction(ActionProxy):
     def process_data(self, badge, trigger):
index 9a6f5ae43b19971ed37d823b28721573fc2efd83..785ed2da965a5461e794f97fcade2cc476068b65 100644 (file)
@@ -70,7 +70,7 @@ class Action(models.Model):
         return ""\r
 \r
     def describe(self, viewer=None):\r
-        return ""\r
+        return self.__class__.__name__\r
 \r
     def get_absolute_url(self):\r
         if self.node:\r
index 5306aa7868f363a24531331bb5a6601a67310f70..caf0eaf1505f0945b8d3d0e5711a33bff9fedccb 100644 (file)
@@ -8,8 +8,11 @@ from django.conf import settings as djsettings
 from django.utils.version import get_svn_revision
 
 OSQA_VERSION = "Development Build"
-SVN_REVISION = get_svn_revision(djsettings.SITE_SRC_ROOT) 
+SVN_REVISION = get_svn_revision(djsettings.SITE_SRC_ROOT)
+
 SETTINGS_PACK = Setting('SETTINGS_PACK', "default")
+DJSTYLE_ADMIN_INTERFACE = Setting('DJSTYLE_ADMIN_INTERFACE', True)
+
 APP_URL = djsettings.APP_URL
 FORUM_SCRIPT_ALIAS = djsettings.FORUM_SCRIPT_ALIAS
 
index 844947cbfc9fa7b4423d12f6571207cdeed4a55c..a3382b1898b271f04087a810c818001e13abe6ce 100644 (file)
@@ -35,11 +35,6 @@ label = _("Application description"),
 help_text = _("The description of your application"),\r
 widget=Textarea))\r
 \r
-APP_INTRO = Setting('APP_INTRO', u'<p>Ask and answer questions, make the world better!</p>', BASIC_SET, dict(\r
-label = _("Application intro"),\r
-help_text = _("The introductory page that is visible in the sidebar for anonymous users."),\r
-widget=Textarea))\r
-\r
 APP_COPYRIGHT = Setting('APP_COPYRIGHT', u'Copyright OSQA, 2010. Some rights reserved under creative commons license.', BASIC_SET, dict(\r
 label = _("Copyright notice"),\r
 help_text = _("The copyright notice visible at the footer of your page.")))\r
@@ -49,7 +44,3 @@ label = _("Feedback site url"),
 help_text = _("If you have a specific place to get feedback from your users, use this field and the fedback link on the footer will point there."),\r
 required=False))\r
 \r
-SHOW_WELCOME_BOX = Setting('SHOW_WELCOME_BOX', True, BASIC_SET, dict(\r
-label = _("Show the Welcome box"),\r
-help_text = _("Do you want to show the welcome box when a user first visits your site."),\r
-required=False))\r
index 81e5446583ff8cd66d0a8f15ddae5e5afa4c3bb3..15bbef669413603f9f3a9447f6a3a28e87e95831 100644 (file)
@@ -22,6 +22,8 @@ class SettingsSetForm(forms.Form):
 
         for setting in set:
             if isinstance(setting, (Setting.emulators.get(str, DummySetting), Setting.emulators.get(unicode, DummySetting))):
+                if not setting.field_context.get('widget', None):
+                    setting.field_context['widget'] = forms.TextInput(attrs={'class': 'longstring'})
                 field = forms.CharField(**setting.field_context)
             elif isinstance(setting, Setting.emulators.get(float, DummySetting)):
                 field = forms.FloatField(**setting.field_context)
index 031763a7632946ce08677c0e802629e4eb98cbb1..2ff349e91c0dcd6da24babbf2291d86df657be4a 100644 (file)
@@ -1,8 +1,20 @@
 from base import Setting, SettingSet
 from django.forms.widgets import Textarea
+from django.utils.translation import ugettext_lazy as _
 
 SIDEBAR_SET = SettingSet('sidebar', 'Sidebar content', "Enter contents to display in the sidebar. You can use markdown and some basic html tags.", 10, True)
 
+SHOW_WELCOME_BOX = Setting('SHOW_WELCOME_BOX', True, SIDEBAR_SET, dict(
+label = _("Show the Welcome box"),
+help_text = _("Do you want to show the welcome box when a user first visits your site."),
+required=False))
+
+APP_INTRO = Setting('APP_INTRO', u'<p>Ask and answer questions, make the world better!</p>', SIDEBAR_SET, dict(
+label = _("Application intro"),
+help_text = _("The introductory page that is visible in the sidebar for anonymous users."),
+widget=Textarea))
+
+
 SIDEBAR_UPPER_SHOW = Setting('SIDEBAR_UPPER_SHOW', True, SIDEBAR_SET, dict(
 label = "Show Upper Block",
 help_text = "Check if your pages should display the upper sidebar block.",
index 4fcfad5d21936727382d313ccddfb9fd342a2713..51bf9190e7688119fb3b06efddd53bdd6564411a 100644 (file)
 .string_list_widget_button.add {
     position: relative;
     left: 554px;
+}
+
+table caption {
+    font-size: 120%;
+       padding: 3px 0;
+    text-align: left;
 }
\ No newline at end of file
diff --git a/forum/skins/default/media/style/djstyle_admin.css b/forum/skins/default/media/style/djstyle_admin.css
new file mode 100644 (file)
index 0000000..5b2965b
--- /dev/null
@@ -0,0 +1,7 @@
+textarea {
+    width: 100%;
+}
+
+input.longstring {
+    width: 100%;
+}
\ No newline at end of file
index 6f653f8b3073bc7e714038334f1878b6a2d555b2..e5d8fdbddcb8fe73d2f7c2d7ba5747385178d320 100644 (file)
@@ -24,7 +24,7 @@
            {% trans "User login" %}\r
     </div>\r
     {% if msg %}\r
-        <p class="warning">{{ msg }}</p>\r
+        <p class="error">{{ msg }}</p>\r
     {% endif %}\r
     {% for provider in top_stackitem_providers %}\r
         <form class="signin_form" method="POST" action="{% url auth_provider_signin provider=provider.id %}">\r
diff --git a/forum/skins/default/templates/auth/signup.html b/forum/skins/default/templates/auth/signup.html
deleted file mode 100644 (file)
index cb1ebbf..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-{% extends "base_content.html" %}
-<!--signup.html-->
-{% load i18n %}
-{% block title %}{% spaceless %}{% trans "Signup" %}{% endspaceless %}{% endblock %}
-
-{% block content %}
-<div class="headNormal">
-    {% trans "Create login name and password" %}
-</div>
-<p class="message">{% trans "Traditional signup info" %}</p>
-<form action="" method="post" accept-charset="utf-8">
-    <ul class="form-horizontal-rows">
-    <li><label for="usename_id">{{form.username.label}}</label>{{form.username}}{{form.username.errors}}</li>
-    <li><label for="email_id">{{form.email.label}}</label>{{form.email}}{{form.email.errors}}</li>
-    <li><label for="password1_id">{{form.password1.label}}</label>{{form.password1}}{{form.password1.errors}}</li>
-    <li><label for="password2_id">{{form.password2.label}}</label>{{form.password2}}{{form.password2.errors}}</li>
-    </ul>
-    <p class="margin-top">{% trans "receive updates motivational blurb" %}</p>
-    <div class='simple-subscribe-options'>
-    {{ email_feeds_form.subscribe }}
-    {% if email_feeds_form.errors %}
-    <p class="error">{% trans "please select one of the options above" %}</p>
-    {% endif %}
-    </div>
-    <div>
-    {% for field in form.anti_spam_fields %}
-        <div>{{ field }}</div>
-        <p class="error">{{ field.errors }}</p>
-    {% endfor %}
-    </div>
-    <div class="submit-row"><input type="submit" class="submit" value="{% trans "Create Account" %}" /> 
-    <strong>{% trans "or" %}
-    <a href="{% url auth_signin %}">{% trans "return to login page" %}</a></strong></div>
-</form>
-{% endblock %}
-<!--end signup.html-->
index 2acdc15d6ec993ea238f3d30f83fae4cea7b65df..e9f654bb52abcd1cbf76f7f93cb03b743199bdae 100644 (file)
@@ -24,6 +24,7 @@
 \r
 {% block sidebar %}\r
     <div class="boxC">\r
+        <a href="{% url admin_switch_interface %}?to=djstyle">{% trans "Switch to django style interface" %}</a>\r
         <h3 class="subtitle">{% trans "Administration menu" %}</h3>\r
         <ul>\r
         {% for set in sets %}\r
diff --git a/forum/skins/default/templates/osqaadmin/dashboard.html b/forum/skins/default/templates/osqaadmin/dashboard.html
new file mode 100644 (file)
index 0000000..3cd1da9
--- /dev/null
@@ -0,0 +1,78 @@
+{% extends basetemplate %}
+
+{% load i18n %}
+{% load user_tags %}
+
+{% block subtitle %}
+    {% trans "Dashboard" %}
+{% endblock %}
+{% block description %}
+    {% trans "Welcome to the OSQA administration area." %}
+{% endblock %}
+
+{% block admincontent %}
+    <div class="module" style="width:49%; display: inline-block; vertical-align: top;">
+        <table style="width: 100%; height: 100%;">
+            <caption>{% trans "Quick statistics"  %}</caption>
+            <tr>
+                <td>
+                {{ statistics.total_questions }} {% trans "question" %}{{ statistics.total_questions|pluralize }} ({{ statistics.questions_last_24 }} {% trans "in the last 24 hours" %})
+                </td>
+            </tr>
+            <tr>
+                <td>
+                {{ statistics.total_answers }} {% trans "answer" %}{{ statistics.total_answers|pluralize }} ({{ statistics.answers_last_24 }} {% trans "in the last 24 hours" %})
+                </td>
+            </tr>
+            <tr>
+                <td>
+                {{ statistics.total_users }} {% trans "user" %}{{ statistics.total_users|pluralize }} ({{ statistics.users_last_24 }} {% trans "joined in the last 24 hours" %})
+                </td>
+            </tr>
+        </table>
+    </div>
+    <div class="module" style="width:49%; display: inline-block;">
+        <table>
+        <caption>{%trans "Site status" %}</caption>
+            <tr>
+                <td>
+                    {% ifequal settings_pack "bootstrap" %}
+                        {% trans "Your site is running in bootstrap mode, click the button below to revert to defaults." %}<br />
+                    {% else %}
+                        {% ifequal settings_pack "default" %}
+                            {% trans "Your site is running in standard mode, click the button below to run in bootstrap mode." %}<br />
+                        {% else %}
+                            {% trans "Your site is running with some customized settings, click the buttons below to run with defaults or in bootstrap mode" %}
+                        {% endifequal %}
+                    {% endifequal %}
+                    {% ifnotequal settings_pack "default" %}
+                        <button onclick="if (window.confirm('{% trans "Are you sure you want to revert to the defaults?" %}')) window.location='{% url admin_go_defaults %}';">{% trans "revert to defaults" %}</button>
+                    {% endifnotequal %}
+                    {% ifnotequal settings_pack "bootstrap" %}
+                        <button onclick="if (window.confirm('{% trans "Are you sure you want to run bootstrap mode?" %}')) window.location='{% url admin_go_bootstrap %}';">{% trans "go bootstrap" %}</button>
+                    {% endifnotequal %}
+                </td>
+            </tr>
+            <tr>
+                <td>
+                    <em>"Bootstrap mode" relaxes the minimum required reputation to perform actions like voting and commenting.
+                    This is useful to help new communities get started.</em>
+                </td>
+            </tr>
+        </table>
+    </div>
+    <div class="module" style="width:98%; display: inline-block;">
+        <table width="100%">
+        <caption>{% trans "Recent activity" %}</caption>
+            <tr>
+                <td colspan="2">
+                    <table width="100%">
+                    {% for activity in recent_activity %}
+                        <tr><td>{% activity_item activity request.user %}</td></tr>
+                    {% endfor %}
+                    </table>
+                </td>
+            </tr>
+        </table>
+    </div>
+{% endblock %}
\ No newline at end of file
diff --git a/forum/skins/default/templates/osqaadmin/djstyle_base.html b/forum/skins/default/templates/osqaadmin/djstyle_base.html
new file mode 100644 (file)
index 0000000..aeb6542
--- /dev/null
@@ -0,0 +1,103 @@
+{% load extra_tags %}
+{% load i18n %}
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    <link rel="stylesheet" href="{{ settings.ADMIN_MEDIA_PREFIX }}css/base.css" type="text/css"/>
+    <link rel="stylesheet" href="{{ settings.ADMIN_MEDIA_PREFIX }}css/forms.css" type="text/css"/>
+    <link rel="stylesheet" href="{{ settings.ADMIN_MEDIA_PREFIX }}css/changelists.css" type="text/css"/>
+    <link rel="stylesheet" type="text/css" media="screen" href="{% media "/media/style/djstyle_admin.css" %}"/>
+    <script src="http://www.google.com/jsapi" type="text/javascript"></script>
+    <script type="text/javascript">
+    //<!--
+        google.load("jquery", "1.3");
+    //-->
+    </script>
+    <script type="text/javascript" src="{% media "/media/js/osqa.admin.js" %}"></script>
+    {% block adminjs %}{% endblock %}
+    <title>{% trans "OSQA administration area" %} - {% block subtitle %}{% endblock %}</title>
+</head>
+<body>
+<div id="container">
+        <div id="header">
+            {% block header %}
+            <div id="branding">
+                <h1 id="site-name"><a href="{% url index %}">{{ settings.APP_SHORT_NAME }} - {% trans "Administration Area" %}</a> </h1>
+            </div>
+            {% endblock %}
+            <div id="user-tools">
+                {% trans "Welcome," %}
+                <strong>{{ request.user.username }}</strong>.
+                <a href="{% url admin_switch_interface %}?to=default">{% trans "To standard interface" %}</a> / <a href="{% url logout %}">{% trans "Log out" %}</a>
+            </div>
+        </div>
+        <div class="breadcrumbs">
+            <a href="{% url index %}">{% trans "Home" %}</a> &gt
+            <a href="{% url admin_index %}">{% trans "Dashboard" %}</a> &gt;
+            {% block pagename %}{% endblock %} - 
+            {% block description %}{% endblock %}
+        </div>
+        <div id="content" class="colMS">
+            <div id="content-main">
+                {% block admincontent %}{% endblock %}
+            </div>
+            <div id="content-related">
+                <div id="basic-sets-menu" class="module">
+                    <h2>{% trans "Basic settings" %}</h2>
+                    <ul>
+                        <li><a href="{% url admin_set allsets.basic.name %}">{{ allsets.basic.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.users.name %}">{{ allsets.users.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.email.name %}">{{ allsets.email.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.paths.name %}">{{ allsets.paths.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.extkeys.name %}">{{ allsets.extkeys.title }}</a></li>
+                    </ul>
+                </div>
+                <div id="workflow-sets-menu" class="module">
+                    <h2>{% trans "Workflow settings" %}</h2>
+                    <ul>
+                        <li><a href="{% url admin_set allsets.repgain.name %}">{{ allsets.repgain.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.minrep.name %}">{{ allsets.minrep.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.voting.name %}">{{ allsets.voting.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.badges.name %}">{{ allsets.badges.title }}</a></li>
+                    </ul>
+                </div>
+                <div id="forum-sets-menu" class="module">
+                    <h2>{% trans "Forum settings" %}</h2>
+                    <ul>
+                        <li><a href="{% url admin_set allsets.form.name %}">{{ allsets.form.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.moderation.name %}">{{ allsets.moderation.title }}</a></li>
+                    </ul>
+                </div>
+                <div id="pages-sets-menu" class="module">
+                    <h2>{% trans "Static content" %}</h2>
+                    <ul>
+                        <li><a href="{% url admin_set allsets.about.name %}">{{ allsets.about.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.faq.name %}">{{ allsets.faq.title }}</a></li>
+                        <li><a href="{% url admin_set allsets.sidebar.name %}">{{ allsets.sidebar.title }}</a></li>
+                    </ul>
+                </div>
+                <div id="other-sets-menu" class="module">
+                    <h2>{% trans "Other settings" %}</h2>
+                    <ul>
+                    {% for set in othersets %}
+                        <li><a href="{% url admin_set set.name %}">{{ set.title }}</a></li>
+                    {% endfor %}
+                    </ul>
+                </div>
+                {% comment %}<div id="tools-menu" class="module">
+                    <h2>{% trans "Tools" %}</h2>
+                    <ul>
+                        <li><a href="{% url admin_statistics %}">{% trans "Statistics" %}</a></li>
+                    </ul>
+                </div>{% endcomment %}
+            </div>
+        </div>
+        <div id="footer" class="breadcumbs">
+            <a href="http://www.osqa.net">OSQA</a> <span class="version">{{ settings.OSQA_VERSION }}</span>
+        </div>
+    </div>
+</body>
\ No newline at end of file
diff --git a/forum/skins/default/templates/osqaadmin/graph.html b/forum/skins/default/templates/osqaadmin/graph.html
new file mode 100644 (file)
index 0000000..ee84f9e
--- /dev/null
@@ -0,0 +1,10 @@
+<div class="module" style="width:385px; height:300px; display: inline-block;">
+    <table style="width: 100%; height: 100%">
+        <caption>{{ graph.caption }}</caption>
+        <tr>
+            <td>
+                <div style="width: 100%; height: 100%" id="{{ graph.id }}"></div>
+            </td>
+        </tr>
+    </table>
+</div>
\ No newline at end of file
index 9735de6f7ad237ccbd988a0424cad1c2dad9e325..04e20d857c6c6ec92f4349f96327e6cad3ac762c 100644 (file)
@@ -1,15 +1,15 @@
-{% extends "osqaadmin/base.html" %}\r
+{% extends basetemplate %}\r
 \r
 {% load i18n %}\r
 {% load extra_tags %}\r
 \r
-{% block title %}{{ form.set.title }}{% endblock %}\r
 {% block subtitle %}{{ form.set.title }}{% endblock %}\r
+{% block pagename %}{{ form.set.title }}{% endblock %}\r
 {% block description %}{{ form.set.description }}{% endblock %}\r
 \r
 {% block admincontent %}\r
     <form action="" method="POST" enctype="multipart/form-data" accept-charset="utf-8">\r
-        <table id="admin_form">\r
+        <table id="admin_form" style="width: 100%">\r
             {{ form.as_table }}\r
             <tr>\r
                 <th></th>\r
diff --git a/forum/skins/default/templates/osqaadmin/statistics.html b/forum/skins/default/templates/osqaadmin/statistics.html
new file mode 100644 (file)
index 0000000..e012522
--- /dev/null
@@ -0,0 +1,33 @@
+{% extends basetemplate %}
+
+{% load i18n %}
+{% load extra_tags %}
+
+{% block adminjs %}
+<script type='text/javascript' src='{% media  "/media/js/excanvas.min.js" %}'></script>
+<script type='text/javascript' src='{% media  "/media/js/jquery.flot.min.js" %}'></script>
+<script type="text/javascript">
+        $().ready(function(){
+        {% for graph in graphs %}
+            var {{ graph.id }} = {{ graph.data }};
+            var {{ graph.id }}_placeholder = $('#{{ graph.id }}');
+
+            $.plot({{ graph.id }}_placeholder, [{{ graph.id }}], {
+                xaxis: { mode: "time" },
+                points: { show: false },
+                lines: { show: true }
+            });
+        {% endfor %}
+        });
+</script>
+{% endblock %}
+
+{% block subtitle %}{% trans "Dashboard" %}{% endblock %}
+{% block pagename %}{% trans "Dashboard" %}{% endblock %}
+{% block description %}{% trans "Some simple graphics to help you get a notion of whats going on in your site." %}{% endblock %}
+
+{% block admincontent %}
+{% for graph in graphs %}
+    {% include "osqaadmin/graph.html" %}
+{% endfor %}
+{% endblock %}
\ No newline at end of file
index a6cc64f365d0d2fd747ca7fff4514ca14c9ab986..7d6b3483c1b34771cead7aca88df9a50231b91f3 100644 (file)
@@ -18,7 +18,7 @@
                 {% endifequal %}
                 </div>
                 <div style="float:left;overflow:hidden;width:750px">
-                    <span class="{{ vote.node.node_type }}-title-link"><a href="{{ vote.node.leaf.get_absolute_url }}">{{ vote.node.leaf.headline }}</a></span>
+                    <span class="{{ vote.node.node_type }}-title-link"><a href="{{ vote.node.get_absolute_url }}">{{ vote.node.headline }}</a></span>
                     <div style="height:5px"></div>
                 </div>          
             </div>
index 0155406b78ae71a802f87515b44fb0e72c443f59..c038ea6129d5495f690ee99eec6dab9f45592adb 100644 (file)
@@ -75,7 +75,7 @@ urlpatterns += patterns('',
     #place general question item in the end of other operations
     url(r'^%s(?P<id>\d+)/(?P<slug>[\w-]*)$' % _('question/'), app.readers.question, name='question'),
     url(r'^%s$' % _('tags/'), app.readers.tags, name='tags'),
-    url(r'^%s(?P<tag>[^/]+)/$' % _('tags/'), app.readers.tag, name='tag_questions'),
+    url(r'^%s(?P<tag>.*)/$' % _('tags/'), app.readers.tag, name='tag_questions'),
 
     url(r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('interesting/')), app.commands.mark_tag, \
                                 kwargs={'reason':'good','action':'add'}, \
@@ -126,7 +126,9 @@ urlpatterns += patterns('',
     url(r'^%s%s%s$' % (_('account/'), _('providers/'),  _('add/')), app.auth.signin_page, name='user_add_external_provider'),
 
 
-    url(r'^%s$' % _('admin/'), app.admin.index, name="admin_index"),
+    url(r'^%s$' % _('admin/'), app.admin.dashboard, name="admin_index"),
+    url(r'^%s%s$' % (_('admin/'), _('switch_interface/')), app.admin.interface_switch, name="admin_switch_interface"),
+    url(r'^%s%s$' % (_('admin/'), _('statistics/')), app.admin.statistics, name="admin_statistics"),
     url(r'^%s%s$' % (_('admin/'), _('denormalize/')), app.admin.recalculate_denormalized, name="admin_denormalize"),
     url(r'^%s%s$' % (_('admin/'), _('go_bootstrap/')), app.admin.go_bootstrap, name="admin_go_bootstrap"),
     url(r'^%s%s$' % (_('admin/'), _('go_defaults/')), app.admin.go_defaults, name="admin_go_defaults"),
index 126a348c735fada04184b24ee04921d37e1ea39c..dd1f3f5a4a472c30a1b6f6587a1c4d6f2ef7b662 100644 (file)
@@ -1,10 +1,12 @@
 from datetime import datetime, timedelta
+import time
 
 from django.shortcuts import render_to_response
 from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
 from django.template import RequestContext
 from django.utils.translation import ugettext as _
+from django.utils import simplejson
 from django.db.models import Sum
 
 from forum.settings.base import Setting
@@ -18,20 +20,84 @@ def super_user_required(fn):
         if request.user.is_authenticated() and request.user.is_superuser:
             return fn(request, *args, **kwargs)
         else:
-            raise Http404
+            return HttpResponseForbidden()
 
     return wrapper
 
-@super_user_required
-def index(request):
-    return render_to_response('osqaadmin/index.html', {
-        'sets': get_all_sets(),
+def admin_page(fn):
+    @super_user_required
+    def wrapper(request, *args, **kwargs):
+        res = fn(request, *args, **kwargs)
+        if isinstance(res, tuple):
+            template, context = res
+            context['basetemplate'] = settings.DJSTYLE_ADMIN_INTERFACE and "osqaadmin/djstyle_base.html" or "osqaadmin/base.html"
+            context['allsets'] = Setting.sets
+            context['othersets'] = sorted(
+                    [s for s in Setting.sets.values() if not s.name in
+                    ('basic', 'users', 'email', 'paths', 'extkeys', 'repgain', 'minrep', 'voting', 'badges', 'about', 'faq', 'sidebar',
+                    'form', 'moderation')]
+                    , lambda s1, s2: s1.weight - s2.weight)
+            return render_to_response(template, context, context_instance=RequestContext(request))
+        else:
+            return res
+
+    return wrapper
+
+@admin_page
+def dashboard(request):
+    return ('osqaadmin/dashboard.html', {
         'settings_pack': unicode(settings.SETTINGS_PACK),
         'statistics': get_statistics(),
         'recent_activity': get_recent_activity(),
-    }, context_instance=RequestContext(request))
+    })
+
+@super_user_required
+def interface_switch(request):
+    if request.GET and request.GET.get('to', None) and request.GET['to'] in ('default', 'djstyle'):
+        settings.DJSTYLE_ADMIN_INTERFACE.set_value(request.GET['to'] == 'djstyle')
 
-@super_user_required    
+    return HttpResponseRedirect(reverse('admin_index'))
+
+@admin_page
+def statistics(request):
+    today = datetime.now()
+    last_month = today - timedelta(days=30)
+
+    last_month_questions = Question.objects.filter(deleted=None, added_at__gt=last_month
+                                                  ).order_by('added_at').values_list('added_at', flat=True)
+
+    last_month_n_questions = Question.objects.filter(deleted=None, added_at__lt=last_month).count()
+    qgraph_data = simplejson.dumps([
+            (time.mktime(d.timetuple()) * 1000, i + last_month_n_questions)
+            for i, d in enumerate(last_month_questions)
+    ])
+
+    last_month_users = User.objects.filter(date_joined__gt=last_month
+                                                  ).order_by('date_joined').values_list('date_joined', flat=True)
+
+    last_month_n_users = User.objects.filter(date_joined__lt=last_month).count()
+
+    ugraph_data = simplejson.dumps([
+            (time.mktime(d.timetuple()) * 1000, i + last_month_n_users)
+            for i, d in enumerate(last_month_users)
+    ])
+
+    return 'osqaadmin/statistics.html', {
+        'graphs': [
+            {
+                'id': 'questions_graph',
+                'caption': _("Questions Graph"),
+                'data': qgraph_data
+            },{
+                'id': 'userss_graph',
+                'caption': _("Users Graph"),
+                'data': ugraph_data
+            }
+        ]
+    }
+
+
+@admin_page
 def settings_set(request, set_name):
     set = Setting.sets.get(set_name, None)
 
@@ -52,14 +118,11 @@ def settings_set(request, set_name):
     else:
         form = SettingsSetForm(set)
 
-    return render_to_response('osqaadmin/set.html', {
+    return 'osqaadmin/set.html', {
         'form': form,
         'markdown': set.markdown,
-        'sets': get_all_sets(),
-    }, context_instance=RequestContext(request))
+    }
 
-def get_all_sets():
-    return sorted(Setting.sets.values(), lambda s1, s2: s1.weight - s2.weight)
 
 def get_recent_activity():
     return Action.objects.order_by('-action_date')[0:30]
@@ -74,7 +137,7 @@ def get_statistics():
         'answers_last_24': Answer.objects.filter(deleted=None, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
     }
 
-@super_user_required      
+@super_user_required
 def go_bootstrap(request):
     #todo: this is the quick and dirty way of implementing a bootstrap mode
     try:
diff --git a/tmp/README b/tmp/README
new file mode 100644 (file)
index 0000000..708174a
--- /dev/null
@@ -0,0 +1 @@
+Just an empty placeholder.
\ No newline at end of file