##// END OF EJS Templates
Fixed permissions for users groups, group can have create repo permission now....
marcink -
r1271:aa7e45ad beta
parent child Browse files
Show More
@@ -1,312 +1,339 b''
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 rmap.resource('users_group', 'users_groups',
138 with rmap.submapper(path_prefix='/_admin',
139 controller='admin/users_groups', path_prefix='/_admin')
139 controller='admin/users_groups') as m:
140 m.connect("users_groups", "/users_groups",
141 action="create", conditions=dict(method=["POST"]))
142 m.connect("users_groups", "/users_groups",
143 action="index", conditions=dict(method=["GET"]))
144 m.connect("formatted_users_groups", "/users_groups.{format}",
145 action="index", conditions=dict(method=["GET"]))
146 m.connect("new_users_group", "/users_groups/new",
147 action="new", conditions=dict(method=["GET"]))
148 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
149 action="new", conditions=dict(method=["GET"]))
150 m.connect("update_users_group", "/users_groups/{id}",
151 action="update", conditions=dict(method=["PUT"]))
152 m.connect("delete_users_group", "/users_groups/{id}",
153 action="delete", conditions=dict(method=["DELETE"]))
154 m.connect("edit_users_group", "/users_groups/{id}/edit",
155 action="edit", conditions=dict(method=["GET"]))
156 m.connect("formatted_edit_users_group",
157 "/users_groups/{id}.{format}/edit",
158 action="edit", conditions=dict(method=["GET"]))
159 m.connect("users_group", "/users_groups/{id}",
160 action="show", conditions=dict(method=["GET"]))
161 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
162 action="show", conditions=dict(method=["GET"]))
163
164 #EXTRAS USER ROUTES
165 m.connect("users_group_perm", "/users_groups_perm/{id}",
166 action="update_perm", conditions=dict(method=["PUT"]))
140
167
141 #ADMIN GROUP REST ROUTES
168 #ADMIN GROUP REST ROUTES
142 rmap.resource('group', 'groups',
169 rmap.resource('group', 'groups',
143 controller='admin/groups', path_prefix='/_admin')
170 controller='admin/groups', path_prefix='/_admin')
144
171
145 #ADMIN PERMISSIONS REST ROUTES
172 #ADMIN PERMISSIONS REST ROUTES
146 rmap.resource('permission', 'permissions',
173 rmap.resource('permission', 'permissions',
147 controller='admin/permissions', path_prefix='/_admin')
174 controller='admin/permissions', path_prefix='/_admin')
148
175
149 ##ADMIN LDAP SETTINGS
176 ##ADMIN LDAP SETTINGS
150 rmap.connect('ldap_settings', '/_admin/ldap',
177 rmap.connect('ldap_settings', '/_admin/ldap',
151 controller='admin/ldap_settings', action='ldap_settings',
178 controller='admin/ldap_settings', action='ldap_settings',
152 conditions=dict(method=["POST"]))
179 conditions=dict(method=["POST"]))
153
180
154 rmap.connect('ldap_home', '/_admin/ldap',
181 rmap.connect('ldap_home', '/_admin/ldap',
155 controller='admin/ldap_settings')
182 controller='admin/ldap_settings')
156
183
157 #ADMIN SETTINGS REST ROUTES
184 #ADMIN SETTINGS REST ROUTES
158 with rmap.submapper(path_prefix='/_admin',
185 with rmap.submapper(path_prefix='/_admin',
159 controller='admin/settings') as m:
186 controller='admin/settings') as m:
160 m.connect("admin_settings", "/settings",
187 m.connect("admin_settings", "/settings",
161 action="create", conditions=dict(method=["POST"]))
188 action="create", conditions=dict(method=["POST"]))
162 m.connect("admin_settings", "/settings",
189 m.connect("admin_settings", "/settings",
163 action="index", conditions=dict(method=["GET"]))
190 action="index", conditions=dict(method=["GET"]))
164 m.connect("formatted_admin_settings", "/settings.{format}",
191 m.connect("formatted_admin_settings", "/settings.{format}",
165 action="index", conditions=dict(method=["GET"]))
192 action="index", conditions=dict(method=["GET"]))
166 m.connect("admin_new_setting", "/settings/new",
193 m.connect("admin_new_setting", "/settings/new",
167 action="new", conditions=dict(method=["GET"]))
194 action="new", conditions=dict(method=["GET"]))
168 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
195 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
169 action="new", conditions=dict(method=["GET"]))
196 action="new", conditions=dict(method=["GET"]))
170 m.connect("/settings/{setting_id}",
197 m.connect("/settings/{setting_id}",
171 action="update", conditions=dict(method=["PUT"]))
198 action="update", conditions=dict(method=["PUT"]))
172 m.connect("/settings/{setting_id}",
199 m.connect("/settings/{setting_id}",
173 action="delete", conditions=dict(method=["DELETE"]))
200 action="delete", conditions=dict(method=["DELETE"]))
174 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
201 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
175 action="edit", conditions=dict(method=["GET"]))
202 action="edit", conditions=dict(method=["GET"]))
176 m.connect("formatted_admin_edit_setting",
203 m.connect("formatted_admin_edit_setting",
177 "/settings/{setting_id}.{format}/edit",
204 "/settings/{setting_id}.{format}/edit",
178 action="edit", conditions=dict(method=["GET"]))
205 action="edit", conditions=dict(method=["GET"]))
179 m.connect("admin_setting", "/settings/{setting_id}",
206 m.connect("admin_setting", "/settings/{setting_id}",
180 action="show", conditions=dict(method=["GET"]))
207 action="show", conditions=dict(method=["GET"]))
181 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
208 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
182 action="show", conditions=dict(method=["GET"]))
209 action="show", conditions=dict(method=["GET"]))
183 m.connect("admin_settings_my_account", "/my_account",
210 m.connect("admin_settings_my_account", "/my_account",
184 action="my_account", conditions=dict(method=["GET"]))
211 action="my_account", conditions=dict(method=["GET"]))
185 m.connect("admin_settings_my_account_update", "/my_account_update",
212 m.connect("admin_settings_my_account_update", "/my_account_update",
186 action="my_account_update", conditions=dict(method=["PUT"]))
213 action="my_account_update", conditions=dict(method=["PUT"]))
187 m.connect("admin_settings_create_repository", "/create_repository",
214 m.connect("admin_settings_create_repository", "/create_repository",
188 action="create_repository", conditions=dict(method=["GET"]))
215 action="create_repository", conditions=dict(method=["GET"]))
189
216
190 #ADMIN MAIN PAGES
217 #ADMIN MAIN PAGES
191 with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
218 with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
192 m.connect('admin_home', '', action='index')
219 m.connect('admin_home', '', action='index')
193 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\. _-]*}',
194 action='add_repo')
221 action='add_repo')
195
222
196 #USER JOURNAL
223 #USER JOURNAL
197 rmap.connect('journal', '/_admin/journal', controller='journal')
224 rmap.connect('journal', '/_admin/journal', controller='journal')
198
225
199 rmap.connect('public_journal', '/_admin/public_journal',
226 rmap.connect('public_journal', '/_admin/public_journal',
200 controller='journal', action="public_journal")
227 controller='journal', action="public_journal")
201
228
202 rmap.connect('public_journal_rss', '/_admin/public_journal_rss',
229 rmap.connect('public_journal_rss', '/_admin/public_journal_rss',
203 controller='journal', action="public_journal_rss")
230 controller='journal', action="public_journal_rss")
204
231
205 rmap.connect('public_journal_atom', '/_admin/public_journal_atom',
232 rmap.connect('public_journal_atom', '/_admin/public_journal_atom',
206 controller='journal', action="public_journal_atom")
233 controller='journal', action="public_journal_atom")
207
234
208 rmap.connect('toggle_following', '/_admin/toggle_following',
235 rmap.connect('toggle_following', '/_admin/toggle_following',
209 controller='journal', action='toggle_following',
236 controller='journal', action='toggle_following',
210 conditions=dict(method=["POST"]))
237 conditions=dict(method=["POST"]))
211
238
212 #SEARCH
239 #SEARCH
213 rmap.connect('search', '/_admin/search', controller='search',)
240 rmap.connect('search', '/_admin/search', controller='search',)
214 rmap.connect('search_repo', '/_admin/search/{search_repo:.*}',
241 rmap.connect('search_repo', '/_admin/search/{search_repo:.*}',
215 controller='search')
242 controller='search')
216
243
217 #LOGIN/LOGOUT/REGISTER/SIGN IN
244 #LOGIN/LOGOUT/REGISTER/SIGN IN
218 rmap.connect('login_home', '/_admin/login', controller='login')
245 rmap.connect('login_home', '/_admin/login', controller='login')
219 rmap.connect('logout_home', '/_admin/logout', controller='login',
246 rmap.connect('logout_home', '/_admin/logout', controller='login',
220 action='logout')
247 action='logout')
221
248
222 rmap.connect('register', '/_admin/register', controller='login',
249 rmap.connect('register', '/_admin/register', controller='login',
223 action='register')
250 action='register')
224
251
225 rmap.connect('reset_password', '/_admin/password_reset',
252 rmap.connect('reset_password', '/_admin/password_reset',
226 controller='login', action='password_reset')
253 controller='login', action='password_reset')
227
254
228 #FEEDS
255 #FEEDS
229 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
256 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
230 controller='feed', action='rss',
257 controller='feed', action='rss',
231 conditions=dict(function=check_repo))
258 conditions=dict(function=check_repo))
232
259
233 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
260 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
234 controller='feed', action='atom',
261 controller='feed', action='atom',
235 conditions=dict(function=check_repo))
262 conditions=dict(function=check_repo))
236
263
237 #REPOSITORY ROUTES
264 #REPOSITORY ROUTES
238 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
265 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
239 controller='changeset', revision='tip',
266 controller='changeset', revision='tip',
240 conditions=dict(function=check_repo))
267 conditions=dict(function=check_repo))
241
268
242 rmap.connect('raw_changeset_home',
269 rmap.connect('raw_changeset_home',
243 '/{repo_name:.*}/raw-changeset/{revision}',
270 '/{repo_name:.*}/raw-changeset/{revision}',
244 controller='changeset', action='raw_changeset',
271 controller='changeset', action='raw_changeset',
245 revision='tip', conditions=dict(function=check_repo))
272 revision='tip', conditions=dict(function=check_repo))
246
273
247 rmap.connect('summary_home', '/{repo_name:.*}',
274 rmap.connect('summary_home', '/{repo_name:.*}',
248 controller='summary', conditions=dict(function=check_repo))
275 controller='summary', conditions=dict(function=check_repo))
249
276
250 rmap.connect('summary_home', '/{repo_name:.*}/summary',
277 rmap.connect('summary_home', '/{repo_name:.*}/summary',
251 controller='summary', conditions=dict(function=check_repo))
278 controller='summary', conditions=dict(function=check_repo))
252
279
253 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
280 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
254 controller='shortlog', conditions=dict(function=check_repo))
281 controller='shortlog', conditions=dict(function=check_repo))
255
282
256 rmap.connect('branches_home', '/{repo_name:.*}/branches',
283 rmap.connect('branches_home', '/{repo_name:.*}/branches',
257 controller='branches', conditions=dict(function=check_repo))
284 controller='branches', conditions=dict(function=check_repo))
258
285
259 rmap.connect('tags_home', '/{repo_name:.*}/tags',
286 rmap.connect('tags_home', '/{repo_name:.*}/tags',
260 controller='tags', conditions=dict(function=check_repo))
287 controller='tags', conditions=dict(function=check_repo))
261
288
262 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
289 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
263 controller='changelog', conditions=dict(function=check_repo))
290 controller='changelog', conditions=dict(function=check_repo))
264
291
265 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
292 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
266 controller='files', revision='tip', f_path='',
293 controller='files', revision='tip', f_path='',
267 conditions=dict(function=check_repo))
294 conditions=dict(function=check_repo))
268
295
269 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
296 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
270 controller='files', action='diff', revision='tip', f_path='',
297 controller='files', action='diff', revision='tip', f_path='',
271 conditions=dict(function=check_repo))
298 conditions=dict(function=check_repo))
272
299
273 rmap.connect('files_rawfile_home',
300 rmap.connect('files_rawfile_home',
274 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
301 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
275 controller='files', action='rawfile', revision='tip',
302 controller='files', action='rawfile', revision='tip',
276 f_path='', conditions=dict(function=check_repo))
303 f_path='', conditions=dict(function=check_repo))
277
304
278 rmap.connect('files_raw_home',
305 rmap.connect('files_raw_home',
279 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
306 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
280 controller='files', action='raw', revision='tip', f_path='',
307 controller='files', action='raw', revision='tip', f_path='',
281 conditions=dict(function=check_repo))
308 conditions=dict(function=check_repo))
282
309
283 rmap.connect('files_annotate_home',
310 rmap.connect('files_annotate_home',
284 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
311 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
285 controller='files', action='annotate', revision='tip',
312 controller='files', action='annotate', revision='tip',
286 f_path='', conditions=dict(function=check_repo))
313 f_path='', conditions=dict(function=check_repo))
287
314
288 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
315 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
289 controller='files', action='archivefile',
316 controller='files', action='archivefile',
290 conditions=dict(function=check_repo))
317 conditions=dict(function=check_repo))
291
318
292 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
319 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
293 controller='settings', action="delete",
320 controller='settings', action="delete",
294 conditions=dict(method=["DELETE"], function=check_repo))
321 conditions=dict(method=["DELETE"], function=check_repo))
295
322
296 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
323 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
297 controller='settings', action="update",
324 controller='settings', action="update",
298 conditions=dict(method=["PUT"], function=check_repo))
325 conditions=dict(method=["PUT"], function=check_repo))
299
326
300 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
327 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
301 controller='settings', action='index',
328 controller='settings', action='index',
302 conditions=dict(function=check_repo))
329 conditions=dict(function=check_repo))
303
330
304 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
331 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
305 controller='settings', action='fork_create',
332 controller='settings', action='fork_create',
306 conditions=dict(function=check_repo, method=["POST"]))
333 conditions=dict(function=check_repo, method=["POST"]))
307
334
308 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
335 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
309 controller='settings', action='fork',
336 controller='settings', action='fork',
310 conditions=dict(function=check_repo))
337 conditions=dict(function=check_repo))
311
338
312 return rmap
339 return rmap
@@ -1,180 +1,213 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.users_groups
3 rhodecode.controllers.admin.users_groups
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Users Groups crud controller for pylons
6 Users Groups crud controller for pylons
7
7
8 :created_on: Jan 25, 2011
8 :created_on: Jan 25, 2011
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 logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31 from pylons import request, session, tmpl_context as c, url, config
31 from pylons import request, session, tmpl_context as c, url, config
32 from pylons.controllers.util import abort, redirect
32 from pylons.controllers.util import abort, redirect
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34
34
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
36 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
37 from rhodecode.lib.base import BaseController, render
37 from rhodecode.lib.base import BaseController, render
38
38
39 from rhodecode.model.db import User, UsersGroup
39 from rhodecode.model.db import User, UsersGroup, Permission, UsersGroupToPerm
40 from rhodecode.model.forms import UserForm, UsersGroupForm
40 from rhodecode.model.forms import UserForm, UsersGroupForm
41 from rhodecode.model.user import UserModel
42 from rhodecode.model.users_group import UsersGroupModel
41 from rhodecode.model.users_group import UsersGroupModel
43
42
44 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
45
44
46
45
47 class UsersGroupsController(BaseController):
46 class UsersGroupsController(BaseController):
48 """REST Controller styled on the Atom Publishing Protocol"""
47 """REST Controller styled on the Atom Publishing Protocol"""
49 # To properly map this controller, ensure your config/routing.py
48 # To properly map this controller, ensure your config/routing.py
50 # file has a resource setup:
49 # file has a resource setup:
51 # map.resource('users_group', 'users_groups')
50 # map.resource('users_group', 'users_groups')
52
51
53 @LoginRequired()
52 @LoginRequired()
54 @HasPermissionAllDecorator('hg.admin')
53 @HasPermissionAllDecorator('hg.admin')
55 def __before__(self):
54 def __before__(self):
56 c.admin_user = session.get('admin_user')
55 c.admin_user = session.get('admin_user')
57 c.admin_username = session.get('admin_username')
56 c.admin_username = session.get('admin_username')
58 super(UsersGroupsController, self).__before__()
57 super(UsersGroupsController, self).__before__()
59 c.available_permissions = config['available_permissions']
58 c.available_permissions = config['available_permissions']
60
59
61 def index(self, format='html'):
60 def index(self, format='html'):
62 """GET /users_groups: All items in the collection"""
61 """GET /users_groups: All items in the collection"""
63 # url('users_groups')
62 # url('users_groups')
64 c.users_groups_list = self.sa.query(UsersGroup).all()
63 c.users_groups_list = self.sa.query(UsersGroup).all()
65 return render('admin/users_groups/users_groups.html')
64 return render('admin/users_groups/users_groups.html')
66
65
67 def create(self):
66 def create(self):
68 """POST /users_groups: Create a new item"""
67 """POST /users_groups: Create a new item"""
69 # url('users_groups')
68 # url('users_groups')
70 users_group_model = UsersGroupModel()
69 users_group_model = UsersGroupModel()
71 users_group_form = UsersGroupForm()()
70 users_group_form = UsersGroupForm()()
72 try:
71 try:
73 form_result = users_group_form.to_python(dict(request.POST))
72 form_result = users_group_form.to_python(dict(request.POST))
74 users_group_model.create(form_result)
73 users_group_model.create(form_result)
75 h.flash(_('created users group %s') \
74 h.flash(_('created users group %s') \
76 % form_result['users_group_name'], category='success')
75 % form_result['users_group_name'], category='success')
77 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
76 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
78 except formencode.Invalid, errors:
77 except formencode.Invalid, errors:
79 return htmlfill.render(
78 return htmlfill.render(
80 render('admin/users_groups/users_group_add.html'),
79 render('admin/users_groups/users_group_add.html'),
81 defaults=errors.value,
80 defaults=errors.value,
82 errors=errors.error_dict or {},
81 errors=errors.error_dict or {},
83 prefix_error=False,
82 prefix_error=False,
84 encoding="UTF-8")
83 encoding="UTF-8")
85 except Exception:
84 except Exception:
86 log.error(traceback.format_exc())
85 log.error(traceback.format_exc())
87 h.flash(_('error occurred during creation of users group %s') \
86 h.flash(_('error occurred during creation of users group %s') \
88 % request.POST.get('users_group_name'), category='error')
87 % request.POST.get('users_group_name'), category='error')
89
88
90 return redirect(url('users_groups'))
89 return redirect(url('users_groups'))
91
90
92 def new(self, format='html'):
91 def new(self, format='html'):
93 """GET /users_groups/new: Form to create a new item"""
92 """GET /users_groups/new: Form to create a new item"""
94 # url('new_users_group')
93 # url('new_users_group')
95 return render('admin/users_groups/users_group_add.html')
94 return render('admin/users_groups/users_group_add.html')
96
95
97 def update(self, id):
96 def update(self, id):
98 """PUT /users_groups/id: Update an existing item"""
97 """PUT /users_groups/id: Update an existing item"""
99 # Forms posted to this method should contain a hidden field:
98 # Forms posted to this method should contain a hidden field:
100 # <input type="hidden" name="_method" value="PUT" />
99 # <input type="hidden" name="_method" value="PUT" />
101 # Or using helpers:
100 # Or using helpers:
102 # h.form(url('users_group', id=ID),
101 # h.form(url('users_group', id=ID),
103 # method='put')
102 # method='put')
104 # url('users_group', id=ID)
103 # url('users_group', id=ID)
105
104
106 users_group_model = UsersGroupModel()
105 users_group_model = UsersGroupModel()
107 c.users_group = users_group_model.get(id)
106 c.users_group = users_group_model.get(id)
108 c.group_members = [(x.user_id, x.user.username) for x in
107 c.group_members = [(x.user_id, x.user.username) for x in
109 c.users_group.members]
108 c.users_group.members]
110
109
111 c.available_members = [(x.user_id, x.username) for x in
110 c.available_members = [(x.user_id, x.username) for x in
112 self.sa.query(User).all()]
111 self.sa.query(User).all()]
113 users_group_form = UsersGroupForm(edit=True,
112 users_group_form = UsersGroupForm(edit=True,
114 old_data=c.users_group.get_dict(),
113 old_data=c.users_group.get_dict(),
115 available_members=[str(x[0]) for x
114 available_members=[str(x[0]) for x
116 in c.available_members])()
115 in c.available_members])()
117
116
118 try:
117 try:
119 form_result = users_group_form.to_python(request.POST)
118 form_result = users_group_form.to_python(request.POST)
120 users_group_model.update(id, form_result)
119 users_group_model.update(id, form_result)
121 h.flash(_('updated users group %s') \
120 h.flash(_('updated users group %s') \
122 % form_result['users_group_name'],
121 % form_result['users_group_name'],
123 category='success')
122 category='success')
124 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
123 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
125 except formencode.Invalid, errors:
124 except formencode.Invalid, errors:
125 e = errors.error_dict or {}
126
127 perm = Permission.get_by_key('hg.create.repository')
128 e.update({'create_repo_perm':
129 UsersGroupToPerm.has_perm(id, perm)})
130
126 return htmlfill.render(
131 return htmlfill.render(
127 render('admin/users_groups/users_group_edit.html'),
132 render('admin/users_groups/users_group_edit.html'),
128 defaults=errors.value,
133 defaults=errors.value,
129 errors=errors.error_dict or {},
134 errors=e,
130 prefix_error=False,
135 prefix_error=False,
131 encoding="UTF-8")
136 encoding="UTF-8")
132 except Exception:
137 except Exception:
133 log.error(traceback.format_exc())
138 log.error(traceback.format_exc())
134 h.flash(_('error occurred during update of users group %s') \
139 h.flash(_('error occurred during update of users group %s') \
135 % request.POST.get('users_group_name'), category='error')
140 % request.POST.get('users_group_name'), category='error')
136
141
137 return redirect(url('users_groups'))
142 return redirect(url('users_groups'))
138
143
139 def delete(self, id):
144 def delete(self, id):
140 """DELETE /users_groups/id: Delete an existing item"""
145 """DELETE /users_groups/id: Delete an existing item"""
141 # Forms posted to this method should contain a hidden field:
146 # Forms posted to this method should contain a hidden field:
142 # <input type="hidden" name="_method" value="DELETE" />
147 # <input type="hidden" name="_method" value="DELETE" />
143 # Or using helpers:
148 # Or using helpers:
144 # h.form(url('users_group', id=ID),
149 # h.form(url('users_group', id=ID),
145 # method='delete')
150 # method='delete')
146 # url('users_group', id=ID)
151 # url('users_group', id=ID)
147 users_group_model = UsersGroupModel()
152 users_group_model = UsersGroupModel()
148 try:
153 try:
149 users_group_model.delete(id)
154 users_group_model.delete(id)
150 h.flash(_('successfully deleted users group'), category='success')
155 h.flash(_('successfully deleted users group'), category='success')
151 except Exception:
156 except Exception:
152 h.flash(_('An error occurred during deletion of users group'),
157 h.flash(_('An error occurred during deletion of users group'),
153 category='error')
158 category='error')
154 return redirect(url('users_groups'))
159 return redirect(url('users_groups'))
155
160
156 def show(self, id, format='html'):
161 def show(self, id, format='html'):
157 """GET /users_groups/id: Show a specific item"""
162 """GET /users_groups/id: Show a specific item"""
158 # url('users_group', id=ID)
163 # url('users_group', id=ID)
159
164
160 def edit(self, id, format='html'):
165 def edit(self, id, format='html'):
161 """GET /users_groups/id/edit: Form to edit an existing item"""
166 """GET /users_groups/id/edit: Form to edit an existing item"""
162 # url('edit_users_group', id=ID)
167 # url('edit_users_group', id=ID)
163
168
164 c.users_group = self.sa.query(UsersGroup).get(id)
169 c.users_group = self.sa.query(UsersGroup).get(id)
165 if not c.users_group:
170 if not c.users_group:
166 return redirect(url('users_groups'))
171 return redirect(url('users_groups'))
167
172
168 c.users_group.permissions = {}
173 c.users_group.permissions = {}
169 c.group_members = [(x.user_id, x.user.username) for x in
174 c.group_members = [(x.user_id, x.user.username) for x in
170 c.users_group.members]
175 c.users_group.members]
171 c.available_members = [(x.user_id, x.username) for x in
176 c.available_members = [(x.user_id, x.username) for x in
172 self.sa.query(User).all()]
177 self.sa.query(User).all()]
173 defaults = c.users_group.get_dict()
178 defaults = c.users_group.get_dict()
174
179 perm = Permission.get_by_key('hg.create.repository')
180 defaults.update({'create_repo_perm':
181 UsersGroupToPerm.has_perm(id, perm)})
175 return htmlfill.render(
182 return htmlfill.render(
176 render('admin/users_groups/users_group_edit.html'),
183 render('admin/users_groups/users_group_edit.html'),
177 defaults=defaults,
184 defaults=defaults,
178 encoding="UTF-8",
185 encoding="UTF-8",
179 force_defaults=False
186 force_defaults=False
180 )
187 )
188
189 def update_perm(self, id):
190 """PUT /users_perm/id: Update an existing item"""
191 # url('users_group_perm', id=ID, method='put')
192
193 grant_perm = request.POST.get('create_repo_perm', False)
194
195 if grant_perm:
196 perm = Permission.get_by_key('hg.create.none')
197 UsersGroupToPerm.revoke_perm(id, perm)
198
199 perm = Permission.get_by_key('hg.create.repository')
200 UsersGroupToPerm.grant_perm(id, perm)
201 h.flash(_("Granted 'repository create' permission to user"),
202 category='success')
203
204 else:
205 perm = Permission.get_by_key('hg.create.repository')
206 UsersGroupToPerm.revoke_perm(id, perm)
207
208 perm = Permission.get_by_key('hg.create.none')
209 UsersGroupToPerm.grant_perm(id, perm)
210 h.flash(_("Revoked 'repository create' permission to user"),
211 category='success')
212
213 return redirect(url('edit_users_group', id=id))
@@ -1,97 +1,102 b''
1 import logging
1 import logging
2 import datetime
2 import datetime
3
3
4 from sqlalchemy import *
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper
6 from sqlalchemy.orm import relation, backref, class_mapper
7 from sqlalchemy.orm.session import Session
7 from sqlalchemy.orm.session import Session
8
8
9 from rhodecode.lib.dbmigrate.migrate import *
9 from rhodecode.lib.dbmigrate.migrate import *
10 from rhodecode.lib.dbmigrate.migrate.changeset import *
10 from rhodecode.lib.dbmigrate.migrate.changeset import *
11
11
12 from rhodecode.model.meta import Base
12 from rhodecode.model.meta import Base
13
13
14 log = logging.getLogger(__name__)
14 log = logging.getLogger(__name__)
15
15
16 def upgrade(migrate_engine):
16 def upgrade(migrate_engine):
17 """ Upgrade operations go here.
17 """ Upgrade operations go here.
18 Don't create your own engine; bind migrate_engine to your metadata
18 Don't create your own engine; bind migrate_engine to your metadata
19 """
19 """
20
20
21 #==========================================================================
21 #==========================================================================
22 # Add table `groups``
22 # Add table `groups``
23 #==========================================================================
23 #==========================================================================
24 from rhodecode.model.db import Group
24 from rhodecode.model.db import Group
25 Group().__table__.create()
25 Group().__table__.create()
26
26
27 #==========================================================================
27 #==========================================================================
28 # Add table `group_to_perm`
28 # Add table `group_to_perm`
29 #==========================================================================
29 #==========================================================================
30 from rhodecode.model.db import GroupToPerm
30 from rhodecode.model.db import GroupToPerm
31 GroupToPerm().__table__.create()
31 GroupToPerm().__table__.create()
32
32
33 #==========================================================================
33 #==========================================================================
34 # Add table `users_groups`
34 # Add table `users_groups`
35 #==========================================================================
35 #==========================================================================
36 from rhodecode.model.db import UsersGroup
36 from rhodecode.model.db import UsersGroup
37 UsersGroup().__table__.create()
37 UsersGroup().__table__.create()
38
38
39 #==========================================================================
39 #==========================================================================
40 # Add table `users_groups_members`
40 # Add table `users_groups_members`
41 #==========================================================================
41 #==========================================================================
42 from rhodecode.model.db import UsersGroupMember
42 from rhodecode.model.db import UsersGroupMember
43 UsersGroupMember().__table__.create()
43 UsersGroupMember().__table__.create()
44
44
45 #==========================================================================
45 #==========================================================================
46 # Add table `users_group_repo_to_perm`
47 #==========================================================================
48 from rhodecode.model.db import UsersGroupRepoToPerm
49 UsersGroupRepoToPerm().__table__.create()
50
51 #==========================================================================
46 # Add table `users_group_to_perm`
52 # Add table `users_group_to_perm`
47 #==========================================================================
53 #==========================================================================
48 from rhodecode.model.db import UsersGroupToPerm
54 from rhodecode.model.db import UsersGroupToPerm
49 UsersGroupToPerm().__table__.create()
55 UsersGroupToPerm().__table__.create()
50
56
51
52 #==========================================================================
57 #==========================================================================
53 # Upgrade of `users` table
58 # Upgrade of `users` table
54 #==========================================================================
59 #==========================================================================
55 from rhodecode.model.db import User
60 from rhodecode.model.db import User
56
61
57 #add column
62 #add column
58 ldap_dn = Column("ldap_dn", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
63 ldap_dn = Column("ldap_dn", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
59 ldap_dn.create(User().__table__)
64 ldap_dn.create(User().__table__)
60
65
61 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
66 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
62 api_key.create(User().__table__)
67 api_key.create(User().__table__)
63
68
64 #remove old column
69 #remove old column
65 is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
70 is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
66 is_ldap.drop(User().__table__)
71 is_ldap.drop(User().__table__)
67
72
68
73
69 #==========================================================================
74 #==========================================================================
70 # Upgrade of `repositories` table
75 # Upgrade of `repositories` table
71 #==========================================================================
76 #==========================================================================
72 from rhodecode.model.db import Repository
77 from rhodecode.model.db import Repository
73
78
74 #ADD downloads column#
79 #ADD downloads column#
75 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
80 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
76 enable_downloads.create(Repository().__table__)
81 enable_downloads.create(Repository().__table__)
77
82
78 #ADD group_id column#
83 #ADD group_id column#
79 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'),
84 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'),
80 nullable=True, unique=False, default=None)
85 nullable=True, unique=False, default=None)
81
86
82 group_id.create(Repository().__table__)
87 group_id.create(Repository().__table__)
83
88
84
89
85 #ADD clone_uri column#
90 #ADD clone_uri column#
86
91
87 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False,
92 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False,
88 assert_unicode=None),
93 assert_unicode=None),
89 nullable=True, unique=False, default=None)
94 nullable=True, unique=False, default=None)
90
95
91 clone_uri.create(Repository().__table__)
96 clone_uri.create(Repository().__table__)
92 return
97 return
93
98
94
99
95 def downgrade(migrate_engine):
100 def downgrade(migrate_engine):
96 meta = MetaData()
101 meta = MetaData()
97 meta.bind = migrate_engine
102 meta.bind = migrate_engine
@@ -1,71 +1,74 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.__init__
3 rhodecode.model.__init__
4 ~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 The application's model objects
6 The application's model objects
7
7
8 :created_on: Nov 25, 2010
8 :created_on: Nov 25, 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
13
14 :example:
14 :example:
15
15
16 .. code-block:: python
16 .. code-block:: python
17
17
18 from paste.deploy import appconfig
18 from paste.deploy import appconfig
19 from pylons import config
19 from pylons import config
20 from sqlalchemy import engine_from_config
20 from sqlalchemy import engine_from_config
21 from rhodecode.config.environment import load_environment
21 from rhodecode.config.environment import load_environment
22
22
23 conf = appconfig('config:development.ini', relative_to = './../../')
23 conf = appconfig('config:development.ini', relative_to = './../../')
24 load_environment(conf.global_conf, conf.local_conf)
24 load_environment(conf.global_conf, conf.local_conf)
25
25
26 engine = engine_from_config(config, 'sqlalchemy.')
26 engine = engine_from_config(config, 'sqlalchemy.')
27 init_model(engine)
27 init_model(engine)
28 # RUN YOUR CODE HERE
28 # RUN YOUR CODE HERE
29
29
30 """
30 """
31 # This program is free software: you can redistribute it and/or modify
31 # This program is free software: you can redistribute it and/or modify
32 # it under the terms of the GNU General Public License as published by
32 # it under the terms of the GNU General Public License as published by
33 # the Free Software Foundation, either version 3 of the License, or
33 # the Free Software Foundation, either version 3 of the License, or
34 # (at your option) any later version.
34 # (at your option) any later version.
35 #
35 #
36 # This program is distributed in the hope that it will be useful,
36 # This program is distributed in the hope that it will be useful,
37 # but WITHOUT ANY WARRANTY; without even the implied warranty of
37 # but WITHOUT ANY WARRANTY; without even the implied warranty of
38 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 # GNU General Public License for more details.
39 # GNU General Public License for more details.
40 #
40 #
41 # You should have received a copy of the GNU General Public License
41 # You should have received a copy of the GNU General Public License
42 # along with this program. If not, see <http://www.gnu.org/licenses/>.
42 # along with this program. If not, see <http://www.gnu.org/licenses/>.
43
43
44 import logging
44 import logging
45
45
46 from rhodecode.model import meta
46 from rhodecode.model import meta
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50 def init_model(engine):
51 def init_model(engine):
51 """Initializes db session, bind the engine with the metadata,
52 """
52 Call this before using any of the tables or classes in the model, preferably
53 Initializes db session, bind the engine with the metadata,
53 once in application start
54 Call this before using any of the tables or classes in the model,
55 preferably once in application start
54
56
55 :param engine: engine to bind to
57 :param engine: engine to bind to
56 """
58 """
57 log.info("initializing db for %s", engine)
59 log.info("initializing db for %s", engine)
58 meta.Base.metadata.bind = engine
60 meta.Base.metadata.bind = engine
59
61
62
60 class BaseModel(object):
63 class BaseModel(object):
61 """Base Model for all RhodeCode models, it adds sql alchemy session
64 """Base Model for all RhodeCode models, it adds sql alchemy session
62 into instance of model
65 into instance of model
63
66
64 :param sa: If passed it reuses this session instead of creating a new one
67 :param sa: If passed it reuses this session instead of creating a new one
65 """
68 """
66
69
67 def __init__(self, sa=None):
70 def __init__(self, sa=None):
68 if sa is not None:
71 if sa is not None:
69 self.sa = sa
72 self.sa = sa
70 else:
73 else:
71 self.sa = meta.Session()
74 self.sa = meta.Session()
@@ -1,276 +1,290 b''
1 """caching_query.py
1 """caching_query.py
2
2
3 Represent persistence structures which allow the usage of
3 Represent persistence structures which allow the usage of
4 Beaker caching with SQLAlchemy.
4 Beaker caching with SQLAlchemy.
5
5
6 The three new concepts introduced here are:
6 The three new concepts introduced here are:
7
7
8 * CachingQuery - a Query subclass that caches and
8 * CachingQuery - a Query subclass that caches and
9 retrieves results in/from Beaker.
9 retrieves results in/from Beaker.
10 * FromCache - a query option that establishes caching
10 * FromCache - a query option that establishes caching
11 parameters on a Query
11 parameters on a Query
12 * RelationshipCache - a variant of FromCache which is specific
12 * RelationshipCache - a variant of FromCache which is specific
13 to a query invoked during a lazy load.
13 to a query invoked during a lazy load.
14 * _params_from_query - extracts value parameters from
14 * _params_from_query - extracts value parameters from
15 a Query.
15 a Query.
16
16
17 The rest of what's here are standard SQLAlchemy and
17 The rest of what's here are standard SQLAlchemy and
18 Beaker constructs.
18 Beaker constructs.
19
19
20 """
20 """
21 import beaker
21 from beaker.exceptions import BeakerException
22 from beaker.exceptions import BeakerException
23
22 from sqlalchemy.orm.interfaces import MapperOption
24 from sqlalchemy.orm.interfaces import MapperOption
23 from sqlalchemy.orm.query import Query
25 from sqlalchemy.orm.query import Query
24 from sqlalchemy.sql import visitors
26 from sqlalchemy.sql import visitors
25 import beaker
27
26
28
27 class CachingQuery(Query):
29 class CachingQuery(Query):
28 """A Query subclass which optionally loads full results from a Beaker
30 """A Query subclass which optionally loads full results from a Beaker
29 cache region.
31 cache region.
30
32
31 The CachingQuery stores additional state that allows it to consult
33 The CachingQuery stores additional state that allows it to consult
32 a Beaker cache before accessing the database:
34 a Beaker cache before accessing the database:
33
35
34 * A "region", which is a cache region argument passed to a
36 * A "region", which is a cache region argument passed to a
35 Beaker CacheManager, specifies a particular cache configuration
37 Beaker CacheManager, specifies a particular cache configuration
36 (including backend implementation, expiration times, etc.)
38 (including backend implementation, expiration times, etc.)
37 * A "namespace", which is a qualifying name that identifies a
39 * A "namespace", which is a qualifying name that identifies a
38 group of keys within the cache. A query that filters on a name
40 group of keys within the cache. A query that filters on a name
39 might use the name "by_name", a query that filters on a date range
41 might use the name "by_name", a query that filters on a date range
40 to a joined table might use the name "related_date_range".
42 to a joined table might use the name "related_date_range".
41
43
42 When the above state is present, a Beaker cache is retrieved.
44 When the above state is present, a Beaker cache is retrieved.
43
45
44 The "namespace" name is first concatenated with
46 The "namespace" name is first concatenated with
45 a string composed of the individual entities and columns the Query
47 a string composed of the individual entities and columns the Query
46 requests, i.e. such as ``Query(User.id, User.name)``.
48 requests, i.e. such as ``Query(User.id, User.name)``.
47
49
48 The Beaker cache is then loaded from the cache manager based
50 The Beaker cache is then loaded from the cache manager based
49 on the region and composed namespace. The key within the cache
51 on the region and composed namespace. The key within the cache
50 itself is then constructed against the bind parameters specified
52 itself is then constructed against the bind parameters specified
51 by this query, which are usually literals defined in the
53 by this query, which are usually literals defined in the
52 WHERE clause.
54 WHERE clause.
53
55
54 The FromCache and RelationshipCache mapper options below represent
56 The FromCache and RelationshipCache mapper options below represent
55 the "public" method of configuring this state upon the CachingQuery.
57 the "public" method of configuring this state upon the CachingQuery.
56
58
57 """
59 """
58
60
59 def __init__(self, manager, *args, **kw):
61 def __init__(self, manager, *args, **kw):
60 self.cache_manager = manager
62 self.cache_manager = manager
61 Query.__init__(self, *args, **kw)
63 Query.__init__(self, *args, **kw)
62
64
63 def __iter__(self):
65 def __iter__(self):
64 """override __iter__ to pull results from Beaker
66 """override __iter__ to pull results from Beaker
65 if particular attributes have been configured.
67 if particular attributes have been configured.
66
68
67 Note that this approach does *not* detach the loaded objects from
69 Note that this approach does *not* detach the loaded objects from
68 the current session. If the cache backend is an in-process cache
70 the current session. If the cache backend is an in-process cache
69 (like "memory") and lives beyond the scope of the current session's
71 (like "memory") and lives beyond the scope of the current session's
70 transaction, those objects may be expired. The method here can be
72 transaction, those objects may be expired. The method here can be
71 modified to first expunge() each loaded item from the current
73 modified to first expunge() each loaded item from the current
72 session before returning the list of items, so that the items
74 session before returning the list of items, so that the items
73 in the cache are not the same ones in the current Session.
75 in the cache are not the same ones in the current Session.
74
76
75 """
77 """
76 if hasattr(self, '_cache_parameters'):
78 if hasattr(self, '_cache_parameters'):
77 return self.get_value(createfunc=lambda: list(Query.__iter__(self)))
79 return self.get_value(createfunc=lambda:
80 list(Query.__iter__(self)))
78 else:
81 else:
79 return Query.__iter__(self)
82 return Query.__iter__(self)
80
83
81 def invalidate(self):
84 def invalidate(self):
82 """Invalidate the value represented by this Query."""
85 """Invalidate the value represented by this Query."""
83
86
84 cache, cache_key = _get_cache_parameters(self)
87 cache, cache_key = _get_cache_parameters(self)
85 cache.remove(cache_key)
88 cache.remove(cache_key)
86
89
87 def get_value(self, merge=True, createfunc=None):
90 def get_value(self, merge=True, createfunc=None):
88 """Return the value from the cache for this query.
91 """Return the value from the cache for this query.
89
92
90 Raise KeyError if no value present and no
93 Raise KeyError if no value present and no
91 createfunc specified.
94 createfunc specified.
92
95
93 """
96 """
94 cache, cache_key = _get_cache_parameters(self)
97 cache, cache_key = _get_cache_parameters(self)
95 ret = cache.get_value(cache_key, createfunc=createfunc)
98 ret = cache.get_value(cache_key, createfunc=createfunc)
96 if merge:
99 if merge:
97 ret = self.merge_result(ret, load=False)
100 ret = self.merge_result(ret, load=False)
98 return ret
101 return ret
99
102
100 def set_value(self, value):
103 def set_value(self, value):
101 """Set the value in the cache for this query."""
104 """Set the value in the cache for this query."""
102
105
103 cache, cache_key = _get_cache_parameters(self)
106 cache, cache_key = _get_cache_parameters(self)
104 cache.put(cache_key, value)
107 cache.put(cache_key, value)
105
108
109
106 def query_callable(manager):
110 def query_callable(manager):
107 def query(*arg, **kw):
111 def query(*arg, **kw):
108 return CachingQuery(manager, *arg, **kw)
112 return CachingQuery(manager, *arg, **kw)
109 return query
113 return query
110
114
115
111 def get_cache_region(name, region):
116 def get_cache_region(name, region):
112 if region not in beaker.cache.cache_regions:
117 if region not in beaker.cache.cache_regions:
113 raise BeakerException('Cache region `%s` not configured '
118 raise BeakerException('Cache region `%s` not configured '
114 'Check if proper cache settings are in the .ini files' % region)
119 'Check if proper cache settings are in the .ini files' % region)
115 kw = beaker.cache.cache_regions[region]
120 kw = beaker.cache.cache_regions[region]
116 return beaker.cache.Cache._get_cache(name, kw)
121 return beaker.cache.Cache._get_cache(name, kw)
117
122
123
118 def _get_cache_parameters(query):
124 def _get_cache_parameters(query):
119 """For a query with cache_region and cache_namespace configured,
125 """For a query with cache_region and cache_namespace configured,
120 return the correspoinding Cache instance and cache key, based
126 return the correspoinding Cache instance and cache key, based
121 on this query's current criterion and parameter values.
127 on this query's current criterion and parameter values.
122
128
123 """
129 """
124 if not hasattr(query, '_cache_parameters'):
130 if not hasattr(query, '_cache_parameters'):
125 raise ValueError("This Query does not have caching parameters configured.")
131 raise ValueError("This Query does not have caching "
132 "parameters configured.")
126
133
127 region, namespace, cache_key = query._cache_parameters
134 region, namespace, cache_key = query._cache_parameters
128
135
129 namespace = _namespace_from_query(namespace, query)
136 namespace = _namespace_from_query(namespace, query)
130
137
131 if cache_key is None:
138 if cache_key is None:
132 # cache key - the value arguments from this query's parameters.
139 # cache key - the value arguments from this query's parameters.
133 args = _params_from_query(query)
140 args = _params_from_query(query)
134 cache_key = " ".join([str(x) for x in args])
141 cache_key = " ".join([str(x) for x in args])
135
142
136 # get cache
143 # get cache
137 #cache = query.cache_manager.get_cache_region(namespace, region)
144 #cache = query.cache_manager.get_cache_region(namespace, region)
138 cache = get_cache_region(namespace, region)
145 cache = get_cache_region(namespace, region)
139 # optional - hash the cache_key too for consistent length
146 # optional - hash the cache_key too for consistent length
140 # import uuid
147 # import uuid
141 # cache_key= str(uuid.uuid5(uuid.NAMESPACE_DNS, cache_key))
148 # cache_key= str(uuid.uuid5(uuid.NAMESPACE_DNS, cache_key))
142
149
143 return cache, cache_key
150 return cache, cache_key
144
151
152
145 def _namespace_from_query(namespace, query):
153 def _namespace_from_query(namespace, query):
146 # cache namespace - the token handed in by the
154 # cache namespace - the token handed in by the
147 # option + class we're querying against
155 # option + class we're querying against
148 namespace = " ".join([namespace] + [str(x) for x in query._entities])
156 namespace = " ".join([namespace] + [str(x) for x in query._entities])
149
157
150 # memcached wants this
158 # memcached wants this
151 namespace = namespace.replace(' ', '_')
159 namespace = namespace.replace(' ', '_')
152
160
153 return namespace
161 return namespace
154
162
163
155 def _set_cache_parameters(query, region, namespace, cache_key):
164 def _set_cache_parameters(query, region, namespace, cache_key):
156
165
157 if hasattr(query, '_cache_parameters'):
166 if hasattr(query, '_cache_parameters'):
158 region, namespace, cache_key = query._cache_parameters
167 region, namespace, cache_key = query._cache_parameters
159 raise ValueError("This query is already configured "
168 raise ValueError("This query is already configured "
160 "for region %r namespace %r" %
169 "for region %r namespace %r" %
161 (region, namespace)
170 (region, namespace)
162 )
171 )
163 query._cache_parameters = region, namespace, cache_key
172 query._cache_parameters = region, namespace, cache_key
164
173
174
165 class FromCache(MapperOption):
175 class FromCache(MapperOption):
166 """Specifies that a Query should load results from a cache."""
176 """Specifies that a Query should load results from a cache."""
167
177
168 propagate_to_loaders = False
178 propagate_to_loaders = False
169
179
170 def __init__(self, region, namespace, cache_key=None):
180 def __init__(self, region, namespace, cache_key=None):
171 """Construct a new FromCache.
181 """Construct a new FromCache.
172
182
173 :param region: the cache region. Should be a
183 :param region: the cache region. Should be a
174 region configured in the Beaker CacheManager.
184 region configured in the Beaker CacheManager.
175
185
176 :param namespace: the cache namespace. Should
186 :param namespace: the cache namespace. Should
177 be a name uniquely describing the target Query's
187 be a name uniquely describing the target Query's
178 lexical structure.
188 lexical structure.
179
189
180 :param cache_key: optional. A string cache key
190 :param cache_key: optional. A string cache key
181 that will serve as the key to the query. Use this
191 that will serve as the key to the query. Use this
182 if your query has a huge amount of parameters (such
192 if your query has a huge amount of parameters (such
183 as when using in_()) which correspond more simply to
193 as when using in_()) which correspond more simply to
184 some other identifier.
194 some other identifier.
185
195
186 """
196 """
187 self.region = region
197 self.region = region
188 self.namespace = namespace
198 self.namespace = namespace
189 self.cache_key = cache_key
199 self.cache_key = cache_key
190
200
191 def process_query(self, query):
201 def process_query(self, query):
192 """Process a Query during normal loading operation."""
202 """Process a Query during normal loading operation."""
193
203
194 _set_cache_parameters(query, self.region, self.namespace, self.cache_key)
204 _set_cache_parameters(query, self.region, self.namespace,
205 self.cache_key)
206
195
207
196 class RelationshipCache(MapperOption):
208 class RelationshipCache(MapperOption):
197 """Specifies that a Query as called within a "lazy load"
209 """Specifies that a Query as called within a "lazy load"
198 should load results from a cache."""
210 should load results from a cache."""
199
211
200 propagate_to_loaders = True
212 propagate_to_loaders = True
201
213
202 def __init__(self, region, namespace, attribute):
214 def __init__(self, region, namespace, attribute):
203 """Construct a new RelationshipCache.
215 """Construct a new RelationshipCache.
204
216
205 :param region: the cache region. Should be a
217 :param region: the cache region. Should be a
206 region configured in the Beaker CacheManager.
218 region configured in the Beaker CacheManager.
207
219
208 :param namespace: the cache namespace. Should
220 :param namespace: the cache namespace. Should
209 be a name uniquely describing the target Query's
221 be a name uniquely describing the target Query's
210 lexical structure.
222 lexical structure.
211
223
212 :param attribute: A Class.attribute which
224 :param attribute: A Class.attribute which
213 indicates a particular class relationship() whose
225 indicates a particular class relationship() whose
214 lazy loader should be pulled from the cache.
226 lazy loader should be pulled from the cache.
215
227
216 """
228 """
217 self.region = region
229 self.region = region
218 self.namespace = namespace
230 self.namespace = namespace
219 self._relationship_options = {
231 self._relationship_options = {
220 (attribute.property.parent.class_, attribute.property.key) : self
232 (attribute.property.parent.class_, attribute.property.key): self
221 }
233 }
222
234
223 def process_query_conditionally(self, query):
235 def process_query_conditionally(self, query):
224 """Process a Query that is used within a lazy loader.
236 """Process a Query that is used within a lazy loader.
225
237
226 (the process_query_conditionally() method is a SQLAlchemy
238 (the process_query_conditionally() method is a SQLAlchemy
227 hook invoked only within lazyload.)
239 hook invoked only within lazyload.)
228
240
229 """
241 """
230 if query._current_path:
242 if query._current_path:
231 mapper, key = query._current_path[-2:]
243 mapper, key = query._current_path[-2:]
232
244
233 for cls in mapper.class_.__mro__:
245 for cls in mapper.class_.__mro__:
234 if (cls, key) in self._relationship_options:
246 if (cls, key) in self._relationship_options:
235 relationship_option = self._relationship_options[(cls, key)]
247 relationship_option = \
248 self._relationship_options[(cls, key)]
236 _set_cache_parameters(
249 _set_cache_parameters(
237 query,
250 query,
238 relationship_option.region,
251 relationship_option.region,
239 relationship_option.namespace,
252 relationship_option.namespace,
240 None)
253 None)
241
254
242 def and_(self, option):
255 def and_(self, option):
243 """Chain another RelationshipCache option to this one.
256 """Chain another RelationshipCache option to this one.
244
257
245 While many RelationshipCache objects can be specified on a single
258 While many RelationshipCache objects can be specified on a single
246 Query separately, chaining them together allows for a more efficient
259 Query separately, chaining them together allows for a more efficient
247 lookup during load.
260 lookup during load.
248
261
249 """
262 """
250 self._relationship_options.update(option._relationship_options)
263 self._relationship_options.update(option._relationship_options)
251 return self
264 return self
252
265
253
266
254 def _params_from_query(query):
267 def _params_from_query(query):
255 """Pull the bind parameter values from a query.
268 """Pull the bind parameter values from a query.
256
269
257 This takes into account any scalar attribute bindparam set up.
270 This takes into account any scalar attribute bindparam set up.
258
271
259 E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
272 E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
260 would return [5, 7].
273 would return [5, 7].
261
274
262 """
275 """
263 v = []
276 v = []
277
264 def visit_bindparam(bind):
278 def visit_bindparam(bind):
265 value = query._params.get(bind.key, bind.value)
279 value = query._params.get(bind.key, bind.value)
266
280
267 # lazyloader may dig a callable in here, intended
281 # lazyloader may dig a callable in here, intended
268 # to late-evaluate params after autoflush is called.
282 # to late-evaluate params after autoflush is called.
269 # convert to a scalar value.
283 # convert to a scalar value.
270 if callable(value):
284 if callable(value):
271 value = value()
285 value = value()
272
286
273 v.append(value)
287 v.append(value)
274 if query._criterion is not None:
288 if query._criterion is not None:
275 visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam})
289 visitors.traverse(query._criterion, {}, {'bindparam': visit_bindparam})
276 return v
290 return v
@@ -1,456 +1,519 b''
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
193 @classmethod
194 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
195 if case_insensitive:
196 gr = Session.query(cls)\
197 .filter(cls.users_group_name.ilike(group_name))
198 else:
199 gr = Session.query(UsersGroup)\
200 .filter(UsersGroup.users_group_name == group_name)
201 if cache:
202 gr = gr.options(FromCache("sql_cache_short",
203 "get_user_%s" % group_name))
204 return gr.scalar()
205
192 class UsersGroupMember(Base):
206 class UsersGroupMember(Base):
193 __tablename__ = 'users_groups_members'
207 __tablename__ = 'users_groups_members'
194 __table_args__ = {'useexisting':True}
208 __table_args__ = {'useexisting':True}
195
209
196 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)
197 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)
198 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)
199
213
200 user = relationship('User', lazy='joined')
214 user = relationship('User', lazy='joined')
201 users_group = relationship('UsersGroup')
215 users_group = relationship('UsersGroup')
202
216
203 def __init__(self, gr_id='', u_id=''):
217 def __init__(self, gr_id='', u_id=''):
204 self.users_group_id = gr_id
218 self.users_group_id = gr_id
205 self.user_id = u_id
219 self.user_id = u_id
206
220
207 class Repository(Base):
221 class Repository(Base):
208 __tablename__ = 'repositories'
222 __tablename__ = 'repositories'
209 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
223 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
210 __mapper_args__ = {'extension':RepositoryMapper()}
224 __mapper_args__ = {'extension':RepositoryMapper()}
211
225
212 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)
213 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)
214 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)
215 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')
216 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)
217 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
231 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
218 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
232 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
219 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
233 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
220 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)
221 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)
222 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)
223
237
224
238
225 user = relationship('User')
239 user = relationship('User')
226 fork = relationship('Repository', remote_side=repo_id)
240 fork = relationship('Repository', remote_side=repo_id)
227 group = relationship('Group')
241 group = relationship('Group')
228 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')
229 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
243 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
230 stats = relationship('Statistics', cascade='all', uselist=False)
244 stats = relationship('Statistics', cascade='all', uselist=False)
231
245
232 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')
233
247
234 logs = relationship('UserLog', cascade='all')
248 logs = relationship('UserLog', cascade='all')
235
249
236 def __repr__(self):
250 def __repr__(self):
237 return "<%s('%s:%s')>" % (self.__class__.__name__,
251 return "<%s('%s:%s')>" % (self.__class__.__name__,
238 self.repo_id, self.repo_name)
252 self.repo_id, self.repo_name)
239
253
240 @classmethod
254 @classmethod
241 def by_repo_name(cls, repo_name):
255 def by_repo_name(cls, repo_name):
242 return Session.query(cls).filter(cls.repo_name == repo_name).one()
256 return Session.query(cls).filter(cls.repo_name == repo_name).one()
243
257
244 @property
258 @property
245 def just_name(self):
259 def just_name(self):
246 return self.repo_name.split(os.sep)[-1]
260 return self.repo_name.split(os.sep)[-1]
247
261
248 @property
262 @property
249 def groups_with_parents(self):
263 def groups_with_parents(self):
250 groups = []
264 groups = []
251 if self.group is None:
265 if self.group is None:
252 return groups
266 return groups
253
267
254 cur_gr = self.group
268 cur_gr = self.group
255 groups.insert(0, cur_gr)
269 groups.insert(0, cur_gr)
256 while 1:
270 while 1:
257 gr = getattr(cur_gr, 'parent_group', None)
271 gr = getattr(cur_gr, 'parent_group', None)
258 cur_gr = cur_gr.parent_group
272 cur_gr = cur_gr.parent_group
259 if gr is None:
273 if gr is None:
260 break
274 break
261 groups.insert(0, gr)
275 groups.insert(0, gr)
262
276
263 return groups
277 return groups
264
278
265 @property
279 @property
266 def groups_and_repo(self):
280 def groups_and_repo(self):
267 return self.groups_with_parents, self.just_name
281 return self.groups_with_parents, self.just_name
268
282
269
283
270 class Group(Base):
284 class Group(Base):
271 __tablename__ = 'groups'
285 __tablename__ = 'groups'
272 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
286 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
273
287
274 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)
275 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)
276 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)
277
291
278 parent_group = relationship('Group', remote_side=group_id)
292 parent_group = relationship('Group', remote_side=group_id)
279
293
280
294
281 def __init__(self, group_name='', parent_group=None):
295 def __init__(self, group_name='', parent_group=None):
282 self.group_name = group_name
296 self.group_name = group_name
283 self.parent_group = parent_group
297 self.parent_group = parent_group
284
298
285 def __repr__(self):
299 def __repr__(self):
286 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
300 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
287 self.group_name)
301 self.group_name)
288
302
289 @property
303 @property
290 def parents(self):
304 def parents(self):
291 groups = []
305 groups = []
292 if self.parent_group is None:
306 if self.parent_group is None:
293 return groups
307 return groups
294 cur_gr = self.parent_group
308 cur_gr = self.parent_group
295 groups.insert(0, cur_gr)
309 groups.insert(0, cur_gr)
296 while 1:
310 while 1:
297 gr = getattr(cur_gr, 'parent_group', None)
311 gr = getattr(cur_gr, 'parent_group', None)
298 cur_gr = cur_gr.parent_group
312 cur_gr = cur_gr.parent_group
299 if gr is None:
313 if gr is None:
300 break
314 break
301 groups.insert(0, gr)
315 groups.insert(0, gr)
302 return groups
316 return groups
303
317
304 @property
318 @property
305 def repositories(self):
319 def repositories(self):
306 return Session.query(Repository).filter(Repository.group == self).all()
320 return Session.query(Repository).filter(Repository.group == self).all()
307
321
308 class Permission(Base):
322 class Permission(Base):
309 __tablename__ = 'permissions'
323 __tablename__ = 'permissions'
310 __table_args__ = {'useexisting':True}
324 __table_args__ = {'useexisting':True}
311 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)
312 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)
313 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)
314
328
315 def __repr__(self):
329 def __repr__(self):
316 return "<%s('%s:%s')>" % (self.__class__.__name__,
330 return "<%s('%s:%s')>" % (self.__class__.__name__,
317 self.permission_id, self.permission_name)
331 self.permission_id, self.permission_name)
318
332
319 @classmethod
333 @classmethod
320 def get_by_key(cls, key):
334 def get_by_key(cls, key):
321 return Session.query(cls).filter(cls.permission_name == key).scalar()
335 return Session.query(cls).filter(cls.permission_name == key).scalar()
322
336
323 class RepoToPerm(Base):
337 class RepoToPerm(Base):
324 __tablename__ = 'repo_to_perm'
338 __tablename__ = 'repo_to_perm'
325 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
339 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
326 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)
327 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)
328 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)
329 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)
330
344
331 user = relationship('User')
345 user = relationship('User')
332 permission = relationship('Permission')
346 permission = relationship('Permission')
333 repository = relationship('Repository')
347 repository = relationship('Repository')
334
348
335 class UserToPerm(Base):
349 class UserToPerm(Base):
336 __tablename__ = 'user_to_perm'
350 __tablename__ = 'user_to_perm'
337 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
351 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
338 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)
339 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)
340 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)
341
355
342 user = relationship('User')
356 user = relationship('User')
343 permission = relationship('Permission')
357 permission = relationship('Permission')
344
358
345 @classmethod
359 @classmethod
346 def has_perm(cls, user_id, perm):
360 def has_perm(cls, user_id, perm):
347 if not isinstance(perm, Permission):
361 if not isinstance(perm, Permission):
348 raise Exception('perm needs to be an instance of Permission class')
362 raise Exception('perm needs to be an instance of Permission class')
349
363
350 return Session.query(cls).filter(cls.user_id == user_id)\
364 return Session.query(cls).filter(cls.user_id == user_id)\
351 .filter(cls.permission == perm).scalar() is not None
365 .filter(cls.permission == perm).scalar() is not None
352
366
353 @classmethod
367 @classmethod
354 def grant_perm(cls, user_id, perm):
368 def grant_perm(cls, user_id, perm):
355 if not isinstance(perm, Permission):
369 if not isinstance(perm, Permission):
356 raise Exception('perm needs to be an instance of Permission class')
370 raise Exception('perm needs to be an instance of Permission class')
357
371
358 new = cls()
372 new = cls()
359 new.user_id = user_id
373 new.user_id = user_id
360 new.permission = perm
374 new.permission = perm
361 try:
375 try:
362 Session.add(new)
376 Session.add(new)
363 Session.commit()
377 Session.commit()
364 except:
378 except:
365 Session.rollback()
379 Session.rollback()
366
380
367
381
368 @classmethod
382 @classmethod
369 def revoke_perm(cls, user_id, perm):
383 def revoke_perm(cls, user_id, perm):
370 if not isinstance(perm, Permission):
384 if not isinstance(perm, Permission):
371 raise Exception('perm needs to be an instance of Permission class')
385 raise Exception('perm needs to be an instance of Permission class')
372
386
373 try:
387 try:
374 Session.query(cls).filter(cls.user_id == user_id)\
388 Session.query(cls).filter(cls.user_id == user_id)\
375 .filter(cls.permission == perm).delete()
389 .filter(cls.permission == perm).delete()
376 Session.commit()
390 Session.commit()
377 except:
391 except:
378 Session.rollback()
392 Session.rollback()
379
393
380 class UsersGroupToPerm(Base):
394 class UsersGroupRepoToPerm(Base):
381 __tablename__ = 'users_group_to_perm'
395 __tablename__ = 'users_group_repo_to_perm'
382 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
396 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
383 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)
384 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)
385 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)
386 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)
387
401
388 users_group = relationship('UsersGroup')
402 users_group = relationship('UsersGroup')
389 permission = relationship('Permission')
403 permission = relationship('Permission')
390 repository = relationship('Repository')
404 repository = relationship('Repository')
391
405
406
407 class UsersGroupToPerm(Base):
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)
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)
412
413 users_group = relationship('UsersGroup')
414 permission = relationship('Permission')
415
416
417 @classmethod
418 def has_perm(cls, users_group_id, perm):
419 if not isinstance(perm, Permission):
420 raise Exception('perm needs to be an instance of Permission class')
421
422 return Session.query(cls).filter(cls.users_group_id ==
423 users_group_id)\
424 .filter(cls.permission == perm)\
425 .scalar() is not None
426
427 @classmethod
428 def grant_perm(cls, users_group_id, perm):
429 if not isinstance(perm, Permission):
430 raise Exception('perm needs to be an instance of Permission class')
431
432 new = cls()
433 new.users_group_id = users_group_id
434 new.permission = perm
435 try:
436 Session.add(new)
437 Session.commit()
438 except:
439 Session.rollback()
440
441
442 @classmethod
443 def revoke_perm(cls, users_group_id, perm):
444 if not isinstance(perm, Permission):
445 raise Exception('perm needs to be an instance of Permission class')
446
447 try:
448 Session.query(cls).filter(cls.users_group_id == users_group_id)\
449 .filter(cls.permission == perm).delete()
450 Session.commit()
451 except:
452 Session.rollback()
453
454
392 class GroupToPerm(Base):
455 class GroupToPerm(Base):
393 __tablename__ = 'group_to_perm'
456 __tablename__ = 'group_to_perm'
394 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
457 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
395
458
396 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)
397 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)
398 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)
399 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)
400
463
401 user = relationship('User')
464 user = relationship('User')
402 permission = relationship('Permission')
465 permission = relationship('Permission')
403 group = relationship('Group')
466 group = relationship('Group')
404
467
405 class Statistics(Base):
468 class Statistics(Base):
406 __tablename__ = 'statistics'
469 __tablename__ = 'statistics'
407 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
470 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
408 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)
409 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)
410 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
473 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
411 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
474 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
412 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
413 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
476 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
414
477
415 repository = relationship('Repository', single_parent=True)
478 repository = relationship('Repository', single_parent=True)
416
479
417 class UserFollowing(Base):
480 class UserFollowing(Base):
418 __tablename__ = 'user_followings'
481 __tablename__ = 'user_followings'
419 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
482 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
420 UniqueConstraint('user_id', 'follows_user_id')
483 UniqueConstraint('user_id', 'follows_user_id')
421 , {'useexisting':True})
484 , {'useexisting':True})
422
485
423 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)
424 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)
425 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)
426 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)
427
490
428 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
491 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
429
492
430 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
493 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
431 follows_repository = relationship('Repository', order_by='Repository.repo_name')
494 follows_repository = relationship('Repository', order_by='Repository.repo_name')
432
495
433 class CacheInvalidation(Base):
496 class CacheInvalidation(Base):
434 __tablename__ = 'cache_invalidation'
497 __tablename__ = 'cache_invalidation'
435 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
498 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
436 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
499 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
437 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
500 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
438 cache_args = Column("cache_args", 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)
439 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
502 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
440
503
441
504
442 def __init__(self, cache_key, cache_args=''):
505 def __init__(self, cache_key, cache_args=''):
443 self.cache_key = cache_key
506 self.cache_key = cache_key
444 self.cache_args = cache_args
507 self.cache_args = cache_args
445 self.cache_active = False
508 self.cache_active = False
446
509
447 def __repr__(self):
510 def __repr__(self):
448 return "<%s('%s:%s')>" % (self.__class__.__name__,
511 return "<%s('%s:%s')>" % (self.__class__.__name__,
449 self.cache_id, self.cache_key)
512 self.cache_id, self.cache_key)
450
513
451 class DbMigrateVersion(Base):
514 class DbMigrateVersion(Base):
452 __tablename__ = 'db_migrate_version'
515 __tablename__ = 'db_migrate_version'
453 __table_args__ = {'useexisting':True}
516 __table_args__ = {'useexisting':True}
454 repository_id = Column('repository_id', String(250), primary_key=True)
517 repository_id = Column('repository_id', String(250), primary_key=True)
455 repository_path = Column('repository_path', Text)
518 repository_path = Column('repository_path', Text)
456 version = Column('version', Integer)
519 version = Column('version', Integer)
@@ -1,583 +1,579 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25
25
26 import formencode
26 import formencode
27 from formencode import All
27 from formencode import All
28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 Email, Bool, StringBoolean, Set
29 Email, Bool, StringBoolean, Set
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from webhelpers.pylonslib.secure_form import authentication_token
32 from webhelpers.pylonslib.secure_form import authentication_token
33
33
34 from rhodecode.lib.utils import repo_name_slug
34 from rhodecode.lib.utils import repo_name_slug
35 from rhodecode.lib.auth import authenticate, get_crypt_password
35 from rhodecode.lib.auth import authenticate, get_crypt_password
36 from rhodecode.lib.exceptions import LdapImportError
36 from rhodecode.lib.exceptions import LdapImportError
37 from rhodecode.model import meta
37 from rhodecode.model import meta
38 from rhodecode.model.user import UserModel
38 from rhodecode.model.user import UserModel
39 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.users_group import UsersGroupModel
41 from rhodecode.model.db import User, UsersGroup
40 from rhodecode.model.db import User, UsersGroup
42 from rhodecode import BACKENDS
41 from rhodecode import BACKENDS
43
42
44 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
45
44
46 #this is needed to translate the messages using _() in validators
45 #this is needed to translate the messages using _() in validators
47 class State_obj(object):
46 class State_obj(object):
48 _ = staticmethod(_)
47 _ = staticmethod(_)
49
48
50 #===============================================================================
49 #==============================================================================
51 # VALIDATORS
50 # VALIDATORS
52 #===============================================================================
51 #==============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
52 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token':_('Token mismatch')}
53 messages = {'invalid_token':_('Token mismatch')}
55
54
56 def validate_python(self, value, state):
55 def validate_python(self, value, state):
57
56
58 if value != authentication_token():
57 if value != authentication_token():
59 raise formencode.Invalid(self.message('invalid_token', state,
58 raise formencode.Invalid(self.message('invalid_token', state,
60 search_number=value), value, state)
59 search_number=value), value, state)
61
60
62 def ValidUsername(edit, old_data):
61 def ValidUsername(edit, old_data):
63 class _ValidUsername(formencode.validators.FancyValidator):
62 class _ValidUsername(formencode.validators.FancyValidator):
64
63
65 def validate_python(self, value, state):
64 def validate_python(self, value, state):
66 if value in ['default', 'new_user']:
65 if value in ['default', 'new_user']:
67 raise formencode.Invalid(_('Invalid username'), value, state)
66 raise formencode.Invalid(_('Invalid username'), value, state)
68 #check if user is unique
67 #check if user is unique
69 old_un = None
68 old_un = None
70 if edit:
69 if edit:
71 old_un = UserModel().get(old_data.get('user_id')).username
70 old_un = UserModel().get(old_data.get('user_id')).username
72
71
73 if old_un != value or not edit:
72 if old_un != value or not edit:
74 if UserModel().get_by_username(value, cache=False,
73 if UserModel().get_by_username(value, cache=False,
75 case_insensitive=True):
74 case_insensitive=True):
76 raise formencode.Invalid(_('This username already exists') ,
75 raise formencode.Invalid(_('This username already '
77 value, state)
76 'exists') , value, state)
78
79
77
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
81 raise formencode.Invalid(_('Username may only contain '
79 raise formencode.Invalid(_('Username may only contain '
82 'alphanumeric characters underscores, '
80 'alphanumeric characters '
83 'periods or dashes and must begin with '
81 'underscores, periods or dashes '
84 'alphanumeric character'),
82 'and must begin with alphanumeric '
85 value, state)
83 'character'), value, state)
86
87
88
84
89 return _ValidUsername
85 return _ValidUsername
90
86
91
87
92
93 def ValidUsersGroup(edit, old_data):
88 def ValidUsersGroup(edit, old_data):
94
89
95 class _ValidUsersGroup(formencode.validators.FancyValidator):
90 class _ValidUsersGroup(formencode.validators.FancyValidator):
96
91
97 def validate_python(self, value, state):
92 def validate_python(self, value, state):
98 if value in ['default']:
93 if value in ['default']:
99 raise formencode.Invalid(_('Invalid group name'), value, state)
94 raise formencode.Invalid(_('Invalid group name'), value, state)
100 #check if group is unique
95 #check if group is unique
101 old_ugname = None
96 old_ugname = None
102 if edit:
97 if edit:
103 old_ugname = UsersGroupModel()\
98 old_ugname = UsersGroup.get(
104 .get(old_data.get('users_group_id')).users_group_name
99 old_data.get('users_group_id')).users_group_name
105
100
106 if old_ugname != value or not edit:
101 if old_ugname != value or not edit:
107 if UsersGroupModel().get_by_groupname(value, cache=False,
102 if UsersGroup.get_by_group_name(value, cache=False,
108 case_insensitive=True):
103 case_insensitive=True):
109 raise formencode.Invalid(_('This users group already exists') ,
104 raise formencode.Invalid(_('This users group '
110 value, state)
105 'already exists') , value,
106 state)
111
107
112
108
113 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
114 raise formencode.Invalid(_('Group name may only contain '
110 raise formencode.Invalid(_('Group name may only contain '
115 'alphanumeric characters underscores, '
111 'alphanumeric characters '
116 'periods or dashes and must begin with '
112 'underscores, periods or dashes '
117 'alphanumeric character'),
113 'and must begin with alphanumeric '
118 value, state)
114 'character'), value, state)
119
115
120 return _ValidUsersGroup
116 return _ValidUsersGroup
121
117
122
118
123
119
124 class ValidPassword(formencode.validators.FancyValidator):
120 class ValidPassword(formencode.validators.FancyValidator):
125
121
126 def to_python(self, value, state):
122 def to_python(self, value, state):
127
123
128 if value:
124 if value:
129
125
130 if value.get('password'):
126 if value.get('password'):
131 try:
127 try:
132 value['password'] = get_crypt_password(value['password'])
128 value['password'] = get_crypt_password(value['password'])
133 except UnicodeEncodeError:
129 except UnicodeEncodeError:
134 e_dict = {'password':_('Invalid characters in password')}
130 e_dict = {'password':_('Invalid characters in password')}
135 raise formencode.Invalid('', value, state, error_dict=e_dict)
131 raise formencode.Invalid('', value, state, error_dict=e_dict)
136
132
137 if value.get('password_confirmation'):
133 if value.get('password_confirmation'):
138 try:
134 try:
139 value['password_confirmation'] = \
135 value['password_confirmation'] = \
140 get_crypt_password(value['password_confirmation'])
136 get_crypt_password(value['password_confirmation'])
141 except UnicodeEncodeError:
137 except UnicodeEncodeError:
142 e_dict = {'password_confirmation':_('Invalid characters in password')}
138 e_dict = {'password_confirmation':_('Invalid characters in password')}
143 raise formencode.Invalid('', value, state, error_dict=e_dict)
139 raise formencode.Invalid('', value, state, error_dict=e_dict)
144
140
145 if value.get('new_password'):
141 if value.get('new_password'):
146 try:
142 try:
147 value['new_password'] = \
143 value['new_password'] = \
148 get_crypt_password(value['new_password'])
144 get_crypt_password(value['new_password'])
149 except UnicodeEncodeError:
145 except UnicodeEncodeError:
150 e_dict = {'new_password':_('Invalid characters in password')}
146 e_dict = {'new_password':_('Invalid characters in password')}
151 raise formencode.Invalid('', value, state, error_dict=e_dict)
147 raise formencode.Invalid('', value, state, error_dict=e_dict)
152
148
153 return value
149 return value
154
150
155 class ValidPasswordsMatch(formencode.validators.FancyValidator):
151 class ValidPasswordsMatch(formencode.validators.FancyValidator):
156
152
157 def validate_python(self, value, state):
153 def validate_python(self, value, state):
158
154
159 if value['password'] != value['password_confirmation']:
155 if value['password'] != value['password_confirmation']:
160 e_dict = {'password_confirmation':
156 e_dict = {'password_confirmation':
161 _('Password do not match')}
157 _('Password do not match')}
162 raise formencode.Invalid('', value, state, error_dict=e_dict)
158 raise formencode.Invalid('', value, state, error_dict=e_dict)
163
159
164 class ValidAuth(formencode.validators.FancyValidator):
160 class ValidAuth(formencode.validators.FancyValidator):
165 messages = {
161 messages = {
166 'invalid_password':_('invalid password'),
162 'invalid_password':_('invalid password'),
167 'invalid_login':_('invalid user name'),
163 'invalid_login':_('invalid user name'),
168 'disabled_account':_('Your account is disabled')
164 'disabled_account':_('Your account is disabled')
169
165
170 }
166 }
171 #error mapping
167 #error mapping
172 e_dict = {'username':messages['invalid_login'],
168 e_dict = {'username':messages['invalid_login'],
173 'password':messages['invalid_password']}
169 'password':messages['invalid_password']}
174 e_dict_disable = {'username':messages['disabled_account']}
170 e_dict_disable = {'username':messages['disabled_account']}
175
171
176 def validate_python(self, value, state):
172 def validate_python(self, value, state):
177 password = value['password']
173 password = value['password']
178 username = value['username']
174 username = value['username']
179 user = UserModel().get_by_username(username)
175 user = UserModel().get_by_username(username)
180
176
181 if authenticate(username, password):
177 if authenticate(username, password):
182 return value
178 return value
183 else:
179 else:
184 if user and user.active is False:
180 if user and user.active is False:
185 log.warning('user %s is disabled', username)
181 log.warning('user %s is disabled', username)
186 raise formencode.Invalid(self.message('disabled_account',
182 raise formencode.Invalid(self.message('disabled_account',
187 state=State_obj),
183 state=State_obj),
188 value, state,
184 value, state,
189 error_dict=self.e_dict_disable)
185 error_dict=self.e_dict_disable)
190 else:
186 else:
191 log.warning('user %s not authenticated', username)
187 log.warning('user %s not authenticated', username)
192 raise formencode.Invalid(self.message('invalid_password',
188 raise formencode.Invalid(self.message('invalid_password',
193 state=State_obj), value, state,
189 state=State_obj), value, state,
194 error_dict=self.e_dict)
190 error_dict=self.e_dict)
195
191
196 class ValidRepoUser(formencode.validators.FancyValidator):
192 class ValidRepoUser(formencode.validators.FancyValidator):
197
193
198 def to_python(self, value, state):
194 def to_python(self, value, state):
199 sa = meta.Session()
195 sa = meta.Session()
200 try:
196 try:
201 self.user_db = sa.query(User)\
197 self.user_db = sa.query(User)\
202 .filter(User.active == True)\
198 .filter(User.active == True)\
203 .filter(User.username == value).one()
199 .filter(User.username == value).one()
204 except Exception:
200 except Exception:
205 raise formencode.Invalid(_('This username is not valid'),
201 raise formencode.Invalid(_('This username is not valid'),
206 value, state)
202 value, state)
207 finally:
203 finally:
208 meta.Session.remove()
204 meta.Session.remove()
209
205
210 return self.user_db.user_id
206 return self.user_db.user_id
211
207
212 def ValidRepoName(edit, old_data):
208 def ValidRepoName(edit, old_data):
213 class _ValidRepoName(formencode.validators.FancyValidator):
209 class _ValidRepoName(formencode.validators.FancyValidator):
214
210
215 def to_python(self, value, state):
211 def to_python(self, value, state):
216 slug = repo_name_slug(value)
212 slug = repo_name_slug(value)
217 if slug in ['_admin']:
213 if slug in ['_admin']:
218 raise formencode.Invalid(_('This repository name is disallowed'),
214 raise formencode.Invalid(_('This repository name is disallowed'),
219 value, state)
215 value, state)
220 if old_data.get('repo_name') != value or not edit:
216 if old_data.get('repo_name') != value or not edit:
221 if RepoModel().get_by_repo_name(slug, cache=False):
217 if RepoModel().get_by_repo_name(slug, cache=False):
222 raise formencode.Invalid(_('This repository already exists') ,
218 raise formencode.Invalid(_('This repository already exists') ,
223 value, state)
219 value, state)
224 return slug
220 return slug
225
221
226
222
227 return _ValidRepoName
223 return _ValidRepoName
228
224
229 def ValidCloneUri():
225 def ValidCloneUri():
230 from mercurial.httprepo import httprepository, httpsrepository
226 from mercurial.httprepo import httprepository, httpsrepository
231 from rhodecode.lib.utils import make_ui
227 from rhodecode.lib.utils import make_ui
232
228
233 class _ValidCloneUri(formencode.validators.FancyValidator):
229 class _ValidCloneUri(formencode.validators.FancyValidator):
234 def to_python(self, value, state):
230 def to_python(self, value, state):
235 if not value:
231 if not value:
236 pass
232 pass
237 elif value.startswith('https'):
233 elif value.startswith('https'):
238 try:
234 try:
239 httpsrepository(make_ui('db'), value).capabilities()
235 httpsrepository(make_ui('db'), value).capabilities()
240 except:
236 except:
241 raise formencode.Invalid(_('invalid clone url'), value,
237 raise formencode.Invalid(_('invalid clone url'), value,
242 state)
238 state)
243 elif value.startswith('http'):
239 elif value.startswith('http'):
244 try:
240 try:
245 httprepository(make_ui('db'), value).capabilities()
241 httprepository(make_ui('db'), value).capabilities()
246 except:
242 except:
247 raise formencode.Invalid(_('invalid clone url'), value,
243 raise formencode.Invalid(_('invalid clone url'), value,
248 state)
244 state)
249 else:
245 else:
250 raise formencode.Invalid(_('Invalid clone url, provide a '
246 raise formencode.Invalid(_('Invalid clone url, provide a '
251 'valid clone http\s url'), value,
247 'valid clone http\s url'), value,
252 state)
248 state)
253
249
254 return _ValidCloneUri
250 return _ValidCloneUri
255
251
256 def ValidForkType(old_data):
252 def ValidForkType(old_data):
257 class _ValidForkType(formencode.validators.FancyValidator):
253 class _ValidForkType(formencode.validators.FancyValidator):
258
254
259 def to_python(self, value, state):
255 def to_python(self, value, state):
260 if old_data['repo_type'] != value:
256 if old_data['repo_type'] != value:
261 raise formencode.Invalid(_('Fork have to be the same '
257 raise formencode.Invalid(_('Fork have to be the same '
262 'type as original'), value, state)
258 'type as original'), value, state)
263 return value
259 return value
264 return _ValidForkType
260 return _ValidForkType
265
261
266 class ValidPerms(formencode.validators.FancyValidator):
262 class ValidPerms(formencode.validators.FancyValidator):
267 messages = {'perm_new_member_name':_('This username or users group name'
263 messages = {'perm_new_member_name':_('This username or users group name'
268 ' is not valid')}
264 ' is not valid')}
269
265
270 def to_python(self, value, state):
266 def to_python(self, value, state):
271 perms_update = []
267 perms_update = []
272 perms_new = []
268 perms_new = []
273 #build a list of permission to update and new permission to create
269 #build a list of permission to update and new permission to create
274 for k, v in value.items():
270 for k, v in value.items():
275 #means new added member to permissions
271 #means new added member to permissions
276 if k.startswith('perm_new_member'):
272 if k.startswith('perm_new_member'):
277 new_perm = value.get('perm_new_member', False)
273 new_perm = value.get('perm_new_member', False)
278 new_member = value.get('perm_new_member_name', False)
274 new_member = value.get('perm_new_member_name', False)
279 new_type = value.get('perm_new_member_type')
275 new_type = value.get('perm_new_member_type')
280
276
281 if new_member and new_perm:
277 if new_member and new_perm:
282 if (new_member, new_perm, new_type) not in perms_new:
278 if (new_member, new_perm, new_type) not in perms_new:
283 perms_new.append((new_member, new_perm, new_type))
279 perms_new.append((new_member, new_perm, new_type))
284 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
280 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
285 member = k[7:]
281 member = k[7:]
286 t = {'u':'user',
282 t = {'u':'user',
287 'g':'users_group'}[k[0]]
283 'g':'users_group'}[k[0]]
288 if member == 'default':
284 if member == 'default':
289 if value['private']:
285 if value['private']:
290 #set none for default when updating to private repo
286 #set none for default when updating to private repo
291 v = 'repository.none'
287 v = 'repository.none'
292 perms_update.append((member, v, t))
288 perms_update.append((member, v, t))
293
289
294 value['perms_updates'] = perms_update
290 value['perms_updates'] = perms_update
295 value['perms_new'] = perms_new
291 value['perms_new'] = perms_new
296
292
297 #update permissions
293 #update permissions
298 sa = meta.Session
294 sa = meta.Session
299 for k, v, t in perms_new:
295 for k, v, t in perms_new:
300 try:
296 try:
301 if t is 'user':
297 if t is 'user':
302 self.user_db = sa.query(User)\
298 self.user_db = sa.query(User)\
303 .filter(User.active == True)\
299 .filter(User.active == True)\
304 .filter(User.username == k).one()
300 .filter(User.username == k).one()
305 if t is 'users_group':
301 if t is 'users_group':
306 self.user_db = sa.query(UsersGroup)\
302 self.user_db = sa.query(UsersGroup)\
307 .filter(UsersGroup.users_group_active == True)\
303 .filter(UsersGroup.users_group_active == True)\
308 .filter(UsersGroup.users_group_name == k).one()
304 .filter(UsersGroup.users_group_name == k).one()
309
305
310 except Exception:
306 except Exception:
311 msg = self.message('perm_new_member_name',
307 msg = self.message('perm_new_member_name',
312 state=State_obj)
308 state=State_obj)
313 raise formencode.Invalid(msg, value, state,
309 raise formencode.Invalid(msg, value, state,
314 error_dict={'perm_new_member_name':msg})
310 error_dict={'perm_new_member_name':msg})
315 return value
311 return value
316
312
317 class ValidSettings(formencode.validators.FancyValidator):
313 class ValidSettings(formencode.validators.FancyValidator):
318
314
319 def to_python(self, value, state):
315 def to_python(self, value, state):
320 #settings form can't edit user
316 #settings form can't edit user
321 if value.has_key('user'):
317 if value.has_key('user'):
322 del['value']['user']
318 del['value']['user']
323
319
324 return value
320 return value
325
321
326 class ValidPath(formencode.validators.FancyValidator):
322 class ValidPath(formencode.validators.FancyValidator):
327 def to_python(self, value, state):
323 def to_python(self, value, state):
328
324
329 if not os.path.isdir(value):
325 if not os.path.isdir(value):
330 msg = _('This is not a valid path')
326 msg = _('This is not a valid path')
331 raise formencode.Invalid(msg, value, state,
327 raise formencode.Invalid(msg, value, state,
332 error_dict={'paths_root_path':msg})
328 error_dict={'paths_root_path':msg})
333 return value
329 return value
334
330
335 def UniqSystemEmail(old_data):
331 def UniqSystemEmail(old_data):
336 class _UniqSystemEmail(formencode.validators.FancyValidator):
332 class _UniqSystemEmail(formencode.validators.FancyValidator):
337 def to_python(self, value, state):
333 def to_python(self, value, state):
338 value = value.lower()
334 value = value.lower()
339 if old_data.get('email') != value:
335 if old_data.get('email') != value:
340 sa = meta.Session()
336 sa = meta.Session()
341 try:
337 try:
342 user = sa.query(User).filter(User.email == value).scalar()
338 user = sa.query(User).filter(User.email == value).scalar()
343 if user:
339 if user:
344 raise formencode.Invalid(_("This e-mail address is already taken") ,
340 raise formencode.Invalid(_("This e-mail address is already taken") ,
345 value, state)
341 value, state)
346 finally:
342 finally:
347 meta.Session.remove()
343 meta.Session.remove()
348
344
349 return value
345 return value
350
346
351 return _UniqSystemEmail
347 return _UniqSystemEmail
352
348
353 class ValidSystemEmail(formencode.validators.FancyValidator):
349 class ValidSystemEmail(formencode.validators.FancyValidator):
354 def to_python(self, value, state):
350 def to_python(self, value, state):
355 value = value.lower()
351 value = value.lower()
356 sa = meta.Session
352 sa = meta.Session
357 try:
353 try:
358 user = sa.query(User).filter(User.email == value).scalar()
354 user = sa.query(User).filter(User.email == value).scalar()
359 if user is None:
355 if user is None:
360 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
356 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
361 value, state)
357 value, state)
362 finally:
358 finally:
363 meta.Session.remove()
359 meta.Session.remove()
364
360
365 return value
361 return value
366
362
367 class LdapLibValidator(formencode.validators.FancyValidator):
363 class LdapLibValidator(formencode.validators.FancyValidator):
368
364
369 def to_python(self, value, state):
365 def to_python(self, value, state):
370
366
371 try:
367 try:
372 import ldap
368 import ldap
373 except ImportError:
369 except ImportError:
374 raise LdapImportError
370 raise LdapImportError
375 return value
371 return value
376
372
377 class AttrLoginValidator(formencode.validators.FancyValidator):
373 class AttrLoginValidator(formencode.validators.FancyValidator):
378
374
379 def to_python(self, value, state):
375 def to_python(self, value, state):
380
376
381 if not value or not isinstance(value, (str, unicode)):
377 if not value or not isinstance(value, (str, unicode)):
382 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
378 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
383 "must be specified - this is the name "
379 "must be specified - this is the name "
384 "of the attribute that is equivalent "
380 "of the attribute that is equivalent "
385 "to 'username'"),
381 "to 'username'"),
386 value, state)
382 value, state)
387
383
388 return value
384 return value
389
385
390 #===============================================================================
386 #===============================================================================
391 # FORMS
387 # FORMS
392 #===============================================================================
388 #===============================================================================
393 class LoginForm(formencode.Schema):
389 class LoginForm(formencode.Schema):
394 allow_extra_fields = True
390 allow_extra_fields = True
395 filter_extra_fields = True
391 filter_extra_fields = True
396 username = UnicodeString(
392 username = UnicodeString(
397 strip=True,
393 strip=True,
398 min=1,
394 min=1,
399 not_empty=True,
395 not_empty=True,
400 messages={
396 messages={
401 'empty':_('Please enter a login'),
397 'empty':_('Please enter a login'),
402 'tooShort':_('Enter a value %(min)i characters long or more')}
398 'tooShort':_('Enter a value %(min)i characters long or more')}
403 )
399 )
404
400
405 password = UnicodeString(
401 password = UnicodeString(
406 strip=True,
402 strip=True,
407 min=6,
403 min=6,
408 not_empty=True,
404 not_empty=True,
409 messages={
405 messages={
410 'empty':_('Please enter a password'),
406 'empty':_('Please enter a password'),
411 'tooShort':_('Enter %(min)i characters or more')}
407 'tooShort':_('Enter %(min)i characters or more')}
412 )
408 )
413
409
414
410
415 #chained validators have access to all data
411 #chained validators have access to all data
416 chained_validators = [ValidAuth]
412 chained_validators = [ValidAuth]
417
413
418 def UserForm(edit=False, old_data={}):
414 def UserForm(edit=False, old_data={}):
419 class _UserForm(formencode.Schema):
415 class _UserForm(formencode.Schema):
420 allow_extra_fields = True
416 allow_extra_fields = True
421 filter_extra_fields = True
417 filter_extra_fields = True
422 username = All(UnicodeString(strip=True, min=1, not_empty=True),
418 username = All(UnicodeString(strip=True, min=1, not_empty=True),
423 ValidUsername(edit, old_data))
419 ValidUsername(edit, old_data))
424 if edit:
420 if edit:
425 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
421 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
426 admin = StringBoolean(if_missing=False)
422 admin = StringBoolean(if_missing=False)
427 else:
423 else:
428 password = All(UnicodeString(strip=True, min=6, not_empty=True))
424 password = All(UnicodeString(strip=True, min=6, not_empty=True))
429 active = StringBoolean(if_missing=False)
425 active = StringBoolean(if_missing=False)
430 name = UnicodeString(strip=True, min=1, not_empty=True)
426 name = UnicodeString(strip=True, min=1, not_empty=True)
431 lastname = UnicodeString(strip=True, min=1, not_empty=True)
427 lastname = UnicodeString(strip=True, min=1, not_empty=True)
432 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
428 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
433
429
434 chained_validators = [ValidPassword]
430 chained_validators = [ValidPassword]
435
431
436 return _UserForm
432 return _UserForm
437
433
438
434
439 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
435 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
440 class _UsersGroupForm(formencode.Schema):
436 class _UsersGroupForm(formencode.Schema):
441 allow_extra_fields = True
437 allow_extra_fields = True
442 filter_extra_fields = True
438 filter_extra_fields = True
443
439
444 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
440 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
445 ValidUsersGroup(edit, old_data))
441 ValidUsersGroup(edit, old_data))
446
442
447 users_group_active = StringBoolean(if_missing=False)
443 users_group_active = StringBoolean(if_missing=False)
448
444
449 if edit:
445 if edit:
450 users_group_members = OneOf(available_members, hideList=False,
446 users_group_members = OneOf(available_members, hideList=False,
451 testValueList=True,
447 testValueList=True,
452 if_missing=None, not_empty=False)
448 if_missing=None, not_empty=False)
453
449
454 return _UsersGroupForm
450 return _UsersGroupForm
455
451
456 def RegisterForm(edit=False, old_data={}):
452 def RegisterForm(edit=False, old_data={}):
457 class _RegisterForm(formencode.Schema):
453 class _RegisterForm(formencode.Schema):
458 allow_extra_fields = True
454 allow_extra_fields = True
459 filter_extra_fields = True
455 filter_extra_fields = True
460 username = All(ValidUsername(edit, old_data),
456 username = All(ValidUsername(edit, old_data),
461 UnicodeString(strip=True, min=1, not_empty=True))
457 UnicodeString(strip=True, min=1, not_empty=True))
462 password = All(UnicodeString(strip=True, min=6, not_empty=True))
458 password = All(UnicodeString(strip=True, min=6, not_empty=True))
463 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
459 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
464 active = StringBoolean(if_missing=False)
460 active = StringBoolean(if_missing=False)
465 name = UnicodeString(strip=True, min=1, not_empty=True)
461 name = UnicodeString(strip=True, min=1, not_empty=True)
466 lastname = UnicodeString(strip=True, min=1, not_empty=True)
462 lastname = UnicodeString(strip=True, min=1, not_empty=True)
467 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
463 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
468
464
469 chained_validators = [ValidPasswordsMatch, ValidPassword]
465 chained_validators = [ValidPasswordsMatch, ValidPassword]
470
466
471 return _RegisterForm
467 return _RegisterForm
472
468
473 def PasswordResetForm():
469 def PasswordResetForm():
474 class _PasswordResetForm(formencode.Schema):
470 class _PasswordResetForm(formencode.Schema):
475 allow_extra_fields = True
471 allow_extra_fields = True
476 filter_extra_fields = True
472 filter_extra_fields = True
477 email = All(ValidSystemEmail(), Email(not_empty=True))
473 email = All(ValidSystemEmail(), Email(not_empty=True))
478 return _PasswordResetForm
474 return _PasswordResetForm
479
475
480 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
476 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
481 repo_groups=[]):
477 repo_groups=[]):
482 class _RepoForm(formencode.Schema):
478 class _RepoForm(formencode.Schema):
483 allow_extra_fields = True
479 allow_extra_fields = True
484 filter_extra_fields = False
480 filter_extra_fields = False
485 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
481 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
486 ValidRepoName(edit, old_data))
482 ValidRepoName(edit, old_data))
487 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
483 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
488 ValidCloneUri()())
484 ValidCloneUri()())
489 repo_group = OneOf(repo_groups, hideList=True)
485 repo_group = OneOf(repo_groups, hideList=True)
490 repo_type = OneOf(supported_backends)
486 repo_type = OneOf(supported_backends)
491 description = UnicodeString(strip=True, min=1, not_empty=True)
487 description = UnicodeString(strip=True, min=1, not_empty=True)
492 private = StringBoolean(if_missing=False)
488 private = StringBoolean(if_missing=False)
493 enable_statistics = StringBoolean(if_missing=False)
489 enable_statistics = StringBoolean(if_missing=False)
494 enable_downloads = StringBoolean(if_missing=False)
490 enable_downloads = StringBoolean(if_missing=False)
495
491
496 if edit:
492 if edit:
497 #this is repo owner
493 #this is repo owner
498 user = All(Int(not_empty=True), ValidRepoUser)
494 user = All(Int(not_empty=True), ValidRepoUser)
499
495
500 chained_validators = [ValidPerms]
496 chained_validators = [ValidPerms]
501 return _RepoForm
497 return _RepoForm
502
498
503 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
499 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
504 class _RepoForkForm(formencode.Schema):
500 class _RepoForkForm(formencode.Schema):
505 allow_extra_fields = True
501 allow_extra_fields = True
506 filter_extra_fields = False
502 filter_extra_fields = False
507 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
503 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
508 ValidRepoName(edit, old_data))
504 ValidRepoName(edit, old_data))
509 description = UnicodeString(strip=True, min=1, not_empty=True)
505 description = UnicodeString(strip=True, min=1, not_empty=True)
510 private = StringBoolean(if_missing=False)
506 private = StringBoolean(if_missing=False)
511 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
507 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
512 return _RepoForkForm
508 return _RepoForkForm
513
509
514 def RepoSettingsForm(edit=False, old_data={}):
510 def RepoSettingsForm(edit=False, old_data={}):
515 class _RepoForm(formencode.Schema):
511 class _RepoForm(formencode.Schema):
516 allow_extra_fields = True
512 allow_extra_fields = True
517 filter_extra_fields = False
513 filter_extra_fields = False
518 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
514 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
519 ValidRepoName(edit, old_data))
515 ValidRepoName(edit, old_data))
520 description = UnicodeString(strip=True, min=1, not_empty=True)
516 description = UnicodeString(strip=True, min=1, not_empty=True)
521 private = StringBoolean(if_missing=False)
517 private = StringBoolean(if_missing=False)
522
518
523 chained_validators = [ValidPerms, ValidSettings]
519 chained_validators = [ValidPerms, ValidSettings]
524 return _RepoForm
520 return _RepoForm
525
521
526
522
527 def ApplicationSettingsForm():
523 def ApplicationSettingsForm():
528 class _ApplicationSettingsForm(formencode.Schema):
524 class _ApplicationSettingsForm(formencode.Schema):
529 allow_extra_fields = True
525 allow_extra_fields = True
530 filter_extra_fields = False
526 filter_extra_fields = False
531 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
527 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
532 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
528 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
533 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
529 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
534
530
535 return _ApplicationSettingsForm
531 return _ApplicationSettingsForm
536
532
537 def ApplicationUiSettingsForm():
533 def ApplicationUiSettingsForm():
538 class _ApplicationUiSettingsForm(formencode.Schema):
534 class _ApplicationUiSettingsForm(formencode.Schema):
539 allow_extra_fields = True
535 allow_extra_fields = True
540 filter_extra_fields = False
536 filter_extra_fields = False
541 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
537 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
542 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
538 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
543 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
539 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
544 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
540 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
545 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
541 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
546 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
542 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
547
543
548 return _ApplicationUiSettingsForm
544 return _ApplicationUiSettingsForm
549
545
550 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
546 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
551 class _DefaultPermissionsForm(formencode.Schema):
547 class _DefaultPermissionsForm(formencode.Schema):
552 allow_extra_fields = True
548 allow_extra_fields = True
553 filter_extra_fields = True
549 filter_extra_fields = True
554 overwrite_default = StringBoolean(if_missing=False)
550 overwrite_default = StringBoolean(if_missing=False)
555 anonymous = OneOf(['True', 'False'], if_missing=False)
551 anonymous = OneOf(['True', 'False'], if_missing=False)
556 default_perm = OneOf(perms_choices)
552 default_perm = OneOf(perms_choices)
557 default_register = OneOf(register_choices)
553 default_register = OneOf(register_choices)
558 default_create = OneOf(create_choices)
554 default_create = OneOf(create_choices)
559
555
560 return _DefaultPermissionsForm
556 return _DefaultPermissionsForm
561
557
562
558
563 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices):
559 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices):
564 class _LdapSettingsForm(formencode.Schema):
560 class _LdapSettingsForm(formencode.Schema):
565 allow_extra_fields = True
561 allow_extra_fields = True
566 filter_extra_fields = True
562 filter_extra_fields = True
567 pre_validators = [LdapLibValidator]
563 pre_validators = [LdapLibValidator]
568 ldap_active = StringBoolean(if_missing=False)
564 ldap_active = StringBoolean(if_missing=False)
569 ldap_host = UnicodeString(strip=True,)
565 ldap_host = UnicodeString(strip=True,)
570 ldap_port = Number(strip=True,)
566 ldap_port = Number(strip=True,)
571 ldap_ldaps = StringBoolean(if_missing=False)
567 ldap_ldaps = StringBoolean(if_missing=False)
572 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
568 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
573 ldap_dn_user = UnicodeString(strip=True,)
569 ldap_dn_user = UnicodeString(strip=True,)
574 ldap_dn_pass = UnicodeString(strip=True,)
570 ldap_dn_pass = UnicodeString(strip=True,)
575 ldap_base_dn = UnicodeString(strip=True,)
571 ldap_base_dn = UnicodeString(strip=True,)
576 ldap_filter = UnicodeString(strip=True,)
572 ldap_filter = UnicodeString(strip=True,)
577 ldap_search_scope = OneOf(search_scope_choices)
573 ldap_search_scope = OneOf(search_scope_choices)
578 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
574 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
579 ldap_attr_firstname = UnicodeString(strip=True,)
575 ldap_attr_firstname = UnicodeString(strip=True,)
580 ldap_attr_lastname = UnicodeString(strip=True,)
576 ldap_attr_lastname = UnicodeString(strip=True,)
581 ldap_attr_email = UnicodeString(strip=True,)
577 ldap_attr_email = UnicodeString(strip=True,)
582
578
583 return _LdapSettingsForm
579 return _LdapSettingsForm
@@ -1,70 +1,71 b''
1 """SQLAlchemy Metadata and Session object"""
1 """SQLAlchemy Metadata and Session object"""
2 from sqlalchemy.ext.declarative import declarative_base
2 from sqlalchemy.ext.declarative import declarative_base
3 from sqlalchemy.orm import scoped_session, sessionmaker, class_mapper
3 from sqlalchemy.orm import scoped_session, sessionmaker, class_mapper
4 from beaker import cache
4 from beaker import cache
5
5
6 from rhodecode.model import caching_query
6 from rhodecode.model import caching_query
7
7
8
8
9 # Beaker CacheManager. A home base for cache configurations.
9 # Beaker CacheManager. A home base for cache configurations.
10 cache_manager = cache.CacheManager()
10 cache_manager = cache.CacheManager()
11
11
12 __all__ = ['Base', 'Session']
12 __all__ = ['Base', 'Session']
13 #
13 #
14 # SQLAlchemy session manager. Updated by model.init_model()
14 # SQLAlchemy session manager. Updated by model.init_model()
15 #
15 #
16 Session = scoped_session(
16 Session = scoped_session(
17 sessionmaker(
17 sessionmaker(
18 query_cls=caching_query.query_callable(cache_manager)
18 query_cls=caching_query.query_callable(cache_manager)
19 )
19 )
20 )
20 )
21
21
22
22 class BaseModel(object):
23 class BaseModel(object):
23 """Base Model for all classess
24 """Base Model for all classess
24
25
25 """
26 """
26
27
27 @classmethod
28 @classmethod
28 def _get_keys(cls):
29 def _get_keys(cls):
29 """return column names for this model """
30 """return column names for this model """
30 return class_mapper(cls).c.keys()
31 return class_mapper(cls).c.keys()
31
32
32 def get_dict(self):
33 def get_dict(self):
33 """return dict with keys and values corresponding
34 """return dict with keys and values corresponding
34 to this model data """
35 to this model data """
35
36
36 d = {}
37 d = {}
37 for k in self._get_keys():
38 for k in self._get_keys():
38 d[k] = getattr(self, k)
39 d[k] = getattr(self, k)
39 return d
40 return d
40
41
41 def get_appstruct(self):
42 def get_appstruct(self):
42 """return list with keys and values tupples corresponding
43 """return list with keys and values tupples corresponding
43 to this model data """
44 to this model data """
44
45
45 l = []
46 l = []
46 for k in self._get_keys():
47 for k in self._get_keys():
47 l.append((k, getattr(self, k),))
48 l.append((k, getattr(self, k),))
48 return l
49 return l
49
50
50 def populate_obj(self, populate_dict):
51 def populate_obj(self, populate_dict):
51 """populate model with data from given populate_dict"""
52 """populate model with data from given populate_dict"""
52
53
53 for k in self._get_keys():
54 for k in self._get_keys():
54 if k in populate_dict:
55 if k in populate_dict:
55 setattr(self, k, populate_dict[k])
56 setattr(self, k, populate_dict[k])
56
57
57 @classmethod
58 @classmethod
58 def query(cls):
59 def query(cls):
59 return Session.query(cls)
60 return Session.query(cls)
60
61
61 @classmethod
62 @classmethod
62 def get(cls, id_):
63 def get(cls, id_):
63 return Session.query(cls).get(id_)
64 return Session.query(cls).get(id_)
64
65
65
66
66 # The declarative Base
67 # The declarative Base
67 Base = declarative_base(cls=BaseModel)
68 Base = declarative_base(cls=BaseModel)
68
69
69 #to use cache use this in query
70 #to use cache use this in query
70 #.options(FromCache("sqlalchemy_cache_type", "cachekey"))
71 #.options(FromCache("sqlalchemy_cache_type", "cachekey"))
@@ -1,112 +1,113 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.permission
3 rhodecode.model.permission
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 permissions model for RhodeCode
6 permissions model for RhodeCode
7
7
8 :created_on: Aug 20, 2010
8 :created_on: Aug 20, 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 logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from sqlalchemy.exc import DatabaseError
29 from sqlalchemy.exc import DatabaseError
30
30
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
32 from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
33 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.caching_query import FromCache
34
34
35 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
36
36
37
37
38 class PermissionModel(BaseModel):
38 class PermissionModel(BaseModel):
39 """Permissions model for RhodeCode
39 """Permissions model for RhodeCode
40 """
40 """
41
41
42 def get_permission(self, permission_id, cache=False):
42 def get_permission(self, permission_id, cache=False):
43 """Get's permissions by id
43 """Get's permissions by id
44
44
45 :param permission_id: id of permission to get from database
45 :param permission_id: id of permission to get from database
46 :param cache: use Cache for this query
46 :param cache: use Cache for this query
47 """
47 """
48 perm = self.sa.query(Permission)
48 perm = self.sa.query(Permission)
49 if cache:
49 if cache:
50 perm = perm.options(FromCache("sql_cache_short",
50 perm = perm.options(FromCache("sql_cache_short",
51 "get_permission_%s" % permission_id))
51 "get_permission_%s" % permission_id))
52 return perm.get(permission_id)
52 return perm.get(permission_id)
53
53
54 def get_permission_by_name(self, name, cache=False):
54 def get_permission_by_name(self, name, cache=False):
55 """Get's permissions by given name
55 """Get's permissions by given name
56
56
57 :param name: name to fetch
57 :param name: name to fetch
58 :param cache: Use cache for this query
58 :param cache: Use cache for this query
59 """
59 """
60 perm = self.sa.query(Permission)\
60 perm = self.sa.query(Permission)\
61 .filter(Permission.permission_name == name)
61 .filter(Permission.permission_name == name)
62 if cache:
62 if cache:
63 perm = perm.options(FromCache("sql_cache_short",
63 perm = perm.options(FromCache("sql_cache_short",
64 "get_permission_%s" % name))
64 "get_permission_%s" % name))
65 return perm.scalar()
65 return perm.scalar()
66
66
67 def update(self, form_result):
67 def update(self, form_result):
68 perm_user = self.sa.query(User)\
68 perm_user = self.sa.query(User)\
69 .filter(User.username == form_result['perm_user_name']).scalar()
69 .filter(User.username ==
70 u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
70 form_result['perm_user_name']).scalar()
71 u2p = self.sa.query(UserToPerm).filter(UserToPerm.user ==
72 perm_user).all()
71 if len(u2p) != 3:
73 if len(u2p) != 3:
72 raise Exception('Defined: %s should be 3 permissions for default'
74 raise Exception('Defined: %s should be 3 permissions for default'
73 ' user. This should not happen please verify'
75 ' user. This should not happen please verify'
74 ' your database' % len(u2p))
76 ' your database' % len(u2p))
75
77
76 try:
78 try:
77 #stage 1 change defaults
79 #stage 1 change defaults
78 for p in u2p:
80 for p in u2p:
79 if p.permission.permission_name.startswith('repository.'):
81 if p.permission.permission_name.startswith('repository.'):
80 p.permission = self.get_permission_by_name(
82 p.permission = self.get_permission_by_name(
81 form_result['default_perm'])
83 form_result['default_perm'])
82 self.sa.add(p)
84 self.sa.add(p)
83
85
84 if p.permission.permission_name.startswith('hg.register.'):
86 if p.permission.permission_name.startswith('hg.register.'):
85 p.permission = self.get_permission_by_name(
87 p.permission = self.get_permission_by_name(
86 form_result['default_register'])
88 form_result['default_register'])
87 self.sa.add(p)
89 self.sa.add(p)
88
90
89 if p.permission.permission_name.startswith('hg.create.'):
91 if p.permission.permission_name.startswith('hg.create.'):
90 p.permission = self.get_permission_by_name(
92 p.permission = self.get_permission_by_name(
91 form_result['default_create'])
93 form_result['default_create'])
92 self.sa.add(p)
94 self.sa.add(p)
93
95
94 #stage 2 update all default permissions for repos if checked
96 #stage 2 update all default permissions for repos if checked
95 if form_result['overwrite_default'] == True:
97 if form_result['overwrite_default'] == True:
96 for r2p in self.sa.query(RepoToPerm)\
98 for r2p in self.sa.query(RepoToPerm)\
97 .filter(RepoToPerm.user == perm_user).all():
99 .filter(RepoToPerm.user == perm_user).all():
98 r2p.permission = self.get_permission_by_name(
100 r2p.permission = self.get_permission_by_name(
99 form_result['default_perm'])
101 form_result['default_perm'])
100 self.sa.add(r2p)
102 self.sa.add(r2p)
101
103
102 #stage 3 set anonymous access
104 #stage 3 set anonymous access
103 if perm_user.username == 'default':
105 if perm_user.username == 'default':
104 perm_user.active = bool(form_result['anonymous'])
106 perm_user.active = bool(form_result['anonymous'])
105 self.sa.add(perm_user)
107 self.sa.add(perm_user)
106
108
107
108 self.sa.commit()
109 self.sa.commit()
109 except (DatabaseError,):
110 except (DatabaseError,):
110 log.error(traceback.format_exc())
111 log.error(traceback.format_exc())
111 self.sa.rollback()
112 self.sa.rollback()
112 raise
113 raise
@@ -1,352 +1,349 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 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 import os
25 import os
26 import shutil
26 import shutil
27 import logging
27 import logging
28 import traceback
28 import traceback
29 from datetime import datetime
29 from datetime import datetime
30
30
31 from sqlalchemy.orm import joinedload, make_transient
31 from sqlalchemy.orm import joinedload, make_transient
32
32
33 from vcs.utils.lazy import LazyProperty
33 from vcs.utils.lazy import LazyProperty
34 from vcs.backends import get_backend
34 from vcs.backends import get_backend
35
35
36 from rhodecode.model import BaseModel
36 from rhodecode.model import BaseModel
37 from rhodecode.model.caching_query import FromCache
37 from rhodecode.model.caching_query import FromCache
38 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
38 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
39 Statistics, UsersGroup, UsersGroupToPerm, RhodeCodeUi
39 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi
40 from rhodecode.model.user import UserModel
40 from rhodecode.model.user import UserModel
41 from rhodecode.model.users_group import UsersGroupMember, UsersGroupModel
42
43
41
44 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
45
43
44
46 class RepoModel(BaseModel):
45 class RepoModel(BaseModel):
47
46
48 @LazyProperty
47 @LazyProperty
49 def repos_path(self):
48 def repos_path(self):
50 """Get's the repositories root path from database
49 """Get's the repositories root path from database
51 """
50 """
52
51
53 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
52 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
54 return q.ui_value
53 return q.ui_value
55
54
56 def get(self, repo_id, cache=False):
55 def get(self, repo_id, cache=False):
57 repo = self.sa.query(Repository)\
56 repo = self.sa.query(Repository)\
58 .filter(Repository.repo_id == repo_id)
57 .filter(Repository.repo_id == repo_id)
59
58
60 if cache:
59 if cache:
61 repo = repo.options(FromCache("sql_cache_short",
60 repo = repo.options(FromCache("sql_cache_short",
62 "get_repo_%s" % repo_id))
61 "get_repo_%s" % repo_id))
63 return repo.scalar()
62 return repo.scalar()
64
63
65
66 def get_by_repo_name(self, repo_name, cache=False):
64 def get_by_repo_name(self, repo_name, cache=False):
67 repo = self.sa.query(Repository)\
65 repo = self.sa.query(Repository)\
68 .filter(Repository.repo_name == repo_name)
66 .filter(Repository.repo_name == repo_name)
69
67
70 if cache:
68 if cache:
71 repo = repo.options(FromCache("sql_cache_short",
69 repo = repo.options(FromCache("sql_cache_short",
72 "get_repo_%s" % repo_name))
70 "get_repo_%s" % repo_name))
73 return repo.scalar()
71 return repo.scalar()
74
72
75
76 def get_full(self, repo_name, cache=False, invalidate=False):
73 def get_full(self, repo_name, cache=False, invalidate=False):
77 repo = self.sa.query(Repository)\
74 repo = self.sa.query(Repository)\
78 .options(joinedload(Repository.fork))\
75 .options(joinedload(Repository.fork))\
79 .options(joinedload(Repository.user))\
76 .options(joinedload(Repository.user))\
80 .filter(Repository.repo_name == repo_name)\
77 .filter(Repository.repo_name == repo_name)\
81
78
82 if cache:
79 if cache:
83 repo = repo.options(FromCache("sql_cache_long",
80 repo = repo.options(FromCache("sql_cache_long",
84 "get_repo_full_%s" % repo_name))
81 "get_repo_full_%s" % repo_name))
85 if invalidate and cache:
82 if invalidate and cache:
86 repo.invalidate()
83 repo.invalidate()
87
84
88 ret = repo.scalar()
85 ret = repo.scalar()
89
86
90 #make transient for sake of errors
87 #make transient for sake of errors
91 make_transient(ret)
88 make_transient(ret)
92 for k in ['fork', 'user']:
89 for k in ['fork', 'user']:
93 attr = getattr(ret, k, False)
90 attr = getattr(ret, k, False)
94 if attr:
91 if attr:
95 make_transient(attr)
92 make_transient(attr)
96 return ret
93 return ret
97
94
98
99 def get_users_js(self):
95 def get_users_js(self):
100
96
101 users = self.sa.query(User).filter(User.active == True).all()
97 users = self.sa.query(User).filter(User.active == True).all()
102 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
98 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
103 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
99 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
104 u.lastname, u.username)
100 u.lastname, u.username)
105 for u in users])
101 for u in users])
106 return users_array
102 return users_array
107
103
108
109 def get_users_groups_js(self):
104 def get_users_groups_js(self):
110 users_groups = self.sa.query(UsersGroup)\
105 users_groups = self.sa.query(UsersGroup)\
111 .filter(UsersGroup.users_group_active == True).all()
106 .filter(UsersGroup.users_group_active == True).all()
112
107
113 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
108 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
114
109
115 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
110 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
116 (gr.users_group_id, gr.users_group_name,
111 (gr.users_group_id, gr.users_group_name,
117 len(gr.members))
112 len(gr.members))
118 for gr in users_groups])
113 for gr in users_groups])
119 return users_groups_array
114 return users_groups_array
120
115
121 def update(self, repo_name, form_data):
116 def update(self, repo_name, form_data):
122 try:
117 try:
123 cur_repo = self.get_by_repo_name(repo_name, cache=False)
118 cur_repo = self.get_by_repo_name(repo_name, cache=False)
124 user_model = UserModel(self.sa)
119 user_model = UserModel(self.sa)
125 users_group_model = UsersGroupModel(self.sa)
126
120
127 #update permissions
121 #update permissions
128 for member, perm, member_type in form_data['perms_updates']:
122 for member, perm, member_type in form_data['perms_updates']:
129 if member_type == 'user':
123 if member_type == 'user':
130 r2p = self.sa.query(RepoToPerm)\
124 r2p = self.sa.query(RepoToPerm)\
131 .filter(RepoToPerm.user == user_model.get_by_username(member))\
125 .filter(RepoToPerm.user == user_model.
126 get_by_username(member))\
132 .filter(RepoToPerm.repository == cur_repo)\
127 .filter(RepoToPerm.repository == cur_repo)\
133 .one()
128 .one()
134
129
135 r2p.permission = self.sa.query(Permission)\
130 r2p.permission = self.sa.query(Permission)\
136 .filter(Permission.permission_name == perm)\
131 .filter(Permission.permission_name ==
137 .scalar()
132 perm).scalar()
138 self.sa.add(r2p)
133 self.sa.add(r2p)
139 else:
134 else:
140 g2p = self.sa.query(UsersGroupToPerm)\
135 g2p = self.sa.query(UsersGroupRepoToPerm)\
141 .filter(UsersGroupToPerm.users_group == users_group_model.get_by_groupname(member))\
136 .filter(UsersGroupRepoToPerm.users_group ==
142 .filter(UsersGroupToPerm.repository == cur_repo)\
137 UsersGroup.get_by_group_name(member))\
143 .one()
138 .filter(UsersGroupRepoToPerm.repository ==
139 cur_repo).one()
144
140
145 g2p.permission = self.sa.query(Permission)\
141 g2p.permission = self.sa.query(Permission)\
146 .filter(Permission.permission_name == perm)\
142 .filter(Permission.permission_name ==
147 .scalar()
143 perm).scalar()
148 self.sa.add(g2p)
144 self.sa.add(g2p)
149
145
150 #set new permissions
146 #set new permissions
151 for member, perm, member_type in form_data['perms_new']:
147 for member, perm, member_type in form_data['perms_new']:
152 if member_type == 'user':
148 if member_type == 'user':
153 r2p = RepoToPerm()
149 r2p = RepoToPerm()
154 r2p.repository = cur_repo
150 r2p.repository = cur_repo
155 r2p.user = user_model.get_by_username(member)
151 r2p.user = user_model.get_by_username(member)
156
152
157 r2p.permission = self.sa.query(Permission)\
153 r2p.permission = self.sa.query(Permission)\
158 .filter(Permission.permission_name == perm)\
154 .filter(Permission.
159 .scalar()
155 permission_name == perm)\
156 .scalar()
160 self.sa.add(r2p)
157 self.sa.add(r2p)
161 else:
158 else:
162 g2p = UsersGroupToPerm()
159 g2p = UsersGroupRepoToPerm()
163 g2p.repository = cur_repo
160 g2p.repository = cur_repo
164 g2p.users_group = users_group_model.get_by_groupname(member)
161 g2p.users_group = UsersGroup.get_by_group_name(member)
165
162
166 g2p.permission = self.sa.query(Permission)\
163 g2p.permission = self.sa.query(Permission)\
167 .filter(Permission.permission_name == perm)\
164 .filter(Permission.
168 .scalar()
165 permission_name == perm)\
166 .scalar()
169 self.sa.add(g2p)
167 self.sa.add(g2p)
170
168
171 #update current repo
169 #update current repo
172 for k, v in form_data.items():
170 for k, v in form_data.items():
173 if k == 'user':
171 if k == 'user':
174 cur_repo.user = user_model.get(v)
172 cur_repo.user = user_model.get(v)
175 else:
173 else:
176 setattr(cur_repo, k, v)
174 setattr(cur_repo, k, v)
177
175
178 self.sa.add(cur_repo)
176 self.sa.add(cur_repo)
179
177
180 if repo_name != form_data['repo_name']:
178 if repo_name != form_data['repo_name']:
181 #rename our data
179 #rename our data
182 self.__rename_repo(repo_name, form_data['repo_name'])
180 self.__rename_repo(repo_name, form_data['repo_name'])
183
181
184 self.sa.commit()
182 self.sa.commit()
185 except:
183 except:
186 log.error(traceback.format_exc())
184 log.error(traceback.format_exc())
187 self.sa.rollback()
185 self.sa.rollback()
188 raise
186 raise
189
187
190 def create(self, form_data, cur_user, just_db=False, fork=False):
188 def create(self, form_data, cur_user, just_db=False, fork=False):
191 try:
189 try:
192 if fork:
190 if fork:
193 #force str since hg doesn't go with unicode
191 #force str since hg doesn't go with unicode
194 repo_name = str(form_data['fork_name'])
192 repo_name = str(form_data['fork_name'])
195 org_name = str(form_data['repo_name'])
193 org_name = str(form_data['repo_name'])
196
194
197 else:
195 else:
198 org_name = repo_name = str(form_data['repo_name'])
196 org_name = repo_name = str(form_data['repo_name'])
199 new_repo = Repository()
197 new_repo = Repository()
200 new_repo.enable_statistics = False
198 new_repo.enable_statistics = False
201 for k, v in form_data.items():
199 for k, v in form_data.items():
202 if k == 'repo_name':
200 if k == 'repo_name':
203 v = repo_name
201 v = repo_name
204 setattr(new_repo, k, v)
202 setattr(new_repo, k, v)
205
203
206 if fork:
204 if fork:
207 parent_repo = self.sa.query(Repository)\
205 parent_repo = self.sa.query(Repository)\
208 .filter(Repository.repo_name == org_name).scalar()
206 .filter(Repository.repo_name == org_name).scalar()
209 new_repo.fork = parent_repo
207 new_repo.fork = parent_repo
210
208
211 new_repo.user_id = cur_user.user_id
209 new_repo.user_id = cur_user.user_id
212 self.sa.add(new_repo)
210 self.sa.add(new_repo)
213
211
214 #create default permission
212 #create default permission
215 repo_to_perm = RepoToPerm()
213 repo_to_perm = RepoToPerm()
216 default = 'repository.read'
214 default = 'repository.read'
217 for p in UserModel(self.sa).get_by_username('default',
215 for p in UserModel(self.sa).get_by_username('default',
218 cache=False).user_perms:
216 cache=False).user_perms:
219 if p.permission.permission_name.startswith('repository.'):
217 if p.permission.permission_name.startswith('repository.'):
220 default = p.permission.permission_name
218 default = p.permission.permission_name
221 break
219 break
222
220
223 default_perm = 'repository.none' if form_data['private'] else default
221 default_perm = 'repository.none' if form_data['private'] else default
224
222
225 repo_to_perm.permission_id = self.sa.query(Permission)\
223 repo_to_perm.permission_id = self.sa.query(Permission)\
226 .filter(Permission.permission_name == default_perm)\
224 .filter(Permission.permission_name == default_perm)\
227 .one().permission_id
225 .one().permission_id
228
226
229 repo_to_perm.repository = new_repo
227 repo_to_perm.repository = new_repo
230 repo_to_perm.user_id = UserModel(self.sa)\
228 repo_to_perm.user_id = UserModel(self.sa)\
231 .get_by_username('default', cache=False).user_id
229 .get_by_username('default', cache=False).user_id
232
230
233 self.sa.add(repo_to_perm)
231 self.sa.add(repo_to_perm)
234
232
235 if not just_db:
233 if not just_db:
236 self.__create_repo(repo_name, form_data['repo_type'],
234 self.__create_repo(repo_name, form_data['repo_type'],
237 form_data['clone_uri'])
235 form_data['clone_uri'])
238
236
239 self.sa.commit()
237 self.sa.commit()
240
238
241 #now automatically start following this repository as owner
239 #now automatically start following this repository as owner
242 from rhodecode.model.scm import ScmModel
240 from rhodecode.model.scm import ScmModel
243 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
241 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
244 cur_user.user_id)
242 cur_user.user_id)
245
243
246 except:
244 except:
247 log.error(traceback.format_exc())
245 log.error(traceback.format_exc())
248 self.sa.rollback()
246 self.sa.rollback()
249 raise
247 raise
250
248
251 def create_fork(self, form_data, cur_user):
249 def create_fork(self, form_data, cur_user):
252 from rhodecode.lib.celerylib import tasks, run_task
250 from rhodecode.lib.celerylib import tasks, run_task
253 run_task(tasks.create_repo_fork, form_data, cur_user)
251 run_task(tasks.create_repo_fork, form_data, cur_user)
254
252
255 def delete(self, repo):
253 def delete(self, repo):
256 try:
254 try:
257 self.sa.delete(repo)
255 self.sa.delete(repo)
258 self.__delete_repo(repo)
256 self.__delete_repo(repo)
259 self.sa.commit()
257 self.sa.commit()
260 except:
258 except:
261 log.error(traceback.format_exc())
259 log.error(traceback.format_exc())
262 self.sa.rollback()
260 self.sa.rollback()
263 raise
261 raise
264
262
265 def delete_perm_user(self, form_data, repo_name):
263 def delete_perm_user(self, form_data, repo_name):
266 try:
264 try:
267 self.sa.query(RepoToPerm)\
265 self.sa.query(RepoToPerm)\
268 .filter(RepoToPerm.repository \
266 .filter(RepoToPerm.repository \
269 == self.get_by_repo_name(repo_name))\
267 == self.get_by_repo_name(repo_name))\
270 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
268 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
271 self.sa.commit()
269 self.sa.commit()
272 except:
270 except:
273 log.error(traceback.format_exc())
271 log.error(traceback.format_exc())
274 self.sa.rollback()
272 self.sa.rollback()
275 raise
273 raise
276
274
277 def delete_perm_users_group(self, form_data, repo_name):
275 def delete_perm_users_group(self, form_data, repo_name):
278 try:
276 try:
279 self.sa.query(UsersGroupToPerm)\
277 self.sa.query(UsersGroupRepoToPerm)\
280 .filter(UsersGroupToPerm.repository \
278 .filter(UsersGroupRepoToPerm.repository \
281 == self.get_by_repo_name(repo_name))\
279 == self.get_by_repo_name(repo_name))\
282 .filter(UsersGroupToPerm.users_group_id \
280 .filter(UsersGroupRepoToPerm.users_group_id \
283 == form_data['users_group_id']).delete()
281 == form_data['users_group_id']).delete()
284 self.sa.commit()
282 self.sa.commit()
285 except:
283 except:
286 log.error(traceback.format_exc())
284 log.error(traceback.format_exc())
287 self.sa.rollback()
285 self.sa.rollback()
288 raise
286 raise
289
287
290 def delete_stats(self, repo_name):
288 def delete_stats(self, repo_name):
291 try:
289 try:
292 self.sa.query(Statistics)\
290 self.sa.query(Statistics)\
293 .filter(Statistics.repository == \
291 .filter(Statistics.repository == \
294 self.get_by_repo_name(repo_name)).delete()
292 self.get_by_repo_name(repo_name)).delete()
295 self.sa.commit()
293 self.sa.commit()
296 except:
294 except:
297 log.error(traceback.format_exc())
295 log.error(traceback.format_exc())
298 self.sa.rollback()
296 self.sa.rollback()
299 raise
297 raise
300
298
301
302 def __create_repo(self, repo_name, alias, clone_uri=False):
299 def __create_repo(self, repo_name, alias, clone_uri=False):
303 """
300 """
304 makes repository on filesystem
301 makes repository on filesystem
305
302
306 :param repo_name:
303 :param repo_name:
307 :param alias:
304 :param alias:
308 """
305 """
309 from rhodecode.lib.utils import check_repo
306 from rhodecode.lib.utils import check_repo
310 repo_path = os.path.join(self.repos_path, repo_name)
307 repo_path = os.path.join(self.repos_path, repo_name)
311 if check_repo(repo_name, self.repos_path):
308 if check_repo(repo_name, self.repos_path):
312 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
309 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
313 clone_uri)
310 clone_uri)
314 backend = get_backend(alias)
311 backend = get_backend(alias)
315 backend(repo_path, create=True, src_url=clone_uri)
312 backend(repo_path, create=True, src_url=clone_uri)
316
313
317 def __rename_repo(self, old, new):
314 def __rename_repo(self, old, new):
318 """
315 """
319 renames repository on filesystem
316 renames repository on filesystem
320
317
321 :param old: old name
318 :param old: old name
322 :param new: new name
319 :param new: new name
323 """
320 """
324 log.info('renaming repo from %s to %s', old, new)
321 log.info('renaming repo from %s to %s', old, new)
325
322
326 old_path = os.path.join(self.repos_path, old)
323 old_path = os.path.join(self.repos_path, old)
327 new_path = os.path.join(self.repos_path, new)
324 new_path = os.path.join(self.repos_path, new)
328 if os.path.isdir(new_path):
325 if os.path.isdir(new_path):
329 raise Exception('Was trying to rename to already existing dir %s',
326 raise Exception('Was trying to rename to already existing dir %s',
330 new_path)
327 new_path)
331 shutil.move(old_path, new_path)
328 shutil.move(old_path, new_path)
332
329
333 def __delete_repo(self, repo):
330 def __delete_repo(self, repo):
334 """
331 """
335 removes repo from filesystem, the removal is acctually made by
332 removes repo from filesystem, the removal is acctually made by
336 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
333 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
337 repository is no longer valid for rhodecode, can be undeleted later on
334 repository is no longer valid for rhodecode, can be undeleted later on
338 by reverting the renames on this repository
335 by reverting the renames on this repository
339
336
340 :param repo: repo object
337 :param repo: repo object
341 """
338 """
342 rm_path = os.path.join(self.repos_path, repo.repo_name)
339 rm_path = os.path.join(self.repos_path, repo.repo_name)
343 log.info("Removing %s", rm_path)
340 log.info("Removing %s", rm_path)
344 #disable hg/git
341 #disable hg/git
345 alias = repo.repo_type
342 alias = repo.repo_type
346 shutil.move(os.path.join(rm_path, '.%s' % alias),
343 shutil.move(os.path.join(rm_path, '.%s' % alias),
347 os.path.join(rm_path, 'rm__.%s' % alias))
344 os.path.join(rm_path, 'rm__.%s' % alias))
348 #disable repo
345 #disable repo
349 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
346 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
350 % (datetime.today()\
347 % (datetime.today()\
351 .strftime('%Y%m%d_%H%M%S_%f'),
348 .strftime('%Y%m%d_%H%M%S_%f'),
352 repo.repo_name)))
349 repo.repo_name)))
@@ -1,109 +1,93 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user_group
3 rhodecode.model.user_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 users groups model for RhodeCode
6 users groups model for RhodeCode
7
7
8 :created_on: Jan 25, 2011
8 :created_on: Jan 25, 2011
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 logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.caching_query import FromCache
32 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.db import UsersGroup, UsersGroupMember
33 from rhodecode.model.db import UsersGroup, UsersGroupMember
34
34
35 from sqlalchemy.exc import DatabaseError
36
37 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
38
36
39
37
40 class UsersGroupModel(BaseModel):
38 class UsersGroupModel(BaseModel):
41
39
42 def get(self, users_group_id, cache=False):
40 def get(self, users_group_id, cache=False):
43 users_group = self.sa.query(UsersGroup)
41 users_group = self.sa.query(UsersGroup)
44 if cache:
42 if cache:
45 users_group = users_group.options(FromCache("sql_cache_short",
43 users_group = users_group.options(FromCache("sql_cache_short",
46 "get_users_group_%s" % users_group_id))
44 "get_users_group_%s" % users_group_id))
47 return users_group.get(users_group_id)
45 return users_group.get(users_group_id)
48
46
49
50 def get_by_groupname(self, users_group_name, cache=False,
51 case_insensitive=False):
52
53 if case_insensitive:
54 user = self.sa.query(UsersGroup)\
55 .filter(UsersGroup.users_group_name.ilike(users_group_name))
56 else:
57 user = self.sa.query(UsersGroup)\
58 .filter(UsersGroup.users_group_name == users_group_name)
59 if cache:
60 user = user.options(FromCache("sql_cache_short",
61 "get_user_%s" % users_group_name))
62 return user.scalar()
63
64 def create(self, form_data):
47 def create(self, form_data):
65 try:
48 try:
66 new_users_group = UsersGroup()
49 new_users_group = UsersGroup()
67 for k, v in form_data.items():
50 for k, v in form_data.items():
68 setattr(new_users_group, k, v)
51 setattr(new_users_group, k, v)
69
52
70 self.sa.add(new_users_group)
53 self.sa.add(new_users_group)
71 self.sa.commit()
54 self.sa.commit()
72 except:
55 except:
73 log.error(traceback.format_exc())
56 log.error(traceback.format_exc())
74 self.sa.rollback()
57 self.sa.rollback()
75 raise
58 raise
76
59
77 def update(self, users_group_id, form_data):
60 def update(self, users_group_id, form_data):
78
61
79 try:
62 try:
80 users_group = self.get(users_group_id, cache=False)
63 users_group = self.get(users_group_id, cache=False)
81
64
82 for k, v in form_data.items():
65 for k, v in form_data.items():
83 if k == 'users_group_members':
66 if k == 'users_group_members':
84 users_group.members = []
67 users_group.members = []
85 self.sa.flush()
68 self.sa.flush()
86 members_list = []
69 members_list = []
87 if v:
70 if v:
88 for u_id in set(v):
71 for u_id in set(v):
89 members_list.append(UsersGroupMember(users_group_id,
72 members_list.append(UsersGroupMember(
90 u_id))
73 users_group_id,
74 u_id))
91 setattr(users_group, 'members', members_list)
75 setattr(users_group, 'members', members_list)
92 setattr(users_group, k, v)
76 setattr(users_group, k, v)
93
77
94 self.sa.add(users_group)
78 self.sa.add(users_group)
95 self.sa.commit()
79 self.sa.commit()
96 except:
80 except:
97 log.error(traceback.format_exc())
81 log.error(traceback.format_exc())
98 self.sa.rollback()
82 self.sa.rollback()
99 raise
83 raise
100
84
101 def delete(self, users_group_id):
85 def delete(self, users_group_id):
102 try:
86 try:
103 users_group = self.get(users_group_id, cache=False)
87 users_group = self.get(users_group_id, cache=False)
104 self.sa.delete(users_group)
88 self.sa.delete(users_group)
105 self.sa.commit()
89 self.sa.commit()
106 except:
90 except:
107 log.error(traceback.format_exc())
91 log.error(traceback.format_exc())
108 self.sa.rollback()
92 self.sa.rollback()
109 raise
93 raise
@@ -1,270 +1,270 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Edit users group')} ${c.users_group.users_group_name} - ${c.rhodecode_name}
5 ${_('Edit users group')} ${c.users_group.users_group_name} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(_('UsersGroups'),h.url('users_groups'))}
11 ${h.link_to(_('UsersGroups'),h.url('users_groups'))}
12 &raquo;
12 &raquo;
13 ${_('edit')} "${c.users_group.users_group_name}"
13 ${_('edit')} "${c.users_group.users_group_name}"
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box box-left">
21 <div class="box box-left">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 <!-- end box / title -->
26 <!-- end box / title -->
27 ${h.form(url('users_group', id=c.users_group.users_group_id),method='put', id='edit_users_group')}
27 ${h.form(url('users_group', id=c.users_group.users_group_id),method='put', id='edit_users_group')}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30 <div class="fields">
30 <div class="fields">
31 <div class="field">
31 <div class="field">
32 <div class="label">
32 <div class="label">
33 <label for="users_group_name">${_('Group name')}:</label>
33 <label for="users_group_name">${_('Group name')}:</label>
34 </div>
34 </div>
35 <div class="input">
35 <div class="input">
36 ${h.text('users_group_name',class_='small')}
36 ${h.text('users_group_name',class_='small')}
37 </div>
37 </div>
38 </div>
38 </div>
39
39
40 <div class="field">
40 <div class="field">
41 <div class="label label-checkbox">
41 <div class="label label-checkbox">
42 <label for="users_group_active">${_('Active')}:</label>
42 <label for="users_group_active">${_('Active')}:</label>
43 </div>
43 </div>
44 <div class="checkboxes">
44 <div class="checkboxes">
45 ${h.checkbox('users_group_active',value=True)}
45 ${h.checkbox('users_group_active',value=True)}
46 </div>
46 </div>
47 </div>
47 </div>
48 <div class="field">
48 <div class="field">
49 <div class="label">
49 <div class="label">
50 <label for="users_group_active">${_('Members')}:</label>
50 <label for="users_group_active">${_('Members')}:</label>
51 </div>
51 </div>
52 <div class="select">
52 <div class="select">
53 <table>
53 <table>
54 <tr>
54 <tr>
55 <td>
55 <td>
56 <div>
56 <div>
57 <div style="float:left">
57 <div style="float:left">
58 <div class="text" style="padding: 0px 0px 6px;">${_('Choosen group members')}</div>
58 <div class="text" style="padding: 0px 0px 6px;">${_('Choosen group members')}</div>
59 ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")}
59 ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")}
60 <div id="remove_all_elements" style="cursor:pointer;text-align:center">
60 <div id="remove_all_elements" style="cursor:pointer;text-align:center">
61 ${_('Remove all elements')}
61 ${_('Remove all elements')}
62 <img alt="remove" style="vertical-align:text-bottom" src="${h.url("/images/icons/arrow_right.png")}"/>
62 <img alt="remove" style="vertical-align:text-bottom" src="${h.url("/images/icons/arrow_right.png")}"/>
63 </div>
63 </div>
64 </div>
64 </div>
65 <div style="float:left;width:20px;padding-top:50px">
65 <div style="float:left;width:20px;padding-top:50px">
66 <img alt="add" id="add_element"
66 <img alt="add" id="add_element"
67 style="padding:2px;cursor:pointer"
67 style="padding:2px;cursor:pointer"
68 src="${h.url("/images/icons/arrow_left.png")}"/>
68 src="${h.url("/images/icons/arrow_left.png")}"/>
69 <br />
69 <br />
70 <img alt="remove" id="remove_element"
70 <img alt="remove" id="remove_element"
71 style="padding:2px;cursor:pointer"
71 style="padding:2px;cursor:pointer"
72 src="${h.url("/images/icons/arrow_right.png")}"/>
72 src="${h.url("/images/icons/arrow_right.png")}"/>
73 </div>
73 </div>
74 <div style="float:left">
74 <div style="float:left">
75 <div class="text" style="padding: 0px 0px 6px;">${_('Available members')}</div>
75 <div class="text" style="padding: 0px 0px 6px;">${_('Available members')}</div>
76 ${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")}
76 ${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")}
77 <div id="add_all_elements" style="cursor:pointer;text-align:center">
77 <div id="add_all_elements" style="cursor:pointer;text-align:center">
78 <img alt="add" style="vertical-align:text-bottom" src="${h.url("/images/icons/arrow_left.png")}"/>
78 <img alt="add" style="vertical-align:text-bottom" src="${h.url("/images/icons/arrow_left.png")}"/>
79 ${_('Add all elements')}
79 ${_('Add all elements')}
80 </div>
80 </div>
81 </div>
81 </div>
82 </div>
82 </div>
83 </td>
83 </td>
84 </tr>
84 </tr>
85 </table>
85 </table>
86 </div>
86 </div>
87
87
88 </div>
88 </div>
89 <div class="buttons">
89 <div class="buttons">
90 ${h.submit('save','save',class_="ui-button")}
90 ${h.submit('save','save',class_="ui-button")}
91 </div>
91 </div>
92 </div>
92 </div>
93 </div>
93 </div>
94 ${h.end_form()}
94 ${h.end_form()}
95 </div>
95 </div>
96
96
97 <script type="text/javascript">
97 <script type="text/javascript">
98 YAHOO.util.Event.onDOMReady(function(){
98 YAHOO.util.Event.onDOMReady(function(){
99 var D = YAHOO.util.Dom;
99 var D = YAHOO.util.Dom;
100 var E = YAHOO.util.Event;
100 var E = YAHOO.util.Event;
101
101
102 //definition of containers ID's
102 //definition of containers ID's
103 var available_container = 'available_members';
103 var available_container = 'available_members';
104 var selected_container = 'users_group_members';
104 var selected_container = 'users_group_members';
105
105
106 //form containing containers id
106 //form containing containers id
107 var form_id = 'edit_users_group';
107 var form_id = 'edit_users_group';
108
108
109 //temp container for selected storage.
109 //temp container for selected storage.
110 var cache = new Array();
110 var cache = new Array();
111 var av_cache = new Array();
111 var av_cache = new Array();
112 var c = D.get(selected_container);
112 var c = D.get(selected_container);
113 var ac = D.get(available_container);
113 var ac = D.get(available_container);
114
114
115 //get only selected options for further fullfilment
115 //get only selected options for further fullfilment
116 for(var i = 0;node =c.options[i];i++){
116 for(var i = 0;node =c.options[i];i++){
117 if(node.selected){
117 if(node.selected){
118 //push selected to my temp storage left overs :)
118 //push selected to my temp storage left overs :)
119 cache.push(node);
119 cache.push(node);
120 }
120 }
121 }
121 }
122
122
123 //clear 'selected' select
123 //clear 'selected' select
124 //c.options.length = 0;
124 //c.options.length = 0;
125
125
126 //fill it with remembered options
126 //fill it with remembered options
127 //for(var i = 0;node = cache[i];i++){
127 //for(var i = 0;node = cache[i];i++){
128 // c.options[i]=new Option(node.text, node.value, false, false);
128 // c.options[i]=new Option(node.text, node.value, false, false);
129 //}
129 //}
130
130
131
131
132 //get all available options to cache
132 //get all available options to cache
133 for(var i = 0;node =ac.options[i];i++){
133 for(var i = 0;node =ac.options[i];i++){
134 //push selected to my temp storage left overs :)
134 //push selected to my temp storage left overs :)
135 av_cache.push(node);
135 av_cache.push(node);
136 }
136 }
137
137
138 //fill available only with those not in choosen
138 //fill available only with those not in choosen
139 ac.options.length=0;
139 ac.options.length=0;
140 tmp_cache = new Array();
140 tmp_cache = new Array();
141
141
142 for(var i = 0;node = av_cache[i];i++){
142 for(var i = 0;node = av_cache[i];i++){
143 var add = true;
143 var add = true;
144 for(var i2 = 0;node_2 = cache[i2];i2++){
144 for(var i2 = 0;node_2 = cache[i2];i2++){
145 if(node.value == node_2.value){
145 if(node.value == node_2.value){
146 add=false;
146 add=false;
147 break;
147 break;
148 }
148 }
149 }
149 }
150 if(add){
150 if(add){
151 tmp_cache.push(new Option(node.text, node.value, false, false));
151 tmp_cache.push(new Option(node.text, node.value, false, false));
152 }
152 }
153 }
153 }
154
154
155 for(var i = 0;node = tmp_cache[i];i++){
155 for(var i = 0;node = tmp_cache[i];i++){
156 ac.options[i] = node;
156 ac.options[i] = node;
157 }
157 }
158
158
159 function prompts_action_callback(e){
159 function prompts_action_callback(e){
160
160
161 var choosen = D.get(selected_container);
161 var choosen = D.get(selected_container);
162 var available = D.get(available_container);
162 var available = D.get(available_container);
163
163
164 //get checked and unchecked options from field
164 //get checked and unchecked options from field
165 function get_checked(from_field){
165 function get_checked(from_field){
166 //temp container for storage.
166 //temp container for storage.
167 var sel_cache = new Array();
167 var sel_cache = new Array();
168 var oth_cache = new Array();
168 var oth_cache = new Array();
169
169
170 for(var i = 0;node = from_field.options[i];i++){
170 for(var i = 0;node = from_field.options[i];i++){
171 if(node.selected){
171 if(node.selected){
172 //push selected fields :)
172 //push selected fields :)
173 sel_cache.push(node);
173 sel_cache.push(node);
174 }
174 }
175 else{
175 else{
176 oth_cache.push(node)
176 oth_cache.push(node)
177 }
177 }
178 }
178 }
179
179
180 return [sel_cache,oth_cache]
180 return [sel_cache,oth_cache]
181 }
181 }
182
182
183 //fill the field with given options
183 //fill the field with given options
184 function fill_with(field,options){
184 function fill_with(field,options){
185 //clear firtst
185 //clear firtst
186 field.options.length=0;
186 field.options.length=0;
187 for(var i = 0;node = options[i];i++){
187 for(var i = 0;node = options[i];i++){
188 field.options[i]=new Option(node.text, node.value,
188 field.options[i]=new Option(node.text, node.value,
189 false, false);
189 false, false);
190 }
190 }
191
191
192 }
192 }
193 //adds to current field
193 //adds to current field
194 function add_to(field,options){
194 function add_to(field,options){
195 for(var i = 0;node = options[i];i++){
195 for(var i = 0;node = options[i];i++){
196 field.appendChild(new Option(node.text, node.value,
196 field.appendChild(new Option(node.text, node.value,
197 false, false));
197 false, false));
198 }
198 }
199 }
199 }
200
200
201 // add action
201 // add action
202 if (this.id=='add_element'){
202 if (this.id=='add_element'){
203 var c = get_checked(available);
203 var c = get_checked(available);
204 add_to(choosen,c[0]);
204 add_to(choosen,c[0]);
205 fill_with(available,c[1]);
205 fill_with(available,c[1]);
206 }
206 }
207 // remove action
207 // remove action
208 if (this.id=='remove_element'){
208 if (this.id=='remove_element'){
209 var c = get_checked(choosen);
209 var c = get_checked(choosen);
210 add_to(available,c[0]);
210 add_to(available,c[0]);
211 fill_with(choosen,c[1]);
211 fill_with(choosen,c[1]);
212 }
212 }
213 // add all elements
213 // add all elements
214 if(this.id=='add_all_elements'){
214 if(this.id=='add_all_elements'){
215 for(var i=0; node = available.options[i];i++){
215 for(var i=0; node = available.options[i];i++){
216 choosen.appendChild(new Option(node.text,
216 choosen.appendChild(new Option(node.text,
217 node.value, false, false));
217 node.value, false, false));
218 }
218 }
219 available.options.length = 0;
219 available.options.length = 0;
220 }
220 }
221 //remove all elements
221 //remove all elements
222 if(this.id=='remove_all_elements'){
222 if(this.id=='remove_all_elements'){
223 for(var i=0; node = choosen.options[i];i++){
223 for(var i=0; node = choosen.options[i];i++){
224 available.appendChild(new Option(node.text,
224 available.appendChild(new Option(node.text,
225 node.value, false, false));
225 node.value, false, false));
226 }
226 }
227 choosen.options.length = 0;
227 choosen.options.length = 0;
228 }
228 }
229
229
230 }
230 }
231
231
232
232
233 E.addListener(['add_element','remove_element',
233 E.addListener(['add_element','remove_element',
234 'add_all_elements','remove_all_elements'],'click',
234 'add_all_elements','remove_all_elements'],'click',
235 prompts_action_callback)
235 prompts_action_callback)
236
236
237 E.addListener(form_id,'submit',function(){
237 E.addListener(form_id,'submit',function(){
238 var choosen = D.get(selected_container);
238 var choosen = D.get(selected_container);
239 for (var i = 0; i < choosen.options.length; i++) {
239 for (var i = 0; i < choosen.options.length; i++) {
240 choosen.options[i].selected = 'selected';
240 choosen.options[i].selected = 'selected';
241 }
241 }
242 })
242 })
243 });
243 });
244 </script>
244 </script>
245 <div class="box box-right">
245 <div class="box box-right">
246 <!-- box / title -->
246 <!-- box / title -->
247 <div class="title">
247 <div class="title">
248 <h5>${_('Permissions')}</h5>
248 <h5>${_('Permissions')}</h5>
249 </div>
249 </div>
250 ${h.form(url('xxx', id=''),method='put')}
250 ${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')}
251 <div class="form">
251 <div class="form">
252 <!-- fields -->
252 <!-- fields -->
253 <div class="fields">
253 <div class="fields">
254 <div class="field">
254 <div class="field">
255 <div class="label label-checkbox">
255 <div class="label label-checkbox">
256 <label for="">${_('Create repositories')}:</label>
256 <label for="">${_('Create repositories')}:</label>
257 </div>
257 </div>
258 <div class="checkboxes">
258 <div class="checkboxes">
259 ${h.checkbox('create',value=True)}
259 ${h.checkbox('create_repo_perm',value=True)}
260 </div>
260 </div>
261 </div>
261 </div>
262 <div class="buttons">
262 <div class="buttons">
263 ${h.submit('save','Save',class_="ui-button")}
263 ${h.submit('save','Save',class_="ui-button")}
264 ${h.reset('reset','Reset',class_="ui-button")}
264 ${h.reset('reset','Reset',class_="ui-button")}
265 </div>
265 </div>
266 </div>
266 </div>
267 </div>
267 </div>
268 ${h.end_form()}
268 ${h.end_form()}
269 </div>
269 </div>
270 </%def> No newline at end of file
270 </%def>
General Comments 0
You need to be logged in to leave comments. Login now