##// END OF EJS Templates
#179 Added followers page
marcink -
r1279:cb216757 beta
parent child Browse files
Show More
@@ -0,0 +1,57
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.controllers.followers
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Followers controller for rhodecode
7
8 :created_on: Apr 23, 2011
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
26
27 from pylons import tmpl_context as c, request
28
29 from rhodecode.lib.helpers import Page
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
31 from rhodecode.lib.base import BaseRepoController, render
32 from rhodecode.model.db import Repository, User, UserFollowing
33
34 log = logging.getLogger(__name__)
35
36
37 class FollowersController(BaseRepoController):
38
39 @LoginRequired()
40 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
41 'repository.admin')
42 def __before__(self):
43 super(FollowersController, self).__before__()
44
45 def followers(self, repo_name):
46 p = int(request.params.get('page', 1))
47 repo_id = getattr(Repository.by_repo_name(repo_name), 'repo_id')
48 d = UserFollowing.get_repo_followers(repo_id)\
49 .order_by(UserFollowing.follows_from)
50 c.followers_pager = Page(d, page=p, items_per_page=20)
51
52 c.followers_data = render('/followers/followers_data.html')
53
54 if request.params.get('partial'):
55 return c.followers_data
56
57 return render('/followers/followers.html')
@@ -0,0 +1,33
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3
4 <%def name="title()">
5 ${c.repo_name} ${_('Followers')} - ${c.rhodecode_name}
6 </%def>
7
8
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(u'Home',h.url('/'))}
11 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
14 ${_('followers')}
15 </%def>
16
17 <%def name="page_nav()">
18 ${self.menu('followers')}
19 </%def>
20 <%def name="main()">
21 <div class="box">
22 <!-- box / title -->
23 <div class="title">
24 ${self.breadcrumbs()}
25 </div>
26 <!-- end box / title -->
27 <div class="table">
28 <div id="followers">
29 ${c.followers_data}
30 </div>
31 </div>
32 </div>
33 </%def> No newline at end of file
@@ -0,0 +1,37
1 ## -*- coding: utf-8 -*-
2
3
4 % for f in c.followers_pager:
5 <div>
6 <div class="follower_user">
7 <div class="gravatar">
8 <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/>
9 </div>
10 <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span>
11 </div>
12 <div style="clear:both;padding-top: 10px"></div>
13 <div class="follower_date">${_('Started following on')} - ${f.follows_from}</div>
14 <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div>
15 </div>
16 % endfor
17
18
19 <div class="pagination-wh pagination-left">
20 <script type="text/javascript">
21 var data_div = 'followers';
22 YAHOO.util.Event.onDOMReady(function(){
23 YAHOO.util.Event.addListener(
24 YUD.getElementsByClassName('pager_link'),"click",
25 function(){
26 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');
27 });
28 });
29 </script>
30
31 ${c.followers_pager.pager('$link_previous ~2~ $link_next',
32 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
33 success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
34 YUE.on(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
35 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
36 YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
37 </div> No newline at end of file
@@ -1,339 +1,344
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10 from rhodecode.lib.utils import check_repo_fast as cr
10 from rhodecode.lib.utils import check_repo_fast as cr
11
11
12
12
13 def make_map(config):
13 def make_map(config):
14 """Create, configure and return the routes Mapper"""
14 """Create, configure and return the routes Mapper"""
15 rmap = Mapper(directory=config['pylons.paths']['controllers'],
15 rmap = Mapper(directory=config['pylons.paths']['controllers'],
16 always_scan=config['debug'])
16 always_scan=config['debug'])
17 rmap.minimization = False
17 rmap.minimization = False
18 rmap.explicit = False
18 rmap.explicit = False
19
19
20 def check_repo(environ, match_dict):
20 def check_repo(environ, match_dict):
21 """
21 """
22 check for valid repository for proper 404 handling
22 check for valid repository for proper 404 handling
23 :param environ:
23 :param environ:
24 :param match_dict:
24 :param match_dict:
25 """
25 """
26 repo_name = match_dict.get('repo_name')
26 repo_name = match_dict.get('repo_name')
27 return not cr(repo_name, config['base_path'])
27 return not cr(repo_name, config['base_path'])
28
28
29 # The ErrorController route (handles 404/500 error pages); it should
29 # The ErrorController route (handles 404/500 error pages); it should
30 # likely stay at the top, ensuring it can always be resolved
30 # likely stay at the top, ensuring it can always be resolved
31 rmap.connect('/error/{action}', controller='error')
31 rmap.connect('/error/{action}', controller='error')
32 rmap.connect('/error/{action}/{id}', controller='error')
32 rmap.connect('/error/{action}/{id}', controller='error')
33
33
34 #==========================================================================
34 #==========================================================================
35 # CUSTOM ROUTES HERE
35 # CUSTOM ROUTES HERE
36 #==========================================================================
36 #==========================================================================
37
37
38 #MAIN PAGE
38 #MAIN PAGE
39 rmap.connect('home', '/', controller='home', action='index')
39 rmap.connect('home', '/', controller='home', action='index')
40 rmap.connect('repo_switcher', '/repos', controller='home',
40 rmap.connect('repo_switcher', '/repos', controller='home',
41 action='repo_switcher')
41 action='repo_switcher')
42 rmap.connect('bugtracker',
42 rmap.connect('bugtracker',
43 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
43 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
44 _static=True)
44 _static=True)
45 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
45 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
46
46
47 #ADMIN REPOSITORY REST ROUTES
47 #ADMIN REPOSITORY REST ROUTES
48 with rmap.submapper(path_prefix='/_admin', controller='admin/repos') as m:
48 with rmap.submapper(path_prefix='/_admin', controller='admin/repos') as m:
49 m.connect("repos", "/repos",
49 m.connect("repos", "/repos",
50 action="create", conditions=dict(method=["POST"]))
50 action="create", conditions=dict(method=["POST"]))
51 m.connect("repos", "/repos",
51 m.connect("repos", "/repos",
52 action="index", conditions=dict(method=["GET"]))
52 action="index", conditions=dict(method=["GET"]))
53 m.connect("formatted_repos", "/repos.{format}",
53 m.connect("formatted_repos", "/repos.{format}",
54 action="index",
54 action="index",
55 conditions=dict(method=["GET"]))
55 conditions=dict(method=["GET"]))
56 m.connect("new_repo", "/repos/new",
56 m.connect("new_repo", "/repos/new",
57 action="new", conditions=dict(method=["GET"]))
57 action="new", conditions=dict(method=["GET"]))
58 m.connect("formatted_new_repo", "/repos/new.{format}",
58 m.connect("formatted_new_repo", "/repos/new.{format}",
59 action="new", conditions=dict(method=["GET"]))
59 action="new", conditions=dict(method=["GET"]))
60 m.connect("/repos/{repo_name:.*}",
60 m.connect("/repos/{repo_name:.*}",
61 action="update", conditions=dict(method=["PUT"],
61 action="update", conditions=dict(method=["PUT"],
62 function=check_repo))
62 function=check_repo))
63 m.connect("/repos/{repo_name:.*}",
63 m.connect("/repos/{repo_name:.*}",
64 action="delete", conditions=dict(method=["DELETE"],
64 action="delete", conditions=dict(method=["DELETE"],
65 function=check_repo))
65 function=check_repo))
66 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
66 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
67 action="edit", conditions=dict(method=["GET"],
67 action="edit", conditions=dict(method=["GET"],
68 function=check_repo))
68 function=check_repo))
69 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
69 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
70 action="edit", conditions=dict(method=["GET"],
70 action="edit", conditions=dict(method=["GET"],
71 function=check_repo))
71 function=check_repo))
72 m.connect("repo", "/repos/{repo_name:.*}",
72 m.connect("repo", "/repos/{repo_name:.*}",
73 action="show", conditions=dict(method=["GET"],
73 action="show", conditions=dict(method=["GET"],
74 function=check_repo))
74 function=check_repo))
75 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
75 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
76 action="show", conditions=dict(method=["GET"],
76 action="show", conditions=dict(method=["GET"],
77 function=check_repo))
77 function=check_repo))
78 #ajax delete repo perm user
78 #ajax delete repo perm user
79 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
79 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
80 action="delete_perm_user", conditions=dict(method=["DELETE"],
80 action="delete_perm_user", conditions=dict(method=["DELETE"],
81 function=check_repo))
81 function=check_repo))
82 #ajax delete repo perm users_group
82 #ajax delete repo perm users_group
83 m.connect('delete_repo_users_group',
83 m.connect('delete_repo_users_group',
84 "/repos_delete_users_group/{repo_name:.*}",
84 "/repos_delete_users_group/{repo_name:.*}",
85 action="delete_perm_users_group",
85 action="delete_perm_users_group",
86 conditions=dict(method=["DELETE"], function=check_repo))
86 conditions=dict(method=["DELETE"], function=check_repo))
87
87
88 #settings actions
88 #settings actions
89 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
89 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
90 action="repo_stats", conditions=dict(method=["DELETE"],
90 action="repo_stats", conditions=dict(method=["DELETE"],
91 function=check_repo))
91 function=check_repo))
92 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
92 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
93 action="repo_cache", conditions=dict(method=["DELETE"],
93 action="repo_cache", conditions=dict(method=["DELETE"],
94 function=check_repo))
94 function=check_repo))
95 m.connect('repo_public_journal',
95 m.connect('repo_public_journal',
96 "/repos_public_journal/{repo_name:.*}",
96 "/repos_public_journal/{repo_name:.*}",
97 action="repo_public_journal", conditions=dict(method=["PUT"],
97 action="repo_public_journal", conditions=dict(method=["PUT"],
98 function=check_repo))
98 function=check_repo))
99 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
99 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
100 action="repo_pull", conditions=dict(method=["PUT"],
100 action="repo_pull", conditions=dict(method=["PUT"],
101 function=check_repo))
101 function=check_repo))
102
102
103 #ADMIN REPOS GROUP REST ROUTES
103 #ADMIN REPOS GROUP REST ROUTES
104 rmap.resource('repos_group', 'repos_groups',
104 rmap.resource('repos_group', 'repos_groups',
105 controller='admin/repos_groups', path_prefix='/_admin')
105 controller='admin/repos_groups', path_prefix='/_admin')
106
106
107 #ADMIN USER REST ROUTES
107 #ADMIN USER REST ROUTES
108 with rmap.submapper(path_prefix='/_admin', controller='admin/users') as m:
108 with rmap.submapper(path_prefix='/_admin', controller='admin/users') as m:
109 m.connect("users", "/users",
109 m.connect("users", "/users",
110 action="create", conditions=dict(method=["POST"]))
110 action="create", conditions=dict(method=["POST"]))
111 m.connect("users", "/users",
111 m.connect("users", "/users",
112 action="index", conditions=dict(method=["GET"]))
112 action="index", conditions=dict(method=["GET"]))
113 m.connect("formatted_users", "/users.{format}",
113 m.connect("formatted_users", "/users.{format}",
114 action="index", conditions=dict(method=["GET"]))
114 action="index", conditions=dict(method=["GET"]))
115 m.connect("new_user", "/users/new",
115 m.connect("new_user", "/users/new",
116 action="new", conditions=dict(method=["GET"]))
116 action="new", conditions=dict(method=["GET"]))
117 m.connect("formatted_new_user", "/users/new.{format}",
117 m.connect("formatted_new_user", "/users/new.{format}",
118 action="new", conditions=dict(method=["GET"]))
118 action="new", conditions=dict(method=["GET"]))
119 m.connect("update_user", "/users/{id}",
119 m.connect("update_user", "/users/{id}",
120 action="update", conditions=dict(method=["PUT"]))
120 action="update", conditions=dict(method=["PUT"]))
121 m.connect("delete_user", "/users/{id}",
121 m.connect("delete_user", "/users/{id}",
122 action="delete", conditions=dict(method=["DELETE"]))
122 action="delete", conditions=dict(method=["DELETE"]))
123 m.connect("edit_user", "/users/{id}/edit",
123 m.connect("edit_user", "/users/{id}/edit",
124 action="edit", conditions=dict(method=["GET"]))
124 action="edit", conditions=dict(method=["GET"]))
125 m.connect("formatted_edit_user",
125 m.connect("formatted_edit_user",
126 "/users/{id}.{format}/edit",
126 "/users/{id}.{format}/edit",
127 action="edit", conditions=dict(method=["GET"]))
127 action="edit", conditions=dict(method=["GET"]))
128 m.connect("user", "/users/{id}",
128 m.connect("user", "/users/{id}",
129 action="show", conditions=dict(method=["GET"]))
129 action="show", conditions=dict(method=["GET"]))
130 m.connect("formatted_user", "/users/{id}.{format}",
130 m.connect("formatted_user", "/users/{id}.{format}",
131 action="show", conditions=dict(method=["GET"]))
131 action="show", conditions=dict(method=["GET"]))
132
132
133 #EXTRAS USER ROUTES
133 #EXTRAS USER ROUTES
134 m.connect("user_perm", "/users_perm/{id}",
134 m.connect("user_perm", "/users_perm/{id}",
135 action="update_perm", conditions=dict(method=["PUT"]))
135 action="update_perm", conditions=dict(method=["PUT"]))
136
136
137 #ADMIN USERS REST ROUTES
137 #ADMIN USERS REST ROUTES
138 with rmap.submapper(path_prefix='/_admin',
138 with rmap.submapper(path_prefix='/_admin',
139 controller='admin/users_groups') as m:
139 controller='admin/users_groups') as m:
140 m.connect("users_groups", "/users_groups",
140 m.connect("users_groups", "/users_groups",
141 action="create", conditions=dict(method=["POST"]))
141 action="create", conditions=dict(method=["POST"]))
142 m.connect("users_groups", "/users_groups",
142 m.connect("users_groups", "/users_groups",
143 action="index", conditions=dict(method=["GET"]))
143 action="index", conditions=dict(method=["GET"]))
144 m.connect("formatted_users_groups", "/users_groups.{format}",
144 m.connect("formatted_users_groups", "/users_groups.{format}",
145 action="index", conditions=dict(method=["GET"]))
145 action="index", conditions=dict(method=["GET"]))
146 m.connect("new_users_group", "/users_groups/new",
146 m.connect("new_users_group", "/users_groups/new",
147 action="new", conditions=dict(method=["GET"]))
147 action="new", conditions=dict(method=["GET"]))
148 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
148 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
149 action="new", conditions=dict(method=["GET"]))
149 action="new", conditions=dict(method=["GET"]))
150 m.connect("update_users_group", "/users_groups/{id}",
150 m.connect("update_users_group", "/users_groups/{id}",
151 action="update", conditions=dict(method=["PUT"]))
151 action="update", conditions=dict(method=["PUT"]))
152 m.connect("delete_users_group", "/users_groups/{id}",
152 m.connect("delete_users_group", "/users_groups/{id}",
153 action="delete", conditions=dict(method=["DELETE"]))
153 action="delete", conditions=dict(method=["DELETE"]))
154 m.connect("edit_users_group", "/users_groups/{id}/edit",
154 m.connect("edit_users_group", "/users_groups/{id}/edit",
155 action="edit", conditions=dict(method=["GET"]))
155 action="edit", conditions=dict(method=["GET"]))
156 m.connect("formatted_edit_users_group",
156 m.connect("formatted_edit_users_group",
157 "/users_groups/{id}.{format}/edit",
157 "/users_groups/{id}.{format}/edit",
158 action="edit", conditions=dict(method=["GET"]))
158 action="edit", conditions=dict(method=["GET"]))
159 m.connect("users_group", "/users_groups/{id}",
159 m.connect("users_group", "/users_groups/{id}",
160 action="show", conditions=dict(method=["GET"]))
160 action="show", conditions=dict(method=["GET"]))
161 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
161 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
162 action="show", conditions=dict(method=["GET"]))
162 action="show", conditions=dict(method=["GET"]))
163
163
164 #EXTRAS USER ROUTES
164 #EXTRAS USER ROUTES
165 m.connect("users_group_perm", "/users_groups_perm/{id}",
165 m.connect("users_group_perm", "/users_groups_perm/{id}",
166 action="update_perm", conditions=dict(method=["PUT"]))
166 action="update_perm", conditions=dict(method=["PUT"]))
167
167
168 #ADMIN GROUP REST ROUTES
168 #ADMIN GROUP REST ROUTES
169 rmap.resource('group', 'groups',
169 rmap.resource('group', 'groups',
170 controller='admin/groups', path_prefix='/_admin')
170 controller='admin/groups', path_prefix='/_admin')
171
171
172 #ADMIN PERMISSIONS REST ROUTES
172 #ADMIN PERMISSIONS REST ROUTES
173 rmap.resource('permission', 'permissions',
173 rmap.resource('permission', 'permissions',
174 controller='admin/permissions', path_prefix='/_admin')
174 controller='admin/permissions', path_prefix='/_admin')
175
175
176 ##ADMIN LDAP SETTINGS
176 ##ADMIN LDAP SETTINGS
177 rmap.connect('ldap_settings', '/_admin/ldap',
177 rmap.connect('ldap_settings', '/_admin/ldap',
178 controller='admin/ldap_settings', action='ldap_settings',
178 controller='admin/ldap_settings', action='ldap_settings',
179 conditions=dict(method=["POST"]))
179 conditions=dict(method=["POST"]))
180
180
181 rmap.connect('ldap_home', '/_admin/ldap',
181 rmap.connect('ldap_home', '/_admin/ldap',
182 controller='admin/ldap_settings')
182 controller='admin/ldap_settings')
183
183
184 #ADMIN SETTINGS REST ROUTES
184 #ADMIN SETTINGS REST ROUTES
185 with rmap.submapper(path_prefix='/_admin',
185 with rmap.submapper(path_prefix='/_admin',
186 controller='admin/settings') as m:
186 controller='admin/settings') as m:
187 m.connect("admin_settings", "/settings",
187 m.connect("admin_settings", "/settings",
188 action="create", conditions=dict(method=["POST"]))
188 action="create", conditions=dict(method=["POST"]))
189 m.connect("admin_settings", "/settings",
189 m.connect("admin_settings", "/settings",
190 action="index", conditions=dict(method=["GET"]))
190 action="index", conditions=dict(method=["GET"]))
191 m.connect("formatted_admin_settings", "/settings.{format}",
191 m.connect("formatted_admin_settings", "/settings.{format}",
192 action="index", conditions=dict(method=["GET"]))
192 action="index", conditions=dict(method=["GET"]))
193 m.connect("admin_new_setting", "/settings/new",
193 m.connect("admin_new_setting", "/settings/new",
194 action="new", conditions=dict(method=["GET"]))
194 action="new", conditions=dict(method=["GET"]))
195 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
195 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
196 action="new", conditions=dict(method=["GET"]))
196 action="new", conditions=dict(method=["GET"]))
197 m.connect("/settings/{setting_id}",
197 m.connect("/settings/{setting_id}",
198 action="update", conditions=dict(method=["PUT"]))
198 action="update", conditions=dict(method=["PUT"]))
199 m.connect("/settings/{setting_id}",
199 m.connect("/settings/{setting_id}",
200 action="delete", conditions=dict(method=["DELETE"]))
200 action="delete", conditions=dict(method=["DELETE"]))
201 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
201 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
202 action="edit", conditions=dict(method=["GET"]))
202 action="edit", conditions=dict(method=["GET"]))
203 m.connect("formatted_admin_edit_setting",
203 m.connect("formatted_admin_edit_setting",
204 "/settings/{setting_id}.{format}/edit",
204 "/settings/{setting_id}.{format}/edit",
205 action="edit", conditions=dict(method=["GET"]))
205 action="edit", conditions=dict(method=["GET"]))
206 m.connect("admin_setting", "/settings/{setting_id}",
206 m.connect("admin_setting", "/settings/{setting_id}",
207 action="show", conditions=dict(method=["GET"]))
207 action="show", conditions=dict(method=["GET"]))
208 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
208 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
209 action="show", conditions=dict(method=["GET"]))
209 action="show", conditions=dict(method=["GET"]))
210 m.connect("admin_settings_my_account", "/my_account",
210 m.connect("admin_settings_my_account", "/my_account",
211 action="my_account", conditions=dict(method=["GET"]))
211 action="my_account", conditions=dict(method=["GET"]))
212 m.connect("admin_settings_my_account_update", "/my_account_update",
212 m.connect("admin_settings_my_account_update", "/my_account_update",
213 action="my_account_update", conditions=dict(method=["PUT"]))
213 action="my_account_update", conditions=dict(method=["PUT"]))
214 m.connect("admin_settings_create_repository", "/create_repository",
214 m.connect("admin_settings_create_repository", "/create_repository",
215 action="create_repository", conditions=dict(method=["GET"]))
215 action="create_repository", conditions=dict(method=["GET"]))
216
216
217 #ADMIN MAIN PAGES
217 #ADMIN MAIN PAGES
218 with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
218 with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
219 m.connect('admin_home', '', action='index')
219 m.connect('admin_home', '', action='index')
220 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
220 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
221 action='add_repo')
221 action='add_repo')
222
222
223 #USER JOURNAL
223 #USER JOURNAL
224 rmap.connect('journal', '/_admin/journal', controller='journal')
224 rmap.connect('journal', '/_admin/journal', controller='journal')
225
225
226 rmap.connect('public_journal', '/_admin/public_journal',
226 rmap.connect('public_journal', '/_admin/public_journal',
227 controller='journal', action="public_journal")
227 controller='journal', action="public_journal")
228
228
229 rmap.connect('public_journal_rss', '/_admin/public_journal_rss',
229 rmap.connect('public_journal_rss', '/_admin/public_journal_rss',
230 controller='journal', action="public_journal_rss")
230 controller='journal', action="public_journal_rss")
231
231
232 rmap.connect('public_journal_atom', '/_admin/public_journal_atom',
232 rmap.connect('public_journal_atom', '/_admin/public_journal_atom',
233 controller='journal', action="public_journal_atom")
233 controller='journal', action="public_journal_atom")
234
234
235 rmap.connect('toggle_following', '/_admin/toggle_following',
235 rmap.connect('toggle_following', '/_admin/toggle_following',
236 controller='journal', action='toggle_following',
236 controller='journal', action='toggle_following',
237 conditions=dict(method=["POST"]))
237 conditions=dict(method=["POST"]))
238
238
239 #SEARCH
239 #SEARCH
240 rmap.connect('search', '/_admin/search', controller='search',)
240 rmap.connect('search', '/_admin/search', controller='search',)
241 rmap.connect('search_repo', '/_admin/search/{search_repo:.*}',
241 rmap.connect('search_repo', '/_admin/search/{search_repo:.*}',
242 controller='search')
242 controller='search')
243
243
244 #LOGIN/LOGOUT/REGISTER/SIGN IN
244 #LOGIN/LOGOUT/REGISTER/SIGN IN
245 rmap.connect('login_home', '/_admin/login', controller='login')
245 rmap.connect('login_home', '/_admin/login', controller='login')
246 rmap.connect('logout_home', '/_admin/logout', controller='login',
246 rmap.connect('logout_home', '/_admin/logout', controller='login',
247 action='logout')
247 action='logout')
248
248
249 rmap.connect('register', '/_admin/register', controller='login',
249 rmap.connect('register', '/_admin/register', controller='login',
250 action='register')
250 action='register')
251
251
252 rmap.connect('reset_password', '/_admin/password_reset',
252 rmap.connect('reset_password', '/_admin/password_reset',
253 controller='login', action='password_reset')
253 controller='login', action='password_reset')
254
254
255 #FEEDS
255 #FEEDS
256 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
256 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
257 controller='feed', action='rss',
257 controller='feed', action='rss',
258 conditions=dict(function=check_repo))
258 conditions=dict(function=check_repo))
259
259
260 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
260 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
261 controller='feed', action='atom',
261 controller='feed', action='atom',
262 conditions=dict(function=check_repo))
262 conditions=dict(function=check_repo))
263
263
264 #REPOSITORY ROUTES
264 #==========================================================================
265 # REPOSITORY ROUTES
266 #==========================================================================
265 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
267 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
266 controller='changeset', revision='tip',
268 controller='changeset', revision='tip',
267 conditions=dict(function=check_repo))
269 conditions=dict(function=check_repo))
268
270
269 rmap.connect('raw_changeset_home',
271 rmap.connect('raw_changeset_home',
270 '/{repo_name:.*}/raw-changeset/{revision}',
272 '/{repo_name:.*}/raw-changeset/{revision}',
271 controller='changeset', action='raw_changeset',
273 controller='changeset', action='raw_changeset',
272 revision='tip', conditions=dict(function=check_repo))
274 revision='tip', conditions=dict(function=check_repo))
273
275
274 rmap.connect('summary_home', '/{repo_name:.*}',
276 rmap.connect('summary_home', '/{repo_name:.*}',
275 controller='summary', conditions=dict(function=check_repo))
277 controller='summary', conditions=dict(function=check_repo))
276
278
277 rmap.connect('summary_home', '/{repo_name:.*}/summary',
279 rmap.connect('summary_home', '/{repo_name:.*}/summary',
278 controller='summary', conditions=dict(function=check_repo))
280 controller='summary', conditions=dict(function=check_repo))
279
281
280 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
282 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
281 controller='shortlog', conditions=dict(function=check_repo))
283 controller='shortlog', conditions=dict(function=check_repo))
282
284
283 rmap.connect('branches_home', '/{repo_name:.*}/branches',
285 rmap.connect('branches_home', '/{repo_name:.*}/branches',
284 controller='branches', conditions=dict(function=check_repo))
286 controller='branches', conditions=dict(function=check_repo))
285
287
286 rmap.connect('tags_home', '/{repo_name:.*}/tags',
288 rmap.connect('tags_home', '/{repo_name:.*}/tags',
287 controller='tags', conditions=dict(function=check_repo))
289 controller='tags', conditions=dict(function=check_repo))
288
290
289 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
291 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
290 controller='changelog', conditions=dict(function=check_repo))
292 controller='changelog', conditions=dict(function=check_repo))
291
293
292 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
294 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
293 controller='files', revision='tip', f_path='',
295 controller='files', revision='tip', f_path='',
294 conditions=dict(function=check_repo))
296 conditions=dict(function=check_repo))
295
297
296 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
298 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
297 controller='files', action='diff', revision='tip', f_path='',
299 controller='files', action='diff', revision='tip', f_path='',
298 conditions=dict(function=check_repo))
300 conditions=dict(function=check_repo))
299
301
300 rmap.connect('files_rawfile_home',
302 rmap.connect('files_rawfile_home',
301 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
303 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
302 controller='files', action='rawfile', revision='tip',
304 controller='files', action='rawfile', revision='tip',
303 f_path='', conditions=dict(function=check_repo))
305 f_path='', conditions=dict(function=check_repo))
304
306
305 rmap.connect('files_raw_home',
307 rmap.connect('files_raw_home',
306 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
308 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
307 controller='files', action='raw', revision='tip', f_path='',
309 controller='files', action='raw', revision='tip', f_path='',
308 conditions=dict(function=check_repo))
310 conditions=dict(function=check_repo))
309
311
310 rmap.connect('files_annotate_home',
312 rmap.connect('files_annotate_home',
311 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
313 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
312 controller='files', action='annotate', revision='tip',
314 controller='files', action='annotate', revision='tip',
313 f_path='', conditions=dict(function=check_repo))
315 f_path='', conditions=dict(function=check_repo))
314
316
315 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
317 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
316 controller='files', action='archivefile',
318 controller='files', action='archivefile',
317 conditions=dict(function=check_repo))
319 conditions=dict(function=check_repo))
318
320
319 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
321 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
320 controller='settings', action="delete",
322 controller='settings', action="delete",
321 conditions=dict(method=["DELETE"], function=check_repo))
323 conditions=dict(method=["DELETE"], function=check_repo))
322
324
323 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
325 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
324 controller='settings', action="update",
326 controller='settings', action="update",
325 conditions=dict(method=["PUT"], function=check_repo))
327 conditions=dict(method=["PUT"], function=check_repo))
326
328
327 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
329 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
328 controller='settings', action='index',
330 controller='settings', action='index',
329 conditions=dict(function=check_repo))
331 conditions=dict(function=check_repo))
330
332
331 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
333 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
332 controller='settings', action='fork_create',
334 controller='settings', action='fork_create',
333 conditions=dict(function=check_repo, method=["POST"]))
335 conditions=dict(function=check_repo, method=["POST"]))
334
336
335 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
337 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
336 controller='settings', action='fork',
338 controller='settings', action='fork',
337 conditions=dict(function=check_repo))
339 conditions=dict(function=check_repo))
338
340
341 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
342 controller='followers', action='followers',
343 conditions=dict(function=check_repo))
339 return rmap
344 return rmap
@@ -1,519 +1,526
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import datetime
28 import datetime
29 from datetime import date
29 from datetime import date
30
30
31 from sqlalchemy import *
31 from sqlalchemy import *
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.orm import relationship, backref
33 from sqlalchemy.orm import relationship, backref
34 from sqlalchemy.orm.interfaces import MapperExtension
34 from sqlalchemy.orm.interfaces import MapperExtension
35
35
36 from rhodecode.lib import str2bool
36 from rhodecode.lib import str2bool
37 from rhodecode.model.meta import Base, Session
37 from rhodecode.model.meta import Base, Session
38 from rhodecode.model.caching_query import FromCache
38 from rhodecode.model.caching_query import FromCache
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42 #==============================================================================
42 #==============================================================================
43 # MAPPER EXTENSIONS
43 # MAPPER EXTENSIONS
44 #==============================================================================
44 #==============================================================================
45
45
46 class RepositoryMapper(MapperExtension):
46 class RepositoryMapper(MapperExtension):
47 def after_update(self, mapper, connection, instance):
47 def after_update(self, mapper, connection, instance):
48 pass
48 pass
49
49
50
50
51 class RhodeCodeSettings(Base):
51 class RhodeCodeSettings(Base):
52 __tablename__ = 'rhodecode_settings'
52 __tablename__ = 'rhodecode_settings'
53 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
53 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
54 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
54 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
55 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
55 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
57
57
58 def __init__(self, k='', v=''):
58 def __init__(self, k='', v=''):
59 self.app_settings_name = k
59 self.app_settings_name = k
60 self.app_settings_value = v
60 self.app_settings_value = v
61
61
62 def __repr__(self):
62 def __repr__(self):
63 return "<%s('%s:%s')>" % (self.__class__.__name__,
63 return "<%s('%s:%s')>" % (self.__class__.__name__,
64 self.app_settings_name, self.app_settings_value)
64 self.app_settings_name, self.app_settings_value)
65
65
66
66
67 @classmethod
67 @classmethod
68 def get_app_settings(cls, cache=False):
68 def get_app_settings(cls, cache=False):
69
69
70 ret = Session.query(cls)
70 ret = Session.query(cls)
71
71
72 if cache:
72 if cache:
73 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
73 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
74
74
75 if not ret:
75 if not ret:
76 raise Exception('Could not get application settings !')
76 raise Exception('Could not get application settings !')
77 settings = {}
77 settings = {}
78 for each in ret:
78 for each in ret:
79 settings['rhodecode_' + each.app_settings_name] = \
79 settings['rhodecode_' + each.app_settings_name] = \
80 each.app_settings_value
80 each.app_settings_value
81
81
82 return settings
82 return settings
83
83
84 @classmethod
84 @classmethod
85 def get_ldap_settings(cls, cache=False):
85 def get_ldap_settings(cls, cache=False):
86 ret = Session.query(cls)\
86 ret = Session.query(cls)\
87 .filter(cls.app_settings_name.startswith('ldap_'))\
87 .filter(cls.app_settings_name.startswith('ldap_'))\
88 .all()
88 .all()
89 fd = {}
89 fd = {}
90 for row in ret:
90 for row in ret:
91 fd.update({row.app_settings_name:str2bool(row.app_settings_value)})
91 fd.update({row.app_settings_name:str2bool(row.app_settings_value)})
92 return fd
92 return fd
93
93
94
94
95 class RhodeCodeUi(Base):
95 class RhodeCodeUi(Base):
96 __tablename__ = 'rhodecode_ui'
96 __tablename__ = 'rhodecode_ui'
97 __table_args__ = {'useexisting':True}
97 __table_args__ = {'useexisting':True}
98 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
98 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
99 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
99 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
100 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
100 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
102 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
103
103
104
104
105 class User(Base):
105 class User(Base):
106 __tablename__ = 'users'
106 __tablename__ = 'users'
107 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
107 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
108 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
108 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
109 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
109 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
110 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
110 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
111 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
111 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
112 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
112 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
113 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
113 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
114 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
114 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
115 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
115 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
116 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
116 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
117 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
117 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
118 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
118 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
119
119
120 user_log = relationship('UserLog', cascade='all')
120 user_log = relationship('UserLog', cascade='all')
121 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
121 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
122
122
123 repositories = relationship('Repository')
123 repositories = relationship('Repository')
124 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
124 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
125
125
126 group_member = relationship('UsersGroupMember', cascade='all')
126 group_member = relationship('UsersGroupMember', cascade='all')
127
127
128 @property
128 @property
129 def full_contact(self):
129 def full_contact(self):
130 return '%s %s <%s>' % (self.name, self.lastname, self.email)
130 return '%s %s <%s>' % (self.name, self.lastname, self.email)
131
131
132 @property
132 @property
133 def short_contact(self):
133 def short_contact(self):
134 return '%s %s' % (self.name, self.lastname)
134 return '%s %s' % (self.name, self.lastname)
135
135
136
136
137 @property
137 @property
138 def is_admin(self):
138 def is_admin(self):
139 return self.admin
139 return self.admin
140
140
141 def __repr__(self):
141 def __repr__(self):
142 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
142 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
143 self.user_id, self.username)
143 self.user_id, self.username)
144
144
145 @classmethod
145 @classmethod
146 def by_username(cls, username):
146 def by_username(cls, username):
147 return Session.query(cls).filter(cls.username == username).one()
147 return Session.query(cls).filter(cls.username == username).one()
148
148
149
149
150 def update_lastlogin(self):
150 def update_lastlogin(self):
151 """Update user lastlogin"""
151 """Update user lastlogin"""
152
152
153 try:
153 try:
154 session = Session.object_session(self)
154 session = Session.object_session(self)
155 self.last_login = datetime.datetime.now()
155 self.last_login = datetime.datetime.now()
156 session.add(self)
156 session.add(self)
157 session.commit()
157 session.commit()
158 log.debug('updated user %s lastlogin', self.username)
158 log.debug('updated user %s lastlogin', self.username)
159 except (DatabaseError,):
159 except (DatabaseError,):
160 session.rollback()
160 session.rollback()
161
161
162
162
163 class UserLog(Base):
163 class UserLog(Base):
164 __tablename__ = 'user_logs'
164 __tablename__ = 'user_logs'
165 __table_args__ = {'useexisting':True}
165 __table_args__ = {'useexisting':True}
166 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
166 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
167 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
167 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
168 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
168 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
169 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
169 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
170 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
170 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
171 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
171 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
172 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
172 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
173
173
174 @property
174 @property
175 def action_as_day(self):
175 def action_as_day(self):
176 return date(*self.action_date.timetuple()[:3])
176 return date(*self.action_date.timetuple()[:3])
177
177
178 user = relationship('User')
178 user = relationship('User')
179 repository = relationship('Repository')
179 repository = relationship('Repository')
180
180
181
181
182 class UsersGroup(Base):
182 class UsersGroup(Base):
183 __tablename__ = 'users_groups'
183 __tablename__ = 'users_groups'
184 __table_args__ = {'useexisting':True}
184 __table_args__ = {'useexisting':True}
185
185
186 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
186 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
187 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
187 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
188 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
188 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
189
189
190 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
190 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
191
191
192
192
193 @classmethod
193 @classmethod
194 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
194 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
195 if case_insensitive:
195 if case_insensitive:
196 gr = Session.query(cls)\
196 gr = Session.query(cls)\
197 .filter(cls.users_group_name.ilike(group_name))
197 .filter(cls.users_group_name.ilike(group_name))
198 else:
198 else:
199 gr = Session.query(UsersGroup)\
199 gr = Session.query(UsersGroup)\
200 .filter(UsersGroup.users_group_name == group_name)
200 .filter(UsersGroup.users_group_name == group_name)
201 if cache:
201 if cache:
202 gr = gr.options(FromCache("sql_cache_short",
202 gr = gr.options(FromCache("sql_cache_short",
203 "get_user_%s" % group_name))
203 "get_user_%s" % group_name))
204 return gr.scalar()
204 return gr.scalar()
205
205
206 class UsersGroupMember(Base):
206 class UsersGroupMember(Base):
207 __tablename__ = 'users_groups_members'
207 __tablename__ = 'users_groups_members'
208 __table_args__ = {'useexisting':True}
208 __table_args__ = {'useexisting':True}
209
209
210 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
210 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
211 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
211 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
212 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
212 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
213
213
214 user = relationship('User', lazy='joined')
214 user = relationship('User', lazy='joined')
215 users_group = relationship('UsersGroup')
215 users_group = relationship('UsersGroup')
216
216
217 def __init__(self, gr_id='', u_id=''):
217 def __init__(self, gr_id='', u_id=''):
218 self.users_group_id = gr_id
218 self.users_group_id = gr_id
219 self.user_id = u_id
219 self.user_id = u_id
220
220
221 class Repository(Base):
221 class Repository(Base):
222 __tablename__ = 'repositories'
222 __tablename__ = 'repositories'
223 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
223 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
224 __mapper_args__ = {'extension':RepositoryMapper()}
224 __mapper_args__ = {'extension':RepositoryMapper()}
225
225
226 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
226 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
227 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
227 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
228 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
228 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
229 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
229 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
230 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
230 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
231 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
231 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
232 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
232 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
233 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
233 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
234 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
234 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
235 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
235 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
236 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
236 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
237
237
238
238
239 user = relationship('User')
239 user = relationship('User')
240 fork = relationship('Repository', remote_side=repo_id)
240 fork = relationship('Repository', remote_side=repo_id)
241 group = relationship('Group')
241 group = relationship('Group')
242 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
242 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
243 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
243 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
244 stats = relationship('Statistics', cascade='all', uselist=False)
244 stats = relationship('Statistics', cascade='all', uselist=False)
245
245
246 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
246 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
247
247
248 logs = relationship('UserLog', cascade='all')
248 logs = relationship('UserLog', cascade='all')
249
249
250 def __repr__(self):
250 def __repr__(self):
251 return "<%s('%s:%s')>" % (self.__class__.__name__,
251 return "<%s('%s:%s')>" % (self.__class__.__name__,
252 self.repo_id, self.repo_name)
252 self.repo_id, self.repo_name)
253
253
254 @classmethod
254 @classmethod
255 def by_repo_name(cls, repo_name):
255 def by_repo_name(cls, repo_name):
256 return Session.query(cls).filter(cls.repo_name == repo_name).one()
256 return Session.query(cls).filter(cls.repo_name == repo_name).one()
257
257
258 @property
258 @property
259 def just_name(self):
259 def just_name(self):
260 return self.repo_name.split(os.sep)[-1]
260 return self.repo_name.split(os.sep)[-1]
261
261
262 @property
262 @property
263 def groups_with_parents(self):
263 def groups_with_parents(self):
264 groups = []
264 groups = []
265 if self.group is None:
265 if self.group is None:
266 return groups
266 return groups
267
267
268 cur_gr = self.group
268 cur_gr = self.group
269 groups.insert(0, cur_gr)
269 groups.insert(0, cur_gr)
270 while 1:
270 while 1:
271 gr = getattr(cur_gr, 'parent_group', None)
271 gr = getattr(cur_gr, 'parent_group', None)
272 cur_gr = cur_gr.parent_group
272 cur_gr = cur_gr.parent_group
273 if gr is None:
273 if gr is None:
274 break
274 break
275 groups.insert(0, gr)
275 groups.insert(0, gr)
276
276
277 return groups
277 return groups
278
278
279 @property
279 @property
280 def groups_and_repo(self):
280 def groups_and_repo(self):
281 return self.groups_with_parents, self.just_name
281 return self.groups_with_parents, self.just_name
282
282
283
283
284 class Group(Base):
284 class Group(Base):
285 __tablename__ = 'groups'
285 __tablename__ = 'groups'
286 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
286 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
287
287
288 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
288 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
289 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
289 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
290 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
290 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
291
291
292 parent_group = relationship('Group', remote_side=group_id)
292 parent_group = relationship('Group', remote_side=group_id)
293
293
294
294
295 def __init__(self, group_name='', parent_group=None):
295 def __init__(self, group_name='', parent_group=None):
296 self.group_name = group_name
296 self.group_name = group_name
297 self.parent_group = parent_group
297 self.parent_group = parent_group
298
298
299 def __repr__(self):
299 def __repr__(self):
300 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
300 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
301 self.group_name)
301 self.group_name)
302
302
303 @property
303 @property
304 def parents(self):
304 def parents(self):
305 groups = []
305 groups = []
306 if self.parent_group is None:
306 if self.parent_group is None:
307 return groups
307 return groups
308 cur_gr = self.parent_group
308 cur_gr = self.parent_group
309 groups.insert(0, cur_gr)
309 groups.insert(0, cur_gr)
310 while 1:
310 while 1:
311 gr = getattr(cur_gr, 'parent_group', None)
311 gr = getattr(cur_gr, 'parent_group', None)
312 cur_gr = cur_gr.parent_group
312 cur_gr = cur_gr.parent_group
313 if gr is None:
313 if gr is None:
314 break
314 break
315 groups.insert(0, gr)
315 groups.insert(0, gr)
316 return groups
316 return groups
317
317
318 @property
318 @property
319 def repositories(self):
319 def repositories(self):
320 return Session.query(Repository).filter(Repository.group == self).all()
320 return Session.query(Repository).filter(Repository.group == self).all()
321
321
322 class Permission(Base):
322 class Permission(Base):
323 __tablename__ = 'permissions'
323 __tablename__ = 'permissions'
324 __table_args__ = {'useexisting':True}
324 __table_args__ = {'useexisting':True}
325 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
325 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
326 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328
328
329 def __repr__(self):
329 def __repr__(self):
330 return "<%s('%s:%s')>" % (self.__class__.__name__,
330 return "<%s('%s:%s')>" % (self.__class__.__name__,
331 self.permission_id, self.permission_name)
331 self.permission_id, self.permission_name)
332
332
333 @classmethod
333 @classmethod
334 def get_by_key(cls, key):
334 def get_by_key(cls, key):
335 return Session.query(cls).filter(cls.permission_name == key).scalar()
335 return Session.query(cls).filter(cls.permission_name == key).scalar()
336
336
337 class RepoToPerm(Base):
337 class RepoToPerm(Base):
338 __tablename__ = 'repo_to_perm'
338 __tablename__ = 'repo_to_perm'
339 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
339 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
340 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
340 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
341 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
341 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
342 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
342 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
343 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
343 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
344
344
345 user = relationship('User')
345 user = relationship('User')
346 permission = relationship('Permission')
346 permission = relationship('Permission')
347 repository = relationship('Repository')
347 repository = relationship('Repository')
348
348
349 class UserToPerm(Base):
349 class UserToPerm(Base):
350 __tablename__ = 'user_to_perm'
350 __tablename__ = 'user_to_perm'
351 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
351 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
352 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
352 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
353 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
353 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
354 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
354 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
355
355
356 user = relationship('User')
356 user = relationship('User')
357 permission = relationship('Permission')
357 permission = relationship('Permission')
358
358
359 @classmethod
359 @classmethod
360 def has_perm(cls, user_id, perm):
360 def has_perm(cls, user_id, perm):
361 if not isinstance(perm, Permission):
361 if not isinstance(perm, Permission):
362 raise Exception('perm needs to be an instance of Permission class')
362 raise Exception('perm needs to be an instance of Permission class')
363
363
364 return Session.query(cls).filter(cls.user_id == user_id)\
364 return Session.query(cls).filter(cls.user_id == user_id)\
365 .filter(cls.permission == perm).scalar() is not None
365 .filter(cls.permission == perm).scalar() is not None
366
366
367 @classmethod
367 @classmethod
368 def grant_perm(cls, user_id, perm):
368 def grant_perm(cls, user_id, perm):
369 if not isinstance(perm, Permission):
369 if not isinstance(perm, Permission):
370 raise Exception('perm needs to be an instance of Permission class')
370 raise Exception('perm needs to be an instance of Permission class')
371
371
372 new = cls()
372 new = cls()
373 new.user_id = user_id
373 new.user_id = user_id
374 new.permission = perm
374 new.permission = perm
375 try:
375 try:
376 Session.add(new)
376 Session.add(new)
377 Session.commit()
377 Session.commit()
378 except:
378 except:
379 Session.rollback()
379 Session.rollback()
380
380
381
381
382 @classmethod
382 @classmethod
383 def revoke_perm(cls, user_id, perm):
383 def revoke_perm(cls, user_id, perm):
384 if not isinstance(perm, Permission):
384 if not isinstance(perm, Permission):
385 raise Exception('perm needs to be an instance of Permission class')
385 raise Exception('perm needs to be an instance of Permission class')
386
386
387 try:
387 try:
388 Session.query(cls).filter(cls.user_id == user_id)\
388 Session.query(cls).filter(cls.user_id == user_id)\
389 .filter(cls.permission == perm).delete()
389 .filter(cls.permission == perm).delete()
390 Session.commit()
390 Session.commit()
391 except:
391 except:
392 Session.rollback()
392 Session.rollback()
393
393
394 class UsersGroupRepoToPerm(Base):
394 class UsersGroupRepoToPerm(Base):
395 __tablename__ = 'users_group_repo_to_perm'
395 __tablename__ = 'users_group_repo_to_perm'
396 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
396 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
397 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
397 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
398 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
398 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
399 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
399 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
400 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
400 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
401
401
402 users_group = relationship('UsersGroup')
402 users_group = relationship('UsersGroup')
403 permission = relationship('Permission')
403 permission = relationship('Permission')
404 repository = relationship('Repository')
404 repository = relationship('Repository')
405
405
406
406
407 class UsersGroupToPerm(Base):
407 class UsersGroupToPerm(Base):
408 __tablename__ = 'users_group_to_perm'
408 __tablename__ = 'users_group_to_perm'
409 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
409 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
410 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
410 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
411 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
411 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
412
412
413 users_group = relationship('UsersGroup')
413 users_group = relationship('UsersGroup')
414 permission = relationship('Permission')
414 permission = relationship('Permission')
415
415
416
416
417 @classmethod
417 @classmethod
418 def has_perm(cls, users_group_id, perm):
418 def has_perm(cls, users_group_id, perm):
419 if not isinstance(perm, Permission):
419 if not isinstance(perm, Permission):
420 raise Exception('perm needs to be an instance of Permission class')
420 raise Exception('perm needs to be an instance of Permission class')
421
421
422 return Session.query(cls).filter(cls.users_group_id ==
422 return Session.query(cls).filter(cls.users_group_id ==
423 users_group_id)\
423 users_group_id)\
424 .filter(cls.permission == perm)\
424 .filter(cls.permission == perm)\
425 .scalar() is not None
425 .scalar() is not None
426
426
427 @classmethod
427 @classmethod
428 def grant_perm(cls, users_group_id, perm):
428 def grant_perm(cls, users_group_id, perm):
429 if not isinstance(perm, Permission):
429 if not isinstance(perm, Permission):
430 raise Exception('perm needs to be an instance of Permission class')
430 raise Exception('perm needs to be an instance of Permission class')
431
431
432 new = cls()
432 new = cls()
433 new.users_group_id = users_group_id
433 new.users_group_id = users_group_id
434 new.permission = perm
434 new.permission = perm
435 try:
435 try:
436 Session.add(new)
436 Session.add(new)
437 Session.commit()
437 Session.commit()
438 except:
438 except:
439 Session.rollback()
439 Session.rollback()
440
440
441
441
442 @classmethod
442 @classmethod
443 def revoke_perm(cls, users_group_id, perm):
443 def revoke_perm(cls, users_group_id, perm):
444 if not isinstance(perm, Permission):
444 if not isinstance(perm, Permission):
445 raise Exception('perm needs to be an instance of Permission class')
445 raise Exception('perm needs to be an instance of Permission class')
446
446
447 try:
447 try:
448 Session.query(cls).filter(cls.users_group_id == users_group_id)\
448 Session.query(cls).filter(cls.users_group_id == users_group_id)\
449 .filter(cls.permission == perm).delete()
449 .filter(cls.permission == perm).delete()
450 Session.commit()
450 Session.commit()
451 except:
451 except:
452 Session.rollback()
452 Session.rollback()
453
453
454
454
455 class GroupToPerm(Base):
455 class GroupToPerm(Base):
456 __tablename__ = 'group_to_perm'
456 __tablename__ = 'group_to_perm'
457 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
457 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
458
458
459 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
459 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
460 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
460 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
461 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
461 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
462 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
462 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
463
463
464 user = relationship('User')
464 user = relationship('User')
465 permission = relationship('Permission')
465 permission = relationship('Permission')
466 group = relationship('Group')
466 group = relationship('Group')
467
467
468 class Statistics(Base):
468 class Statistics(Base):
469 __tablename__ = 'statistics'
469 __tablename__ = 'statistics'
470 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
470 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
471 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
471 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
472 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
472 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
473 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
473 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
474 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
474 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
475 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
475 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
476 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
476 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
477
477
478 repository = relationship('Repository', single_parent=True)
478 repository = relationship('Repository', single_parent=True)
479
479
480 class UserFollowing(Base):
480 class UserFollowing(Base):
481 __tablename__ = 'user_followings'
481 __tablename__ = 'user_followings'
482 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
482 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
483 UniqueConstraint('user_id', 'follows_user_id')
483 UniqueConstraint('user_id', 'follows_user_id')
484 , {'useexisting':True})
484 , {'useexisting':True})
485
485
486 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
486 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
487 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
487 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
488 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
488 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
489 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
489 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
490 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
490
491
491 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
492 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
492
493
493 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
494 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
494 follows_repository = relationship('Repository', order_by='Repository.repo_name')
495 follows_repository = relationship('Repository', order_by='Repository.repo_name')
495
496
497
498
499 @classmethod
500 def get_repo_followers(cls, repo_id):
501 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
502
496 class CacheInvalidation(Base):
503 class CacheInvalidation(Base):
497 __tablename__ = 'cache_invalidation'
504 __tablename__ = 'cache_invalidation'
498 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
505 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
499 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
506 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
500 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
507 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
501 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
508 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
502 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
509 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
503
510
504
511
505 def __init__(self, cache_key, cache_args=''):
512 def __init__(self, cache_key, cache_args=''):
506 self.cache_key = cache_key
513 self.cache_key = cache_key
507 self.cache_args = cache_args
514 self.cache_args = cache_args
508 self.cache_active = False
515 self.cache_active = False
509
516
510 def __repr__(self):
517 def __repr__(self):
511 return "<%s('%s:%s')>" % (self.__class__.__name__,
518 return "<%s('%s:%s')>" % (self.__class__.__name__,
512 self.cache_id, self.cache_key)
519 self.cache_id, self.cache_key)
513
520
514 class DbMigrateVersion(Base):
521 class DbMigrateVersion(Base):
515 __tablename__ = 'db_migrate_version'
522 __tablename__ = 'db_migrate_version'
516 __table_args__ = {'useexisting':True}
523 __table_args__ = {'useexisting':True}
517 repository_id = Column('repository_id', String(250), primary_key=True)
524 repository_id = Column('repository_id', String(250), primary_key=True)
518 repository_path = Column('repository_path', Text)
525 repository_path = Column('repository_path', Text)
519 version = Column('version', Integer)
526 version = Column('version', Integer)
@@ -1,355 +1,355
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <!-- HEADER -->
4 <!-- HEADER -->
5 <div id="header">
5 <div id="header">
6 <!-- user -->
6 <!-- user -->
7 <ul id="logged-user">
7 <ul id="logged-user">
8 <li class="first">
8 <li class="first">
9 <div class="gravatar">
9 <div class="gravatar">
10 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
10 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
11 </div>
11 </div>
12 <div class="account">
12 <div class="account">
13 %if c.rhodecode_user.username == 'default':
13 %if c.rhodecode_user.username == 'default':
14 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
14 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
15 %else:
15 %else:
16 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
16 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
17 %endif
17 %endif
18 </div>
18 </div>
19 </li>
19 </li>
20 <li>
20 <li>
21 <a href="${h.url('home')}">${_('Home')}</a>
21 <a href="${h.url('home')}">${_('Home')}</a>
22 </li>
22 </li>
23 %if c.rhodecode_user.username != 'default':
23 %if c.rhodecode_user.username != 'default':
24 <li>
24 <li>
25 <a href="${h.url('journal')}">${_('Journal')}</a>
25 <a href="${h.url('journal')}">${_('Journal')}</a>
26 ##(${c.unread_journal}
26 ##(${c.unread_journal}
27 </li>
27 </li>
28 %endif
28 %endif
29 %if c.rhodecode_user.username == 'default':
29 %if c.rhodecode_user.username == 'default':
30 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
30 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
31 %else:
31 %else:
32 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
32 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
33 %endif
33 %endif
34 </ul>
34 </ul>
35 <!-- end user -->
35 <!-- end user -->
36 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
36 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
37 <div id="logo">
37 <div id="logo">
38 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
38 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
39 </div>
39 </div>
40 <!-- MENU -->
40 <!-- MENU -->
41 ${self.page_nav()}
41 ${self.page_nav()}
42 <!-- END MENU -->
42 <!-- END MENU -->
43 ${self.body()}
43 ${self.body()}
44 </div>
44 </div>
45 </div>
45 </div>
46 <!-- END HEADER -->
46 <!-- END HEADER -->
47
47
48 <!-- CONTENT -->
48 <!-- CONTENT -->
49 <div id="content">
49 <div id="content">
50 <div class="flash_msg">
50 <div class="flash_msg">
51 <% messages = h.flash.pop_messages() %>
51 <% messages = h.flash.pop_messages() %>
52 % if messages:
52 % if messages:
53 <ul id="flash-messages">
53 <ul id="flash-messages">
54 % for message in messages:
54 % for message in messages:
55 <li class="${message.category}_msg">${message}</li>
55 <li class="${message.category}_msg">${message}</li>
56 % endfor
56 % endfor
57 </ul>
57 </ul>
58 % endif
58 % endif
59 </div>
59 </div>
60 <div id="main">
60 <div id="main">
61 ${next.main()}
61 ${next.main()}
62 </div>
62 </div>
63 </div>
63 </div>
64 <!-- END CONTENT -->
64 <!-- END CONTENT -->
65
65
66 <!-- FOOTER -->
66 <!-- FOOTER -->
67 <div id="footer">
67 <div id="footer">
68 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
68 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
69 <div>
69 <div>
70 <p class="footer-link">
70 <p class="footer-link">
71 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
71 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
72 </p>
72 </p>
73 <p class="footer-link-right">
73 <p class="footer-link-right">
74 <a href="${h.url('rhodecode_official')}">RhodeCode</a>
74 <a href="${h.url('rhodecode_official')}">RhodeCode</a>
75 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
75 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
76 </p>
76 </p>
77 </div>
77 </div>
78 </div>
78 </div>
79 <script type="text/javascript">
79 <script type="text/javascript">
80 function tooltip_activate(){
80 function tooltip_activate(){
81 ${h.tooltip.activate()}
81 ${h.tooltip.activate()}
82 }
82 }
83 tooltip_activate();
83 tooltip_activate();
84 </script>
84 </script>
85 </div>
85 </div>
86 <!-- END FOOTER -->
86 <!-- END FOOTER -->
87
87
88 ### MAKO DEFS ###
88 ### MAKO DEFS ###
89 <%def name="page_nav()">
89 <%def name="page_nav()">
90 ${self.menu()}
90 ${self.menu()}
91 </%def>
91 </%def>
92
92
93 <%def name="breadcrumbs()">
93 <%def name="breadcrumbs()">
94 <div class="breadcrumbs">
94 <div class="breadcrumbs">
95 ${self.breadcrumbs_links()}
95 ${self.breadcrumbs_links()}
96 </div>
96 </div>
97 </%def>
97 </%def>
98
98
99
99
100 <%def name="menu(current=None)">
100 <%def name="menu(current=None)">
101 <%
101 <%
102 def is_current(selected):
102 def is_current(selected):
103 if selected == current:
103 if selected == current:
104 return h.literal('class="current"')
104 return h.literal('class="current"')
105 %>
105 %>
106 %if current not in ['home','admin']:
106 %if current not in ['home','admin']:
107 ##REGULAR MENU
107 ##REGULAR MENU
108 <ul id="quick">
108 <ul id="quick">
109 <!-- repo switcher -->
109 <!-- repo switcher -->
110 <li>
110 <li>
111 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
111 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
112 <span class="icon">
112 <span class="icon">
113 <img src="${h.url("/images/icons/database.png")}" alt="${_('Products')}" />
113 <img src="${h.url("/images/icons/database.png")}" alt="${_('Products')}" />
114 </span>
114 </span>
115 <span>&darr;</span>
115 <span>&darr;</span>
116 </a>
116 </a>
117 <ul id="repo_switcher_list" class="repo_switcher">
117 <ul id="repo_switcher_list" class="repo_switcher">
118 <li>
118 <li>
119 <a href="#">${_('loading...')}</a>
119 <a href="#">${_('loading...')}</a>
120 </li>
120 </li>
121 </ul>
121 </ul>
122 <script type="text/javascript">
122 <script type="text/javascript">
123 YUE.on('repo_switcher','mouseover',function(){
123 YUE.on('repo_switcher','mouseover',function(){
124 function qfilter(){
124 function qfilter(){
125 var S = YAHOO.util.Selector;
125 var S = YAHOO.util.Selector;
126
126
127 var q_filter = YUD.get('q_filter_rs');
127 var q_filter = YUD.get('q_filter_rs');
128 var F = YAHOO.namespace('q_filter_rs');
128 var F = YAHOO.namespace('q_filter_rs');
129
129
130 YUE.on(q_filter,'click',function(){
130 YUE.on(q_filter,'click',function(){
131 q_filter.value = '';
131 q_filter.value = '';
132 });
132 });
133
133
134 F.filterTimeout = null;
134 F.filterTimeout = null;
135
135
136 F.updateFilter = function() {
136 F.updateFilter = function() {
137 // Reset timeout
137 // Reset timeout
138 F.filterTimeout = null;
138 F.filterTimeout = null;
139
139
140 var obsolete = [];
140 var obsolete = [];
141 var nodes = S.query('ul#repo_switcher_list li a.repo_name');
141 var nodes = S.query('ul#repo_switcher_list li a.repo_name');
142 var req = YUD.get('q_filter_rs').value;
142 var req = YUD.get('q_filter_rs').value;
143 for (n in nodes){
143 for (n in nodes){
144 YUD.setStyle(nodes[n].parentNode,'display','')
144 YUD.setStyle(nodes[n].parentNode,'display','')
145 }
145 }
146 if (req){
146 if (req){
147 for (n in nodes){
147 for (n in nodes){
148 console.log(n);
148 console.log(n);
149 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
149 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
150 obsolete.push(nodes[n]);
150 obsolete.push(nodes[n]);
151 }
151 }
152 }
152 }
153 if(obsolete){
153 if(obsolete){
154 for (n in obsolete){
154 for (n in obsolete){
155 YUD.setStyle(obsolete[n].parentNode,'display','none');
155 YUD.setStyle(obsolete[n].parentNode,'display','none');
156 }
156 }
157 }
157 }
158 }
158 }
159 }
159 }
160
160
161 YUE.on(q_filter,'keyup',function(e){
161 YUE.on(q_filter,'keyup',function(e){
162 clearTimeout(F.filterTimeout);
162 clearTimeout(F.filterTimeout);
163 setTimeout(F.updateFilter,600);
163 setTimeout(F.updateFilter,600);
164 });
164 });
165 }
165 }
166 var loaded = YUD.hasClass('repo_switcher','loaded');
166 var loaded = YUD.hasClass('repo_switcher','loaded');
167 if(!loaded){
167 if(!loaded){
168 YUD.addClass('repo_switcher','loaded');
168 YUD.addClass('repo_switcher','loaded');
169 YAHOO.util.Connect.asyncRequest('GET',"${h.url('repo_switcher')}",{
169 YAHOO.util.Connect.asyncRequest('GET',"${h.url('repo_switcher')}",{
170 success:function(o){
170 success:function(o){
171 YUD.get('repo_switcher_list').innerHTML = o.responseText;
171 YUD.get('repo_switcher_list').innerHTML = o.responseText;
172 qfilter();
172 qfilter();
173 },
173 },
174 failure:function(o){
174 failure:function(o){
175 YUD.removeClass('repo_switcher','loaded');
175 YUD.removeClass('repo_switcher','loaded');
176 }
176 }
177 },null);
177 },null);
178 }
178 }
179 return false;
179 return false;
180 });
180 });
181 </script>
181 </script>
182 </li>
182 </li>
183
183
184 <li ${is_current('summary')}>
184 <li ${is_current('summary')}>
185 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
185 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
186 <span class="icon">
186 <span class="icon">
187 <img src="${h.url("/images/icons/clipboard_16.png")}" alt="${_('Summary')}" />
187 <img src="${h.url("/images/icons/clipboard_16.png")}" alt="${_('Summary')}" />
188 </span>
188 </span>
189 <span>${_('Summary')}</span>
189 <span>${_('Summary')}</span>
190 </a>
190 </a>
191 </li>
191 </li>
192 ##<li ${is_current('shortlog')}>
192 ##<li ${is_current('shortlog')}>
193 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
193 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
194 ## <span class="icon">
194 ## <span class="icon">
195 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
195 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
196 ## </span>
196 ## </span>
197 ## <span>${_('Shortlog')}</span>
197 ## <span>${_('Shortlog')}</span>
198 ## </a>
198 ## </a>
199 ##</li>
199 ##</li>
200 <li ${is_current('changelog')}>
200 <li ${is_current('changelog')}>
201 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
201 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
202 <span class="icon">
202 <span class="icon">
203 <img src="${h.url("/images/icons/time.png")}" alt="${_('Changelog')}" />
203 <img src="${h.url("/images/icons/time.png")}" alt="${_('Changelog')}" />
204 </span>
204 </span>
205 <span>${_('Changelog')}</span>
205 <span>${_('Changelog')}</span>
206 </a>
206 </a>
207 </li>
207 </li>
208
208
209 <li ${is_current('switch_to')}>
209 <li ${is_current('switch_to')}>
210 <a title="${_('Switch to')}" href="#">
210 <a title="${_('Switch to')}" href="#">
211 <span class="icon">
211 <span class="icon">
212 <img src="${h.url("/images/icons/arrow_switch.png")}" alt="${_('Switch to')}" />
212 <img src="${h.url("/images/icons/arrow_switch.png")}" alt="${_('Switch to')}" />
213 </span>
213 </span>
214 <span>${_('Switch to')}</span>
214 <span>${_('Switch to')}</span>
215 </a>
215 </a>
216 <ul>
216 <ul>
217 <li>
217 <li>
218 ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
218 ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
219 <ul>
219 <ul>
220 %if c.rhodecode_repo.branches.values():
220 %if c.rhodecode_repo.branches.values():
221 %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
221 %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
222 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
222 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
223 %endfor
223 %endfor
224 %else:
224 %else:
225 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
225 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
226 %endif
226 %endif
227 </ul>
227 </ul>
228 </li>
228 </li>
229 <li>
229 <li>
230 ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
230 ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
231 <ul>
231 <ul>
232 %if c.rhodecode_repo.tags.values():
232 %if c.rhodecode_repo.tags.values():
233 %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
233 %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
234 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
234 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
235 %endfor
235 %endfor
236 %else:
236 %else:
237 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
237 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
238 %endif
238 %endif
239 </ul>
239 </ul>
240 </li>
240 </li>
241 </ul>
241 </ul>
242 </li>
242 </li>
243 <li ${is_current('files')}>
243 <li ${is_current('files')}>
244 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
244 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
245 <span class="icon">
245 <span class="icon">
246 <img src="${h.url("/images/icons/file.png")}" alt="${_('Files')}" />
246 <img src="${h.url("/images/icons/file.png")}" alt="${_('Files')}" />
247 </span>
247 </span>
248 <span>${_('Files')}</span>
248 <span>${_('Files')}</span>
249 </a>
249 </a>
250 </li>
250 </li>
251
251
252 <li ${is_current('options')}>
252 <li ${is_current('options')}>
253 <a title="${_('Options')}" href="#">
253 <a title="${_('Options')}" href="#">
254 <span class="icon">
254 <span class="icon">
255 <img src="${h.url("/images/icons/table_gear.png")}" alt="${_('Admin')}" />
255 <img src="${h.url("/images/icons/table_gear.png")}" alt="${_('Admin')}" />
256 </span>
256 </span>
257 <span>${_('Options')}</span>
257 <span>${_('Options')}</span>
258 </a>
258 </a>
259 <ul>
259 <ul>
260 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
260 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
261 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
261 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
262 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
262 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
263 %else:
263 %else:
264 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
264 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
265 %endif
265 %endif
266 %endif
266 %endif
267 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
267 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
268 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
268 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
269
269
270 %if h.HasPermissionAll('hg.admin')('access admin main page'):
270 %if h.HasPermissionAll('hg.admin')('access admin main page'):
271 <li>
271 <li>
272 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
272 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
273 <%def name="admin_menu()">
273 <%def name="admin_menu()">
274 <ul>
274 <ul>
275 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
275 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
276 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
276 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
277 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
277 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
278 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
278 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
279 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
279 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
280 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
280 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
281 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
281 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
282 </ul>
282 </ul>
283 </%def>
283 </%def>
284
284
285 ${admin_menu()}
285 ${admin_menu()}
286 </li>
286 </li>
287 %endif
287 %endif
288
288
289 </ul>
289 </ul>
290 </li>
290 </li>
291
291
292 <li>
292 <li>
293 <a title="${_('Followers')}" href="#">
293 <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
294 <span class="icon_short">
294 <span class="icon_short">
295 <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
295 <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
296 </span>
296 </span>
297 <span id="current_followers_count" class="short">${c.repository_followers}</span>
297 <span id="current_followers_count" class="short">${c.repository_followers}</span>
298 </a>
298 </a>
299 </li>
299 </li>
300 <li>
300 <li>
301 <a title="${_('Forks')}" href="#">
301 <a title="${_('Forks')}" href="#">
302 <span class="icon_short">
302 <span class="icon_short">
303 <img src="${h.url("/images/icons/arrow_divide.png")}" alt="${_('Forks')}" />
303 <img src="${h.url("/images/icons/arrow_divide.png")}" alt="${_('Forks')}" />
304 </span>
304 </span>
305 <span class="short">${c.repository_forks}</span>
305 <span class="short">${c.repository_forks}</span>
306 </a>
306 </a>
307 </li>
307 </li>
308
308
309
309
310
310
311 </ul>
311 </ul>
312 %else:
312 %else:
313 ##ROOT MENU
313 ##ROOT MENU
314 <ul id="quick">
314 <ul id="quick">
315 <li>
315 <li>
316 <a title="${_('Home')}" href="${h.url('home')}">
316 <a title="${_('Home')}" href="${h.url('home')}">
317 <span class="icon">
317 <span class="icon">
318 <img src="${h.url("/images/icons/home_16.png")}" alt="${_('Home')}" />
318 <img src="${h.url("/images/icons/home_16.png")}" alt="${_('Home')}" />
319 </span>
319 </span>
320 <span>${_('Home')}</span>
320 <span>${_('Home')}</span>
321 </a>
321 </a>
322 </li>
322 </li>
323 %if c.rhodecode_user.username != 'default':
323 %if c.rhodecode_user.username != 'default':
324 <li>
324 <li>
325 <a title="${_('Journal')}" href="${h.url('journal')}">
325 <a title="${_('Journal')}" href="${h.url('journal')}">
326 <span class="icon">
326 <span class="icon">
327 <img src="${h.url("/images/icons/book.png")}" alt="${_('Journal')}" />
327 <img src="${h.url("/images/icons/book.png")}" alt="${_('Journal')}" />
328 </span>
328 </span>
329 <span>${_('Journal')}</span>
329 <span>${_('Journal')}</span>
330 </a>
330 </a>
331 </li>
331 </li>
332 %endif
332 %endif
333 <li>
333 <li>
334 <a title="${_('Search')}" href="${h.url('search')}">
334 <a title="${_('Search')}" href="${h.url('search')}">
335 <span class="icon">
335 <span class="icon">
336 <img src="${h.url("/images/icons/search_16.png")}" alt="${_('Search')}" />
336 <img src="${h.url("/images/icons/search_16.png")}" alt="${_('Search')}" />
337 </span>
337 </span>
338 <span>${_('Search')}</span>
338 <span>${_('Search')}</span>
339 </a>
339 </a>
340 </li>
340 </li>
341
341
342 %if h.HasPermissionAll('hg.admin')('access admin main page'):
342 %if h.HasPermissionAll('hg.admin')('access admin main page'):
343 <li ${is_current('admin')}>
343 <li ${is_current('admin')}>
344 <a title="${_('Admin')}" href="${h.url('admin_home')}">
344 <a title="${_('Admin')}" href="${h.url('admin_home')}">
345 <span class="icon">
345 <span class="icon">
346 <img src="${h.url("/images/icons/cog_edit.png")}" alt="${_('Admin')}" />
346 <img src="${h.url("/images/icons/cog_edit.png")}" alt="${_('Admin')}" />
347 </span>
347 </span>
348 <span>${_('Admin')}</span>
348 <span>${_('Admin')}</span>
349 </a>
349 </a>
350 ${admin_menu()}
350 ${admin_menu()}
351 </li>
351 </li>
352 %endif
352 %endif
353 </ul>
353 </ul>
354 %endif
354 %endif
355 </%def> No newline at end of file
355 </%def>
General Comments 0
You need to be logged in to leave comments. Login now