changeset 206:e58b71703438

Manage 'homepage' and 'download' project links
author Sylvain Beucler <beuc@beuc.net>
date Fri, 30 Jul 2010 15:54:41 +0200
parents 93815ee7cef7
children 6fef32fad596
files savane/svmain/fixtures/demo/users_groups.yaml savane/svmain/models.py savane/svmain/templatetags/svtopmenu.py savane/svmain/tests.py savane/svmain/urls.py savane/svmain/views.py templates/svmain/svtopmenu.html
diffstat 7 files changed, 95 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/savane/svmain/fixtures/demo/users_groups.yaml
+++ b/savane/svmain/fixtures/demo/users_groups.yaml
@@ -3,6 +3,8 @@
   fields:
     name: "Official GNU software"
     description: "This project is part of the GNU Project."
+    url_homepage: "http://www.gnu.org/software/%PROJECT/"
+    url_download: "http://ftp.gnu.org/gnu/%PROJECT/"
 - model: auth.group
   pk: 1
   fields:
--- a/savane/svmain/models.py
+++ b/savane/svmain/models.py
@@ -58,11 +58,25 @@
 similar to extending a model class (at the SQL tables level), and
 AutoOneToOneField is a trick from django-annoying to automatically
 create the extended data on first access.
+
+However this means all SvGroupInfo fields have a default value or can
+be NULL, which means the rest of the code will have to handle NULL
+cases :/
+
+There are also reports of issues when used with the South framework.
+
+Also this code:
+  group.svgroupinfo.type = ...
+  group.svgroupinfo.save()
+Currently fails: type remains NULL, probably because the result of the
+first invocation of 'group.svgroupinfo' return a different result
+thant the second one.  We may need to do things differently...
 """
 
 from django.db import models
 from django.contrib.auth import models as auth_models
 from django.utils.translation import ugettext, ugettext_lazy as _
+import datetime
 
 
 class SshKey(models.Model):
@@ -374,7 +388,8 @@
 
     group = AutoOneToOneField(auth_models.Group, primary_key=True)
 
-    type = models.ForeignKey(GroupConfiguration)
+    type = models.ForeignKey(GroupConfiguration,
+      null=True)  # NULL when object initially created by AutoOneToOneField
     full_name = models.CharField(max_length=255, blank=True,
       help_text="Full project name (not Unix system name)")
     is_public = models.BooleanField(default=False)
@@ -393,14 +408,15 @@
     license = models.ForeignKey(License, blank=True, null=True)
     license_other = models.TextField(blank=True)
 
-    devel_status = models.ForeignKey(DevelopmentStatus)
+    devel_status = models.ForeignKey(DevelopmentStatus,
+      null=True)  # NULL when object initially created by AutoOneToOneField
 
     # Registration-specific
     register_purpose = models.TextField(blank=True)
     required_software = models.TextField(blank=True)
     other_comments = models.TextField(blank=True)
 
-    register_time = models.DateTimeField()
+    register_time = models.DateTimeField(default=datetime.datetime.now)
     #rand_hash text,
 
     registered_gpg_keys = models.TextField(blank=True)
@@ -501,6 +517,14 @@
     def get_active_memberships(self):
         return self.group.membership_set.exclude(admin_flags='P')
 
+    def get_url_homepage(self):
+        return (self.url_homepage
+                or self.type.url_homepage.replace('%PROJECT', self.group.name))
+
+    def get_url_download(self):
+        return (self.url_download
+                or self.type.url_download.replace('%PROJECT', self.group.name))
+
     @staticmethod
     def query_active_groups_raw(conn, fields):
         """
@@ -581,13 +605,15 @@
     def is_member(user, group):
         return (user.is_superuser or
                 user.is_staff or
-                group.user_set.filter(pk=user.pk).count() > 0)
+                (not user.is_anonymous()
+                 and group.user_set.filter(pk=user.pk).count() > 0))
 
     @staticmethod
     def is_admin(user, group):
         return (user.is_superuser or
                 user.is_staff or
-                (Membership.is_member(user, group)
+                (not user.is_anonymous()
+                 and Membership.is_member(user, group)
                  and Membership.objects
                  .filter(user=user, group=group, admin_flags='A').count() > 0))
 
--- a/savane/svmain/templatetags/svtopmenu.py
+++ b/savane/svmain/templatetags/svtopmenu.py
@@ -39,7 +39,7 @@
     group = context['group']
 
     if menu_name == 'group':
-        entry_home = { 'text' : 'Home',
+        entry_home = { 'text' : 'Main',
                    'href' : reverse('savane:svmain:group_detail', args=[group.name]),
                    'title': "Project Main Page at %s" % 'this website'}
         entry_home['children'] = []
@@ -60,15 +60,38 @@
             entry_home['children'].append({'text' : _("Manage members"),
                                            'href' : reverse('savane:svmain:group_admin_members', args=[group.name]) })
 
-        entry_test = {
-                    'text' : 2, 'href' : 2, 'title': 2, 'children':
-                    [
-                        {'text' : 2.1, 'href' : 2.1, 'title': 2.1 },
-                    ]
-                }
+        entry_homepage = {'text' : _("Homepage"),
+                          'href' : group.svgroupinfo.get_url_homepage(),
+                          'title': _("Browse project homepage (outside of Savane)")}
+
+        entry_download = {'text' : _("Download"),
+                          'href' : group.svgroupinfo.get_url_download(),
+                          'title': _("Download area: files released")}
+
+        entry_mailinglists = {'text' : _("Mailing lists") + " (TODO)",
+                              'href' : '',
+                              'title': _("List existing mailing lists")}
+        entry_mailinglists['children'] = []
+        entry_mailinglists['children'].append({'text' : _("Browse") + " (TODO)",
+                                                   'href' : '' })
+        if (svmain_models.Membership.is_admin(context['user'], group)):
+            entry_mailinglists['children'].append({'separator' : True })
+            entry_mailinglists['children'].append({'text' : _("Configure:") + " (TODO)", 'strong': True,
+                                                   'href' : '' })
+ 
+        entry_sourcecode = {'text' : _("Source code") + " (TODO)",
+                           'href' : '',
+                           'title': _("Source Code Management")}
+        entry_sourcecode['children'] = []
+        entry_sourcecode['children'].append({'text' : _("Use X") + " (TODO)",
+                                               'href' : '' })
+ 
 
         entries.append(entry_home)
-        entries.append(entry_test)
+        entries.append(entry_homepage)
+        entries.append(entry_download)
+        entries.append(entry_mailinglists)
+        entries.append(entry_sourcecode)
     elif menu_name == 'my':
         pass
 
--- a/savane/svmain/tests.py
+++ b/savane/svmain/tests.py
@@ -20,6 +20,7 @@
 from django.test import TestCase
 from django.core.urlresolvers import reverse
 import django.contrib.auth.models as auth_models
+import savane.svmain.models as svmain_models
 import re
 
 class SimpleTest(TestCase):
@@ -49,3 +50,28 @@
         response = self.client.get(reverse('registration_activate', args=[hash]))
         self.assertRedirects(response, reverse('registration_activation_complete'))
         self.assertTrue(self.client.login(username='test', password='test'))
+
+    def test_020_group_url(self):
+        """
+        Create a new group and check the page menu
+        """
+        conf = svmain_models.GroupConfiguration(name='testconf',
+                                                url_homepage='http://www.test.tld/homepage/%PROJECT/',
+                                                url_download='http://www.test.tld/download/%PROJECT/')
+        conf.save()
+        
+        group = auth_models.Group(name='test')
+        group.save()
+        # Work-around AutoOneToOneField bug
+        group.svgroupinfo
+        group.svgroupinfo.type = conf
+        group.svgroupinfo.save()
+
+        response = self.client.get(reverse('savane:svmain:group_detail', args=[group.name]))
+        self.assertContains(response, 'http://www.test.tld/homepage/test/')
+        self.assertContains(response, 'http://www.test.tld/homepage/test/')
+
+        group.svgroupinfo.url_homepage = 'http://www.mysite.tld/%PROJECT/'
+        group.svgroupinfo.save()
+        response = self.client.get(reverse('savane:svmain:group_detail', args=[group.name]))
+        self.assertContains(response, 'http://www.mysite.tld/%PROJECT/')
--- a/savane/svmain/urls.py
+++ b/savane/svmain/urls.py
@@ -107,7 +107,8 @@
         'extra_context' : { 'title' : 'Editing public info' }, },
       name='group_admin_info'),
   url(r'^p/(?P<slug>[-\w]+)/admin/features/$', views.group_admin_features,
-      { 'extra_context' : { 'title' : 'Select features' }, },
+      { 'extra_context' : { 'title' : 'Select features' },
+        'post_save_redirect': ''},
       name='group_admin_features'),
   url(r'^p/(?P<slug>[-\w]+)/admin/members/$', views.group_admin_members,
       { 'extra_context' : { 'title' : 'Manage members' }, },
--- a/savane/svmain/views.py
+++ b/savane/svmain/views.py
@@ -157,7 +157,7 @@
     return context
 
 @render_to("svmain/group_admin_features.html", mimetype=None)
-def group_admin_features(request, slug, extra_context={}):
+def group_admin_features(request, slug, extra_context={}, post_save_redirect=None):
     group = get_object_or_404(auth_models.Group, name=slug)
     object = group.svgroupinfo
 
--- a/templates/svmain/svtopmenu.html
+++ b/templates/svmain/svtopmenu.html
@@ -2,6 +2,7 @@
 {% for l1 in entries %}
   <li class="topmenuitemmainitem">
     <a class="tabs" href="{{l1.href}}" title="{{l1.title}}">{{ l1.text }}</a>
+    {% if l1.children %}
     <ul id="submenu{{forloop.counter}}" class="topmenuitemsubmenu">
     {% for l2 in l1.children %}
       {% if l2.separator %}
@@ -13,6 +14,7 @@
       {% endif %}
     {% endfor %}
     </ul>
+    {% endif %}
   </li>
 {% endfor %}
 </ul>