Merge branch 'dev' of https://code.grnet.gr/git/astakos into dev
authorroot <root@dev84.dev.grnet.gr>
Tue, 2 Oct 2012 09:06:14 +0000 (12:06 +0300)
committerroot <root@dev84.dev.grnet.gr>
Tue, 2 Oct 2012 09:06:14 +0000 (12:06 +0300)
13 files changed:
snf-astakos-app/.settings/org.eclipse.core.resources.prefs
snf-astakos-app/astakos/im/forms.py
snf-astakos-app/astakos/im/models.py
snf-astakos-app/astakos/im/settings.py
snf-astakos-app/astakos/im/static/im/css/forms.css
snf-astakos-app/astakos/im/static/im/css/modules.css
snf-astakos-app/astakos/im/static/im/js/common.js
snf-astakos-app/astakos/im/templates/im/astakosgroup_detail.html
snf-astakos-app/astakos/im/templates/im/astakosgroup_list.html
snf-astakos-app/astakos/im/templates/im/astakosuserquota_list.html
snf-astakos-app/astakos/im/templatetags/filters.py
snf-astakos-app/astakos/im/urls.py
snf-astakos-app/astakos/im/views.py

index 92a5002..0492ee8 100644 (file)
@@ -1,3 +1,6 @@
-#Mon Sep 10 11:32:44 EEST 2012
+#Thu Sep 27 13:01:48 EEST 2012
 eclipse.preferences.version=1
+encoding//astakos/im/migrations/0010_auto__add_field_astakosuser_activation_sent__chg_field_service_url.py=utf-8
+encoding//astakos/im/migrations/0011_set_old_activation_sent.py=utf-8
 encoding//astakos/im/migrations/0017_populate_resource_data.py=utf-8
+encoding//astakos/im/migrations/0023_populate_resource_data.py=utf-8
index 5ee0d8b..5df37de 100644 (file)
@@ -629,5 +629,21 @@ class TimelineForm(forms.Form):
 
 class AstakosGroupSortForm(forms.Form):
     sort_by = forms.ChoiceField(label='Sort by',
-                                choices=(('groupname', 'Name'), ('kindname', 'Type')),
+                                choices=(('groupname', 'Name'),
+                                         ('kindname', 'Type'),
+                                         ('issue_date', 'Issue Date'),
+                                         ('expiration_date', 'Expiration Date'),
+                                         ('approved_members_num', 'Participants'),
+                                         ('is_enabled', 'Status'),
+                                         ('moderation_enabled', 'Moderation'),
+                                         ('membership_status','Enrollment Status')
+                                         ),
+                                required=False)
+
+class MembersSortForm(forms.Form):
+    sort_by = forms.ChoiceField(label='Sort by',
+                                choices=(('person__email', 'User Id'),
+                                         ('person__first_name', 'Name'),
+                                         ('date_joined', 'Status')
+                                         ),
                                 required=False)
index e0db115..c1c7495 100644 (file)
@@ -120,22 +120,17 @@ class AstakosGroup(Group):
         'Homepage Url', max_length=255, null=True, blank=True)
     desc = models.TextField('Description', null=True)
     policy = models.ManyToManyField(Resource, null=True, blank=True,
-                                    through='AstakosGroupQuota'
-                                    )
+                                    through='AstakosGroupQuota')
     creation_date = models.DateTimeField('Creation date',
-                                         default=datetime.now()
-                                         )
+                                         default=datetime.now())
     issue_date = models.DateTimeField('Issue date', null=True)
     expiration_date = models.DateTimeField('Expiration date', null=True)
     moderation_enabled = models.BooleanField('Moderated membership?',
-                                             default=True
-                                             )
+                                             default=True)
     approval_date = models.DateTimeField('Activation date', null=True,
-                                         blank=True
-                                         )
+                                         blank=True)
     estimated_participants = models.PositiveIntegerField('Estimated #members',
-                                                         null=True
-                                                         )
+                                                         null=True)
 
     @property
     def is_disabled(self):
@@ -187,16 +182,18 @@ class AstakosGroup(Group):
 
     @property
     def members(self):
-        return [m.person for m in self.membership_set.all()]
+        q = self.membership_set.select_related().all()
+        return [m.person for m in q]
 
     @property
     def approved_members(self):
-        return [m.person for m in self.membership_set.all() if m.is_approved]
+        q = self.membership_set.select_related().all()
+        return [m.person for m in q if m.is_approved]
 
     @property
     def quota(self):
         d = defaultdict(int)
-        for q in self.astakosgroupquota_set.all():
+        for q in self.astakosgroupquota_set.select_related().all():
             d[q.resource] += q.uplimit
         return d
 
@@ -204,6 +201,10 @@ class AstakosGroup(Group):
     def owners(self):
         return self.owner.all()
 
+    @property
+    def owner_details(self):
+        return self.owner.select_related().all()
+
     @owners.setter
     def owners(self, l):
         self.owner = l
@@ -295,9 +296,9 @@ class AstakosUser(User):
     @property
     def quota(self):
         d = defaultdict(int)
-        for q in self.astakosuserquota_set.all():
+        for q in self.astakosuserquota_set.select_related().all():
             d[q.resource.name] += q.uplimit
-        for m in self.membership_set.all():
+        for m in self.membership_set.select_related().all():
             if not m.is_approved:
                 continue
             g = m.group
index 967680d..576466e 100644 (file)
@@ -152,4 +152,4 @@ SERVICES = getattr(settings, 'ASTAKOS_SERVICES',
 AQUARIUM_URL = getattr(settings, 'ASTAKOS_AQUARIUM_URL', '')
 
 # Set how many objects should be displayed per page
-PAGINATE_BY = getattr(settings, 'ASTAKOS_PAGINATE_BY', 10)
\ No newline at end of file
+PAGINATE_BY = getattr(settings, 'ASTAKOS_PAGINATE_BY', 8)
\ No newline at end of file
index f016797..81ead51 100644 (file)
@@ -152,6 +152,9 @@ form+p:first-child, form legend + p                         { margin-bottom:2em; }
 form.link-like                                                                 { display:inline-block; margin:0 5px; float:right;}\r
 form.link-like input[type="submit"]                            { margin:0; padding:0 5px; background:transparent; color:#F89A1C; cursor:pointer; height:auto;  }\r
 form.link-like input[type="submit"]:hover              { text-decoration:underline;  }\r
+form.link-like.alone                                                   { float:none; margin:0;}\r
+form.link-like.alone .form-row                                 { margin:0; }\r
+form.link-like.alone input[type="submit"]              { padding:0; }  \r
 .projects form.withlabels .checkbox-widget             { margin-top:5px; }\r
 .projects form .with-checkbox                                  { margin:20px 0; }\r
 .projects form .with-checkbox label                            { padding-top:7px; }\r
index f95c6d6..133bdc4 100644 (file)
@@ -286,11 +286,14 @@ dl.alt-style dt:nth-child(2n)                                     { background:black; }
 .details img                                                                   { max-width:100%; }\r
 .question .section                                                             { margin-top:1em; }\r
 .question pre                                                                  { border:1px dashed #000; padding:5px; margin:10px 0; line-height:auto; }\r
-.widjets                                                                               { margin: 0; padding:0; }\r
+.widjets                                                                               { position:relative; }\r
+.widjets ul                                                                            { margin: 0; padding:0; }\r
 .widjets li                                                                            { width:50%; float:left; list-style:none outside; margin:30px 0; }\r
 .widjets li div                                                                        { border:1px dashed #000; padding:20px 20px 70px; width:60%; margin:0 auto; position:relative; }\r
 .widjets li div img                                                            { max-width:100%; }\r
 .widjets li .btn                                                               { text-align:center; position:absolute; bottom:0; left:0; right:0; }\r
+.widjets .widjet-x                                                             { position:absolute; right:0;top:0; font-weight:bold; font-size:1.5em; }\r
+.widjets .widjet-x:hover                                               { text-decoration:none; color:#000; }\r
 \r
 /* billing styles */\r
 .alt-style .table-div                                                  { border:1px dashed #000; }\r
index 5a15b95..3880b21 100644 (file)
@@ -205,6 +205,13 @@ $(document).ready(function() {
                $(this).hide();\r
        })\r
        \r
+       \r
+       $('.widjet-x').click(function(e){\r
+               e.preventDefault();\r
+               $(this).siblings('ul').hide('slow');\r
+               $(this).hide();\r
+       })\r
+       \r
 });\r
 \r
 $(window).resize(function() {\r
index 47f8741..afc5d8a 100644 (file)
@@ -3,23 +3,25 @@
 {% load filters %}
 
 {% block page.body %}
+{% with object.owners as owners %}
+{% with object.quota as quota %}
 <div class="projects">
        
        <h2>
-               {% if request.user in object.members %}
+               {% if object.is_member %}
                        <em>
-                               {% if request.user in object.owner.all %}
+                               {% if object.is_owner %}
                                        [ADMINISTRATOR]
                                {%  else %}
                                        [ ENROLLED ]
                                {% endif %}
                        </em>           
                {% endif %}
-               <span>[ {{object.kind|upper}} ]</span>  
+               <span>[ {{object.kindname|upper}} ]</span>
         </h2>
         
         <div class="details">
-               {% if request.user in object.owner.all %}
+               {% if object.is_owner %}
                        <a href="#" class="edit">[ EDIT GROUP INFO ]</a>
                {% endif %}
                <div class="data">
                         </dl>
                </div>
                <div class="editable" style="display:none;">
-               <form action="{% url astakos.im.views.group_update object.id %}" method="post"
+               <form action="" method="post"
                    class="withlabels">{% csrf_token %}
-                   {% include "im/form_render.html" %}
-                   <div class="form-row submit">
-                       <input type="submit" class="submit altcol" value="FINISHED EDITING" />
-                   </div>
+                   {% with update_form as form %}
+                    {% include "im/form_render.html" %}
+                    <div class="form-row submit">
+                        <input type="submit" class="submit altcol" value="FINISHED EDITING" />
+                    </div>
+                   {% endwith %}
            </form>
                </div>
         </div>
@@ -51,7 +55,7 @@
                        <dt>Name</dt>
                        <dd>{{object.name}}&nbsp;</dd>
                        <dt>Type</dt>
-                       <dd>{{object.kind|capfirst}}&nbsp;</dd>
+                       <dd>{{object.kindname|capfirst}}&nbsp;</dd>
                        <dt>Issue date:</dt>
                        <dd>{{object.issue_date|date:"d/m/Y"}}&nbsp;</dd>
                        <dt>Expiration Date</dt>
@@ -61,8 +65,9 @@
                        <dt>Activated</dt>
                        <dd>{% if object.is_enabled %}Yes{% else %}No{% endif %}</dd>
                        <dt>Owner</dt>
-                       <dd>{% for o in object.owner.all %}
-                    {% if user == o %}
+                       {{ o.owners }}
+                       <dd>{% for o in owners %}
+                    {% if object.is_owner %}
                         Me
                     {% else%}
                         {{o.realname}} ({{o.email}})
         {% endif %} 
         </div>
         <div class="full-dotted">
-               {% if object.members %}
-                <table class="alt-style table_sorting">
-                       <caption>MEMBERS:</caption>
-                       <thead>
-                               <tr>
-                                       <th>User Id</th>
-                                       <th>Name</th>
-                                       <th>Status</th>
-                               </tr>
-                       </thead>
-                       <tbody>
-                       {% for m in object.membership_set.all %}
-              <tr>
-                <td>{{m.person.email}}</td>
-                <td>{{m.person.realname}}</td>
-                {% if m.person in m.group.owner.all %}
-                <td>Owner</td>
-                {% else %}
-                    {% if m.is_approved %}
-                    <td>Approved</td>
+           {% with page|concat:sorting as args %}
+           {% with object.membership_set.select_related.all|paginate:args as membership %}
+            {% if membership %}
+            <form method="GET" class="minimal" action="">
+                <div class="form-row">
+                    <select name="sorting" onchange="this.form.submit();">
+                        <option value="">Sort by</option>
+                        <option value="person__email" {% if sorting == 'person__email' %}selected{% endif %}>User Id</option>
+                        <option value="person__first_name" {% if sorting == 'person__first_name' %}selected{% endif %}>Name</option>
+                        <option value="date_joined" {% if sorting == 'date_joined' %}selected{% endif %}>Status</option>
+                    </select>
+                </div>
+            </form>
+             <table class="alt-style">
+                <caption>MEMBERS:</caption>
+                <thead>
+                    <tr>
+                        <th>User Id</th>
+                        <th>Name</th>
+                        <th>Status</th>
+                    </tr>
+                </thead>
+                <tbody>
+                {% for m in membership.object_list %}
+                  <tr>
+                    <td>{{m.person.email}}</td>
+                    <td>{{m.person.realname}}</td>
+                    {% if m.person in owners %}
+                    <td>Owner</td>
                     {% else %}
-                    <td>Pending 
-                        {% if user in m.group.owner.all %}
-                            <a href="{% url approve_member m.group.id m.person.id %}">Accept</a>
-                            <a href="{% url disapprove_member m.group.id m.person.id  %}">Reject</a>
+                        {% if m.is_approved %}
+                        <td>Approved</td>
+                        {% else %}
+                        <td>Pending
+                            {% if object.is_owner %}
+                                <a href="{% url approve_member object.id m.person.id %}?{% if page %}page={{ page }}{% endif %}{% if sorting %}&sorting={{sorting}}{% endif %}">Accept</a>
+                                <a href="{% url disapprove_member object.id m.person.id  %}?{% if page %}page={{ page }}{% endif %}{% if sorting %}&sorting={{sorting}}{% endif %}">Reject</a>
+                            {% endif %}
+                        </td>    
                         {% endif %}
-                    </td>    
                     {% endif %}
-                {% endif %}
-              </tr>
-            {% endfor %}
-            </tbody>
-                </table>
-                {% else %}
-            <p>No members yet!</p>
-        {% endif %}
+                  </tr>
+                {% endfor %}
+                </tbody>
+             </table>
+             <div class="pagination">
+                <p class="next-prev">
+                    {% if membership.has_previous %}
+                        <a href="?page={{ membership.previous_page_number }}{% if sorting %}&sorting={{sorting}}{% endif %}">previous</a>
+                    {% endif %}
+                    {% if membership.has_next %}
+                        <a href="?page={{ membership.next_page_number }}{% if sorting %}&sorting={{sorting}}{% endif %}">next</a>
+                    {% endif %}
+                </p>
+                <p class="nums">
+                    <span class="current">
+                        Page {{ membership.number }} of {{ membership.paginator.num_pages }}
+                    </span>
+                </p>
+            </div>
+             {% else %}
+                <p>No members yet!</p>
+            {% endif %}
+        {% endwith %}
+        {% endwith %}
         </div>
      
      
-    {% if user in object.owner.all %}
+    {% if object.is_owner %}
     <div class="full-dotted">
-        <form action="{% url add_members object.id %}" method="post" class="withlabels">{% csrf_token %}
+        <form action="" method="post" class="withlabels">{% csrf_token %}
             <h2>Enroll more members</h2>
-                {% with search_form as form %}
+                {% with addmembers_form as form %}
                     {% include "im/form_render.html" %}
                 {% endwith %}
                 <div class="form-row submit">
      
     
 </div>
+{% endwith %}
+{% endwith %}
 {% endblock %}
index 180e5c1..92cbd02 100644 (file)
@@ -4,44 +4,61 @@
 
 {% block page.body %}
 <div class="maincol {% block innerpage.class %}{% endblock %}">
-    <h2>GROUPS</h2>
-    {% if form %}
-    <p>You can search for a group by name</p>
-    <form action="{% url group_search %}" method="post" class="withlabels signup">{% csrf_token %}
-            {% include "im/form_render.html" %}
-            <div class="form-row submit">
-                <input type="submit" class="submit altcol" value="SEARCH" />
-            </div>
-    </form>
-     
-    <form action="{% url group_all %}" method="post" class="link-like">{% csrf_token %}
-            <div class="form-row submit">
-                <input type="submit" class="submit altcol" value="Show all groups" />
-            </div>
-    </form>
-    {% else %}
     <div class="projects">
-               <!--<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. <br />You can <a href="{% url group_create_list %}">create a new group</a> or <a href="{% url group_search %}">join</a> to an existing one.</p>
-                
-               <ul class="widjets clearfix">   
-                       <li>
-                               <div>
-                                       <p>WELCOME!<br />Connect with a world of people who share your passions.<br />With millions of groups at your fingertips, it's easy to find the group that's best for you -- no matter your interest.</p>
-                                       <p class="btn"><a href="{% url group_create_list %}" class="submit">CREATE</a></p>
-                               </div>
-                       </li>
-                       <li>
-                               <div>
-                                       <p>LOOKING FOR A GROUP?</p><p>Well, this is the place to start!</br>sdofuisd ofuaofi usdiof uiofu osifuaoi ufisdfiousf oiusd<br /><img alt="THINK ABOUT IT" src="/static/medialibrary/2012/06/behind_okeanos.png"></p>
-                                       <p class="btn"><a href="{% url group_search %}" class="submit">JOIN</a></p>
-                               </div>
-                       </li>
-               </ul>-->
+           <h2>GROUPS</h2>
+           {% if form %}
+           <p>You can search for a group by name</p>
+           <form action="{% url group_search %}" method="post" class="withlabels signup">{% csrf_token %}
+                   {% include "im/form_render.html" %}
+                   <div class="form-row submit">
+                       <input type="submit" class="submit altcol" value="SEARCH" />
+                   </div>
+           </form>
+            
+           <form action="{% url group_all %}" method="post" class="link-like alone">{% csrf_token %}
+               <div class="form-row submit">
+                   <input type="submit" class="submit altcol" value="Show all groups" />
+               </div>
+           </form>
+           {% else %}
+    
+               <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <br>You can <a href="{% url group_create_list %}">create a new group</a> or <a href="{% url group_search %}">join</a> to an existing one.</p>
+               <div class="widjets"> 
+                       <a href="#" class="widjet-x" title="remove boxes">X</a>
+                       <ul class="clearfix">   
+                               <li>
+                                       <div>
+                                               <p>WELCOME!<br>Connect with a world of people who share your passions.<br>With millions of groups at your fingertips, it's easy to find the group that's best for you -- no matter your interest.</p>
+                                               <p class="btn"><a href="{% url group_create_list %}" class="submit">CREATE</a></p>
+                                       </div>
+                               </li>
+                               <li>
+                                       <div>
+                                               <p>LOOKING FOR A GROUP?</p><p>Well, this is the place to start!<br>sdofuisd ofuaofi usdiof uiofu osifuaoi ufisdfiousf oiusd<br><img alt="THINK ABOUT IT" src="/static/medialibrary/2012/06/behind_okeanos.png"></p>
+                                               <p class="btn"><a href="{% url group_search %}" class="submit">JOIN</a></p>
+                                       </div>
+                               </li>
+                       </ul>
+               </div>
         
     {% endif %}
     {% with page_obj.object_list as object_list %}
+    <!-- Search group -->
     {% if object_list %}
         <div class="full-dotted">
+               <form method="GET" class="minimal" action=""> 
+                               <div class="form-row">
+                                       <select name="sorting" onchange="this.form.submit();">
+                                           <option value="">Sort by</option>
+                                           <option value="groupname" {% if sorting == 'groupname' %}selected{% endif %}>Name</option>
+                                   <option value="kindname" {% if sorting == 'kindname' %}selected{% endif %}>Type</option>                    
+                                   <option value="issue_date" {% if sorting == 'issue_date' %}selected{% endif %}>Issue date</option>                  
+                                   <option value="expiration_date" {% if sorting == 'expiration_date' %}selected{% endif %}>Expiration Date</option>
+                                   <option value="approved_members_num" {% if sorting == 'approved_members_num' %}selected{% endif %}>Participants</option> 
+                                       </select>
+                                       <input type="hidden" name="q" value="{{q}}"/>
+                               </div>
+                       </form>
             <table class="alt-style complex">
                 <caption>
                     SEARCH RESULTS
                         {% if o.membership_approval_date %}
     
                         Registered
-                        <form action="{% url group_leave o.id %}" method="post" class="link-like">{% csrf_token %}
-                             <input type="submit"  value="LEAVE GROUP" />
-                        </form>        
+                        {% if not o.is_owner %}
+                            <form action="{% url group_leave o.id %}" method="post" class="link-like">{% csrf_token %}
+                                 <input type="submit"  value="LEAVE GROUP" />
+                            </form>
+                        {% endif %}
                         
                             
 
                     <td><a href="#" class="more-info" title="more info">&nbsp;</a></td>
                   </tr>
                   <tr class="{% cycle 'tmore1' 'tmore2' %}" style="display:none">
-                    <td colspan="8" class="info-td">
+                    <td colspan="7" class="info-td">
                         <div>
                             <p>{{o.desc}}</p>
                             <p>{% if o.homepage%}
-                                Visit it group's home page: <a target="_blank" href="{{ o.homepage }}">{{ o.homepage }}</a>
-                            {% else %}
-                                There is no homepage for this group yet.
+                                Group's home page: <a target="_blank" href="{{ o.homepage }}">{{ o.homepage }}</a>
+                            
                             {% endif %}
                             </p>
                         </div> 
     <div class="pagination">
                <p class="next-prev">
                {% if page_obj.has_previous %}
-                <a href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}">previous</a>
+                <a href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}{% if sorting %}&sorting={{sorting}}{% endif %}">previous</a>
             {% endif %}
             {% if page_obj.has_next %}
-                <a href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}">next</a>
+                <a href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}{% if sorting %}&sorting={{sorting}}{% endif %}">next</a>
             {% endif %}
        </p>
                <p class="nums">
             </span>
                </p>
    </div>
-      {% else %}
-               {% if mine %}
+      <!-- Group listing -->
+        {% else %}
+            {% if mine %}
+            {% with own_page|concat:own_sorting as args %}
+            {% with mine|paginate:args as mine %}
                    <div class="full-dotted">
                                        <form method="GET" class="minimal" action="">
                                                <div class="form-row">
                                                    <select name="own_sorting" onchange="this.form.submit();">
                                                            <option value="">Sort by</option>
                                                            <option value="groupname" {% if own_sorting == 'groupname' %}selected{% endif %}>Name</option>
-                                                   <option value="kindname" {% if own_sorting == 'kindname' %}selected{% endif %}>Type</option>                                
+                                                   <option value="kindname" {% if own_sorting == 'kindname' %}selected{% endif %}>Type</option>                        
+                                                   <option value="issue_date" {% if own_sorting == 'issue_date' %}selected{% endif %}>Issue date</option>                      
+                                                   <option value="expiration_date" {% if own_sorting == 'expiration_date' %}selected{% endif %}>Expiration Date</option>
+                                                   <option value="approved_members_num" {% if own_sorting == 'approved_members_num' %}selected{% endif %}>Participants</option>
+                                                   <option value="is_enabled" {% if own_sorting == 'is_enabled' %}selected{% endif %}>Status</option>
+                                                   <option value="moderation_enabled" {% if own_sorting == 'moderation_enabled' %}selected{% endif %}>Moderation</option>              
                                                        </select>
                                                </div>
                                        </form>
-                                       <table class="alt-style complex" id="">
+                                       <table class="alt-style complex">
                                    <caption>MY GROUPS</caption>
                                    <thead>
                                      <tr>
                                                <div>
                                                        <p>{{o.desc}}</p>
                                                        <p>{% if o.homepage%}
-                                                                               Visit it group's home page: <a href="{{ o.homepage }}">{{ o.homepage }}</a>
-                                                                       {% else %}
-                                                                               There is no homepage for this group yet.
+                                                                               Group's home page: <a href="{{ o.homepage }}">{{ o.homepage }}</a>
                                                                        {% endif %}
                                                                        </p>
                                                </div>  
                         </span>
                                        </p>
                           </div>
-                                
+                       
+               {% endwith %}
+            {% endwith %}
                {% endif %}
-               {% if other %}  
+               
+               {% if other %}
+            {% with other_page|concat:other_sorting as args %}
+            {% with other|paginate:args as other %}
                        <div class="full-dotted">
                                <form method="GET" class="minimal" action="">
                                                <div class="form-row">
                                                            <option value="">Sort by</option>
                                                            <option value="groupname" {% if other_sorting == 'groupname' %}selected{% endif %}>Name</option>
                                                    <option value="kindname" {% if other_sorting == 'kindname' %}selected{% endif %}>Type</option>                      
+                                                   <option value="issue_date" {% if other_sorting == 'issue_date' %}selected{% endif %}>Issue date</option>                    
+                                                   <option value="expiration_date" {% if other_sorting == 'expiration_date' %}selected{% endif %}>Expiration Date</option>
+                                                   <option value="approved_members_num" {% if other_sorting == 'approved_members_num' %}selected{% endif %}>Participants</option>
+                                                   <option value="membership_status" {% if other_sorting == 'membership_status' %}selected{% endif %}>Enrollment Status</option>
+                                                    
                                                        </select>
                                                </div>
                                        </form>
                                        <th>Type</th>
                                        <th>Issued</th>
                                        <th>Expires</th>
+
                                         
                                        <th>Enrolled</th>
                                       
                                        <td>{{ o.approved_members_num }}</td>
                                        
                                        <td>
-                                       {% if o.membership_approval_date %}
-                       
-                                       Registered
+                                       {% if o.membership_status %}
+                                           Registered
                                        <form action="{% url group_leave o.id %}" method="post" class="link-like">{% csrf_token %}
                                             <input type="submit"  value="LEAVE GROUP" />
                                        </form> 
                                            
-                                               
                                        {% else %}
                                            Pending
                                        {% endif %}
                                        <td><a href="#" class="more-info" title="more info">&nbsp;</a></td>
                                      </tr>
                                      <tr class="{% cycle 'tmore1' 'tmore2' %}" style="display:none">
-                                       <td colspan="8" class="info-td">
+                                       <td colspan="7" class="info-td">
                                                <div>
                                                        <p>{{o.desc}}</p>
                                                        <p>{% if o.homepage%}
                         </span>
                                        </p>
                           </div>
-                                
+                   
+                       {% endwith %}
+            {% endwith %}
                        {% endif %}
+               
             {% if q %}
                 <h2>No groups found!</h2>
             {% endif %}
index 917697d..fbb0fc2 100644 (file)
@@ -5,26 +5,39 @@
 {% block page.body %}
 <div class="maincol {% block innerpage.class %}{% endblock %}">
     <div class="section">
-        {% if quota %}
-          <table class="zebra-striped id-sorted">
-            <thead>
-              <tr>
-                <th>Resource</th>
-                <th>Limit</th>
-              </tr>
-            </thead>
-            <tbody>
-            {% for k in quota|dkeys %}
-                <tr>
-                    <td>{{ k }}</td>
-                    <td>{{ quota|lookup:k }}</td>
-                  </tr>
+            {% for k, v in user.quota|items %}
+                <strong>{{k}}</strong>
+                <table class="zebra-striped id-sorted">
+<!-- 
+                    <thead>
+                      <tr>
+                        <th>Limit (Group)</th>
+                      </tr>
+                    </thead>
+ -->
+                    <tbody>
+                    {% for m in user.membership_set.select_related.all %}
+                        {% if m.group.is_enabled %}
+                            {% with m.group.quota as quota %}
+                            {% if  quota %}
+                                {% for kk, vv in quota|items %}
+                                    {% if k == kk %}
+                                    <tr>
+                                        <td>{{ vv }} ({{m.group.name}})</td>
+                                    </tr>
+                                    {% endif %}
+                                {% endfor %}
+                            {% endif %}
+                            {% endwith %}
+                        {% endif %}
+                    {% endfor %}
+                                    <tr>
+                                        <td><strong>{{ v }}</strong></td>
+                                    </tr>
+                                    <tr/>
+                    </tbody>
+                </table>
             {% endfor %}
-            </tbody>
-        </table>
-        {% else %}
-            <p>No policies</p>
-        {% endif %}
     </div>
 </div>
 {% endblock %}
index c0c9edb..82031f0 100644 (file)
 import calendar
 import datetime
 
+from collections import defaultdict
+
 from django import template
+from django.core.paginator import Paginator, EmptyPage
+from django.db.models.query import QuerySet
 
 from astakos.im.settings import PAGINATE_BY
 
 register = template.Library()
 
+DELIM = ','
+
 @register.filter
 def monthssince(joined_date):
     now = datetime.datetime.now()
@@ -88,4 +94,44 @@ def todate(value, arg = ''):
 
 @register.filter
 def rcut(value, chars = '/'):
-    return value.rstrip(chars)
\ No newline at end of file
+    return value.rstrip(chars)
+
+@register.filter
+def paginate(l, args):
+    page, delim, sorting = args.partition(DELIM)
+    if sorting:
+        if isinstance(l, QuerySet):
+            l = l.order_by(sorting)
+        elif isinstance(l, list):
+            default = ''
+            if sorting.endswith('_date'):
+                default = datetime.datetime.utcfromtimestamp(0)
+            l.sort(key=lambda i: getattr(i, sorting) \
+                        if getattr(i, sorting) else default)
+            
+    paginator = Paginator(l, PAGINATE_BY)
+    
+    try:
+        page_number = int(page)
+    except ValueError:
+        if page == 'last':
+            page_number = paginator.num_pages
+        else:
+            page_number = 1
+    try:
+        page = paginator.page(page_number)
+    except EmptyPage:
+        page = paginator.page(1)
+    return page
+
+@register.filter
+def concat(str1, str2):
+    if not str2:
+        return str(str1)
+    return '%s%s%s' % (str1, DELIM, str2)
+
+@register.filter
+def items(d):
+    if isinstance(d, defaultdict):
+        return d.iteritems()
+    return d
\ No newline at end of file
index bc164da..a62b71b 100644 (file)
@@ -67,8 +67,6 @@ urlpatterns = patterns('astakos.im.views',
                            'group_list', {}, name='group_list'),
                        url(r'^group/(?P<group_id>\d+)/?$', 'group_detail',
                            {}, name='group_detail'),
-                       url(r'^group/update/(?P<group_id>\d+)/?$',
-                           'group_update', {}, name='group_update'),
                        url(r'^group/search/?$',
                            'group_search', {}, name='group_search'),
                        url(r'^group/all/?$',
@@ -81,8 +79,6 @@ urlpatterns = patterns('astakos.im.views',
                            'approve_member', {}, name='approve_member'),
                        url(r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/disapprove/?$',
                            'disapprove_member', {}, name='disapprove_member'),
-                       url(r'^group/(?P<group_id>\d+)/add/?$',
-                           'add_members', {}, name='add_members'),
                        url(r'^group/create/?$', 'group_create_list', {},
                            name='group_create_list'),
                        )
index b31b09f..c5cd73e 100644 (file)
@@ -50,14 +50,14 @@ from django.forms.fields import URLField
 from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, \
     HttpResponseRedirect, HttpResponseBadRequest, Http404
 from django.shortcuts import redirect
-from django.template import RequestContext, loader
+from django.template import RequestContext, loader as template_loader
 from django.utils.http import urlencode
 from django.utils.translation import ugettext as _
 from django.views.generic.create_update import (create_object, delete_object,
                                                 get_model_and_form_class)
 from django.views.generic.list_detail import object_list, object_detail
 from django.http import HttpResponseBadRequest
-from django.core.paginator import Paginator, InvalidPage
+from django.core.xheaders import populate_xheaders
 
 from astakos.im.models import (
     AstakosUser, ApprovalTerms, AstakosGroup, Resource,
@@ -69,7 +69,8 @@ from astakos.im.forms import (LoginForm, InvitationForm, ProfileForm,
                               ExtendedPasswordChangeForm, EmailChangeForm,
                               AstakosGroupCreationForm, AstakosGroupSearchForm,
                               AstakosGroupUpdateForm, AddGroupMembersForm,
-                              AstakosGroupSortForm, TimelineForm)
+                              AstakosGroupSortForm, MembersSortForm,
+                              TimelineForm)
 from astakos.im.functions import (send_feedback, SendMailError,
                                   invite as invite_func, logout as auth_logout,
                                   activate as activate_func,
@@ -98,7 +99,7 @@ def render_response(template, tab=None, status=200, reset_cookie=False,
     if tab is None:
         tab = template.partition('_')[0].partition('.html')[0]
     kwargs.setdefault('tab', tab)
-    html = loader.render_to_string(
+    html = template_loader.render_to_string(
         template, kwargs, context_instance=context_instance)
     response = HttpResponse(html, status=status)
     if reset_cookie:
@@ -465,12 +466,13 @@ def logout(request, template='registration/logged_out.html', extra_context=None)
         return response
     messages.success(request, _('You have successfully logged out.'))
     context = get_context(request, extra_context)
-    response.write(loader.render_to_string(template, context_instance=context))
+    response.write(template_loader.render_to_string(template, context_instance=context))
     return response
 
 
 @transaction.commit_manually
-def activate(request, greeting_email_template_name='im/welcome_email.txt', helpdesk_email_template_name='im/helpdesk_notification.txt'):
+def activate(request, greeting_email_template_name='im/welcome_email.txt',
+             helpdesk_email_template_name='im/helpdesk_notification.txt'):
     """
     Activates the user identified by the ``auth`` request parameter, sends a welcome email
     and renews the user token.
@@ -649,7 +651,6 @@ def group_add(request, kind_name='default'):
     except:
         return HttpResponseBadRequest(_('No such group kind'))
 
-    template_loader = loader
     post_save_redirect = '/im/group/%(id)s/'
     context_processors = None
     model, form_class = get_model_and_form_class(
@@ -732,9 +733,11 @@ def group_list(request):
         (SELECT COUNT(*) FROM im_membership
             WHERE group_id = im_astakosgroup.group_ptr_id
             AND date_joined IS NOT NULL) AS approved_members_num,
-        (SELECT date_joined FROM im_membership
-            WHERE group_id = im_astakosgroup.group_ptr_id
-            AND person_id = %s) AS membership_approval_date
+        (SELECT CASE WHEN(
+                    SELECT date_joined FROM im_membership
+                    WHERE group_id = im_astakosgroup.group_ptr_id
+                    AND person_id = %s) IS NULL
+                    THEN 0 ELSE 1 END) AS membership_status
         FROM im_astakosgroup
         INNER JOIN im_membership ON (
             im_astakosgroup.group_ptr_id = im_membership.group_id)
@@ -752,81 +755,105 @@ def group_list(request):
             d['own'].append(g)
         else:
             d['other'].append(g)
-    d.setdefault('own', [])
-    d.setdefault('other', [])
-    for k, l in d.iteritems():
-        page = request.GET.get('%s_page' % k, 1)
-        sorting = globals()['%s_sorting' % k] = request.GET.get('%s_sorting' % k)
-        if sorting:
-            sort_form = AstakosGroupSortForm({'sort_by': sorting})
-            if sort_form.is_valid():
-                l.sort(key=lambda i: getattr(i, sorting))
-                globals()['%s_sorting' % k] = sorting
-        paginator = Paginator(l, PAGINATE_BY)
-        
-        try:
-            page_number = int(page)
-        except ValueError:
-            if page == 'last':
-                page_number = paginator.num_pages
-            else:
-                # Page is not 'last', nor can it be converted to an int.
-                raise Http404
-        try:
-            page_obj = globals()['%s_page_obj' % k] = paginator.page(page_number)
-        except InvalidPage:
-            raise Http404
+    
+    # validate sorting
+    fields = ('own', 'other')
+    for f in fields:
+        v = globals()['%s_sorting' % f] = request.GET.get('%s_sorting' % f)
+        if v:
+            form = AstakosGroupSortForm({'sort_by': v})
+            if not form.is_valid():
+                globals()['%s_sorting' % f] = form.cleaned_data.get('sort_by')
     return object_list(request, queryset=none,
                        extra_context={'is_search':False,
-                                      'mine': own_page_obj,
-                                      'other': other_page_obj,
+                                      'mine': d['own'],
+                                      'other': d['other'],
                                       'own_sorting': own_sorting,
-                                      'other_sorting': other_sorting
+                                      'other_sorting': other_sorting,
+                                      'own_page': request.GET.get('own_page', 1),
+                                      'other_page': request.GET.get('other_page', 1)
                                       })
 
 
 @signed_terms_required
 @login_required
 def group_detail(request, group_id):
+    q = AstakosGroup.objects.select_related().filter(pk=group_id)
+    q = q.extra(select={
+        'is_member': """SELECT CASE WHEN EXISTS(
+                            SELECT id FROM im_membership
+                            WHERE group_id = im_astakosgroup.group_ptr_id
+                            AND person_id = %s)
+                        THEN 1 ELSE 0 END""" % request.user.id,
+        'is_owner': """SELECT CASE WHEN EXISTS(
+                        SELECT id FROM im_astakosuser_owner
+                        WHERE astakosgroup_id = im_astakosgroup.group_ptr_id
+                        AND astakosuser_id = %s)
+                        THEN 1 ELSE 0 END""" % request.user.id,
+        'kindname': """SELECT name FROM im_groupkind
+                       WHERE id = im_astakosgroup.kind_id"""})
+    
+    model = q.model
+    context_processors = None
+    mimetype = None
     try:
-        group = AstakosGroup.objects.select_related().get(id=group_id)
+        obj = q.get()
     except AstakosGroup.DoesNotExist:
-        return HttpResponseBadRequest(_('Invalid group.'))
-    form = AstakosGroupUpdateForm(instance=group)
-    search_form = AddGroupMembersForm()
-    return object_detail(request,
-                         AstakosGroup.objects.all(),
-                         object_id=group_id,
-                         extra_context={'quota': group.quota,
-                                        'form': form,
-                                        'search_form': search_form}
-                         )
+        raise Http404("No %s found matching the query" % (
+            model._meta.verbose_name))
+    
+    update_form = AstakosGroupUpdateForm(instance=obj)
+    addmembers_form = AddGroupMembersForm()
+    if request.method == 'POST':
+        update_data = {}
+        addmembers_data = {}
+        for k,v in request.POST.iteritems():
+            if k in update_form.fields:
+                update_data[k] = v
+            if k in addmembers_form.fields:
+                addmembers_data[k] = v
+        update_data = update_data or None
+        addmembers_data = addmembers_data or None
+        update_form = AstakosGroupUpdateForm(update_data, instance=obj)
+        addmembers_form = AddGroupMembersForm(addmembers_data)
+        if update_form.is_valid():
+            update_form.save()
+        if addmembers_form.is_valid():
+            map(obj.approve_member, addmembers_form.valid_users)
+            addmembers_form = AddGroupMembersForm()
+    
+    template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
+    t = template_loader.get_template(template_name)
+    c = RequestContext(request, {
+        'object': obj,
+    }, context_processors)
+    
+    # validate sorting
+    sorting= request.GET.get('sorting')
+    if sorting:
+        form = MembersSortForm({'sort_by': sorting})
+        if form.is_valid():
+            sorting = form.cleaned_data.get('sort_by')
+         
+    extra_context = {'update_form': update_form,
+                     'addmembers_form': addmembers_form,
+                     'page': request.GET.get('page', 1),
+                     'sorting': sorting}
+    for key, value in extra_context.items():
+        if callable(value):
+            c[key] = value()
+        else:
+            c[key] = value
+    response = HttpResponse(t.render(c), mimetype=mimetype)
+    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
+    return response
 
 
 @signed_terms_required
 @login_required
-def group_update(request, group_id):
-    if request.method != 'POST':
-        return HttpResponseBadRequest('Method not allowed.')
-    try:
-        group = AstakosGroup.objects.select_related().get(id=group_id)
-    except AstakosGroup.DoesNotExist:
-        return HttpResponseBadRequest(_('Invalid group.'))
-    form = AstakosGroupUpdateForm(request.POST, instance=group)
-    if form.is_valid():
-        form.save()
-    search_form = AddGroupMembersForm()
-    return object_detail(request,
-                         AstakosGroup.objects.all(),
-                         object_id=group_id,
-                         extra_context={'quota': group.quota,
-                                        'form': form,
-                                        'search_form': search_form})
-
-@signed_terms_required
-@login_required
 def group_search(request, extra_context=None, **kwargs):
     q = request.GET.get('q')
+    sorting = request.GET.get('sorting')
     if request.method == 'GET':
         form = AstakosGroupSearchForm({'q': q} if q else None)
     else:
@@ -853,7 +880,16 @@ def group_search(request, extra_context=None, **kwargs):
                     SELECT date_joined FROM im_membership
                     WHERE group_id = im_astakosgroup.group_ptr_id
                     AND person_id = %s)
+                    THEN 1 ELSE 0 END""" % request.user.id,
+                'is_owner': """
+                    SELECT CASE WHEN EXISTS(
+                    SELECT id FROM im_astakosuser_owner
+                    WHERE astakosgroup_id = im_astakosgroup.group_ptr_id
+                    AND astakosuser_id = %s)
                     THEN 1 ELSE 0 END""" % request.user.id})
+        if sorting:
+            # TODO check sorting value
+            queryset = queryset.order_by(sorting)
     else:
         queryset = AstakosGroup.objects.none()
     return object_list(
@@ -864,7 +900,8 @@ def group_search(request, extra_context=None, **kwargs):
         template_name='im/astakosgroup_list.html',
         extra_context=dict(form=form,
                            is_search=True,
-                           q=q))
+                           q=q,
+                           sorting=sorting))
 
 @signed_terms_required
 @login_required
@@ -888,6 +925,10 @@ def group_all(request, extra_context=None, **kwargs):
                     WHERE group_id = im_astakosgroup.group_ptr_id
                     AND person_id = %s)
                     THEN 1 ELSE 0 END""" % request.user.id})
+    sorting = request.GET.get('sorting')
+    if sorting:
+        # TODO check sorting value
+        q = q.order_by(sorting)
     return object_list(
                 request,
                 q,
@@ -895,7 +936,8 @@ def group_all(request, extra_context=None, **kwargs):
                 page=request.GET.get('page') or 1,
                 template_name='im/astakosgroup_list.html',
                 extra_context=dict(form=AstakosGroupSearchForm(),
-                                   is_search=True))
+                                   is_search=True,
+                                   sorting=sorting))
 
 
 @signed_terms_required
@@ -923,8 +965,7 @@ def group_leave(request, group_id):
     try:
         m = Membership.objects.select_related().get(
             group__id=group_id,
-            person=request.user
-        )
+            person=request.user)
     except Membership.DoesNotExist:
         return HttpResponseBadRequest(_('Invalid membership.'))
     if request.user in m.group.owner.all():
@@ -936,9 +977,7 @@ def group_leave(request, group_id):
         template_name='im/astakosgroup_list.html',
         post_delete_redirect=reverse(
             'group_detail',
-            kwargs=dict(group_id=group_id)
-        )
-    )
+            kwargs=dict(group_id=group_id)))
 
 
 def handle_membership(func):
@@ -947,20 +986,14 @@ def handle_membership(func):
         try:
             m = Membership.objects.select_related().get(
                 group__id=group_id,
-                person__id=user_id
-            )
+                person__id=user_id)
         except Membership.DoesNotExist:
             return HttpResponseBadRequest(_('Invalid membership.'))
         else:
             if request.user not in m.group.owner.all():
                 return HttpResponseForbidden(_('User is not a group owner.'))
             func(request, m)
-            return render_response(
-                template='im/astakosgroup_detail.html',
-                context_instance=get_context(request),
-                object=m.group,
-                quota=m.group.quota
-            )
+            return group_detail(request, group_id)
     return wrapper
 
 
@@ -975,6 +1008,7 @@ def approve_member(request, membership):
         messages.success(request, msg)
     except BaseException, e:
         logger.exception(e)
+        realname = membership.person.realname
         msg = _('Something went wrong during %s\'s approval.' % realname)
         messages.error(request, msg)
 
@@ -994,46 +1028,18 @@ def disapprove_member(request, membership):
         messages.error(request, msg)
 
 
-
-
-@signed_terms_required
-@login_required
-def add_members(request, group_id):
-    if request.method != 'POST':
-        return HttpResponseBadRequest(_('Bad method'))
-    try:
-        group = AstakosGroup.objects.select_related().get(id=group_id)
-    except AstakosGroup.DoesNotExist:
-        return HttpResponseBadRequest(_('Invalid group.'))
-    search_form = AddGroupMembersForm(request.POST)
-    if search_form.is_valid():
-        users = search_form.get_valid_users()
-        map(group.approve_member, users)
-        search_form = AddGroupMembersForm()
-    form = AstakosGroupUpdateForm(instance=group)
-    return object_detail(request,
-                         AstakosGroup.objects.all(),
-                         object_id=group_id,
-                         extra_context={'quota': group.quota,
-                                        'form': form,
-                                        'search_form' : search_form})
-
-
 @signed_terms_required
 @login_required
 def resource_list(request):
     return render_response(
         template='im/astakosuserquota_list.html',
-        context_instance=get_context(request),
-        quota=request.user.quota
-    )
+        context_instance=get_context(request))
 
 
 def group_create_list(request):
     return render_response(
         template='im/astakosgroup_create_list.html',
-        context_instance=get_context(request),
-    )
+        context_instance=get_context(request),)
 
 
 @signed_terms_required
@@ -1057,7 +1063,7 @@ def billing(request):
     
     try:
         status, data = r.result
-        data=clear_billing_data(data)
+        data=_clear_billing_data(data)
         if status != 200:
             messages.error(request, _('Service response status: %d' % status))
     except:
@@ -1074,7 +1080,7 @@ def billing(request):
         start=int(start),
         month_last_day=month_last_day)  
     
-def clear_billing_data(data):
+def _clear_billing_data(data):
     
     # remove addcredits entries
     def isnotcredit(e):
@@ -1123,3 +1129,4 @@ def timeline(request):
                            form=form,
                            timeline_header=timeline_header,
                            timeline_body=timeline_body)
+    return data