##// END OF EJS Templates
#56 added ajax removal of users groups,...
marcink -
r1015:65129c33 beta
parent child Browse files
Show More
@@ -0,0 +1,95 b''
1 <table id="permissions_manage">
2 <tr>
3 <td>${_('none')}</td>
4 <td>${_('read')}</td>
5 <td>${_('write')}</td>
6 <td>${_('admin')}</td>
7 <td>${_('member')}</td>
8 <td></td>
9 </tr>
10 ## USERS
11 <script type="text/javascript">
12 function ajaxActionUser(user_id,field_id){
13 var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
14 var callback = { success:function(o){
15 var tr = YUD.get(String(field_id));
16 tr.parentNode.removeChild(tr);},
17 failure:function(o){
18 alert("${_('Failed to remove user')}");},};
19 var postData = '_method=delete&user_id='+user_id;
20 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
21 </script>
22 %for r2p in c.repo_info.repo_to_perm:
23 %if r2p.user.username =='default' and c.repo_info.private:
24 <tr>
25 <td colspan="4">
26 <span class="private_repo_msg">
27 ${_('private repository')}
28 </span>
29 </td>
30 <td class="private_repo_msg"><img style="vertical-align:bottom" src="/images/icons/user.png"/>${r2p.user.username}</td>
31 </tr>
32 %else:
33 <tr id="id${id(r2p.user.username)}">
34 <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.none')}</td>
35 <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.read')}</td>
36 <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.write')}</td>
37 <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.admin')}</td>
38 <td style="white-space: nowrap;"><img style="vertical-align:bottom" src="/images/icons/user.png"/>${r2p.user.username}</td>
39 <td>
40 %if r2p.user.username !='default':
41 <span class="delete_icon action_button" onclick="ajaxActionUser(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
42 </span>
43 %endif
44 </td>
45 </tr>
46 %endif
47 %endfor
48
49 ## USERS GROUPS
50 <script type="text/javascript">
51 function ajaxActionUsersGroup(users_group_id,field_id){
52 var sUrl = "${h.url('delete_repo_users_group',repo_name=c.repo_name)}";
53 var callback = { success:function(o){
54 var tr = YUD.get(String(field_id));
55 tr.parentNode.removeChild(tr);},
56 failure:function(o){
57 alert("${_('Failed to remove users group')}");},};
58 var postData = '_method=delete&users_group_id='+users_group_id;
59 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
60 </script>
61 %for g2p in c.repo_info.users_group_to_perm:
62 <tr id="id${id(g2p.users_group.users_group_name)}">
63 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.none')}</td>
64 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.read')}</td>
65 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.write')}</td>
66 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.admin')}</td>
67 <td><img style="vertical-align:bottom" src="/images/icons/group.png"/>${g2p.users_group.users_group_name}</td>
68 <td>
69 <span class="delete_icon action_button" onclick="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
70 </span>
71 </td>
72 </tr>
73 %endfor
74 <tr id="add_perm_input">
75 <td>${h.radio('perm_new_member','repository.none')}</td>
76 <td>${h.radio('perm_new_member','repository.read')}</td>
77 <td>${h.radio('perm_new_member','repository.write')}</td>
78 <td>${h.radio('perm_new_member','repository.admin')}</td>
79 <td class='ac'>
80 <div class="perm_ac" id="perm_ac">
81 ${h.text('perm_new_member_name',class_='yui-ac-input')}
82 ${h.hidden('perm_new_member_type')}
83 <div id="perm_container"></div>
84 </div>
85 </td>
86 <td></td>
87 </tr>
88 <tr>
89 <td colspan="6">
90 <span id="add_perm" class="add_icon" style="cursor: pointer;">
91 ${_('Add another member')}
92 </span>
93 </td>
94 </tr>
95 </table> No newline at end of file
@@ -1,219 +1,224 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 def make_map(config):
12 def make_map(config):
13 """Create, configure and return the routes Mapper"""
13 """Create, configure and return the routes Mapper"""
14 map = Mapper(directory=config['pylons.paths']['controllers'],
14 map = Mapper(directory=config['pylons.paths']['controllers'],
15 always_scan=config['debug'])
15 always_scan=config['debug'])
16 map.minimization = False
16 map.minimization = False
17 map.explicit = False
17 map.explicit = False
18
18
19 def check_repo(environ, match_dict):
19 def check_repo(environ, match_dict):
20 """
20 """
21 check for valid repository for proper 404 handling
21 check for valid repository for proper 404 handling
22 :param environ:
22 :param environ:
23 :param match_dict:
23 :param match_dict:
24 """
24 """
25 repo_name = match_dict.get('repo_name')
25 repo_name = match_dict.get('repo_name')
26 return not cr(repo_name, config['base_path'])
26 return not cr(repo_name, config['base_path'])
27
27
28 # The ErrorController route (handles 404/500 error pages); it should
28 # The ErrorController route (handles 404/500 error pages); it should
29 # likely stay at the top, ensuring it can always be resolved
29 # likely stay at the top, ensuring it can always be resolved
30 map.connect('/error/{action}', controller='error')
30 map.connect('/error/{action}', controller='error')
31 map.connect('/error/{action}/{id}', controller='error')
31 map.connect('/error/{action}/{id}', controller='error')
32
32
33 #==========================================================================
33 #==========================================================================
34 # CUSTOM ROUTES HERE
34 # CUSTOM ROUTES HERE
35 #==========================================================================
35 #==========================================================================
36
36
37 #MAIN PAGE
37 #MAIN PAGE
38 map.connect('home', '/', controller='home', action='index')
38 map.connect('home', '/', controller='home', action='index')
39 map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
39 map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
40 map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
40 map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
41 #ADMIN REPOSITORY REST ROUTES
41 #ADMIN REPOSITORY REST ROUTES
42 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
42 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
43 m.connect("repos", "/repos",
43 m.connect("repos", "/repos",
44 action="create", conditions=dict(method=["POST"]))
44 action="create", conditions=dict(method=["POST"]))
45 m.connect("repos", "/repos",
45 m.connect("repos", "/repos",
46 action="index", conditions=dict(method=["GET"]))
46 action="index", conditions=dict(method=["GET"]))
47 m.connect("formatted_repos", "/repos.{format}",
47 m.connect("formatted_repos", "/repos.{format}",
48 action="index",
48 action="index",
49 conditions=dict(method=["GET"]))
49 conditions=dict(method=["GET"]))
50 m.connect("new_repo", "/repos/new",
50 m.connect("new_repo", "/repos/new",
51 action="new", conditions=dict(method=["GET"]))
51 action="new", conditions=dict(method=["GET"]))
52 m.connect("formatted_new_repo", "/repos/new.{format}",
52 m.connect("formatted_new_repo", "/repos/new.{format}",
53 action="new", conditions=dict(method=["GET"]))
53 action="new", conditions=dict(method=["GET"]))
54 m.connect("/repos/{repo_name:.*}",
54 m.connect("/repos/{repo_name:.*}",
55 action="update", conditions=dict(method=["PUT"],
55 action="update", conditions=dict(method=["PUT"],
56 function=check_repo))
56 function=check_repo))
57 m.connect("/repos/{repo_name:.*}",
57 m.connect("/repos/{repo_name:.*}",
58 action="delete", conditions=dict(method=["DELETE"],
58 action="delete", conditions=dict(method=["DELETE"],
59 function=check_repo))
59 function=check_repo))
60 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
60 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
61 action="edit", conditions=dict(method=["GET"],
61 action="edit", conditions=dict(method=["GET"],
62 function=check_repo))
62 function=check_repo))
63 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
63 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
64 action="edit", conditions=dict(method=["GET"],
64 action="edit", conditions=dict(method=["GET"],
65 function=check_repo))
65 function=check_repo))
66 m.connect("repo", "/repos/{repo_name:.*}",
66 m.connect("repo", "/repos/{repo_name:.*}",
67 action="show", conditions=dict(method=["GET"],
67 action="show", conditions=dict(method=["GET"],
68 function=check_repo))
68 function=check_repo))
69 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
69 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
70 action="show", conditions=dict(method=["GET"],
70 action="show", conditions=dict(method=["GET"],
71 function=check_repo))
71 function=check_repo))
72 #ajax delete repo perm user
72 #ajax delete repo perm user
73 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
73 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
74 action="delete_perm_user", conditions=dict(method=["DELETE"],
74 action="delete_perm_user", conditions=dict(method=["DELETE"],
75 function=check_repo))
75 function=check_repo))
76 #ajax delete repo perm users_group
77 m.connect('delete_repo_users_group', "/repos_delete_users_group/{repo_name:.*}",
78 action="delete_perm_users_group", conditions=dict(method=["DELETE"],
79 function=check_repo))
80
76 #settings actions
81 #settings actions
77 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
82 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
78 action="repo_stats", conditions=dict(method=["DELETE"],
83 action="repo_stats", conditions=dict(method=["DELETE"],
79 function=check_repo))
84 function=check_repo))
80 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
85 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
81 action="repo_cache", conditions=dict(method=["DELETE"],
86 action="repo_cache", conditions=dict(method=["DELETE"],
82 function=check_repo))
87 function=check_repo))
83
88
84 #ADMIN USER REST ROUTES
89 #ADMIN USER REST ROUTES
85 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
90 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
86
91
87 #ADMIN USER REST ROUTES
92 #ADMIN USER REST ROUTES
88 map.resource('users_group', 'users_groups', controller='admin/users_groups', path_prefix='/_admin')
93 map.resource('users_group', 'users_groups', controller='admin/users_groups', path_prefix='/_admin')
89
94
90 #ADMIN GROUP REST ROUTES
95 #ADMIN GROUP REST ROUTES
91 map.resource('group', 'groups', controller='admin/groups', path_prefix='/_admin')
96 map.resource('group', 'groups', controller='admin/groups', path_prefix='/_admin')
92
97
93 #ADMIN PERMISSIONS REST ROUTES
98 #ADMIN PERMISSIONS REST ROUTES
94 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
99 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
95
100
96 ##ADMIN LDAP SETTINGS
101 ##ADMIN LDAP SETTINGS
97 map.connect('ldap_settings', '/_admin/ldap', controller='admin/ldap_settings',
102 map.connect('ldap_settings', '/_admin/ldap', controller='admin/ldap_settings',
98 action='ldap_settings', conditions=dict(method=["POST"]))
103 action='ldap_settings', conditions=dict(method=["POST"]))
99 map.connect('ldap_home', '/_admin/ldap', controller='admin/ldap_settings',)
104 map.connect('ldap_home', '/_admin/ldap', controller='admin/ldap_settings',)
100
105
101
106
102 #ADMIN SETTINGS REST ROUTES
107 #ADMIN SETTINGS REST ROUTES
103 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
108 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
104 m.connect("admin_settings", "/settings",
109 m.connect("admin_settings", "/settings",
105 action="create", conditions=dict(method=["POST"]))
110 action="create", conditions=dict(method=["POST"]))
106 m.connect("admin_settings", "/settings",
111 m.connect("admin_settings", "/settings",
107 action="index", conditions=dict(method=["GET"]))
112 action="index", conditions=dict(method=["GET"]))
108 m.connect("formatted_admin_settings", "/settings.{format}",
113 m.connect("formatted_admin_settings", "/settings.{format}",
109 action="index", conditions=dict(method=["GET"]))
114 action="index", conditions=dict(method=["GET"]))
110 m.connect("admin_new_setting", "/settings/new",
115 m.connect("admin_new_setting", "/settings/new",
111 action="new", conditions=dict(method=["GET"]))
116 action="new", conditions=dict(method=["GET"]))
112 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
117 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
113 action="new", conditions=dict(method=["GET"]))
118 action="new", conditions=dict(method=["GET"]))
114 m.connect("/settings/{setting_id}",
119 m.connect("/settings/{setting_id}",
115 action="update", conditions=dict(method=["PUT"]))
120 action="update", conditions=dict(method=["PUT"]))
116 m.connect("/settings/{setting_id}",
121 m.connect("/settings/{setting_id}",
117 action="delete", conditions=dict(method=["DELETE"]))
122 action="delete", conditions=dict(method=["DELETE"]))
118 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
123 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
119 action="edit", conditions=dict(method=["GET"]))
124 action="edit", conditions=dict(method=["GET"]))
120 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
125 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
121 action="edit", conditions=dict(method=["GET"]))
126 action="edit", conditions=dict(method=["GET"]))
122 m.connect("admin_setting", "/settings/{setting_id}",
127 m.connect("admin_setting", "/settings/{setting_id}",
123 action="show", conditions=dict(method=["GET"]))
128 action="show", conditions=dict(method=["GET"]))
124 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
129 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
125 action="show", conditions=dict(method=["GET"]))
130 action="show", conditions=dict(method=["GET"]))
126 m.connect("admin_settings_my_account", "/my_account",
131 m.connect("admin_settings_my_account", "/my_account",
127 action="my_account", conditions=dict(method=["GET"]))
132 action="my_account", conditions=dict(method=["GET"]))
128 m.connect("admin_settings_my_account_update", "/my_account_update",
133 m.connect("admin_settings_my_account_update", "/my_account_update",
129 action="my_account_update", conditions=dict(method=["PUT"]))
134 action="my_account_update", conditions=dict(method=["PUT"]))
130 m.connect("admin_settings_create_repository", "/create_repository",
135 m.connect("admin_settings_create_repository", "/create_repository",
131 action="create_repository", conditions=dict(method=["GET"]))
136 action="create_repository", conditions=dict(method=["GET"]))
132
137
133 #ADMIN MAIN PAGES
138 #ADMIN MAIN PAGES
134 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
139 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
135 m.connect('admin_home', '', action='index')#main page
140 m.connect('admin_home', '', action='index')#main page
136 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
141 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
137 action='add_repo')
142 action='add_repo')
138
143
139
144
140 #USER JOURNAL
145 #USER JOURNAL
141 map.connect('journal', '/_admin/journal', controller='journal',)
146 map.connect('journal', '/_admin/journal', controller='journal',)
142 map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
147 map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
143 action='toggle_following', conditions=dict(method=["POST"]))
148 action='toggle_following', conditions=dict(method=["POST"]))
144
149
145
150
146 #SEARCH
151 #SEARCH
147 map.connect('search', '/_admin/search', controller='search',)
152 map.connect('search', '/_admin/search', controller='search',)
148 map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
153 map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
149
154
150 #LOGIN/LOGOUT/REGISTER/SIGN IN
155 #LOGIN/LOGOUT/REGISTER/SIGN IN
151 map.connect('login_home', '/_admin/login', controller='login')
156 map.connect('login_home', '/_admin/login', controller='login')
152 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
157 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
153 map.connect('register', '/_admin/register', controller='login', action='register')
158 map.connect('register', '/_admin/register', controller='login', action='register')
154 map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
159 map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
155
160
156 #FEEDS
161 #FEEDS
157 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
162 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
158 controller='feed', action='rss',
163 controller='feed', action='rss',
159 conditions=dict(function=check_repo))
164 conditions=dict(function=check_repo))
160 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
165 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
161 controller='feed', action='atom',
166 controller='feed', action='atom',
162 conditions=dict(function=check_repo))
167 conditions=dict(function=check_repo))
163
168
164
169
165 #REPOSITORY ROUTES
170 #REPOSITORY ROUTES
166 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
171 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
167 controller='changeset', revision='tip',
172 controller='changeset', revision='tip',
168 conditions=dict(function=check_repo))
173 conditions=dict(function=check_repo))
169 map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
174 map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
170 controller='changeset', action='raw_changeset', revision='tip',
175 controller='changeset', action='raw_changeset', revision='tip',
171 conditions=dict(function=check_repo))
176 conditions=dict(function=check_repo))
172 map.connect('summary_home', '/{repo_name:.*}',
177 map.connect('summary_home', '/{repo_name:.*}',
173 controller='summary', conditions=dict(function=check_repo))
178 controller='summary', conditions=dict(function=check_repo))
174 map.connect('summary_home', '/{repo_name:.*}/summary',
179 map.connect('summary_home', '/{repo_name:.*}/summary',
175 controller='summary', conditions=dict(function=check_repo))
180 controller='summary', conditions=dict(function=check_repo))
176 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
181 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
177 controller='shortlog', conditions=dict(function=check_repo))
182 controller='shortlog', conditions=dict(function=check_repo))
178 map.connect('branches_home', '/{repo_name:.*}/branches',
183 map.connect('branches_home', '/{repo_name:.*}/branches',
179 controller='branches', conditions=dict(function=check_repo))
184 controller='branches', conditions=dict(function=check_repo))
180 map.connect('tags_home', '/{repo_name:.*}/tags',
185 map.connect('tags_home', '/{repo_name:.*}/tags',
181 controller='tags', conditions=dict(function=check_repo))
186 controller='tags', conditions=dict(function=check_repo))
182 map.connect('changelog_home', '/{repo_name:.*}/changelog',
187 map.connect('changelog_home', '/{repo_name:.*}/changelog',
183 controller='changelog', conditions=dict(function=check_repo))
188 controller='changelog', conditions=dict(function=check_repo))
184 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
189 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
185 controller='files', revision='tip', f_path='',
190 controller='files', revision='tip', f_path='',
186 conditions=dict(function=check_repo))
191 conditions=dict(function=check_repo))
187 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
192 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
188 controller='files', action='diff', revision='tip', f_path='',
193 controller='files', action='diff', revision='tip', f_path='',
189 conditions=dict(function=check_repo))
194 conditions=dict(function=check_repo))
190 map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
195 map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
191 controller='files', action='rawfile', revision='tip', f_path='',
196 controller='files', action='rawfile', revision='tip', f_path='',
192 conditions=dict(function=check_repo))
197 conditions=dict(function=check_repo))
193 map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
198 map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
194 controller='files', action='raw', revision='tip', f_path='',
199 controller='files', action='raw', revision='tip', f_path='',
195 conditions=dict(function=check_repo))
200 conditions=dict(function=check_repo))
196 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
201 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
197 controller='files', action='annotate', revision='tip', f_path='',
202 controller='files', action='annotate', revision='tip', f_path='',
198 conditions=dict(function=check_repo))
203 conditions=dict(function=check_repo))
199 map.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
204 map.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
200 controller='files', action='archivefile',
205 controller='files', action='archivefile',
201 conditions=dict(function=check_repo))
206 conditions=dict(function=check_repo))
202 map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
207 map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
203 controller='settings', action="delete",
208 controller='settings', action="delete",
204 conditions=dict(method=["DELETE"], function=check_repo))
209 conditions=dict(method=["DELETE"], function=check_repo))
205 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
210 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
206 controller='settings', action="update",
211 controller='settings', action="update",
207 conditions=dict(method=["PUT"], function=check_repo))
212 conditions=dict(method=["PUT"], function=check_repo))
208 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
213 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
209 controller='settings', action='index',
214 controller='settings', action='index',
210 conditions=dict(function=check_repo))
215 conditions=dict(function=check_repo))
211
216
212 map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
217 map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
213 controller='settings', action='fork_create',
218 controller='settings', action='fork_create',
214 conditions=dict(function=check_repo, method=["POST"]))
219 conditions=dict(function=check_repo, method=["POST"]))
215 map.connect('repo_fork_home', '/{repo_name:.*}/fork',
220 map.connect('repo_fork_home', '/{repo_name:.*}/fork',
216 controller='settings', action='fork',
221 controller='settings', action='fork',
217 conditions=dict(function=check_repo))
222 conditions=dict(function=check_repo))
218
223
219 return map
224 return map
@@ -1,316 +1,341 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Admin controller for RhodeCode
6 Admin controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import formencode
30 import formencode
31 from operator import itemgetter
31 from operator import itemgetter
32 from formencode import htmlfill
32 from formencode import htmlfill
33
33
34 from paste.httpexceptions import HTTPInternalServerError
34 from paste.httpexceptions import HTTPInternalServerError
35 from pylons import request, response, session, tmpl_context as c, url
35 from pylons import request, response, session, tmpl_context as c, url
36 from pylons.controllers.util import abort, redirect
36 from pylons.controllers.util import abort, redirect
37 from pylons.i18n.translation import _
37 from pylons.i18n.translation import _
38
38
39 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
41 HasPermissionAnyDecorator
41 HasPermissionAnyDecorator
42 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger
43 from rhodecode.lib.utils import invalidate_cache, action_logger
44 from rhodecode.model.db import User
44 from rhodecode.model.db import User
45 from rhodecode.model.forms import RepoForm
45 from rhodecode.model.forms import RepoForm
46 from rhodecode.model.scm import ScmModel
46 from rhodecode.model.scm import ScmModel
47 from rhodecode.model.repo import RepoModel
47 from rhodecode.model.repo import RepoModel
48
48
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52 class ReposController(BaseController):
52 class ReposController(BaseController):
53 """REST Controller styled on the Atom Publishing Protocol"""
53 """REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
55 # file has a resource setup:
56 # map.resource('repo', 'repos')
56 # map.resource('repo', 'repos')
57
57
58 @LoginRequired()
58 @LoginRequired()
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 def __before__(self):
60 def __before__(self):
61 c.admin_user = session.get('admin_user')
61 c.admin_user = session.get('admin_user')
62 c.admin_username = session.get('admin_username')
62 c.admin_username = session.get('admin_username')
63 super(ReposController, self).__before__()
63 super(ReposController, self).__before__()
64
64
65 @HasPermissionAllDecorator('hg.admin')
65 @HasPermissionAllDecorator('hg.admin')
66 def index(self, format='html'):
66 def index(self, format='html'):
67 """GET /repos: All items in the collection"""
67 """GET /repos: All items in the collection"""
68 # url('repos')
68 # url('repos')
69 cached_repo_list = ScmModel().get_repos()
69 cached_repo_list = ScmModel().get_repos()
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
71 return render('admin/repos/repos.html')
71 return render('admin/repos/repos.html')
72
72
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
74 def create(self):
74 def create(self):
75 """POST /repos: Create a new item"""
75 """POST /repos: Create a new item"""
76 # url('repos')
76 # url('repos')
77 repo_model = RepoModel()
77 repo_model = RepoModel()
78 _form = RepoForm()()
78 _form = RepoForm()()
79 form_result = {}
79 form_result = {}
80 try:
80 try:
81 form_result = _form.to_python(dict(request.POST))
81 form_result = _form.to_python(dict(request.POST))
82 repo_model.create(form_result, c.rhodecode_user)
82 repo_model.create(form_result, c.rhodecode_user)
83 h.flash(_('created repository %s') % form_result['repo_name'],
83 h.flash(_('created repository %s') % form_result['repo_name'],
84 category='success')
84 category='success')
85
85
86 if request.POST.get('user_created'):
86 if request.POST.get('user_created'):
87 action_logger(self.rhodecode_user, 'user_created_repo',
87 action_logger(self.rhodecode_user, 'user_created_repo',
88 form_result['repo_name'], '', self.sa)
88 form_result['repo_name'], '', self.sa)
89 else:
89 else:
90 action_logger(self.rhodecode_user, 'admin_created_repo',
90 action_logger(self.rhodecode_user, 'admin_created_repo',
91 form_result['repo_name'], '', self.sa)
91 form_result['repo_name'], '', self.sa)
92
92
93 except formencode.Invalid, errors:
93 except formencode.Invalid, errors:
94 c.new_repo = errors.value['repo_name']
94 c.new_repo = errors.value['repo_name']
95
95
96 if request.POST.get('user_created'):
96 if request.POST.get('user_created'):
97 r = render('admin/repos/repo_add_create_repository.html')
97 r = render('admin/repos/repo_add_create_repository.html')
98 else:
98 else:
99 r = render('admin/repos/repo_add.html')
99 r = render('admin/repos/repo_add.html')
100
100
101 return htmlfill.render(
101 return htmlfill.render(
102 r,
102 r,
103 defaults=errors.value,
103 defaults=errors.value,
104 errors=errors.error_dict or {},
104 errors=errors.error_dict or {},
105 prefix_error=False,
105 prefix_error=False,
106 encoding="UTF-8")
106 encoding="UTF-8")
107
107
108 except Exception:
108 except Exception:
109 log.error(traceback.format_exc())
109 log.error(traceback.format_exc())
110 msg = _('error occurred during creation of repository %s') \
110 msg = _('error occurred during creation of repository %s') \
111 % form_result.get('repo_name')
111 % form_result.get('repo_name')
112 h.flash(msg, category='error')
112 h.flash(msg, category='error')
113 if request.POST.get('user_created'):
113 if request.POST.get('user_created'):
114 return redirect(url('home'))
114 return redirect(url('home'))
115 return redirect(url('repos'))
115 return redirect(url('repos'))
116
116
117 @HasPermissionAllDecorator('hg.admin')
117 @HasPermissionAllDecorator('hg.admin')
118 def new(self, format='html'):
118 def new(self, format='html'):
119 """GET /repos/new: Form to create a new item"""
119 """GET /repos/new: Form to create a new item"""
120 new_repo = request.GET.get('repo', '')
120 new_repo = request.GET.get('repo', '')
121 c.new_repo = h.repo_name_slug(new_repo)
121 c.new_repo = h.repo_name_slug(new_repo)
122
122
123 return render('admin/repos/repo_add.html')
123 return render('admin/repos/repo_add.html')
124
124
125 @HasPermissionAllDecorator('hg.admin')
125 @HasPermissionAllDecorator('hg.admin')
126 def update(self, repo_name):
126 def update(self, repo_name):
127 """PUT /repos/repo_name: Update an existing item"""
127 """PUT /repos/repo_name: Update an existing item"""
128 # Forms posted to this method should contain a hidden field:
128 # Forms posted to this method should contain a hidden field:
129 # <input type="hidden" name="_method" value="PUT" />
129 # <input type="hidden" name="_method" value="PUT" />
130 # Or using helpers:
130 # Or using helpers:
131 # h.form(url('repo', repo_name=ID),
131 # h.form(url('repo', repo_name=ID),
132 # method='put')
132 # method='put')
133 # url('repo', repo_name=ID)
133 # url('repo', repo_name=ID)
134 repo_model = RepoModel()
134 repo_model = RepoModel()
135 changed_name = repo_name
135 changed_name = repo_name
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
137
137
138 try:
138 try:
139 form_result = _form.to_python(dict(request.POST))
139 form_result = _form.to_python(dict(request.POST))
140 repo_model.update(repo_name, form_result)
140 repo_model.update(repo_name, form_result)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
142 h.flash(_('Repository %s updated successfully' % repo_name),
142 h.flash(_('Repository %s updated successfully' % repo_name),
143 category='success')
143 category='success')
144 changed_name = form_result['repo_name']
144 changed_name = form_result['repo_name']
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
146 changed_name, '', self.sa)
146 changed_name, '', self.sa)
147
147
148 except formencode.Invalid, errors:
148 except formencode.Invalid, errors:
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
150 if c.repo_info.stats:
150 if c.repo_info.stats:
151 last_rev = c.repo_info.stats.stat_on_revision
151 last_rev = c.repo_info.stats.stat_on_revision
152 else:
152 else:
153 last_rev = 0
153 last_rev = 0
154 c.stats_revision = last_rev
154 c.stats_revision = last_rev
155 r = ScmModel().get(repo_name)
155 r = ScmModel().get(repo_name)
156 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
156 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
157
157
158 if last_rev == 0:
158 if last_rev == 0:
159 c.stats_percentage = 0
159 c.stats_percentage = 0
160 else:
160 else:
161 c.stats_percentage = '%.2f' % ((float((last_rev)) /
161 c.stats_percentage = '%.2f' % ((float((last_rev)) /
162 c.repo_last_rev) * 100)
162 c.repo_last_rev) * 100)
163
163
164 c.users_array = repo_model.get_users_js()
164 c.users_array = repo_model.get_users_js()
165 c.users_groups_array = repo_model.get_users_groups_js()
165 c.users_groups_array = repo_model.get_users_groups_js()
166
166
167 errors.value.update({'user':c.repo_info.user.username})
167 errors.value.update({'user':c.repo_info.user.username})
168 return htmlfill.render(
168 return htmlfill.render(
169 render('admin/repos/repo_edit.html'),
169 render('admin/repos/repo_edit.html'),
170 defaults=errors.value,
170 defaults=errors.value,
171 errors=errors.error_dict or {},
171 errors=errors.error_dict or {},
172 prefix_error=False,
172 prefix_error=False,
173 encoding="UTF-8")
173 encoding="UTF-8")
174
174
175 except Exception:
175 except Exception:
176 log.error(traceback.format_exc())
176 log.error(traceback.format_exc())
177 h.flash(_('error occurred during update of repository %s') \
177 h.flash(_('error occurred during update of repository %s') \
178 % repo_name, category='error')
178 % repo_name, category='error')
179
179
180 return redirect(url('edit_repo', repo_name=changed_name))
180 return redirect(url('edit_repo', repo_name=changed_name))
181
181
182 @HasPermissionAllDecorator('hg.admin')
182 @HasPermissionAllDecorator('hg.admin')
183 def delete(self, repo_name):
183 def delete(self, repo_name):
184 """DELETE /repos/repo_name: Delete an existing item"""
184 """DELETE /repos/repo_name: Delete an existing item"""
185 # Forms posted to this method should contain a hidden field:
185 # Forms posted to this method should contain a hidden field:
186 # <input type="hidden" name="_method" value="DELETE" />
186 # <input type="hidden" name="_method" value="DELETE" />
187 # Or using helpers:
187 # Or using helpers:
188 # h.form(url('repo', repo_name=ID),
188 # h.form(url('repo', repo_name=ID),
189 # method='delete')
189 # method='delete')
190 # url('repo', repo_name=ID)
190 # url('repo', repo_name=ID)
191
191
192 repo_model = RepoModel()
192 repo_model = RepoModel()
193 repo = repo_model.get_by_repo_name(repo_name)
193 repo = repo_model.get_by_repo_name(repo_name)
194 if not repo:
194 if not repo:
195 h.flash(_('%s repository is not mapped to db perhaps'
195 h.flash(_('%s repository is not mapped to db perhaps'
196 ' it was moved or renamed from the filesystem'
196 ' it was moved or renamed from the filesystem'
197 ' please run the application again'
197 ' please run the application again'
198 ' in order to rescan repositories') % repo_name,
198 ' in order to rescan repositories') % repo_name,
199 category='error')
199 category='error')
200
200
201 return redirect(url('repos'))
201 return redirect(url('repos'))
202 try:
202 try:
203 action_logger(self.rhodecode_user, 'admin_deleted_repo',
203 action_logger(self.rhodecode_user, 'admin_deleted_repo',
204 repo_name, '', self.sa)
204 repo_name, '', self.sa)
205 repo_model.delete(repo)
205 repo_model.delete(repo)
206 invalidate_cache('get_repo_cached_%s' % repo_name)
206 invalidate_cache('get_repo_cached_%s' % repo_name)
207 h.flash(_('deleted repository %s') % repo_name, category='success')
207 h.flash(_('deleted repository %s') % repo_name, category='success')
208
208
209 except Exception, e:
209 except Exception, e:
210 log.error(traceback.format_exc())
210 log.error(traceback.format_exc())
211 h.flash(_('An error occurred during deletion of %s') % repo_name,
211 h.flash(_('An error occurred during deletion of %s') % repo_name,
212 category='error')
212 category='error')
213
213
214 return redirect(url('repos'))
214 return redirect(url('repos'))
215
215
216 @HasPermissionAllDecorator('hg.admin')
216 @HasPermissionAllDecorator('hg.admin')
217 def delete_perm_user(self, repo_name):
217 def delete_perm_user(self, repo_name):
218 """
218 """DELETE an existing repository permission user
219 DELETE an existing repository permission user
219
220 :param repo_name:
220 :param repo_name:
221 """
221 """
222
222
223 try:
223 try:
224 repo_model = RepoModel()
224 repo_model = RepoModel()
225 repo_model.delete_perm_user(request.POST, repo_name)
225 repo_model.delete_perm_user(request.POST, repo_name)
226 except Exception, e:
226 except Exception, e:
227 h.flash(_('An error occurred during deletion of repository user'),
227 h.flash(_('An error occurred during deletion of repository user'),
228 category='error')
228 category='error')
229 raise HTTPInternalServerError()
229 raise HTTPInternalServerError()
230
230
231 @HasPermissionAllDecorator('hg.admin')
231 @HasPermissionAllDecorator('hg.admin')
232 def repo_stats(self, repo_name):
232 def delete_perm_users_group(self, repo_name):
233 """DELETE an existing repository permission users group
234
235 :param repo_name:
233 """
236 """
234 DELETE an existing repository statistics
237 try:
238 repo_model = RepoModel()
239 repo_model.delete_perm_users_group(request.POST, repo_name)
240 except Exception, e:
241 h.flash(_('An error occurred during deletion of repository'
242 ' users groups'),
243 category='error')
244 raise HTTPInternalServerError()
245
246 @HasPermissionAllDecorator('hg.admin')
247 def repo_stats(self, repo_name):
248 """DELETE an existing repository statistics
249
235 :param repo_name:
250 :param repo_name:
236 """
251 """
237
252
238 try:
253 try:
239 repo_model = RepoModel()
254 repo_model = RepoModel()
240 repo_model.delete_stats(repo_name)
255 repo_model.delete_stats(repo_name)
241 except Exception, e:
256 except Exception, e:
242 h.flash(_('An error occurred during deletion of repository stats'),
257 h.flash(_('An error occurred during deletion of repository stats'),
243 category='error')
258 category='error')
244 return redirect(url('edit_repo', repo_name=repo_name))
259 return redirect(url('edit_repo', repo_name=repo_name))
245
260
246 @HasPermissionAllDecorator('hg.admin')
261 @HasPermissionAllDecorator('hg.admin')
247 def repo_cache(self, repo_name):
262 def repo_cache(self, repo_name):
248 """
263 """INVALIDATE existing repository cache
249 INVALIDATE existing repository cache
264
250 :param repo_name:
265 :param repo_name:
251 """
266 """
252
267
253 try:
268 try:
254 ScmModel().mark_for_invalidation(repo_name)
269 ScmModel().mark_for_invalidation(repo_name)
255 except Exception, e:
270 except Exception, e:
256 h.flash(_('An error occurred during cache invalidation'),
271 h.flash(_('An error occurred during cache invalidation'),
257 category='error')
272 category='error')
258 return redirect(url('edit_repo', repo_name=repo_name))
273 return redirect(url('edit_repo', repo_name=repo_name))
259
274
260 @HasPermissionAllDecorator('hg.admin')
275 @HasPermissionAllDecorator('hg.admin')
261 def show(self, repo_name, format='html'):
276 def show(self, repo_name, format='html'):
262 """GET /repos/repo_name: Show a specific item"""
277 """GET /repos/repo_name: Show a specific item"""
263 # url('repo', repo_name=ID)
278 # url('repo', repo_name=ID)
264
279
265 @HasPermissionAllDecorator('hg.admin')
280 @HasPermissionAllDecorator('hg.admin')
266 def edit(self, repo_name, format='html'):
281 def edit(self, repo_name, format='html'):
267 """GET /repos/repo_name/edit: Form to edit an existing item"""
282 """GET /repos/repo_name/edit: Form to edit an existing item"""
268 # url('edit_repo', repo_name=ID)
283 # url('edit_repo', repo_name=ID)
269 repo_model = RepoModel()
284 repo_model = RepoModel()
285 c.repo_info = repo_model.get_by_repo_name(repo_name)
286
270 r = ScmModel().get(repo_name)
287 r = ScmModel().get(repo_name)
271 c.repo_info = repo_model.get_by_repo_name(repo_name)
272
288
273 if c.repo_info is None:
289 if c.repo_info is None:
274 h.flash(_('%s repository is not mapped to db perhaps'
290 h.flash(_('%s repository is not mapped to db perhaps'
275 ' it was created or renamed from the filesystem'
291 ' it was created or renamed from the filesystem'
276 ' please run the application again'
292 ' please run the application again'
277 ' in order to rescan repositories') % repo_name,
293 ' in order to rescan repositories') % repo_name,
278 category='error')
294 category='error')
279
295
280 return redirect(url('repos'))
296 return redirect(url('repos'))
281
297
282 if c.repo_info.stats:
298 if c.repo_info.stats:
283 last_rev = c.repo_info.stats.stat_on_revision
299 last_rev = c.repo_info.stats.stat_on_revision
284 else:
300 else:
285 last_rev = 0
301 last_rev = 0
286 c.stats_revision = last_rev
302 c.stats_revision = last_rev
287
303
288 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
304 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
289
305
290 if last_rev == 0 or c.repo_last_rev == 0:
306 if last_rev == 0 or c.repo_last_rev == 0:
291 c.stats_percentage = 0
307 c.stats_percentage = 0
292 else:
308 else:
293 c.stats_percentage = '%.2f' % ((float((last_rev)) /
309 c.stats_percentage = '%.2f' % ((float((last_rev)) /
294 c.repo_last_rev) * 100)
310 c.repo_last_rev) * 100)
295
311
312 c.users_array = repo_model.get_users_js()
313 c.users_groups_array = repo_model.get_users_groups_js()
314
296 defaults = c.repo_info.get_dict()
315 defaults = c.repo_info.get_dict()
316
317 #fill owner
297 if c.repo_info.user:
318 if c.repo_info.user:
298 defaults.update({'user':c.repo_info.user.username})
319 defaults.update({'user':c.repo_info.user.username})
299 else:
320 else:
300 replacement_user = self.sa.query(User)\
321 replacement_user = self.sa.query(User)\
301 .filter(User.admin == True).first().username
322 .filter(User.admin == True).first().username
302 defaults.update({'user':replacement_user})
323 defaults.update({'user':replacement_user})
303
324
304 c.users_array = repo_model.get_users_js()
305 c.users_groups_array = repo_model.get_users_groups_js()
306
325
326 #fill repository users
307 for p in c.repo_info.repo_to_perm:
327 for p in c.repo_info.repo_to_perm:
308 defaults.update({'perm_%s' % p.user.username:
328 defaults.update({'u_perm_%s' % p.user.username:
329 p.permission.permission_name})
330
331 #fill repository groups
332 for p in c.repo_info.users_group_to_perm:
333 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
309 p.permission.permission_name})
334 p.permission.permission_name})
310
335
311 return htmlfill.render(
336 return htmlfill.render(
312 render('admin/repos/repo_edit.html'),
337 render('admin/repos/repo_edit.html'),
313 defaults=defaults,
338 defaults=defaults,
314 encoding="UTF-8",
339 encoding="UTF-8",
315 force_defaults=False
340 force_defaults=False
316 )
341 )
@@ -1,184 +1,201 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.settings
3 rhodecode.controllers.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Settings controller for rhodecode
6 Settings controller for rhodecode
7
7
8 :created_on: Jun 30, 2010
8 :created_on: Jun 30, 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30
30
31 import formencode
31 import formencode
32 from formencode import htmlfill
32 from formencode import htmlfill
33
33
34 from pylons import tmpl_context as c, request, url
34 from pylons import tmpl_context as c, request, url
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 import rhodecode.lib.helpers as h
38 import rhodecode.lib.helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
40 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.utils import invalidate_cache, action_logger
41 from rhodecode.lib.utils import invalidate_cache, action_logger
42 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
42 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
43 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.db import User
44
45
45 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
46
47
47 class SettingsController(BaseController):
48 class SettingsController(BaseController):
48
49
49 @LoginRequired()
50 @LoginRequired()
50 @HasRepoPermissionAllDecorator('repository.admin')
51 @HasRepoPermissionAllDecorator('repository.admin')
51 def __before__(self):
52 def __before__(self):
52 super(SettingsController, self).__before__()
53 super(SettingsController, self).__before__()
53
54
54 def index(self, repo_name):
55 def index(self, repo_name):
55 repo_model = RepoModel()
56 repo_model = RepoModel()
56 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
57 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
57 if not repo:
58 if not repo:
58 h.flash(_('%s repository is not mapped to db perhaps'
59 h.flash(_('%s repository is not mapped to db perhaps'
59 ' it was created or renamed from the file system'
60 ' it was created or renamed from the file system'
60 ' please run the application again'
61 ' please run the application again'
61 ' in order to rescan repositories') % repo_name,
62 ' in order to rescan repositories') % repo_name,
62 category='error')
63 category='error')
63
64
64 return redirect(url('home'))
65 return redirect(url('home'))
65 defaults = c.repo_info.get_dict()
66
66 defaults.update({'user':c.repo_info.user.username})
67 c.users_array = repo_model.get_users_js()
67 c.users_array = repo_model.get_users_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
68
69
70 defaults = c.repo_info.get_dict()
71
72 #fill owner
73 if c.repo_info.user:
74 defaults.update({'user':c.repo_info.user.username})
75 else:
76 replacement_user = self.sa.query(User)\
77 .filter(User.admin == True).first().username
78 defaults.update({'user':replacement_user})
79
80 #fill repository users
69 for p in c.repo_info.repo_to_perm:
81 for p in c.repo_info.repo_to_perm:
70 defaults.update({'perm_%s' % p.user.username:
82 defaults.update({'u_perm_%s' % p.user.username:
83 p.permission.permission_name})
84
85 #fill repository groups
86 for p in c.repo_info.users_group_to_perm:
87 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
71 p.permission.permission_name})
88 p.permission.permission_name})
72
89
73 return htmlfill.render(
90 return htmlfill.render(
74 render('settings/repo_settings.html'),
91 render('settings/repo_settings.html'),
75 defaults=defaults,
92 defaults=defaults,
76 encoding="UTF-8",
93 encoding="UTF-8",
77 force_defaults=False
94 force_defaults=False
78 )
95 )
79
96
80 def update(self, repo_name):
97 def update(self, repo_name):
81 repo_model = RepoModel()
98 repo_model = RepoModel()
82 changed_name = repo_name
99 changed_name = repo_name
83 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
100 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
84 try:
101 try:
85 form_result = _form.to_python(dict(request.POST))
102 form_result = _form.to_python(dict(request.POST))
86 repo_model.update(repo_name, form_result)
103 repo_model.update(repo_name, form_result)
87 invalidate_cache('get_repo_cached_%s' % repo_name)
104 invalidate_cache('get_repo_cached_%s' % repo_name)
88 h.flash(_('Repository %s updated successfully' % repo_name),
105 h.flash(_('Repository %s updated successfully' % repo_name),
89 category='success')
106 category='success')
90 changed_name = form_result['repo_name']
107 changed_name = form_result['repo_name']
91 action_logger(self.rhodecode_user, 'user_updated_repo',
108 action_logger(self.rhodecode_user, 'user_updated_repo',
92 changed_name, '', self.sa)
109 changed_name, '', self.sa)
93 except formencode.Invalid, errors:
110 except formencode.Invalid, errors:
94 c.repo_info = repo_model.get_by_repo_name(repo_name)
111 c.repo_info = repo_model.get_by_repo_name(repo_name)
95 c.users_array = repo_model.get_users_js()
112 c.users_array = repo_model.get_users_js()
96 errors.value.update({'user':c.repo_info.user.username})
113 errors.value.update({'user':c.repo_info.user.username})
97 return htmlfill.render(
114 return htmlfill.render(
98 render('settings/repo_settings.html'),
115 render('settings/repo_settings.html'),
99 defaults=errors.value,
116 defaults=errors.value,
100 errors=errors.error_dict or {},
117 errors=errors.error_dict or {},
101 prefix_error=False,
118 prefix_error=False,
102 encoding="UTF-8")
119 encoding="UTF-8")
103 except Exception:
120 except Exception:
104 log.error(traceback.format_exc())
121 log.error(traceback.format_exc())
105 h.flash(_('error occurred during update of repository %s') \
122 h.flash(_('error occurred during update of repository %s') \
106 % repo_name, category='error')
123 % repo_name, category='error')
107
124
108 return redirect(url('repo_settings_home', repo_name=changed_name))
125 return redirect(url('repo_settings_home', repo_name=changed_name))
109
126
110
127
111
128
112 def delete(self, repo_name):
129 def delete(self, repo_name):
113 """DELETE /repos/repo_name: Delete an existing item"""
130 """DELETE /repos/repo_name: Delete an existing item"""
114 # Forms posted to this method should contain a hidden field:
131 # Forms posted to this method should contain a hidden field:
115 # <input type="hidden" name="_method" value="DELETE" />
132 # <input type="hidden" name="_method" value="DELETE" />
116 # Or using helpers:
133 # Or using helpers:
117 # h.form(url('repo_settings_delete', repo_name=ID),
134 # h.form(url('repo_settings_delete', repo_name=ID),
118 # method='delete')
135 # method='delete')
119 # url('repo_settings_delete', repo_name=ID)
136 # url('repo_settings_delete', repo_name=ID)
120
137
121 repo_model = RepoModel()
138 repo_model = RepoModel()
122 repo = repo_model.get_by_repo_name(repo_name)
139 repo = repo_model.get_by_repo_name(repo_name)
123 if not repo:
140 if not repo:
124 h.flash(_('%s repository is not mapped to db perhaps'
141 h.flash(_('%s repository is not mapped to db perhaps'
125 ' it was moved or renamed from the filesystem'
142 ' it was moved or renamed from the filesystem'
126 ' please run the application again'
143 ' please run the application again'
127 ' in order to rescan repositories') % repo_name,
144 ' in order to rescan repositories') % repo_name,
128 category='error')
145 category='error')
129
146
130 return redirect(url('home'))
147 return redirect(url('home'))
131 try:
148 try:
132 action_logger(self.rhodecode_user, 'user_deleted_repo',
149 action_logger(self.rhodecode_user, 'user_deleted_repo',
133 repo_name, '', self.sa)
150 repo_name, '', self.sa)
134 repo_model.delete(repo)
151 repo_model.delete(repo)
135 invalidate_cache('get_repo_cached_%s' % repo_name)
152 invalidate_cache('get_repo_cached_%s' % repo_name)
136 h.flash(_('deleted repository %s') % repo_name, category='success')
153 h.flash(_('deleted repository %s') % repo_name, category='success')
137 except Exception:
154 except Exception:
138 h.flash(_('An error occurred during deletion of %s') % repo_name,
155 h.flash(_('An error occurred during deletion of %s') % repo_name,
139 category='error')
156 category='error')
140
157
141 return redirect(url('home'))
158 return redirect(url('home'))
142
159
143 def fork(self, repo_name):
160 def fork(self, repo_name):
144 repo_model = RepoModel()
161 repo_model = RepoModel()
145 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
162 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
146 if not repo:
163 if not repo:
147 h.flash(_('%s repository is not mapped to db perhaps'
164 h.flash(_('%s repository is not mapped to db perhaps'
148 ' it was created or renamed from the file system'
165 ' it was created or renamed from the file system'
149 ' please run the application again'
166 ' please run the application again'
150 ' in order to rescan repositories') % repo_name,
167 ' in order to rescan repositories') % repo_name,
151 category='error')
168 category='error')
152
169
153 return redirect(url('home'))
170 return redirect(url('home'))
154
171
155 return render('settings/repo_fork.html')
172 return render('settings/repo_fork.html')
156
173
157
174
158
175
159 def fork_create(self, repo_name):
176 def fork_create(self, repo_name):
160 repo_model = RepoModel()
177 repo_model = RepoModel()
161 c.repo_info = repo_model.get_by_repo_name(repo_name)
178 c.repo_info = repo_model.get_by_repo_name(repo_name)
162 _form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
179 _form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
163 form_result = {}
180 form_result = {}
164 try:
181 try:
165 form_result = _form.to_python(dict(request.POST))
182 form_result = _form.to_python(dict(request.POST))
166 form_result.update({'repo_name':repo_name})
183 form_result.update({'repo_name':repo_name})
167 repo_model.create_fork(form_result, c.rhodecode_user)
184 repo_model.create_fork(form_result, c.rhodecode_user)
168 h.flash(_('forked %s repository as %s') \
185 h.flash(_('forked %s repository as %s') \
169 % (repo_name, form_result['fork_name']),
186 % (repo_name, form_result['fork_name']),
170 category='success')
187 category='success')
171 action_logger(self.rhodecode_user,
188 action_logger(self.rhodecode_user,
172 'user_forked_repo:%s' % form_result['fork_name'],
189 'user_forked_repo:%s' % form_result['fork_name'],
173 repo_name, '', self.sa)
190 repo_name, '', self.sa)
174 except formencode.Invalid, errors:
191 except formencode.Invalid, errors:
175 c.new_repo = errors.value['fork_name']
192 c.new_repo = errors.value['fork_name']
176 r = render('settings/repo_fork.html')
193 r = render('settings/repo_fork.html')
177
194
178 return htmlfill.render(
195 return htmlfill.render(
179 r,
196 r,
180 defaults=errors.value,
197 defaults=errors.value,
181 errors=errors.error_dict or {},
198 errors=errors.error_dict or {},
182 prefix_error=False,
199 prefix_error=False,
183 encoding="UTF-8")
200 encoding="UTF-8")
184 return redirect(url('home'))
201 return redirect(url('home'))
@@ -1,345 +1,346 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
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, class_mapper
33 from sqlalchemy.orm import relationship, backref, class_mapper
34 from sqlalchemy.orm.session import Session
34 from sqlalchemy.orm.session import Session
35
35
36 from rhodecode.model.meta import Base
36 from rhodecode.model.meta import Base
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 class BaseModel(object):
40 class BaseModel(object):
41
41
42 @classmethod
42 @classmethod
43 def _get_keys(cls):
43 def _get_keys(cls):
44 """return column names for this model """
44 """return column names for this model """
45 return class_mapper(cls).c.keys()
45 return class_mapper(cls).c.keys()
46
46
47 def get_dict(self):
47 def get_dict(self):
48 """return dict with keys and values corresponding
48 """return dict with keys and values corresponding
49 to this model data """
49 to this model data """
50
50
51 d = {}
51 d = {}
52 for k in self._get_keys():
52 for k in self._get_keys():
53 d[k] = getattr(self, k)
53 d[k] = getattr(self, k)
54 return d
54 return d
55
55
56 def get_appstruct(self):
56 def get_appstruct(self):
57 """return list with keys and values tupples corresponding
57 """return list with keys and values tupples corresponding
58 to this model data """
58 to this model data """
59
59
60 l = []
60 l = []
61 for k in self._get_keys():
61 for k in self._get_keys():
62 l.append((k, getattr(self, k),))
62 l.append((k, getattr(self, k),))
63 return l
63 return l
64
64
65 def populate_obj(self, populate_dict):
65 def populate_obj(self, populate_dict):
66 """populate model with data from given populate_dict"""
66 """populate model with data from given populate_dict"""
67
67
68 for k in self._get_keys():
68 for k in self._get_keys():
69 if k in populate_dict:
69 if k in populate_dict:
70 setattr(self, k, populate_dict[k])
70 setattr(self, k, populate_dict[k])
71
71
72 class RhodeCodeSettings(Base, BaseModel):
72 class RhodeCodeSettings(Base, BaseModel):
73 __tablename__ = 'rhodecode_settings'
73 __tablename__ = 'rhodecode_settings'
74 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
74 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
75 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
75 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
76 app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
76 app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
77 app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
77 app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
78
78
79 def __init__(self, k='', v=''):
79 def __init__(self, k='', v=''):
80 self.app_settings_name = k
80 self.app_settings_name = k
81 self.app_settings_value = v
81 self.app_settings_value = v
82
82
83 def __repr__(self):
83 def __repr__(self):
84 return "<%s('%s:%s')>" % (self.__class__.__name__,
84 return "<%s('%s:%s')>" % (self.__class__.__name__,
85 self.app_settings_name, self.app_settings_value)
85 self.app_settings_name, self.app_settings_value)
86
86
87 class RhodeCodeUi(Base, BaseModel):
87 class RhodeCodeUi(Base, BaseModel):
88 __tablename__ = 'rhodecode_ui'
88 __tablename__ = 'rhodecode_ui'
89 __table_args__ = {'useexisting':True}
89 __table_args__ = {'useexisting':True}
90 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
90 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
91 ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
91 ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
92 ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
92 ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
93 ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
93 ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
94 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
94 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
95
95
96
96
97 class User(Base, BaseModel):
97 class User(Base, BaseModel):
98 __tablename__ = 'users'
98 __tablename__ = 'users'
99 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
99 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
100 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
100 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
101 username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102 password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102 password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
103 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
103 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
104 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
104 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
105 name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
107 email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
107 email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
108 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
108 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
109 ldap_dn = Column("ldap_dn", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
109 ldap_dn = Column("ldap_dn", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
110
110
111 user_log = relationship('UserLog', cascade='all')
111 user_log = relationship('UserLog', cascade='all')
112 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
112 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
113
113
114 repositories = relationship('Repository')
114 repositories = relationship('Repository')
115 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
115 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
116
116
117 @property
117 @property
118 def full_contact(self):
118 def full_contact(self):
119 return '%s %s <%s>' % (self.name, self.lastname, self.email)
119 return '%s %s <%s>' % (self.name, self.lastname, self.email)
120
120
121
121
122 @property
122 @property
123 def is_admin(self):
123 def is_admin(self):
124 return self.admin
124 return self.admin
125
125
126 def __repr__(self):
126 def __repr__(self):
127 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
127 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
128 self.user_id, self.username)
128 self.user_id, self.username)
129
129
130 def update_lastlogin(self):
130 def update_lastlogin(self):
131 """Update user lastlogin"""
131 """Update user lastlogin"""
132
132
133 try:
133 try:
134 session = Session.object_session(self)
134 session = Session.object_session(self)
135 self.last_login = datetime.datetime.now()
135 self.last_login = datetime.datetime.now()
136 session.add(self)
136 session.add(self)
137 session.commit()
137 session.commit()
138 log.debug('updated user %s lastlogin', self.username)
138 log.debug('updated user %s lastlogin', self.username)
139 except (DatabaseError,):
139 except (DatabaseError,):
140 session.rollback()
140 session.rollback()
141
141
142
142
143 class UserLog(Base, BaseModel):
143 class UserLog(Base, BaseModel):
144 __tablename__ = 'user_logs'
144 __tablename__ = 'user_logs'
145 __table_args__ = {'useexisting':True}
145 __table_args__ = {'useexisting':True}
146 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
146 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
147 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
147 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
148 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
148 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
149 repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
149 repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
150 user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
150 user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
151 action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
151 action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
152 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
152 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
153
153
154 @property
154 @property
155 def action_as_day(self):
155 def action_as_day(self):
156 return date(*self.action_date.timetuple()[:3])
156 return date(*self.action_date.timetuple()[:3])
157
157
158 user = relationship('User')
158 user = relationship('User')
159 repository = relationship('Repository')
159 repository = relationship('Repository')
160
160
161
161
162 class UsersGroup(Base, BaseModel):
162 class UsersGroup(Base, BaseModel):
163 __tablename__ = 'users_groups'
163 __tablename__ = 'users_groups'
164 __table_args__ = {'useexisting':True}
164 __table_args__ = {'useexisting':True}
165
165
166 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
166 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
167 users_group_name = Column("users_group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
167 users_group_name = Column("users_group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
168 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
168 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
169
169
170 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
170 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
171
171
172 class UsersGroupMember(Base, BaseModel):
172 class UsersGroupMember(Base, BaseModel):
173 __tablename__ = 'users_groups_members'
173 __tablename__ = 'users_groups_members'
174 __table_args__ = {'useexisting':True}
174 __table_args__ = {'useexisting':True}
175
175
176 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
176 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
177 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
177 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
178 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
178 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
179
179
180 user = relationship('User', lazy='joined')
180 user = relationship('User', lazy='joined')
181 users_group = relationship('UsersGroup')
181 users_group = relationship('UsersGroup')
182
182
183 def __init__(self, gr_id, u_id):
183 def __init__(self, gr_id, u_id):
184 self.users_group_id = gr_id
184 self.users_group_id = gr_id
185 self.user_id = u_id
185 self.user_id = u_id
186
186
187 class Repository(Base, BaseModel):
187 class Repository(Base, BaseModel):
188 __tablename__ = 'repositories'
188 __tablename__ = 'repositories'
189 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
189 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
190 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
190 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
191 repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
191 repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
192 repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
192 repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
193 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
193 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
194 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
194 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
195 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
195 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
196 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
196 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
197 description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
197 description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
198 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
198 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
199 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
199 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
200
200
201 user = relationship('User')
201 user = relationship('User')
202 fork = relationship('Repository', remote_side=repo_id)
202 fork = relationship('Repository', remote_side=repo_id)
203 group = relationship('Group')
203 group = relationship('Group')
204 repo_to_perm = relationship('RepoToPerm', cascade='all')
204 repo_to_perm = relationship('RepoToPerm', cascade='all')
205 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
205 stats = relationship('Statistics', cascade='all', uselist=False)
206 stats = relationship('Statistics', cascade='all', uselist=False)
206
207
207 repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
208 repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
208
209
209 logs = relationship('UserLog', cascade='all')
210 logs = relationship('UserLog', cascade='all')
210
211
211 def __repr__(self):
212 def __repr__(self):
212 return "<%s('%s:%s')>" % (self.__class__.__name__,
213 return "<%s('%s:%s')>" % (self.__class__.__name__,
213 self.repo_id, self.repo_name)
214 self.repo_id, self.repo_name)
214
215
215 class Group(Base, BaseModel):
216 class Group(Base, BaseModel):
216 __tablename__ = 'groups'
217 __tablename__ = 'groups'
217 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
218 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
218
219
219 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
220 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
220 group_name = Column("group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
221 group_name = Column("group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
221 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
222 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
222
223
223 parent_group = relationship('Group', remote_side=group_id)
224 parent_group = relationship('Group', remote_side=group_id)
224
225
225
226
226 def __init__(self, group_name='', parent_group=None):
227 def __init__(self, group_name='', parent_group=None):
227 self.group_name = group_name
228 self.group_name = group_name
228 self.parent_group = parent_group
229 self.parent_group = parent_group
229
230
230 def __repr__(self):
231 def __repr__(self):
231 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
232 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
232 self.group_name)
233 self.group_name)
233
234
234 class Permission(Base, BaseModel):
235 class Permission(Base, BaseModel):
235 __tablename__ = 'permissions'
236 __tablename__ = 'permissions'
236 __table_args__ = {'useexisting':True}
237 __table_args__ = {'useexisting':True}
237 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
238 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
238 permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
239 permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
239 permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
240 permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
240
241
241 def __repr__(self):
242 def __repr__(self):
242 return "<%s('%s:%s')>" % (self.__class__.__name__,
243 return "<%s('%s:%s')>" % (self.__class__.__name__,
243 self.permission_id, self.permission_name)
244 self.permission_id, self.permission_name)
244
245
245 class RepoToPerm(Base, BaseModel):
246 class RepoToPerm(Base, BaseModel):
246 __tablename__ = 'repo_to_perm'
247 __tablename__ = 'repo_to_perm'
247 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
248 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
248 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
249 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
249 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
250 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
250 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
251 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
251 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
252 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
252
253
253 user = relationship('User')
254 user = relationship('User')
254 permission = relationship('Permission')
255 permission = relationship('Permission')
255 repository = relationship('Repository')
256 repository = relationship('Repository')
256
257
257 class UserToPerm(Base, BaseModel):
258 class UserToPerm(Base, BaseModel):
258 __tablename__ = 'user_to_perm'
259 __tablename__ = 'user_to_perm'
259 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
260 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
260 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
261 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
261 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
262 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
262 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
263 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
263
264
264 user = relationship('User')
265 user = relationship('User')
265 permission = relationship('Permission')
266 permission = relationship('Permission')
266
267
267
268
268 class UsersGroupToPerm(Base, BaseModel):
269 class UsersGroupToPerm(Base, BaseModel):
269 __tablename__ = 'users_group_to_perm'
270 __tablename__ = 'users_group_to_perm'
270 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
271 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
271 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
272 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
272 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
273 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
273 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
274 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
274 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
275 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
275
276
276 users_group = relationship('UsersGroup')
277 users_group = relationship('UsersGroup')
277 permission = relationship('Permission')
278 permission = relationship('Permission')
278 repository = relationship('Repository')
279 repository = relationship('Repository')
279
280
280 class GroupToPerm(Base, BaseModel):
281 class GroupToPerm(Base, BaseModel):
281 __tablename__ = 'group_to_perm'
282 __tablename__ = 'group_to_perm'
282 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
283 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
283
284
284 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
285 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
285 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
286 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
286 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
287 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
287 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
288 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
288
289
289 user = relationship('User')
290 user = relationship('User')
290 permission = relationship('Permission')
291 permission = relationship('Permission')
291 group = relationship('Group')
292 group = relationship('Group')
292
293
293 class Statistics(Base, BaseModel):
294 class Statistics(Base, BaseModel):
294 __tablename__ = 'statistics'
295 __tablename__ = 'statistics'
295 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
296 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
296 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
297 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
297 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
298 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
298 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
299 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
299 commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
300 commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
300 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
301 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
301 languages = Column("languages", LargeBinary(), nullable=False)#JSON data
302 languages = Column("languages", LargeBinary(), nullable=False)#JSON data
302
303
303 repository = relationship('Repository', single_parent=True)
304 repository = relationship('Repository', single_parent=True)
304
305
305 class UserFollowing(Base, BaseModel):
306 class UserFollowing(Base, BaseModel):
306 __tablename__ = 'user_followings'
307 __tablename__ = 'user_followings'
307 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
308 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
308 UniqueConstraint('user_id', 'follows_user_id')
309 UniqueConstraint('user_id', 'follows_user_id')
309 , {'useexisting':True})
310 , {'useexisting':True})
310
311
311 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
312 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
312 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
313 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
313 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
314 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
314 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
315 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
315
316
316 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
317 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
317
318
318 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
319 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
319 follows_repository = relationship('Repository', order_by='Repository.repo_name')
320 follows_repository = relationship('Repository', order_by='Repository.repo_name')
320
321
321 class CacheInvalidation(Base, BaseModel):
322 class CacheInvalidation(Base, BaseModel):
322 __tablename__ = 'cache_invalidation'
323 __tablename__ = 'cache_invalidation'
323 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
324 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
324 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
325 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
325 cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
328 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
328
329
329
330
330 def __init__(self, cache_key, cache_args=''):
331 def __init__(self, cache_key, cache_args=''):
331 self.cache_key = cache_key
332 self.cache_key = cache_key
332 self.cache_args = cache_args
333 self.cache_args = cache_args
333 self.cache_active = False
334 self.cache_active = False
334
335
335 def __repr__(self):
336 def __repr__(self):
336 return "<%s('%s:%s')>" % (self.__class__.__name__,
337 return "<%s('%s:%s')>" % (self.__class__.__name__,
337 self.cache_id, self.cache_key)
338 self.cache_id, self.cache_key)
338
339
339 class DbMigrateVersion(Base, BaseModel):
340 class DbMigrateVersion(Base, BaseModel):
340 __tablename__ = 'db_migrate_version'
341 __tablename__ = 'db_migrate_version'
341 __table_args__ = {'useexisting':True}
342 __table_args__ = {'useexisting':True}
342 repository_id = Column('repository_id', String(250), primary_key=True)
343 repository_id = Column('repository_id', String(250), primary_key=True)
343 repository_path = Column('repository_path', Text)
344 repository_path = Column('repository_path', Text)
344 version = Column('version', Integer)
345 version = Column('version', Integer)
345
346
@@ -1,549 +1,552 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
32
33 import rhodecode.lib.helpers as h
33 import rhodecode.lib.helpers as h
34 from rhodecode.lib.auth import authenticate, get_crypt_password
34 from rhodecode.lib.auth import authenticate, get_crypt_password
35 from rhodecode.lib.exceptions import LdapImportError
35 from rhodecode.lib.exceptions import LdapImportError
36 from rhodecode.model import meta
36 from rhodecode.model import meta
37 from rhodecode.model.user import UserModel
37 from rhodecode.model.user import UserModel
38 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.users_group import UsersGroupModel
39 from rhodecode.model.users_group import UsersGroupModel
40 from rhodecode.model.db import User, UsersGroup
40 from rhodecode.model.db import User, UsersGroup
41 from rhodecode import BACKENDS
41 from rhodecode import BACKENDS
42
42
43 from webhelpers.pylonslib.secure_form import authentication_token
43 from webhelpers.pylonslib.secure_form import authentication_token
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47 #this is needed to translate the messages using _() in validators
47 #this is needed to translate the messages using _() in validators
48 class State_obj(object):
48 class State_obj(object):
49 _ = staticmethod(_)
49 _ = staticmethod(_)
50
50
51 #===============================================================================
51 #===============================================================================
52 # VALIDATORS
52 # VALIDATORS
53 #===============================================================================
53 #===============================================================================
54 class ValidAuthToken(formencode.validators.FancyValidator):
54 class ValidAuthToken(formencode.validators.FancyValidator):
55 messages = {'invalid_token':_('Token mismatch')}
55 messages = {'invalid_token':_('Token mismatch')}
56
56
57 def validate_python(self, value, state):
57 def validate_python(self, value, state):
58
58
59 if value != authentication_token():
59 if value != authentication_token():
60 raise formencode.Invalid(self.message('invalid_token', state,
60 raise formencode.Invalid(self.message('invalid_token', state,
61 search_number=value), value, state)
61 search_number=value), value, state)
62
62
63 def ValidUsername(edit, old_data):
63 def ValidUsername(edit, old_data):
64 class _ValidUsername(formencode.validators.FancyValidator):
64 class _ValidUsername(formencode.validators.FancyValidator):
65
65
66 def validate_python(self, value, state):
66 def validate_python(self, value, state):
67 if value in ['default', 'new_user']:
67 if value in ['default', 'new_user']:
68 raise formencode.Invalid(_('Invalid username'), value, state)
68 raise formencode.Invalid(_('Invalid username'), value, state)
69 #check if user is unique
69 #check if user is unique
70 old_un = None
70 old_un = None
71 if edit:
71 if edit:
72 old_un = UserModel().get(old_data.get('user_id')).username
72 old_un = UserModel().get(old_data.get('user_id')).username
73
73
74 if old_un != value or not edit:
74 if old_un != value or not edit:
75 if UserModel().get_by_username(value, cache=False,
75 if UserModel().get_by_username(value, cache=False,
76 case_insensitive=True):
76 case_insensitive=True):
77 raise formencode.Invalid(_('This username already exists') ,
77 raise formencode.Invalid(_('This username already exists') ,
78 value, state)
78 value, state)
79
79
80
80
81 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
81 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
82 raise formencode.Invalid(_('Username may only contain '
82 raise formencode.Invalid(_('Username may only contain '
83 'alphanumeric characters underscores, '
83 'alphanumeric characters underscores, '
84 'periods or dashes and must begin with '
84 'periods or dashes and must begin with '
85 'alphanumeric character'),
85 'alphanumeric character'),
86 value, state)
86 value, state)
87
87
88
88
89
89
90 return _ValidUsername
90 return _ValidUsername
91
91
92
92
93
93
94 def ValidUsersGroup(edit, old_data):
94 def ValidUsersGroup(edit, old_data):
95
95
96 class _ValidUsersGroup(formencode.validators.FancyValidator):
96 class _ValidUsersGroup(formencode.validators.FancyValidator):
97
97
98 def validate_python(self, value, state):
98 def validate_python(self, value, state):
99 if value in ['default']:
99 if value in ['default']:
100 raise formencode.Invalid(_('Invalid group name'), value, state)
100 raise formencode.Invalid(_('Invalid group name'), value, state)
101 #check if group is unique
101 #check if group is unique
102 old_ugname = None
102 old_ugname = None
103 if edit:
103 if edit:
104 old_ugname = UsersGroupModel()\
104 old_ugname = UsersGroupModel()\
105 .get(old_data.get('users_group_id')).users_group_name
105 .get(old_data.get('users_group_id')).users_group_name
106
106
107 if old_ugname != value or not edit:
107 if old_ugname != value or not edit:
108 if UsersGroupModel().get_by_groupname(value, cache=False,
108 if UsersGroupModel().get_by_groupname(value, cache=False,
109 case_insensitive=True):
109 case_insensitive=True):
110 raise formencode.Invalid(_('This users group already exists') ,
110 raise formencode.Invalid(_('This users group already exists') ,
111 value, state)
111 value, state)
112
112
113
113
114 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
114 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
115 raise formencode.Invalid(_('Group name may only contain '
115 raise formencode.Invalid(_('Group name may only contain '
116 'alphanumeric characters underscores, '
116 'alphanumeric characters underscores, '
117 'periods or dashes and must begin with '
117 'periods or dashes and must begin with '
118 'alphanumeric character'),
118 'alphanumeric character'),
119 value, state)
119 value, state)
120
120
121 return _ValidUsersGroup
121 return _ValidUsersGroup
122
122
123
123
124
124
125 class ValidPassword(formencode.validators.FancyValidator):
125 class ValidPassword(formencode.validators.FancyValidator):
126
126
127 def to_python(self, value, state):
127 def to_python(self, value, state):
128
128
129 if value:
129 if value:
130
130
131 if value.get('password'):
131 if value.get('password'):
132 try:
132 try:
133 value['password'] = get_crypt_password(value['password'])
133 value['password'] = get_crypt_password(value['password'])
134 except UnicodeEncodeError:
134 except UnicodeEncodeError:
135 e_dict = {'password':_('Invalid characters in password')}
135 e_dict = {'password':_('Invalid characters in password')}
136 raise formencode.Invalid('', value, state, error_dict=e_dict)
136 raise formencode.Invalid('', value, state, error_dict=e_dict)
137
137
138 if value.get('password_confirmation'):
138 if value.get('password_confirmation'):
139 try:
139 try:
140 value['password_confirmation'] = \
140 value['password_confirmation'] = \
141 get_crypt_password(value['password_confirmation'])
141 get_crypt_password(value['password_confirmation'])
142 except UnicodeEncodeError:
142 except UnicodeEncodeError:
143 e_dict = {'password_confirmation':_('Invalid characters in password')}
143 e_dict = {'password_confirmation':_('Invalid characters in password')}
144 raise formencode.Invalid('', value, state, error_dict=e_dict)
144 raise formencode.Invalid('', value, state, error_dict=e_dict)
145
145
146 if value.get('new_password'):
146 if value.get('new_password'):
147 try:
147 try:
148 value['new_password'] = \
148 value['new_password'] = \
149 get_crypt_password(value['new_password'])
149 get_crypt_password(value['new_password'])
150 except UnicodeEncodeError:
150 except UnicodeEncodeError:
151 e_dict = {'new_password':_('Invalid characters in password')}
151 e_dict = {'new_password':_('Invalid characters in password')}
152 raise formencode.Invalid('', value, state, error_dict=e_dict)
152 raise formencode.Invalid('', value, state, error_dict=e_dict)
153
153
154 return value
154 return value
155
155
156 class ValidPasswordsMatch(formencode.validators.FancyValidator):
156 class ValidPasswordsMatch(formencode.validators.FancyValidator):
157
157
158 def validate_python(self, value, state):
158 def validate_python(self, value, state):
159
159
160 if value['password'] != value['password_confirmation']:
160 if value['password'] != value['password_confirmation']:
161 e_dict = {'password_confirmation':
161 e_dict = {'password_confirmation':
162 _('Password do not match')}
162 _('Password do not match')}
163 raise formencode.Invalid('', value, state, error_dict=e_dict)
163 raise formencode.Invalid('', value, state, error_dict=e_dict)
164
164
165 class ValidAuth(formencode.validators.FancyValidator):
165 class ValidAuth(formencode.validators.FancyValidator):
166 messages = {
166 messages = {
167 'invalid_password':_('invalid password'),
167 'invalid_password':_('invalid password'),
168 'invalid_login':_('invalid user name'),
168 'invalid_login':_('invalid user name'),
169 'disabled_account':_('Your account is disabled')
169 'disabled_account':_('Your account is disabled')
170
170
171 }
171 }
172 #error mapping
172 #error mapping
173 e_dict = {'username':messages['invalid_login'],
173 e_dict = {'username':messages['invalid_login'],
174 'password':messages['invalid_password']}
174 'password':messages['invalid_password']}
175 e_dict_disable = {'username':messages['disabled_account']}
175 e_dict_disable = {'username':messages['disabled_account']}
176
176
177 def validate_python(self, value, state):
177 def validate_python(self, value, state):
178 password = value['password']
178 password = value['password']
179 username = value['username']
179 username = value['username']
180 user = UserModel().get_by_username(username)
180 user = UserModel().get_by_username(username)
181
181
182 if authenticate(username, password):
182 if authenticate(username, password):
183 return value
183 return value
184 else:
184 else:
185 if user and user.active is False:
185 if user and user.active is False:
186 log.warning('user %s is disabled', username)
186 log.warning('user %s is disabled', username)
187 raise formencode.Invalid(self.message('disabled_account',
187 raise formencode.Invalid(self.message('disabled_account',
188 state=State_obj),
188 state=State_obj),
189 value, state,
189 value, state,
190 error_dict=self.e_dict_disable)
190 error_dict=self.e_dict_disable)
191 else:
191 else:
192 log.warning('user %s not authenticated', username)
192 log.warning('user %s not authenticated', username)
193 raise formencode.Invalid(self.message('invalid_password',
193 raise formencode.Invalid(self.message('invalid_password',
194 state=State_obj), value, state,
194 state=State_obj), value, state,
195 error_dict=self.e_dict)
195 error_dict=self.e_dict)
196
196
197 class ValidRepoUser(formencode.validators.FancyValidator):
197 class ValidRepoUser(formencode.validators.FancyValidator):
198
198
199 def to_python(self, value, state):
199 def to_python(self, value, state):
200 sa = meta.Session()
200 sa = meta.Session()
201 try:
201 try:
202 self.user_db = sa.query(User)\
202 self.user_db = sa.query(User)\
203 .filter(User.active == True)\
203 .filter(User.active == True)\
204 .filter(User.username == value).one()
204 .filter(User.username == value).one()
205 except Exception:
205 except Exception:
206 raise formencode.Invalid(_('This username is not valid'),
206 raise formencode.Invalid(_('This username is not valid'),
207 value, state)
207 value, state)
208 finally:
208 finally:
209 meta.Session.remove()
209 meta.Session.remove()
210
210
211 return self.user_db.user_id
211 return self.user_db.user_id
212
212
213 def ValidRepoName(edit, old_data):
213 def ValidRepoName(edit, old_data):
214 class _ValidRepoName(formencode.validators.FancyValidator):
214 class _ValidRepoName(formencode.validators.FancyValidator):
215
215
216 def to_python(self, value, state):
216 def to_python(self, value, state):
217 slug = h.repo_name_slug(value)
217 slug = h.repo_name_slug(value)
218 if slug in ['_admin']:
218 if slug in ['_admin']:
219 raise formencode.Invalid(_('This repository name is disallowed'),
219 raise formencode.Invalid(_('This repository name is disallowed'),
220 value, state)
220 value, state)
221 if old_data.get('repo_name') != value or not edit:
221 if old_data.get('repo_name') != value or not edit:
222 if RepoModel().get_by_repo_name(slug, cache=False):
222 if RepoModel().get_by_repo_name(slug, cache=False):
223 raise formencode.Invalid(_('This repository already exists') ,
223 raise formencode.Invalid(_('This repository already exists') ,
224 value, state)
224 value, state)
225 return slug
225 return slug
226
226
227
227
228 return _ValidRepoName
228 return _ValidRepoName
229
229
230 def ValidForkType(old_data):
230 def ValidForkType(old_data):
231 class _ValidForkType(formencode.validators.FancyValidator):
231 class _ValidForkType(formencode.validators.FancyValidator):
232
232
233 def to_python(self, value, state):
233 def to_python(self, value, state):
234 if old_data['repo_type'] != value:
234 if old_data['repo_type'] != value:
235 raise formencode.Invalid(_('Fork have to be the same type as original'),
235 raise formencode.Invalid(_('Fork have to be the same type as original'),
236 value, state)
236 value, state)
237 return value
237 return value
238 return _ValidForkType
238 return _ValidForkType
239
239
240 class ValidPerms(formencode.validators.FancyValidator):
240 class ValidPerms(formencode.validators.FancyValidator):
241 messages = {'perm_new_member_name':_('This username or users group name'
241 messages = {'perm_new_member_name':_('This username or users group name'
242 ' is not valid')}
242 ' is not valid')}
243
243
244 def to_python(self, value, state):
244 def to_python(self, value, state):
245 perms_update = []
245 perms_update = []
246 perms_new = []
246 perms_new = []
247 #build a list of permission to update and new permission to create
247 #build a list of permission to update and new permission to create
248 for k, v in value.items():
248 for k, v in value.items():
249 if k.startswith('perm_'):
249 #means new added member to permissions
250 if k.startswith('perm_new_member'):
250 if k.startswith('perm_new_member'):
251 #means new added member to permissions
251 new_perm = value.get('perm_new_member', False)
252 new_perm = value.get('perm_new_member', False)
252 new_member = value.get('perm_new_member_name', False)
253 new_member = value.get('perm_new_member_name', False)
253 new_type = value.get('perm_new_member_type')
254 new_type = value.get('perm_new_member_type')
255
254
256 if new_member and new_perm:
255 if new_member and new_perm:
257 if (new_member, new_perm, new_type) not in perms_new:
256 if (new_member, new_perm, new_type) not in perms_new:
258 perms_new.append((new_member, new_perm, new_type))
257 perms_new.append((new_member, new_perm, new_type))
259 else:
258 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
260 usr = k[5:]
259 member = k[7:]
261 t = 'user'
260 t = {'u':'user',
262 if usr == 'default':
261 'g':'users_group'}[k[0]]
263 if value['private']:
262 if member == 'default':
264 #set none for default when updating to private repo
263 if value['private']:
265 v = 'repository.none'
264 #set none for default when updating to private repo
266 perms_update.append((usr, v, t))
265 v = 'repository.none'
266 perms_update.append((member, v, t))
267
267 value['perms_updates'] = perms_update
268 value['perms_updates'] = perms_update
268 value['perms_new'] = perms_new
269 value['perms_new'] = perms_new
269
270
270 #update permissions
271 #update permissions
271 sa = meta.Session
272 sa = meta.Session
272 for k, v, t in perms_new:
273 for k, v, t in perms_new:
273 try:
274 try:
274 if t is 'user':
275 if t is 'user':
275 self.user_db = sa.query(User)\
276 self.user_db = sa.query(User)\
276 .filter(User.active == True)\
277 .filter(User.active == True)\
277 .filter(User.username == k).one()
278 .filter(User.username == k).one()
278 if t is 'users_group':
279 if t is 'users_group':
279 self.user_db = sa.query(UsersGroup)\
280 self.user_db = sa.query(UsersGroup)\
280 .filter(UsersGroup.users_group_active == True)\
281 .filter(UsersGroup.users_group_active == True)\
281 .filter(UsersGroup.users_group_name == k).one()
282 .filter(UsersGroup.users_group_name == k).one()
282
283
283 except Exception:
284 except Exception:
284 msg = self.message('perm_new_member_name',
285 msg = self.message('perm_new_member_name',
285 state=State_obj)
286 state=State_obj)
286 raise formencode.Invalid(msg, value, state,
287 raise formencode.Invalid(msg, value, state,
287 error_dict={'perm_new_member_name':msg})
288 error_dict={'perm_new_member_name':msg})
288 return value
289 return value
289
290
290 class ValidSettings(formencode.validators.FancyValidator):
291 class ValidSettings(formencode.validators.FancyValidator):
291
292
292 def to_python(self, value, state):
293 def to_python(self, value, state):
293 #settings form can't edit user
294 #settings form can't edit user
294 if value.has_key('user'):
295 if value.has_key('user'):
295 del['value']['user']
296 del['value']['user']
296
297
297 return value
298 return value
298
299
299 class ValidPath(formencode.validators.FancyValidator):
300 class ValidPath(formencode.validators.FancyValidator):
300 def to_python(self, value, state):
301 def to_python(self, value, state):
301
302
302 if not os.path.isdir(value):
303 if not os.path.isdir(value):
303 msg = _('This is not a valid path')
304 msg = _('This is not a valid path')
304 raise formencode.Invalid(msg, value, state,
305 raise formencode.Invalid(msg, value, state,
305 error_dict={'paths_root_path':msg})
306 error_dict={'paths_root_path':msg})
306 return value
307 return value
307
308
308 def UniqSystemEmail(old_data):
309 def UniqSystemEmail(old_data):
309 class _UniqSystemEmail(formencode.validators.FancyValidator):
310 class _UniqSystemEmail(formencode.validators.FancyValidator):
310 def to_python(self, value, state):
311 def to_python(self, value, state):
311 value = value.lower()
312 value = value.lower()
312 if old_data.get('email') != value:
313 if old_data.get('email') != value:
313 sa = meta.Session()
314 sa = meta.Session()
314 try:
315 try:
315 user = sa.query(User).filter(User.email == value).scalar()
316 user = sa.query(User).filter(User.email == value).scalar()
316 if user:
317 if user:
317 raise formencode.Invalid(_("This e-mail address is already taken") ,
318 raise formencode.Invalid(_("This e-mail address is already taken") ,
318 value, state)
319 value, state)
319 finally:
320 finally:
320 meta.Session.remove()
321 meta.Session.remove()
321
322
322 return value
323 return value
323
324
324 return _UniqSystemEmail
325 return _UniqSystemEmail
325
326
326 class ValidSystemEmail(formencode.validators.FancyValidator):
327 class ValidSystemEmail(formencode.validators.FancyValidator):
327 def to_python(self, value, state):
328 def to_python(self, value, state):
328 value = value.lower()
329 value = value.lower()
329 sa = meta.Session
330 sa = meta.Session
330 try:
331 try:
331 user = sa.query(User).filter(User.email == value).scalar()
332 user = sa.query(User).filter(User.email == value).scalar()
332 if user is None:
333 if user is None:
333 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
334 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
334 value, state)
335 value, state)
335 finally:
336 finally:
336 meta.Session.remove()
337 meta.Session.remove()
337
338
338 return value
339 return value
339
340
340 class LdapLibValidator(formencode.validators.FancyValidator):
341 class LdapLibValidator(formencode.validators.FancyValidator):
341
342
342 def to_python(self, value, state):
343 def to_python(self, value, state):
343
344
344 try:
345 try:
345 import ldap
346 import ldap
346 except ImportError:
347 except ImportError:
347 raise LdapImportError
348 raise LdapImportError
348 return value
349 return value
349
350
350 class AttrLoginValidator(formencode.validators.FancyValidator):
351 class AttrLoginValidator(formencode.validators.FancyValidator):
351
352
352 def to_python(self, value, state):
353 def to_python(self, value, state):
353
354
354 if not value or not isinstance(value, (str, unicode)):
355 if not value or not isinstance(value, (str, unicode)):
355 raise formencode.Invalid(_("The LDAP Login attribute of the CN must be specified "
356 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
356 "- this is the name of the attribute that is equivalent to 'username'"),
357 "must be specified - this is the name "
358 "of the attribute that is equivalent "
359 "to 'username'"),
357 value, state)
360 value, state)
358
361
359 return value
362 return value
360
363
361 #===============================================================================
364 #===============================================================================
362 # FORMS
365 # FORMS
363 #===============================================================================
366 #===============================================================================
364 class LoginForm(formencode.Schema):
367 class LoginForm(formencode.Schema):
365 allow_extra_fields = True
368 allow_extra_fields = True
366 filter_extra_fields = True
369 filter_extra_fields = True
367 username = UnicodeString(
370 username = UnicodeString(
368 strip=True,
371 strip=True,
369 min=1,
372 min=1,
370 not_empty=True,
373 not_empty=True,
371 messages={
374 messages={
372 'empty':_('Please enter a login'),
375 'empty':_('Please enter a login'),
373 'tooShort':_('Enter a value %(min)i characters long or more')}
376 'tooShort':_('Enter a value %(min)i characters long or more')}
374 )
377 )
375
378
376 password = UnicodeString(
379 password = UnicodeString(
377 strip=True,
380 strip=True,
378 min=6,
381 min=6,
379 not_empty=True,
382 not_empty=True,
380 messages={
383 messages={
381 'empty':_('Please enter a password'),
384 'empty':_('Please enter a password'),
382 'tooShort':_('Enter %(min)i characters or more')}
385 'tooShort':_('Enter %(min)i characters or more')}
383 )
386 )
384
387
385
388
386 #chained validators have access to all data
389 #chained validators have access to all data
387 chained_validators = [ValidAuth]
390 chained_validators = [ValidAuth]
388
391
389 def UserForm(edit=False, old_data={}):
392 def UserForm(edit=False, old_data={}):
390 class _UserForm(formencode.Schema):
393 class _UserForm(formencode.Schema):
391 allow_extra_fields = True
394 allow_extra_fields = True
392 filter_extra_fields = True
395 filter_extra_fields = True
393 username = All(UnicodeString(strip=True, min=1, not_empty=True),
396 username = All(UnicodeString(strip=True, min=1, not_empty=True),
394 ValidUsername(edit, old_data))
397 ValidUsername(edit, old_data))
395 if edit:
398 if edit:
396 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
399 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
397 admin = StringBoolean(if_missing=False)
400 admin = StringBoolean(if_missing=False)
398 else:
401 else:
399 password = All(UnicodeString(strip=True, min=6, not_empty=True))
402 password = All(UnicodeString(strip=True, min=6, not_empty=True))
400 active = StringBoolean(if_missing=False)
403 active = StringBoolean(if_missing=False)
401 name = UnicodeString(strip=True, min=1, not_empty=True)
404 name = UnicodeString(strip=True, min=1, not_empty=True)
402 lastname = UnicodeString(strip=True, min=1, not_empty=True)
405 lastname = UnicodeString(strip=True, min=1, not_empty=True)
403 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
406 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
404
407
405 chained_validators = [ValidPassword]
408 chained_validators = [ValidPassword]
406
409
407 return _UserForm
410 return _UserForm
408
411
409
412
410 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
413 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
411 class _UsersGroupForm(formencode.Schema):
414 class _UsersGroupForm(formencode.Schema):
412 allow_extra_fields = True
415 allow_extra_fields = True
413 filter_extra_fields = True
416 filter_extra_fields = True
414
417
415 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
418 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
416 ValidUsersGroup(edit, old_data))
419 ValidUsersGroup(edit, old_data))
417
420
418 users_group_active = StringBoolean(if_missing=False)
421 users_group_active = StringBoolean(if_missing=False)
419
422
420 if edit:
423 if edit:
421 users_group_members = OneOf(available_members, hideList=False,
424 users_group_members = OneOf(available_members, hideList=False,
422 testValueList=True,
425 testValueList=True,
423 if_missing=None, not_empty=False)
426 if_missing=None, not_empty=False)
424
427
425 return _UsersGroupForm
428 return _UsersGroupForm
426
429
427 def RegisterForm(edit=False, old_data={}):
430 def RegisterForm(edit=False, old_data={}):
428 class _RegisterForm(formencode.Schema):
431 class _RegisterForm(formencode.Schema):
429 allow_extra_fields = True
432 allow_extra_fields = True
430 filter_extra_fields = True
433 filter_extra_fields = True
431 username = All(ValidUsername(edit, old_data),
434 username = All(ValidUsername(edit, old_data),
432 UnicodeString(strip=True, min=1, not_empty=True))
435 UnicodeString(strip=True, min=1, not_empty=True))
433 password = All(UnicodeString(strip=True, min=6, not_empty=True))
436 password = All(UnicodeString(strip=True, min=6, not_empty=True))
434 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
437 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
435 active = StringBoolean(if_missing=False)
438 active = StringBoolean(if_missing=False)
436 name = UnicodeString(strip=True, min=1, not_empty=True)
439 name = UnicodeString(strip=True, min=1, not_empty=True)
437 lastname = UnicodeString(strip=True, min=1, not_empty=True)
440 lastname = UnicodeString(strip=True, min=1, not_empty=True)
438 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
441 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
439
442
440 chained_validators = [ValidPasswordsMatch, ValidPassword]
443 chained_validators = [ValidPasswordsMatch, ValidPassword]
441
444
442 return _RegisterForm
445 return _RegisterForm
443
446
444 def PasswordResetForm():
447 def PasswordResetForm():
445 class _PasswordResetForm(formencode.Schema):
448 class _PasswordResetForm(formencode.Schema):
446 allow_extra_fields = True
449 allow_extra_fields = True
447 filter_extra_fields = True
450 filter_extra_fields = True
448 email = All(ValidSystemEmail(), Email(not_empty=True))
451 email = All(ValidSystemEmail(), Email(not_empty=True))
449 return _PasswordResetForm
452 return _PasswordResetForm
450
453
451 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
454 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
452 class _RepoForm(formencode.Schema):
455 class _RepoForm(formencode.Schema):
453 allow_extra_fields = True
456 allow_extra_fields = True
454 filter_extra_fields = False
457 filter_extra_fields = False
455 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
458 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
456 ValidRepoName(edit, old_data))
459 ValidRepoName(edit, old_data))
457 description = UnicodeString(strip=True, min=1, not_empty=True)
460 description = UnicodeString(strip=True, min=1, not_empty=True)
458 private = StringBoolean(if_missing=False)
461 private = StringBoolean(if_missing=False)
459 enable_statistics = StringBoolean(if_missing=False)
462 enable_statistics = StringBoolean(if_missing=False)
460 enable_downloads = StringBoolean(if_missing=False)
463 enable_downloads = StringBoolean(if_missing=False)
461 repo_type = OneOf(supported_backends)
464 repo_type = OneOf(supported_backends)
462 if edit:
465 if edit:
463 #this is repo owner
466 #this is repo owner
464 user = All(Int(not_empty=True), ValidRepoUser)
467 user = All(Int(not_empty=True), ValidRepoUser)
465
468
466 chained_validators = [ValidPerms]
469 chained_validators = [ValidPerms]
467 return _RepoForm
470 return _RepoForm
468
471
469 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
472 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
470 class _RepoForkForm(formencode.Schema):
473 class _RepoForkForm(formencode.Schema):
471 allow_extra_fields = True
474 allow_extra_fields = True
472 filter_extra_fields = False
475 filter_extra_fields = False
473 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
476 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
474 ValidRepoName(edit, old_data))
477 ValidRepoName(edit, old_data))
475 description = UnicodeString(strip=True, min=1, not_empty=True)
478 description = UnicodeString(strip=True, min=1, not_empty=True)
476 private = StringBoolean(if_missing=False)
479 private = StringBoolean(if_missing=False)
477 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
480 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
478 return _RepoForkForm
481 return _RepoForkForm
479
482
480 def RepoSettingsForm(edit=False, old_data={}):
483 def RepoSettingsForm(edit=False, old_data={}):
481 class _RepoForm(formencode.Schema):
484 class _RepoForm(formencode.Schema):
482 allow_extra_fields = True
485 allow_extra_fields = True
483 filter_extra_fields = False
486 filter_extra_fields = False
484 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
487 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
485 ValidRepoName(edit, old_data))
488 ValidRepoName(edit, old_data))
486 description = UnicodeString(strip=True, min=1, not_empty=True)
489 description = UnicodeString(strip=True, min=1, not_empty=True)
487 private = StringBoolean(if_missing=False)
490 private = StringBoolean(if_missing=False)
488
491
489 chained_validators = [ValidPerms, ValidSettings]
492 chained_validators = [ValidPerms, ValidSettings]
490 return _RepoForm
493 return _RepoForm
491
494
492
495
493 def ApplicationSettingsForm():
496 def ApplicationSettingsForm():
494 class _ApplicationSettingsForm(formencode.Schema):
497 class _ApplicationSettingsForm(formencode.Schema):
495 allow_extra_fields = True
498 allow_extra_fields = True
496 filter_extra_fields = False
499 filter_extra_fields = False
497 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
500 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
498 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
501 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
499 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
502 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
500
503
501 return _ApplicationSettingsForm
504 return _ApplicationSettingsForm
502
505
503 def ApplicationUiSettingsForm():
506 def ApplicationUiSettingsForm():
504 class _ApplicationUiSettingsForm(formencode.Schema):
507 class _ApplicationUiSettingsForm(formencode.Schema):
505 allow_extra_fields = True
508 allow_extra_fields = True
506 filter_extra_fields = False
509 filter_extra_fields = False
507 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
510 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
508 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
511 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
509 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
512 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
510 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
513 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
511 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
514 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
512 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
515 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
513
516
514 return _ApplicationUiSettingsForm
517 return _ApplicationUiSettingsForm
515
518
516 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
519 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
517 class _DefaultPermissionsForm(formencode.Schema):
520 class _DefaultPermissionsForm(formencode.Schema):
518 allow_extra_fields = True
521 allow_extra_fields = True
519 filter_extra_fields = True
522 filter_extra_fields = True
520 overwrite_default = StringBoolean(if_missing=False)
523 overwrite_default = StringBoolean(if_missing=False)
521 anonymous = OneOf(['True', 'False'], if_missing=False)
524 anonymous = OneOf(['True', 'False'], if_missing=False)
522 default_perm = OneOf(perms_choices)
525 default_perm = OneOf(perms_choices)
523 default_register = OneOf(register_choices)
526 default_register = OneOf(register_choices)
524 default_create = OneOf(create_choices)
527 default_create = OneOf(create_choices)
525
528
526 return _DefaultPermissionsForm
529 return _DefaultPermissionsForm
527
530
528
531
529 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices):
532 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices):
530 class _LdapSettingsForm(formencode.Schema):
533 class _LdapSettingsForm(formencode.Schema):
531 allow_extra_fields = True
534 allow_extra_fields = True
532 filter_extra_fields = True
535 filter_extra_fields = True
533 pre_validators = [LdapLibValidator]
536 pre_validators = [LdapLibValidator]
534 ldap_active = StringBoolean(if_missing=False)
537 ldap_active = StringBoolean(if_missing=False)
535 ldap_host = UnicodeString(strip=True,)
538 ldap_host = UnicodeString(strip=True,)
536 ldap_port = Number(strip=True,)
539 ldap_port = Number(strip=True,)
537 ldap_ldaps = StringBoolean(if_missing=False)
540 ldap_ldaps = StringBoolean(if_missing=False)
538 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
541 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
539 ldap_dn_user = UnicodeString(strip=True,)
542 ldap_dn_user = UnicodeString(strip=True,)
540 ldap_dn_pass = UnicodeString(strip=True,)
543 ldap_dn_pass = UnicodeString(strip=True,)
541 ldap_base_dn = UnicodeString(strip=True,)
544 ldap_base_dn = UnicodeString(strip=True,)
542 ldap_filter = UnicodeString(strip=True,)
545 ldap_filter = UnicodeString(strip=True,)
543 ldap_search_scope = OneOf(search_scope_choices)
546 ldap_search_scope = OneOf(search_scope_choices)
544 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
547 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
545 ldap_attr_firstname = UnicodeString(strip=True,)
548 ldap_attr_firstname = UnicodeString(strip=True,)
546 ldap_attr_lastname = UnicodeString(strip=True,)
549 ldap_attr_lastname = UnicodeString(strip=True,)
547 ldap_attr_email = UnicodeString(strip=True,)
550 ldap_attr_email = UnicodeString(strip=True,)
548
551
549 return _LdapSettingsForm
552 return _LdapSettingsForm
@@ -1,314 +1,327 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27 import os
27 import os
28 import shutil
28 import shutil
29 import logging
29 import logging
30 import traceback
30 import traceback
31 from datetime import datetime
31 from datetime import datetime
32
32
33 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
34 from rhodecode.model.caching_query import FromCache
34 from rhodecode.model.caching_query import FromCache
35 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
35 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
36 Statistics, UsersGroup, UsersGroupToPerm
36 Statistics, UsersGroup, UsersGroupToPerm
37 from rhodecode.model.user import UserModel
37 from rhodecode.model.user import UserModel
38 from rhodecode.model.users_group import UsersGroupMember, UsersGroupModel
38 from rhodecode.model.users_group import UsersGroupMember, UsersGroupModel
39
39
40 from vcs.backends import get_backend
40 from vcs.backends import get_backend
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44 class RepoModel(BaseModel):
44 class RepoModel(BaseModel):
45
45
46 def __init__(self, sa=None):
46 def __init__(self, sa=None):
47 try:
47 try:
48 from pylons import app_globals
48 from pylons import app_globals
49 self._base_path = app_globals.base_path
49 self._base_path = app_globals.base_path
50 except:
50 except:
51 self._base_path = None
51 self._base_path = None
52
52
53 @property
53 @property
54 def base_path():
54 def base_path():
55 if self._base_path is None:
55 if self._base_path is None:
56 raise Exception('Base Path is empty, try set this after'
56 raise Exception('Base Path is empty, try set this after'
57 'class initialization when not having '
57 'class initialization when not having '
58 'app_globals available')
58 'app_globals available')
59 return self._base_path
59 return self._base_path
60
60
61 super(RepoModel, self).__init__()
61 super(RepoModel, self).__init__()
62
62
63
63
64 def get(self, repo_id, cache=False):
64 def get(self, repo_id, cache=False):
65 repo = self.sa.query(Repository)\
65 repo = self.sa.query(Repository)\
66 .filter(Repository.repo_id == repo_id)
66 .filter(Repository.repo_id == repo_id)
67
67
68 if cache:
68 if cache:
69 repo = repo.options(FromCache("sql_cache_short",
69 repo = repo.options(FromCache("sql_cache_short",
70 "get_repo_%s" % repo_id))
70 "get_repo_%s" % repo_id))
71 return repo.scalar()
71 return repo.scalar()
72
72
73
73
74 def get_by_repo_name(self, repo_name, cache=False):
74 def get_by_repo_name(self, repo_name, cache=False):
75 repo = self.sa.query(Repository)\
75 repo = self.sa.query(Repository)\
76 .filter(Repository.repo_name == repo_name)
76 .filter(Repository.repo_name == repo_name)
77
77
78 if cache:
78 if cache:
79 repo = repo.options(FromCache("sql_cache_short",
79 repo = repo.options(FromCache("sql_cache_short",
80 "get_repo_%s" % repo_name))
80 "get_repo_%s" % repo_name))
81 return repo.scalar()
81 return repo.scalar()
82
82
83 def get_users_js(self):
83 def get_users_js(self):
84
84
85 users = self.sa.query(User).filter(User.active == True).all()
85 users = self.sa.query(User).filter(User.active == True).all()
86 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
86 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
87 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
87 users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
88 u.lastname, u.username)
88 u.lastname, u.username)
89 for u in users])
89 for u in users])
90 return users_array
90 return users_array
91
91
92
92
93 def get_users_groups_js(self):
93 def get_users_groups_js(self):
94 users_groups = self.sa.query(UsersGroup)\
94 users_groups = self.sa.query(UsersGroup)\
95 .filter(UsersGroup.users_group_active == True).all()
95 .filter(UsersGroup.users_group_active == True).all()
96
96
97 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
97 g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
98
98
99 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
99 users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
100 (gr.users_group_id, gr.users_group_name,
100 (gr.users_group_id, gr.users_group_name,
101 len(gr.members))
101 len(gr.members))
102 for gr in users_groups])
102 for gr in users_groups])
103 return users_groups_array
103 return users_groups_array
104
104
105 def update(self, repo_name, form_data):
105 def update(self, repo_name, form_data):
106 try:
106 try:
107 cur_repo = self.get_by_repo_name(repo_name, cache=False)
107 cur_repo = self.get_by_repo_name(repo_name, cache=False)
108 user_model = UserModel(self.sa)
108 user_model = UserModel(self.sa)
109 users_group_model = UsersGroupModel(self.sa)
109 users_group_model = UsersGroupModel(self.sa)
110
110
111 #update permissions
111 #update permissions
112 for member, perm, member_type in form_data['perms_updates']:
112 for member, perm, member_type in form_data['perms_updates']:
113 if member_type == 'user':
113 if member_type == 'user':
114 r2p = self.sa.query(RepoToPerm)\
114 r2p = self.sa.query(RepoToPerm)\
115 .filter(RepoToPerm.user == user_model.get_by_username(member))\
115 .filter(RepoToPerm.user == user_model.get_by_username(member))\
116 .filter(RepoToPerm.repository == cur_repo)\
116 .filter(RepoToPerm.repository == cur_repo)\
117 .one()
117 .one()
118
118
119 r2p.permission = self.sa.query(Permission)\
119 r2p.permission = self.sa.query(Permission)\
120 .filter(Permission.permission_name == perm)\
120 .filter(Permission.permission_name == perm)\
121 .scalar()
121 .scalar()
122 self.sa.add(r2p)
122 self.sa.add(r2p)
123 else:
123 else:
124 g2p = self.sa.query(UsersGroupToPerm)\
124 g2p = self.sa.query(UsersGroupToPerm)\
125 .filter(UsersGroupToPerm.users_group == users_group_model.get_by_groupname(member))\
125 .filter(UsersGroupToPerm.users_group == users_group_model.get_by_groupname(member))\
126 .filter(UsersGroupToPerm.repository == cur_repo)\
126 .filter(UsersGroupToPerm.repository == cur_repo)\
127 .one()
127 .one()
128
128
129 g2p.permission = self.sa.query(Permission)\
129 g2p.permission = self.sa.query(Permission)\
130 .filter(Permission.permission_name == perm)\
130 .filter(Permission.permission_name == perm)\
131 .scalar()
131 .scalar()
132 self.sa.add(g2p)
132 self.sa.add(g2p)
133
133
134 #set new permissions
134 #set new permissions
135 for member, perm, member_type in form_data['perms_new']:
135 for member, perm, member_type in form_data['perms_new']:
136 if member_type == 'user':
136 if member_type == 'user':
137 r2p = RepoToPerm()
137 r2p = RepoToPerm()
138 r2p.repository = cur_repo
138 r2p.repository = cur_repo
139 r2p.user = user_model.get_by_username(member)
139 r2p.user = user_model.get_by_username(member)
140
140
141 r2p.permission = self.sa.query(Permission)\
141 r2p.permission = self.sa.query(Permission)\
142 .filter(Permission.permission_name == perm)\
142 .filter(Permission.permission_name == perm)\
143 .scalar()
143 .scalar()
144 self.sa.add(r2p)
144 self.sa.add(r2p)
145 else:
145 else:
146 g2p = UsersGroupToPerm()
146 g2p = UsersGroupToPerm()
147 g2p.repository = cur_repo
147 g2p.repository = cur_repo
148 g2p.users_group = users_group_model.get_by_groupname(member)
148 g2p.users_group = users_group_model.get_by_groupname(member)
149
149
150 g2p.permission = self.sa.query(Permission)\
150 g2p.permission = self.sa.query(Permission)\
151 .filter(Permission.permission_name == perm)\
151 .filter(Permission.permission_name == perm)\
152 .scalar()
152 .scalar()
153 self.sa.add(g2p)
153 self.sa.add(g2p)
154
154
155 #update current repo
155 #update current repo
156 for k, v in form_data.items():
156 for k, v in form_data.items():
157 if k == 'user':
157 if k == 'user':
158 cur_repo.user = user_model.get(v)
158 cur_repo.user = user_model.get(v)
159 else:
159 else:
160 setattr(cur_repo, k, v)
160 setattr(cur_repo, k, v)
161
161
162 self.sa.add(cur_repo)
162 self.sa.add(cur_repo)
163
163
164 if repo_name != form_data['repo_name']:
164 if repo_name != form_data['repo_name']:
165 #rename our data
165 #rename our data
166 self.__rename_repo(repo_name, form_data['repo_name'])
166 self.__rename_repo(repo_name, form_data['repo_name'])
167
167
168 self.sa.commit()
168 self.sa.commit()
169 except:
169 except:
170 log.error(traceback.format_exc())
170 log.error(traceback.format_exc())
171 self.sa.rollback()
171 self.sa.rollback()
172 raise
172 raise
173
173
174 def create(self, form_data, cur_user, just_db=False, fork=False):
174 def create(self, form_data, cur_user, just_db=False, fork=False):
175 try:
175 try:
176 if fork:
176 if fork:
177 #force str since hg doesn't go with unicode
177 #force str since hg doesn't go with unicode
178 repo_name = str(form_data['fork_name'])
178 repo_name = str(form_data['fork_name'])
179 org_name = str(form_data['repo_name'])
179 org_name = str(form_data['repo_name'])
180
180
181 else:
181 else:
182 org_name = repo_name = str(form_data['repo_name'])
182 org_name = repo_name = str(form_data['repo_name'])
183 new_repo = Repository()
183 new_repo = Repository()
184 new_repo.enable_statistics = True
184 new_repo.enable_statistics = True
185 for k, v in form_data.items():
185 for k, v in form_data.items():
186 if k == 'repo_name':
186 if k == 'repo_name':
187 v = repo_name
187 v = repo_name
188 setattr(new_repo, k, v)
188 setattr(new_repo, k, v)
189
189
190 if fork:
190 if fork:
191 parent_repo = self.sa.query(Repository)\
191 parent_repo = self.sa.query(Repository)\
192 .filter(Repository.repo_name == org_name).scalar()
192 .filter(Repository.repo_name == org_name).scalar()
193 new_repo.fork = parent_repo
193 new_repo.fork = parent_repo
194
194
195 new_repo.user_id = cur_user.user_id
195 new_repo.user_id = cur_user.user_id
196 self.sa.add(new_repo)
196 self.sa.add(new_repo)
197
197
198 #create default permission
198 #create default permission
199 repo_to_perm = RepoToPerm()
199 repo_to_perm = RepoToPerm()
200 default = 'repository.read'
200 default = 'repository.read'
201 for p in UserModel(self.sa).get_by_username('default', cache=False).user_perms:
201 for p in UserModel(self.sa).get_by_username('default', cache=False).user_perms:
202 if p.permission.permission_name.startswith('repository.'):
202 if p.permission.permission_name.startswith('repository.'):
203 default = p.permission.permission_name
203 default = p.permission.permission_name
204 break
204 break
205
205
206 default_perm = 'repository.none' if form_data['private'] else default
206 default_perm = 'repository.none' if form_data['private'] else default
207
207
208 repo_to_perm.permission_id = self.sa.query(Permission)\
208 repo_to_perm.permission_id = self.sa.query(Permission)\
209 .filter(Permission.permission_name == default_perm)\
209 .filter(Permission.permission_name == default_perm)\
210 .one().permission_id
210 .one().permission_id
211
211
212 repo_to_perm.repository_id = new_repo.repo_id
212 repo_to_perm.repository_id = new_repo.repo_id
213 repo_to_perm.user_id = UserModel(self.sa)\
213 repo_to_perm.user_id = UserModel(self.sa)\
214 .get_by_username('default', cache=False).user_id
214 .get_by_username('default', cache=False).user_id
215
215
216 self.sa.add(repo_to_perm)
216 self.sa.add(repo_to_perm)
217 self.sa.commit()
217 self.sa.commit()
218
218
219
219
220 #now automatically start following this repository as owner
220 #now automatically start following this repository as owner
221 from rhodecode.model.scm import ScmModel
221 from rhodecode.model.scm import ScmModel
222 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
222 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
223 cur_user.user_id)
223 cur_user.user_id)
224
224
225 if not just_db:
225 if not just_db:
226 self.__create_repo(repo_name, form_data['repo_type'])
226 self.__create_repo(repo_name, form_data['repo_type'])
227 except:
227 except:
228 log.error(traceback.format_exc())
228 log.error(traceback.format_exc())
229 self.sa.rollback()
229 self.sa.rollback()
230 raise
230 raise
231
231
232 def create_fork(self, form_data, cur_user):
232 def create_fork(self, form_data, cur_user):
233 from rhodecode.lib.celerylib import tasks, run_task
233 from rhodecode.lib.celerylib import tasks, run_task
234 run_task(tasks.create_repo_fork, form_data, cur_user)
234 run_task(tasks.create_repo_fork, form_data, cur_user)
235
235
236 def delete(self, repo):
236 def delete(self, repo):
237 try:
237 try:
238 self.sa.delete(repo)
238 self.sa.delete(repo)
239 self.__delete_repo(repo)
239 self.__delete_repo(repo)
240 self.sa.commit()
240 self.sa.commit()
241 except:
241 except:
242 log.error(traceback.format_exc())
242 log.error(traceback.format_exc())
243 self.sa.rollback()
243 self.sa.rollback()
244 raise
244 raise
245
245
246 def delete_perm_user(self, form_data, repo_name):
246 def delete_perm_user(self, form_data, repo_name):
247 try:
247 try:
248 self.sa.query(RepoToPerm)\
248 self.sa.query(RepoToPerm)\
249 .filter(RepoToPerm.repository \
249 .filter(RepoToPerm.repository \
250 == self.get_by_repo_name(repo_name))\
250 == self.get_by_repo_name(repo_name))\
251 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
251 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
252 self.sa.commit()
252 self.sa.commit()
253 except:
253 except:
254 log.error(traceback.format_exc())
254 log.error(traceback.format_exc())
255 self.sa.rollback()
255 self.sa.rollback()
256 raise
256 raise
257
257
258 def delete_perm_users_group(self, form_data, repo_name):
259 try:
260 self.sa.query(UsersGroupToPerm)\
261 .filter(UsersGroupToPerm.repository \
262 == self.get_by_repo_name(repo_name))\
263 .filter(UsersGroupToPerm.users_group_id \
264 == form_data['users_group_id']).delete()
265 self.sa.commit()
266 except:
267 log.error(traceback.format_exc())
268 self.sa.rollback()
269 raise
270
258 def delete_stats(self, repo_name):
271 def delete_stats(self, repo_name):
259 try:
272 try:
260 self.sa.query(Statistics)\
273 self.sa.query(Statistics)\
261 .filter(Statistics.repository == \
274 .filter(Statistics.repository == \
262 self.get_by_repo_name(repo_name)).delete()
275 self.get_by_repo_name(repo_name)).delete()
263 self.sa.commit()
276 self.sa.commit()
264 except:
277 except:
265 log.error(traceback.format_exc())
278 log.error(traceback.format_exc())
266 self.sa.rollback()
279 self.sa.rollback()
267 raise
280 raise
268
281
269
282
270 def __create_repo(self, repo_name, alias):
283 def __create_repo(self, repo_name, alias):
271 """
284 """
272 makes repository on filesystem
285 makes repository on filesystem
273 :param repo_name:
286 :param repo_name:
274 :param alias:
287 :param alias:
275 """
288 """
276 from rhodecode.lib.utils import check_repo
289 from rhodecode.lib.utils import check_repo
277 repo_path = os.path.join(self.base_path, repo_name)
290 repo_path = os.path.join(self.base_path, repo_name)
278 if check_repo(repo_name, self.base_path):
291 if check_repo(repo_name, self.base_path):
279 log.info('creating repo %s in %s', repo_name, repo_path)
292 log.info('creating repo %s in %s', repo_name, repo_path)
280 backend = get_backend(alias)
293 backend = get_backend(alias)
281 backend(repo_path, create=True)
294 backend(repo_path, create=True)
282
295
283 def __rename_repo(self, old, new):
296 def __rename_repo(self, old, new):
284 """
297 """
285 renames repository on filesystem
298 renames repository on filesystem
286 :param old: old name
299 :param old: old name
287 :param new: new name
300 :param new: new name
288 """
301 """
289 log.info('renaming repo from %s to %s', old, new)
302 log.info('renaming repo from %s to %s', old, new)
290
303
291 old_path = os.path.join(self.base_path, old)
304 old_path = os.path.join(self.base_path, old)
292 new_path = os.path.join(self.base_path, new)
305 new_path = os.path.join(self.base_path, new)
293 if os.path.isdir(new_path):
306 if os.path.isdir(new_path):
294 raise Exception('Was trying to rename to already existing dir %s',
307 raise Exception('Was trying to rename to already existing dir %s',
295 new_path)
308 new_path)
296 shutil.move(old_path, new_path)
309 shutil.move(old_path, new_path)
297
310
298 def __delete_repo(self, repo):
311 def __delete_repo(self, repo):
299 """
312 """
300 removes repo from filesystem, the removal is acctually made by
313 removes repo from filesystem, the removal is acctually made by
301 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
314 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
302 repository is no longer valid for rhodecode, can be undeleted later on
315 repository is no longer valid for rhodecode, can be undeleted later on
303 by reverting the renames on this repository
316 by reverting the renames on this repository
304 :param repo: repo object
317 :param repo: repo object
305 """
318 """
306 rm_path = os.path.join(self.base_path, repo.repo_name)
319 rm_path = os.path.join(self.base_path, repo.repo_name)
307 log.info("Removing %s", rm_path)
320 log.info("Removing %s", rm_path)
308 #disable hg/git
321 #disable hg/git
309 alias = repo.repo_type
322 alias = repo.repo_type
310 shutil.move(os.path.join(rm_path, '.%s' % alias),
323 shutil.move(os.path.join(rm_path, '.%s' % alias),
311 os.path.join(rm_path, 'rm__.%s' % alias))
324 os.path.join(rm_path, 'rm__.%s' % alias))
312 #disable repo
325 #disable repo
313 shutil.move(rm_path, os.path.join(self.base_path, 'rm__%s__%s' \
326 shutil.move(rm_path, os.path.join(self.base_path, 'rm__%s__%s' \
314 % (datetime.today(), repo.repo_name)))
327 % (datetime.today(), repo.repo_name)))
@@ -1,407 +1,339 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 repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
5 ${_('Edit repository')} ${c.repo_info.repo_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(_('Repositories'),h.url('repos'))}
11 ${h.link_to(_('Repositories'),h.url('repos'))}
12 &raquo;
12 &raquo;
13 ${_('edit')} "${c.repo_name}"
13 ${_('edit')} "${c.repo_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 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 <div class="form">
27 <div class="form">
28 <!-- fields -->
28 <!-- fields -->
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="repo_name">${_('Name')}:</label>
32 <label for="repo_name">${_('Name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('repo_name',class_="medium")}
35 ${h.text('repo_name',class_="medium")}
36 </div>
36 </div>
37 </div>
37 </div>
38 <div class="field">
38 <div class="field">
39 <div class="label">
39 <div class="label">
40 <label for="repo_type">${_('Type')}:</label>
40 <label for="repo_type">${_('Type')}:</label>
41 </div>
41 </div>
42 <div class="input">
42 <div class="input">
43 ${h.select('repo_type','hg',c.backends,class_="medium")}
43 ${h.select('repo_type','hg',c.backends,class_="medium")}
44 </div>
44 </div>
45 </div>
45 </div>
46 <div class="field">
46 <div class="field">
47 <div class="label label-textarea">
47 <div class="label label-textarea">
48 <label for="description">${_('Description')}:</label>
48 <label for="description">${_('Description')}:</label>
49 </div>
49 </div>
50 <div class="textarea text-area editor">
50 <div class="textarea text-area editor">
51 ${h.textarea('description',cols=23,rows=5)}
51 ${h.textarea('description',cols=23,rows=5)}
52 </div>
52 </div>
53 </div>
53 </div>
54
54
55 <div class="field">
55 <div class="field">
56 <div class="label label-checkbox">
56 <div class="label label-checkbox">
57 <label for="private">${_('Private')}:</label>
57 <label for="private">${_('Private')}:</label>
58 </div>
58 </div>
59 <div class="checkboxes">
59 <div class="checkboxes">
60 ${h.checkbox('private',value="True")}
60 ${h.checkbox('private',value="True")}
61 </div>
61 </div>
62 </div>
62 </div>
63 <div class="field">
63 <div class="field">
64 <div class="label label-checkbox">
64 <div class="label label-checkbox">
65 <label for="enable_statistics">${_('Enable statistics')}:</label>
65 <label for="enable_statistics">${_('Enable statistics')}:</label>
66 </div>
66 </div>
67 <div class="checkboxes">
67 <div class="checkboxes">
68 ${h.checkbox('enable_statistics',value="True")}
68 ${h.checkbox('enable_statistics',value="True")}
69 </div>
69 </div>
70 </div>
70 </div>
71 <div class="field">
71 <div class="field">
72 <div class="label label-checkbox">
72 <div class="label label-checkbox">
73 <label for="enable_downloads">${_('Enable downloads')}:</label>
73 <label for="enable_downloads">${_('Enable downloads')}:</label>
74 </div>
74 </div>
75 <div class="checkboxes">
75 <div class="checkboxes">
76 ${h.checkbox('enable_downloads',value="True")}
76 ${h.checkbox('enable_downloads',value="True")}
77 </div>
77 </div>
78 </div>
78 </div>
79 <div class="field">
79 <div class="field">
80 <div class="label">
80 <div class="label">
81 <label for="user">${_('Owner')}:</label>
81 <label for="user">${_('Owner')}:</label>
82 </div>
82 </div>
83 <div class="input input-small ac">
83 <div class="input input-small ac">
84 <div class="perm_ac">
84 <div class="perm_ac">
85 ${h.text('user',class_='yui-ac-input')}
85 ${h.text('user',class_='yui-ac-input')}
86 <div id="owner_container"></div>
86 <div id="owner_container"></div>
87 </div>
87 </div>
88 </div>
88 </div>
89 </div>
89 </div>
90
90
91 <div class="field">
91 <div class="field">
92 <div class="label">
92 <div class="label">
93 <label for="input">${_('Permissions')}:</label>
93 <label for="input">${_('Permissions')}:</label>
94 </div>
94 </div>
95 <div class="input">
95 <div class="input">
96 <table id="permissions_manage">
96 <%include file="repo_edit_perms.html"/>
97 <tr>
97 </div>
98 <td>${_('none')}</td>
99 <td>${_('read')}</td>
100 <td>${_('write')}</td>
101 <td>${_('admin')}</td>
102 <td>${_('member')}</td>
103 <td></td>
104 </tr>
105
106 %for r2p in c.repo_info.repo_to_perm:
107 %if r2p.user.username =='default' and c.repo_info.private:
108 <tr>
109 <td colspan="4">
110 <span class="private_repo_msg">
111 ${_('private repository')}
112 </span>
113 </td>
114 <td class="private_repo_msg">${r2p.user.username}</td>
115 </tr>
116 %else:
117 <tr id="id${id(r2p.user.username)}">
118 <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
119 <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
120 <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
121 <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
122 <td>${r2p.user.username}</td>
123 <td>
124 %if r2p.user.username !='default':
125 <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
126 <script type="text/javascript">
127 function ajaxAction(user_id,field_id){
128 var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
129 var callback = { success:function(o){
130 var tr = YAHOO.util.Dom.get(String(field_id));
131 tr.parentNode.removeChild(tr);},failure:function(o){
132 alert("${_('Failed to remove user')}");},};
133 var postData = '_method=delete&user_id='+user_id;
134 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
135 </script>
136 </span>
137 %endif
138 </td>
139 </tr>
140 %endif
141 %endfor
142
143 <tr id="add_perm_input">
144 <td>${h.radio('perm_new_member','repository.none')}</td>
145 <td>${h.radio('perm_new_member','repository.read')}</td>
146 <td>${h.radio('perm_new_member','repository.write')}</td>
147 <td>${h.radio('perm_new_member','repository.admin')}</td>
148 <td class='ac'>
149 <div class="perm_ac" id="perm_ac">
150 ${h.text('perm_new_member_name',class_='yui-ac-input')}
151 ${h.hidden('perm_new_member_type')}
152 <div id="perm_container"></div>
153 </div>
154 </td>
155 <td></td>
156 </tr>
157 <tr>
158 <td colspan="6">
159 <span id="add_perm" class="add_icon" style="cursor: pointer;">
160 ${_('Add another member')}
161 </span>
162 </td>
163 </tr>
164 </table>
165 </div>
166
98
167 <div class="buttons">
99 <div class="buttons">
168 ${h.submit('save','Save',class_="ui-button")}
100 ${h.submit('save','Save',class_="ui-button")}
169 ${h.reset('reset','Reset',class_="ui-button")}
101 ${h.reset('reset','Reset',class_="ui-button")}
170 </div>
102 </div>
171 </div>
103 </div>
172 </div>
104 </div>
173 </div>
105 </div>
174 ${h.end_form()}
106 ${h.end_form()}
175 <script type="text/javascript">
107 <script type="text/javascript">
176 YAHOO.util.Event.onDOMReady(function(){
108 YAHOO.util.Event.onDOMReady(function(){
177 var D = YAHOO.util.Dom;
109 var D = YAHOO.util.Dom;
178 if(!D.hasClass('perm_new_member_name','error')){
110 if(!D.hasClass('perm_new_member_name','error')){
179 D.setStyle('add_perm_input','display','none');
111 D.setStyle('add_perm_input','display','none');
180 }
112 }
181 YAHOO.util.Event.addListener('add_perm','click',function(){
113 YAHOO.util.Event.addListener('add_perm','click',function(){
182 D.setStyle('add_perm_input','display','');
114 D.setStyle('add_perm_input','display','');
183 D.setStyle('add_perm','opacity','0.6');
115 D.setStyle('add_perm','opacity','0.6');
184 D.setStyle('add_perm','cursor','default');
116 D.setStyle('add_perm','cursor','default');
185 });
117 });
186 });
118 });
187 </script>
119 </script>
188 <script type="text/javascript">
120 <script type="text/javascript">
189 YAHOO.example.FnMultipleFields = function(){
121 YAHOO.example.FnMultipleFields = function(){
190 var myUsers = ${c.users_array|n};
122 var myUsers = ${c.users_array|n};
191 var myGroups = ${c.users_groups_array|n};
123 var myGroups = ${c.users_groups_array|n};
192
124
193 // Define a custom search function for the DataSource of users
125 // Define a custom search function for the DataSource of users
194 var matchUsers = function(sQuery) {
126 var matchUsers = function(sQuery) {
195 // Case insensitive matching
127 // Case insensitive matching
196 var query = sQuery.toLowerCase();
128 var query = sQuery.toLowerCase();
197 var i=0;
129 var i=0;
198 var l=myUsers.length;
130 var l=myUsers.length;
199 var matches = [];
131 var matches = [];
200
132
201 // Match against each name of each contact
133 // Match against each name of each contact
202 for(; i<l; i++) {
134 for(; i<l; i++) {
203 contact = myUsers[i];
135 contact = myUsers[i];
204 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
136 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
205 (contact.lname.toLowerCase().indexOf(query) > -1) ||
137 (contact.lname.toLowerCase().indexOf(query) > -1) ||
206 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
138 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
207 matches[matches.length] = contact;
139 matches[matches.length] = contact;
208 }
140 }
209 }
141 }
210 return matches;
142 return matches;
211 };
143 };
212
144
213 // Define a custom search function for the DataSource of usersGroups
145 // Define a custom search function for the DataSource of usersGroups
214 var matchGroups = function(sQuery) {
146 var matchGroups = function(sQuery) {
215 // Case insensitive matching
147 // Case insensitive matching
216 var query = sQuery.toLowerCase();
148 var query = sQuery.toLowerCase();
217 var i=0;
149 var i=0;
218 var l=myGroups.length;
150 var l=myGroups.length;
219 var matches = [];
151 var matches = [];
220
152
221 // Match against each name of each contact
153 // Match against each name of each contact
222 for(; i<l; i++) {
154 for(; i<l; i++) {
223 matched_group = myGroups[i];
155 matched_group = myGroups[i];
224 if(matched_group.grname.toLowerCase().indexOf(query) > -1) {
156 if(matched_group.grname.toLowerCase().indexOf(query) > -1) {
225 matches[matches.length] = matched_group;
157 matches[matches.length] = matched_group;
226 }
158 }
227 }
159 }
228 return matches;
160 return matches;
229 };
161 };
230
162
231 //match all
163 //match all
232 var matchAll = function(sQuery){
164 var matchAll = function(sQuery){
233 u = matchUsers(sQuery);
165 u = matchUsers(sQuery);
234 g = matchGroups(sQuery);
166 g = matchGroups(sQuery);
235 return u.concat(g);
167 return u.concat(g);
236 };
168 };
237
169
238 // DataScheme for members
170 // DataScheme for members
239 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
171 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
240 memberDS.responseSchema = {
172 memberDS.responseSchema = {
241 fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
173 fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
242 };
174 };
243
175
244 // DataScheme for owner
176 // DataScheme for owner
245 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
177 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
246 ownerDS.responseSchema = {
178 ownerDS.responseSchema = {
247 fields: ["id", "fname", "lname", "nname"]
179 fields: ["id", "fname", "lname", "nname"]
248 };
180 };
249
181
250 // Instantiate AutoComplete for perms
182 // Instantiate AutoComplete for perms
251 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
183 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
252 membersAC.useShadow = false;
184 membersAC.useShadow = false;
253 membersAC.resultTypeList = false;
185 membersAC.resultTypeList = false;
254
186
255 // Instantiate AutoComplete for owner
187 // Instantiate AutoComplete for owner
256 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
188 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
257 ownerAC.useShadow = false;
189 ownerAC.useShadow = false;
258 ownerAC.resultTypeList = false;
190 ownerAC.resultTypeList = false;
259
191
260
192
261 // Helper highlight function for the formatter
193 // Helper highlight function for the formatter
262 var highlightMatch = function(full, snippet, matchindex) {
194 var highlightMatch = function(full, snippet, matchindex) {
263 return full.substring(0, matchindex) +
195 return full.substring(0, matchindex) +
264 "<span class='match'>" +
196 "<span class='match'>" +
265 full.substr(matchindex, snippet.length) +
197 full.substr(matchindex, snippet.length) +
266 "</span>" +
198 "</span>" +
267 full.substring(matchindex + snippet.length);
199 full.substring(matchindex + snippet.length);
268 };
200 };
269
201
270 // Custom formatter to highlight the matching letters
202 // Custom formatter to highlight the matching letters
271 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
203 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
272 var query = sQuery.toLowerCase();
204 var query = sQuery.toLowerCase();
273
205
274 if (oResultData.grname != undefined){
206 if (oResultData.grname != undefined){
275 var grname = oResultData.grname;
207 var grname = oResultData.grname;
276 var grmembers = oResultData.grmembers;
208 var grmembers = oResultData.grmembers;
277 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
209 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
278 var grprefix = "${_('Group')}: ";
210 var grprefix = "${_('Group')}: ";
279 var grsuffix = " ("+grmembers+" ${_('members')})";
211 var grsuffix = " ("+grmembers+" ${_('members')})";
280
212
281 if (grnameMatchIndex > -1){
213 if (grnameMatchIndex > -1){
282 return grprefix+highlightMatch(grname,query,grnameMatchIndex)+grsuffix;
214 return grprefix+highlightMatch(grname,query,grnameMatchIndex)+grsuffix;
283 }
215 }
284
216
285 return grprefix+oResultData.grname+grsuffix;
217 return grprefix+oResultData.grname+grsuffix;
286 }
218 }
287 else if(oResultData.fname != undefined){
219 else if(oResultData.fname != undefined){
288
220
289 var fname = oResultData.fname,
221 var fname = oResultData.fname,
290 lname = oResultData.lname,
222 lname = oResultData.lname,
291 nname = oResultData.nname || "", // Guard against null value
223 nname = oResultData.nname || "", // Guard against null value
292 fnameMatchIndex = fname.toLowerCase().indexOf(query),
224 fnameMatchIndex = fname.toLowerCase().indexOf(query),
293 lnameMatchIndex = lname.toLowerCase().indexOf(query),
225 lnameMatchIndex = lname.toLowerCase().indexOf(query),
294 nnameMatchIndex = nname.toLowerCase().indexOf(query),
226 nnameMatchIndex = nname.toLowerCase().indexOf(query),
295 displayfname, displaylname, displaynname;
227 displayfname, displaylname, displaynname;
296
228
297 if(fnameMatchIndex > -1) {
229 if(fnameMatchIndex > -1) {
298 displayfname = highlightMatch(fname, query, fnameMatchIndex);
230 displayfname = highlightMatch(fname, query, fnameMatchIndex);
299 }
231 }
300 else {
232 else {
301 displayfname = fname;
233 displayfname = fname;
302 }
234 }
303
235
304 if(lnameMatchIndex > -1) {
236 if(lnameMatchIndex > -1) {
305 displaylname = highlightMatch(lname, query, lnameMatchIndex);
237 displaylname = highlightMatch(lname, query, lnameMatchIndex);
306 }
238 }
307 else {
239 else {
308 displaylname = lname;
240 displaylname = lname;
309 }
241 }
310
242
311 if(nnameMatchIndex > -1) {
243 if(nnameMatchIndex > -1) {
312 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
244 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
313 }
245 }
314 else {
246 else {
315 displaynname = nname ? "(" + nname + ")" : "";
247 displaynname = nname ? "(" + nname + ")" : "";
316 }
248 }
317
249
318 return displayfname + " " + displaylname + " " + displaynname;
250 return displayfname + " " + displaylname + " " + displaynname;
319 }
251 }
320 else{
252 else{
321 return '';
253 return '';
322 }
254 }
323 };
255 };
324 membersAC.formatResult = custom_formatter;
256 membersAC.formatResult = custom_formatter;
325 ownerAC.formatResult = custom_formatter;
257 ownerAC.formatResult = custom_formatter;
326
258
327 var myHandler = function(sType, aArgs) {
259 var myHandler = function(sType, aArgs) {
328
260
329 var myAC = aArgs[0]; // reference back to the AC instance
261 var myAC = aArgs[0]; // reference back to the AC instance
330 var elLI = aArgs[1]; // reference to the selected LI element
262 var elLI = aArgs[1]; // reference to the selected LI element
331 var oData = aArgs[2]; // object literal of selected item's result data
263 var oData = aArgs[2]; // object literal of selected item's result data
332
264
333 //fill the autocomplete with value
265 //fill the autocomplete with value
334 if(oData.nname != undefined){
266 if(oData.nname != undefined){
335 //users
267 //users
336 myAC.getInputEl().value = oData.nname;
268 myAC.getInputEl().value = oData.nname;
337 YUD.get('perm_new_member_type').value = 'user';
269 YUD.get('perm_new_member_type').value = 'user';
338 }
270 }
339 else{
271 else{
340 //groups
272 //groups
341 myAC.getInputEl().value = oData.grname;
273 myAC.getInputEl().value = oData.grname;
342 YUD.get('perm_new_member_type').value = 'users_group';
274 YUD.get('perm_new_member_type').value = 'users_group';
343 }
275 }
344
276
345 };
277 };
346
278
347 membersAC.itemSelectEvent.subscribe(myHandler);
279 membersAC.itemSelectEvent.subscribe(myHandler);
348 ownerAC.itemSelectEvent.subscribe(myHandler);
280 ownerAC.itemSelectEvent.subscribe(myHandler);
349
281
350 return {
282 return {
351 memberDS: memberDS,
283 memberDS: memberDS,
352 ownerDS: ownerDS,
284 ownerDS: ownerDS,
353 membersAC: membersAC,
285 membersAC: membersAC,
354 ownerAC: ownerAC,
286 ownerAC: ownerAC,
355 };
287 };
356 }();
288 }();
357
289
358 </script>
290 </script>
359
291
360 </div>
292 </div>
361
293
362 <div class="box box-right">
294 <div class="box box-right">
363 <div class="title">
295 <div class="title">
364 <h5>${_('Administration')}</h5>
296 <h5>${_('Administration')}</h5>
365 </div>
297 </div>
366
298
367 <h3>${_('Statistics')}</h3>
299 <h3>${_('Statistics')}</h3>
368
300
369 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
301 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
370 <div class="form">
302 <div class="form">
371 <div class="fields">
303 <div class="fields">
372 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
304 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
373
305
374 <div class="field">
306 <div class="field">
375 <ul>
307 <ul>
376 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
308 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
377 <li>${_('Percentage of stats gathered')}: ${c.stats_percentage} %</li>
309 <li>${_('Percentage of stats gathered')}: ${c.stats_percentage} %</li>
378 </ul>
310 </ul>
379 </div>
311 </div>
380
312
381 </div>
313 </div>
382 </div>
314 </div>
383 ${h.end_form()}
315 ${h.end_form()}
384
316
385 <h3>${_('Cache')}</h3>
317 <h3>${_('Cache')}</h3>
386 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
318 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
387 <div class="form">
319 <div class="form">
388 <div class="fields">
320 <div class="fields">
389 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="refresh_icon action_button",onclick="return confirm('Confirm to invalidate repository cache');")}
321 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="refresh_icon action_button",onclick="return confirm('Confirm to invalidate repository cache');")}
390 </div>
322 </div>
391 </div>
323 </div>
392 ${h.end_form()}
324 ${h.end_form()}
393
325
394
326
395 <h3>${_('Delete')}</h3>
327 <h3>${_('Delete')}</h3>
396 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
328 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
397 <div class="form">
329 <div class="form">
398 <div class="fields">
330 <div class="fields">
399 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
331 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
400 </div>
332 </div>
401 </div>
333 </div>
402 ${h.end_form()}
334 ${h.end_form()}
403
335
404 </div>
336 </div>
405
337
406
338
407 </%def> No newline at end of file
339 </%def>
@@ -1,392 +1,392 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
6 <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
10 ${self.css()}
10 ${self.css()}
11 <!-- scripts -->
11 <!-- scripts -->
12 ${self.js()}
12 ${self.js()}
13 %if c.ga_code:
13 %if c.ga_code:
14 <script type="text/javascript">
14 <script type="text/javascript">
15
15
16 var _gaq = _gaq || [];
16 var _gaq = _gaq || [];
17 _gaq.push(['_setAccount', '${c.ga_code}']);
17 _gaq.push(['_setAccount', '${c.ga_code}']);
18 _gaq.push(['_trackPageview']);
18 _gaq.push(['_trackPageview']);
19
19
20 (function() {
20 (function() {
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
24 })();
24 })();
25
25
26
26
27 </script>
27 </script>
28 %endif
28 %endif
29 </head>
29 </head>
30 <body>
30 <body>
31 <!-- header -->
31 <!-- header -->
32 <div id="header">
32 <div id="header">
33 <!-- user -->
33 <!-- user -->
34 <ul id="logged-user">
34 <ul id="logged-user">
35 <li class="first">
35 <li class="first">
36 <div class="gravatar">
36 <div class="gravatar">
37 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
37 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
38 </div>
38 </div>
39 <div class="account">
39 <div class="account">
40 %if c.rhodecode_user.username == 'default':
40 %if c.rhodecode_user.username == 'default':
41 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
41 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
42 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
42 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
43 %else:
43 %else:
44 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
44 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
45 %endif
45 %endif
46
46
47 %else:
47 %else:
48 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
48 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
49 %endif
49 %endif
50 </div>
50 </div>
51 </li>
51 </li>
52 <li>
52 <li>
53 <a href="${h.url('home')}">${_('Home')}</a>
53 <a href="${h.url('home')}">${_('Home')}</a>
54 </li>
54 </li>
55 %if c.rhodecode_user.username != 'default':
55 %if c.rhodecode_user.username != 'default':
56 <li>
56 <li>
57 <a href="${h.url('journal')}">${_('Journal')}</a>
57 <a href="${h.url('journal')}">${_('Journal')}</a>
58 ##(${c.unread_journal})</a>
58 ##(${c.unread_journal})</a>
59 </li>
59 </li>
60 %endif
60 %endif
61 %if c.rhodecode_user.username == 'default':
61 %if c.rhodecode_user.username == 'default':
62 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
62 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
63 %else:
63 %else:
64 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
64 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
65 %endif
65 %endif
66 </ul>
66 </ul>
67 <!-- end user -->
67 <!-- end user -->
68 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
68 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
69 <!-- logo -->
69 <!-- logo -->
70 <div id="logo">
70 <div id="logo">
71 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
71 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
72 </div>
72 </div>
73 <!-- end logo -->
73 <!-- end logo -->
74 <!-- menu -->
74 <!-- menu -->
75 ${self.page_nav()}
75 ${self.page_nav()}
76 <!-- quick -->
76 <!-- quick -->
77 </div>
77 </div>
78 </div>
78 </div>
79 <!-- end header -->
79 <!-- end header -->
80
80
81 <!-- CONTENT -->
81 <!-- CONTENT -->
82 <div id="content">
82 <div id="content">
83 <div class="flash_msg">
83 <div class="flash_msg">
84 <% messages = h.flash.pop_messages() %>
84 <% messages = h.flash.pop_messages() %>
85 % if messages:
85 % if messages:
86 <ul id="flash-messages">
86 <ul id="flash-messages">
87 % for message in messages:
87 % for message in messages:
88 <li class="${message.category}_msg">${message}</li>
88 <li class="${message.category}_msg">${message}</li>
89 % endfor
89 % endfor
90 </ul>
90 </ul>
91 % endif
91 % endif
92 </div>
92 </div>
93 <div id="main">
93 <div id="main">
94 ${next.main()}
94 ${next.main()}
95 </div>
95 </div>
96 </div>
96 </div>
97 <!-- END CONTENT -->
97 <!-- END CONTENT -->
98
98
99 <!-- footer -->
99 <!-- footer -->
100 <div id="footer">
100 <div id="footer">
101 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
101 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
102 <div>
102 <div>
103 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
103 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
104 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
104 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
105 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
105 <p>RhodeCode ${c.rhodecode_version} &copy; 2010-2011 by Marcin Kuzminski</p>
106 </div>
106 </div>
107 </div>
107 </div>
108 <script type="text/javascript">
108 <script type="text/javascript">
109 function tooltip_activate(){
109 function tooltip_activate(){
110 ${h.tooltip.activate()}
110 ${h.tooltip.activate()}
111 }
111 }
112 tooltip_activate();
112 tooltip_activate();
113 </script>
113 </script>
114 </div>
114 </div>
115 <!-- end footer -->
115 <!-- end footer -->
116 </body>
116 </body>
117
117
118 </html>
118 </html>
119
119
120 ### MAKO DEFS ###
120 ### MAKO DEFS ###
121 <%def name="page_nav()">
121 <%def name="page_nav()">
122 ${self.menu()}
122 ${self.menu()}
123 </%def>
123 </%def>
124
124
125 <%def name="menu(current=None)">
125 <%def name="menu(current=None)">
126 <%
126 <%
127 def is_current(selected):
127 def is_current(selected):
128 if selected == current:
128 if selected == current:
129 return h.literal('class="current"')
129 return h.literal('class="current"')
130 %>
130 %>
131 %if current not in ['home','admin']:
131 %if current not in ['home','admin']:
132 ##REGULAR MENU
132 ##REGULAR MENU
133 <ul id="quick">
133 <ul id="quick">
134 <!-- repo switcher -->
134 <!-- repo switcher -->
135 <li>
135 <li>
136 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
136 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
137 <span class="icon">
137 <span class="icon">
138 <img src="/images/icons/database.png" alt="${_('Products')}" />
138 <img src="/images/icons/database.png" alt="${_('Products')}" />
139 </span>
139 </span>
140 <span>&darr;</span>
140 <span>&darr;</span>
141 </a>
141 </a>
142 <ul class="repo_switcher">
142 <ul class="repo_switcher">
143 %for repo in c.cached_repo_list:
143 %for repo in c.cached_repo_list:
144
144
145 %if repo['repo'].dbrepo.private:
145 %if repo['repo'].dbrepo.private:
146 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
146 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
147 %else:
147 %else:
148 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
148 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
149 %endif
149 %endif
150 %endfor
150 %endfor
151 </ul>
151 </ul>
152 </li>
152 </li>
153
153
154 <li ${is_current('summary')}>
154 <li ${is_current('summary')}>
155 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
155 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
156 <span class="icon">
156 <span class="icon">
157 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
157 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
158 </span>
158 </span>
159 <span>${_('Summary')}</span>
159 <span>${_('Summary')}</span>
160 </a>
160 </a>
161 </li>
161 </li>
162 ##<li ${is_current('shortlog')}>
162 ##<li ${is_current('shortlog')}>
163 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
163 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
164 ## <span class="icon">
164 ## <span class="icon">
165 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
165 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
166 ## </span>
166 ## </span>
167 ## <span>${_('Shortlog')}</span>
167 ## <span>${_('Shortlog')}</span>
168 ## </a>
168 ## </a>
169 ##</li>
169 ##</li>
170 <li ${is_current('changelog')}>
170 <li ${is_current('changelog')}>
171 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
171 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
172 <span class="icon">
172 <span class="icon">
173 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
173 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
174 </span>
174 </span>
175 <span>${_('Changelog')}</span>
175 <span>${_('Changelog')}</span>
176 </a>
176 </a>
177 </li>
177 </li>
178
178
179 <li ${is_current('switch_to')}>
179 <li ${is_current('switch_to')}>
180 <a title="${_('Switch to')}" href="#">
180 <a title="${_('Switch to')}" href="#">
181 <span class="icon">
181 <span class="icon">
182 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
182 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
183 </span>
183 </span>
184 <span>${_('Switch to')}</span>
184 <span>${_('Switch to')}</span>
185 </a>
185 </a>
186 <ul>
186 <ul>
187 <li>
187 <li>
188 ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
188 ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
189 <ul>
189 <ul>
190 %if c.repository_branches.values():
190 %if c.repository_branches.values():
191 %for cnt,branch in enumerate(c.repository_branches.items()):
191 %for cnt,branch in enumerate(c.repository_branches.items()):
192 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
192 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
193 %endfor
193 %endfor
194 %else:
194 %else:
195 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
195 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
196 %endif
196 %endif
197 </ul>
197 </ul>
198 </li>
198 </li>
199 <li>
199 <li>
200 ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
200 ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
201 <ul>
201 <ul>
202 %if c.repository_tags.values():
202 %if c.repository_tags.values():
203 %for cnt,tag in enumerate(c.repository_tags.items()):
203 %for cnt,tag in enumerate(c.repository_tags.items()):
204 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
204 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
205 %endfor
205 %endfor
206 %else:
206 %else:
207 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
207 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
208 %endif
208 %endif
209 </ul>
209 </ul>
210 </li>
210 </li>
211 </ul>
211 </ul>
212 </li>
212 </li>
213 <li ${is_current('files')}>
213 <li ${is_current('files')}>
214 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
214 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
215 <span class="icon">
215 <span class="icon">
216 <img src="/images/icons/file.png" alt="${_('Files')}" />
216 <img src="/images/icons/file.png" alt="${_('Files')}" />
217 </span>
217 </span>
218 <span>${_('Files')}</span>
218 <span>${_('Files')}</span>
219 </a>
219 </a>
220 </li>
220 </li>
221
221
222 <li ${is_current('options')}>
222 <li ${is_current('options')}>
223 <a title="${_('Options')}" href="#">
223 <a title="${_('Options')}" href="#">
224 <span class="icon">
224 <span class="icon">
225 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
225 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
226 </span>
226 </span>
227 <span>${_('Options')}</span>
227 <span>${_('Options')}</span>
228 </a>
228 </a>
229 <ul>
229 <ul>
230 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
230 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
231 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
231 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
232 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
232 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
233 %else:
233 %else:
234 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
234 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
235 %endif
235 %endif
236 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
236 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
237 %endif
237 %endif
238 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
238 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
239
239
240 %if h.HasPermissionAll('hg.admin')('access admin main page'):
240 %if h.HasPermissionAll('hg.admin')('access admin main page'):
241 <li>
241 <li>
242 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
242 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
243 <%def name="admin_menu()">
243 <%def name="admin_menu()">
244 <ul>
244 <ul>
245 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
245 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
246 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
246 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
247 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
247 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
248 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
248 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
249 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
249 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
250 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
250 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
251 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
251 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
252 </ul>
252 </ul>
253 </%def>
253 </%def>
254
254
255 ${admin_menu()}
255 ${admin_menu()}
256 </li>
256 </li>
257 %endif
257 %endif
258
258
259 </ul>
259 </ul>
260 </li>
260 </li>
261
261
262 <li>
262 <li>
263 <a title="${_('Followers')}" href="#">
263 <a title="${_('Followers')}" href="#">
264 <span class="icon_short">
264 <span class="icon_short">
265 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
265 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
266 </span>
266 </span>
267 <span class="short">${c.repository_followers}</span>
267 <span class="short">${c.repository_followers}</span>
268 </a>
268 </a>
269 </li>
269 </li>
270 <li>
270 <li>
271 <a title="${_('Forks')}" href="#">
271 <a title="${_('Forks')}" href="#">
272 <span class="icon_short">
272 <span class="icon_short">
273 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
273 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
274 </span>
274 </span>
275 <span class="short">${c.repository_forks}</span>
275 <span class="short">${c.repository_forks}</span>
276 </a>
276 </a>
277 </li>
277 </li>
278
278
279
279
280
280
281 </ul>
281 </ul>
282 %else:
282 %else:
283 ##ROOT MENU
283 ##ROOT MENU
284 <ul id="quick">
284 <ul id="quick">
285 <li>
285 <li>
286 <a title="${_('Home')}" href="${h.url('home')}">
286 <a title="${_('Home')}" href="${h.url('home')}">
287 <span class="icon">
287 <span class="icon">
288 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
288 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
289 </span>
289 </span>
290 <span>${_('Home')}</span>
290 <span>${_('Home')}</span>
291 </a>
291 </a>
292 </li>
292 </li>
293 %if c.rhodecode_user.username != 'default':
293 %if c.rhodecode_user.username != 'default':
294 <li>
294 <li>
295 <a title="${_('Journal')}" href="${h.url('journal')}">
295 <a title="${_('Journal')}" href="${h.url('journal')}">
296 <span class="icon">
296 <span class="icon">
297 <img src="/images/icons/book.png" alt="${_('Journal')}" />
297 <img src="/images/icons/book.png" alt="${_('Journal')}" />
298 </span>
298 </span>
299 <span>${_('Journal')}</span>
299 <span>${_('Journal')}</span>
300 </a>
300 </a>
301 </li>
301 </li>
302 %endif
302 %endif
303 <li>
303 <li>
304 <a title="${_('Search')}" href="${h.url('search')}">
304 <a title="${_('Search')}" href="${h.url('search')}">
305 <span class="icon">
305 <span class="icon">
306 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
306 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
307 </span>
307 </span>
308 <span>${_('Search')}</span>
308 <span>${_('Search')}</span>
309 </a>
309 </a>
310 </li>
310 </li>
311
311
312 %if h.HasPermissionAll('hg.admin')('access admin main page'):
312 %if h.HasPermissionAll('hg.admin')('access admin main page'):
313 <li ${is_current('admin')}>
313 <li ${is_current('admin')}>
314 <a title="${_('Admin')}" href="${h.url('admin_home')}">
314 <a title="${_('Admin')}" href="${h.url('admin_home')}">
315 <span class="icon">
315 <span class="icon">
316 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
316 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
317 </span>
317 </span>
318 <span>${_('Admin')}</span>
318 <span>${_('Admin')}</span>
319 </a>
319 </a>
320 ${admin_menu()}
320 ${admin_menu()}
321 </li>
321 </li>
322 %endif
322 %endif
323 </ul>
323 </ul>
324 %endif
324 %endif
325 </%def>
325 </%def>
326
326
327
327
328 <%def name="css()">
328 <%def name="css()">
329 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
329 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
330 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
330 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
331 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
331 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
332 </%def>
332 </%def>
333
333
334 <%def name="js()">
334 <%def name="js()">
335 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
335 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
336 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
336 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
337 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
337 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
338 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
338 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
339 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
339 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
340
340
341 <script type="text/javascript" src="/js/yui2a.js"></script>
341 <script type="text/javascript" src="/js/yui2a.js"></script>
342 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
342 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
343 <script type="text/javascript" src="/js/yui.flot.js"></script>
343 <script type="text/javascript" src="/js/yui.flot.js"></script>
344
344
345 <script type="text/javascript">
345 <script type="text/javascript">
346 var base_url ='/_admin/toggle_following';
346 var base_url ='/_admin/toggle_following';
347 var YUC = YAHOO.util.Connect;
347 var YUC = YAHOO.util.Connect;
348 var YUD = YAHOO.util.Dom;
348 var YUD = YAHOO.util.Dom;
349 var YUE = YAHOO.util.Event;
349 var YUE = YAHOO.util.Event;
350
350
351 function onSuccess(target){
351 function onSuccess(target){
352
352
353 var f = YUD.get(target.id);
353 var f = YUD.get(target.id);
354 if(f.getAttribute('class')=='follow'){
354 if(f.getAttribute('class')=='follow'){
355 f.setAttribute('class','following');
355 f.setAttribute('class','following');
356 f.setAttribute('title',"${_('Stop following this repository')}");
356 f.setAttribute('title',"${_('Stop following this repository')}");
357 }
357 }
358 else{
358 else{
359 f.setAttribute('class','follow');
359 f.setAttribute('class','follow');
360 f.setAttribute('title',"${_('Start following this repository')}");
360 f.setAttribute('title',"${_('Start following this repository')}");
361 }
361 }
362 }
362 }
363
363
364 function toggleFollowingUser(fallows_user_id,token){
364 function toggleFollowingUser(fallows_user_id,token){
365 args = 'follows_user_id='+fallows_user_id;
365 args = 'follows_user_id='+fallows_user_id;
366 args+= '&amp;auth_token='+token;
366 args+= '&amp;auth_token='+token;
367 YUC.asyncRequest('POST',base_url,{
367 YUC.asyncRequest('POST',base_url,{
368 success:function(o){
368 success:function(o){
369 onSuccess();
369 onSuccess();
370 }
370 }
371 },args); return false;
371 },args); return false;
372 }
372 }
373
373
374 function toggleFollowingRepo(target,fallows_repo_id,token){
374 function toggleFollowingRepo(target,fallows_repo_id,token){
375
375
376 args = 'follows_repo_id='+fallows_repo_id;
376 args = 'follows_repo_id='+fallows_repo_id;
377 args+= '&amp;auth_token='+token;
377 args+= '&amp;auth_token='+token;
378 YUC.asyncRequest('POST',base_url,{
378 YUC.asyncRequest('POST',base_url,{
379 success:function(o){
379 success:function(o){
380 onSuccess(target);
380 onSuccess(target);
381 }
381 }
382 },args); return false;
382 },args); return false;
383 }
383 }
384 </script>
384 </script>
385
385
386 </%def>
386 </%def>
387
387
388 <%def name="breadcrumbs()">
388 <%def name="breadcrumbs()">
389 <div class="breadcrumbs">
389 <div class="breadcrumbs">
390 ${self.breadcrumbs_links()}
390 ${self.breadcrumbs_links()}
391 </div>
391 </div>
392 </%def> No newline at end of file
392 </%def>
@@ -1,263 +1,195 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 ${c.repo_name} ${_('Settings')} - ${c.rhodecode_name}
5 ${c.repo_name} ${_('Settings')} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))}
9 ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))}
10 &raquo;
10 &raquo;
11 ${_('Settings')}
11 ${_('Settings')}
12 </%def>
12 </%def>
13
13
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('settings')}
15 ${self.menu('settings')}
16 </%def>
16 </%def>
17 <%def name="main()">
17 <%def name="main()">
18 <div class="box">
18 <div class="box">
19 <!-- box / title -->
19 <!-- box / title -->
20 <div class="title">
20 <div class="title">
21 ${self.breadcrumbs()}
21 ${self.breadcrumbs()}
22 </div>
22 </div>
23 ${h.form(url('repo_settings_update', repo_name=c.repo_info.repo_name),method='put')}
23 ${h.form(url('repo_settings_update', repo_name=c.repo_info.repo_name),method='put')}
24 <div class="form">
24 <div class="form">
25 <!-- fields -->
25 <!-- fields -->
26 <div class="fields">
26 <div class="fields">
27 <div class="field">
27 <div class="field">
28 <div class="label">
28 <div class="label">
29 <label for="repo_name">${_('Name')}:</label>
29 <label for="repo_name">${_('Name')}:</label>
30 </div>
30 </div>
31 <div class="input input-medium">
31 <div class="input input-medium">
32 ${h.text('repo_name',class_="small")}
32 ${h.text('repo_name',class_="small")}
33 </div>
33 </div>
34 </div>
34 </div>
35
35
36 <div class="field">
36 <div class="field">
37 <div class="label label-textarea">
37 <div class="label label-textarea">
38 <label for="description">${_('Description')}:</label>
38 <label for="description">${_('Description')}:</label>
39 </div>
39 </div>
40 <div class="textarea text-area editor">
40 <div class="textarea text-area editor">
41 ${h.textarea('description',cols=23,rows=5)}
41 ${h.textarea('description',cols=23,rows=5)}
42 </div>
42 </div>
43 </div>
43 </div>
44
44
45 <div class="field">
45 <div class="field">
46 <div class="label label-checkbox">
46 <div class="label label-checkbox">
47 <label for="private">${_('Private')}:</label>
47 <label for="private">${_('Private')}:</label>
48 </div>
48 </div>
49 <div class="checkboxes">
49 <div class="checkboxes">
50 ${h.checkbox('private',value="True")}
50 ${h.checkbox('private',value="True")}
51 </div>
51 </div>
52 </div>
52 </div>
53
53
54 <div class="field">
54 <div class="field">
55 <div class="label">
55 <div class="label">
56 <label for="">${_('Permissions')}:</label>
56 <label for="">${_('Permissions')}:</label>
57 </div>
57 </div>
58 <div class="input">
58 <div class="input">
59 <table id="permissions_manage">
59 <%include file="../admin/repos/repo_edit_perms.html"/>
60 <tr>
60 </div>
61 <td>${_('none')}</td>
62 <td>${_('read')}</td>
63 <td>${_('write')}</td>
64 <td>${_('admin')}</td>
65 <td>${_('user')}</td>
66 <td></td>
67 </tr>
68
69 %for r2p in c.repo_info.repo_to_perm:
70 %if r2p.user.username =='default' and c.repo_info.private:
71 <tr>
72 <td colspan="4">
73 <span class="private_repo_msg">
74 ${_('private repository')}
75 </span>
76 </td>
77 <td class="private_repo_msg">${r2p.user.username}</td>
78 </tr>
79 %else:
80 <tr id="id${id(r2p.user.username)}">
81 <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
82 <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
83 <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
84 <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
85 <td>${r2p.user.username}</td>
86 <td>
87 %if r2p.user.username !='default':
88 <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
89 <script type="text/javascript">
90 function ajaxAction(user_id,field_id){
91 var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
92 var callback = { success:function(o){
93 var tr = YAHOO.util.Dom.get(String(field_id));
94 tr.parentNode.removeChild(tr);},failure:function(o){
95 alert("${_('Failed to remove user')}");},};
96 var postData = '_method=delete&user_id='+user_id;
97 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
98 </script>
99 </span>
100 %endif
101 </td>
102 </tr>
103 %endif
104 %endfor
105
106
107 <tr id="add_perm_input">
108 <td>${h.radio('perm_new_user','repository.none')}</td>
109 <td>${h.radio('perm_new_user','repository.read')}</td>
110 <td>${h.radio('perm_new_user','repository.write')}</td>
111 <td>${h.radio('perm_new_user','repository.admin')}</td>
112 <td class='ac'>
113 <div class="perm_ac" id="perm_ac">
114 ${h.text('perm_new_user_name',class_='yui-ac-input')}
115 <div id="perm_container"></div>
116 </div>
117 </td>
118 <td></td>
119 </tr>
120 <tr>
121 <td colspan="6">
122 <span id="add_perm" class="add_icon" style="cursor: pointer;">
123 ${_('Add another user')}
124 </span>
125 </td>
126 </tr>
127 </table>
128 </div>
129
61
130 <div class="buttons">
62 <div class="buttons">
131 ${h.submit('update','Update',class_="ui-button")}
63 ${h.submit('update','Update',class_="ui-button")}
132 ${h.reset('reset','Reset',class_="ui-button")}
64 ${h.reset('reset','Reset',class_="ui-button")}
133 </div>
65 </div>
134 </div>
66 </div>
135 </div>
67 </div>
136 ${h.end_form()}
68 ${h.end_form()}
137 <script type="text/javascript">
69 <script type="text/javascript">
138 YAHOO.util.Event.onDOMReady(function(){
70 YAHOO.util.Event.onDOMReady(function(){
139 var D = YAHOO.util.Dom;
71 var D = YAHOO.util.Dom;
140 if(!D.hasClass('perm_new_user_name','error')){
72 if(!D.hasClass('perm_new_user_name','error')){
141 D.setStyle('add_perm_input','display','none');
73 D.setStyle('add_perm_input','display','none');
142 }
74 }
143 YAHOO.util.Event.addListener('add_perm','click',function(){
75 YAHOO.util.Event.addListener('add_perm','click',function(){
144 D.setStyle('add_perm_input','display','');
76 D.setStyle('add_perm_input','display','');
145 D.setStyle('add_perm','opacity','0.6');
77 D.setStyle('add_perm','opacity','0.6');
146 D.setStyle('add_perm','cursor','default');
78 D.setStyle('add_perm','cursor','default');
147 });
79 });
148 });
80 });
149 </script>
81 </script>
150 <script type="text/javascript">
82 <script type="text/javascript">
151 YAHOO.example.FnMultipleFields = function(){
83 YAHOO.example.FnMultipleFields = function(){
152 var myContacts = ${c.users_array|n}
84 var myContacts = ${c.users_array|n}
153
85
154 // Define a custom search function for the DataSource
86 // Define a custom search function for the DataSource
155 var matchNames = function(sQuery) {
87 var matchNames = function(sQuery) {
156 // Case insensitive matching
88 // Case insensitive matching
157 var query = sQuery.toLowerCase(),
89 var query = sQuery.toLowerCase(),
158 contact,
90 contact,
159 i=0,
91 i=0,
160 l=myContacts.length,
92 l=myContacts.length,
161 matches = [];
93 matches = [];
162
94
163 // Match against each name of each contact
95 // Match against each name of each contact
164 for(; i<l; i++) {
96 for(; i<l; i++) {
165 contact = myContacts[i];
97 contact = myContacts[i];
166 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
98 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
167 (contact.lname.toLowerCase().indexOf(query) > -1) ||
99 (contact.lname.toLowerCase().indexOf(query) > -1) ||
168 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
100 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
169 matches[matches.length] = contact;
101 matches[matches.length] = contact;
170 }
102 }
171 }
103 }
172
104
173 return matches;
105 return matches;
174 };
106 };
175
107
176 // Use a FunctionDataSource
108 // Use a FunctionDataSource
177 var oDS = new YAHOO.util.FunctionDataSource(matchNames);
109 var oDS = new YAHOO.util.FunctionDataSource(matchNames);
178 oDS.responseSchema = {
110 oDS.responseSchema = {
179 fields: ["id", "fname", "lname", "nname"]
111 fields: ["id", "fname", "lname", "nname"]
180 }
112 }
181
113
182 // Instantiate AutoComplete for perms
114 // Instantiate AutoComplete for perms
183 var oAC_perms = new YAHOO.widget.AutoComplete("perm_new_user_name", "perm_container", oDS);
115 var oAC_perms = new YAHOO.widget.AutoComplete("perm_new_user_name", "perm_container", oDS);
184 oAC_perms.useShadow = false;
116 oAC_perms.useShadow = false;
185 oAC_perms.resultTypeList = false;
117 oAC_perms.resultTypeList = false;
186
118
187 // Instantiate AutoComplete for owner
119 // Instantiate AutoComplete for owner
188 var oAC_owner = new YAHOO.widget.AutoComplete("user", "owner_container", oDS);
120 var oAC_owner = new YAHOO.widget.AutoComplete("user", "owner_container", oDS);
189 oAC_owner.useShadow = false;
121 oAC_owner.useShadow = false;
190 oAC_owner.resultTypeList = false;
122 oAC_owner.resultTypeList = false;
191
123
192
124
193 // Custom formatter to highlight the matching letters
125 // Custom formatter to highlight the matching letters
194 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
126 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
195 var query = sQuery.toLowerCase(),
127 var query = sQuery.toLowerCase(),
196 fname = oResultData.fname,
128 fname = oResultData.fname,
197 lname = oResultData.lname,
129 lname = oResultData.lname,
198 nname = oResultData.nname || "", // Guard against null value
130 nname = oResultData.nname || "", // Guard against null value
199 query = sQuery.toLowerCase(),
131 query = sQuery.toLowerCase(),
200 fnameMatchIndex = fname.toLowerCase().indexOf(query),
132 fnameMatchIndex = fname.toLowerCase().indexOf(query),
201 lnameMatchIndex = lname.toLowerCase().indexOf(query),
133 lnameMatchIndex = lname.toLowerCase().indexOf(query),
202 nnameMatchIndex = nname.toLowerCase().indexOf(query),
134 nnameMatchIndex = nname.toLowerCase().indexOf(query),
203 displayfname, displaylname, displaynname;
135 displayfname, displaylname, displaynname;
204
136
205 if(fnameMatchIndex > -1) {
137 if(fnameMatchIndex > -1) {
206 displayfname = highlightMatch(fname, query, fnameMatchIndex);
138 displayfname = highlightMatch(fname, query, fnameMatchIndex);
207 }
139 }
208 else {
140 else {
209 displayfname = fname;
141 displayfname = fname;
210 }
142 }
211
143
212 if(lnameMatchIndex > -1) {
144 if(lnameMatchIndex > -1) {
213 displaylname = highlightMatch(lname, query, lnameMatchIndex);
145 displaylname = highlightMatch(lname, query, lnameMatchIndex);
214 }
146 }
215 else {
147 else {
216 displaylname = lname;
148 displaylname = lname;
217 }
149 }
218
150
219 if(nnameMatchIndex > -1) {
151 if(nnameMatchIndex > -1) {
220 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
152 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
221 }
153 }
222 else {
154 else {
223 displaynname = nname ? "(" + nname + ")" : "";
155 displaynname = nname ? "(" + nname + ")" : "";
224 }
156 }
225
157
226 return displayfname + " " + displaylname + " " + displaynname;
158 return displayfname + " " + displaylname + " " + displaynname;
227
159
228 };
160 };
229 oAC_perms.formatResult = custom_formatter;
161 oAC_perms.formatResult = custom_formatter;
230 oAC_owner.formatResult = custom_formatter;
162 oAC_owner.formatResult = custom_formatter;
231
163
232 // Helper function for the formatter
164 // Helper function for the formatter
233 var highlightMatch = function(full, snippet, matchindex) {
165 var highlightMatch = function(full, snippet, matchindex) {
234 return full.substring(0, matchindex) +
166 return full.substring(0, matchindex) +
235 "<span class='match'>" +
167 "<span class='match'>" +
236 full.substr(matchindex, snippet.length) +
168 full.substr(matchindex, snippet.length) +
237 "</span>" +
169 "</span>" +
238 full.substring(matchindex + snippet.length);
170 full.substring(matchindex + snippet.length);
239 };
171 };
240
172
241 var myHandler = function(sType, aArgs) {
173 var myHandler = function(sType, aArgs) {
242 var myAC = aArgs[0]; // reference back to the AC instance
174 var myAC = aArgs[0]; // reference back to the AC instance
243 var elLI = aArgs[1]; // reference to the selected LI element
175 var elLI = aArgs[1]; // reference to the selected LI element
244 var oData = aArgs[2]; // object literal of selected item's result data
176 var oData = aArgs[2]; // object literal of selected item's result data
245 myAC.getInputEl().value = oData.nname;
177 myAC.getInputEl().value = oData.nname;
246 };
178 };
247
179
248 oAC_perms.itemSelectEvent.subscribe(myHandler);
180 oAC_perms.itemSelectEvent.subscribe(myHandler);
249 //oAC_owner.itemSelectEvent.subscribe(myHandler);
181 //oAC_owner.itemSelectEvent.subscribe(myHandler);
250
182
251 return {
183 return {
252 oDS: oDS,
184 oDS: oDS,
253 oAC_perms: oAC_perms,
185 oAC_perms: oAC_perms,
254 oAC_owner: oAC_owner,
186 oAC_owner: oAC_owner,
255 };
187 };
256 }();
188 }();
257
189
258 </script>
190 </script>
259 </div>
191 </div>
260 </div>
192 </div>
261 </%def>
193 </%def>
262
194
263
195
General Comments 0
You need to be logged in to leave comments. Login now