##// END OF EJS Templates
Gist: don't allow files inside directories when creating gists
marcink -
r3846:2576a20d beta
parent child Browse files
Show More
@@ -1,434 +1,435 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 logging
22 import logging
23
23
24 import formencode
24 import formencode
25 from formencode import All
25 from formencode import All
26
26
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28
28
29 from rhodecode.model import validators as v
29 from rhodecode.model import validators as v
30 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
36 allow_extra_fields = True
36 allow_extra_fields = True
37 filter_extra_fields = True
37 filter_extra_fields = True
38 username = v.UnicodeString(
38 username = v.UnicodeString(
39 strip=True,
39 strip=True,
40 min=1,
40 min=1,
41 not_empty=True,
41 not_empty=True,
42 messages={
42 messages={
43 'empty': _(u'Please enter a login'),
43 'empty': _(u'Please enter a login'),
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 )
45 )
46
46
47 password = v.UnicodeString(
47 password = v.UnicodeString(
48 strip=False,
48 strip=False,
49 min=3,
49 min=3,
50 not_empty=True,
50 not_empty=True,
51 messages={
51 messages={
52 'empty': _(u'Please enter a password'),
52 'empty': _(u'Please enter a password'),
53 'tooShort': _(u'Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
54 )
54 )
55
55
56 remember = v.StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
57
57
58 chained_validators = [v.ValidAuth()]
58 chained_validators = [v.ValidAuth()]
59
59
60
60
61 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
62 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
63 allow_extra_fields = True
63 allow_extra_fields = True
64 filter_extra_fields = True
64 filter_extra_fields = True
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 v.ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
67 if edit:
67 if edit:
68 new_password = All(
68 new_password = All(
69 v.ValidPassword(),
69 v.ValidPassword(),
70 v.UnicodeString(strip=False, min=6, not_empty=False)
70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 )
71 )
72 password_confirmation = All(
72 password_confirmation = All(
73 v.ValidPassword(),
73 v.ValidPassword(),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 )
75 )
76 admin = v.StringBoolean(if_missing=False)
76 admin = v.StringBoolean(if_missing=False)
77 else:
77 else:
78 password = All(
78 password = All(
79 v.ValidPassword(),
79 v.ValidPassword(),
80 v.UnicodeString(strip=False, min=6, not_empty=True)
80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 )
81 )
82 password_confirmation = All(
82 password_confirmation = All(
83 v.ValidPassword(),
83 v.ValidPassword(),
84 v.UnicodeString(strip=False, min=6, not_empty=False)
84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 )
85 )
86
86
87 active = v.StringBoolean(if_missing=False)
87 active = v.StringBoolean(if_missing=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91
91
92 chained_validators = [v.ValidPasswordsMatch()]
92 chained_validators = [v.ValidPasswordsMatch()]
93
93
94 return _UserForm
94 return _UserForm
95
95
96
96
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
98 class _UserGroupForm(formencode.Schema):
98 class _UserGroupForm(formencode.Schema):
99 allow_extra_fields = True
99 allow_extra_fields = True
100 filter_extra_fields = True
100 filter_extra_fields = True
101
101
102 users_group_name = All(
102 users_group_name = All(
103 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 v.ValidUserGroup(edit, old_data)
104 v.ValidUserGroup(edit, old_data)
105 )
105 )
106
106
107 users_group_active = v.StringBoolean(if_missing=False)
107 users_group_active = v.StringBoolean(if_missing=False)
108
108
109 if edit:
109 if edit:
110 users_group_members = v.OneOf(
110 users_group_members = v.OneOf(
111 available_members, hideList=False, testValueList=True,
111 available_members, hideList=False, testValueList=True,
112 if_missing=None, not_empty=False
112 if_missing=None, not_empty=False
113 )
113 )
114
114
115 return _UserGroupForm
115 return _UserGroupForm
116
116
117
117
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
119 can_create_in_root=False):
119 can_create_in_root=False):
120 class _ReposGroupForm(formencode.Schema):
120 class _ReposGroupForm(formencode.Schema):
121 allow_extra_fields = True
121 allow_extra_fields = True
122 filter_extra_fields = False
122 filter_extra_fields = False
123
123
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
125 v.SlugifyName())
125 v.SlugifyName())
126 group_description = v.UnicodeString(strip=True, min=1,
126 group_description = v.UnicodeString(strip=True, min=1,
127 not_empty=False)
127 not_empty=False)
128 if edit:
128 if edit:
129 #FIXME: do a special check that we cannot move a group to one of
129 #FIXME: do a special check that we cannot move a group to one of
130 #it's children
130 #it's children
131 pass
131 pass
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
133 v.OneOf(available_groups, hideList=False,
133 v.OneOf(available_groups, hideList=False,
134 testValueList=True,
134 testValueList=True,
135 if_missing=None, not_empty=True))
135 if_missing=None, not_empty=True))
136 enable_locking = v.StringBoolean(if_missing=False)
136 enable_locking = v.StringBoolean(if_missing=False)
137 chained_validators = [v.ValidReposGroup(edit, old_data)]
137 chained_validators = [v.ValidReposGroup(edit, old_data)]
138
138
139 return _ReposGroupForm
139 return _ReposGroupForm
140
140
141
141
142 def RegisterForm(edit=False, old_data={}):
142 def RegisterForm(edit=False, old_data={}):
143 class _RegisterForm(formencode.Schema):
143 class _RegisterForm(formencode.Schema):
144 allow_extra_fields = True
144 allow_extra_fields = True
145 filter_extra_fields = True
145 filter_extra_fields = True
146 username = All(
146 username = All(
147 v.ValidUsername(edit, old_data),
147 v.ValidUsername(edit, old_data),
148 v.UnicodeString(strip=True, min=1, not_empty=True)
148 v.UnicodeString(strip=True, min=1, not_empty=True)
149 )
149 )
150 password = All(
150 password = All(
151 v.ValidPassword(),
151 v.ValidPassword(),
152 v.UnicodeString(strip=False, min=6, not_empty=True)
152 v.UnicodeString(strip=False, min=6, not_empty=True)
153 )
153 )
154 password_confirmation = All(
154 password_confirmation = All(
155 v.ValidPassword(),
155 v.ValidPassword(),
156 v.UnicodeString(strip=False, min=6, not_empty=True)
156 v.UnicodeString(strip=False, min=6, not_empty=True)
157 )
157 )
158 active = v.StringBoolean(if_missing=False)
158 active = v.StringBoolean(if_missing=False)
159 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
159 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
160 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
160 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
161 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
161 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
162
162
163 chained_validators = [v.ValidPasswordsMatch()]
163 chained_validators = [v.ValidPasswordsMatch()]
164
164
165 return _RegisterForm
165 return _RegisterForm
166
166
167
167
168 def PasswordResetForm():
168 def PasswordResetForm():
169 class _PasswordResetForm(formencode.Schema):
169 class _PasswordResetForm(formencode.Schema):
170 allow_extra_fields = True
170 allow_extra_fields = True
171 filter_extra_fields = True
171 filter_extra_fields = True
172 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
172 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
173 return _PasswordResetForm
173 return _PasswordResetForm
174
174
175
175
176 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
176 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
177 repo_groups=[], landing_revs=[]):
177 repo_groups=[], landing_revs=[]):
178 class _RepoForm(formencode.Schema):
178 class _RepoForm(formencode.Schema):
179 allow_extra_fields = True
179 allow_extra_fields = True
180 filter_extra_fields = False
180 filter_extra_fields = False
181 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
181 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
182 v.SlugifyName())
182 v.SlugifyName())
183 repo_group = All(v.CanWriteGroup(old_data),
183 repo_group = All(v.CanWriteGroup(old_data),
184 v.OneOf(repo_groups, hideList=True))
184 v.OneOf(repo_groups, hideList=True))
185 repo_type = v.OneOf(supported_backends)
185 repo_type = v.OneOf(supported_backends)
186 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
186 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
187 repo_private = v.StringBoolean(if_missing=False)
187 repo_private = v.StringBoolean(if_missing=False)
188 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
188 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
189 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
189 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
190
190
191 repo_enable_statistics = v.StringBoolean(if_missing=False)
191 repo_enable_statistics = v.StringBoolean(if_missing=False)
192 repo_enable_downloads = v.StringBoolean(if_missing=False)
192 repo_enable_downloads = v.StringBoolean(if_missing=False)
193 repo_enable_locking = v.StringBoolean(if_missing=False)
193 repo_enable_locking = v.StringBoolean(if_missing=False)
194
194
195 if edit:
195 if edit:
196 #this is repo owner
196 #this is repo owner
197 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
197 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
198
198
199 chained_validators = [v.ValidCloneUri(),
199 chained_validators = [v.ValidCloneUri(),
200 v.ValidRepoName(edit, old_data)]
200 v.ValidRepoName(edit, old_data)]
201 return _RepoForm
201 return _RepoForm
202
202
203
203
204 def RepoPermsForm():
204 def RepoPermsForm():
205 class _RepoPermsForm(formencode.Schema):
205 class _RepoPermsForm(formencode.Schema):
206 allow_extra_fields = True
206 allow_extra_fields = True
207 filter_extra_fields = False
207 filter_extra_fields = False
208 chained_validators = [v.ValidPerms(type_='repo')]
208 chained_validators = [v.ValidPerms(type_='repo')]
209 return _RepoPermsForm
209 return _RepoPermsForm
210
210
211
211
212 def RepoGroupPermsForm():
212 def RepoGroupPermsForm():
213 class _RepoGroupPermsForm(formencode.Schema):
213 class _RepoGroupPermsForm(formencode.Schema):
214 allow_extra_fields = True
214 allow_extra_fields = True
215 filter_extra_fields = False
215 filter_extra_fields = False
216 recursive = v.StringBoolean(if_missing=False)
216 recursive = v.StringBoolean(if_missing=False)
217 chained_validators = [v.ValidPerms(type_='repo_group')]
217 chained_validators = [v.ValidPerms(type_='repo_group')]
218 return _RepoGroupPermsForm
218 return _RepoGroupPermsForm
219
219
220
220
221 def UserGroupPermsForm():
221 def UserGroupPermsForm():
222 class _UserPermsForm(formencode.Schema):
222 class _UserPermsForm(formencode.Schema):
223 allow_extra_fields = True
223 allow_extra_fields = True
224 filter_extra_fields = False
224 filter_extra_fields = False
225 chained_validators = [v.ValidPerms(type_='user_group')]
225 chained_validators = [v.ValidPerms(type_='user_group')]
226 return _UserPermsForm
226 return _UserPermsForm
227
227
228
228
229 def RepoFieldForm():
229 def RepoFieldForm():
230 class _RepoFieldForm(formencode.Schema):
230 class _RepoFieldForm(formencode.Schema):
231 filter_extra_fields = True
231 filter_extra_fields = True
232 allow_extra_fields = True
232 allow_extra_fields = True
233
233
234 new_field_key = All(v.FieldKey(),
234 new_field_key = All(v.FieldKey(),
235 v.UnicodeString(strip=True, min=3, not_empty=True))
235 v.UnicodeString(strip=True, min=3, not_empty=True))
236 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
236 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
237 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
237 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
238 if_missing='str')
238 if_missing='str')
239 new_field_label = v.UnicodeString(not_empty=False)
239 new_field_label = v.UnicodeString(not_empty=False)
240 new_field_desc = v.UnicodeString(not_empty=False)
240 new_field_desc = v.UnicodeString(not_empty=False)
241
241
242 return _RepoFieldForm
242 return _RepoFieldForm
243
243
244
244
245 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
245 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
246 repo_groups=[], landing_revs=[]):
246 repo_groups=[], landing_revs=[]):
247 class _RepoForkForm(formencode.Schema):
247 class _RepoForkForm(formencode.Schema):
248 allow_extra_fields = True
248 allow_extra_fields = True
249 filter_extra_fields = False
249 filter_extra_fields = False
250 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
250 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
251 v.SlugifyName())
251 v.SlugifyName())
252 repo_group = All(v.CanWriteGroup(),
252 repo_group = All(v.CanWriteGroup(),
253 v.OneOf(repo_groups, hideList=True))
253 v.OneOf(repo_groups, hideList=True))
254 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
254 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
255 description = v.UnicodeString(strip=True, min=1, not_empty=True)
255 description = v.UnicodeString(strip=True, min=1, not_empty=True)
256 private = v.StringBoolean(if_missing=False)
256 private = v.StringBoolean(if_missing=False)
257 copy_permissions = v.StringBoolean(if_missing=False)
257 copy_permissions = v.StringBoolean(if_missing=False)
258 update_after_clone = v.StringBoolean(if_missing=False)
258 update_after_clone = v.StringBoolean(if_missing=False)
259 fork_parent_id = v.UnicodeString()
259 fork_parent_id = v.UnicodeString()
260 chained_validators = [v.ValidForkName(edit, old_data)]
260 chained_validators = [v.ValidForkName(edit, old_data)]
261 landing_rev = v.OneOf(landing_revs, hideList=True)
261 landing_rev = v.OneOf(landing_revs, hideList=True)
262
262
263 return _RepoForkForm
263 return _RepoForkForm
264
264
265
265
266 def ApplicationSettingsForm():
266 def ApplicationSettingsForm():
267 class _ApplicationSettingsForm(formencode.Schema):
267 class _ApplicationSettingsForm(formencode.Schema):
268 allow_extra_fields = True
268 allow_extra_fields = True
269 filter_extra_fields = False
269 filter_extra_fields = False
270 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
270 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
271 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
271 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
272 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
272 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
273
273
274 return _ApplicationSettingsForm
274 return _ApplicationSettingsForm
275
275
276
276
277 def ApplicationVisualisationForm():
277 def ApplicationVisualisationForm():
278 class _ApplicationVisualisationForm(formencode.Schema):
278 class _ApplicationVisualisationForm(formencode.Schema):
279 allow_extra_fields = True
279 allow_extra_fields = True
280 filter_extra_fields = False
280 filter_extra_fields = False
281 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
281 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
282 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
282 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
283 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
283 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
284
284
285 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
285 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
286 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
286 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
287
287
288 return _ApplicationVisualisationForm
288 return _ApplicationVisualisationForm
289
289
290
290
291 def ApplicationUiSettingsForm():
291 def ApplicationUiSettingsForm():
292 class _ApplicationUiSettingsForm(formencode.Schema):
292 class _ApplicationUiSettingsForm(formencode.Schema):
293 allow_extra_fields = True
293 allow_extra_fields = True
294 filter_extra_fields = False
294 filter_extra_fields = False
295 web_push_ssl = v.StringBoolean(if_missing=False)
295 web_push_ssl = v.StringBoolean(if_missing=False)
296 paths_root_path = All(
296 paths_root_path = All(
297 v.ValidPath(),
297 v.ValidPath(),
298 v.UnicodeString(strip=True, min=1, not_empty=True)
298 v.UnicodeString(strip=True, min=1, not_empty=True)
299 )
299 )
300 hooks_changegroup_update = v.StringBoolean(if_missing=False)
300 hooks_changegroup_update = v.StringBoolean(if_missing=False)
301 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
301 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
302 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
302 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
303 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
303 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
304
304
305 extensions_largefiles = v.StringBoolean(if_missing=False)
305 extensions_largefiles = v.StringBoolean(if_missing=False)
306 extensions_hgsubversion = v.StringBoolean(if_missing=False)
306 extensions_hgsubversion = v.StringBoolean(if_missing=False)
307 extensions_hggit = v.StringBoolean(if_missing=False)
307 extensions_hggit = v.StringBoolean(if_missing=False)
308
308
309 return _ApplicationUiSettingsForm
309 return _ApplicationUiSettingsForm
310
310
311
311
312 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
312 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
313 user_group_perms_choices, create_choices,
313 user_group_perms_choices, create_choices,
314 repo_group_create_choices, user_group_create_choices,
314 repo_group_create_choices, user_group_create_choices,
315 fork_choices, register_choices, extern_activate_choices):
315 fork_choices, register_choices, extern_activate_choices):
316 class _DefaultPermissionsForm(formencode.Schema):
316 class _DefaultPermissionsForm(formencode.Schema):
317 allow_extra_fields = True
317 allow_extra_fields = True
318 filter_extra_fields = True
318 filter_extra_fields = True
319 overwrite_default_repo = v.StringBoolean(if_missing=False)
319 overwrite_default_repo = v.StringBoolean(if_missing=False)
320 overwrite_default_group = v.StringBoolean(if_missing=False)
320 overwrite_default_group = v.StringBoolean(if_missing=False)
321 overwrite_default_user_group = v.StringBoolean(if_missing=False)
321 overwrite_default_user_group = v.StringBoolean(if_missing=False)
322 anonymous = v.StringBoolean(if_missing=False)
322 anonymous = v.StringBoolean(if_missing=False)
323 default_repo_perm = v.OneOf(repo_perms_choices)
323 default_repo_perm = v.OneOf(repo_perms_choices)
324 default_group_perm = v.OneOf(group_perms_choices)
324 default_group_perm = v.OneOf(group_perms_choices)
325 default_user_group_perm = v.OneOf(user_group_perms_choices)
325 default_user_group_perm = v.OneOf(user_group_perms_choices)
326
326
327 default_repo_create = v.OneOf(create_choices)
327 default_repo_create = v.OneOf(create_choices)
328 default_user_group_create = v.OneOf(user_group_create_choices)
328 default_user_group_create = v.OneOf(user_group_create_choices)
329 #default_repo_group_create = v.OneOf(repo_group_create_choices) #not impl. yet
329 #default_repo_group_create = v.OneOf(repo_group_create_choices) #not impl. yet
330 default_fork = v.OneOf(fork_choices)
330 default_fork = v.OneOf(fork_choices)
331
331
332 default_register = v.OneOf(register_choices)
332 default_register = v.OneOf(register_choices)
333 default_extern_activate = v.OneOf(extern_activate_choices)
333 default_extern_activate = v.OneOf(extern_activate_choices)
334 return _DefaultPermissionsForm
334 return _DefaultPermissionsForm
335
335
336
336
337 def CustomDefaultPermissionsForm():
337 def CustomDefaultPermissionsForm():
338 class _CustomDefaultPermissionsForm(formencode.Schema):
338 class _CustomDefaultPermissionsForm(formencode.Schema):
339 filter_extra_fields = True
339 filter_extra_fields = True
340 allow_extra_fields = True
340 allow_extra_fields = True
341 inherit_default_permissions = v.StringBoolean(if_missing=False)
341 inherit_default_permissions = v.StringBoolean(if_missing=False)
342
342
343 create_repo_perm = v.StringBoolean(if_missing=False)
343 create_repo_perm = v.StringBoolean(if_missing=False)
344 create_user_group_perm = v.StringBoolean(if_missing=False)
344 create_user_group_perm = v.StringBoolean(if_missing=False)
345 #create_repo_group_perm Impl. later
345 #create_repo_group_perm Impl. later
346
346
347 fork_repo_perm = v.StringBoolean(if_missing=False)
347 fork_repo_perm = v.StringBoolean(if_missing=False)
348
348
349 return _CustomDefaultPermissionsForm
349 return _CustomDefaultPermissionsForm
350
350
351
351
352 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
352 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
353 class _DefaultsForm(formencode.Schema):
353 class _DefaultsForm(formencode.Schema):
354 allow_extra_fields = True
354 allow_extra_fields = True
355 filter_extra_fields = True
355 filter_extra_fields = True
356 default_repo_type = v.OneOf(supported_backends)
356 default_repo_type = v.OneOf(supported_backends)
357 default_repo_private = v.StringBoolean(if_missing=False)
357 default_repo_private = v.StringBoolean(if_missing=False)
358 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
358 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
359 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
359 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
360 default_repo_enable_locking = v.StringBoolean(if_missing=False)
360 default_repo_enable_locking = v.StringBoolean(if_missing=False)
361
361
362 return _DefaultsForm
362 return _DefaultsForm
363
363
364
364
365 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
365 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
366 tls_kind_choices):
366 tls_kind_choices):
367 class _LdapSettingsForm(formencode.Schema):
367 class _LdapSettingsForm(formencode.Schema):
368 allow_extra_fields = True
368 allow_extra_fields = True
369 filter_extra_fields = True
369 filter_extra_fields = True
370 #pre_validators = [LdapLibValidator]
370 #pre_validators = [LdapLibValidator]
371 ldap_active = v.StringBoolean(if_missing=False)
371 ldap_active = v.StringBoolean(if_missing=False)
372 ldap_host = v.UnicodeString(strip=True,)
372 ldap_host = v.UnicodeString(strip=True,)
373 ldap_port = v.Number(strip=True,)
373 ldap_port = v.Number(strip=True,)
374 ldap_tls_kind = v.OneOf(tls_kind_choices)
374 ldap_tls_kind = v.OneOf(tls_kind_choices)
375 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
375 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
376 ldap_dn_user = v.UnicodeString(strip=True,)
376 ldap_dn_user = v.UnicodeString(strip=True,)
377 ldap_dn_pass = v.UnicodeString(strip=True,)
377 ldap_dn_pass = v.UnicodeString(strip=True,)
378 ldap_base_dn = v.UnicodeString(strip=True,)
378 ldap_base_dn = v.UnicodeString(strip=True,)
379 ldap_filter = v.UnicodeString(strip=True,)
379 ldap_filter = v.UnicodeString(strip=True,)
380 ldap_search_scope = v.OneOf(search_scope_choices)
380 ldap_search_scope = v.OneOf(search_scope_choices)
381 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
381 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
382 ldap_attr_firstname = v.UnicodeString(strip=True,)
382 ldap_attr_firstname = v.UnicodeString(strip=True,)
383 ldap_attr_lastname = v.UnicodeString(strip=True,)
383 ldap_attr_lastname = v.UnicodeString(strip=True,)
384 ldap_attr_email = v.UnicodeString(strip=True,)
384 ldap_attr_email = v.UnicodeString(strip=True,)
385
385
386 return _LdapSettingsForm
386 return _LdapSettingsForm
387
387
388
388
389 def UserExtraEmailForm():
389 def UserExtraEmailForm():
390 class _UserExtraEmailForm(formencode.Schema):
390 class _UserExtraEmailForm(formencode.Schema):
391 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
391 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
392 return _UserExtraEmailForm
392 return _UserExtraEmailForm
393
393
394
394
395 def UserExtraIpForm():
395 def UserExtraIpForm():
396 class _UserExtraIpForm(formencode.Schema):
396 class _UserExtraIpForm(formencode.Schema):
397 ip = v.ValidIp()(not_empty=True)
397 ip = v.ValidIp()(not_empty=True)
398 return _UserExtraIpForm
398 return _UserExtraIpForm
399
399
400
400
401 def PullRequestForm(repo_id):
401 def PullRequestForm(repo_id):
402 class _PullRequestForm(formencode.Schema):
402 class _PullRequestForm(formencode.Schema):
403 allow_extra_fields = True
403 allow_extra_fields = True
404 filter_extra_fields = True
404 filter_extra_fields = True
405
405
406 user = v.UnicodeString(strip=True, required=True)
406 user = v.UnicodeString(strip=True, required=True)
407 org_repo = v.UnicodeString(strip=True, required=True)
407 org_repo = v.UnicodeString(strip=True, required=True)
408 org_ref = v.UnicodeString(strip=True, required=True)
408 org_ref = v.UnicodeString(strip=True, required=True)
409 other_repo = v.UnicodeString(strip=True, required=True)
409 other_repo = v.UnicodeString(strip=True, required=True)
410 other_ref = v.UnicodeString(strip=True, required=True)
410 other_ref = v.UnicodeString(strip=True, required=True)
411 revisions = All(#v.NotReviewedRevisions(repo_id)(),
411 revisions = All(#v.NotReviewedRevisions(repo_id)(),
412 v.UniqueList(not_empty=True))
412 v.UniqueList(not_empty=True))
413 review_members = v.UniqueList(not_empty=True)
413 review_members = v.UniqueList(not_empty=True)
414
414
415 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
415 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
416 pullrequest_desc = v.UnicodeString(strip=True, required=False)
416 pullrequest_desc = v.UnicodeString(strip=True, required=False)
417
417
418 ancestor_rev = v.UnicodeString(strip=True, required=True)
418 ancestor_rev = v.UnicodeString(strip=True, required=True)
419 merge_rev = v.UnicodeString(strip=True, required=True)
419 merge_rev = v.UnicodeString(strip=True, required=True)
420
420
421 return _PullRequestForm
421 return _PullRequestForm
422
422
423
423
424 def GistForm(lifetime_options):
424 def GistForm(lifetime_options):
425 class _GistForm(formencode.Schema):
425 class _GistForm(formencode.Schema):
426
426
427 filename = v.UnicodeString(strip=True, required=False)
427 filename = All(v.BasePath()(),
428 v.UnicodeString(strip=True, required=False))
428 description = v.UnicodeString(required=False, if_missing='')
429 description = v.UnicodeString(required=False, if_missing='')
429 lifetime = v.OneOf(lifetime_options)
430 lifetime = v.OneOf(lifetime_options)
430 content = v.UnicodeString(required=True, not_empty=True)
431 content = v.UnicodeString(required=True, not_empty=True)
431 public = v.UnicodeString(required=False, if_missing='')
432 public = v.UnicodeString(required=False, if_missing='')
432 private = v.UnicodeString(required=False, if_missing='')
433 private = v.UnicodeString(required=False, if_missing='')
433
434
434 return _GistForm
435 return _GistForm
@@ -1,173 +1,176 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.gist
3 rhodecode.model.gist
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 gist model for RhodeCode
6 gist model for RhodeCode
7
7
8 :created_on: May 9, 2013
8 :created_on: May 9, 2013
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2013 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2013 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import time
27 import time
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import shutil
30 import shutil
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from rhodecode.lib.utils2 import safe_unicode, unique_id, safe_int, \
33 from rhodecode.lib.utils2 import safe_unicode, unique_id, safe_int, \
34 time_to_datetime, safe_str, AttributeDict
34 time_to_datetime, safe_str, AttributeDict
35 from rhodecode.lib.compat import json
35 from rhodecode.lib.compat import json
36 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
37 from rhodecode.model import BaseModel
37 from rhodecode.model import BaseModel
38 from rhodecode.model.db import Gist
38 from rhodecode.model.db import Gist
39 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.scm import ScmModel
40 from rhodecode.model.scm import ScmModel
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44 GIST_STORE_LOC = '.rc_gist_store'
44 GIST_STORE_LOC = '.rc_gist_store'
45 GIST_METADATA_FILE = '.rc_gist_metadata'
45 GIST_METADATA_FILE = '.rc_gist_metadata'
46
46
47
47
48 class GistModel(BaseModel):
48 class GistModel(BaseModel):
49
49
50 def _get_gist(self, gist):
50 def _get_gist(self, gist):
51 """
51 """
52 Helper method to get gist by ID, or gist_access_id as a fallback
52 Helper method to get gist by ID, or gist_access_id as a fallback
53
53
54 :param gist: GistID, gist_access_id, or Gist instance
54 :param gist: GistID, gist_access_id, or Gist instance
55 """
55 """
56 return self._get_instance(Gist, gist,
56 return self._get_instance(Gist, gist,
57 callback=Gist.get_by_access_id)
57 callback=Gist.get_by_access_id)
58
58
59 def __delete_gist(self, gist):
59 def __delete_gist(self, gist):
60 """
60 """
61 removes gist from filesystem
61 removes gist from filesystem
62
62
63 :param gist: gist object
63 :param gist: gist object
64 """
64 """
65 root_path = RepoModel().repos_path
65 root_path = RepoModel().repos_path
66 rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
66 rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
67 log.info("Removing %s" % (rm_path))
67 log.info("Removing %s" % (rm_path))
68 shutil.rmtree(rm_path)
68 shutil.rmtree(rm_path)
69
69
70 def get_gist(self, gist):
70 def get_gist(self, gist):
71 return self._get_gist(gist)
71 return self._get_gist(gist)
72
72
73 def get_gist_files(self, gist_access_id):
73 def get_gist_files(self, gist_access_id):
74 """
74 """
75 Get files for given gist
75 Get files for given gist
76
76
77 :param gist_access_id:
77 :param gist_access_id:
78 """
78 """
79 repo = Gist.get_by_access_id(gist_access_id)
79 repo = Gist.get_by_access_id(gist_access_id)
80 cs = repo.scm_instance.get_changeset()
80 cs = repo.scm_instance.get_changeset()
81 return (
81 return (
82 cs, [n for n in cs.get_node('/')]
82 cs, [n for n in cs.get_node('/')]
83 )
83 )
84
84
85 def create(self, description, owner, gist_mapping,
85 def create(self, description, owner, gist_mapping,
86 gist_type=Gist.GIST_PUBLIC, lifetime=-1):
86 gist_type=Gist.GIST_PUBLIC, lifetime=-1):
87 """
87 """
88
88
89 :param description: description of the gist
89 :param description: description of the gist
90 :param owner: user who created this gist
90 :param owner: user who created this gist
91 :param gist_mapping: mapping {filename:{'content':content},...}
91 :param gist_mapping: mapping {filename:{'content':content},...}
92 :param gist_type: type of gist private/public
92 :param gist_type: type of gist private/public
93 :param lifetime: in minutes, -1 == forever
93 :param lifetime: in minutes, -1 == forever
94 """
94 """
95 gist_id = safe_unicode(unique_id(20))
95 gist_id = safe_unicode(unique_id(20))
96 lifetime = safe_int(lifetime, -1)
96 lifetime = safe_int(lifetime, -1)
97 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
97 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
98 log.debug('set GIST expiration date to: %s'
98 log.debug('set GIST expiration date to: %s'
99 % (time_to_datetime(gist_expires)
99 % (time_to_datetime(gist_expires)
100 if gist_expires != -1 else 'forever'))
100 if gist_expires != -1 else 'forever'))
101 #create the Database version
101 #create the Database version
102 gist = Gist()
102 gist = Gist()
103 gist.gist_description = description
103 gist.gist_description = description
104 gist.gist_access_id = gist_id
104 gist.gist_access_id = gist_id
105 gist.gist_owner = owner.user_id
105 gist.gist_owner = owner.user_id
106 gist.gist_expires = gist_expires
106 gist.gist_expires = gist_expires
107 gist.gist_type = safe_unicode(gist_type)
107 gist.gist_type = safe_unicode(gist_type)
108 self.sa.add(gist)
108 self.sa.add(gist)
109 self.sa.flush()
109 self.sa.flush()
110 if gist_type == Gist.GIST_PUBLIC:
110 if gist_type == Gist.GIST_PUBLIC:
111 # use DB ID for easy to use GIST ID
111 # use DB ID for easy to use GIST ID
112 gist_id = safe_unicode(gist.gist_id)
112 gist_id = safe_unicode(gist.gist_id)
113 gist.gist_access_id = gist_id
113 gist.gist_access_id = gist_id
114 self.sa.add(gist)
114 self.sa.add(gist)
115
115
116 gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
116 gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
117 log.debug('Creating new %s GIST repo in %s' % (gist_type, gist_repo_path))
117 log.debug('Creating new %s GIST repo in %s' % (gist_type, gist_repo_path))
118 repo = RepoModel()._create_repo(repo_name=gist_repo_path, alias='hg',
118 repo = RepoModel()._create_repo(repo_name=gist_repo_path, alias='hg',
119 parent=None)
119 parent=None)
120
120
121 processed_mapping = {}
121 processed_mapping = {}
122 for filename in gist_mapping:
122 for filename in gist_mapping:
123 if filename != os.path.basename(filename):
124 raise Exception('Filename cannot be inside a directory')
125
123 content = gist_mapping[filename]['content']
126 content = gist_mapping[filename]['content']
124 #TODO: expand support for setting explicit lexers
127 #TODO: expand support for setting explicit lexers
125 # if lexer is None:
128 # if lexer is None:
126 # try:
129 # try:
127 # lexer = pygments.lexers.guess_lexer_for_filename(filename,content)
130 # lexer = pygments.lexers.guess_lexer_for_filename(filename,content)
128 # except pygments.util.ClassNotFound:
131 # except pygments.util.ClassNotFound:
129 # lexer = 'text'
132 # lexer = 'text'
130 processed_mapping[filename] = {'content': content}
133 processed_mapping[filename] = {'content': content}
131
134
132 # now create single multifile commit
135 # now create single multifile commit
133 message = 'added file'
136 message = 'added file'
134 message += 's: ' if len(processed_mapping) > 1 else ': '
137 message += 's: ' if len(processed_mapping) > 1 else ': '
135 message += ', '.join([x for x in processed_mapping])
138 message += ', '.join([x for x in processed_mapping])
136
139
137 #fake RhodeCode Repository object
140 #fake RhodeCode Repository object
138 fake_repo = AttributeDict(dict(
141 fake_repo = AttributeDict(dict(
139 repo_name=gist_repo_path,
142 repo_name=gist_repo_path,
140 scm_instance_no_cache=lambda: repo,
143 scm_instance_no_cache=lambda: repo,
141 ))
144 ))
142 ScmModel().create_nodes(
145 ScmModel().create_nodes(
143 user=owner.user_id, repo=fake_repo,
146 user=owner.user_id, repo=fake_repo,
144 message=message,
147 message=message,
145 nodes=processed_mapping,
148 nodes=processed_mapping,
146 trigger_push_hook=False
149 trigger_push_hook=False
147 )
150 )
148 # store metadata inside the gist, this can be later used for imports
151 # store metadata inside the gist, this can be later used for imports
149 # or gist identification
152 # or gist identification
150 metadata = {
153 metadata = {
151 'gist_db_id': gist.gist_id,
154 'gist_db_id': gist.gist_id,
152 'gist_access_id': gist.gist_access_id,
155 'gist_access_id': gist.gist_access_id,
153 'gist_owner_id': owner.user_id,
156 'gist_owner_id': owner.user_id,
154 'gist_type': gist.gist_type,
157 'gist_type': gist.gist_type,
155 'gist_exipres': gist.gist_expires
158 'gist_exipres': gist.gist_expires
156 }
159 }
157 with open(os.path.join(repo.path, '.hg', GIST_METADATA_FILE), 'wb') as f:
160 with open(os.path.join(repo.path, '.hg', GIST_METADATA_FILE), 'wb') as f:
158 f.write(json.dumps(metadata))
161 f.write(json.dumps(metadata))
159 return gist
162 return gist
160
163
161 def delete(self, gist, fs_remove=True):
164 def delete(self, gist, fs_remove=True):
162 gist = self._get_gist(gist)
165 gist = self._get_gist(gist)
163
166
164 try:
167 try:
165 self.sa.delete(gist)
168 self.sa.delete(gist)
166 if fs_remove:
169 if fs_remove:
167 self.__delete_gist(gist)
170 self.__delete_gist(gist)
168 else:
171 else:
169 log.debug('skipping removal from filesystem')
172 log.debug('skipping removal from filesystem')
170
173
171 except Exception:
174 except Exception:
172 log.error(traceback.format_exc())
175 log.error(traceback.format_exc())
173 raise
176 raise
@@ -1,809 +1,827 b''
1 """
1 """
2 Set of generic validators
2 Set of generic validators
3 """
3 """
4 import os
4 import os
5 import re
5 import re
6 import formencode
6 import formencode
7 import logging
7 import logging
8 from collections import defaultdict
8 from collections import defaultdict
9 from pylons.i18n.translation import _
9 from pylons.i18n.translation import _
10 from webhelpers.pylonslib.secure_form import authentication_token
10 from webhelpers.pylonslib.secure_form import authentication_token
11
11
12 from formencode.validators import (
12 from formencode.validators import (
13 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
13 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
14 NotEmpty, IPAddress, CIDR, String, FancyValidator
14 NotEmpty, IPAddress, CIDR, String, FancyValidator
15 )
15 )
16 from rhodecode.lib.compat import OrderedSet
16 from rhodecode.lib.compat import OrderedSet
17 from rhodecode.lib import ipaddr
17 from rhodecode.lib import ipaddr
18 from rhodecode.lib.utils import repo_name_slug
18 from rhodecode.lib.utils import repo_name_slug
19 from rhodecode.lib.utils2 import safe_int, str2bool
19 from rhodecode.lib.utils2 import safe_int, str2bool
20 from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\
20 from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\
21 ChangesetStatus
21 ChangesetStatus
22 from rhodecode.lib.exceptions import LdapImportError
22 from rhodecode.lib.exceptions import LdapImportError
23 from rhodecode.config.routing import ADMIN_PREFIX
23 from rhodecode.config.routing import ADMIN_PREFIX
24 from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny
24 from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny
25
25
26 # silence warnings and pylint
26 # silence warnings and pylint
27 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
27 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
28 NotEmpty, IPAddress, CIDR, String, FancyValidator
28 NotEmpty, IPAddress, CIDR, String, FancyValidator
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32
32
33 class UniqueList(formencode.FancyValidator):
33 class UniqueList(formencode.FancyValidator):
34 """
34 """
35 Unique List !
35 Unique List !
36 """
36 """
37 messages = dict(
37 messages = dict(
38 empty=_('Value cannot be an empty list'),
38 empty=_('Value cannot be an empty list'),
39 missing_value=_('Value cannot be an empty list'),
39 missing_value=_('Value cannot be an empty list'),
40 )
40 )
41
41
42 def _to_python(self, value, state):
42 def _to_python(self, value, state):
43 if isinstance(value, list):
43 if isinstance(value, list):
44 return value
44 return value
45 elif isinstance(value, set):
45 elif isinstance(value, set):
46 return list(value)
46 return list(value)
47 elif isinstance(value, tuple):
47 elif isinstance(value, tuple):
48 return list(value)
48 return list(value)
49 elif value is None:
49 elif value is None:
50 return []
50 return []
51 else:
51 else:
52 return [value]
52 return [value]
53
53
54 def empty_value(self, value):
54 def empty_value(self, value):
55 return []
55 return []
56
56
57
57
58 class StateObj(object):
58 class StateObj(object):
59 """
59 """
60 this is needed to translate the messages using _() in validators
60 this is needed to translate the messages using _() in validators
61 """
61 """
62 _ = staticmethod(_)
62 _ = staticmethod(_)
63
63
64
64
65 def M(self, key, state=None, **kwargs):
65 def M(self, key, state=None, **kwargs):
66 """
66 """
67 returns string from self.message based on given key,
67 returns string from self.message based on given key,
68 passed kw params are used to substitute %(named)s params inside
68 passed kw params are used to substitute %(named)s params inside
69 translated strings
69 translated strings
70
70
71 :param msg:
71 :param msg:
72 :param state:
72 :param state:
73 """
73 """
74 if state is None:
74 if state is None:
75 state = StateObj()
75 state = StateObj()
76 else:
76 else:
77 state._ = staticmethod(_)
77 state._ = staticmethod(_)
78 #inject validator into state object
78 #inject validator into state object
79 return self.message(key, state, **kwargs)
79 return self.message(key, state, **kwargs)
80
80
81
81
82 def ValidUsername(edit=False, old_data={}):
82 def ValidUsername(edit=False, old_data={}):
83 class _validator(formencode.validators.FancyValidator):
83 class _validator(formencode.validators.FancyValidator):
84 messages = {
84 messages = {
85 'username_exists': _(u'Username "%(username)s" already exists'),
85 'username_exists': _(u'Username "%(username)s" already exists'),
86 'system_invalid_username':
86 'system_invalid_username':
87 _(u'Username "%(username)s" is forbidden'),
87 _(u'Username "%(username)s" is forbidden'),
88 'invalid_username':
88 'invalid_username':
89 _(u'Username may only contain alphanumeric characters '
89 _(u'Username may only contain alphanumeric characters '
90 'underscores, periods or dashes and must begin with '
90 'underscores, periods or dashes and must begin with '
91 'alphanumeric character')
91 'alphanumeric character')
92 }
92 }
93
93
94 def validate_python(self, value, state):
94 def validate_python(self, value, state):
95 if value in ['default', 'new_user']:
95 if value in ['default', 'new_user']:
96 msg = M(self, 'system_invalid_username', state, username=value)
96 msg = M(self, 'system_invalid_username', state, username=value)
97 raise formencode.Invalid(msg, value, state)
97 raise formencode.Invalid(msg, value, state)
98 #check if user is unique
98 #check if user is unique
99 old_un = None
99 old_un = None
100 if edit:
100 if edit:
101 old_un = User.get(old_data.get('user_id')).username
101 old_un = User.get(old_data.get('user_id')).username
102
102
103 if old_un != value or not edit:
103 if old_un != value or not edit:
104 if User.get_by_username(value, case_insensitive=True):
104 if User.get_by_username(value, case_insensitive=True):
105 msg = M(self, 'username_exists', state, username=value)
105 msg = M(self, 'username_exists', state, username=value)
106 raise formencode.Invalid(msg, value, state)
106 raise formencode.Invalid(msg, value, state)
107
107
108 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*$', value) is None:
108 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*$', value) is None:
109 msg = M(self, 'invalid_username', state)
109 msg = M(self, 'invalid_username', state)
110 raise formencode.Invalid(msg, value, state)
110 raise formencode.Invalid(msg, value, state)
111 return _validator
111 return _validator
112
112
113
113
114 def ValidRepoUser():
114 def ValidRepoUser():
115 class _validator(formencode.validators.FancyValidator):
115 class _validator(formencode.validators.FancyValidator):
116 messages = {
116 messages = {
117 'invalid_username': _(u'Username %(username)s is not valid')
117 'invalid_username': _(u'Username %(username)s is not valid')
118 }
118 }
119
119
120 def validate_python(self, value, state):
120 def validate_python(self, value, state):
121 try:
121 try:
122 User.query().filter(User.active == True)\
122 User.query().filter(User.active == True)\
123 .filter(User.username == value).one()
123 .filter(User.username == value).one()
124 except Exception:
124 except Exception:
125 msg = M(self, 'invalid_username', state, username=value)
125 msg = M(self, 'invalid_username', state, username=value)
126 raise formencode.Invalid(msg, value, state,
126 raise formencode.Invalid(msg, value, state,
127 error_dict=dict(username=msg)
127 error_dict=dict(username=msg)
128 )
128 )
129
129
130 return _validator
130 return _validator
131
131
132
132
133 def ValidUserGroup(edit=False, old_data={}):
133 def ValidUserGroup(edit=False, old_data={}):
134 class _validator(formencode.validators.FancyValidator):
134 class _validator(formencode.validators.FancyValidator):
135 messages = {
135 messages = {
136 'invalid_group': _(u'Invalid user group name'),
136 'invalid_group': _(u'Invalid user group name'),
137 'group_exist': _(u'User group "%(usergroup)s" already exists'),
137 'group_exist': _(u'User group "%(usergroup)s" already exists'),
138 'invalid_usergroup_name':
138 'invalid_usergroup_name':
139 _(u'user group name may only contain alphanumeric '
139 _(u'user group name may only contain alphanumeric '
140 'characters underscores, periods or dashes and must begin '
140 'characters underscores, periods or dashes and must begin '
141 'with alphanumeric character')
141 'with alphanumeric character')
142 }
142 }
143
143
144 def validate_python(self, value, state):
144 def validate_python(self, value, state):
145 if value in ['default']:
145 if value in ['default']:
146 msg = M(self, 'invalid_group', state)
146 msg = M(self, 'invalid_group', state)
147 raise formencode.Invalid(msg, value, state,
147 raise formencode.Invalid(msg, value, state,
148 error_dict=dict(users_group_name=msg)
148 error_dict=dict(users_group_name=msg)
149 )
149 )
150 #check if group is unique
150 #check if group is unique
151 old_ugname = None
151 old_ugname = None
152 if edit:
152 if edit:
153 old_id = old_data.get('users_group_id')
153 old_id = old_data.get('users_group_id')
154 old_ugname = UserGroup.get(old_id).users_group_name
154 old_ugname = UserGroup.get(old_id).users_group_name
155
155
156 if old_ugname != value or not edit:
156 if old_ugname != value or not edit:
157 is_existing_group = UserGroup.get_by_group_name(value,
157 is_existing_group = UserGroup.get_by_group_name(value,
158 case_insensitive=True)
158 case_insensitive=True)
159 if is_existing_group:
159 if is_existing_group:
160 msg = M(self, 'group_exist', state, usergroup=value)
160 msg = M(self, 'group_exist', state, usergroup=value)
161 raise formencode.Invalid(msg, value, state,
161 raise formencode.Invalid(msg, value, state,
162 error_dict=dict(users_group_name=msg)
162 error_dict=dict(users_group_name=msg)
163 )
163 )
164
164
165 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
165 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
166 msg = M(self, 'invalid_usergroup_name', state)
166 msg = M(self, 'invalid_usergroup_name', state)
167 raise formencode.Invalid(msg, value, state,
167 raise formencode.Invalid(msg, value, state,
168 error_dict=dict(users_group_name=msg)
168 error_dict=dict(users_group_name=msg)
169 )
169 )
170
170
171 return _validator
171 return _validator
172
172
173
173
174 def ValidReposGroup(edit=False, old_data={}):
174 def ValidReposGroup(edit=False, old_data={}):
175 class _validator(formencode.validators.FancyValidator):
175 class _validator(formencode.validators.FancyValidator):
176 messages = {
176 messages = {
177 'group_parent_id': _(u'Cannot assign this group as parent'),
177 'group_parent_id': _(u'Cannot assign this group as parent'),
178 'group_exists': _(u'Group "%(group_name)s" already exists'),
178 'group_exists': _(u'Group "%(group_name)s" already exists'),
179 'repo_exists':
179 'repo_exists':
180 _(u'Repository with name "%(group_name)s" already exists')
180 _(u'Repository with name "%(group_name)s" already exists')
181 }
181 }
182
182
183 def validate_python(self, value, state):
183 def validate_python(self, value, state):
184 # TODO WRITE VALIDATIONS
184 # TODO WRITE VALIDATIONS
185 group_name = value.get('group_name')
185 group_name = value.get('group_name')
186 group_parent_id = value.get('group_parent_id')
186 group_parent_id = value.get('group_parent_id')
187
187
188 # slugify repo group just in case :)
188 # slugify repo group just in case :)
189 slug = repo_name_slug(group_name)
189 slug = repo_name_slug(group_name)
190
190
191 # check for parent of self
191 # check for parent of self
192 parent_of_self = lambda: (
192 parent_of_self = lambda: (
193 old_data['group_id'] == int(group_parent_id)
193 old_data['group_id'] == int(group_parent_id)
194 if group_parent_id else False
194 if group_parent_id else False
195 )
195 )
196 if edit and parent_of_self():
196 if edit and parent_of_self():
197 msg = M(self, 'group_parent_id', state)
197 msg = M(self, 'group_parent_id', state)
198 raise formencode.Invalid(msg, value, state,
198 raise formencode.Invalid(msg, value, state,
199 error_dict=dict(group_parent_id=msg)
199 error_dict=dict(group_parent_id=msg)
200 )
200 )
201
201
202 old_gname = None
202 old_gname = None
203 if edit:
203 if edit:
204 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
204 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
205
205
206 if old_gname != group_name or not edit:
206 if old_gname != group_name or not edit:
207
207
208 # check group
208 # check group
209 gr = RepoGroup.query()\
209 gr = RepoGroup.query()\
210 .filter(RepoGroup.group_name == slug)\
210 .filter(RepoGroup.group_name == slug)\
211 .filter(RepoGroup.group_parent_id == group_parent_id)\
211 .filter(RepoGroup.group_parent_id == group_parent_id)\
212 .scalar()
212 .scalar()
213
213
214 if gr:
214 if gr:
215 msg = M(self, 'group_exists', state, group_name=slug)
215 msg = M(self, 'group_exists', state, group_name=slug)
216 raise formencode.Invalid(msg, value, state,
216 raise formencode.Invalid(msg, value, state,
217 error_dict=dict(group_name=msg)
217 error_dict=dict(group_name=msg)
218 )
218 )
219
219
220 # check for same repo
220 # check for same repo
221 repo = Repository.query()\
221 repo = Repository.query()\
222 .filter(Repository.repo_name == slug)\
222 .filter(Repository.repo_name == slug)\
223 .scalar()
223 .scalar()
224
224
225 if repo:
225 if repo:
226 msg = M(self, 'repo_exists', state, group_name=slug)
226 msg = M(self, 'repo_exists', state, group_name=slug)
227 raise formencode.Invalid(msg, value, state,
227 raise formencode.Invalid(msg, value, state,
228 error_dict=dict(group_name=msg)
228 error_dict=dict(group_name=msg)
229 )
229 )
230
230
231 return _validator
231 return _validator
232
232
233
233
234 def ValidPassword():
234 def ValidPassword():
235 class _validator(formencode.validators.FancyValidator):
235 class _validator(formencode.validators.FancyValidator):
236 messages = {
236 messages = {
237 'invalid_password':
237 'invalid_password':
238 _(u'Invalid characters (non-ascii) in password')
238 _(u'Invalid characters (non-ascii) in password')
239 }
239 }
240
240
241 def validate_python(self, value, state):
241 def validate_python(self, value, state):
242 try:
242 try:
243 (value or '').decode('ascii')
243 (value or '').decode('ascii')
244 except UnicodeError:
244 except UnicodeError:
245 msg = M(self, 'invalid_password', state)
245 msg = M(self, 'invalid_password', state)
246 raise formencode.Invalid(msg, value, state,)
246 raise formencode.Invalid(msg, value, state,)
247 return _validator
247 return _validator
248
248
249
249
250 def ValidPasswordsMatch():
250 def ValidPasswordsMatch():
251 class _validator(formencode.validators.FancyValidator):
251 class _validator(formencode.validators.FancyValidator):
252 messages = {
252 messages = {
253 'password_mismatch': _(u'Passwords do not match'),
253 'password_mismatch': _(u'Passwords do not match'),
254 }
254 }
255
255
256 def validate_python(self, value, state):
256 def validate_python(self, value, state):
257
257
258 pass_val = value.get('password') or value.get('new_password')
258 pass_val = value.get('password') or value.get('new_password')
259 if pass_val != value['password_confirmation']:
259 if pass_val != value['password_confirmation']:
260 msg = M(self, 'password_mismatch', state)
260 msg = M(self, 'password_mismatch', state)
261 raise formencode.Invalid(msg, value, state,
261 raise formencode.Invalid(msg, value, state,
262 error_dict=dict(password_confirmation=msg)
262 error_dict=dict(password_confirmation=msg)
263 )
263 )
264 return _validator
264 return _validator
265
265
266
266
267 def ValidAuth():
267 def ValidAuth():
268 class _validator(formencode.validators.FancyValidator):
268 class _validator(formencode.validators.FancyValidator):
269 messages = {
269 messages = {
270 'invalid_password': _(u'invalid password'),
270 'invalid_password': _(u'invalid password'),
271 'invalid_username': _(u'invalid user name'),
271 'invalid_username': _(u'invalid user name'),
272 'disabled_account': _(u'Your account is disabled')
272 'disabled_account': _(u'Your account is disabled')
273 }
273 }
274
274
275 def validate_python(self, value, state):
275 def validate_python(self, value, state):
276 from rhodecode.lib.auth import authenticate
276 from rhodecode.lib.auth import authenticate
277
277
278 password = value['password']
278 password = value['password']
279 username = value['username']
279 username = value['username']
280
280
281 if not authenticate(username, password):
281 if not authenticate(username, password):
282 user = User.get_by_username(username)
282 user = User.get_by_username(username)
283 if user and not user.active:
283 if user and not user.active:
284 log.warning('user %s is disabled' % username)
284 log.warning('user %s is disabled' % username)
285 msg = M(self, 'disabled_account', state)
285 msg = M(self, 'disabled_account', state)
286 raise formencode.Invalid(msg, value, state,
286 raise formencode.Invalid(msg, value, state,
287 error_dict=dict(username=msg)
287 error_dict=dict(username=msg)
288 )
288 )
289 else:
289 else:
290 log.warning('user %s failed to authenticate' % username)
290 log.warning('user %s failed to authenticate' % username)
291 msg = M(self, 'invalid_username', state)
291 msg = M(self, 'invalid_username', state)
292 msg2 = M(self, 'invalid_password', state)
292 msg2 = M(self, 'invalid_password', state)
293 raise formencode.Invalid(msg, value, state,
293 raise formencode.Invalid(msg, value, state,
294 error_dict=dict(username=msg, password=msg2)
294 error_dict=dict(username=msg, password=msg2)
295 )
295 )
296 return _validator
296 return _validator
297
297
298
298
299 def ValidAuthToken():
299 def ValidAuthToken():
300 class _validator(formencode.validators.FancyValidator):
300 class _validator(formencode.validators.FancyValidator):
301 messages = {
301 messages = {
302 'invalid_token': _(u'Token mismatch')
302 'invalid_token': _(u'Token mismatch')
303 }
303 }
304
304
305 def validate_python(self, value, state):
305 def validate_python(self, value, state):
306 if value != authentication_token():
306 if value != authentication_token():
307 msg = M(self, 'invalid_token', state)
307 msg = M(self, 'invalid_token', state)
308 raise formencode.Invalid(msg, value, state)
308 raise formencode.Invalid(msg, value, state)
309 return _validator
309 return _validator
310
310
311
311
312 def ValidRepoName(edit=False, old_data={}):
312 def ValidRepoName(edit=False, old_data={}):
313 class _validator(formencode.validators.FancyValidator):
313 class _validator(formencode.validators.FancyValidator):
314 messages = {
314 messages = {
315 'invalid_repo_name':
315 'invalid_repo_name':
316 _(u'Repository name %(repo)s is disallowed'),
316 _(u'Repository name %(repo)s is disallowed'),
317 'repository_exists':
317 'repository_exists':
318 _(u'Repository named %(repo)s already exists'),
318 _(u'Repository named %(repo)s already exists'),
319 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
319 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
320 'exists in group "%(group)s"'),
320 'exists in group "%(group)s"'),
321 'same_group_exists': _(u'Repository group with name "%(repo)s" '
321 'same_group_exists': _(u'Repository group with name "%(repo)s" '
322 'already exists')
322 'already exists')
323 }
323 }
324
324
325 def _to_python(self, value, state):
325 def _to_python(self, value, state):
326 repo_name = repo_name_slug(value.get('repo_name', ''))
326 repo_name = repo_name_slug(value.get('repo_name', ''))
327 repo_group = value.get('repo_group')
327 repo_group = value.get('repo_group')
328 if repo_group:
328 if repo_group:
329 gr = RepoGroup.get(repo_group)
329 gr = RepoGroup.get(repo_group)
330 group_path = gr.full_path
330 group_path = gr.full_path
331 group_name = gr.group_name
331 group_name = gr.group_name
332 # value needs to be aware of group name in order to check
332 # value needs to be aware of group name in order to check
333 # db key This is an actual just the name to store in the
333 # db key This is an actual just the name to store in the
334 # database
334 # database
335 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
335 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
336 else:
336 else:
337 group_name = group_path = ''
337 group_name = group_path = ''
338 repo_name_full = repo_name
338 repo_name_full = repo_name
339
339
340 value['repo_name'] = repo_name
340 value['repo_name'] = repo_name
341 value['repo_name_full'] = repo_name_full
341 value['repo_name_full'] = repo_name_full
342 value['group_path'] = group_path
342 value['group_path'] = group_path
343 value['group_name'] = group_name
343 value['group_name'] = group_name
344 return value
344 return value
345
345
346 def validate_python(self, value, state):
346 def validate_python(self, value, state):
347
347
348 repo_name = value.get('repo_name')
348 repo_name = value.get('repo_name')
349 repo_name_full = value.get('repo_name_full')
349 repo_name_full = value.get('repo_name_full')
350 group_path = value.get('group_path')
350 group_path = value.get('group_path')
351 group_name = value.get('group_name')
351 group_name = value.get('group_name')
352
352
353 if repo_name in [ADMIN_PREFIX, '']:
353 if repo_name in [ADMIN_PREFIX, '']:
354 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
354 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
355 raise formencode.Invalid(msg, value, state,
355 raise formencode.Invalid(msg, value, state,
356 error_dict=dict(repo_name=msg)
356 error_dict=dict(repo_name=msg)
357 )
357 )
358
358
359 rename = old_data.get('repo_name') != repo_name_full
359 rename = old_data.get('repo_name') != repo_name_full
360 create = not edit
360 create = not edit
361 if rename or create:
361 if rename or create:
362
362
363 if group_path != '':
363 if group_path != '':
364 if Repository.get_by_repo_name(repo_name_full):
364 if Repository.get_by_repo_name(repo_name_full):
365 msg = M(self, 'repository_in_group_exists', state,
365 msg = M(self, 'repository_in_group_exists', state,
366 repo=repo_name, group=group_name)
366 repo=repo_name, group=group_name)
367 raise formencode.Invalid(msg, value, state,
367 raise formencode.Invalid(msg, value, state,
368 error_dict=dict(repo_name=msg)
368 error_dict=dict(repo_name=msg)
369 )
369 )
370 elif RepoGroup.get_by_group_name(repo_name_full):
370 elif RepoGroup.get_by_group_name(repo_name_full):
371 msg = M(self, 'same_group_exists', state,
371 msg = M(self, 'same_group_exists', state,
372 repo=repo_name)
372 repo=repo_name)
373 raise formencode.Invalid(msg, value, state,
373 raise formencode.Invalid(msg, value, state,
374 error_dict=dict(repo_name=msg)
374 error_dict=dict(repo_name=msg)
375 )
375 )
376
376
377 elif Repository.get_by_repo_name(repo_name_full):
377 elif Repository.get_by_repo_name(repo_name_full):
378 msg = M(self, 'repository_exists', state,
378 msg = M(self, 'repository_exists', state,
379 repo=repo_name)
379 repo=repo_name)
380 raise formencode.Invalid(msg, value, state,
380 raise formencode.Invalid(msg, value, state,
381 error_dict=dict(repo_name=msg)
381 error_dict=dict(repo_name=msg)
382 )
382 )
383 return value
383 return value
384 return _validator
384 return _validator
385
385
386
386
387 def ValidForkName(*args, **kwargs):
387 def ValidForkName(*args, **kwargs):
388 return ValidRepoName(*args, **kwargs)
388 return ValidRepoName(*args, **kwargs)
389
389
390
390
391 def SlugifyName():
391 def SlugifyName():
392 class _validator(formencode.validators.FancyValidator):
392 class _validator(formencode.validators.FancyValidator):
393
393
394 def _to_python(self, value, state):
394 def _to_python(self, value, state):
395 return repo_name_slug(value)
395 return repo_name_slug(value)
396
396
397 def validate_python(self, value, state):
397 def validate_python(self, value, state):
398 pass
398 pass
399
399
400 return _validator
400 return _validator
401
401
402
402
403 def ValidCloneUri():
403 def ValidCloneUri():
404 from rhodecode.lib.utils import make_ui
404 from rhodecode.lib.utils import make_ui
405
405
406 def url_handler(repo_type, url, ui=None):
406 def url_handler(repo_type, url, ui=None):
407 if repo_type == 'hg':
407 if repo_type == 'hg':
408 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
408 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
409 from mercurial.httppeer import httppeer
409 from mercurial.httppeer import httppeer
410 if url.startswith('http'):
410 if url.startswith('http'):
411 ## initially check if it's at least the proper URL
411 ## initially check if it's at least the proper URL
412 ## or does it pass basic auth
412 ## or does it pass basic auth
413 MercurialRepository._check_url(url)
413 MercurialRepository._check_url(url)
414 httppeer(ui, url)._capabilities()
414 httppeer(ui, url)._capabilities()
415 elif url.startswith('svn+http'):
415 elif url.startswith('svn+http'):
416 from hgsubversion.svnrepo import svnremoterepo
416 from hgsubversion.svnrepo import svnremoterepo
417 svnremoterepo(ui, url).capabilities
417 svnremoterepo(ui, url).capabilities
418 elif url.startswith('git+http'):
418 elif url.startswith('git+http'):
419 raise NotImplementedError()
419 raise NotImplementedError()
420 else:
420 else:
421 raise Exception('clone from URI %s not allowed' % (url))
421 raise Exception('clone from URI %s not allowed' % (url))
422
422
423 elif repo_type == 'git':
423 elif repo_type == 'git':
424 from rhodecode.lib.vcs.backends.git.repository import GitRepository
424 from rhodecode.lib.vcs.backends.git.repository import GitRepository
425 if url.startswith('http'):
425 if url.startswith('http'):
426 ## initially check if it's at least the proper URL
426 ## initially check if it's at least the proper URL
427 ## or does it pass basic auth
427 ## or does it pass basic auth
428 GitRepository._check_url(url)
428 GitRepository._check_url(url)
429 elif url.startswith('svn+http'):
429 elif url.startswith('svn+http'):
430 raise NotImplementedError()
430 raise NotImplementedError()
431 elif url.startswith('hg+http'):
431 elif url.startswith('hg+http'):
432 raise NotImplementedError()
432 raise NotImplementedError()
433 else:
433 else:
434 raise Exception('clone from URI %s not allowed' % (url))
434 raise Exception('clone from URI %s not allowed' % (url))
435
435
436 class _validator(formencode.validators.FancyValidator):
436 class _validator(formencode.validators.FancyValidator):
437 messages = {
437 messages = {
438 'clone_uri': _(u'invalid clone url'),
438 'clone_uri': _(u'invalid clone url'),
439 'invalid_clone_uri': _(u'Invalid clone url, provide a '
439 'invalid_clone_uri': _(u'Invalid clone url, provide a '
440 'valid clone http(s)/svn+http(s) url')
440 'valid clone http(s)/svn+http(s) url')
441 }
441 }
442
442
443 def validate_python(self, value, state):
443 def validate_python(self, value, state):
444 repo_type = value.get('repo_type')
444 repo_type = value.get('repo_type')
445 url = value.get('clone_uri')
445 url = value.get('clone_uri')
446
446
447 if not url:
447 if not url:
448 pass
448 pass
449 else:
449 else:
450 try:
450 try:
451 url_handler(repo_type, url, make_ui('db', clear_session=False))
451 url_handler(repo_type, url, make_ui('db', clear_session=False))
452 except Exception:
452 except Exception:
453 log.exception('Url validation failed')
453 log.exception('Url validation failed')
454 msg = M(self, 'clone_uri')
454 msg = M(self, 'clone_uri')
455 raise formencode.Invalid(msg, value, state,
455 raise formencode.Invalid(msg, value, state,
456 error_dict=dict(clone_uri=msg)
456 error_dict=dict(clone_uri=msg)
457 )
457 )
458 return _validator
458 return _validator
459
459
460
460
461 def ValidForkType(old_data={}):
461 def ValidForkType(old_data={}):
462 class _validator(formencode.validators.FancyValidator):
462 class _validator(formencode.validators.FancyValidator):
463 messages = {
463 messages = {
464 'invalid_fork_type': _(u'Fork have to be the same type as parent')
464 'invalid_fork_type': _(u'Fork have to be the same type as parent')
465 }
465 }
466
466
467 def validate_python(self, value, state):
467 def validate_python(self, value, state):
468 if old_data['repo_type'] != value:
468 if old_data['repo_type'] != value:
469 msg = M(self, 'invalid_fork_type', state)
469 msg = M(self, 'invalid_fork_type', state)
470 raise formencode.Invalid(msg, value, state,
470 raise formencode.Invalid(msg, value, state,
471 error_dict=dict(repo_type=msg)
471 error_dict=dict(repo_type=msg)
472 )
472 )
473 return _validator
473 return _validator
474
474
475
475
476 def CanWriteGroup(old_data=None):
476 def CanWriteGroup(old_data=None):
477 class _validator(formencode.validators.FancyValidator):
477 class _validator(formencode.validators.FancyValidator):
478 messages = {
478 messages = {
479 'permission_denied': _(u"You don't have permissions "
479 'permission_denied': _(u"You don't have permissions "
480 "to create repository in this group"),
480 "to create repository in this group"),
481 'permission_denied_root': _(u"no permission to create repository "
481 'permission_denied_root': _(u"no permission to create repository "
482 "in root location")
482 "in root location")
483 }
483 }
484
484
485 def _to_python(self, value, state):
485 def _to_python(self, value, state):
486 #root location
486 #root location
487 if value in [-1, "-1"]:
487 if value in [-1, "-1"]:
488 return None
488 return None
489 return value
489 return value
490
490
491 def validate_python(self, value, state):
491 def validate_python(self, value, state):
492 gr = RepoGroup.get(value)
492 gr = RepoGroup.get(value)
493 gr_name = gr.group_name if gr else None # None means ROOT location
493 gr_name = gr.group_name if gr else None # None means ROOT location
494 val = HasReposGroupPermissionAny('group.write', 'group.admin')
494 val = HasReposGroupPermissionAny('group.write', 'group.admin')
495 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository')
495 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository')
496 forbidden = not val(gr_name, 'can write into group validator')
496 forbidden = not val(gr_name, 'can write into group validator')
497 value_changed = True # old_data['repo_group'].get('group_id') != safe_int(value)
497 value_changed = True # old_data['repo_group'].get('group_id') != safe_int(value)
498 if value_changed: # do check if we changed the value
498 if value_changed: # do check if we changed the value
499 #parent group need to be existing
499 #parent group need to be existing
500 if gr and forbidden:
500 if gr and forbidden:
501 msg = M(self, 'permission_denied', state)
501 msg = M(self, 'permission_denied', state)
502 raise formencode.Invalid(msg, value, state,
502 raise formencode.Invalid(msg, value, state,
503 error_dict=dict(repo_type=msg)
503 error_dict=dict(repo_type=msg)
504 )
504 )
505 ## check if we can write to root location !
505 ## check if we can write to root location !
506 elif gr is None and not can_create_repos():
506 elif gr is None and not can_create_repos():
507 msg = M(self, 'permission_denied_root', state)
507 msg = M(self, 'permission_denied_root', state)
508 raise formencode.Invalid(msg, value, state,
508 raise formencode.Invalid(msg, value, state,
509 error_dict=dict(repo_type=msg)
509 error_dict=dict(repo_type=msg)
510 )
510 )
511
511
512 return _validator
512 return _validator
513
513
514
514
515 def CanCreateGroup(can_create_in_root=False):
515 def CanCreateGroup(can_create_in_root=False):
516 class _validator(formencode.validators.FancyValidator):
516 class _validator(formencode.validators.FancyValidator):
517 messages = {
517 messages = {
518 'permission_denied': _(u"You don't have permissions "
518 'permission_denied': _(u"You don't have permissions "
519 "to create a group in this location")
519 "to create a group in this location")
520 }
520 }
521
521
522 def to_python(self, value, state):
522 def to_python(self, value, state):
523 #root location
523 #root location
524 if value in [-1, "-1"]:
524 if value in [-1, "-1"]:
525 return None
525 return None
526 return value
526 return value
527
527
528 def validate_python(self, value, state):
528 def validate_python(self, value, state):
529 gr = RepoGroup.get(value)
529 gr = RepoGroup.get(value)
530 gr_name = gr.group_name if gr else None # None means ROOT location
530 gr_name = gr.group_name if gr else None # None means ROOT location
531
531
532 if can_create_in_root and gr is None:
532 if can_create_in_root and gr is None:
533 #we can create in root, we're fine no validations required
533 #we can create in root, we're fine no validations required
534 return
534 return
535
535
536 forbidden_in_root = gr is None and not can_create_in_root
536 forbidden_in_root = gr is None and not can_create_in_root
537 val = HasReposGroupPermissionAny('group.admin')
537 val = HasReposGroupPermissionAny('group.admin')
538 forbidden = not val(gr_name, 'can create group validator')
538 forbidden = not val(gr_name, 'can create group validator')
539 if forbidden_in_root or forbidden:
539 if forbidden_in_root or forbidden:
540 msg = M(self, 'permission_denied', state)
540 msg = M(self, 'permission_denied', state)
541 raise formencode.Invalid(msg, value, state,
541 raise formencode.Invalid(msg, value, state,
542 error_dict=dict(group_parent_id=msg)
542 error_dict=dict(group_parent_id=msg)
543 )
543 )
544
544
545 return _validator
545 return _validator
546
546
547
547
548 def ValidPerms(type_='repo'):
548 def ValidPerms(type_='repo'):
549 if type_ == 'repo_group':
549 if type_ == 'repo_group':
550 EMPTY_PERM = 'group.none'
550 EMPTY_PERM = 'group.none'
551 elif type_ == 'repo':
551 elif type_ == 'repo':
552 EMPTY_PERM = 'repository.none'
552 EMPTY_PERM = 'repository.none'
553 elif type_ == 'user_group':
553 elif type_ == 'user_group':
554 EMPTY_PERM = 'usergroup.none'
554 EMPTY_PERM = 'usergroup.none'
555
555
556 class _validator(formencode.validators.FancyValidator):
556 class _validator(formencode.validators.FancyValidator):
557 messages = {
557 messages = {
558 'perm_new_member_name':
558 'perm_new_member_name':
559 _(u'This username or user group name is not valid')
559 _(u'This username or user group name is not valid')
560 }
560 }
561
561
562 def to_python(self, value, state):
562 def to_python(self, value, state):
563 perms_update = OrderedSet()
563 perms_update = OrderedSet()
564 perms_new = OrderedSet()
564 perms_new = OrderedSet()
565 # build a list of permission to update and new permission to create
565 # build a list of permission to update and new permission to create
566
566
567 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
567 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
568 new_perms_group = defaultdict(dict)
568 new_perms_group = defaultdict(dict)
569 for k, v in value.copy().iteritems():
569 for k, v in value.copy().iteritems():
570 if k.startswith('perm_new_member'):
570 if k.startswith('perm_new_member'):
571 del value[k]
571 del value[k]
572 _type, part = k.split('perm_new_member_')
572 _type, part = k.split('perm_new_member_')
573 args = part.split('_')
573 args = part.split('_')
574 if len(args) == 1:
574 if len(args) == 1:
575 new_perms_group[args[0]]['perm'] = v
575 new_perms_group[args[0]]['perm'] = v
576 elif len(args) == 2:
576 elif len(args) == 2:
577 _key, pos = args
577 _key, pos = args
578 new_perms_group[pos][_key] = v
578 new_perms_group[pos][_key] = v
579
579
580 # fill new permissions in order of how they were added
580 # fill new permissions in order of how they were added
581 for k in sorted(map(int, new_perms_group.keys())):
581 for k in sorted(map(int, new_perms_group.keys())):
582 perm_dict = new_perms_group[str(k)]
582 perm_dict = new_perms_group[str(k)]
583 new_member = perm_dict.get('name')
583 new_member = perm_dict.get('name')
584 new_perm = perm_dict.get('perm')
584 new_perm = perm_dict.get('perm')
585 new_type = perm_dict.get('type')
585 new_type = perm_dict.get('type')
586 if new_member and new_perm and new_type:
586 if new_member and new_perm and new_type:
587 perms_new.add((new_member, new_perm, new_type))
587 perms_new.add((new_member, new_perm, new_type))
588
588
589 for k, v in value.iteritems():
589 for k, v in value.iteritems():
590 if k.startswith('u_perm_') or k.startswith('g_perm_'):
590 if k.startswith('u_perm_') or k.startswith('g_perm_'):
591 member = k[7:]
591 member = k[7:]
592 t = {'u': 'user',
592 t = {'u': 'user',
593 'g': 'users_group'
593 'g': 'users_group'
594 }[k[0]]
594 }[k[0]]
595 if member == 'default':
595 if member == 'default':
596 if str2bool(value.get('repo_private')):
596 if str2bool(value.get('repo_private')):
597 # set none for default when updating to
597 # set none for default when updating to
598 # private repo protects agains form manipulation
598 # private repo protects agains form manipulation
599 v = EMPTY_PERM
599 v = EMPTY_PERM
600 perms_update.add((member, v, t))
600 perms_update.add((member, v, t))
601
601
602 value['perms_updates'] = list(perms_update)
602 value['perms_updates'] = list(perms_update)
603 value['perms_new'] = list(perms_new)
603 value['perms_new'] = list(perms_new)
604
604
605 # update permissions
605 # update permissions
606 for k, v, t in perms_new:
606 for k, v, t in perms_new:
607 try:
607 try:
608 if t is 'user':
608 if t is 'user':
609 self.user_db = User.query()\
609 self.user_db = User.query()\
610 .filter(User.active == True)\
610 .filter(User.active == True)\
611 .filter(User.username == k).one()
611 .filter(User.username == k).one()
612 if t is 'users_group':
612 if t is 'users_group':
613 self.user_db = UserGroup.query()\
613 self.user_db = UserGroup.query()\
614 .filter(UserGroup.users_group_active == True)\
614 .filter(UserGroup.users_group_active == True)\
615 .filter(UserGroup.users_group_name == k).one()
615 .filter(UserGroup.users_group_name == k).one()
616
616
617 except Exception:
617 except Exception:
618 log.exception('Updated permission failed')
618 log.exception('Updated permission failed')
619 msg = M(self, 'perm_new_member_type', state)
619 msg = M(self, 'perm_new_member_type', state)
620 raise formencode.Invalid(msg, value, state,
620 raise formencode.Invalid(msg, value, state,
621 error_dict=dict(perm_new_member_name=msg)
621 error_dict=dict(perm_new_member_name=msg)
622 )
622 )
623 return value
623 return value
624 return _validator
624 return _validator
625
625
626
626
627 def ValidSettings():
627 def ValidSettings():
628 class _validator(formencode.validators.FancyValidator):
628 class _validator(formencode.validators.FancyValidator):
629 def _to_python(self, value, state):
629 def _to_python(self, value, state):
630 # settings form for users that are not admin
630 # settings form for users that are not admin
631 # can't edit certain parameters, it's extra backup if they mangle
631 # can't edit certain parameters, it's extra backup if they mangle
632 # with forms
632 # with forms
633
633
634 forbidden_params = [
634 forbidden_params = [
635 'user', 'repo_type', 'repo_enable_locking',
635 'user', 'repo_type', 'repo_enable_locking',
636 'repo_enable_downloads', 'repo_enable_statistics'
636 'repo_enable_downloads', 'repo_enable_statistics'
637 ]
637 ]
638
638
639 for param in forbidden_params:
639 for param in forbidden_params:
640 if param in value:
640 if param in value:
641 del value[param]
641 del value[param]
642 return value
642 return value
643
643
644 def validate_python(self, value, state):
644 def validate_python(self, value, state):
645 pass
645 pass
646 return _validator
646 return _validator
647
647
648
648
649 def ValidPath():
649 def ValidPath():
650 class _validator(formencode.validators.FancyValidator):
650 class _validator(formencode.validators.FancyValidator):
651 messages = {
651 messages = {
652 'invalid_path': _(u'This is not a valid path')
652 'invalid_path': _(u'This is not a valid path')
653 }
653 }
654
654
655 def validate_python(self, value, state):
655 def validate_python(self, value, state):
656 if not os.path.isdir(value):
656 if not os.path.isdir(value):
657 msg = M(self, 'invalid_path', state)
657 msg = M(self, 'invalid_path', state)
658 raise formencode.Invalid(msg, value, state,
658 raise formencode.Invalid(msg, value, state,
659 error_dict=dict(paths_root_path=msg)
659 error_dict=dict(paths_root_path=msg)
660 )
660 )
661 return _validator
661 return _validator
662
662
663
663
664 def UniqSystemEmail(old_data={}):
664 def UniqSystemEmail(old_data={}):
665 class _validator(formencode.validators.FancyValidator):
665 class _validator(formencode.validators.FancyValidator):
666 messages = {
666 messages = {
667 'email_taken': _(u'This e-mail address is already taken')
667 'email_taken': _(u'This e-mail address is already taken')
668 }
668 }
669
669
670 def _to_python(self, value, state):
670 def _to_python(self, value, state):
671 return value.lower()
671 return value.lower()
672
672
673 def validate_python(self, value, state):
673 def validate_python(self, value, state):
674 if (old_data.get('email') or '').lower() != value:
674 if (old_data.get('email') or '').lower() != value:
675 user = User.get_by_email(value, case_insensitive=True)
675 user = User.get_by_email(value, case_insensitive=True)
676 if user:
676 if user:
677 msg = M(self, 'email_taken', state)
677 msg = M(self, 'email_taken', state)
678 raise formencode.Invalid(msg, value, state,
678 raise formencode.Invalid(msg, value, state,
679 error_dict=dict(email=msg)
679 error_dict=dict(email=msg)
680 )
680 )
681 return _validator
681 return _validator
682
682
683
683
684 def ValidSystemEmail():
684 def ValidSystemEmail():
685 class _validator(formencode.validators.FancyValidator):
685 class _validator(formencode.validators.FancyValidator):
686 messages = {
686 messages = {
687 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
687 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
688 }
688 }
689
689
690 def _to_python(self, value, state):
690 def _to_python(self, value, state):
691 return value.lower()
691 return value.lower()
692
692
693 def validate_python(self, value, state):
693 def validate_python(self, value, state):
694 user = User.get_by_email(value, case_insensitive=True)
694 user = User.get_by_email(value, case_insensitive=True)
695 if user is None:
695 if user is None:
696 msg = M(self, 'non_existing_email', state, email=value)
696 msg = M(self, 'non_existing_email', state, email=value)
697 raise formencode.Invalid(msg, value, state,
697 raise formencode.Invalid(msg, value, state,
698 error_dict=dict(email=msg)
698 error_dict=dict(email=msg)
699 )
699 )
700
700
701 return _validator
701 return _validator
702
702
703
703
704 def LdapLibValidator():
704 def LdapLibValidator():
705 class _validator(formencode.validators.FancyValidator):
705 class _validator(formencode.validators.FancyValidator):
706 messages = {
706 messages = {
707
707
708 }
708 }
709
709
710 def validate_python(self, value, state):
710 def validate_python(self, value, state):
711 try:
711 try:
712 import ldap
712 import ldap
713 ldap # pyflakes silence !
713 ldap # pyflakes silence !
714 except ImportError:
714 except ImportError:
715 raise LdapImportError()
715 raise LdapImportError()
716
716
717 return _validator
717 return _validator
718
718
719
719
720 def AttrLoginValidator():
720 def AttrLoginValidator():
721 class _validator(formencode.validators.FancyValidator):
721 class _validator(formencode.validators.FancyValidator):
722 messages = {
722 messages = {
723 'invalid_cn':
723 'invalid_cn':
724 _(u'The LDAP Login attribute of the CN must be specified - '
724 _(u'The LDAP Login attribute of the CN must be specified - '
725 'this is the name of the attribute that is equivalent '
725 'this is the name of the attribute that is equivalent '
726 'to "username"')
726 'to "username"')
727 }
727 }
728 messages['empty'] = messages['invalid_cn']
728 messages['empty'] = messages['invalid_cn']
729
729
730 return _validator
730 return _validator
731
731
732
732
733 def NotReviewedRevisions(repo_id):
733 def NotReviewedRevisions(repo_id):
734 class _validator(formencode.validators.FancyValidator):
734 class _validator(formencode.validators.FancyValidator):
735 messages = {
735 messages = {
736 'rev_already_reviewed':
736 'rev_already_reviewed':
737 _(u'Revisions %(revs)s are already part of pull request '
737 _(u'Revisions %(revs)s are already part of pull request '
738 'or have set status')
738 'or have set status')
739 }
739 }
740
740
741 def validate_python(self, value, state):
741 def validate_python(self, value, state):
742 # check revisions if they are not reviewed, or a part of another
742 # check revisions if they are not reviewed, or a part of another
743 # pull request
743 # pull request
744 statuses = ChangesetStatus.query()\
744 statuses = ChangesetStatus.query()\
745 .filter(ChangesetStatus.revision.in_(value))\
745 .filter(ChangesetStatus.revision.in_(value))\
746 .filter(ChangesetStatus.repo_id == repo_id)\
746 .filter(ChangesetStatus.repo_id == repo_id)\
747 .all()
747 .all()
748
748
749 errors = []
749 errors = []
750 for cs in statuses:
750 for cs in statuses:
751 if cs.pull_request_id:
751 if cs.pull_request_id:
752 errors.append(['pull_req', cs.revision[:12]])
752 errors.append(['pull_req', cs.revision[:12]])
753 elif cs.status:
753 elif cs.status:
754 errors.append(['status', cs.revision[:12]])
754 errors.append(['status', cs.revision[:12]])
755
755
756 if errors:
756 if errors:
757 revs = ','.join([x[1] for x in errors])
757 revs = ','.join([x[1] for x in errors])
758 msg = M(self, 'rev_already_reviewed', state, revs=revs)
758 msg = M(self, 'rev_already_reviewed', state, revs=revs)
759 raise formencode.Invalid(msg, value, state,
759 raise formencode.Invalid(msg, value, state,
760 error_dict=dict(revisions=revs)
760 error_dict=dict(revisions=revs)
761 )
761 )
762
762
763 return _validator
763 return _validator
764
764
765
765
766 def ValidIp():
766 def ValidIp():
767 class _validator(CIDR):
767 class _validator(CIDR):
768 messages = dict(
768 messages = dict(
769 badFormat=_('Please enter a valid IPv4 or IpV6 address'),
769 badFormat=_('Please enter a valid IPv4 or IpV6 address'),
770 illegalBits=_('The network size (bits) must be within the range'
770 illegalBits=_('The network size (bits) must be within the range'
771 ' of 0-32 (not %(bits)r)'))
771 ' of 0-32 (not %(bits)r)')
772 )
772
773
773 def to_python(self, value, state):
774 def to_python(self, value, state):
774 v = super(_validator, self).to_python(value, state)
775 v = super(_validator, self).to_python(value, state)
775 v = v.strip()
776 v = v.strip()
776 net = ipaddr.IPNetwork(address=v)
777 net = ipaddr.IPNetwork(address=v)
777 if isinstance(net, ipaddr.IPv4Network):
778 if isinstance(net, ipaddr.IPv4Network):
778 #if IPv4 doesn't end with a mask, add /32
779 #if IPv4 doesn't end with a mask, add /32
779 if '/' not in value:
780 if '/' not in value:
780 v += '/32'
781 v += '/32'
781 if isinstance(net, ipaddr.IPv6Network):
782 if isinstance(net, ipaddr.IPv6Network):
782 #if IPv6 doesn't end with a mask, add /128
783 #if IPv6 doesn't end with a mask, add /128
783 if '/' not in value:
784 if '/' not in value:
784 v += '/128'
785 v += '/128'
785 return v
786 return v
786
787
787 def validate_python(self, value, state):
788 def validate_python(self, value, state):
788 try:
789 try:
789 addr = value.strip()
790 addr = value.strip()
790 #this raises an ValueError if address is not IpV4 or IpV6
791 #this raises an ValueError if address is not IpV4 or IpV6
791 ipaddr.IPNetwork(address=addr)
792 ipaddr.IPNetwork(address=addr)
792 except ValueError:
793 except ValueError:
793 raise formencode.Invalid(self.message('badFormat', state),
794 raise formencode.Invalid(self.message('badFormat', state),
794 value, state)
795 value, state)
795
796
796 return _validator
797 return _validator
797
798
798
799
799 def FieldKey():
800 def FieldKey():
800 class _validator(formencode.validators.FancyValidator):
801 class _validator(formencode.validators.FancyValidator):
801 messages = dict(
802 messages = dict(
802 badFormat=_('Key name can only consist of letters, '
803 badFormat=_('Key name can only consist of letters, '
803 'underscore, dash or numbers'),)
804 'underscore, dash or numbers')
805 )
804
806
805 def validate_python(self, value, state):
807 def validate_python(self, value, state):
806 if not re.match('[a-zA-Z0-9_-]+$', value):
808 if not re.match('[a-zA-Z0-9_-]+$', value):
807 raise formencode.Invalid(self.message('badFormat', state),
809 raise formencode.Invalid(self.message('badFormat', state),
808 value, state)
810 value, state)
809 return _validator
811 return _validator
812
813
814 def BasePath():
815 class _validator(formencode.validators.FancyValidator):
816 messages = dict(
817 badPath=_('Filename cannot be inside a directory')
818 )
819
820 def _to_python(self, value, state):
821 return value
822
823 def validate_python(self, value, state):
824 if value != os.path.basename(value):
825 raise formencode.Invalid(self.message('badPath', state),
826 value, state)
827 return _validator
@@ -1,150 +1,160 b''
1 import datetime
1 import datetime
2
2
3 from rhodecode.tests import *
3 from rhodecode.tests import *
4 from rhodecode.model.gist import GistModel
4 from rhodecode.model.gist import GistModel
5 from rhodecode.model.meta import Session
5 from rhodecode.model.meta import Session
6 from rhodecode.model.db import User, Gist
6 from rhodecode.model.db import User, Gist
7
7
8
8
9 def _create_gist(f_name, content='some gist', lifetime=-1,
9 def _create_gist(f_name, content='some gist', lifetime=-1,
10 description='gist-desc', gist_type='public',
10 description='gist-desc', gist_type='public',
11 owner=TEST_USER_ADMIN_LOGIN):
11 owner=TEST_USER_ADMIN_LOGIN):
12 gist_mapping = {
12 gist_mapping = {
13 f_name: {'content': content}
13 f_name: {'content': content}
14 }
14 }
15 user = User.get_by_username(owner)
15 user = User.get_by_username(owner)
16 gist = GistModel().create(description, owner=user,
16 gist = GistModel().create(description, owner=user,
17 gist_mapping=gist_mapping, gist_type=gist_type,
17 gist_mapping=gist_mapping, gist_type=gist_type,
18 lifetime=lifetime)
18 lifetime=lifetime)
19 Session().commit()
19 Session().commit()
20 return gist
20 return gist
21
21
22
22
23 class TestGistsController(TestController):
23 class TestGistsController(TestController):
24
24
25 def tearDown(self):
25 def tearDown(self):
26 for g in Gist.get_all():
26 for g in Gist.get_all():
27 GistModel().delete(g)
27 GistModel().delete(g)
28 Session().commit()
28 Session().commit()
29
29
30 def test_index(self):
30 def test_index(self):
31 self.log_user()
31 self.log_user()
32 response = self.app.get(url('gists'))
32 response = self.app.get(url('gists'))
33 # Test response...
33 # Test response...
34 response.mustcontain('There are no gists yet')
34 response.mustcontain('There are no gists yet')
35
35
36 _create_gist('gist1')
36 _create_gist('gist1')
37 _create_gist('gist2', lifetime=1400)
37 _create_gist('gist2', lifetime=1400)
38 _create_gist('gist3', description='gist3-desc')
38 _create_gist('gist3', description='gist3-desc')
39 _create_gist('gist4', gist_type='private')
39 _create_gist('gist4', gist_type='private')
40 response = self.app.get(url('gists'))
40 response = self.app.get(url('gists'))
41 # Test response...
41 # Test response...
42 response.mustcontain('gist:1')
42 response.mustcontain('gist:1')
43 response.mustcontain('gist:2')
43 response.mustcontain('gist:2')
44 response.mustcontain('Expires: in 23 hours') # we don't care about the end
44 response.mustcontain('Expires: in 23 hours') # we don't care about the end
45 response.mustcontain('gist:3')
45 response.mustcontain('gist:3')
46 response.mustcontain('gist3-desc')
46 response.mustcontain('gist3-desc')
47 response.mustcontain(no=['gist:4'])
47 response.mustcontain(no=['gist:4'])
48
48
49 def test_index_private_gists(self):
49 def test_index_private_gists(self):
50 self.log_user()
50 self.log_user()
51 gist = _create_gist('gist5', gist_type='private')
51 gist = _create_gist('gist5', gist_type='private')
52 response = self.app.get(url('gists', private=1))
52 response = self.app.get(url('gists', private=1))
53 # Test response...
53 # Test response...
54
54
55 #and privates
55 #and privates
56 response.mustcontain('gist:%s' % gist.gist_access_id)
56 response.mustcontain('gist:%s' % gist.gist_access_id)
57
57
58 def test_create_missing_description(self):
58 def test_create_missing_description(self):
59 self.log_user()
59 self.log_user()
60 response = self.app.post(url('gists'),
60 response = self.app.post(url('gists'),
61 params={'lifetime': -1}, status=200)
61 params={'lifetime': -1}, status=200)
62
62
63 response.mustcontain('Missing value')
63 response.mustcontain('Missing value')
64
64
65 def test_create(self):
65 def test_create(self):
66 self.log_user()
66 self.log_user()
67 response = self.app.post(url('gists'),
67 response = self.app.post(url('gists'),
68 params={'lifetime': -1,
68 params={'lifetime': -1,
69 'content': 'gist test',
69 'content': 'gist test',
70 'filename': 'foo',
70 'filename': 'foo',
71 'public': 'public'},
71 'public': 'public'},
72 status=302)
72 status=302)
73 response = response.follow()
73 response = response.follow()
74 response.mustcontain('added file: foo')
74 response.mustcontain('added file: foo')
75 response.mustcontain('gist test')
75 response.mustcontain('gist test')
76 response.mustcontain('<div class="ui-btn green badge">Public gist</div>')
76 response.mustcontain('<div class="ui-btn green badge">Public gist</div>')
77
77
78 def test_create_with_path_with_dirs(self):
79 self.log_user()
80 response = self.app.post(url('gists'),
81 params={'lifetime': -1,
82 'content': 'gist test',
83 'filename': '/home/foo',
84 'public': 'public'},
85 status=200)
86 response.mustcontain('Filename cannot be inside a directory')
87
78 def test_access_expired_gist(self):
88 def test_access_expired_gist(self):
79 self.log_user()
89 self.log_user()
80 gist = _create_gist('never-see-me')
90 gist = _create_gist('never-see-me')
81 gist.gist_expires = 0 # 1970
91 gist.gist_expires = 0 # 1970
82 Session().add(gist)
92 Session().add(gist)
83 Session().commit()
93 Session().commit()
84
94
85 response = self.app.get(url('gist', id=gist.gist_access_id), status=404)
95 response = self.app.get(url('gist', id=gist.gist_access_id), status=404)
86
96
87 def test_create_private(self):
97 def test_create_private(self):
88 self.log_user()
98 self.log_user()
89 response = self.app.post(url('gists'),
99 response = self.app.post(url('gists'),
90 params={'lifetime': -1,
100 params={'lifetime': -1,
91 'content': 'private gist test',
101 'content': 'private gist test',
92 'filename': 'private-foo',
102 'filename': 'private-foo',
93 'private': 'private'},
103 'private': 'private'},
94 status=302)
104 status=302)
95 response = response.follow()
105 response = response.follow()
96 response.mustcontain('added file: private-foo<')
106 response.mustcontain('added file: private-foo<')
97 response.mustcontain('private gist test')
107 response.mustcontain('private gist test')
98 response.mustcontain('<div class="ui-btn yellow badge">Private gist</div>')
108 response.mustcontain('<div class="ui-btn yellow badge">Private gist</div>')
99
109
100 def test_create_with_description(self):
110 def test_create_with_description(self):
101 self.log_user()
111 self.log_user()
102 response = self.app.post(url('gists'),
112 response = self.app.post(url('gists'),
103 params={'lifetime': -1,
113 params={'lifetime': -1,
104 'content': 'gist test',
114 'content': 'gist test',
105 'filename': 'foo-desc',
115 'filename': 'foo-desc',
106 'description': 'gist-desc',
116 'description': 'gist-desc',
107 'public': 'public'},
117 'public': 'public'},
108 status=302)
118 status=302)
109 response = response.follow()
119 response = response.follow()
110 response.mustcontain('added file: foo-desc')
120 response.mustcontain('added file: foo-desc')
111 response.mustcontain('gist test')
121 response.mustcontain('gist test')
112 response.mustcontain('gist-desc')
122 response.mustcontain('gist-desc')
113 response.mustcontain('<div class="ui-btn green badge">Public gist</div>')
123 response.mustcontain('<div class="ui-btn green badge">Public gist</div>')
114
124
115 def test_new(self):
125 def test_new(self):
116 self.log_user()
126 self.log_user()
117 response = self.app.get(url('new_gist'))
127 response = self.app.get(url('new_gist'))
118
128
119 def test_update(self):
129 def test_update(self):
120 self.skipTest('not implemented')
130 self.skipTest('not implemented')
121 response = self.app.put(url('gist', id=1))
131 response = self.app.put(url('gist', id=1))
122
132
123 def test_delete(self):
133 def test_delete(self):
124 self.log_user()
134 self.log_user()
125 gist = _create_gist('delete-me')
135 gist = _create_gist('delete-me')
126 response = self.app.delete(url('gist', id=gist.gist_id))
136 response = self.app.delete(url('gist', id=gist.gist_id))
127 self.checkSessionFlash(response, 'Deleted gist %s' % gist.gist_id)
137 self.checkSessionFlash(response, 'Deleted gist %s' % gist.gist_id)
128
138
129 def test_delete_normal_user_his_gist(self):
139 def test_delete_normal_user_his_gist(self):
130 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
140 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
131 gist = _create_gist('delete-me', owner=TEST_USER_REGULAR_LOGIN)
141 gist = _create_gist('delete-me', owner=TEST_USER_REGULAR_LOGIN)
132 response = self.app.delete(url('gist', id=gist.gist_id))
142 response = self.app.delete(url('gist', id=gist.gist_id))
133 self.checkSessionFlash(response, 'Deleted gist %s' % gist.gist_id)
143 self.checkSessionFlash(response, 'Deleted gist %s' % gist.gist_id)
134
144
135 def test_delete_normal_user_not_his_own_gist(self):
145 def test_delete_normal_user_not_his_own_gist(self):
136 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
146 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
137 gist = _create_gist('delete-me')
147 gist = _create_gist('delete-me')
138 response = self.app.delete(url('gist', id=gist.gist_id), status=403)
148 response = self.app.delete(url('gist', id=gist.gist_id), status=403)
139
149
140 def test_show(self):
150 def test_show(self):
141 gist = _create_gist('gist-show-me')
151 gist = _create_gist('gist-show-me')
142 response = self.app.get(url('gist', id=gist.gist_access_id))
152 response = self.app.get(url('gist', id=gist.gist_access_id))
143 response.mustcontain('added file: gist-show-me<')
153 response.mustcontain('added file: gist-show-me<')
144 response.mustcontain('test_admin (RhodeCode Admin) - created')
154 response.mustcontain('test_admin (RhodeCode Admin) - created')
145 response.mustcontain('gist-desc')
155 response.mustcontain('gist-desc')
146 response.mustcontain('<div class="ui-btn green badge">Public gist</div>')
156 response.mustcontain('<div class="ui-btn green badge">Public gist</div>')
147
157
148 def test_edit(self):
158 def test_edit(self):
149 self.skipTest('not implemented')
159 self.skipTest('not implemented')
150 response = self.app.get(url('edit_gist', id=1))
160 response = self.app.get(url('edit_gist', id=1))
General Comments 0
You need to be logged in to leave comments. Login now