]> git.openstreetmap.org Git - osqa.git/commitdiff
Adds the option to create static pages with several options to customize its behaviour.
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Mon, 7 Jun 2010 01:56:21 +0000 (01:56 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Mon, 7 Jun 2010 01:56:21 +0000 (01:56 +0000)
git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@381 0cfe37f9-358a-4d5e-be75-b63607b5c754

32 files changed:
forum/actions/__init__.py
forum/actions/meta.py
forum/actions/page.py [new file with mode: 0644]
forum/actions/user.py
forum/forms/__init__.py [new file with mode: 0644]
forum/forms/admin.py [new file with mode: 0644]
forum/forms/auth.py [moved from forum/authentication/forms.py with 96% similarity]
forum/forms/general.py [moved from forum/utils/forms.py with 100% similarity]
forum/forms/qanda.py [moved from forum/forms.py with 98% similarity]
forum/middleware/anon_user.py
forum/middleware/cancel.py
forum/models/__init__.py
forum/models/node.py
forum/models/page.py [new file with mode: 0644]
forum/settings/__init__.py
forum/settings/forms.py
forum/skins/default/media/js/osqa.admin.js
forum/skins/default/templates/osqaadmin/djstyle_base.html
forum/skins/default/templates/osqaadmin/edit_page.html [new file with mode: 0644]
forum/skins/default/templates/osqaadmin/static_pages.html [new file with mode: 0644]
forum/skins/default/templates/page.html [new file with mode: 0644]
forum/urls.py
forum/views/admin.py
forum/views/auth.py
forum/views/commands.py
forum/views/meta.py
forum/views/readers.py
forum/views/users.py
forum/views/writers.py
forum_modules/localauth/forms.py
forum_modules/localauth/views.py
manage.py

index a68106994501385853ebe1f9f2c712323bbbc806..4c6c6784b30ef42f2923805e2260430ad6041309 100644 (file)
@@ -1,3 +1,4 @@
 from meta import *\r
 from node import *\r
 from meta import *\r
 from node import *\r
-from user import *
\ No newline at end of file
+from user import *\r
+from page import *
\ No newline at end of file
index adf51ca933c63fdf26d2b4a89aa8d4acb4f7c883..ccdaa75f390396d09b2687b95e1277f3b450e9b9 100644 (file)
@@ -157,7 +157,7 @@ class AcceptAnswerAction(ActionProxy):
 \r
         return _("%(user)s accepted %(answerer)s answer on %(asker)s question %(question)s") % {\r
             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
 \r
         return _("%(user)s accepted %(answerer)s answer on %(asker)s question %(question)s") % {\r
             'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
-            'answerer': self.hyperlink(answer.author.get_profile_url(), self.friendly_username(viewer, answer.author)),\r
+            'answerer': self.hyperlink(answer.author.get_profile_url(), self.friendly_ownername(viewer, answer.author)),\r
             'asker': asker,\r
             'question': self.hyperlink(question.get_absolute_url(), question.title)\r
         }\r
             'asker': asker,\r
             'question': self.hyperlink(question.get_absolute_url(), question.title)\r
         }\r
diff --git a/forum/actions/page.py b/forum/actions/page.py
new file mode 100644 (file)
index 0000000..bfeda16
--- /dev/null
@@ -0,0 +1,58 @@
+from django.utils.translation import ugettext as _
+from forum.models.action import ActionProxy
+from forum.models import Page
+
+class NewPageAction(ActionProxy):
+    verb = _("created")
+
+    def process_data(self, **data):
+        title = data.pop('title')
+        body = data.pop('content')
+
+        page = Page(author=self.user, title=title, body=body, extra=data)
+        page.save()
+        self.node = page
+
+    def describe(self, viewer=None):
+        return _("%(user)s created a new page titled %(page)s") % {
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+            'page': self.hyperlink(self.node.get_absolute_url(), self.node.title)
+        }
+
+class EditPageAction(ActionProxy):
+    verb = _("edited")
+
+    def process_data(self, **data):
+        title = data.pop('title')
+        body = data.pop('content')
+
+        if (title != self.node.title) and (body != self.node.body):
+            self.node.create_revision(self.user, title=title, body=body)
+
+        self.node.extra = data
+        self.node.save()
+
+    def describe(self, viewer=None):
+        return _("%(user)s edited the page titled %(page)s") % {
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+            'page': self.hyperlink(self.node.get_absolute_url(), self.node.title)
+        }
+
+class PublishAction(ActionProxy):
+    verb = _("published")
+
+    def process_action(self):
+        self.node.marked = True
+        self.node.nstate.published = self
+        self.node.save()
+
+    def cancel_action(self):
+        self.node.marked = False
+        self.node.nstate.published = None
+        self.node.save()
+
+    def describe(self, viewer=None):
+        return _("%(user)s published a new page titled %(page)s") % {
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+            'page': self.hyperlink(self.node.get_absolute_url(), self.node.title)
+        }
index 6c174cee2e92ed989feee691931b69115f702e28..df90c66f562ffd163ea818597968a96e6550c405 100644 (file)
@@ -24,7 +24,7 @@ class EditProfileAction(ActionProxy):
     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)),
     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')),
+            'hes_or_your': self.viewer_or_user_verb(viewer, self.user, _('your'), _('his')),
             'profile_link': self.hyperlink(self.user.get_profile_url(), _('profile')),
         }
 
             'profile_link': self.hyperlink(self.user.get_profile_url(), _('profile')),
         }
 
diff --git a/forum/forms/__init__.py b/forum/forms/__init__.py
new file mode 100644 (file)
index 0000000..ea5108c
--- /dev/null
@@ -0,0 +1,4 @@
+from qanda import *
+from admin import *
+from auth import *
+from general import *
diff --git a/forum/forms/admin.py b/forum/forms/admin.py
new file mode 100644 (file)
index 0000000..eabeb57
--- /dev/null
@@ -0,0 +1,86 @@
+import socket
+from django import forms
+from django.utils.translation import ugettext as _
+from qanda import TitleField, EditorField
+from forum import settings
+
+class IPListField(forms.CharField):
+    def clean(self, value):
+        ips = [ip.strip() for ip in value.strip().strip(',').split(',')]
+        iplist = []
+
+        if len(ips) < 1:
+            raise forms.ValidationError(_('Please input at least one ip address'))
+
+        for ip in ips:
+            try:
+                socket.inet_aton(ip)
+            except socket.error:
+                raise forms.ValidationError(_('Invalid ip address: %s' % ip))
+
+            if not len(ip.split('.')) == 4:
+                raise forms.ValidationError(_('Please use the dotted quad notation for the ip addresses'))
+
+            iplist.append(ip)
+
+        return iplist
+
+class MaintenanceModeForm(forms.Form):
+    ips = IPListField(label=_('Allow ips'),
+                      help_text=_('Comma separated list of ips allowed to access the site while in maintenance'),
+                      required=True,
+                      widget=forms.TextInput(attrs={'class': 'longstring'}))
+
+    message = forms.CharField(label=_('Message'),
+                              help_text=_('A message to display to your site visitors while in maintainance mode'),
+                              widget=forms.Textarea)
+
+
+TEMPLATE_CHOICES = (
+    ('default', _('Default')),
+    ('sidebar', _('Default with sidebar')),
+    ('none', _('None')),
+)
+
+RENDER_CHOICES = (
+    ('markdown', _('Markdown')),
+    ('html', _('HTML')),
+    ('escape', _('Escaped'))
+)
+
+class UrlFieldWidget(forms.TextInput):
+    def render(self, name, value, attrs=None):
+        if not value:
+            value = ''
+            
+        return """
+                <input class="url_field" type="text" name="%(name)s" value="%(value)s" />
+                <a class="url_field_anchor" target="_blank" href="%(app_url)s%(script_alias)s"></a>
+            """  % {'name': name, 'value': value, 'app_url': settings.APP_URL, 'script_alias': settings.FORUM_SCRIPT_ALIAS}
+
+
+class PageForm(forms.Form):
+
+    def __init__(self, page, *args, **kwargs):
+        if page:
+            initial = page.extra
+            initial.update(dict(title=page.title, content=page.body))
+            super(PageForm, self).__init__(initial=initial, *args, **kwargs)
+        else:
+            super(PageForm, self).__init__(*args, **kwargs)
+
+
+    title  = forms.CharField(label=_('Title'), max_length=255, widget=forms.TextInput(attrs={'class': 'longstring'}), initial='New page')
+    path  = forms.CharField(label=_('Page URL'), widget=UrlFieldWidget, initial='pages/new/')
+
+    content = forms.CharField(label=_('Page Content'), widget=forms.Textarea(attrs={'rows': 30}))
+    render = forms.ChoiceField(widget=forms.RadioSelect, choices=RENDER_CHOICES, initial='markdown', label=_('Render Mode'))
+
+    template = forms.ChoiceField(widget=forms.RadioSelect, choices=TEMPLATE_CHOICES, initial='default', label=_('Template'))
+    sidebar = forms.CharField(label=_('Sidebar Content'), widget=forms.Textarea(attrs={'rows': 20}), required=False)
+    sidebar_wrap = forms.BooleanField(label=_("Wrap sidebar block"), initial=True, required=False) 
+    sidebar_render = forms.ChoiceField(widget=forms.RadioSelect, choices=RENDER_CHOICES, initial='markdown', label=_('Sidebar Render Mode'))
+
+    comments = forms.BooleanField(label=_("Allow comments"), initial=False, required=False)
+
+    
\ No newline at end of file
similarity index 96%
rename from forum/authentication/forms.py
rename to forum/forms/auth.py
index 01c857d8e417a4e42ceead5cfd4f6b90f6d3ca73..594e59f8e526de85326df6fe14d2a2a4a6b88b37 100644 (file)
@@ -1,4 +1,4 @@
-from forum.utils.forms import NextUrlField,  UserNameField,  UserEmailField, SetPasswordForm
+from general import NextUrlField,  UserNameField,  UserEmailField, SetPasswordForm
 from forum.models import Question, User
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import ugettext as _
 from forum.models import Question, User
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import ugettext as _
similarity index 100%
rename from forum/utils/forms.py
rename to forum/forms/general.py
similarity index 98%
rename from forum/forms.py
rename to forum/forms/qanda.py
index 0b865374625542efaa720a6766144cf7108a500b..7c58500975faca4b1f031ccf46948440e7a23224 100644 (file)
@@ -1,13 +1,12 @@
 import re
 from datetime import date
 from django import forms
 import re
 from datetime import date
 from django import forms
-from models import *
+from forum.models import *
 from django.utils.translation import ugettext as _
 from django.contrib.humanize.templatetags.humanize import apnumber
 from django.utils.translation import ugettext as _
 from django.contrib.humanize.templatetags.humanize import apnumber
-from forum.models import User
 
 from django.utils.safestring import mark_safe
 
 from django.utils.safestring import mark_safe
-from forum.utils.forms import NextUrlField, UserNameField, SetPasswordForm
+from general import NextUrlField, UserNameField, SetPasswordForm
 from forum import settings
 import logging
 
 from forum import settings
 import logging
 
@@ -255,6 +254,7 @@ class EditUserForm(forms.Form):
         if self.user.email != self.cleaned_data['email']:
             if settings.EMAIL_UNIQUE == True:
                 if 'email' in self.cleaned_data:
         if self.user.email != self.cleaned_data['email']:
             if settings.EMAIL_UNIQUE == True:
                 if 'email' in self.cleaned_data:
+                    from forum.models import User
                     try:
                         User.objects.get(email = self.cleaned_data['email'])
                     except User.DoesNotExist:
                     try:
                         User.objects.get(email = self.cleaned_data['email'])
                     except User.DoesNotExist:
index a517f664b0e37c8c513cb5445e94a92bb3e8ed54..26c138c8fbc3beeadaea979ac3e046c3b57eea86 100644 (file)
@@ -1,5 +1,5 @@
 from django.http import HttpResponseRedirect
 from django.http import HttpResponseRedirect
-from forum.utils.forms import get_next_url
+from forum.forms import get_next_url
 from django.utils.translation import ugettext as _
 from forum.user_messages import create_message, get_and_delete_messages
 from forum import settings
 from django.utils.translation import ugettext as _
 from forum.user_messages import create_message, get_and_delete_messages
 from forum import settings
index 15a4371dabf83c10b01ebbeda4be3c273b303e0a..2d78a171c5e811ae4c9845a6a06a27ec1e72ec25 100644 (file)
@@ -1,5 +1,5 @@
 from django.http import HttpResponseRedirect
 from django.http import HttpResponseRedirect
-from forum.utils.forms import get_next_url
+from forum.forms import get_next_url
 import logging
 class CancelActionMiddleware(object):
     def process_view(self, request, view_func, view_args, view_kwargs):
 import logging
 class CancelActionMiddleware(object):
     def process_view(self, request, view_func, view_args, view_kwargs):
index 449ca3a8d94a7b5cc5c83681ab24cd5e1b05e949..7a15132362bc0bc70c0d83809d28a37818bc1278 100644 (file)
@@ -7,6 +7,7 @@ from comment import Comment
 from action import Action, ActionRepute
 from meta import Vote, Flag, Badge, Award
 from utils import KeyValue
 from action import Action, ActionRepute
 from meta import Vote, Flag, Badge, Award
 from utils import KeyValue
+from page import Page
 
 try:
     from south.modelsinspector import add_introspection_rules
 
 try:
     from south.modelsinspector import add_introspection_rules
@@ -22,7 +23,7 @@ __all__ = [
         'Answer', 'AnswerRevision',
         'Tag', 'Comment', 'MarkedTag', 'Badge', 'Award',
         'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',
         'Answer', 'AnswerRevision',
         'Tag', 'Comment', 'MarkedTag', 'Badge', 'Award',
         'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',
-        'Action', 'ActionRepute', 'Vote', 'Flag'
+        'Action', 'ActionRepute', 'Vote', 'Flag', 'Page'
         ]
 
 
         ]
 
 
index bf05cb54beb0f24be0ec6d6daf6ee886c5f35aa4..b0f53612493f57952ba91fc9bfa653e3fd46f6ae 100644 (file)
@@ -23,8 +23,12 @@ class NodeContent(models.Model):
     def html(self):
         return self.as_markdown()
 
     def html(self):
         return self.as_markdown()
 
+    @classmethod
+    def _as_markdown(cls, content, *extensions):
+        return mark_safe(sanitize_html(markdown.markdown(content, extensions=extensions)))
+
     def as_markdown(self, *extensions):
     def as_markdown(self, *extensions):
-        return mark_safe(sanitize_html(markdown.markdown(self.body, extensions=extensions)))
+        return self._as_markdown(self.body, *extensions)
 
     @property
     def headline(self):
 
     @property
     def headline(self):
diff --git a/forum/models/page.py b/forum/models/page.py
new file mode 100644 (file)
index 0000000..ff3b1a4
--- /dev/null
@@ -0,0 +1,40 @@
+from base import *
+from django.utils.translation import ugettext as _
+
+class Page(Node):
+    friendly_name = _("page")
+
+    @property
+    def published(self):
+        return self.marked
+
+    def save(self, *args, **kwargs):
+        old_options = self._original_state.get('extra', None)
+
+        super(Page, self).save(*args, **kwargs)
+
+        registry = settings.STATIC_PAGE_REGISTRY
+
+        if old_options:
+            registry.pop(old_options.get('path', ''), None)
+
+        registry[self.extra['path']] = self.id
+
+
+        settings.STATIC_PAGE_REGISTRY.set_value(registry)
+
+    @property
+    def headline(self):
+        if self.published:
+            return self.title
+        else:
+            return _("[Unpublished] %s") % self.title
+
+    @models.permalink
+    def get_absolute_url(self):
+        return ('static_page', (), {'path': self.extra['path']})
+
+    class Meta(Node.Meta):
+        proxy = True
+
+    
\ No newline at end of file
index 95f2441641dc56aca0da2a165ab704c38fda916b..addab2d0e68cc179f8c1e96b202bde880483fe40 100644 (file)
@@ -1,6 +1,5 @@
 import os.path
 from base import Setting, SettingSet
 import os.path
 from base import Setting, SettingSet
-from forms import ImageFormWidget
 
 from django.forms.widgets import Textarea
 from django.utils.translation import ugettext_lazy as _
 
 from django.forms.widgets import Textarea
 from django.utils.translation import ugettext_lazy as _
@@ -18,6 +17,8 @@ DJSTYLE_ADMIN_INTERFACE = Setting('DJSTYLE_ADMIN_INTERFACE', True)
 APP_URL = djsettings.APP_URL
 FORUM_SCRIPT_ALIAS = djsettings.FORUM_SCRIPT_ALIAS
 
 APP_URL = djsettings.APP_URL
 FORUM_SCRIPT_ALIAS = djsettings.FORUM_SCRIPT_ALIAS
 
+STATIC_PAGE_REGISTRY = Setting('STATIC_PAGE_REGISTRY', {})
+
 
 from basic import *
 from sidebar import *
 
 from basic import *
 from sidebar import *
index 27581d5412eb95c3e953865102c1386c545a6184..432ba0b8053d37d1cdea4514deafecfa2ae9a841 100644 (file)
@@ -1,8 +1,7 @@
 import os
 import os
-import socket
 from string import strip
 from django import forms
 from string import strip
 from django import forms
-from base import Setting
+from forum.settings.base import Setting
 from django.utils.translation import ugettext as _
 from django.core.files.storage import FileSystemStorage
 
 from django.utils.translation import ugettext as _
 from django.core.files.storage import FileSystemStorage
 
@@ -110,36 +109,5 @@ class CommaStringListWidget(forms.Textarea):
             return ', '.join(data[name])    
 
 
             return ', '.join(data[name])    
 
 
-class IPListField(forms.CharField):
-    def clean(self, value):
-        ips = [ip.strip() for ip in value.strip().strip(',').split(',')]
-        iplist = []
-
-        if len(ips) < 1:
-            raise forms.ValidationError(_('Please input at least one ip address'))    
-
-        for ip in ips:
-            try:
-                socket.inet_aton(ip)
-            except socket.error:
-                raise forms.ValidationError(_('Invalid ip address: %s' % ip))
-
-            if not len(ip.split('.')) == 4:
-                raise forms.ValidationError(_('Please use the dotted quad notation for the ip addresses'))
-
-            iplist.append(ip)
-
-        return iplist
-
-class MaintenanceModeForm(forms.Form):
-    ips = IPListField(label=_('Allow ips'),
-                      help_text=_('Comma separated list of ips allowed to access the site while in maintenance'),
-                      required=True,
-                      widget=forms.TextInput(attrs={'class': 'longstring'}))
-
-    message = forms.CharField(label=_('Message'),
-                              help_text=_('A message to display to your site visitors while in maintainance mode'),
-                              widget=forms.Textarea)
-
 
 
 
 
index 634f4c8fcfb8694739e24bf54e28b5f69c36f9be..cce64a5daa6acb962e69a2099fd48bffdd1a850a 100644 (file)
@@ -41,4 +41,21 @@ $(function() {
             }\r
         }\r
     });\r
             }\r
         }\r
     });\r
+\r
+    $('.url_field').each(function() {\r
+        var $input = $(this);\r
+        var $anchor = $input.parent().find('.url_field_anchor');\r
+        var app_url = $anchor.attr('href');\r
+\r
+        function rewrite_anchor() {\r
+            var val = app_url + $input.val();\r
+\r
+            $anchor.attr('href', val);\r
+            $anchor.html(val);\r
+\r
+        }\r
+\r
+        $input.keyup(rewrite_anchor);\r
+        rewrite_anchor();        \r
+    });\r
 });
\ No newline at end of file
 });
\ No newline at end of file
index 2d74adf1de217e0db053b950ada16d4628800a4a..7798b49004fb0a829298729bdd4f1cfc27456989 100644 (file)
@@ -38,7 +38,7 @@
             </div>
         </div>
         <div class="breadcrumbs">
             </div>
         </div>
         <div class="breadcrumbs">
-            <a href="{% url index %}">{% trans "Home" %}</a> &gt
+            <a href="{% url index %}">{% trans "Home" %}</a> &gt;
             <a href="{% url admin_index %}">{% trans "Dashboard" %}</a> &gt;
             {% block pagename %}{% endblock %} - 
             {% block description %}{% endblock %}
             <a href="{% url admin_index %}">{% trans "Dashboard" %}</a> &gt;
             {% block pagename %}{% endblock %} - 
             {% block description %}{% endblock %}
@@ -82,6 +82,7 @@
                 <div id="pages-sets-menu" class="module">
                     <h2>{% trans "Static content" %}</h2>
                     <ul>
                 <div id="pages-sets-menu" class="module">
                     <h2>{% trans "Static content" %}</h2>
                     <ul>
+                        <li><a href="{% url admin_static_pages %}">{% trans "Custom Pages" %}</a></li>
                         <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>
                         <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>
diff --git a/forum/skins/default/templates/osqaadmin/edit_page.html b/forum/skins/default/templates/osqaadmin/edit_page.html
new file mode 100644 (file)
index 0000000..269cec8
--- /dev/null
@@ -0,0 +1,32 @@
+{% extends basetemplate %}
+
+{% load i18n %}
+
+{% block subtitle %}{% trans "Editing page" %}{% endblock %}
+{% block pagename %}
+    <a href="{% url admin_static_pages %}">{% trans "Static Pages" %}</a> &gt;
+    {% if page %}{% trans "Editing page" %}{% else %}{% trans "Creating page" %}{% endif %}
+{% endblock %}
+{% block description %}
+    {% if page %}{{ page.title }}{% else %}{% trans "New page" %}{% endif %}
+    ({% if published %}{% trans "Published" %}{% else %}{% trans "Unpublished" %}{% endif %})    
+{% endblock %}
+
+{% block admincontent %}
+    <form action="" method="post" accept-charset="utf-8">
+        <table style="width: 100%">
+        {{ form.as_table }}
+        <tr>
+            <th></th>
+            <td>
+                <input id="submit" name="submit" type="submit" value="{% trans "Save" %}" />
+                {% if published %}
+                    <input id="unpublish" name="unpublish" type="submit" value="{% trans "Unpublish" %}" />
+                {% else %}
+                    <input id="publish" name="publish" type="submit" value="{% trans "Publish" %}" />
+                {% endif %}
+            </td>
+        </tr>
+        </table>
+    </form>
+{% endblock %}
\ No newline at end of file
diff --git a/forum/skins/default/templates/osqaadmin/static_pages.html b/forum/skins/default/templates/osqaadmin/static_pages.html
new file mode 100644 (file)
index 0000000..7d0e567
--- /dev/null
@@ -0,0 +1,28 @@
+{% extends basetemplate %}
+
+{% load i18n %}
+
+{% block subtitle %}{% trans "Static pages" %}{% endblock %}
+{% block pagename %}{% trans "Static pages" %}{% endblock %}
+{% block description %}{% trans "Allows you to create a set of static pages" %}{% endblock %}
+
+{% block admincontent %}
+    <h1>{% trans "Select page to edit" %}</h1>
+    <ul class="object-tools">
+        <li><a class="addlink" href="{% url admin_new_page %}">{% trans "New page" %}</a></li>
+    </ul>
+    <div class="module">
+        <table style="width: 100%">
+            <caption>{% trans "Pages" %}</caption>
+            <tbody>
+                {% for page in pages %}
+                    <tr>
+                        <th scope="row"><a href="{% url admin_edit_page id=page.id %}">{{ page.headline }}</a></th>
+                        <td><a class="changelink" href="{% url admin_edit_page id=page.id %}">{% trans "Edit" %}</a></td>
+                    </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+
+{% endblock %}
\ No newline at end of file
diff --git a/forum/skins/default/templates/page.html b/forum/skins/default/templates/page.html
new file mode 100644 (file)
index 0000000..cf9b459
--- /dev/null
@@ -0,0 +1,27 @@
+{% extends base %}
+{% load i18n markup node_tags general_sidebar_tags %}
+{% block title %}{% spaceless %}{{ page.title }}{% endspaceless %}{% endblock %}
+
+{% block content %}
+<div class="headNormal">{{ page.title }}</div>
+<div class="content">
+{{ body }}
+</div>
+{% if page.extra.comments %}
+    {% comments page request.user %}
+{% endif %}
+{% endblock %}
+
+{% ifequal page.extra.template "sidebar" %}
+    {% block sidebar %}
+        {% sidebar_upper %}
+        {% if page.extra.sidebar %}
+            {% if page.extra.sidebar_wrap %}<div class="boxC"><div class="body">{% endif %}
+                {{ sidebar }}
+            {% if page.extra.sidebar_wrap %}</div></div>{% endif %}
+        {% endif %}
+        {% sidebar_lower %}
+    {% endblock %}
+{% endifequal %}
+
+
index 9ba2ebdcd4d38828d12d3e79951aa95eb2aa7843..e517ddbf71ab6332e0da35fae0d284519c9f3a84 100644 (file)
@@ -140,8 +140,14 @@ urlpatterns += patterns('',
     url(r'^%s%s(?P<set_name>\w+)/(?P<var_name>\w+)/$' % (_('admin/'), _('settings/')), app.admin.get_default, name="admin_default"),
     url(r'^%s%s$' % (_('admin/'), _('maintenance/')), app.admin.maintenance, name="admin_maintenance"),
     url(r'^%s%s$' % (_('admin/'), _('flagged_posts/')), app.admin.flagged_posts, name="admin_flagged_posts"),
     url(r'^%s%s(?P<set_name>\w+)/(?P<var_name>\w+)/$' % (_('admin/'), _('settings/')), app.admin.get_default, name="admin_default"),
     url(r'^%s%s$' % (_('admin/'), _('maintenance/')), app.admin.maintenance, name="admin_maintenance"),
     url(r'^%s%s$' % (_('admin/'), _('flagged_posts/')), app.admin.flagged_posts, name="admin_flagged_posts"),
+    url(r'^%s%s$' % (_('admin/'), _('static_pages/')), app.admin.static_pages, name="admin_static_pages"),
+
+    url(r'^%s%s%s$' % (_('admin/'), _('static_pages/'), _('new/')), app.admin.edit_page, name="admin_new_page"),
+    url(r'^%s%s%s(?P<id>\d+)/$' % (_('admin/'), _('static_pages/'), _('edit/')), app.admin.edit_page, name="admin_edit_page"),
 
     url(r'^%s%s(?P<set_name>\w+)/$' % (_('admin/'), _('settings/')), app.admin.settings_set, name="admin_set"),
 
     url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
 
     url(r'^%s%s(?P<set_name>\w+)/$' % (_('admin/'), _('settings/')), app.admin.settings_set, name="admin_set"),
 
     url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
+
+    url(r'^(?P<path>.+)$', app.meta.page, name="static_page")
 )
 )
index 2b3426efac14622346f92d6474f2f2fd975dd6af..800e59fdbed7446d3652007fc1d2c1e45a728036 100644 (file)
@@ -1,7 +1,7 @@
 from datetime import datetime, timedelta
 import time
 
 from datetime import datetime, timedelta
 import time
 
-from django.shortcuts import render_to_response
+from django.shortcuts import render_to_response, get_object_or_404
 from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
 from django.template import RequestContext
 from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
 from django.template import RequestContext
@@ -9,9 +9,11 @@ from django.utils.translation import ugettext as _
 from django.utils import simplejson
 from django.db.models import Sum
 from forum.settings.base import Setting
 from django.utils import simplejson
 from django.db.models import Sum
 from forum.settings.base import Setting
-from forum.settings.forms import SettingsSetForm, MaintenanceModeForm
+from forum.forms import MaintenanceModeForm, PageForm
+from forum.settings.forms import SettingsSetForm
 
 
-from forum.models import Question, Answer, User, Node, Action
+from forum.models import Question, Answer, User, Node, Action, Page
+from forum.actions import NewPageAction, EditPageAction, PublishAction
 from forum import settings
 
 def super_user_required(fn):
 from forum import settings
 
 def super_user_required(fn):
@@ -283,4 +285,51 @@ def flagged_posts(request):
         'flagged_posts': get_flagged_posts(),
     })
 
         'flagged_posts': get_flagged_posts(),
     })
 
+@admin_page
+def static_pages(request):
+    pages = Page.objects.all()
+
+    return ('osqaadmin/static_pages.html', {
+        'pages': pages,
+    })
+
+@admin_page
+def edit_page(request, id=None):
+    if id:
+        page = get_object_or_404(Page, id=id)
+    else:
+        page = None
+
+    if request.POST:
+        form = PageForm(page, request.POST)
+
+        if form.is_valid():
+            if form.has_changed():
+                if not page:
+                    page = NewPageAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data).node
+                else:
+                    EditPageAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save(data=form.cleaned_data)
+
+            if ('publish' in request.POST) and (not page.published):
+                PublishAction(user=request.user, node=page, ip=request.META['REMOTE_ADDR']).save()
+            elif ('unpublish' in request.POST) and page.published:
+                page.nstate.published.cancel(ip=request.META['REMOTE_ADDR'])
+
+            return HttpResponseRedirect(reverse('admin_edit_page', kwargs={'id': page.id}))
+
+    else:
+        form = PageForm(page)
+
+    if page:
+        published = page.published
+    else:
+        published = False
+
+    return ('osqaadmin/edit_page.html', {
+        'page': page,
+        'form': form,
+        'published': published
+    })
+
+
 
 
index 1230cf7f90408288037ff5ca5aec992443ad3b7b..ebccf0eefdc5669a8953537eb71ffb7788f94d1a 100644 (file)
@@ -12,7 +12,7 @@ from django.http import get_host
 import types
 import datetime
 
 import types
 import datetime
 
-from forum.authentication.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \
+from forum.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \
         TemporaryLoginRequestForm, ChangePasswordForm, SetPasswordForm
 from forum.utils.mail import send_email, send_template_email
 
         TemporaryLoginRequestForm, ChangePasswordForm, SetPasswordForm
 from forum.utils.mail import send_email, send_template_email
 
index 456199d8c1c05d75e996c20e42df288796631e46..ed6c03ffbe923b62886c5e4190baf732bf1cbeca 100644 (file)
@@ -292,8 +292,9 @@ def accept_answer(request, id):
         answer.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
         commands['unmark_accepted'] = [answer.id]
     else:
         answer.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
         commands['unmark_accepted'] = [answer.id]
     else:
-        if question.answer_accepted:
-            accepted = question.accepted_answer
+        accepted = question.accepted_answer
+
+        if accepted:
             accepted.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
             commands['unmark_accepted'] = [accepted.id]
 
             accepted.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
             commands['unmark_accepted'] = [accepted.id]
 
index b4cb75affa147a78a03a66b9f42b92bd7cd6bde6..608d1cb1aa02ee4253e064082846cf21476149b2 100644 (file)
@@ -3,18 +3,19 @@ from itertools import groupby
 from django.shortcuts import render_to_response, get_object_or_404
 from django.core.urlresolvers import reverse
 from django.template import RequestContext, loader
 from django.shortcuts import render_to_response, get_object_or_404
 from django.core.urlresolvers import reverse
 from django.template import RequestContext, loader
-from django.http import HttpResponseRedirect, HttpResponse
+from django.http import HttpResponseRedirect, HttpResponse, Http404
 from django.views.static import serve
 from forum import settings
 from forum.forms import FeedbackForm
 from django.core.urlresolvers import reverse
 from django.utils.translation import ugettext as _
 from django.db.models import Count
 from django.views.static import serve
 from forum import settings
 from forum.forms import FeedbackForm
 from django.core.urlresolvers import reverse
 from django.utils.translation import ugettext as _
 from django.db.models import Count
-from forum.utils.forms import get_next_url
-from forum.models import Badge, Award, User
+from forum.forms import get_next_url
+from forum.models import Badge, Award, User, Page
 from forum.badges.base import BadgesMeta
 from forum import settings
 from forum.utils.mail import send_template_email
 from forum.badges.base import BadgesMeta
 from forum import settings
 from forum.utils.mail import send_template_email
+from django.utils.safestring import mark_safe
 import re
 
 def favicon(request):
 import re
 
 def favicon(request):
@@ -94,3 +95,50 @@ def badge(request, id, slug):
         'badge' : badge,
     }, context_instance=RequestContext(request))
 
         'badge' : badge,
     }, context_instance=RequestContext(request))
 
+def page(request, path):
+    if path in settings.STATIC_PAGE_REGISTRY:
+        try:
+            page = Page.objects.get(id=settings.STATIC_PAGE_REGISTRY[path])
+
+            if not page.published or request.user.is_superuser:
+                raise Http404
+        except:
+            raise Http404
+    else:
+        raise Http404
+
+    template = page.extra.get('template', 'default')
+    sidebar = page.extra.get('sidebar', '')
+
+    if template == 'default':
+        base = 'base_content.html'
+    elif template == 'sidebar':
+        base = 'base.html'
+
+        sidebar_render = page.extra.get('render', 'markdown')
+
+        if sidebar_render == 'markdown':
+            sidebar = page._as_markdown(sidebar)
+        elif sidebar_render == 'html':
+            sidebar = mark_safe(sidebar)
+
+    else:
+        return HttpResponse(page.body)
+
+    render = page.extra.get('render', 'markdown')
+
+    if render == 'markdown':
+        body = page.as_markdown()
+    elif render == 'html':
+        body = mark_safe(page.body)
+    else:
+        body = page.body
+
+    return render_to_response('page.html', {
+        'page' : page,
+        'body' : body,
+        'sidebar': sidebar,
+        'base': base,        
+        }, context_instance=RequestContext(request))
+
+
index 6e75b378a1572b2900f78933db16bdeab4157f69..a1bb746ddd65ff834b16aeb232ec49d7e6cb3a51 100644 (file)
@@ -24,7 +24,7 @@ from forum.utils.html import sanitize_html
 from forum.utils.diff import textDiff as htmldiff
 from forum.forms import *
 from forum.models import *
 from forum.utils.diff import textDiff as htmldiff
 from forum.forms import *
 from forum.models import *
-from forum.utils.forms import get_next_url
+from forum.forms import get_next_url
 from forum.actions import QuestionViewAction
 from forum.modules.decorators import decoratable
 import decorators
 from forum.actions import QuestionViewAction
 from forum.modules.decorators import decoratable
 import decorators
index 6bc3477d35c4461d6618e88527572a41c53ee083..da556be2654706cf0124786f99bd6b7663142f7e 100644 (file)
@@ -204,7 +204,7 @@ def user_stats(request, user):
 \r
 @user_view('users/recent.html', 'recent', _('recent user activity'), _('recent activity'))\r
 def user_recent(request, user):\r
 \r
 @user_view('users/recent.html', 'recent', _('recent user activity'), _('recent activity'))\r
 def user_recent(request, user):\r
-    activities = user.actions.exclude(action_type__in=("voteup", "votedown", "voteupcomment", "flag")).order_by('-action_date')[:USERS_PAGE_SIZE]\r
+    activities = user.actions.exclude(action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by('-action_date')[:USERS_PAGE_SIZE]\r
 \r
     return {"view_user" : user, "activities" : activities}\r
 \r
 \r
     return {"view_user" : user, "activities" : activities}\r
 \r
index b6e13af629fe3af691889d3f71d9b96d2bceec14..aace1f6aa269d63fe6bcd5e974aacabf8054a924 100644 (file)
@@ -17,7 +17,7 @@ from forum.actions import AskAction, AnswerAction, ReviseAction, RollbackAction,
 from forum.modules.decorators import decoratable
 from forum.forms import *
 from forum.models import *
 from forum.modules.decorators import decoratable
 from forum.forms import *
 from forum.models import *
-from forum.utils.forms import get_next_url
+from forum.forms import get_next_url
 
 
 def upload(request):#ajax upload file to a question or answer
 
 
 def upload(request):#ajax upload file to a question or answer
index a3fd9928be7a59beb026f38f431fb2a2dc687583..961c7da389674583cbe1d923b429839f94e5fc7e 100644 (file)
@@ -1,4 +1,4 @@
-from forum.utils.forms import NextUrlField,  UserNameField,  UserEmailField, SetPasswordForm
+from forum.forms import NextUrlField,  UserNameField,  UserEmailField, SetPasswordForm
 from forum.models import Question
 from forum.modules import call_all_handlers
 from django.contrib.contenttypes.models import ContentType
 from forum.models import Question
 from forum.modules import call_all_handlers
 from django.contrib.contenttypes.models import ContentType
index 4392c5a939837cf078c4335dfef0333a60fb4a3e..e1daff3e7b87b8bb551a36207ed21743ec869596 100644 (file)
@@ -4,7 +4,7 @@ from django.template import RequestContext
 from django.utils.translation import ugettext as _
 
 from forms import ClassicRegisterForm
 from django.utils.translation import ugettext as _
 
 from forms import ClassicRegisterForm
-from forum.authentication.forms import SimpleEmailSubscribeForm
+from forum.forms import SimpleEmailSubscribeForm
 from forum.views.auth import login_and_forward
 from forum.actions import UserJoinsAction
 
 from forum.views.auth import login_and_forward
 from forum.actions import UserJoinsAction
 
index bcd2f8ee599be94b17e98c4395b50ddf357384c5..f9894f584e6defa2ad62893817cdaabee0e0e20a 100644 (file)
--- a/manage.py
+++ b/manage.py
@@ -6,7 +6,7 @@ except ImportError, e:
     import traceback
     traceback.print_exc()
     import sys
     import traceback
     traceback.print_exc()
     import sys
-    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+    sys.stderr.write("Error: Can't find the file 'forms.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file forms.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
     sys.exit(1)
 
 if __name__ == "__main__":
     sys.exit(1)
 
 if __name__ == "__main__":