savannah-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Savannah-cvs] [SCM] Savane-cleanup framework branch, master, updated. d


From: Sylvain Beucler
Subject: [Savannah-cvs] [SCM] Savane-cleanup framework branch, master, updated. dc1a5cd96ded77638df05915c3718561f7cec003
Date: Wed, 29 Jul 2009 13:30:48 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Savane-cleanup framework".

The branch, master has been updated
       via  dc1a5cd96ded77638df05915c3718561f7cec003 (commit)
       via  3871ff94c11e2169a6dcfac438a820a94c116c3f (commit)
       via  d383a838005429b50772d03cee88a5e5dba8718a (commit)
      from  59b0954efd82ef5c8467be04fa6b794bd845a6f8 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.savannah.gnu.org/cgit/savane-cleanup/framework.git/commit/?id=dc1a5cd96ded77638df05915c3718561f7cec003

commit dc1a5cd96ded77638df05915c3718561f7cec003
Author: Sylvain Beucler <address@hidden>
Date:   Wed Jul 29 15:30:20 2009 +0200

    Something that's I don't understand in @decorator prevents from using the 
decorator inline (without declaring an intermediate function) - let get rid of 
it and implement the decorator by hand

diff --git a/INSTALL b/INSTALL
index 3ab0491..aaf7c6d 100644
--- a/INSTALL
+++ b/INSTALL
@@ -9,7 +9,7 @@
 
 * Dependencies as Debian packages
 
-apt-get install mysql-server python-django python-mysqldb python-decorator
+apt-get install mysql-server python-django python-mysqldb
 
 
 * Install process
diff --git a/src/savane/my/urls.py b/src/savane/my/urls.py
index d0ba8e7..1c30dee 100644
--- a/src/savane/my/urls.py
+++ b/src/savane/my/urls.py
@@ -23,34 +23,25 @@ from django.views.generic.simple import direct_to_template
 from django.views.generic.list_detail import object_list
 import views
 import savane.svmain.models as svmain_models
-from decorator import decorator
 
address@hidden
-def only_mine(f, *args, **kwargs):
+def only_mine(f):
     """Filter a generic query_set to only display objets related to
     the current user"""
-    request = args[0]
-    user = request.user
-    kwargs['queryset'] = kwargs['queryset'].filter(user=user.id)
-    return f(*args, **kwargs)
-
address@hidden
-def object_list__only_mine(*args, **kwargs):
-    return object_list(*args, **kwargs)
-
address@hidden
-def direct_to_template__login_required(*args, **kwargs):
-    return direct_to_template(*args, **kwargs)
+    def _dec(request, queryset, *args, **kwargs):
+        user = request.user
+        queryset = queryset.filter(user=user.id)
+        return f(request, queryset, *args, **kwargs)
+    return _dec
 
 urlpatterns = patterns ('',
-  url(r'^$', direct_to_template__login_required,
+  url(r'^$', login_required(direct_to_template),
       { 'template' : 'my/index.html' },
       name='savane.my.views.index'),
   url('^conf/$', views.sv_conf),
   url('^conf/resume_skill$', views.sv_resume_skill),
   url('^conf/ssh_gpg$', views.sv_ssh_gpg),
   url('^conf/ssh_gpg$', views.sv_ssh_gpg),
-  url(r'^groups/$', object_list__only_mine,
+  url(r'^groups/$', only_mine(object_list),
       { 'queryset' : svmain_models.ExtendedGroup.objects.all() },
       name='savane.my.group_list'),
 )

http://git.savannah.gnu.org/cgit/savane-cleanup/framework.git/commit/?id=3871ff94c11e2169a6dcfac438a820a94c116c3f

commit 3871ff94c11e2169a6dcfac438a820a94c116c3f
Author: Sylvain Beucler <address@hidden>
Date:   Wed Jul 29 15:01:00 2009 +0200

    Add '/u', '/us', '/p', '/pr' URL aliases

diff --git a/src/savane/my/views.py b/src/savane/my/views.py
index f1d5c29..3eb7686 100644
--- a/src/savane/my/views.py
+++ b/src/savane/my/views.py
@@ -18,7 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from django.template import RequestContext
-from django.shortcuts import render_to_response
+from django.shortcuts import render_to_response, get_object_or_404
 from django.http import HttpResponseRedirect
 from django.contrib.auth import authenticate, login, logout
 from django.contrib.auth.decorators import login_required
diff --git a/src/savane/svmain/urls.py b/src/savane/svmain/urls.py
index 6b76464..f4a13dd 100644
--- a/src/savane/svmain/urls.py
+++ b/src/savane/svmain/urls.py
@@ -20,6 +20,7 @@
 from django.conf.urls.defaults import *
 
 from savane.svmain import models as svmain_models
+import views
 
 urlpatterns = patterns ('',
   url(r'^$', 'django.views.generic.simple.direct_to_template',
@@ -33,15 +34,19 @@ urlpatterns = patterns ('',
   # TODO: not sure about the views naming convention - all this
   # "models in 'svmain', views in 'my'" is getting messy, probably a
   # mistake from me (Beuc) :P
-  url(r'^projects/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
+  url(r'^p/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
       { 'queryset' : svmain_models.ExtendedGroup.objects.all(),
         'slug_field' : 'name' },
       name='savane.svmain.group_detail'),
+  url(r'^pr/(?P<slug>[-\w]+)$', views.group_redir),
+  url(r'^projects/(?P<slug>[-\w]+)$', views.group_redir),
 
-  url(r'^users/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
+  url(r'^u/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
       { 'queryset' : svmain_models.ExtendedUser.objects.all(),
         'slug_field' : 'username' },
       name='savane.svmain.user_detail'),
+  url(r'^us/(?P<slug>[-\w]+)$', views.user_redir),
+  url(r'^users/(?P<slug>[-\w]+)$', views.user_redir),
 
   url(r'^license/$', 'django.views.generic.list_detail.object_list',
       { 'queryset' : svmain_models.License.objects.all(), },
diff --git a/src/savane/svmain/views.py b/src/savane/svmain/views.py
new file mode 100644
index 0000000..b5d9973
--- /dev/null
+++ b/src/savane/svmain/views.py
@@ -0,0 +1,29 @@
+# Manage user attributes
+# Copyright (C) 2009  Sylvain Beucler
+#
+# This file is part of Savane.
+# 
+# Savane is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+# 
+# Savane is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+# 
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from django.http import HttpResponseRedirect
+from django.shortcuts import render_to_response, get_object_or_404
+import models as svmain_models
+
+def group_redir(request, slug):
+    eg = get_object_or_404(svmain_models.ExtendedGroup, name=slug)
+    return HttpResponseRedirect(eg.get_absolute_url())
+
+def user_redir(request, slug):
+    ug = get_object_or_404(svmain_models.ExtendedUser, username=slug)
+    return HttpResponseRedirect(ug.get_absolute_url())

http://git.savannah.gnu.org/cgit/savane-cleanup/framework.git/commit/?id=d383a838005429b50772d03cee88a5e5dba8718a

commit d383a838005429b50772d03cee88a5e5dba8718a
Author: Sylvain Beucler <address@hidden>
Date:   Wed Jul 29 14:02:47 2009 +0200

    - Import user->group membership
    
    - Clean-up duplicates and dangling membership
    
    - Document the User/Group inheritence (compared to using Profiles)
    
    - Introduce get_obsolute_url(...) functions in models
    
    - Add templates for users, groups and licenses, with links from one
      another
    
    - Filter users by status in the admin interface
    
    - Display a 404 when accessing 'my' with a User that doesn't have an
      ExtendedUser
    
    - Simplify login template to inherit error reporting

diff --git a/migrate_old_savane.sql b/migrate_old_savane.sql
index 648959b..6a3f8a5 100644
--- a/migrate_old_savane.sql
+++ b/migrate_old_savane.sql
@@ -270,3 +270,48 @@ INSERT INTO svmain_extendedgroup
       url_extralink_documentation
     FROM savane_old.groups LEFT JOIN savane.svmain_license ON 
savane_old.groups.license = savane.svmain_license.slug
     WHERE savane_old.groups.group_id != 100;
+
+-- Import users<->groups relationships
+-- Get rid of duplicates (long: several minutes):
+DELETE FROM savane_old.user_group
+  WHERE user_group_id IN (
+    SELECT A.user_group_id
+      FROM savane_old.user_group A, savane_old.user_group B
+      WHERE A.user_id = B.user_id AND A.group_id = B.group_id
+      GROUP BY A.user_id, A.group_id HAVING count(*) > 1
+  );
+-- Actual import
+INSERT INTO auth_user_groups
+    (user_id, group_id)
+  SELECT user_id, group_id
+    FROM savane_old.user_group;
+INSERT INTO svmain_membership
+    (user_id, group_id, admin_flags, onduty)
+  SELECT user_id, group_id, admin_flags, onduty
+    FROM savane_old.user_group;
+-- Get rid of ghost relationships (deleted group)
+DELETE FROM svmain_membership
+  WHERE group_id IN (
+    SELECT group_id FROM (
+      SELECT group_id
+        FROM svmain_membership
+          LEFT JOIN svmain_extendedgroup ON svmain_membership.group_id = 
svmain_extendedgroup.group_ptr_id
+        WHERE group_ptr_id IS NULL
+      ) AS temp
+    );
+-- Get rid of ghost relationships (deleted user)
+DELETE FROM svmain_membership WHERE user_id IN (
+  SELECT user_id FROM (
+    SELECT user_id
+      FROM svmain_membership
+        LEFT JOIN svmain_extendeduser ON svmain_membership.user_id = 
svmain_extendeduser.user_ptr_id
+      WHERE user_ptr_id IS NULL
+    ) AS temp
+  );
+-- Set members of 'administration' as superusers
+-- TODO: get the supergroup name from the old Savane configuration
+UPDATE auth_user SET is_staff=1, is_superuser=1
+  WHERE id IN (
+    SELECT user_id
+    FROM auth_user_groups JOIN auth_group ON auth_user_groups.group_id = 
auth_group.id
+    WHERE auth_group.name='administration');
diff --git a/src/savane/my/urls.py b/src/savane/my/urls.py
index 72e07f4..d0ba8e7 100644
--- a/src/savane/my/urls.py
+++ b/src/savane/my/urls.py
@@ -31,7 +31,6 @@ def only_mine(f, *args, **kwargs):
     the current user"""
     request = args[0]
     user = request.user
-    print kwargs
     kwargs['queryset'] = kwargs['queryset'].filter(user=user.id)
     return f(*args, **kwargs)
 
@@ -53,5 +52,5 @@ urlpatterns = patterns ('',
   url('^conf/ssh_gpg$', views.sv_ssh_gpg),
   url(r'^groups/$', object_list__only_mine,
       { 'queryset' : svmain_models.ExtendedGroup.objects.all() },
-      name='savane.my.generic.group_list'),
+      name='savane.my.group_list'),
 )
diff --git a/src/savane/my/views.py b/src/savane/my/views.py
index b7a4dcc..f1d5c29 100644
--- a/src/savane/my/views.py
+++ b/src/savane/my/views.py
@@ -84,7 +84,7 @@ def sv_resume_skill( request ):
                                context_instance=RequestContext(request))
 @login_required()
 def sv_ssh_gpg( request ):
-    eu = ExtendedUser.objects.get(pk=request.user.pk)
+    eu = get_object_or_404(ExtendedUser, pk=request.user.pk)
 
     error_msg = None
     success_msg = None
diff --git a/src/savane/svmain/admin.py b/src/savane/svmain/admin.py
index 4d79f05..a66d807 100644
--- a/src/savane/svmain/admin.py
+++ b/src/savane/svmain/admin.py
@@ -27,7 +27,7 @@ class ExtendedUserAdmin(admin.ModelAdmin):
                      'people_view_skills', 'email_hide', 'timezone', 
'theme',)}),
         )
     list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
-    list_filter = ('is_staff', 'is_superuser')
+    list_filter = ('is_staff', 'is_superuser', 'status')
     search_fields = ('username', 'first_name', 'last_name', 'email')
     ordering = ('username',)
     filter_horizontal = ('user_permissions',)
diff --git a/src/savane/svmain/models.py b/src/savane/svmain/models.py
index 84a3657..91211a2 100644
--- a/src/savane/svmain/models.py
+++ b/src/savane/svmain/models.py
@@ -19,6 +19,42 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+"""
+User/group extra attributes
+
+This may look like reinventing the User.get_profile() that comes with
+Django;
+http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/
+http://mirobetm.blogspot.com/2007/04/en-django-extending-user_2281.html
+
+However profiles were mainly useful in Django < 1.0 where you couldn't
+subclass User as we do.
+
+Profiles also have a few drawbacks, namely they are site-specific,
+which means you cannot have multiple applications have different
+profiles in the same website, while with subclassing you only need to
+user different class names (to avoid parent->child fieldname clash).
+
+Moreover splitting the information in two different models can be
+cumbersome when using ModelForms.
+
+Subclassing drawback: there's apparently a technique to use a
+vhost-based profile class (with django.contrib.site and multiples
+settings.py). But it's not useful for Savane IMHO.
+
+In addition, it seems impossible to convert an existing User to a
+derived class from Python (this can be done through DB but that's
+ugly). This apparently prevents auto-creating our derived class when a
+new User is directly created (and sends a post_save signal).
+
+Profiles vs. inheritance is also described at
+http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/
+
+Note that Scott's authentication backend has the same issue than
+profiles: only one profile class can be used on a single website, so
+we don't use it.
+"""
+
 from django.db import models
 from django.contrib.auth import models as auth_models
 
@@ -59,10 +95,36 @@ class ExtendedUser(auth_models.User):
     timezone = models.CharField(max_length=192, blank=True)
     theme = models.CharField(max_length=45, blank=True)
 
+    # Non-field link to extended groups
+    extendedgroup_set = models.ManyToManyField('ExtendedGroup', 
through='Membership')
 
     # Inherit specialized models.Manager with convenience functions
     objects = auth_models.UserManager()
 
+    @models.permalink
+    def get_absolute_url(self):
+        return ('savane.svmain.user_detail', [self.username])
+
+# FIXME
+# Let's make sure extendeduser is always created, even if somehow a
+# normal User is created (from the admin interface, e.g.)
+# This currently fails, and this doesn't support creating a model if
+# another apps creates a derived class.
+#from django.contrib.auth.models import User
+#from django.db.models.signals import post_save
+#def user_post_save_handler(sender, **kwargs):
+#    """
+#    Create an ExtendedUser when a User is directly created
+#
+#    Called when User is created
+#    (but not called when a ExtendedUser is created)
+#    """
+#    u = kwargs['instance']
+#    if kwargs['created'] == True:
+#        eu = ExtendedUser(user_ptr=u)
+#        eu.save()  # ERROR
+#post_save.connect(user_post_save_handler, sender=User)
+
 class License(models.Model):
     """
     Main license used by a project
@@ -77,6 +139,10 @@ class License(models.Model):
     def __unicode__(self):
         return self.slug + ": " + self.name
 
+    @models.permalink
+    def get_absolute_url(self):
+        return ('savane.svmain.license_detail', [self.slug])
+
     class Meta:
         ordering = ['slug']
 
@@ -382,6 +448,50 @@ class ExtendedGroup(auth_models.Group):
     def __unicode__(self):
         return self.name
 
+    @models.permalink
+    def get_absolute_url(self):
+        return ('savane.svmain.group_detail', [self.name])
+
     class Meta:
         ordering = ['name']
 
+
+class Membership(models.Model):
+    """
+    Extra attributes about a User<->Group relationship
+    (e.g. "is the user an admin?")
+    """
+    user = models.ForeignKey(ExtendedUser)
+    group = models.ForeignKey(ExtendedGroup)
+
+    admin_flags_CHOICES = (
+        ('A', 'Admin'),
+        # IMHO we need to put 'P' in a separate table, like 'pending
+        # membership', otherwise it's too easy to make mistakes
+        ('P', 'Pending moderation'),
+        ('SQD', 'Squad'), # FIXME: I dislike squad=user
+        )
+    admin_flags = models.CharField(max_length=3, choices=admin_flags_CHOICES,
+      blank=True, help_text="membership properties")
+    onduty = models.BooleanField(default=True,
+      help_text="Untick to hide emeritous members from the project page")
+
+    # TODO: split news params
+    #news_flags int(11) default NULL
+    
+    # Trackers-related
+    #privacy_flags = models.BooleanField(default=True)
+    #bugs_flags int(11) default NULL
+    #task_flags int(11) default NULL
+    #patch_flags int(11) default NULL
+    #support_flags int(11) default NULL
+    #cookbook_flags int(11) default NULL
+
+    # Deprecated
+    #forum_flags int(11) default NULL
+
+    def __unicode__(self):
+        return "[%s is a member of %s]" % (self.user.username, self.group.name)
+
+    class Meta:
+        unique_together = (('user', 'group'),)
diff --git a/src/savane/svmain/urls.py b/src/savane/svmain/urls.py
index c42dcaa..6b76464 100644
--- a/src/savane/svmain/urls.py
+++ b/src/savane/svmain/urls.py
@@ -19,6 +19,8 @@
 
 from django.conf.urls.defaults import *
 
+from savane.svmain import models as svmain_models
+
 urlpatterns = patterns ('',
   url(r'^$', 'django.views.generic.simple.direct_to_template',
       { 'template' : 'index.html',
@@ -27,4 +29,24 @@ urlpatterns = patterns ('',
   url(r'^contact$', 'django.views.generic.simple.direct_to_template',
       { 'template' : 'contact.html' },
       name='contact'),
+
+  # TODO: not sure about the views naming convention - all this
+  # "models in 'svmain', views in 'my'" is getting messy, probably a
+  # mistake from me (Beuc) :P
+  url(r'^projects/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
+      { 'queryset' : svmain_models.ExtendedGroup.objects.all(),
+        'slug_field' : 'name' },
+      name='savane.svmain.group_detail'),
+
+  url(r'^users/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
+      { 'queryset' : svmain_models.ExtendedUser.objects.all(),
+        'slug_field' : 'username' },
+      name='savane.svmain.user_detail'),
+
+  url(r'^license/$', 'django.views.generic.list_detail.object_list',
+      { 'queryset' : svmain_models.License.objects.all(), },
+      name='savane.svmain.license_list'),
+  url(r'^license/(?P<slug>[-\w]+)$', 
'django.views.generic.list_detail.object_detail',
+      { 'queryset' : svmain_models.License.objects.all(), },
+      name='savane.svmain.license_detail'),
 )
diff --git a/template/registration/login.html b/template/registration/login.html
index 2cfe5a8..e5ca5a4 100644
--- a/template/registration/login.html
+++ b/template/registration/login.html
@@ -2,14 +2,12 @@
 {% extends "base.html" %}
 
 {% block content %}
-Please login:
+Login:
+
 <form action="{% url django.contrib.auth.views.login %}" method="post">
-<dl>
-  <dt>Login Name:</dt>
-  <dd><input type="text" name="username" value="" size="12" /></dd>
-  <dt>Password:</dt>
-  <dd><input type="password" name="password" size="12" /></dd>
-  <dd><input type="submit" name="login" value="Login" /></dd>
-</dl>
+{{form.as_p}}
+<input type="submit" name="login" value="Login" />
+</table>
 </form>
+
 {% endblock %}
diff --git a/template/svmain/extendedgroup_detail.html 
b/template/svmain/extendedgroup_detail.html
new file mode 100644
index 0000000..98bdc93
--- /dev/null
+++ b/template/svmain/extendedgroup_detail.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+<p>
+Name: {{object.name}}<br />
+License: <a 
href="{{object.license.get_absolute_url}}">{{object.license.name}}</a><br />
+Development status: {{object.devel_status}}<br />
+</p>
+
+<p>Members:</p>
+
+{% if object.user_set.all %}
+<ul>
+  {% for user in object.user_set.all %}
+  <li><a href="{{ user.extendeduser.get_absolute_url }}">{{ user.username 
}}</a></li>
+  {% endfor %}
+  </ul>
+{% else %}
+  No members!
+{% endif %}
+
+{% endblock %}
+
+{% comment %}
+Local Variables: **
+mode: django-html **
+tab-width: 4 **
+indent-tabs-mode: nil **
+End: **
+{% endcomment %}
diff --git a/template/svmain/extendedgroup_list.html 
b/template/svmain/extendedgroup_list.html
index cd529fc..fdc3da1 100644
--- a/template/svmain/extendedgroup_list.html
+++ b/template/svmain/extendedgroup_list.html
@@ -5,11 +5,11 @@
 {% if object_list %}
     <ul>
     {% for object in object_list %}
-        <li><a href="{{object.id}}">{{ object }}</a></li>
+        <li><a href="{{ object.get_absolute_url }}">{{ object }}</a></li>
     {% endfor %}
     </ul>
 {% else %}
-    <p>You are not part of any group.</p>
+    <p>No group.</p>
 {% endif %}
 
 {% endblock %}
diff --git a/template/svmain/extendeduser_detail.html 
b/template/svmain/extendeduser_detail.html
new file mode 100644
index 0000000..f1fbad5
--- /dev/null
+++ b/template/svmain/extendeduser_detail.html
@@ -0,0 +1,59 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+<p>Name: {{object.username}}</p>
+
+<p>Is a member of (using Django user.groups):</p>
+
+{% if object.groups.all %}
+<ul>
+  {% for group in object.groups.all %}
+  <li>
+    <a href="{{ group.extendedgroup.get_absolute_url }}">{{ group.name }}</a>
+  </li>
+  {% endfor %}
+  </ul>
+{% else %}
+  Not part of any group yet
+{% endif %}
+
+<p>Is a member of (using Membership):</p>
+
+{% if object.membership_set.all %}
+<ul>
+  {% for membership in object.membership_set.all %}
+  <li>
+    <a href="{{ membership.group.get_absolute_url }}">{{ membership.group.name 
}}</a> {{ membership.admin_flags}}
+  </li>
+  {% endfor %}
+  </ul>
+{% else %}
+  Not part of any group yet
+{% endif %}
+
+
+<p>Is a member of (using Membership + direct field):</p>
+
+{% if object.extendedgroup_set.all %}
+<ul>
+  {% for group in object.extendedgroup_set.all %}
+  <li>
+    <a href="{{ group.get_absolute_url }}">{{ group.name }}</a>
+  </li>
+  {% endfor %}
+  </ul>
+{% else %}
+  Not part of any group yet
+{% endif %}
+
+
+{% endblock %}
+
+{% comment %}
+Local Variables: **
+mode: django-html **
+tab-width: 4 **
+indent-tabs-mode: nil **
+End: **
+{% endcomment %}
diff --git a/template/svmain/license_detail.html 
b/template/svmain/license_detail.html
new file mode 100644
index 0000000..6ff59b4
--- /dev/null
+++ b/template/svmain/license_detail.html
@@ -0,0 +1,28 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+<p><a href="{% url savane.svmain.license_list %}">License list</a></p>
+
+<p>
+Name: {{object.slug}}<br />
+URL: <a href="{{object.license.url}}">{{object.url}}</a><br />
+</p>
+
+<p>Projects that use it:</p>
+
+{{ object.extendedgroup_set.count }} project(s) use this license<br />
+
+{% for eg in object.extendedgroup_set.all %}
+<a href="{{eg.get_absolute_url}}">{{eg.name}}</a>{% if forloop.last 
%}{%else%},{% endif %}
+{% endfor %}
+
+{% endblock %}
+
+{% comment %}
+Local Variables: **
+mode: django-html **
+tab-width: 4 **
+indent-tabs-mode: nil **
+End: **
+{% endcomment %}
diff --git a/template/svmain/license_list.html 
b/template/svmain/license_list.html
new file mode 100644
index 0000000..233a6fd
--- /dev/null
+++ b/template/svmain/license_list.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+{% for object in object_list %}
+<a href="{{object.get_absolute_url}}">{{object.name}}</a><br />
+{% endfor %}
+
+{% endblock %}
+
+{% comment %}
+Local Variables: **
+mode: django-html **
+tab-width: 4 **
+indent-tabs-mode: nil **
+End: **
+{% endcomment %}

-----------------------------------------------------------------------

Summary of changes:
 INSTALL                                            |    2 +-
 migrate_old_savane.sql                             |   45 ++++++++
 src/savane/my/urls.py                              |   28 ++----
 src/savane/my/views.py                             |    4 +-
 src/savane/svmain/admin.py                         |    2 +-
 src/savane/svmain/models.py                        |  110 ++++++++++++++++++++
 src/savane/svmain/urls.py                          |   27 +++++
 .../{context_processors.py => svmain/views.py}     |   19 ++--
 template/registration/login.html                   |   14 +--
 template/svmain/extendedgroup_detail.html          |   31 ++++++
 template/svmain/extendedgroup_list.html            |    4 +-
 template/svmain/extendeduser_detail.html           |   59 +++++++++++
 template/svmain/license_detail.html                |   28 +++++
 template/svmain/license_list.html                  |   17 +++
 14 files changed, 348 insertions(+), 42 deletions(-)
 copy src/savane/{context_processors.py => svmain/views.py} (60%)
 create mode 100644 template/svmain/extendedgroup_detail.html
 create mode 100644 template/svmain/extendeduser_detail.html
 create mode 100644 template/svmain/license_detail.html
 create mode 100644 template/svmain/license_list.html


hooks/post-receive
-- 
Savane-cleanup framework




reply via email to

[Prev in Thread] Current Thread [Next in Thread]