allura
修訂 | 3281984437c586ed54a854caec2396d901817886 (tree) |
---|---|
時間 | 2012-07-18 23:28:54 |
作者 | Igor Bondarenko <jetmind2@gmai...> |
Commiter | Dave Brondsema |
[#4349] ticket:110 Add /nf/admin/new_projects page.
@@ -2,14 +2,16 @@ import logging | ||
2 | 2 | from datetime import datetime, timedelta |
3 | 3 | from collections import defaultdict |
4 | 4 | |
5 | -from tg import expose, flash, config, request | |
5 | +from tg import expose, validate, flash, config, request | |
6 | 6 | from tg.decorators import with_trailing_slash, without_trailing_slash |
7 | 7 | from ming.orm import session |
8 | 8 | import pymongo |
9 | -from pylons import c | |
9 | +from pylons import c, g | |
10 | +from formencode import validators | |
10 | 11 | |
11 | 12 | from allura.lib import helpers as h |
12 | 13 | from allura.lib.security import require_access |
14 | +from allura.lib.widgets import form_fields as ffw | |
13 | 15 | from allura import model as M |
14 | 16 | from allura.command.show_models import dfs, build_model_inheritance_graph |
15 | 17 |
@@ -18,6 +20,9 @@ from urlparse import urlparse | ||
18 | 20 | |
19 | 21 | log = logging.getLogger(__name__) |
20 | 22 | |
23 | +class W: | |
24 | + page_list = ffw.PageList() | |
25 | + page_size = ffw.PageSize() | |
21 | 26 | |
22 | 27 | class SiteAdminController(object): |
23 | 28 |
@@ -164,3 +169,22 @@ class SiteAdminController(object): | ||
164 | 169 | flash('Artifact not found', 'error') |
165 | 170 | |
166 | 171 | return data |
172 | + | |
173 | + @expose('jinja:allura:templates/site_admin_new_projects.html') | |
174 | + @validate(dict(page=validators.Int(if_empty=0), | |
175 | + limit=validators.Int(if_empty=100))) | |
176 | + def new_projects(self, page=0, limit=100, **kwargs): | |
177 | + c.page_list = W.page_list | |
178 | + c.page_size = W.page_size | |
179 | + limit, pagenum, start = g.handle_paging(limit, page, default=100) | |
180 | + count = 0 | |
181 | + projects = (M.Project.query.find({'name': {'$regex': '^[^u][^/]'}}) | |
182 | + .sort('_id', -1)) | |
183 | + count = projects.count() | |
184 | + projects = projects.skip(start).limit(limit) | |
185 | + return { | |
186 | + 'projects': projects, | |
187 | + 'limit': limit, | |
188 | + 'pagenum': pagenum, | |
189 | + 'count': count | |
190 | + } |
@@ -597,6 +597,13 @@ class Project(MappedClass, ActivityNode, ActivityObject): | ||
597 | 597 | g.credentials.project_roles(project_id=self.root_project._id).named) |
598 | 598 | return [ r.user for r in named_roles.roles_that_reach if r.user_id is not None ] |
599 | 599 | |
600 | + def admins(self): | |
601 | + """Find all the users who have 'Admin' role for this project""" | |
602 | + admin_role = ProjectRole.query.get(name='Admin', project_id=self._id) | |
603 | + if not admin_role: | |
604 | + return [] | |
605 | + return [r.user.username for r in admin_role.users_with_role(self)] | |
606 | + | |
600 | 607 | def user_in_project(self, username): |
601 | 608 | from .auth import User |
602 | 609 | u = User.by_username(username) |
@@ -2746,7 +2746,13 @@ div.codehilite pre div.code_block { | ||
2746 | 2746 | padding-left:10px; |
2747 | 2747 | width: 97%; |
2748 | 2748 | } |
2749 | - | |
2750 | 2749 | input.nofloat { |
2751 | 2750 | float: none; |
2752 | 2751 | } |
2752 | +table thead tr th.tiny.narrow, table tr td.narrow { | |
2753 | + padding-left: 2px; | |
2754 | + padding-right: 2px; | |
2755 | +} | |
2756 | +#selected-projects { | |
2757 | + padding: 10px 10px; | |
2758 | +} |
@@ -0,0 +1,15 @@ | ||
1 | +$(document).ready(function() { | |
2 | + $('.js-select-project').change(function() { | |
3 | + var shortname = $(this).attr('data-shortname'); | |
4 | + if ($(this).is(':checked')) { | |
5 | + $('#selected-projects').append(' ' + shortname); | |
6 | + } else { | |
7 | + var shortnames = $('#selected-projects').text().split(' '); | |
8 | + for (var i = 0; i < shortnames.length; i++) { | |
9 | + if (shortnames[i] == shortname) break; | |
10 | + } | |
11 | + shortnames.splice(i, 1); | |
12 | + $('#selected-projects').text(shortnames.join(' ')); | |
13 | + } | |
14 | + }); | |
15 | +}); |
@@ -1,4 +1,7 @@ | ||
1 | 1 | {% set hide_left_bar=False %} |
2 | +{% if page == 'new_projects' %} | |
3 | + {% set hide_left_bar=True %} | |
4 | +{% endif %} | |
2 | 5 | {% extends g.theme.master %} |
3 | 6 | |
4 | 7 | {% block title %}Forge Site Admin{% endblock %} |
@@ -16,6 +19,7 @@ | ||
16 | 19 | <li class="{{page=='stats' and 'active' or ''}}"><a href="stats"><b data-icon="{{g.icons['stats'].char}}" class="ico {{g.icons['stats'].css}}"></b>Stats</a></li> |
17 | 20 | <li class="{{page=='api_tickets' and 'active' or ''}}"><a href="api_tickets"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>API Tickets</a></li> |
18 | 21 | <li class="{{page=='add_subscribers' and 'active' or ''}}"><a href="add_subscribers"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Add Subscribers</a></li> |
22 | + <li class="{{page=='new_projects' and 'active' or ''}}"><a href="new_projects"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>New Projects</a></li> | |
19 | 23 | </ul> |
20 | 24 | </div> |
21 | 25 | {% endblock %} |
@@ -0,0 +1,44 @@ | ||
1 | +{% set page="new_projects" %} | |
2 | +{% extends 'allura:templates/site_admin.html' %} | |
3 | + | |
4 | +{% block content %} | |
5 | + {{ c.page_size.display(limit=limit, count=count, page=pagenum) }} | |
6 | + <table> | |
7 | + <thead> | |
8 | + <tr> | |
9 | + <th class="narrow"></th> | |
10 | + <th class="narrow">Created</th> | |
11 | + <th>Shortname</th> | |
12 | + <th>Name</th> | |
13 | + <th>Short description</th> | |
14 | + <th>Summary</th> | |
15 | + <th>Deleted?</th> | |
16 | + <th>Homepage</th> | |
17 | + <th>Admins</th> | |
18 | + </tr> | |
19 | + </thead> | |
20 | + {% for p in projects %} | |
21 | + <tr> | |
22 | + <td class="narrow"> | |
23 | + <input type="checkbox" class="js-select-project" data-shortname="{{ p.shortname }}" /> | |
24 | + </td> | |
25 | + <td class="narrow"> | |
26 | + <small>{{ p._id.generation_time.strftime('%Y-%m-%d %H:%M:%S') }}</small> | |
27 | + </td> | |
28 | + <td><small>{{ p.shortname }}</small></td> | |
29 | + <td><small>{{ p.name }}</small></td> | |
30 | + <td><small>{{ p.short_description }}</small></td> | |
31 | + <td><small>{{ p.summary }}</small></td> | |
32 | + <td><small>{{ 'Yes' if p.deleted else 'No' }}</small></td> | |
33 | + <td><small>{{ p.external_homepage|urlize(22) }}</small></td> | |
34 | + <td><small>{{ p.admins()|join(' ') }}</small></td> | |
35 | + </tr> | |
36 | + {% endfor %} | |
37 | + </table> | |
38 | + {{ c.page_list.display(limit=limit, count=count, page=pagenum) }} | |
39 | + <div id="selected-projects"></div> | |
40 | +{% endblock %} | |
41 | + | |
42 | +{% block extra_js %} | |
43 | + <script type="text/javascript" src="{{g.forge_static('js/site_admin_new_projects.js')}}"></script> | |
44 | +{% endblock %} |
@@ -40,3 +40,10 @@ class TestSiteAdmin(TestController): | ||
40 | 40 | def test_tickets_access(self): |
41 | 41 | r = self.app.get('/nf/admin/api_tickets', extra_environ=dict( |
42 | 42 | username='test-user'), status=403) |
43 | + | |
44 | + def test_new_projects_access(self): | |
45 | + self.app.get('/nf/admin/new_projects', extra_environ=dict( | |
46 | + username='test_user'), status=403) | |
47 | + r = self.app.get('/nf/admin/new_projects', extra_environ=dict( | |
48 | + username='*anonymous'), status=302).follow() | |
49 | + assert 'Login' in r |