Show More
@@ -1,6 +1,6 b'' | |||||
1 |
======================== |
|
1 | ======================== | |
2 |
|
|
2 | RhodeCode documentation! | |
3 |
======================== |
|
3 | ======================== | |
4 |
|
4 | |||
5 | ``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_ |
|
5 | ``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_ | |
6 | with a built in push/pull server and full text search. |
|
6 | with a built in push/pull server and full text search. | |
@@ -102,7 +102,6 b' Incoming / Plans' | |||||
102 | - pull requests and web based merges |
|
102 | - pull requests and web based merges | |
103 | - per line file history |
|
103 | - per line file history | |
104 | - SSH based authentication with server side key management |
|
104 | - SSH based authentication with server side key management | |
105 | - Redmine and other bugtrackers integration |
|
|||
106 | - Commit based built in wiki system |
|
105 | - Commit based built in wiki system | |
107 | - More statistics and graph (global annotation + some more statistics) |
|
106 | - More statistics and graph (global annotation + some more statistics) | |
108 | - Other advancements as development continues (or you can of course make |
|
107 | - Other advancements as development continues (or you can of course make |
@@ -58,13 +58,34 b' container_auth_enabled = false' | |||||
58 | proxypass_auth_enabled = false |
|
58 | proxypass_auth_enabled = false | |
59 |
|
59 | |||
60 | ## overwrite schema of clone url |
|
60 | ## overwrite schema of clone url | |
61 | # available vars: |
|
61 | ## available vars: | |
62 | # scheme - http/https |
|
62 | ## scheme - http/https | |
63 | # user - current user |
|
63 | ## user - current user | |
64 | # pass - password |
|
64 | ## pass - password | |
65 | # netloc - network location |
|
65 | ## netloc - network location | |
66 | # path - usually repo_name |
|
66 | ## path - usually repo_name | |
67 | # clone_uri = {scheme}://{user}{pass}{netloc}{path} |
|
67 | ||
|
68 | #clone_uri = {scheme}://{user}{pass}{netloc}{path} | |||
|
69 | ||||
|
70 | ## issue tracking mapping for commits messages | |||
|
71 | ## uncomment url_pat, issue_server, issue_prefix to enable | |||
|
72 | ||||
|
73 | ||||
|
74 | ## pattern to get the issues from commit messages | |||
|
75 | ## default one used here is #1234 | |||
|
76 | ||||
|
77 | #url_pat = (?:^#|\s#)(\w+) | |||
|
78 | ||||
|
79 | ## server url to the issue, each {id} will be replaced with id | |||
|
80 | ## fetched from the regex | |||
|
81 | ||||
|
82 | #issue_server = https://myissueserver.com/issue/{id} | |||
|
83 | ||||
|
84 | ## prefix to add to link to indicate it's an url | |||
|
85 | ## #314 will be replaced by <issue_prefix><id> | |||
|
86 | ||||
|
87 | #issue_prefix = # | |||
|
88 | ||||
68 |
|
89 | |||
69 | #################################### |
|
90 | #################################### | |
70 | ### CELERY CONFIG #### |
|
91 | ### CELERY CONFIG #### |
@@ -10,6 +10,8 b" There's a single schema for calling all " | |||||
10 | with JSON protocol both ways. An url to send API request in RhodeCode is |
|
10 | with JSON protocol both ways. An url to send API request in RhodeCode is | |
11 | <your_server>/_admin/api |
|
11 | <your_server>/_admin/api | |
12 |
|
12 | |||
|
13 | API ACCESS FOR WEB VIEWS | |||
|
14 | ++++++++++++++++++++++++ | |||
13 |
|
15 | |||
14 | API access can also be turned on for each view decorated with `@LoginRequired` |
|
16 | API access can also be turned on for each view decorated with `@LoginRequired` | |
15 | decorator. To enable API access simple change standard login decorator into |
|
17 | decorator. To enable API access simple change standard login decorator into | |
@@ -18,6 +20,9 b' by adding a GET parameter to url `?api_k' | |||||
18 | enabled on RSS/ATOM feed views. |
|
20 | enabled on RSS/ATOM feed views. | |
19 |
|
21 | |||
20 |
|
22 | |||
|
23 | API ACCESS | |||
|
24 | ++++++++++ | |||
|
25 | ||||
21 | All clients are required to send JSON-RPC spec JSON data:: |
|
26 | All clients are required to send JSON-RPC spec JSON data:: | |
22 |
|
27 | |||
23 | { |
|
28 | { | |
@@ -69,15 +74,47 b' INPUT::' | |||||
69 | api_key : "<api_key>" |
|
74 | api_key : "<api_key>" | |
70 | method : "pull" |
|
75 | method : "pull" | |
71 | args : { |
|
76 | args : { | |
72 |
"repo" : "<repo |
|
77 | "repo_name" : "<reponame>" | |
73 | } |
|
78 | } | |
74 |
|
79 | |||
75 | OUTPUT:: |
|
80 | OUTPUT:: | |
76 |
|
81 | |||
77 |
result : "Pulled from <repo |
|
82 | result : "Pulled from <reponame>" | |
78 | error : null |
|
83 | error : null | |
79 |
|
84 | |||
80 |
|
85 | |||
|
86 | get_user | |||
|
87 | -------- | |||
|
88 | ||||
|
89 | Get's an user by username, Returns empty result if user is not found. | |||
|
90 | This command can be executed only using api_key belonging to user with admin | |||
|
91 | rights. | |||
|
92 | ||||
|
93 | INPUT:: | |||
|
94 | ||||
|
95 | api_key : "<api_key>" | |||
|
96 | method : "get_user" | |||
|
97 | args : { | |||
|
98 | "username" : "<username>" | |||
|
99 | } | |||
|
100 | ||||
|
101 | OUTPUT:: | |||
|
102 | ||||
|
103 | result: None if user does not exist or | |||
|
104 | { | |||
|
105 | "id" : "<id>", | |||
|
106 | "username" : "<username>", | |||
|
107 | "firstname": "<firstname>", | |||
|
108 | "lastname" : "<lastname>", | |||
|
109 | "email" : "<email>", | |||
|
110 | "active" : "<bool>", | |||
|
111 | "admin" : "<bool>", | |||
|
112 | "ldap" : "<ldap_dn>" | |||
|
113 | } | |||
|
114 | ||||
|
115 | error: null | |||
|
116 | ||||
|
117 | ||||
81 | get_users |
|
118 | get_users | |
82 | --------- |
|
119 | --------- | |
83 |
|
120 | |||
@@ -131,46 +168,11 b' INPUT::' | |||||
131 | OUTPUT:: |
|
168 | OUTPUT:: | |
132 |
|
169 | |||
133 | result: { |
|
170 | result: { | |
|
171 | "id" : "<new_user_id>", | |||
134 |
|
|
172 | "msg" : "created new user <username>" | |
135 | } |
|
173 | } | |
136 | error: null |
|
174 | error: null | |
137 |
|
175 | |||
138 | get_users_groups |
|
|||
139 | ---------------- |
|
|||
140 |
|
||||
141 | Lists all existing users groups. This command can be executed only using api_key |
|
|||
142 | belonging to user with admin rights. |
|
|||
143 |
|
||||
144 | INPUT:: |
|
|||
145 |
|
||||
146 | api_key : "<api_key>" |
|
|||
147 | method : "get_users_groups" |
|
|||
148 | args : { } |
|
|||
149 |
|
||||
150 | OUTPUT:: |
|
|||
151 |
|
||||
152 | result : [ |
|
|||
153 | { |
|
|||
154 | "id" : "<id>", |
|
|||
155 | "name" : "<name>", |
|
|||
156 | "active": "<bool>", |
|
|||
157 | "members" : [ |
|
|||
158 | { |
|
|||
159 | "id" : "<userid>", |
|
|||
160 | "username" : "<username>", |
|
|||
161 | "firstname": "<firstname>", |
|
|||
162 | "lastname" : "<lastname>", |
|
|||
163 | "email" : "<email>", |
|
|||
164 | "active" : "<bool>", |
|
|||
165 | "admin" : "<bool>", |
|
|||
166 | "ldap" : "<ldap_dn>" |
|
|||
167 | }, |
|
|||
168 | … |
|
|||
169 | ] |
|
|||
170 | } |
|
|||
171 | ] |
|
|||
172 | error : null |
|
|||
173 |
|
||||
174 | get_users_group |
|
176 | get_users_group | |
175 | --------------- |
|
177 | --------------- | |
176 |
|
178 | |||
@@ -189,24 +191,61 b' OUTPUT::' | |||||
189 |
|
191 | |||
190 | result : None if group not exist |
|
192 | result : None if group not exist | |
191 | { |
|
193 | { | |
192 | "id" : "<id>", |
|
194 | "id" : "<id>", | |
193 |
"name" : |
|
195 | "group_name" : "<groupname>", | |
194 | "active": "<bool>", |
|
196 | "active": "<bool>", | |
195 | "members" : [ |
|
197 | "members" : [ | |
196 |
|
|
198 | { "id" : "<userid>", | |
197 |
|
|
199 | "username" : "<username>", | |
198 |
|
|
200 | "firstname": "<firstname>", | |
199 |
|
|
201 | "lastname" : "<lastname>", | |
200 |
|
|
202 | "email" : "<email>", | |
201 |
|
|
203 | "active" : "<bool>", | |
202 |
|
|
204 | "admin" : "<bool>", | |
203 |
|
|
205 | "ldap" : "<ldap_dn>" | |
204 |
|
|
206 | }, | |
205 |
|
|
207 | … | |
206 |
|
|
208 | ] | |
207 |
|
|
209 | } | |
208 | error : null |
|
210 | error : null | |
209 |
|
|
211 | ||
|
212 | get_users_groups | |||
|
213 | ---------------- | |||
|
214 | ||||
|
215 | Lists all existing users groups. This command can be executed only using | |||
|
216 | api_key belonging to user with admin rights. | |||
|
217 | ||||
|
218 | INPUT:: | |||
|
219 | ||||
|
220 | api_key : "<api_key>" | |||
|
221 | method : "get_users_groups" | |||
|
222 | args : { } | |||
|
223 | ||||
|
224 | OUTPUT:: | |||
|
225 | ||||
|
226 | result : [ | |||
|
227 | { | |||
|
228 | "id" : "<id>", | |||
|
229 | "group_name" : "<groupname>", | |||
|
230 | "active": "<bool>", | |||
|
231 | "members" : [ | |||
|
232 | { | |||
|
233 | "id" : "<userid>", | |||
|
234 | "username" : "<username>", | |||
|
235 | "firstname": "<firstname>", | |||
|
236 | "lastname" : "<lastname>", | |||
|
237 | "email" : "<email>", | |||
|
238 | "active" : "<bool>", | |||
|
239 | "admin" : "<bool>", | |||
|
240 | "ldap" : "<ldap_dn>" | |||
|
241 | }, | |||
|
242 | … | |||
|
243 | ] | |||
|
244 | } | |||
|
245 | ] | |||
|
246 | error : null | |||
|
247 | ||||
|
248 | ||||
210 | create_users_group |
|
249 | create_users_group | |
211 | ------------------ |
|
250 | ------------------ | |
212 |
|
251 | |||
@@ -218,7 +257,7 b' INPUT::' | |||||
218 | api_key : "<api_key>" |
|
257 | api_key : "<api_key>" | |
219 | method : "create_users_group" |
|
258 | method : "create_users_group" | |
220 | args: { |
|
259 | args: { | |
221 | "name": "<name>", |
|
260 | "group_name": "<groupname>", | |
222 | "active":"<bool> = True" |
|
261 | "active":"<bool> = True" | |
223 | } |
|
262 | } | |
224 |
|
263 | |||
@@ -226,7 +265,7 b' OUTPUT::' | |||||
226 |
|
265 | |||
227 | result: { |
|
266 | result: { | |
228 | "id": "<newusersgroupid>", |
|
267 | "id": "<newusersgroupid>", | |
229 | "msg": "created new users group <name>" |
|
268 | "msg": "created new users group <groupname>" | |
230 | } |
|
269 | } | |
231 | error: null |
|
270 | error: null | |
232 |
|
271 | |||
@@ -253,6 +292,51 b' OUTPUT::' | |||||
253 | } |
|
292 | } | |
254 | error: null |
|
293 | error: null | |
255 |
|
294 | |||
|
295 | get_repo | |||
|
296 | -------- | |||
|
297 | ||||
|
298 | Gets an existing repository. This command can be executed only using api_key | |||
|
299 | belonging to user with admin rights | |||
|
300 | ||||
|
301 | INPUT:: | |||
|
302 | ||||
|
303 | api_key : "<api_key>" | |||
|
304 | method : "get_repo" | |||
|
305 | args: { | |||
|
306 | "repo_name" : "<reponame>" | |||
|
307 | } | |||
|
308 | ||||
|
309 | OUTPUT:: | |||
|
310 | ||||
|
311 | result: None if repository does not exist or | |||
|
312 | { | |||
|
313 | "id" : "<id>", | |||
|
314 | "repo_name" : "<reponame>" | |||
|
315 | "type" : "<type>", | |||
|
316 | "description" : "<description>", | |||
|
317 | "members" : [ | |||
|
318 | { "id" : "<userid>", | |||
|
319 | "username" : "<username>", | |||
|
320 | "firstname": "<firstname>", | |||
|
321 | "lastname" : "<lastname>", | |||
|
322 | "email" : "<email>", | |||
|
323 | "active" : "<bool>", | |||
|
324 | "admin" : "<bool>", | |||
|
325 | "ldap" : "<ldap_dn>", | |||
|
326 | "permission" : "repository.(read|write|admin)" | |||
|
327 | }, | |||
|
328 | … | |||
|
329 | { | |||
|
330 | "id" : "<usersgroupid>", | |||
|
331 | "name" : "<usersgroupname>", | |||
|
332 | "active": "<bool>", | |||
|
333 | "permission" : "repository.(read|write|admin)" | |||
|
334 | }, | |||
|
335 | … | |||
|
336 | ] | |||
|
337 | } | |||
|
338 | error: null | |||
|
339 | ||||
256 | get_repos |
|
340 | get_repos | |
257 | --------- |
|
341 | --------- | |
258 |
|
342 | |||
@@ -270,7 +354,7 b' OUTPUT::' | |||||
270 | result: [ |
|
354 | result: [ | |
271 | { |
|
355 | { | |
272 | "id" : "<id>", |
|
356 | "id" : "<id>", | |
273 |
"name" : |
|
357 | "repo_name" : "<reponame>" | |
274 | "type" : "<type>", |
|
358 | "type" : "<type>", | |
275 | "description" : "<description>" |
|
359 | "description" : "<description>" | |
276 | }, |
|
360 | }, | |
@@ -278,57 +362,13 b' OUTPUT::' | |||||
278 | ] |
|
362 | ] | |
279 | error: null |
|
363 | error: null | |
280 |
|
364 | |||
281 | get_repo |
|
|||
282 | -------- |
|
|||
283 |
|
||||
284 | Gets an existing repository. This command can be executed only using api_key |
|
|||
285 | belonging to user with admin rights |
|
|||
286 |
|
||||
287 | INPUT:: |
|
|||
288 |
|
||||
289 | api_key : "<api_key>" |
|
|||
290 | method : "get_repo" |
|
|||
291 | args: { |
|
|||
292 | "name" : "<name>" |
|
|||
293 | } |
|
|||
294 |
|
||||
295 | OUTPUT:: |
|
|||
296 |
|
||||
297 | result: None if repository not exist |
|
|||
298 | { |
|
|||
299 | "id" : "<id>", |
|
|||
300 | "name" : "<name>" |
|
|||
301 | "type" : "<type>", |
|
|||
302 | "description" : "<description>", |
|
|||
303 | "members" : [ |
|
|||
304 | { "id" : "<userid>", |
|
|||
305 | "username" : "<username>", |
|
|||
306 | "firstname": "<firstname>", |
|
|||
307 | "lastname" : "<lastname>", |
|
|||
308 | "email" : "<email>", |
|
|||
309 | "active" : "<bool>", |
|
|||
310 | "admin" : "<bool>", |
|
|||
311 | "ldap" : "<ldap_dn>", |
|
|||
312 | "permission" : "repository.(read|write|admin)" |
|
|||
313 | }, |
|
|||
314 | … |
|
|||
315 | { |
|
|||
316 | "id" : "<usersgroupid>", |
|
|||
317 | "name" : "<usersgroupname>", |
|
|||
318 | "active": "<bool>", |
|
|||
319 | "permission" : "repository.(read|write|admin)" |
|
|||
320 | }, |
|
|||
321 | … |
|
|||
322 | ] |
|
|||
323 | } |
|
|||
324 | error: null |
|
|||
325 |
|
|
365 | ||
326 | get_repo_nodes |
|
366 | get_repo_nodes | |
327 | -------------- |
|
367 | -------------- | |
328 |
|
368 | |||
329 | returns a list of nodes and it's children in a flat list for a given path |
|
369 | returns a list of nodes and it's children in a flat list for a given path | |
330 | at given revision. It's possible to specify ret_type to show only files or |
|
370 | at given revision. It's possible to specify ret_type to show only `files` or | |
331 | dirs. This command can be executed only using api_key belonging to user |
|
371 | `dirs`. This command can be executed only using api_key belonging to user | |
332 | with admin rights |
|
372 | with admin rights | |
333 |
|
373 | |||
334 | INPUT:: |
|
374 | INPUT:: | |
@@ -336,7 +376,7 b' INPUT::' | |||||
336 | api_key : "<api_key>" |
|
376 | api_key : "<api_key>" | |
337 | method : "get_repo_nodes" |
|
377 | method : "get_repo_nodes" | |
338 | args: { |
|
378 | args: { | |
339 | "repo_name" : "<name>", |
|
379 | "repo_name" : "<reponame>", | |
340 | "revision" : "<revision>", |
|
380 | "revision" : "<revision>", | |
341 | "root_path" : "<root_path>", |
|
381 | "root_path" : "<root_path>", | |
342 | "ret_type" : "<ret_type>" = 'all' |
|
382 | "ret_type" : "<ret_type>" = 'all' | |
@@ -369,7 +409,7 b' INPUT::' | |||||
369 | api_key : "<api_key>" |
|
409 | api_key : "<api_key>" | |
370 | method : "create_repo" |
|
410 | method : "create_repo" | |
371 | args: { |
|
411 | args: { | |
372 |
"name" : |
|
412 | "repo_name" : "<reponame>", | |
373 | "owner_name" : "<ownername>", |
|
413 | "owner_name" : "<ownername>", | |
374 | "description" : "<description> = ''", |
|
414 | "description" : "<description> = ''", | |
375 | "repo_type" : "<type> = 'hg'", |
|
415 | "repo_type" : "<type> = 'hg'", | |
@@ -378,7 +418,10 b' INPUT::' | |||||
378 |
|
418 | |||
379 | OUTPUT:: |
|
419 | OUTPUT:: | |
380 |
|
420 | |||
381 |
result: |
|
421 | result: { | |
|
422 | "id": "<newrepoid>", | |||
|
423 | "msg": "Created new repository <reponame>", | |||
|
424 | } | |||
382 |
|
|
425 | error: null | |
383 |
|
426 | |||
384 | add_user_to_repo |
|
427 | add_user_to_repo | |
@@ -394,13 +437,15 b' INPUT::' | |||||
394 | method : "add_user_to_repo" |
|
437 | method : "add_user_to_repo" | |
395 | args: { |
|
438 | args: { | |
396 | "repo_name" : "<reponame>", |
|
439 | "repo_name" : "<reponame>", | |
397 | "username" : "<username>", |
|
440 | "username" : "<username>", | |
398 | "perm" : "(None|repository.(read|write|admin))", |
|
441 | "perm" : "(None|repository.(read|write|admin))", | |
399 | } |
|
442 | } | |
400 |
|
443 | |||
401 | OUTPUT:: |
|
444 | OUTPUT:: | |
402 |
|
445 | |||
403 |
result: |
|
446 | result: { | |
|
447 | "msg" : "Added perm: <perm> for <username> in repo: <reponame>" | |||
|
448 | } | |||
404 |
|
|
449 | error: null | |
405 |
|
450 | |||
406 | add_users_group_to_repo |
|
451 | add_users_group_to_repo | |
@@ -416,6 +461,12 b' INPUT::' | |||||
416 | method : "add_users_group_to_repo" |
|
461 | method : "add_users_group_to_repo" | |
417 | args: { |
|
462 | args: { | |
418 | "repo_name" : "<reponame>", |
|
463 | "repo_name" : "<reponame>", | |
419 |
"group_name" : |
|
464 | "group_name" : "<groupname>", | |
420 | "perm" : "(None|repository.(read|write|admin))", |
|
465 | "perm" : "(None|repository.(read|write|admin))", | |
421 |
|
|
466 | } | |
|
467 | OUTPUT:: | |||
|
468 | ||||
|
469 | result: { | |||
|
470 | "msg" : Added perm: <perm> for <groupname> in repo: <reponame>" | |||
|
471 | } | |||
|
472 |
@@ -1,4 +1,4 b'' | |||||
1 | .. _api: |
|
1 | .. _indexapi: | |
2 |
|
2 | |||
3 | API Reference |
|
3 | API Reference | |
4 | ============= |
|
4 | ============= |
@@ -6,14 +6,29 b' The :mod:`models` Module' | |||||
6 | .. automodule:: rhodecode.model |
|
6 | .. automodule:: rhodecode.model | |
7 | :members: |
|
7 | :members: | |
8 |
|
8 | |||
|
9 | .. automodule:: rhodecode.model.comment | |||
|
10 | :members: | |||
|
11 | ||||
|
12 | .. automodule:: rhodecode.model.notification | |||
|
13 | :members: | |||
|
14 | ||||
9 | .. automodule:: rhodecode.model.permission |
|
15 | .. automodule:: rhodecode.model.permission | |
10 | :members: |
|
16 | :members: | |
11 |
|
17 | |||
|
18 | .. automodule:: rhodecode.model.repo_permission | |||
|
19 | :members: | |||
|
20 | ||||
12 | .. automodule:: rhodecode.model.repo |
|
21 | .. automodule:: rhodecode.model.repo | |
13 | :members: |
|
22 | :members: | |
14 |
|
23 | |||
|
24 | .. automodule:: rhodecode.model.repos_group | |||
|
25 | :members: | |||
|
26 | ||||
15 | .. automodule:: rhodecode.model.scm |
|
27 | .. automodule:: rhodecode.model.scm | |
16 | :members: |
|
28 | :members: | |
17 |
|
29 | |||
18 | .. automodule:: rhodecode.model.user |
|
30 | .. automodule:: rhodecode.model.user | |
19 | :members: |
|
31 | :members: | |
|
32 | ||||
|
33 | .. automodule:: rhodecode.model.users_group | |||
|
34 | :members: No newline at end of file |
@@ -33,7 +33,9 b' news' | |||||
33 | - implements #330 api method for listing nodes ar particular revision |
|
33 | - implements #330 api method for listing nodes ar particular revision | |
34 | - fixed #331 RhodeCode mangles repository names if the a repository group |
|
34 | - fixed #331 RhodeCode mangles repository names if the a repository group | |
35 | contains the "full path" to the repositories |
|
35 | contains the "full path" to the repositories | |
36 |
|
36 | - #73 added linking issues in commit messages to choosen issue tracker url | ||
|
37 | based on user defined regular expression | |||
|
38 | ||||
37 | fixes |
|
39 | fixes | |
38 | ----- |
|
40 | ----- | |
39 |
|
41 |
@@ -2,8 +2,8 b'' | |||||
2 |
|
2 | |||
3 | .. include:: ./../README.rst |
|
3 | .. include:: ./../README.rst | |
4 |
|
4 | |||
5 | Documentation |
|
5 | Users Guide | |
6 |
----------- |
|
6 | ----------- | |
7 |
|
7 | |||
8 | **Installation:** |
|
8 | **Installation:** | |
9 |
|
9 | |||
@@ -23,7 +23,6 b' Documentation' | |||||
23 | usage/enable_git |
|
23 | usage/enable_git | |
24 | usage/statistics |
|
24 | usage/statistics | |
25 | usage/backup |
|
25 | usage/backup | |
26 | usage/api_key_access |
|
|||
27 |
|
26 | |||
28 | **Develop** |
|
27 | **Develop** | |
29 |
|
28 | |||
@@ -36,7 +35,7 b' Documentation' | |||||
36 | **API** |
|
35 | **API** | |
37 |
|
36 | |||
38 | .. toctree:: |
|
37 | .. toctree:: | |
39 |
:maxdepth: |
|
38 | :maxdepth: 1 | |
40 |
|
39 | |||
41 | api/index |
|
40 | api/index | |
42 |
|
41 |
@@ -425,7 +425,25 b' the following in the [app:main] section ' | |||||
425 | forge the authentication header and could effectively become authenticated |
|
425 | forge the authentication header and could effectively become authenticated | |
426 | using any account of their liking. |
|
426 | using any account of their liking. | |
427 |
|
427 | |||
|
428 | Integration with Issue trackers | |||
|
429 | ------------------------------- | |||
428 |
|
430 | |||
|
431 | RhodeCode provides a simple integration with issue trackers. It's possible | |||
|
432 | to define a regular expression that will fetch issue id stored in commit | |||
|
433 | messages and replace that with an url to this issue. To enable this simply | |||
|
434 | uncomment following variables in the ini file:: | |||
|
435 | ||||
|
436 | url_pat = (?:^#|\s#)(\w+) | |||
|
437 | issue_server = https://myissueserver.com/issue/{id} | |||
|
438 | issue_prefix = # | |||
|
439 | ||||
|
440 | `url_pat` is the regular expression that will match issues, default given regex | |||
|
441 | will match issues in format of #<number> eg. #300. | |||
|
442 | Matched issues will be replace with the `issue_server` url replacing {id} with | |||
|
443 | id fetched from regex. Since the # is striped `issue_prefix` is added as a | |||
|
444 | prefix to url. `issue_prefix` can be something different than # if you pass | |||
|
445 | ISSUE- as issue prefix this will generate an url in format | |||
|
446 | `<a href="https://myissueserver.com/issue/300">ISSUE-300</a>` | |||
429 |
|
447 | |||
430 | Hook management |
|
448 | Hook management | |
431 | --------------- |
|
449 | --------------- |
@@ -58,13 +58,34 b' container_auth_enabled = false' | |||||
58 | proxypass_auth_enabled = false |
|
58 | proxypass_auth_enabled = false | |
59 |
|
59 | |||
60 | ## overwrite schema of clone url |
|
60 | ## overwrite schema of clone url | |
61 | # available vars: |
|
61 | ## available vars: | |
62 | # scheme - http/https |
|
62 | ## scheme - http/https | |
63 | # user - current user |
|
63 | ## user - current user | |
64 | # pass - password |
|
64 | ## pass - password | |
65 | # netloc - network location |
|
65 | ## netloc - network location | |
66 | # path - usually repo_name |
|
66 | ## path - usually repo_name | |
67 | # clone_uri = {scheme}://{user}{pass}{netloc}{path} |
|
67 | ||
|
68 | #clone_uri = {scheme}://{user}{pass}{netloc}{path} | |||
|
69 | ||||
|
70 | ## issue tracking mapping for commits messages | |||
|
71 | ## uncomment url_pat, issue_server, issue_prefix to enable | |||
|
72 | ||||
|
73 | ||||
|
74 | ## pattern to get the issues from commit messages | |||
|
75 | ## default one used here is #1234 | |||
|
76 | ||||
|
77 | #url_pat = (?:^#|\s#)(\w+) | |||
|
78 | ||||
|
79 | ## server url to the issue, each {id} will be replaced with id | |||
|
80 | ## fetched from the regex | |||
|
81 | ||||
|
82 | #issue_server = https://myissueserver.com/issue/{id} | |||
|
83 | ||||
|
84 | ## prefix to add to link to indicate it's an url | |||
|
85 | ## #314 will be replaced by <issue_prefix><id> | |||
|
86 | ||||
|
87 | #issue_prefix = # | |||
|
88 | ||||
68 |
|
89 | |||
69 | #################################### |
|
90 | #################################### | |
70 | ### CELERY CONFIG #### |
|
91 | ### CELERY CONFIG #### |
@@ -58,14 +58,35 b' container_auth_enabled = false' | |||||
58 | proxypass_auth_enabled = false |
|
58 | proxypass_auth_enabled = false | |
59 |
|
59 | |||
60 | ## overwrite schema of clone url |
|
60 | ## overwrite schema of clone url | |
61 | # available vars: |
|
61 | ## available vars: | |
62 | # scheme - http/https |
|
62 | ## scheme - http/https | |
63 | # user - current user |
|
63 | ## user - current user | |
64 | # pass - password |
|
64 | ## pass - password | |
65 | # netloc - network location |
|
65 | ## netloc - network location | |
66 | # path - usually repo_name |
|
66 | ## path - usually repo_name | |
|
67 | ||||
67 | # clone_uri = {scheme}://{user}{pass}{netloc}{path} |
|
68 | # clone_uri = {scheme}://{user}{pass}{netloc}{path} | |
68 |
|
69 | |||
|
70 | ## issue tracking mapping for commits messages | |||
|
71 | ## uncomment url_pat, issue_server, issue_prefix to enable | |||
|
72 | ||||
|
73 | ||||
|
74 | ## pattern to get the issues from commit messages | |||
|
75 | ## default one used here is #1234 | |||
|
76 | ||||
|
77 | #url_pat = (?:^#|\s#)(\w+) | |||
|
78 | ||||
|
79 | ## server url to the issue, each {id} will be replaced with id | |||
|
80 | ## fetched from the regex | |||
|
81 | ||||
|
82 | #issue_server = https://myissueserver.com/issue/{id} | |||
|
83 | ||||
|
84 | ## prefix to add to link to indicate it's an url | |||
|
85 | ## #314 will be replaced by <issue_prefix><id> | |||
|
86 | ||||
|
87 | #issue_prefix = # | |||
|
88 | ||||
|
89 | ||||
69 | #################################### |
|
90 | #################################### | |
70 | ### CELERY CONFIG #### |
|
91 | ### CELERY CONFIG #### | |
71 | #################################### |
|
92 | #################################### |
@@ -64,23 +64,23 b' class ApiController(JSONRPCController):' | |||||
64 | """ |
|
64 | """ | |
65 |
|
65 | |||
66 | @HasPermissionAllDecorator('hg.admin') |
|
66 | @HasPermissionAllDecorator('hg.admin') | |
67 | def pull(self, apiuser, repo): |
|
67 | def pull(self, apiuser, repo_name): | |
68 | """ |
|
68 | """ | |
69 | Dispatch pull action on given repo |
|
69 | Dispatch pull action on given repo | |
70 |
|
70 | |||
71 |
|
71 | |||
72 | :param user: |
|
72 | :param user: | |
73 | :param repo: |
|
73 | :param repo_name: | |
74 | """ |
|
74 | """ | |
75 |
|
75 | |||
76 | if Repository.is_valid(repo) is False: |
|
76 | if Repository.is_valid(repo_name) is False: | |
77 | raise JSONRPCError('Unknown repo "%s"' % repo) |
|
77 | raise JSONRPCError('Unknown repo "%s"' % repo_name) | |
78 |
|
78 | |||
79 | try: |
|
79 | try: | |
80 | ScmModel().pull_changes(repo, self.rhodecode_user.username) |
|
80 | ScmModel().pull_changes(repo_name, self.rhodecode_user.username) | |
81 | return 'Pulled from %s' % repo |
|
81 | return 'Pulled from %s' % repo_name | |
82 | except Exception: |
|
82 | except Exception: | |
83 | raise JSONRPCError('Unable to pull changes from "%s"' % repo) |
|
83 | raise JSONRPCError('Unable to pull changes from "%s"' % repo_name) | |
84 |
|
84 | |||
85 | @HasPermissionAllDecorator('hg.admin') |
|
85 | @HasPermissionAllDecorator('hg.admin') | |
86 | def get_user(self, apiuser, username): |
|
86 | def get_user(self, apiuser, username): | |
@@ -151,10 +151,15 b' class ApiController(JSONRPCController):' | |||||
151 | raise JSONRPCError("user %s already exist" % username) |
|
151 | raise JSONRPCError("user %s already exist" % username) | |
152 |
|
152 | |||
153 | try: |
|
153 | try: | |
154 |
UserModel().create_or_update( |
|
154 | usr = UserModel().create_or_update( | |
155 | lastname, active, admin, ldap_dn) |
|
155 | username, password, email, firstname, | |
|
156 | lastname, active, admin, ldap_dn | |||
|
157 | ) | |||
156 | Session.commit() |
|
158 | Session.commit() | |
157 | return dict(msg='created new user %s' % username) |
|
159 | return dict( | |
|
160 | id=usr.user_id, | |||
|
161 | msg='created new user %s' % username | |||
|
162 | ) | |||
158 | except Exception: |
|
163 | except Exception: | |
159 | log.error(traceback.format_exc()) |
|
164 | log.error(traceback.format_exc()) | |
160 | raise JSONRPCError('failed to create user %s' % username) |
|
165 | raise JSONRPCError('failed to create user %s' % username) | |
@@ -185,7 +190,7 b' class ApiController(JSONRPCController):' | |||||
185 | ldap=user.ldap_dn)) |
|
190 | ldap=user.ldap_dn)) | |
186 |
|
191 | |||
187 | return dict(id=users_group.users_group_id, |
|
192 | return dict(id=users_group.users_group_id, | |
188 | name=users_group.users_group_name, |
|
193 | group_name=users_group.users_group_name, | |
189 | active=users_group.users_group_active, |
|
194 | active=users_group.users_group_active, | |
190 | members=members) |
|
195 | members=members) | |
191 |
|
196 | |||
@@ -212,31 +217,31 b' class ApiController(JSONRPCController):' | |||||
212 | ldap=user.ldap_dn)) |
|
217 | ldap=user.ldap_dn)) | |
213 |
|
218 | |||
214 | result.append(dict(id=users_group.users_group_id, |
|
219 | result.append(dict(id=users_group.users_group_id, | |
215 | name=users_group.users_group_name, |
|
220 | group_name=users_group.users_group_name, | |
216 | active=users_group.users_group_active, |
|
221 | active=users_group.users_group_active, | |
217 | members=members)) |
|
222 | members=members)) | |
218 | return result |
|
223 | return result | |
219 |
|
224 | |||
220 | @HasPermissionAllDecorator('hg.admin') |
|
225 | @HasPermissionAllDecorator('hg.admin') | |
221 | def create_users_group(self, apiuser, name, active=True): |
|
226 | def create_users_group(self, apiuser, group_name, active=True): | |
222 | """ |
|
227 | """ | |
223 | Creates an new usergroup |
|
228 | Creates an new usergroup | |
224 |
|
229 | |||
225 | :param name: |
|
230 | :param group_name: | |
226 | :param active: |
|
231 | :param active: | |
227 | """ |
|
232 | """ | |
228 |
|
233 | |||
229 | if self.get_users_group(apiuser, name): |
|
234 | if self.get_users_group(apiuser, group_name): | |
230 | raise JSONRPCError("users group %s already exist" % name) |
|
235 | raise JSONRPCError("users group %s already exist" % group_name) | |
231 |
|
236 | |||
232 | try: |
|
237 | try: | |
233 | ug = UsersGroupModel().create(name=name, active=active) |
|
238 | ug = UsersGroupModel().create(name=group_name, active=active) | |
234 | Session.commit() |
|
239 | Session.commit() | |
235 | return dict(id=ug.users_group_id, |
|
240 | return dict(id=ug.users_group_id, | |
236 | msg='created new users group %s' % name) |
|
241 | msg='created new users group %s' % group_name) | |
237 | except Exception: |
|
242 | except Exception: | |
238 | log.error(traceback.format_exc()) |
|
243 | log.error(traceback.format_exc()) | |
239 | raise JSONRPCError('failed to create group %s' % name) |
|
244 | raise JSONRPCError('failed to create group %s' % group_name) | |
240 |
|
245 | |||
241 | @HasPermissionAllDecorator('hg.admin') |
|
246 | @HasPermissionAllDecorator('hg.admin') | |
242 | def add_user_to_users_group(self, apiuser, group_name, username): |
|
247 | def add_user_to_users_group(self, apiuser, group_name, username): | |
@@ -312,7 +317,7 b' class ApiController(JSONRPCController):' | |||||
312 |
|
317 | |||
313 | return dict( |
|
318 | return dict( | |
314 | id=repo.repo_id, |
|
319 | id=repo.repo_id, | |
315 | name=repo.repo_name, |
|
320 | repo_name=repo.repo_name, | |
316 | type=repo.repo_type, |
|
321 | type=repo.repo_type, | |
317 | description=repo.description, |
|
322 | description=repo.description, | |
318 | members=members |
|
323 | members=members | |
@@ -331,7 +336,7 b' class ApiController(JSONRPCController):' | |||||
331 | result.append( |
|
336 | result.append( | |
332 | dict( |
|
337 | dict( | |
333 | id=repository.repo_id, |
|
338 | id=repository.repo_id, | |
334 | name=repository.repo_name, |
|
339 | repo_name=repository.repo_name, | |
335 | type=repository.repo_type, |
|
340 | type=repository.repo_type, | |
336 | description=repository.description |
|
341 | description=repository.description | |
337 | ) |
|
342 | ) | |
@@ -367,13 +372,13 b' class ApiController(JSONRPCController):' | |||||
367 | raise JSONRPCError(e) |
|
372 | raise JSONRPCError(e) | |
368 |
|
373 | |||
369 | @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') |
|
374 | @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') | |
370 | def create_repo(self, apiuser, name, owner_name, description='', |
|
375 | def create_repo(self, apiuser, repo_name, owner_name, description='', | |
371 | repo_type='hg', private=False): |
|
376 | repo_type='hg', private=False): | |
372 | """ |
|
377 | """ | |
373 | Create a repository |
|
378 | Create a repository | |
374 |
|
379 | |||
375 | :param apiuser: |
|
380 | :param apiuser: | |
376 | :param name: |
|
381 | :param repo_name: | |
377 | :param description: |
|
382 | :param description: | |
378 | :param type: |
|
383 | :param type: | |
379 | :param private: |
|
384 | :param private: | |
@@ -386,10 +391,10 b' class ApiController(JSONRPCController):' | |||||
386 | except NoResultFound: |
|
391 | except NoResultFound: | |
387 | raise JSONRPCError('unknown user %s' % owner) |
|
392 | raise JSONRPCError('unknown user %s' % owner) | |
388 |
|
393 | |||
389 |
if |
|
394 | if Repository.get_by_repo_name(repo_name): | |
390 | raise JSONRPCError("repo %s already exist" % name) |
|
395 | raise JSONRPCError("repo %s already exist" % repo_name) | |
391 |
|
396 | |||
392 | groups = name.split('/') |
|
397 | groups = repo_name.split('/') | |
393 | real_name = groups[-1] |
|
398 | real_name = groups[-1] | |
394 | groups = groups[:-1] |
|
399 | groups = groups[:-1] | |
395 | parent_id = None |
|
400 | parent_id = None | |
@@ -405,10 +410,10 b' class ApiController(JSONRPCController):' | |||||
405 | ) |
|
410 | ) | |
406 | parent_id = group.group_id |
|
411 | parent_id = group.group_id | |
407 |
|
412 | |||
408 | RepoModel().create( |
|
413 | repo = RepoModel().create( | |
409 | dict( |
|
414 | dict( | |
410 | repo_name=real_name, |
|
415 | repo_name=real_name, | |
411 | repo_name_full=name, |
|
416 | repo_name_full=repo_name, | |
412 | description=description, |
|
417 | description=description, | |
413 | private=private, |
|
418 | private=private, | |
414 | repo_type=repo_type, |
|
419 | repo_type=repo_type, | |
@@ -418,9 +423,15 b' class ApiController(JSONRPCController):' | |||||
418 | owner |
|
423 | owner | |
419 | ) |
|
424 | ) | |
420 | Session.commit() |
|
425 | Session.commit() | |
|
426 | ||||
|
427 | return dict( | |||
|
428 | id=repo.repo_id, | |||
|
429 | msg="Created new repository %s" % repo.repo_name | |||
|
430 | ) | |||
|
431 | ||||
421 | except Exception: |
|
432 | except Exception: | |
422 | log.error(traceback.format_exc()) |
|
433 | log.error(traceback.format_exc()) | |
423 | raise JSONRPCError('failed to create repository %s' % name) |
|
434 | raise JSONRPCError('failed to create repository %s' % repo_name) | |
424 |
|
435 | |||
425 | @HasPermissionAnyDecorator('hg.admin') |
|
436 | @HasPermissionAnyDecorator('hg.admin') | |
426 | def add_user_to_repo(self, apiuser, repo_name, username, perm): |
|
437 | def add_user_to_repo(self, apiuser, repo_name, username, perm): |
@@ -97,6 +97,13 b' class DbManage(object):' | |||||
97 | from rhodecode.lib.dbmigrate.migrate.exceptions import \ |
|
97 | from rhodecode.lib.dbmigrate.migrate.exceptions import \ | |
98 | DatabaseNotControlledError |
|
98 | DatabaseNotControlledError | |
99 |
|
99 | |||
|
100 | if 'sqlite' in self.dburi: | |||
|
101 | print ( | |||
|
102 | '********************** WARNING **********************\n' | |||
|
103 | 'Make sure your version of sqlite is at least 3.7.X. \n' | |||
|
104 | 'Earlier versions are known to fail on some migrations\n' | |||
|
105 | '*****************************************************\n' | |||
|
106 | ) | |||
100 | upgrade = ask_ok('You are about to perform database upgrade, make ' |
|
107 | upgrade = ask_ok('You are about to perform database upgrade, make ' | |
101 | 'sure You backed up your database before. ' |
|
108 | 'sure You backed up your database before. ' | |
102 | 'Continue ? [y/n]') |
|
109 | 'Continue ? [y/n]') | |
@@ -161,6 +168,9 b' class DbManage(object):' | |||||
161 | print ('Adding ldap defaults') |
|
168 | print ('Adding ldap defaults') | |
162 | self.klass.create_ldap_options(skip_existing=True) |
|
169 | self.klass.create_ldap_options(skip_existing=True) | |
163 |
|
170 | |||
|
171 | def step_4(self): | |||
|
172 | print ('TODO:') | |||
|
173 | ||||
164 | upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1) |
|
174 | upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1) | |
165 |
|
175 | |||
166 | # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE |
|
176 | # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE |
@@ -8,6 +8,7 b' import hashlib' | |||||
8 | import StringIO |
|
8 | import StringIO | |
9 | import urllib |
|
9 | import urllib | |
10 | import math |
|
10 | import math | |
|
11 | import logging | |||
11 |
|
12 | |||
12 | from datetime import datetime |
|
13 | from datetime import datetime | |
13 | from pygments.formatters.html import HtmlFormatter |
|
14 | from pygments.formatters.html import HtmlFormatter | |
@@ -41,6 +42,8 b' from rhodecode.lib.utils import repo_nam' | |||||
41 | from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe |
|
42 | from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe | |
42 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
43 | from rhodecode.lib.markup_renderer import MarkupRenderer | |
43 |
|
44 | |||
|
45 | log = logging.getLogger(__name__) | |||
|
46 | ||||
44 |
|
47 | |||
45 | def _reset(name, value=None, id=NotGiven, type="reset", **attrs): |
|
48 | def _reset(name, value=None, id=NotGiven, type="reset", **attrs): | |
46 | """ |
|
49 | """ | |
@@ -728,7 +731,7 b' def fancy_file_stats(stats):' | |||||
728 | return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d)) |
|
731 | return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d)) | |
729 |
|
732 | |||
730 |
|
733 | |||
731 | def urlify_text(text): |
|
734 | def urlify_text(text_): | |
732 | import re |
|
735 | import re | |
733 |
|
736 | |||
734 | url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]''' |
|
737 | url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]''' | |
@@ -738,8 +741,42 b' def urlify_text(text):' | |||||
738 | url_full = match_obj.groups()[0] |
|
741 | url_full = match_obj.groups()[0] | |
739 | return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full}) |
|
742 | return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full}) | |
740 |
|
743 | |||
741 | return literal(url_pat.sub(url_func, text)) |
|
744 | return literal(url_pat.sub(url_func, text_)) | |
742 |
|
745 | |||
|
746 | def urlify_commit(text_): | |||
|
747 | import re | |||
|
748 | import traceback | |||
|
749 | ||||
|
750 | try: | |||
|
751 | conf = config['app_conf'] | |||
|
752 | ||||
|
753 | URL_PAT = re.compile(r'%s' % conf.get('url_pat')) | |||
|
754 | ||||
|
755 | if URL_PAT: | |||
|
756 | ISSUE_SERVER = conf.get('issue_server') | |||
|
757 | ISSUE_PREFIX = conf.get('issue_prefix') | |||
|
758 | def url_func(match_obj): | |||
|
759 | issue_id = match_obj.groups()[0] | |||
|
760 | tmpl = ( | |||
|
761 | '<a class="%(cls)s" href="%(url)s">' | |||
|
762 | ' %(issue-prefix)s%(id-repr)s' | |||
|
763 | '</a>' | |||
|
764 | ) | |||
|
765 | return tmpl % ( | |||
|
766 | { | |||
|
767 | 'cls':'issue-tracker-link', | |||
|
768 | 'url':ISSUE_SERVER.replace('{id}',issue_id), | |||
|
769 | 'id-repr':issue_id, | |||
|
770 | 'issue-prefix':ISSUE_PREFIX, | |||
|
771 | 'serv':ISSUE_SERVER, | |||
|
772 | } | |||
|
773 | ) | |||
|
774 | return literal(URL_PAT.sub(url_func, text_)) | |||
|
775 | except: | |||
|
776 | log.error(traceback.format_exc()) | |||
|
777 | pass | |||
|
778 | ||||
|
779 | return text_ | |||
743 |
|
780 | |||
744 | def rst(source): |
|
781 | def rst(source): | |
745 | return literal('<div class="rst-block">%s</div>' % |
|
782 | return literal('<div class="rst-block">%s</div>' % |
@@ -1,3 +1,4 b'' | |||||
|
1 | ||||
1 |
|
2 | |||
2 | class InvalidMessage(RuntimeError): |
|
3 | class InvalidMessage(RuntimeError): | |
3 | """ |
|
4 | """ | |
@@ -5,6 +6,7 b' class InvalidMessage(RuntimeError):' | |||||
5 | as recipients or sender address. |
|
6 | as recipients or sender address. | |
6 | """ |
|
7 | """ | |
7 |
|
8 | |||
|
9 | ||||
8 | class BadHeaders(RuntimeError): |
|
10 | class BadHeaders(RuntimeError): | |
9 | """ |
|
11 | """ | |
10 | Raised if message contains newlines in headers. |
|
12 | Raised if message contains newlines in headers. |
@@ -45,6 +45,8 b' class Message(object):' | |||||
45 | :param bcc: BCC list |
|
45 | :param bcc: BCC list | |
46 | :param extra_headers: dict of extra email headers |
|
46 | :param extra_headers: dict of extra email headers | |
47 | :param attachments: list of Attachment instances |
|
47 | :param attachments: list of Attachment instances | |
|
48 | :param recipients_separator: alternative separator for any of | |||
|
49 | 'From', 'To', 'Delivered-To', 'Cc', 'Bcc' fields | |||
48 | """ |
|
50 | """ | |
49 |
|
51 | |||
50 | def __init__(self, |
|
52 | def __init__(self, | |
@@ -56,8 +58,8 b' class Message(object):' | |||||
56 | cc=None, |
|
58 | cc=None, | |
57 | bcc=None, |
|
59 | bcc=None, | |
58 | extra_headers=None, |
|
60 | extra_headers=None, | |
59 |
attachments=None |
|
61 | attachments=None, | |
60 |
|
62 | recipients_separator="; "): | ||
61 |
|
63 | |||
62 | self.subject = subject or '' |
|
64 | self.subject = subject or '' | |
63 | self.sender = sender |
|
65 | self.sender = sender | |
@@ -70,6 +72,8 b' class Message(object):' | |||||
70 | self.bcc = bcc or [] |
|
72 | self.bcc = bcc or [] | |
71 | self.extra_headers = extra_headers or {} |
|
73 | self.extra_headers = extra_headers or {} | |
72 |
|
74 | |||
|
75 | self.recipients_separator = recipients_separator | |||
|
76 | ||||
73 | @property |
|
77 | @property | |
74 | def send_to(self): |
|
78 | def send_to(self): | |
75 | return set(self.recipients) | set(self.bcc or ()) | set(self.cc or ()) |
|
79 | return set(self.recipients) | set(self.bcc or ()) | set(self.cc or ()) | |
@@ -92,7 +96,8 b' class Message(object):' | |||||
92 | To=self.recipients, |
|
96 | To=self.recipients, | |
93 | From=self.sender, |
|
97 | From=self.sender, | |
94 | Body=self.body, |
|
98 | Body=self.body, | |
95 |
Html=self.html |
|
99 | Html=self.html, | |
|
100 | separator=self.recipients_separator) | |||
96 |
|
101 | |||
97 | if self.bcc: |
|
102 | if self.bcc: | |
98 | response.base['Bcc'] = self.bcc |
|
103 | response.base['Bcc'] = self.bcc |
@@ -141,12 +141,14 b' class MailResponse(object):' | |||||
141 | MailResponse.to_message. This lets you change it and work with it, then |
|
141 | MailResponse.to_message. This lets you change it and work with it, then | |
142 | send it out when it's ready. |
|
142 | send it out when it's ready. | |
143 | """ |
|
143 | """ | |
144 |
def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None |
|
144 | def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None, | |
|
145 | separator="; "): | |||
145 | self.Body = Body |
|
146 | self.Body = Body | |
146 | self.Html = Html |
|
147 | self.Html = Html | |
147 | self.base = MailBase([('To', To), ('From', From), ('Subject', Subject)]) |
|
148 | self.base = MailBase([('To', To), ('From', From), ('Subject', Subject)]) | |
148 | self.multipart = self.Body and self.Html |
|
149 | self.multipart = self.Body and self.Html | |
149 | self.attachments = [] |
|
150 | self.attachments = [] | |
|
151 | self.separator = separator | |||
150 |
|
152 | |||
151 | def __contains__(self, key): |
|
153 | def __contains__(self, key): | |
152 | return self.base.__contains__(key) |
|
154 | return self.base.__contains__(key) | |
@@ -298,7 +300,7 b' class MailResponse(object):' | |||||
298 | self.base.body = self.Html |
|
300 | self.base.body = self.Html | |
299 | self.base.content_encoding['Content-Type'] = ('text/html', {}) |
|
301 | self.base.content_encoding['Content-Type'] = ('text/html', {}) | |
300 |
|
302 | |||
301 | return to_message(self.base) |
|
303 | return to_message(self.base, separator=self.separator) | |
302 |
|
304 | |||
303 | def all_parts(self): |
|
305 | def all_parts(self): | |
304 | """ |
|
306 | """ | |
@@ -310,7 +312,7 b' class MailResponse(object):' | |||||
310 | def keys(self): |
|
312 | def keys(self): | |
311 | return self.base.keys() |
|
313 | return self.base.keys() | |
312 |
|
314 | |||
313 | def to_message(mail): |
|
315 | def to_message(mail, separator="; "): | |
314 | """ |
|
316 | """ | |
315 | Given a MailBase message, this will construct a MIMEPart |
|
317 | Given a MailBase message, this will construct a MIMEPart | |
316 | that is canonicalized for use with the Python email API. |
|
318 | that is canonicalized for use with the Python email API. | |
@@ -339,10 +341,16 b' def to_message(mail):' | |||||
339 |
|
341 | |||
340 | for k in mail.keys(): |
|
342 | for k in mail.keys(): | |
341 | if k in ADDRESS_HEADERS_WHITELIST: |
|
343 | if k in ADDRESS_HEADERS_WHITELIST: | |
342 |
out[k.encode('ascii')] = header_to_mime_encoding( |
|
344 | out[k.encode('ascii')] = header_to_mime_encoding( | |
|
345 | mail[k], | |||
|
346 | not_email=False, | |||
|
347 | separator=separator | |||
|
348 | ) | |||
343 | else: |
|
349 | else: | |
344 |
out[k.encode('ascii')] = header_to_mime_encoding( |
|
350 | out[k.encode('ascii')] = header_to_mime_encoding( | |
345 |
|
|
351 | mail[k], | |
|
352 | not_email=True | |||
|
353 | ) | |||
346 |
|
354 | |||
347 | out.extract_payload(mail) |
|
355 | out.extract_payload(mail) | |
348 |
|
356 | |||
@@ -403,12 +411,12 b' class MIMEPart(MIMEBase):' | |||||
403 | self.is_multipart()) |
|
411 | self.is_multipart()) | |
404 |
|
412 | |||
405 |
|
413 | |||
406 | def header_to_mime_encoding(value, not_email=False): |
|
414 | def header_to_mime_encoding(value, not_email=False, separator=", "): | |
407 | if not value: return "" |
|
415 | if not value: return "" | |
408 |
|
416 | |||
409 | encoder = Charset(DEFAULT_ENCODING) |
|
417 | encoder = Charset(DEFAULT_ENCODING) | |
410 | if type(value) == list: |
|
418 | if type(value) == list: | |
411 |
return |
|
419 | return separator.join(properly_encode_header( | |
412 | v, encoder, not_email) for v in value) |
|
420 | v, encoder, not_email) for v in value) | |
413 | else: |
|
421 | else: | |
414 | return properly_encode_header(value, encoder, not_email) |
|
422 | return properly_encode_header(value, encoder, not_email) |
@@ -59,7 +59,8 b' class SmtpMailer(object):' | |||||
59 |
|
59 | |||
60 | if isinstance(recipients, basestring): |
|
60 | if isinstance(recipients, basestring): | |
61 | recipients = [recipients] |
|
61 | recipients = [recipients] | |
62 |
msg = Message(subject, recipients, body, html, self.mail_from |
|
62 | msg = Message(subject, recipients, body, html, self.mail_from, | |
|
63 | recipients_separator=", ") | |||
63 | raw_msg = msg.to_message() |
|
64 | raw_msg = msg.to_message() | |
64 |
|
65 | |||
65 | if self.ssl: |
|
66 | if self.ssl: |
@@ -152,12 +152,12 b' def get_repos(path, recursive=False):' | |||||
152 | """ |
|
152 | """ | |
153 | Scans given path for repos and return (name,(type,path)) tuple |
|
153 | Scans given path for repos and return (name,(type,path)) tuple | |
154 |
|
154 | |||
155 |
:param path: path to scan |
|
155 | :param path: path to scan for repositories | |
156 | :param recursive: recursive search and return names with subdirs in front |
|
156 | :param recursive: recursive search and return names with subdirs in front | |
157 | """ |
|
157 | """ | |
158 |
|
158 | |||
159 | # remove ending slash for better results |
|
159 | # remove ending slash for better results | |
160 |
path = path.rstrip( |
|
160 | path = path.rstrip(os.sep) | |
161 |
|
161 | |||
162 | def _get_repos(p): |
|
162 | def _get_repos(p): | |
163 | if not os.access(p, os.W_OK): |
|
163 | if not os.access(p, os.W_OK): |
@@ -1,7 +1,7 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.model.notification |
|
3 | rhodecode.model.notification | |
4 | ~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | Model for notifications |
|
6 | Model for notifications | |
7 |
|
7 |
@@ -48,7 +48,7 b'' | |||||
48 | <div class="left"> |
|
48 | <div class="left"> | |
49 | <div> |
|
49 | <div> | |
50 | ${h.checkbox(cs.short_id,class_="changeset_range")} |
|
50 | ${h.checkbox(cs.short_id,class_="changeset_range")} | |
51 | <span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span> |
|
51 | <span class="tooltip" title="${cs.date}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span> | |
52 | </div> |
|
52 | </div> | |
53 | <div class="author"> |
|
53 | <div class="author"> | |
54 | <div class="gravatar"> |
|
54 | <div class="gravatar"> |
@@ -49,7 +49,7 b'' | |||||
49 | <span>${h.person(c.changeset.author)}</span><br/> |
|
49 | <span>${h.person(c.changeset.author)}</span><br/> | |
50 | <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/> |
|
50 | <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/> | |
51 | </div> |
|
51 | </div> | |
52 | <div class="message">${h.wrap_paragraphs(c.changeset.message)}</div> |
|
52 | <div class="message">${h.urlify_commit(h.wrap_paragraphs(c.changeset.message))}</div> | |
53 | </div> |
|
53 | </div> | |
54 | <div class="right"> |
|
54 | <div class="right"> | |
55 | <div class="changes"> |
|
55 | <div class="changes"> | |
@@ -95,7 +95,7 b'' | |||||
95 | <div class="cs_${change}"> |
|
95 | <div class="cs_${change}"> | |
96 | <div class="node"> |
|
96 | <div class="node"> | |
97 | %if change != 'removed': |
|
97 | %if change != 'removed': | |
98 | ${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path))} |
|
98 | ${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path)+"_target")} | |
99 | %else: |
|
99 | %else: | |
100 | ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID('',filenode.path)))} |
|
100 | ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID('',filenode.path)))} | |
101 | %endif |
|
101 | %endif | |
@@ -138,11 +138,15 b'' | |||||
138 | YUE.on(YUQ('.show-inline-comments'),'change',function(e){ |
|
138 | YUE.on(YUQ('.show-inline-comments'),'change',function(e){ | |
139 | var show = 'none'; |
|
139 | var show = 'none'; | |
140 | var target = e.currentTarget; |
|
140 | var target = e.currentTarget; | |
|
141 | console.log(target); | |||
141 | if(target.checked){ |
|
142 | if(target.checked){ | |
142 | var show = '' |
|
143 | var show = '' | |
143 | } |
|
144 | } | |
|
145 | console.log('aa') | |||
144 | var boxid = YUD.getAttribute(target,'id_for'); |
|
146 | var boxid = YUD.getAttribute(target,'id_for'); | |
|
147 | console.log(boxid); | |||
145 | var comments = YUQ('#{0} .inline-comments'.format(boxid)); |
|
148 | var comments = YUQ('#{0} .inline-comments'.format(boxid)); | |
|
149 | console.log(comments) | |||
146 | for(c in comments){ |
|
150 | for(c in comments){ | |
147 | YUD.setStyle(comments[c],'display',show); |
|
151 | YUD.setStyle(comments[c],'display',show); | |
148 | } |
|
152 | } |
@@ -41,7 +41,7 b'' | |||||
41 | <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td> |
|
41 | <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td> | |
42 | <td><div class="author">${h.person(cs.author)}</div></td> |
|
42 | <td><div class="author">${h.person(cs.author)}</div></td> | |
43 | <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td> |
|
43 | <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td> | |
44 |
<td><div class="message">${h. |
|
44 | <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message))}</div></td> | |
45 | </tr> |
|
45 | </tr> | |
46 | %endfor |
|
46 | %endfor | |
47 | </table> |
|
47 | </table> |
@@ -7,8 +7,8 b'' | |||||
7 |
|
7 | |||
8 | %for change,filenode,diff,cs1,cs2,stat in changes: |
|
8 | %for change,filenode,diff,cs1,cs2,stat in changes: | |
9 | %if change !='removed': |
|
9 | %if change !='removed': | |
10 | <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}" style="clear:both;height:90px;margin-top:-60px"></div> |
|
10 | <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}_target" style="clear:both;height:90px;margin-top:-60px"></div> | |
11 | <div class="diffblock margined comm"> |
|
11 | <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}" class="diffblock margined comm"> | |
12 | <div class="code-header"> |
|
12 | <div class="code-header"> | |
13 | <div class="changeset_header"> |
|
13 | <div class="changeset_header"> | |
14 | <div class="changeset_file"> |
|
14 | <div class="changeset_file"> |
@@ -2,16 +2,19 b'' | |||||
2 | %if c.repo_changesets: |
|
2 | %if c.repo_changesets: | |
3 | <table class="table_disp"> |
|
3 | <table class="table_disp"> | |
4 | <tr> |
|
4 | <tr> | |
5 |
|
|
5 | <th class="left">${_('revision')}</th> | |
|
6 | <th class="left">${_('commit message')}</th> | |||
6 | <th class="left">${_('age')}</th> |
|
7 | <th class="left">${_('age')}</th> | |
7 | <th class="left">${_('author')}</th> |
|
8 | <th class="left">${_('author')}</th> | |
8 | <th class="left">${_('revision')}</th> |
|
|||
9 | <th class="left">${_('branch')}</th> |
|
9 | <th class="left">${_('branch')}</th> | |
10 | <th class="left">${_('tags')}</th> |
|
10 | <th class="left">${_('tags')}</th> | |
11 | </tr> |
|
11 | </tr> | |
12 | %for cnt,cs in enumerate(c.repo_changesets): |
|
12 | %for cnt,cs in enumerate(c.repo_changesets): | |
13 | <tr class="parity${cnt%2}"> |
|
13 | <tr class="parity${cnt%2}"> | |
14 | <td> |
|
14 | <td> | |
|
15 | <div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div> | |||
|
16 | </td> | |||
|
17 | <td> | |||
15 | ${h.link_to(h.truncate(cs.message,50), |
|
18 | ${h.link_to(h.truncate(cs.message,50), | |
16 | h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id), |
|
19 | h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id), | |
17 | title=cs.message)} |
|
20 | title=cs.message)} | |
@@ -20,7 +23,6 b'' | |||||
20 | ${h.age(cs.date)}</span> |
|
23 | ${h.age(cs.date)}</span> | |
21 | </td> |
|
24 | </td> | |
22 | <td title="${cs.author}">${h.person(cs.author)}</td> |
|
25 | <td title="${cs.author}">${h.person(cs.author)}</td> | |
23 | <td><div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div></td> |
|
|||
24 | <td> |
|
26 | <td> | |
25 | <span class="logtags"> |
|
27 | <span class="logtags"> | |
26 | <span class="branchtag">${cs.branch}</span> |
|
28 | <span class="branchtag">${cs.branch}</span> |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now