##// END OF EJS Templates
Allow RhodeCode maintainers to specify a custom bug tracker....
Jonathan Sternberg -
r4006:cdf10b3d default
parent child Browse files
Show More
@@ -1,514 +1,517 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # RhodeCode - Pylons environment configuration #
4 4 # #
5 5 # The %(here)s variable will be replaced with the parent directory of this file#
6 6 ################################################################################
7 7
8 8 [DEFAULT]
9 9 debug = true
10 10 pdebug = false
11 11 ################################################################################
12 12 ## Uncomment and replace with the address which should receive ##
13 13 ## any error reports after application crash ##
14 14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 15 ################################################################################
16 16 #email_to = admin@localhost
17 17 #error_email_from = paste_error@localhost
18 18 #app_email_from = rhodecode-noreply@localhost
19 19 #error_message =
20 20 #email_prefix = [RhodeCode]
21 21
22 22 #smtp_server = mail.server.com
23 23 #smtp_username =
24 24 #smtp_password =
25 25 #smtp_port =
26 26 #smtp_use_tls = false
27 27 #smtp_use_ssl = true
28 28 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
29 29 #smtp_auth =
30 30
31 31 [server:main]
32 32 ## PASTE ##
33 33 #use = egg:Paste#http
34 34 ## nr of worker threads to spawn
35 35 #threadpool_workers = 5
36 36 ## max request before thread respawn
37 37 #threadpool_max_requests = 10
38 38 ## option to use threads of process
39 39 #use_threadpool = true
40 40
41 41 ## WAITRESS ##
42 42 use = egg:waitress#main
43 43 ## number of worker threads
44 44 threads = 5
45 45 ## MAX BODY SIZE 100GB
46 46 max_request_body_size = 107374182400
47 47 ## use poll instead of select, fixes fd limits, may not work on old
48 48 ## windows systems.
49 49 #asyncore_use_poll = True
50 50
51 51 ## GUNICORN ##
52 52 #use = egg:gunicorn#main
53 53 ## number of process workers. You must set `instance_id = *` when this option
54 54 ## is set to more than one worker
55 55 #workers = 1
56 56 ## process name
57 57 #proc_name = rhodecode
58 58 ## type of worker class, one of sync, eventlet, gevent, tornado
59 59 ## recommended for bigger setup is using of of other than sync one
60 60 #worker_class = sync
61 61 #max_requests = 5
62 62 ## ammount of time a worker can handle request before it get's killed and
63 63 ## restarted
64 64 #timeout = 3600
65 65
66 66 ## COMMON ##
67 67 host = 0.0.0.0
68 68 port = 5000
69 69
70 70 ## prefix middleware for rc
71 71 #[filter:proxy-prefix]
72 72 #use = egg:PasteDeploy#prefix
73 73 #prefix = /<your-prefix>
74 74
75 75 [app:main]
76 76 use = egg:rhodecode
77 77 ## enable proxy prefix middleware
78 78 #filter-with = proxy-prefix
79 79
80 80 full_stack = true
81 81 static_files = true
82 82 ## Optional Languages
83 83 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
84 84 lang = en
85 85 cache_dir = %(here)s/data
86 86 index_dir = %(here)s/data/index
87 87
88 88 ## perform a full repository scan on each server start, this should be
89 89 ## set to false after first startup, to allow faster server restarts.
90 90 initial_repo_scan = true
91 91
92 92 ## uncomment and set this path to use archive download cache
93 93 #archive_cache_dir = /tmp/tarballcache
94 94
95 95 ## change this to unique ID for security
96 96 app_instance_uuid = rc-production
97 97
98 98 ## cut off limit for large diffs (size in bytes)
99 99 cut_off_limit = 256000
100 100
101 101 ## use cache version of scm repo everywhere
102 102 vcs_full_cache = true
103 103
104 104 ## force https in RhodeCode, fixes https redirects, assumes it's always https
105 105 force_https = false
106 106
107 107 ## use Strict-Transport-Security headers
108 108 use_htsts = false
109 109
110 110 ## number of commits stats will parse on each iteration
111 111 commit_parse_limit = 25
112 112
113 113 ## use gravatar service to display avatars
114 114 use_gravatar = true
115 115
116 116 ## path to git executable
117 117 git_path = git
118 118
119 119 ## git rev filter option, --all is the default filter, if you need to
120 120 ## hide all refs in changelog switch this to --branches --tags
121 121 git_rev_filter=--all
122 122
123 123 ## RSS feed options
124 124 rss_cut_off_limit = 256000
125 125 rss_items_per_page = 10
126 126 rss_include_diff = false
127 127
128 128 ## options for showing and identifying changesets
129 129 show_sha_length = 12
130 130 show_revision_number = true
131 131
132 132 ## gist URL alias, used to create nicer urls for gist. This should be an
133 133 ## url that does rewrites to _admin/gists/<gistid>.
134 134 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
135 135 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
136 136 gist_alias_url =
137 137
138 138 ## white list of API enabled controllers. This allows to add list of
139 139 ## controllers to which access will be enabled by api_key. eg: to enable
140 140 ## api access to raw_files put `FilesController:raw`, to enable access to patches
141 141 ## add `ChangesetController:changeset_patch`. This list should be "," separated
142 142 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
143 143 api_access_controllers_whitelist =
144 144
145 145 ## alternative_gravatar_url allows you to use your own avatar server application
146 146 ## the following parts of the URL will be replaced
147 147 ## {email} user email
148 148 ## {md5email} md5 hash of the user email (like at gravatar.com)
149 149 ## {size} size of the image that is expected from the server application
150 150 ## {scheme} http/https from RhodeCode server
151 151 ## {netloc} network location from RhodeCode server
152 152 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
153 153 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
154 154
155 155
156 156 ## container auth options
157 157 container_auth_enabled = false
158 158 proxypass_auth_enabled = false
159 159
160 160 ## default encoding used to convert from and to unicode
161 161 ## can be also a comma seperated list of encoding in case of mixed encodings
162 162 default_encoding = utf8
163 163
164 164 ## overwrite schema of clone url
165 165 ## available vars:
166 166 ## scheme - http/https
167 167 ## user - current user
168 168 ## pass - password
169 169 ## netloc - network location
170 170 ## path - usually repo_name
171 171
172 172 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
173 173
174 ## issue tracker RhodeCode (leave blank to disable, absent for default)
175 #bugtracker = http://bitbucket.org/marcinkuzminski/rhodecode/issues
176
174 177 ## issue tracking mapping for commits messages
175 178 ## comment out issue_pat, issue_server, issue_prefix to enable
176 179
177 180 ## pattern to get the issues from commit messages
178 181 ## default one used here is #<numbers> with a regex passive group for `#`
179 182 ## {id} will be all groups matched from this pattern
180 183
181 184 issue_pat = (?:\s*#)(\d+)
182 185
183 186 ## server url to the issue, each {id} will be replaced with match
184 187 ## fetched from the regex and {repo} is replaced with full repository name
185 188 ## including groups {repo_name} is replaced with just name of repo
186 189
187 190 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
188 191
189 192 ## prefix to add to link to indicate it's an url
190 193 ## #314 will be replaced by <issue_prefix><id>
191 194
192 195 issue_prefix = #
193 196
194 197 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
195 198 ## multiple patterns, to other issues server, wiki or others
196 199 ## below an example how to create a wiki pattern
197 200 # #wiki-some-id -> https://mywiki.com/some-id
198 201
199 202 #issue_pat_wiki = (?:wiki-)(.+)
200 203 #issue_server_link_wiki = https://mywiki.com/{id}
201 204 #issue_prefix_wiki = WIKI-
202 205
203 206
204 207 ## instance-id prefix
205 208 ## a prefix key for this instance used for cache invalidation when running
206 209 ## multiple instances of rhodecode, make sure it's globally unique for
207 210 ## all running rhodecode instances. Leave empty if you don't use it
208 211 instance_id =
209 212
210 213 ## alternative return HTTP header for failed authentication. Default HTTP
211 214 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
212 215 ## handling that. Set this variable to 403 to return HTTPForbidden
213 216 auth_ret_code =
214 217
215 218 ## locking return code. When repository is locked return this HTTP code. 2XX
216 219 ## codes don't break the transactions while 4XX codes do
217 220 lock_ret_code = 423
218 221
219 222 allow_repo_location_change = True
220 223
221 224 ####################################
222 225 ### CELERY CONFIG ####
223 226 ####################################
224 227 use_celery = false
225 228 broker.host = localhost
226 229 broker.vhost = rabbitmqhost
227 230 broker.port = 5672
228 231 broker.user = rabbitmq
229 232 broker.password = qweqwe
230 233
231 234 celery.imports = rhodecode.lib.celerylib.tasks
232 235
233 236 celery.result.backend = amqp
234 237 celery.result.dburi = amqp://
235 238 celery.result.serialier = json
236 239
237 240 #celery.send.task.error.emails = true
238 241 #celery.amqp.task.result.expires = 18000
239 242
240 243 celeryd.concurrency = 2
241 244 #celeryd.log.file = celeryd.log
242 245 celeryd.log.level = debug
243 246 celeryd.max.tasks.per.child = 1
244 247
245 248 ## tasks will never be sent to the queue, but executed locally instead.
246 249 celery.always.eager = false
247 250
248 251 ####################################
249 252 ### BEAKER CACHE ####
250 253 ####################################
251 254 beaker.cache.data_dir=%(here)s/data/cache/data
252 255 beaker.cache.lock_dir=%(here)s/data/cache/lock
253 256
254 257 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
255 258
256 259 beaker.cache.super_short_term.type=memory
257 260 beaker.cache.super_short_term.expire=10
258 261 beaker.cache.super_short_term.key_length = 256
259 262
260 263 beaker.cache.short_term.type=memory
261 264 beaker.cache.short_term.expire=60
262 265 beaker.cache.short_term.key_length = 256
263 266
264 267 beaker.cache.long_term.type=memory
265 268 beaker.cache.long_term.expire=36000
266 269 beaker.cache.long_term.key_length = 256
267 270
268 271 beaker.cache.sql_cache_short.type=memory
269 272 beaker.cache.sql_cache_short.expire=10
270 273 beaker.cache.sql_cache_short.key_length = 256
271 274
272 275 beaker.cache.sql_cache_med.type=memory
273 276 beaker.cache.sql_cache_med.expire=360
274 277 beaker.cache.sql_cache_med.key_length = 256
275 278
276 279 beaker.cache.sql_cache_long.type=file
277 280 beaker.cache.sql_cache_long.expire=3600
278 281 beaker.cache.sql_cache_long.key_length = 256
279 282
280 283 ####################################
281 284 ### BEAKER SESSION ####
282 285 ####################################
283 286 ## Type of storage used for the session, current types are
284 287 ## dbm, file, memcached, database, and memory.
285 288 ## The storage uses the Container API
286 289 ## that is also used by the cache system.
287 290
288 291 ## db session ##
289 292 #beaker.session.type = ext:database
290 293 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
291 294 #beaker.session.table_name = db_session
292 295
293 296 ## encrypted cookie client side session, good for many instances ##
294 297 #beaker.session.type = cookie
295 298
296 299 ## file based cookies (default) ##
297 300 #beaker.session.type = file
298 301
299 302 beaker.session.key = rhodecode
300 303 beaker.session.secret = ${app_instance_uuid}
301 304
302 305 ## Secure encrypted cookie. Requires AES and AES python libraries
303 306 ## you must disable beaker.session.secret to use this
304 307 #beaker.session.encrypt_key = <key_for_encryption>
305 308 #beaker.session.validate_key = <validation_key>
306 309
307 310 ## sets session as invalid if it haven't been accessed for given amount of time
308 311 beaker.session.timeout = 2592000
309 312 beaker.session.httponly = true
310 313 #beaker.session.cookie_path = /<your-prefix>
311 314
312 315 ## uncomment for https secure cookie
313 316 beaker.session.secure = false
314 317
315 318 ## auto save the session to not to use .save()
316 319 beaker.session.auto = False
317 320
318 321 ## default cookie expiration time in seconds `true` expire at browser close ##
319 322 #beaker.session.cookie_expires = 3600
320 323
321 324
322 325 ############################
323 326 ## ERROR HANDLING SYSTEMS ##
324 327 ############################
325 328
326 329 ####################
327 330 ### [errormator] ###
328 331 ####################
329 332
330 333 ## Errormator is tailored to work with RhodeCode, see
331 334 ## http://errormator.com for details how to obtain an account
332 335 ## you must install python package `errormator_client` to make it work
333 336
334 337 ## errormator enabled
335 338 errormator = false
336 339
337 340 errormator.server_url = https://api.errormator.com
338 341 errormator.api_key = YOUR_API_KEY
339 342
340 343 ## TWEAK AMOUNT OF INFO SENT HERE
341 344
342 345 ## enables 404 error logging (default False)
343 346 errormator.report_404 = false
344 347
345 348 ## time in seconds after request is considered being slow (default 1)
346 349 errormator.slow_request_time = 1
347 350
348 351 ## record slow requests in application
349 352 ## (needs to be enabled for slow datastore recording and time tracking)
350 353 errormator.slow_requests = true
351 354
352 355 ## enable hooking to application loggers
353 356 # errormator.logging = true
354 357
355 358 ## minimum log level for log capture
356 359 # errormator.logging.level = WARNING
357 360
358 361 ## send logs only from erroneous/slow requests
359 362 ## (saves API quota for intensive logging)
360 363 errormator.logging_on_error = false
361 364
362 365 ## list of additonal keywords that should be grabbed from environ object
363 366 ## can be string with comma separated list of words in lowercase
364 367 ## (by default client will always send following info:
365 368 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
366 369 ## start with HTTP* this list be extended with additional keywords here
367 370 errormator.environ_keys_whitelist =
368 371
369 372
370 373 ## list of keywords that should be blanked from request object
371 374 ## can be string with comma separated list of words in lowercase
372 375 ## (by default client will always blank keys that contain following words
373 376 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
374 377 ## this list be extended with additional keywords set here
375 378 errormator.request_keys_blacklist =
376 379
377 380
378 381 ## list of namespaces that should be ignores when gathering log entries
379 382 ## can be string with comma separated list of namespaces
380 383 ## (by default the client ignores own entries: errormator_client.client)
381 384 errormator.log_namespace_blacklist =
382 385
383 386
384 387 ################
385 388 ### [sentry] ###
386 389 ################
387 390
388 391 ## sentry is a alternative open source error aggregator
389 392 ## you must install python packages `sentry` and `raven` to enable
390 393
391 394 sentry.dsn = YOUR_DNS
392 395 sentry.servers =
393 396 sentry.name =
394 397 sentry.key =
395 398 sentry.public_key =
396 399 sentry.secret_key =
397 400 sentry.project =
398 401 sentry.site =
399 402 sentry.include_paths =
400 403 sentry.exclude_paths =
401 404
402 405
403 406 ################################################################################
404 407 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
405 408 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
406 409 ## execute malicious code after an exception is raised. ##
407 410 ################################################################################
408 411 #set debug = false
409 412
410 413 ##################################
411 414 ### LOGVIEW CONFIG ###
412 415 ##################################
413 416 logview.sqlalchemy = #faa
414 417 logview.pylons.templating = #bfb
415 418 logview.pylons.util = #eee
416 419
417 420 #########################################################
418 421 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
419 422 #########################################################
420 423 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
421 424 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
422 425 sqlalchemy.db1.echo = false
423 426 sqlalchemy.db1.pool_recycle = 3600
424 427 sqlalchemy.db1.convert_unicode = true
425 428
426 429 ################################
427 430 ### LOGGING CONFIGURATION ####
428 431 ################################
429 432 [loggers]
430 433 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
431 434
432 435 [handlers]
433 436 keys = console, console_sql
434 437
435 438 [formatters]
436 439 keys = generic, color_formatter, color_formatter_sql
437 440
438 441 #############
439 442 ## LOGGERS ##
440 443 #############
441 444 [logger_root]
442 445 level = NOTSET
443 446 handlers = console
444 447
445 448 [logger_routes]
446 449 level = DEBUG
447 450 handlers =
448 451 qualname = routes.middleware
449 452 ## "level = DEBUG" logs the route matched and routing variables.
450 453 propagate = 1
451 454
452 455 [logger_beaker]
453 456 level = DEBUG
454 457 handlers =
455 458 qualname = beaker.container
456 459 propagate = 1
457 460
458 461 [logger_templates]
459 462 level = INFO
460 463 handlers =
461 464 qualname = pylons.templating
462 465 propagate = 1
463 466
464 467 [logger_rhodecode]
465 468 level = DEBUG
466 469 handlers =
467 470 qualname = rhodecode
468 471 propagate = 1
469 472
470 473 [logger_sqlalchemy]
471 474 level = INFO
472 475 handlers = console_sql
473 476 qualname = sqlalchemy.engine
474 477 propagate = 0
475 478
476 479 [logger_whoosh_indexer]
477 480 level = DEBUG
478 481 handlers =
479 482 qualname = whoosh_indexer
480 483 propagate = 1
481 484
482 485 ##############
483 486 ## HANDLERS ##
484 487 ##############
485 488
486 489 [handler_console]
487 490 class = StreamHandler
488 491 args = (sys.stderr,)
489 492 level = DEBUG
490 493 formatter = color_formatter
491 494
492 495 [handler_console_sql]
493 496 class = StreamHandler
494 497 args = (sys.stderr,)
495 498 level = DEBUG
496 499 formatter = color_formatter_sql
497 500
498 501 ################
499 502 ## FORMATTERS ##
500 503 ################
501 504
502 505 [formatter_generic]
503 506 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
504 507 datefmt = %Y-%m-%d %H:%M:%S
505 508
506 509 [formatter_color_formatter]
507 510 class=rhodecode.lib.colored_formatter.ColorFormatter
508 511 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
509 512 datefmt = %Y-%m-%d %H:%M:%S
510 513
511 514 [formatter_color_formatter_sql]
512 515 class=rhodecode.lib.colored_formatter.ColorFormatterSql
513 516 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
514 517 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,514 +1,517 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # RhodeCode - Pylons environment configuration #
4 4 # #
5 5 # The %(here)s variable will be replaced with the parent directory of this file#
6 6 ################################################################################
7 7
8 8 [DEFAULT]
9 9 debug = true
10 10 pdebug = false
11 11 ################################################################################
12 12 ## Uncomment and replace with the address which should receive ##
13 13 ## any error reports after application crash ##
14 14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 15 ################################################################################
16 16 #email_to = admin@localhost
17 17 #error_email_from = paste_error@localhost
18 18 #app_email_from = rhodecode-noreply@localhost
19 19 #error_message =
20 20 #email_prefix = [RhodeCode]
21 21
22 22 #smtp_server = mail.server.com
23 23 #smtp_username =
24 24 #smtp_password =
25 25 #smtp_port =
26 26 #smtp_use_tls = false
27 27 #smtp_use_ssl = true
28 28 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
29 29 #smtp_auth =
30 30
31 31 [server:main]
32 32 ## PASTE ##
33 33 #use = egg:Paste#http
34 34 ## nr of worker threads to spawn
35 35 #threadpool_workers = 5
36 36 ## max request before thread respawn
37 37 #threadpool_max_requests = 10
38 38 ## option to use threads of process
39 39 #use_threadpool = true
40 40
41 41 ## WAITRESS ##
42 42 use = egg:waitress#main
43 43 ## number of worker threads
44 44 threads = 5
45 45 ## MAX BODY SIZE 100GB
46 46 max_request_body_size = 107374182400
47 47 ## use poll instead of select, fixes fd limits, may not work on old
48 48 ## windows systems.
49 49 #asyncore_use_poll = True
50 50
51 51 ## GUNICORN ##
52 52 #use = egg:gunicorn#main
53 53 ## number of process workers. You must set `instance_id = *` when this option
54 54 ## is set to more than one worker
55 55 #workers = 1
56 56 ## process name
57 57 #proc_name = rhodecode
58 58 ## type of worker class, one of sync, eventlet, gevent, tornado
59 59 ## recommended for bigger setup is using of of other than sync one
60 60 #worker_class = sync
61 61 #max_requests = 5
62 62 ## ammount of time a worker can handle request before it get's killed and
63 63 ## restarted
64 64 #timeout = 3600
65 65
66 66 ## COMMON ##
67 67 host = 127.0.0.1
68 68 port = 5000
69 69
70 70 ## prefix middleware for rc
71 71 #[filter:proxy-prefix]
72 72 #use = egg:PasteDeploy#prefix
73 73 #prefix = /<your-prefix>
74 74
75 75 [app:main]
76 76 use = egg:rhodecode
77 77 ## enable proxy prefix middleware
78 78 #filter-with = proxy-prefix
79 79
80 80 full_stack = true
81 81 static_files = true
82 82 ## Optional Languages
83 83 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
84 84 lang = en
85 85 cache_dir = %(here)s/data
86 86 index_dir = %(here)s/data/index
87 87
88 88 ## perform a full repository scan on each server start, this should be
89 89 ## set to false after first startup, to allow faster server restarts.
90 90 initial_repo_scan = true
91 91
92 92 ## uncomment and set this path to use archive download cache
93 93 #archive_cache_dir = /tmp/tarballcache
94 94
95 95 ## change this to unique ID for security
96 96 app_instance_uuid = rc-production
97 97
98 98 ## cut off limit for large diffs (size in bytes)
99 99 cut_off_limit = 256000
100 100
101 101 ## use cache version of scm repo everywhere
102 102 vcs_full_cache = true
103 103
104 104 ## force https in RhodeCode, fixes https redirects, assumes it's always https
105 105 force_https = false
106 106
107 107 ## use Strict-Transport-Security headers
108 108 use_htsts = false
109 109
110 110 ## number of commits stats will parse on each iteration
111 111 commit_parse_limit = 25
112 112
113 113 ## use gravatar service to display avatars
114 114 use_gravatar = true
115 115
116 116 ## path to git executable
117 117 git_path = git
118 118
119 119 ## git rev filter option, --all is the default filter, if you need to
120 120 ## hide all refs in changelog switch this to --branches --tags
121 121 git_rev_filter=--all
122 122
123 123 ## RSS feed options
124 124 rss_cut_off_limit = 256000
125 125 rss_items_per_page = 10
126 126 rss_include_diff = false
127 127
128 128 ## options for showing and identifying changesets
129 129 show_sha_length = 12
130 130 show_revision_number = true
131 131
132 132 ## gist URL alias, used to create nicer urls for gist. This should be an
133 133 ## url that does rewrites to _admin/gists/<gistid>.
134 134 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
135 135 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
136 136 gist_alias_url =
137 137
138 138 ## white list of API enabled controllers. This allows to add list of
139 139 ## controllers to which access will be enabled by api_key. eg: to enable
140 140 ## api access to raw_files put `FilesController:raw`, to enable access to patches
141 141 ## add `ChangesetController:changeset_patch`. This list should be "," separated
142 142 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
143 143 api_access_controllers_whitelist =
144 144
145 145 ## alternative_gravatar_url allows you to use your own avatar server application
146 146 ## the following parts of the URL will be replaced
147 147 ## {email} user email
148 148 ## {md5email} md5 hash of the user email (like at gravatar.com)
149 149 ## {size} size of the image that is expected from the server application
150 150 ## {scheme} http/https from RhodeCode server
151 151 ## {netloc} network location from RhodeCode server
152 152 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
153 153 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
154 154
155 155
156 156 ## container auth options
157 157 container_auth_enabled = false
158 158 proxypass_auth_enabled = false
159 159
160 160 ## default encoding used to convert from and to unicode
161 161 ## can be also a comma seperated list of encoding in case of mixed encodings
162 162 default_encoding = utf8
163 163
164 164 ## overwrite schema of clone url
165 165 ## available vars:
166 166 ## scheme - http/https
167 167 ## user - current user
168 168 ## pass - password
169 169 ## netloc - network location
170 170 ## path - usually repo_name
171 171
172 172 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
173 173
174 ## issue tracker for RhodeCode (leave blank to disable, absent for default)
175 #bugtracker = http://bitbucket.org/marcinkuzminski/rhodecode/issues
176
174 177 ## issue tracking mapping for commits messages
175 178 ## comment out issue_pat, issue_server, issue_prefix to enable
176 179
177 180 ## pattern to get the issues from commit messages
178 181 ## default one used here is #<numbers> with a regex passive group for `#`
179 182 ## {id} will be all groups matched from this pattern
180 183
181 184 issue_pat = (?:\s*#)(\d+)
182 185
183 186 ## server url to the issue, each {id} will be replaced with match
184 187 ## fetched from the regex and {repo} is replaced with full repository name
185 188 ## including groups {repo_name} is replaced with just name of repo
186 189
187 190 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
188 191
189 192 ## prefix to add to link to indicate it's an url
190 193 ## #314 will be replaced by <issue_prefix><id>
191 194
192 195 issue_prefix = #
193 196
194 197 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
195 198 ## multiple patterns, to other issues server, wiki or others
196 199 ## below an example how to create a wiki pattern
197 200 # #wiki-some-id -> https://mywiki.com/some-id
198 201
199 202 #issue_pat_wiki = (?:wiki-)(.+)
200 203 #issue_server_link_wiki = https://mywiki.com/{id}
201 204 #issue_prefix_wiki = WIKI-
202 205
203 206
204 207 ## instance-id prefix
205 208 ## a prefix key for this instance used for cache invalidation when running
206 209 ## multiple instances of rhodecode, make sure it's globally unique for
207 210 ## all running rhodecode instances. Leave empty if you don't use it
208 211 instance_id =
209 212
210 213 ## alternative return HTTP header for failed authentication. Default HTTP
211 214 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
212 215 ## handling that. Set this variable to 403 to return HTTPForbidden
213 216 auth_ret_code =
214 217
215 218 ## locking return code. When repository is locked return this HTTP code. 2XX
216 219 ## codes don't break the transactions while 4XX codes do
217 220 lock_ret_code = 423
218 221
219 222 allow_repo_location_change = True
220 223
221 224 ####################################
222 225 ### CELERY CONFIG ####
223 226 ####################################
224 227 use_celery = false
225 228 broker.host = localhost
226 229 broker.vhost = rabbitmqhost
227 230 broker.port = 5672
228 231 broker.user = rabbitmq
229 232 broker.password = qweqwe
230 233
231 234 celery.imports = rhodecode.lib.celerylib.tasks
232 235
233 236 celery.result.backend = amqp
234 237 celery.result.dburi = amqp://
235 238 celery.result.serialier = json
236 239
237 240 #celery.send.task.error.emails = true
238 241 #celery.amqp.task.result.expires = 18000
239 242
240 243 celeryd.concurrency = 2
241 244 #celeryd.log.file = celeryd.log
242 245 celeryd.log.level = debug
243 246 celeryd.max.tasks.per.child = 1
244 247
245 248 ## tasks will never be sent to the queue, but executed locally instead.
246 249 celery.always.eager = false
247 250
248 251 ####################################
249 252 ### BEAKER CACHE ####
250 253 ####################################
251 254 beaker.cache.data_dir=%(here)s/data/cache/data
252 255 beaker.cache.lock_dir=%(here)s/data/cache/lock
253 256
254 257 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
255 258
256 259 beaker.cache.super_short_term.type=memory
257 260 beaker.cache.super_short_term.expire=10
258 261 beaker.cache.super_short_term.key_length = 256
259 262
260 263 beaker.cache.short_term.type=memory
261 264 beaker.cache.short_term.expire=60
262 265 beaker.cache.short_term.key_length = 256
263 266
264 267 beaker.cache.long_term.type=memory
265 268 beaker.cache.long_term.expire=36000
266 269 beaker.cache.long_term.key_length = 256
267 270
268 271 beaker.cache.sql_cache_short.type=memory
269 272 beaker.cache.sql_cache_short.expire=10
270 273 beaker.cache.sql_cache_short.key_length = 256
271 274
272 275 beaker.cache.sql_cache_med.type=memory
273 276 beaker.cache.sql_cache_med.expire=360
274 277 beaker.cache.sql_cache_med.key_length = 256
275 278
276 279 beaker.cache.sql_cache_long.type=file
277 280 beaker.cache.sql_cache_long.expire=3600
278 281 beaker.cache.sql_cache_long.key_length = 256
279 282
280 283 ####################################
281 284 ### BEAKER SESSION ####
282 285 ####################################
283 286 ## Type of storage used for the session, current types are
284 287 ## dbm, file, memcached, database, and memory.
285 288 ## The storage uses the Container API
286 289 ## that is also used by the cache system.
287 290
288 291 ## db session ##
289 292 #beaker.session.type = ext:database
290 293 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
291 294 #beaker.session.table_name = db_session
292 295
293 296 ## encrypted cookie client side session, good for many instances ##
294 297 #beaker.session.type = cookie
295 298
296 299 ## file based cookies (default) ##
297 300 #beaker.session.type = file
298 301
299 302 beaker.session.key = rhodecode
300 303 beaker.session.secret = ${app_instance_uuid}
301 304
302 305 ## Secure encrypted cookie. Requires AES and AES python libraries
303 306 ## you must disable beaker.session.secret to use this
304 307 #beaker.session.encrypt_key = <key_for_encryption>
305 308 #beaker.session.validate_key = <validation_key>
306 309
307 310 ## sets session as invalid if it haven't been accessed for given amount of time
308 311 beaker.session.timeout = 2592000
309 312 beaker.session.httponly = true
310 313 #beaker.session.cookie_path = /<your-prefix>
311 314
312 315 ## uncomment for https secure cookie
313 316 beaker.session.secure = false
314 317
315 318 ## auto save the session to not to use .save()
316 319 beaker.session.auto = False
317 320
318 321 ## default cookie expiration time in seconds `true` expire at browser close ##
319 322 #beaker.session.cookie_expires = 3600
320 323
321 324
322 325 ############################
323 326 ## ERROR HANDLING SYSTEMS ##
324 327 ############################
325 328
326 329 ####################
327 330 ### [errormator] ###
328 331 ####################
329 332
330 333 ## Errormator is tailored to work with RhodeCode, see
331 334 ## http://errormator.com for details how to obtain an account
332 335 ## you must install python package `errormator_client` to make it work
333 336
334 337 ## errormator enabled
335 338 errormator = false
336 339
337 340 errormator.server_url = https://api.errormator.com
338 341 errormator.api_key = YOUR_API_KEY
339 342
340 343 ## TWEAK AMOUNT OF INFO SENT HERE
341 344
342 345 ## enables 404 error logging (default False)
343 346 errormator.report_404 = false
344 347
345 348 ## time in seconds after request is considered being slow (default 1)
346 349 errormator.slow_request_time = 1
347 350
348 351 ## record slow requests in application
349 352 ## (needs to be enabled for slow datastore recording and time tracking)
350 353 errormator.slow_requests = true
351 354
352 355 ## enable hooking to application loggers
353 356 # errormator.logging = true
354 357
355 358 ## minimum log level for log capture
356 359 # errormator.logging.level = WARNING
357 360
358 361 ## send logs only from erroneous/slow requests
359 362 ## (saves API quota for intensive logging)
360 363 errormator.logging_on_error = false
361 364
362 365 ## list of additonal keywords that should be grabbed from environ object
363 366 ## can be string with comma separated list of words in lowercase
364 367 ## (by default client will always send following info:
365 368 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
366 369 ## start with HTTP* this list be extended with additional keywords here
367 370 errormator.environ_keys_whitelist =
368 371
369 372
370 373 ## list of keywords that should be blanked from request object
371 374 ## can be string with comma separated list of words in lowercase
372 375 ## (by default client will always blank keys that contain following words
373 376 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
374 377 ## this list be extended with additional keywords set here
375 378 errormator.request_keys_blacklist =
376 379
377 380
378 381 ## list of namespaces that should be ignores when gathering log entries
379 382 ## can be string with comma separated list of namespaces
380 383 ## (by default the client ignores own entries: errormator_client.client)
381 384 errormator.log_namespace_blacklist =
382 385
383 386
384 387 ################
385 388 ### [sentry] ###
386 389 ################
387 390
388 391 ## sentry is a alternative open source error aggregator
389 392 ## you must install python packages `sentry` and `raven` to enable
390 393
391 394 sentry.dsn = YOUR_DNS
392 395 sentry.servers =
393 396 sentry.name =
394 397 sentry.key =
395 398 sentry.public_key =
396 399 sentry.secret_key =
397 400 sentry.project =
398 401 sentry.site =
399 402 sentry.include_paths =
400 403 sentry.exclude_paths =
401 404
402 405
403 406 ################################################################################
404 407 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
405 408 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
406 409 ## execute malicious code after an exception is raised. ##
407 410 ################################################################################
408 411 set debug = false
409 412
410 413 ##################################
411 414 ### LOGVIEW CONFIG ###
412 415 ##################################
413 416 logview.sqlalchemy = #faa
414 417 logview.pylons.templating = #bfb
415 418 logview.pylons.util = #eee
416 419
417 420 #########################################################
418 421 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
419 422 #########################################################
420 423 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
421 424 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
422 425 sqlalchemy.db1.echo = false
423 426 sqlalchemy.db1.pool_recycle = 3600
424 427 sqlalchemy.db1.convert_unicode = true
425 428
426 429 ################################
427 430 ### LOGGING CONFIGURATION ####
428 431 ################################
429 432 [loggers]
430 433 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
431 434
432 435 [handlers]
433 436 keys = console, console_sql
434 437
435 438 [formatters]
436 439 keys = generic, color_formatter, color_formatter_sql
437 440
438 441 #############
439 442 ## LOGGERS ##
440 443 #############
441 444 [logger_root]
442 445 level = NOTSET
443 446 handlers = console
444 447
445 448 [logger_routes]
446 449 level = DEBUG
447 450 handlers =
448 451 qualname = routes.middleware
449 452 ## "level = DEBUG" logs the route matched and routing variables.
450 453 propagate = 1
451 454
452 455 [logger_beaker]
453 456 level = DEBUG
454 457 handlers =
455 458 qualname = beaker.container
456 459 propagate = 1
457 460
458 461 [logger_templates]
459 462 level = INFO
460 463 handlers =
461 464 qualname = pylons.templating
462 465 propagate = 1
463 466
464 467 [logger_rhodecode]
465 468 level = DEBUG
466 469 handlers =
467 470 qualname = rhodecode
468 471 propagate = 1
469 472
470 473 [logger_sqlalchemy]
471 474 level = INFO
472 475 handlers = console_sql
473 476 qualname = sqlalchemy.engine
474 477 propagate = 0
475 478
476 479 [logger_whoosh_indexer]
477 480 level = DEBUG
478 481 handlers =
479 482 qualname = whoosh_indexer
480 483 propagate = 1
481 484
482 485 ##############
483 486 ## HANDLERS ##
484 487 ##############
485 488
486 489 [handler_console]
487 490 class = StreamHandler
488 491 args = (sys.stderr,)
489 492 level = INFO
490 493 formatter = generic
491 494
492 495 [handler_console_sql]
493 496 class = StreamHandler
494 497 args = (sys.stderr,)
495 498 level = WARN
496 499 formatter = generic
497 500
498 501 ################
499 502 ## FORMATTERS ##
500 503 ################
501 504
502 505 [formatter_generic]
503 506 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
504 507 datefmt = %Y-%m-%d %H:%M:%S
505 508
506 509 [formatter_color_formatter]
507 510 class=rhodecode.lib.colored_formatter.ColorFormatter
508 511 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
509 512 datefmt = %Y-%m-%d %H:%M:%S
510 513
511 514 [formatter_color_formatter_sql]
512 515 class=rhodecode.lib.colored_formatter.ColorFormatterSql
513 516 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
514 517 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,524 +1,527 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # RhodeCode - Pylons environment configuration #
4 4 # #
5 5 # The %(here)s variable will be replaced with the parent directory of this file#
6 6 ################################################################################
7 7
8 8 [DEFAULT]
9 9 debug = true
10 10 pdebug = false
11 11 ################################################################################
12 12 ## Uncomment and replace with the address which should receive ##
13 13 ## any error reports after application crash ##
14 14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 15 ################################################################################
16 16 #email_to = admin@localhost
17 17 #error_email_from = paste_error@localhost
18 18 #app_email_from = rhodecode-noreply@localhost
19 19 #error_message =
20 20 #email_prefix = [RhodeCode]
21 21
22 22 #smtp_server = mail.server.com
23 23 #smtp_username =
24 24 #smtp_password =
25 25 #smtp_port =
26 26 #smtp_use_tls = false
27 27 #smtp_use_ssl = true
28 28 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
29 29 #smtp_auth =
30 30
31 31 [server:main]
32 32 ## PASTE ##
33 33 #use = egg:Paste#http
34 34 ## nr of worker threads to spawn
35 35 #threadpool_workers = 5
36 36 ## max request before thread respawn
37 37 #threadpool_max_requests = 10
38 38 ## option to use threads of process
39 39 #use_threadpool = true
40 40
41 41 ## WAITRESS ##
42 42 use = egg:waitress#main
43 43 ## number of worker threads
44 44 threads = 5
45 45 ## MAX BODY SIZE 100GB
46 46 max_request_body_size = 107374182400
47 47 ## use poll instead of select, fixes fd limits, may not work on old
48 48 ## windows systems.
49 49 #asyncore_use_poll = True
50 50
51 51 ## GUNICORN ##
52 52 #use = egg:gunicorn#main
53 53 ## number of process workers. You must set `instance_id = *` when this option
54 54 ## is set to more than one worker
55 55 #workers = 1
56 56 ## process name
57 57 #proc_name = rhodecode
58 58 ## type of worker class, one of sync, eventlet, gevent, tornado
59 59 ## recommended for bigger setup is using of of other than sync one
60 60 #worker_class = sync
61 61 #max_requests = 5
62 62 ## ammount of time a worker can handle request before it get's killed and
63 63 ## restarted
64 64 #timeout = 3600
65 65
66 66 ## COMMON ##
67 67 host = 127.0.0.1
68 68 port = 5000
69 69
70 70 ## prefix middleware for rc
71 71 #[filter:proxy-prefix]
72 72 #use = egg:PasteDeploy#prefix
73 73 #prefix = /<your-prefix>
74 74
75 75 [app:main]
76 76 use = egg:rhodecode
77 77 ## enable proxy prefix middleware
78 78 #filter-with = proxy-prefix
79 79
80 80 full_stack = true
81 81 static_files = true
82 82 ## Optional Languages
83 83 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
84 84 lang = en
85 85 cache_dir = %(here)s/data
86 86 index_dir = %(here)s/data/index
87 87
88 88 ## perform a full repository scan on each server start, this should be
89 89 ## set to false after first startup, to allow faster server restarts.
90 90 initial_repo_scan = true
91 91
92 92 ## uncomment and set this path to use archive download cache
93 93 #archive_cache_dir = /tmp/tarballcache
94 94
95 95 ## change this to unique ID for security
96 96 app_instance_uuid = ${app_instance_uuid}
97 97
98 98 ## cut off limit for large diffs (size in bytes)
99 99 cut_off_limit = 256000
100 100
101 101 ## use cache version of scm repo everywhere
102 102 vcs_full_cache = true
103 103
104 104 ## force https in RhodeCode, fixes https redirects, assumes it's always https
105 105 force_https = false
106 106
107 107 ## use Strict-Transport-Security headers
108 108 use_htsts = false
109 109
110 110 ## number of commits stats will parse on each iteration
111 111 commit_parse_limit = 25
112 112
113 113 ## use gravatar service to display avatars
114 114 use_gravatar = true
115 115
116 116 ## path to git executable
117 117 git_path = git
118 118
119 119 ## git rev filter option, --all is the default filter, if you need to
120 120 ## hide all refs in changelog switch this to --branches --tags
121 121 git_rev_filter=--all
122 122
123 123 ## RSS feed options
124 124 rss_cut_off_limit = 256000
125 125 rss_items_per_page = 10
126 126 rss_include_diff = false
127 127
128 128 ## options for showing and identifying changesets
129 129 show_sha_length = 12
130 130 show_revision_number = true
131 131
132 132 ## gist URL alias, used to create nicer urls for gist. This should be an
133 133 ## url that does rewrites to _admin/gists/<gistid>.
134 134 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
135 135 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
136 136 gist_alias_url =
137 137
138 138 ## white list of API enabled controllers. This allows to add list of
139 139 ## controllers to which access will be enabled by api_key. eg: to enable
140 140 ## api access to raw_files put `FilesController:raw`, to enable access to patches
141 141 ## add `ChangesetController:changeset_patch`. This list should be "," separated
142 142 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
143 143 api_access_controllers_whitelist =
144 144
145 145 ## alternative_gravatar_url allows you to use your own avatar server application
146 146 ## the following parts of the URL will be replaced
147 147 ## {email} user email
148 148 ## {md5email} md5 hash of the user email (like at gravatar.com)
149 149 ## {size} size of the image that is expected from the server application
150 150 ## {scheme} http/https from RhodeCode server
151 151 ## {netloc} network location from RhodeCode server
152 152 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
153 153 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
154 154
155 155
156 156 ## container auth options
157 157 container_auth_enabled = false
158 158 proxypass_auth_enabled = false
159 159
160 160 ## default encoding used to convert from and to unicode
161 161 ## can be also a comma seperated list of encoding in case of mixed encodings
162 162 default_encoding = utf8
163 163
164 164 ## overwrite schema of clone url
165 165 ## available vars:
166 166 ## scheme - http/https
167 167 ## user - current user
168 168 ## pass - password
169 169 ## netloc - network location
170 170 ## path - usually repo_name
171 171
172 172 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
173 173
174 ## issue tracker for RhodeCode (leave blank to disable, absent for default)
175 #bugtracker = http://bitbucket.org/marcinkuzminski/rhodecode/issues
176
174 177 ## issue tracking mapping for commits messages
175 178 ## comment out issue_pat, issue_server, issue_prefix to enable
176 179
177 180 ## pattern to get the issues from commit messages
178 181 ## default one used here is #<numbers> with a regex passive group for `#`
179 182 ## {id} will be all groups matched from this pattern
180 183
181 184 issue_pat = (?:\s*#)(\d+)
182 185
183 186 ## server url to the issue, each {id} will be replaced with match
184 187 ## fetched from the regex and {repo} is replaced with full repository name
185 188 ## including groups {repo_name} is replaced with just name of repo
186 189
187 190 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
188 191
189 192 ## prefix to add to link to indicate it's an url
190 193 ## #314 will be replaced by <issue_prefix><id>
191 194
192 195 issue_prefix = #
193 196
194 197 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
195 198 ## multiple patterns, to other issues server, wiki or others
196 199 ## below an example how to create a wiki pattern
197 200 # #wiki-some-id -> https://mywiki.com/some-id
198 201
199 202 #issue_pat_wiki = (?:wiki-)(.+)
200 203 #issue_server_link_wiki = https://mywiki.com/{id}
201 204 #issue_prefix_wiki = WIKI-
202 205
203 206
204 207 ## instance-id prefix
205 208 ## a prefix key for this instance used for cache invalidation when running
206 209 ## multiple instances of rhodecode, make sure it's globally unique for
207 210 ## all running rhodecode instances. Leave empty if you don't use it
208 211 instance_id =
209 212
210 213 ## alternative return HTTP header for failed authentication. Default HTTP
211 214 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
212 215 ## handling that. Set this variable to 403 to return HTTPForbidden
213 216 auth_ret_code =
214 217
215 218 ## locking return code. When repository is locked return this HTTP code. 2XX
216 219 ## codes don't break the transactions while 4XX codes do
217 220 lock_ret_code = 423
218 221
219 222 allow_repo_location_change = True
220 223
221 224 ####################################
222 225 ### CELERY CONFIG ####
223 226 ####################################
224 227 use_celery = false
225 228 broker.host = localhost
226 229 broker.vhost = rabbitmqhost
227 230 broker.port = 5672
228 231 broker.user = rabbitmq
229 232 broker.password = qweqwe
230 233
231 234 celery.imports = rhodecode.lib.celerylib.tasks
232 235
233 236 celery.result.backend = amqp
234 237 celery.result.dburi = amqp://
235 238 celery.result.serialier = json
236 239
237 240 #celery.send.task.error.emails = true
238 241 #celery.amqp.task.result.expires = 18000
239 242
240 243 celeryd.concurrency = 2
241 244 #celeryd.log.file = celeryd.log
242 245 celeryd.log.level = debug
243 246 celeryd.max.tasks.per.child = 1
244 247
245 248 ## tasks will never be sent to the queue, but executed locally instead.
246 249 celery.always.eager = false
247 250
248 251 ####################################
249 252 ### BEAKER CACHE ####
250 253 ####################################
251 254 beaker.cache.data_dir=%(here)s/data/cache/data
252 255 beaker.cache.lock_dir=%(here)s/data/cache/lock
253 256
254 257 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
255 258
256 259 beaker.cache.super_short_term.type=memory
257 260 beaker.cache.super_short_term.expire=10
258 261 beaker.cache.super_short_term.key_length = 256
259 262
260 263 beaker.cache.short_term.type=memory
261 264 beaker.cache.short_term.expire=60
262 265 beaker.cache.short_term.key_length = 256
263 266
264 267 beaker.cache.long_term.type=memory
265 268 beaker.cache.long_term.expire=36000
266 269 beaker.cache.long_term.key_length = 256
267 270
268 271 beaker.cache.sql_cache_short.type=memory
269 272 beaker.cache.sql_cache_short.expire=10
270 273 beaker.cache.sql_cache_short.key_length = 256
271 274
272 275 beaker.cache.sql_cache_med.type=memory
273 276 beaker.cache.sql_cache_med.expire=360
274 277 beaker.cache.sql_cache_med.key_length = 256
275 278
276 279 beaker.cache.sql_cache_long.type=file
277 280 beaker.cache.sql_cache_long.expire=3600
278 281 beaker.cache.sql_cache_long.key_length = 256
279 282
280 283 ####################################
281 284 ### BEAKER SESSION ####
282 285 ####################################
283 286 ## Type of storage used for the session, current types are
284 287 ## dbm, file, memcached, database, and memory.
285 288 ## The storage uses the Container API
286 289 ## that is also used by the cache system.
287 290
288 291 ## db session ##
289 292 #beaker.session.type = ext:database
290 293 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
291 294 #beaker.session.table_name = db_session
292 295
293 296 ## encrypted cookie client side session, good for many instances ##
294 297 #beaker.session.type = cookie
295 298
296 299 ## file based cookies (default) ##
297 300 #beaker.session.type = file
298 301
299 302 beaker.session.key = rhodecode
300 303 beaker.session.secret = ${app_instance_uuid}
301 304
302 305 ## Secure encrypted cookie. Requires AES and AES python libraries
303 306 ## you must disable beaker.session.secret to use this
304 307 #beaker.session.encrypt_key = <key_for_encryption>
305 308 #beaker.session.validate_key = <validation_key>
306 309
307 310 ## sets session as invalid if it haven't been accessed for given amount of time
308 311 beaker.session.timeout = 2592000
309 312 beaker.session.httponly = true
310 313 #beaker.session.cookie_path = /<your-prefix>
311 314
312 315 ## uncomment for https secure cookie
313 316 beaker.session.secure = false
314 317
315 318 ## auto save the session to not to use .save()
316 319 beaker.session.auto = False
317 320
318 321 ## default cookie expiration time in seconds `true` expire at browser close ##
319 322 #beaker.session.cookie_expires = 3600
320 323
321 324
322 325 ############################
323 326 ## ERROR HANDLING SYSTEMS ##
324 327 ############################
325 328
326 329 ####################
327 330 ### [errormator] ###
328 331 ####################
329 332
330 333 ## Errormator is tailored to work with RhodeCode, see
331 334 ## http://errormator.com for details how to obtain an account
332 335 ## you must install python package `errormator_client` to make it work
333 336
334 337 ## errormator enabled
335 338 errormator = false
336 339
337 340 errormator.server_url = https://api.errormator.com
338 341 errormator.api_key = YOUR_API_KEY
339 342
340 343 ## TWEAK AMOUNT OF INFO SENT HERE
341 344
342 345 ## enables 404 error logging (default False)
343 346 errormator.report_404 = false
344 347
345 348 ## time in seconds after request is considered being slow (default 1)
346 349 errormator.slow_request_time = 1
347 350
348 351 ## record slow requests in application
349 352 ## (needs to be enabled for slow datastore recording and time tracking)
350 353 errormator.slow_requests = true
351 354
352 355 ## enable hooking to application loggers
353 356 # errormator.logging = true
354 357
355 358 ## minimum log level for log capture
356 359 # errormator.logging.level = WARNING
357 360
358 361 ## send logs only from erroneous/slow requests
359 362 ## (saves API quota for intensive logging)
360 363 errormator.logging_on_error = false
361 364
362 365 ## list of additonal keywords that should be grabbed from environ object
363 366 ## can be string with comma separated list of words in lowercase
364 367 ## (by default client will always send following info:
365 368 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
366 369 ## start with HTTP* this list be extended with additional keywords here
367 370 errormator.environ_keys_whitelist =
368 371
369 372
370 373 ## list of keywords that should be blanked from request object
371 374 ## can be string with comma separated list of words in lowercase
372 375 ## (by default client will always blank keys that contain following words
373 376 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
374 377 ## this list be extended with additional keywords set here
375 378 errormator.request_keys_blacklist =
376 379
377 380
378 381 ## list of namespaces that should be ignores when gathering log entries
379 382 ## can be string with comma separated list of namespaces
380 383 ## (by default the client ignores own entries: errormator_client.client)
381 384 errormator.log_namespace_blacklist =
382 385
383 386
384 387 ################
385 388 ### [sentry] ###
386 389 ################
387 390
388 391 ## sentry is a alternative open source error aggregator
389 392 ## you must install python packages `sentry` and `raven` to enable
390 393
391 394 sentry.dsn = YOUR_DNS
392 395 sentry.servers =
393 396 sentry.name =
394 397 sentry.key =
395 398 sentry.public_key =
396 399 sentry.secret_key =
397 400 sentry.project =
398 401 sentry.site =
399 402 sentry.include_paths =
400 403 sentry.exclude_paths =
401 404
402 405
403 406 ################################################################################
404 407 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
405 408 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
406 409 ## execute malicious code after an exception is raised. ##
407 410 ################################################################################
408 411 set debug = false
409 412
410 413 ##################################
411 414 ### LOGVIEW CONFIG ###
412 415 ##################################
413 416 logview.sqlalchemy = #faa
414 417 logview.pylons.templating = #bfb
415 418 logview.pylons.util = #eee
416 419
417 420 #########################################################
418 421 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
419 422 #########################################################
420 423
421 424 # SQLITE [default]
422 425 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
423 426
424 427 # POSTGRESQL
425 428 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
426 429
427 430 # MySQL
428 431 # sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
429 432
430 433 # see sqlalchemy docs for others
431 434
432 435 sqlalchemy.db1.echo = false
433 436 sqlalchemy.db1.pool_recycle = 3600
434 437 sqlalchemy.db1.convert_unicode = true
435 438
436 439 ################################
437 440 ### LOGGING CONFIGURATION ####
438 441 ################################
439 442 [loggers]
440 443 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
441 444
442 445 [handlers]
443 446 keys = console, console_sql
444 447
445 448 [formatters]
446 449 keys = generic, color_formatter, color_formatter_sql
447 450
448 451 #############
449 452 ## LOGGERS ##
450 453 #############
451 454 [logger_root]
452 455 level = NOTSET
453 456 handlers = console
454 457
455 458 [logger_routes]
456 459 level = DEBUG
457 460 handlers =
458 461 qualname = routes.middleware
459 462 ## "level = DEBUG" logs the route matched and routing variables.
460 463 propagate = 1
461 464
462 465 [logger_beaker]
463 466 level = DEBUG
464 467 handlers =
465 468 qualname = beaker.container
466 469 propagate = 1
467 470
468 471 [logger_templates]
469 472 level = INFO
470 473 handlers =
471 474 qualname = pylons.templating
472 475 propagate = 1
473 476
474 477 [logger_rhodecode]
475 478 level = DEBUG
476 479 handlers =
477 480 qualname = rhodecode
478 481 propagate = 1
479 482
480 483 [logger_sqlalchemy]
481 484 level = INFO
482 485 handlers = console_sql
483 486 qualname = sqlalchemy.engine
484 487 propagate = 0
485 488
486 489 [logger_whoosh_indexer]
487 490 level = DEBUG
488 491 handlers =
489 492 qualname = whoosh_indexer
490 493 propagate = 1
491 494
492 495 ##############
493 496 ## HANDLERS ##
494 497 ##############
495 498
496 499 [handler_console]
497 500 class = StreamHandler
498 501 args = (sys.stderr,)
499 502 level = INFO
500 503 formatter = generic
501 504
502 505 [handler_console_sql]
503 506 class = StreamHandler
504 507 args = (sys.stderr,)
505 508 level = WARN
506 509 formatter = generic
507 510
508 511 ################
509 512 ## FORMATTERS ##
510 513 ################
511 514
512 515 [formatter_generic]
513 516 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
514 517 datefmt = %Y-%m-%d %H:%M:%S
515 518
516 519 [formatter_color_formatter]
517 520 class=rhodecode.lib.colored_formatter.ColorFormatter
518 521 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
519 522 datefmt = %Y-%m-%d %H:%M:%S
520 523
521 524 [formatter_color_formatter_sql]
522 525 class=rhodecode.lib.colored_formatter.ColorFormatterSql
523 526 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
524 527 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,708 +1,705 b''
1 1 """
2 2 Routes configuration
3 3
4 4 The more specific and detailed routes should be defined first so they
5 5 may take precedent over the more generic routes. For more information
6 6 refer to the routes manual at http://routes.groovie.org/docs/
7 7 """
8 8 from __future__ import with_statement
9 9 from routes import Mapper
10 10
11 11 # prefix for non repository related links needs to be prefixed with `/`
12 12 ADMIN_PREFIX = '/_admin'
13 13
14 14
15 15 def make_map(config):
16 16 """Create, configure and return the routes Mapper"""
17 17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 18 always_scan=config['debug'])
19 19 rmap.minimization = False
20 20 rmap.explicit = False
21 21
22 22 from rhodecode.lib.utils import is_valid_repo
23 23 from rhodecode.lib.utils import is_valid_repos_group
24 24
25 25 def check_repo(environ, match_dict):
26 26 """
27 27 check for valid repository for proper 404 handling
28 28
29 29 :param environ:
30 30 :param match_dict:
31 31 """
32 32 from rhodecode.model.db import Repository
33 33 repo_name = match_dict.get('repo_name')
34 34
35 35 if match_dict.get('f_path'):
36 36 #fix for multiple initial slashes that causes errors
37 37 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
38 38
39 39 try:
40 40 by_id = repo_name.split('_')
41 41 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
42 42 repo_name = Repository.get(by_id[1]).repo_name
43 43 match_dict['repo_name'] = repo_name
44 44 except Exception:
45 45 pass
46 46
47 47 return is_valid_repo(repo_name, config['base_path'])
48 48
49 49 def check_group(environ, match_dict):
50 50 """
51 51 check for valid repository group for proper 404 handling
52 52
53 53 :param environ:
54 54 :param match_dict:
55 55 """
56 56 repos_group_name = match_dict.get('group_name')
57 57 return is_valid_repos_group(repos_group_name, config['base_path'])
58 58
59 59 def check_group_skip_path(environ, match_dict):
60 60 """
61 61 check for valid repository group for proper 404 handling, but skips
62 62 verification of existing path
63 63
64 64 :param environ:
65 65 :param match_dict:
66 66 """
67 67 repos_group_name = match_dict.get('group_name')
68 68 return is_valid_repos_group(repos_group_name, config['base_path'],
69 69 skip_path_check=True)
70 70
71 71 def check_user_group(environ, match_dict):
72 72 """
73 73 check for valid user group for proper 404 handling
74 74
75 75 :param environ:
76 76 :param match_dict:
77 77 """
78 78 return True
79 79
80 80 def check_int(environ, match_dict):
81 81 return match_dict.get('id').isdigit()
82 82
83 83 # The ErrorController route (handles 404/500 error pages); it should
84 84 # likely stay at the top, ensuring it can always be resolved
85 85 rmap.connect('/error/{action}', controller='error')
86 86 rmap.connect('/error/{action}/{id}', controller='error')
87 87
88 88 #==========================================================================
89 89 # CUSTOM ROUTES HERE
90 90 #==========================================================================
91 91
92 92 #MAIN PAGE
93 93 rmap.connect('home', '/', controller='home', action='index')
94 94 rmap.connect('repo_switcher', '/repos', controller='home',
95 95 action='repo_switcher')
96 96 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
97 97 controller='home', action='branch_tag_switcher')
98 rmap.connect('bugtracker',
99 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
100 _static=True)
101 98 rmap.connect('rst_help',
102 99 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
103 100 _static=True)
104 101 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
105 102
106 103 #ADMIN REPOSITORY REST ROUTES
107 104 with rmap.submapper(path_prefix=ADMIN_PREFIX,
108 105 controller='admin/repos') as m:
109 106 m.connect("repos", "/repos",
110 107 action="create", conditions=dict(method=["POST"]))
111 108 m.connect("repos", "/repos",
112 109 action="index", conditions=dict(method=["GET"]))
113 110 m.connect("formatted_repos", "/repos.{format}",
114 111 action="index",
115 112 conditions=dict(method=["GET"]))
116 113 m.connect("new_repo", "/create_repository",
117 114 action="create_repository", conditions=dict(method=["GET"]))
118 115 m.connect("/repos/{repo_name:.*?}",
119 116 action="update", conditions=dict(method=["PUT"],
120 117 function=check_repo))
121 118 m.connect("/repos/{repo_name:.*?}",
122 119 action="delete", conditions=dict(method=["DELETE"],
123 120 function=check_repo))
124 121 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
125 122 action="edit", conditions=dict(method=["GET"],
126 123 function=check_repo))
127 124 m.connect("repo", "/repos/{repo_name:.*?}",
128 125 action="show", conditions=dict(method=["GET"],
129 126 function=check_repo))
130 127 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
131 128 action="show", conditions=dict(method=["GET"],
132 129 function=check_repo))
133 130 #add repo perm member
134 131 m.connect('set_repo_perm_member',
135 132 "/repos/{repo_name:.*?}/grant_perm",
136 133 action="set_repo_perm_member",
137 134 conditions=dict(method=["POST"], function=check_repo))
138 135
139 136 #ajax delete repo perm user
140 137 m.connect('delete_repo_perm_member',
141 138 "/repos/{repo_name:.*?}/revoke_perm",
142 139 action="delete_repo_perm_member",
143 140 conditions=dict(method=["DELETE"], function=check_repo))
144 141
145 142 #settings actions
146 143 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
147 144 action="repo_stats", conditions=dict(method=["DELETE"],
148 145 function=check_repo))
149 146 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
150 147 action="repo_cache", conditions=dict(method=["DELETE"],
151 148 function=check_repo))
152 149 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
153 150 action="repo_public_journal", conditions=dict(method=["PUT"],
154 151 function=check_repo))
155 152 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
156 153 action="repo_pull", conditions=dict(method=["PUT"],
157 154 function=check_repo))
158 155 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
159 156 action="repo_as_fork", conditions=dict(method=["PUT"],
160 157 function=check_repo))
161 158 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
162 159 action="repo_locking", conditions=dict(method=["PUT"],
163 160 function=check_repo))
164 161 m.connect('toggle_locking', "/locking_toggle/{repo_name:.*?}",
165 162 action="toggle_locking", conditions=dict(method=["GET"],
166 163 function=check_repo))
167 164
168 165 #repo fields
169 166 m.connect('create_repo_fields', "/repo_fields/{repo_name:.*?}/new",
170 167 action="create_repo_field", conditions=dict(method=["PUT"],
171 168 function=check_repo))
172 169
173 170 m.connect('delete_repo_fields', "/repo_fields/{repo_name:.*?}/{field_id}",
174 171 action="delete_repo_field", conditions=dict(method=["DELETE"],
175 172 function=check_repo))
176 173
177 174 with rmap.submapper(path_prefix=ADMIN_PREFIX,
178 175 controller='admin/repos_groups') as m:
179 176 m.connect("repos_groups", "/repos_groups",
180 177 action="create", conditions=dict(method=["POST"]))
181 178 m.connect("repos_groups", "/repos_groups",
182 179 action="index", conditions=dict(method=["GET"]))
183 180 m.connect("formatted_repos_groups", "/repos_groups.{format}",
184 181 action="index", conditions=dict(method=["GET"]))
185 182 m.connect("new_repos_group", "/repos_groups/new",
186 183 action="new", conditions=dict(method=["GET"]))
187 184 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
188 185 action="new", conditions=dict(method=["GET"]))
189 186 m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
190 187 action="update", conditions=dict(method=["PUT"],
191 188 function=check_group))
192 189 #add repo group perm member
193 190 m.connect('set_repo_group_perm_member',
194 191 "/repos_groups/{group_name:.*?}/grant_perm",
195 192 action="set_repo_group_perm_member",
196 193 conditions=dict(method=["POST"], function=check_group))
197 194
198 195 #ajax delete repo group perm
199 196 m.connect('delete_repo_group_perm_member',
200 197 "/repos_groups/{group_name:.*?}/revoke_perm",
201 198 action="delete_repo_group_perm_member",
202 199 conditions=dict(method=["DELETE"], function=check_group))
203 200
204 201 m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
205 202 action="delete", conditions=dict(method=["DELETE"],
206 203 function=check_group_skip_path))
207 204 m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
208 205 action="edit", conditions=dict(method=["GET"],
209 206 function=check_group))
210 207 m.connect("formatted_edit_repos_group",
211 208 "/repos_groups/{group_name:.*?}.{format}/edit",
212 209 action="edit", conditions=dict(method=["GET"],
213 210 function=check_group))
214 211 m.connect("repos_group", "/repos_groups/{group_name:.*?}",
215 212 action="show", conditions=dict(method=["GET"],
216 213 function=check_group))
217 214 m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
218 215 action="show", conditions=dict(method=["GET"],
219 216 function=check_group))
220 217
221 218 #ADMIN USER REST ROUTES
222 219 with rmap.submapper(path_prefix=ADMIN_PREFIX,
223 220 controller='admin/users') as m:
224 221 m.connect("users", "/users",
225 222 action="create", conditions=dict(method=["POST"]))
226 223 m.connect("users", "/users",
227 224 action="index", conditions=dict(method=["GET"]))
228 225 m.connect("formatted_users", "/users.{format}",
229 226 action="index", conditions=dict(method=["GET"]))
230 227 m.connect("new_user", "/users/new",
231 228 action="new", conditions=dict(method=["GET"]))
232 229 m.connect("formatted_new_user", "/users/new.{format}",
233 230 action="new", conditions=dict(method=["GET"]))
234 231 m.connect("update_user", "/users/{id}",
235 232 action="update", conditions=dict(method=["PUT"]))
236 233 m.connect("delete_user", "/users/{id}",
237 234 action="delete", conditions=dict(method=["DELETE"]))
238 235 m.connect("edit_user", "/users/{id}/edit",
239 236 action="edit", conditions=dict(method=["GET"]))
240 237 m.connect("formatted_edit_user",
241 238 "/users/{id}.{format}/edit",
242 239 action="edit", conditions=dict(method=["GET"]))
243 240 m.connect("user", "/users/{id}",
244 241 action="show", conditions=dict(method=["GET"]))
245 242 m.connect("formatted_user", "/users/{id}.{format}",
246 243 action="show", conditions=dict(method=["GET"]))
247 244
248 245 #EXTRAS USER ROUTES
249 246 m.connect("user_perm", "/users_perm/{id}",
250 247 action="update_perm", conditions=dict(method=["PUT"]))
251 248 m.connect("user_emails", "/users_emails/{id}",
252 249 action="add_email", conditions=dict(method=["PUT"]))
253 250 m.connect("user_emails_delete", "/users_emails/{id}",
254 251 action="delete_email", conditions=dict(method=["DELETE"]))
255 252 m.connect("user_ips", "/users_ips/{id}",
256 253 action="add_ip", conditions=dict(method=["PUT"]))
257 254 m.connect("user_ips_delete", "/users_ips/{id}",
258 255 action="delete_ip", conditions=dict(method=["DELETE"]))
259 256
260 257 #ADMIN USER GROUPS REST ROUTES
261 258 with rmap.submapper(path_prefix=ADMIN_PREFIX,
262 259 controller='admin/users_groups') as m:
263 260 m.connect("users_groups", "/users_groups",
264 261 action="create", conditions=dict(method=["POST"]))
265 262 m.connect("users_groups", "/users_groups",
266 263 action="index", conditions=dict(method=["GET"]))
267 264 m.connect("formatted_users_groups", "/users_groups.{format}",
268 265 action="index", conditions=dict(method=["GET"]))
269 266 m.connect("new_users_group", "/users_groups/new",
270 267 action="new", conditions=dict(method=["GET"]))
271 268 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
272 269 action="new", conditions=dict(method=["GET"]))
273 270 m.connect("update_users_group", "/users_groups/{id}",
274 271 action="update", conditions=dict(method=["PUT"]))
275 272 m.connect("delete_users_group", "/users_groups/{id}",
276 273 action="delete", conditions=dict(method=["DELETE"]))
277 274 m.connect("edit_users_group", "/users_groups/{id}/edit",
278 275 action="edit", conditions=dict(method=["GET"]),
279 276 function=check_user_group)
280 277 m.connect("formatted_edit_users_group",
281 278 "/users_groups/{id}.{format}/edit",
282 279 action="edit", conditions=dict(method=["GET"]))
283 280 m.connect("users_group", "/users_groups/{id}",
284 281 action="show", conditions=dict(method=["GET"]))
285 282 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
286 283 action="show", conditions=dict(method=["GET"]))
287 284
288 285 #EXTRAS USER ROUTES
289 286 # update
290 287 m.connect("users_group_perm", "/users_groups/{id}/update_global_perm",
291 288 action="update_perm", conditions=dict(method=["PUT"]))
292 289
293 290 #add user group perm member
294 291 m.connect('set_user_group_perm_member', "/users_groups/{id}/grant_perm",
295 292 action="set_user_group_perm_member",
296 293 conditions=dict(method=["POST"]))
297 294
298 295 #ajax delete user group perm
299 296 m.connect('delete_user_group_perm_member', "/users_groups/{id}/revoke_perm",
300 297 action="delete_user_group_perm_member",
301 298 conditions=dict(method=["DELETE"]))
302 299
303 300 #ADMIN GROUP REST ROUTES
304 301 rmap.resource('group', 'groups',
305 302 controller='admin/groups', path_prefix=ADMIN_PREFIX)
306 303
307 304 #ADMIN PERMISSIONS REST ROUTES
308 305 rmap.resource('permission', 'permissions',
309 306 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
310 307
311 308 #ADMIN DEFAULTS REST ROUTES
312 309 rmap.resource('default', 'defaults',
313 310 controller='admin/defaults', path_prefix=ADMIN_PREFIX)
314 311
315 312 ##ADMIN LDAP SETTINGS
316 313 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
317 314 controller='admin/ldap_settings', action='ldap_settings',
318 315 conditions=dict(method=["POST"]))
319 316
320 317 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
321 318 controller='admin/ldap_settings')
322 319
323 320 #ADMIN SETTINGS REST ROUTES
324 321 with rmap.submapper(path_prefix=ADMIN_PREFIX,
325 322 controller='admin/settings') as m:
326 323 m.connect("admin_settings", "/settings",
327 324 action="create", conditions=dict(method=["POST"]))
328 325 m.connect("admin_settings", "/settings",
329 326 action="index", conditions=dict(method=["GET"]))
330 327 m.connect("formatted_admin_settings", "/settings.{format}",
331 328 action="index", conditions=dict(method=["GET"]))
332 329 m.connect("admin_new_setting", "/settings/new",
333 330 action="new", conditions=dict(method=["GET"]))
334 331 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
335 332 action="new", conditions=dict(method=["GET"]))
336 333 m.connect("/settings/{setting_id}",
337 334 action="update", conditions=dict(method=["PUT"]))
338 335 m.connect("/settings/{setting_id}",
339 336 action="delete", conditions=dict(method=["DELETE"]))
340 337 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
341 338 action="edit", conditions=dict(method=["GET"]))
342 339 m.connect("formatted_admin_edit_setting",
343 340 "/settings/{setting_id}.{format}/edit",
344 341 action="edit", conditions=dict(method=["GET"]))
345 342 m.connect("admin_setting", "/settings/{setting_id}",
346 343 action="show", conditions=dict(method=["GET"]))
347 344 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
348 345 action="show", conditions=dict(method=["GET"]))
349 346 m.connect("admin_settings_my_account", "/my_account",
350 347 action="my_account", conditions=dict(method=["GET"]))
351 348 m.connect("admin_settings_my_account_update", "/my_account_update",
352 349 action="my_account_update", conditions=dict(method=["PUT"]))
353 350 m.connect("admin_settings_my_repos", "/my_account/repos",
354 351 action="my_account_my_repos", conditions=dict(method=["GET"]))
355 352 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
356 353 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
357 354
358 355 #NOTIFICATION REST ROUTES
359 356 with rmap.submapper(path_prefix=ADMIN_PREFIX,
360 357 controller='admin/notifications') as m:
361 358 m.connect("notifications", "/notifications",
362 359 action="create", conditions=dict(method=["POST"]))
363 360 m.connect("notifications", "/notifications",
364 361 action="index", conditions=dict(method=["GET"]))
365 362 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
366 363 action="mark_all_read", conditions=dict(method=["GET"]))
367 364 m.connect("formatted_notifications", "/notifications.{format}",
368 365 action="index", conditions=dict(method=["GET"]))
369 366 m.connect("new_notification", "/notifications/new",
370 367 action="new", conditions=dict(method=["GET"]))
371 368 m.connect("formatted_new_notification", "/notifications/new.{format}",
372 369 action="new", conditions=dict(method=["GET"]))
373 370 m.connect("/notifications/{notification_id}",
374 371 action="update", conditions=dict(method=["PUT"]))
375 372 m.connect("/notifications/{notification_id}",
376 373 action="delete", conditions=dict(method=["DELETE"]))
377 374 m.connect("edit_notification", "/notifications/{notification_id}/edit",
378 375 action="edit", conditions=dict(method=["GET"]))
379 376 m.connect("formatted_edit_notification",
380 377 "/notifications/{notification_id}.{format}/edit",
381 378 action="edit", conditions=dict(method=["GET"]))
382 379 m.connect("notification", "/notifications/{notification_id}",
383 380 action="show", conditions=dict(method=["GET"]))
384 381 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
385 382 action="show", conditions=dict(method=["GET"]))
386 383
387 384 #ADMIN GIST
388 385 with rmap.submapper(path_prefix=ADMIN_PREFIX,
389 386 controller='admin/gists') as m:
390 387 m.connect("gists", "/gists",
391 388 action="create", conditions=dict(method=["POST"]))
392 389 m.connect("gists", "/gists",
393 390 action="index", conditions=dict(method=["GET"]))
394 391 m.connect("new_gist", "/gists/new",
395 392 action="new", conditions=dict(method=["GET"]))
396 393 m.connect("formatted_new_gist", "/gists/new.{format}",
397 394 action="new", conditions=dict(method=["GET"]))
398 395 m.connect("formatted_gists", "/gists.{format}",
399 396 action="index", conditions=dict(method=["GET"]))
400 397 m.connect("/gists/{gist_id}",
401 398 action="update", conditions=dict(method=["PUT"]))
402 399 m.connect("/gists/{gist_id}",
403 400 action="delete", conditions=dict(method=["DELETE"]))
404 401 m.connect("edit_gist", "/gists/{gist_id}/edit",
405 402 action="edit", conditions=dict(method=["GET"]))
406 403 m.connect("formatted_edit_gist",
407 404 "/gists/{gist_id}/{format}/edit",
408 405 action="edit", conditions=dict(method=["GET"]))
409 406 m.connect("gist", "/gists/{gist_id}",
410 407 action="show", conditions=dict(method=["GET"]))
411 408 m.connect("formatted_gist", "/gists/{gist_id}/{format}",
412 409 action="show", conditions=dict(method=["GET"]))
413 410 m.connect("formatted_gist_file", "/gists/{gist_id}/{format}/{revision}/{f_path:.*}",
414 411 action="show", conditions=dict(method=["GET"]))
415 412
416 413 #ADMIN MAIN PAGES
417 414 with rmap.submapper(path_prefix=ADMIN_PREFIX,
418 415 controller='admin/admin') as m:
419 416 m.connect('admin_home', '', action='index')
420 417 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
421 418 action='add_repo')
422 419 #==========================================================================
423 420 # API V2
424 421 #==========================================================================
425 422 with rmap.submapper(path_prefix=ADMIN_PREFIX,
426 423 controller='api/api') as m:
427 424 m.connect('api', '/api')
428 425
429 426 #USER JOURNAL
430 427 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
431 428 controller='journal', action='index')
432 429 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
433 430 controller='journal', action='journal_rss')
434 431 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
435 432 controller='journal', action='journal_atom')
436 433
437 434 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
438 435 controller='journal', action="public_journal")
439 436
440 437 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
441 438 controller='journal', action="public_journal_rss")
442 439
443 440 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
444 441 controller='journal', action="public_journal_rss")
445 442
446 443 rmap.connect('public_journal_atom',
447 444 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
448 445 action="public_journal_atom")
449 446
450 447 rmap.connect('public_journal_atom_old',
451 448 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
452 449 action="public_journal_atom")
453 450
454 451 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
455 452 controller='journal', action='toggle_following',
456 453 conditions=dict(method=["POST"]))
457 454
458 455 #SEARCH
459 456 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
460 457 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
461 458 controller='search',
462 459 conditions=dict(function=check_repo))
463 460 rmap.connect('search_repo', '/{repo_name:.*?}/search',
464 461 controller='search',
465 462 conditions=dict(function=check_repo),
466 463 )
467 464
468 465 #LOGIN/LOGOUT/REGISTER/SIGN IN
469 466 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
470 467 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
471 468 action='logout')
472 469
473 470 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
474 471 action='register')
475 472
476 473 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
477 474 controller='login', action='password_reset')
478 475
479 476 rmap.connect('reset_password_confirmation',
480 477 '%s/password_reset_confirmation' % ADMIN_PREFIX,
481 478 controller='login', action='password_reset_confirmation')
482 479
483 480 #FEEDS
484 481 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
485 482 controller='feed', action='rss',
486 483 conditions=dict(function=check_repo))
487 484
488 485 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
489 486 controller='feed', action='atom',
490 487 conditions=dict(function=check_repo))
491 488
492 489 #==========================================================================
493 490 # REPOSITORY ROUTES
494 491 #==========================================================================
495 492 rmap.connect('summary_home', '/{repo_name:.*?}',
496 493 controller='summary',
497 494 conditions=dict(function=check_repo))
498 495
499 496 rmap.connect('repo_size', '/{repo_name:.*?}/repo_size',
500 497 controller='summary', action='repo_size',
501 498 conditions=dict(function=check_repo))
502 499
503 500 rmap.connect('repos_group_home', '/{group_name:.*}',
504 501 controller='admin/repos_groups', action="show_by_name",
505 502 conditions=dict(function=check_group))
506 503
507 504 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
508 505 controller='changeset', revision='tip',
509 506 conditions=dict(function=check_repo))
510 507
511 508 # no longer user, but kept for routes to work
512 509 rmap.connect("_edit_repo", "/{repo_name:.*?}/edit",
513 510 controller='admin/repos', action="edit",
514 511 conditions=dict(method=["GET"], function=check_repo)
515 512 )
516 513
517 514 rmap.connect("edit_repo", "/{repo_name:.*?}/settings",
518 515 controller='admin/repos', action="edit",
519 516 conditions=dict(method=["GET"], function=check_repo)
520 517 )
521 518
522 519 #still working url for backward compat.
523 520 rmap.connect('raw_changeset_home_depraced',
524 521 '/{repo_name:.*?}/raw-changeset/{revision}',
525 522 controller='changeset', action='changeset_raw',
526 523 revision='tip', conditions=dict(function=check_repo))
527 524
528 525 ## new URLs
529 526 rmap.connect('changeset_raw_home',
530 527 '/{repo_name:.*?}/changeset-diff/{revision}',
531 528 controller='changeset', action='changeset_raw',
532 529 revision='tip', conditions=dict(function=check_repo))
533 530
534 531 rmap.connect('changeset_patch_home',
535 532 '/{repo_name:.*?}/changeset-patch/{revision}',
536 533 controller='changeset', action='changeset_patch',
537 534 revision='tip', conditions=dict(function=check_repo))
538 535
539 536 rmap.connect('changeset_download_home',
540 537 '/{repo_name:.*?}/changeset-download/{revision}',
541 538 controller='changeset', action='changeset_download',
542 539 revision='tip', conditions=dict(function=check_repo))
543 540
544 541 rmap.connect('changeset_comment',
545 542 '/{repo_name:.*?}/changeset/{revision}/comment',
546 543 controller='changeset', revision='tip', action='comment',
547 544 conditions=dict(function=check_repo))
548 545
549 546 rmap.connect('changeset_comment_preview',
550 547 '/{repo_name:.*?}/changeset/comment/preview',
551 548 controller='changeset', action='preview_comment',
552 549 conditions=dict(function=check_repo, method=["POST"]))
553 550
554 551 rmap.connect('changeset_comment_delete',
555 552 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
556 553 controller='changeset', action='delete_comment',
557 554 conditions=dict(function=check_repo, method=["DELETE"]))
558 555
559 556 rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
560 557 controller='changeset', action='changeset_info')
561 558
562 559 rmap.connect('compare_url',
563 560 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
564 561 controller='compare', action='index',
565 562 conditions=dict(function=check_repo),
566 563 requirements=dict(
567 564 org_ref_type='(branch|book|tag|rev|__other_ref_type__)',
568 565 other_ref_type='(branch|book|tag|rev|__org_ref_type__)')
569 566 )
570 567
571 568 rmap.connect('pullrequest_home',
572 569 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
573 570 action='index', conditions=dict(function=check_repo,
574 571 method=["GET"]))
575 572
576 573 rmap.connect('pullrequest',
577 574 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
578 575 action='create', conditions=dict(function=check_repo,
579 576 method=["POST"]))
580 577
581 578 rmap.connect('pullrequest_show',
582 579 '/{repo_name:.*?}/pull-request/{pull_request_id}',
583 580 controller='pullrequests',
584 581 action='show', conditions=dict(function=check_repo,
585 582 method=["GET"]))
586 583 rmap.connect('pullrequest_update',
587 584 '/{repo_name:.*?}/pull-request/{pull_request_id}',
588 585 controller='pullrequests',
589 586 action='update', conditions=dict(function=check_repo,
590 587 method=["PUT"]))
591 588 rmap.connect('pullrequest_delete',
592 589 '/{repo_name:.*?}/pull-request/{pull_request_id}',
593 590 controller='pullrequests',
594 591 action='delete', conditions=dict(function=check_repo,
595 592 method=["DELETE"]))
596 593
597 594 rmap.connect('pullrequest_show_all',
598 595 '/{repo_name:.*?}/pull-request',
599 596 controller='pullrequests',
600 597 action='show_all', conditions=dict(function=check_repo,
601 598 method=["GET"]))
602 599
603 600 rmap.connect('pullrequest_comment',
604 601 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
605 602 controller='pullrequests',
606 603 action='comment', conditions=dict(function=check_repo,
607 604 method=["POST"]))
608 605
609 606 rmap.connect('pullrequest_comment_delete',
610 607 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
611 608 controller='pullrequests', action='delete_comment',
612 609 conditions=dict(function=check_repo, method=["DELETE"]))
613 610
614 611 rmap.connect('summary_home_summary', '/{repo_name:.*?}/summary',
615 612 controller='summary', conditions=dict(function=check_repo))
616 613
617 614 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
618 615 controller='branches', conditions=dict(function=check_repo))
619 616
620 617 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
621 618 controller='tags', conditions=dict(function=check_repo))
622 619
623 620 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
624 621 controller='bookmarks', conditions=dict(function=check_repo))
625 622
626 623 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
627 624 controller='changelog', conditions=dict(function=check_repo))
628 625
629 626 rmap.connect('changelog_summary_home', '/{repo_name:.*?}/changelog_summary',
630 627 controller='changelog', action='changelog_summary',
631 628 conditions=dict(function=check_repo))
632 629
633 630 rmap.connect('changelog_file_home', '/{repo_name:.*?}/changelog/{revision}/{f_path:.*}',
634 631 controller='changelog', f_path=None,
635 632 conditions=dict(function=check_repo))
636 633
637 634 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
638 635 controller='changelog', action='changelog_details',
639 636 conditions=dict(function=check_repo))
640 637
641 638 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
642 639 controller='files', revision='tip', f_path='',
643 640 conditions=dict(function=check_repo))
644 641
645 642 rmap.connect('files_home_nopath', '/{repo_name:.*?}/files/{revision}',
646 643 controller='files', revision='tip', f_path='',
647 644 conditions=dict(function=check_repo))
648 645
649 646 rmap.connect('files_history_home',
650 647 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
651 648 controller='files', action='history', revision='tip', f_path='',
652 649 conditions=dict(function=check_repo))
653 650
654 651 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
655 652 controller='files', action='diff', revision='tip', f_path='',
656 653 conditions=dict(function=check_repo))
657 654
658 655 rmap.connect('files_rawfile_home',
659 656 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
660 657 controller='files', action='rawfile', revision='tip',
661 658 f_path='', conditions=dict(function=check_repo))
662 659
663 660 rmap.connect('files_raw_home',
664 661 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
665 662 controller='files', action='raw', revision='tip', f_path='',
666 663 conditions=dict(function=check_repo))
667 664
668 665 rmap.connect('files_annotate_home',
669 666 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
670 667 controller='files', action='index', revision='tip',
671 668 f_path='', annotate=True, conditions=dict(function=check_repo))
672 669
673 670 rmap.connect('files_edit_home',
674 671 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
675 672 controller='files', action='edit', revision='tip',
676 673 f_path='', conditions=dict(function=check_repo))
677 674
678 675 rmap.connect('files_add_home',
679 676 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
680 677 controller='files', action='add', revision='tip',
681 678 f_path='', conditions=dict(function=check_repo))
682 679
683 680 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
684 681 controller='files', action='archivefile',
685 682 conditions=dict(function=check_repo))
686 683
687 684 rmap.connect('files_nodelist_home',
688 685 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
689 686 controller='files', action='nodelist',
690 687 conditions=dict(function=check_repo))
691 688
692 689 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
693 690 controller='forks', action='fork_create',
694 691 conditions=dict(function=check_repo, method=["POST"]))
695 692
696 693 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
697 694 controller='forks', action='fork',
698 695 conditions=dict(function=check_repo))
699 696
700 697 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
701 698 controller='forks', action='forks',
702 699 conditions=dict(function=check_repo))
703 700
704 701 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
705 702 controller='followers', action='followers',
706 703 conditions=dict(function=check_repo))
707 704
708 705 return rmap
@@ -1,348 +1,349 b''
1 1 """The base Controller API
2 2
3 3 Provides the BaseController class for subclassing.
4 4 """
5 5 import logging
6 6 import time
7 7 import traceback
8 8
9 9 from paste.auth.basic import AuthBasicAuthenticator
10 10 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden
11 11 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
12 12
13 13 from pylons import config, tmpl_context as c, request, session, url
14 14 from pylons.controllers import WSGIController
15 15 from pylons.controllers.util import redirect
16 16 from pylons.templating import render_mako as render
17 17
18 18 from rhodecode import __version__, BACKENDS
19 19
20 20 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
21 21 safe_str, safe_int
22 22 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
23 23 HasPermissionAnyMiddleware, CookieStoreWrapper
24 24 from rhodecode.lib.utils import get_repo_slug
25 25 from rhodecode.model import meta
26 26
27 27 from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting
28 28 from rhodecode.model.notification import NotificationModel
29 29 from rhodecode.model.scm import ScmModel
30 30 from rhodecode.model.meta import Session
31 31
32 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 def _filter_proxy(ip):
36 36 """
37 37 HEADERS can have multiple ips inside the left-most being the original
38 38 client, and each successive proxy that passed the request adding the IP
39 39 address where it received the request from.
40 40
41 41 :param ip:
42 42 """
43 43 if ',' in ip:
44 44 _ips = ip.split(',')
45 45 _first_ip = _ips[0].strip()
46 46 log.debug('Got multiple IPs %s, using %s' % (','.join(_ips), _first_ip))
47 47 return _first_ip
48 48 return ip
49 49
50 50
51 51 def _get_ip_addr(environ):
52 52 proxy_key = 'HTTP_X_REAL_IP'
53 53 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
54 54 def_key = 'REMOTE_ADDR'
55 55
56 56 ip = environ.get(proxy_key)
57 57 if ip:
58 58 return _filter_proxy(ip)
59 59
60 60 ip = environ.get(proxy_key2)
61 61 if ip:
62 62 return _filter_proxy(ip)
63 63
64 64 ip = environ.get(def_key, '0.0.0.0')
65 65 return _filter_proxy(ip)
66 66
67 67
68 68 def _get_access_path(environ):
69 69 path = environ.get('PATH_INFO')
70 70 org_req = environ.get('pylons.original_request')
71 71 if org_req:
72 72 path = org_req.environ.get('PATH_INFO')
73 73 return path
74 74
75 75
76 76 class BasicAuth(AuthBasicAuthenticator):
77 77
78 78 def __init__(self, realm, authfunc, auth_http_code=None):
79 79 self.realm = realm
80 80 self.authfunc = authfunc
81 81 self._rc_auth_http_code = auth_http_code
82 82
83 83 def build_authentication(self):
84 84 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
85 85 if self._rc_auth_http_code and self._rc_auth_http_code == '403':
86 86 # return 403 if alternative http return code is specified in
87 87 # RhodeCode config
88 88 return HTTPForbidden(headers=head)
89 89 return HTTPUnauthorized(headers=head)
90 90
91 91 def authenticate(self, environ):
92 92 authorization = AUTHORIZATION(environ)
93 93 if not authorization:
94 94 return self.build_authentication()
95 95 (authmeth, auth) = authorization.split(' ', 1)
96 96 if 'basic' != authmeth.lower():
97 97 return self.build_authentication()
98 98 auth = auth.strip().decode('base64')
99 99 _parts = auth.split(':', 1)
100 100 if len(_parts) == 2:
101 101 username, password = _parts
102 102 if self.authfunc(environ, username, password):
103 103 return username
104 104 return self.build_authentication()
105 105
106 106 __call__ = authenticate
107 107
108 108
109 109 class BaseVCSController(object):
110 110
111 111 def __init__(self, application, config):
112 112 self.application = application
113 113 self.config = config
114 114 # base path of repo locations
115 115 self.basepath = self.config['base_path']
116 116 #authenticate this mercurial request using authfunc
117 117 self.authenticate = BasicAuth('', authfunc,
118 118 config.get('auth_ret_code'))
119 119 self.ip_addr = '0.0.0.0'
120 120
121 121 def _handle_request(self, environ, start_response):
122 122 raise NotImplementedError()
123 123
124 124 def _get_by_id(self, repo_name):
125 125 """
126 126 Get's a special pattern _<ID> from clone url and tries to replace it
127 127 with a repository_name for support of _<ID> non changable urls
128 128
129 129 :param repo_name:
130 130 """
131 131 try:
132 132 data = repo_name.split('/')
133 133 if len(data) >= 2:
134 134 by_id = data[1].split('_')
135 135 if len(by_id) == 2 and by_id[1].isdigit():
136 136 _repo_name = Repository.get(by_id[1]).repo_name
137 137 data[1] = _repo_name
138 138 except Exception:
139 139 log.debug('Failed to extract repo_name from id %s' % (
140 140 traceback.format_exc()
141 141 )
142 142 )
143 143
144 144 return '/'.join(data)
145 145
146 146 def _invalidate_cache(self, repo_name):
147 147 """
148 148 Set's cache for this repository for invalidation on next access
149 149
150 150 :param repo_name: full repo name, also a cache key
151 151 """
152 152 ScmModel().mark_for_invalidation(repo_name)
153 153
154 154 def _check_permission(self, action, user, repo_name, ip_addr=None):
155 155 """
156 156 Checks permissions using action (push/pull) user and repository
157 157 name
158 158
159 159 :param action: push or pull action
160 160 :param user: user instance
161 161 :param repo_name: repository name
162 162 """
163 163 #check IP
164 164 authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr)
165 165 if not authuser.ip_allowed:
166 166 return False
167 167 else:
168 168 log.info('Access for IP:%s allowed' % (ip_addr))
169 169 if action == 'push':
170 170 if not HasPermissionAnyMiddleware('repository.write',
171 171 'repository.admin')(user,
172 172 repo_name):
173 173 return False
174 174
175 175 else:
176 176 #any other action need at least read permission
177 177 if not HasPermissionAnyMiddleware('repository.read',
178 178 'repository.write',
179 179 'repository.admin')(user,
180 180 repo_name):
181 181 return False
182 182
183 183 return True
184 184
185 185 def _get_ip_addr(self, environ):
186 186 return _get_ip_addr(environ)
187 187
188 188 def _check_ssl(self, environ, start_response):
189 189 """
190 190 Checks the SSL check flag and returns False if SSL is not present
191 191 and required True otherwise
192 192 """
193 193 org_proto = environ['wsgi._org_proto']
194 194 #check if we have SSL required ! if not it's a bad request !
195 195 require_ssl = str2bool(RhodeCodeUi.get_by_key('push_ssl').ui_value)
196 196 if require_ssl and org_proto == 'http':
197 197 log.debug('proto is %s and SSL is required BAD REQUEST !'
198 198 % org_proto)
199 199 return False
200 200 return True
201 201
202 202 def _check_locking_state(self, environ, action, repo, user_id):
203 203 """
204 204 Checks locking on this repository, if locking is enabled and lock is
205 205 present returns a tuple of make_lock, locked, locked_by.
206 206 make_lock can have 3 states None (do nothing) True, make lock
207 207 False release lock, This value is later propagated to hooks, which
208 208 do the locking. Think about this as signals passed to hooks what to do.
209 209
210 210 """
211 211 locked = False # defines that locked error should be thrown to user
212 212 make_lock = None
213 213 repo = Repository.get_by_repo_name(repo)
214 214 user = User.get(user_id)
215 215
216 216 # this is kind of hacky, but due to how mercurial handles client-server
217 217 # server see all operation on changeset; bookmarks, phases and
218 218 # obsolescence marker in different transaction, we don't want to check
219 219 # locking on those
220 220 obsolete_call = environ['QUERY_STRING'] in ['cmd=listkeys',]
221 221 locked_by = repo.locked
222 222 if repo and repo.enable_locking and not obsolete_call:
223 223 if action == 'push':
224 224 #check if it's already locked !, if it is compare users
225 225 user_id, _date = repo.locked
226 226 if user.user_id == user_id:
227 227 log.debug('Got push from user %s, now unlocking' % (user))
228 228 # unlock if we have push from user who locked
229 229 make_lock = False
230 230 else:
231 231 # we're not the same user who locked, ban with 423 !
232 232 locked = True
233 233 if action == 'pull':
234 234 if repo.locked[0] and repo.locked[1]:
235 235 locked = True
236 236 else:
237 237 log.debug('Setting lock on repo %s by %s' % (repo, user))
238 238 make_lock = True
239 239
240 240 else:
241 241 log.debug('Repository %s do not have locking enabled' % (repo))
242 242 log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s'
243 243 % (make_lock, locked, locked_by))
244 244 return make_lock, locked, locked_by
245 245
246 246 def __call__(self, environ, start_response):
247 247 start = time.time()
248 248 try:
249 249 return self._handle_request(environ, start_response)
250 250 finally:
251 251 log = logging.getLogger('rhodecode.' + self.__class__.__name__)
252 252 log.debug('Request time: %.3fs' % (time.time() - start))
253 253 meta.Session.remove()
254 254
255 255
256 256 class BaseController(WSGIController):
257 257
258 258 def __before__(self):
259 259 """
260 260 __before__ is called before controller methods and after __call__
261 261 """
262 262 c.rhodecode_version = __version__
263 263 c.rhodecode_instanceid = config.get('instance_id')
264 264 c.rhodecode_name = config.get('rhodecode_title')
265 c.rhodecode_bugtracker = config.get('bugtracker', 'http://bitbucket.org/marcinkuzminski/rhodecode/issues')
265 266 c.use_gravatar = str2bool(config.get('use_gravatar'))
266 267 c.ga_code = config.get('rhodecode_ga_code')
267 268 # Visual options
268 269 c.visual = AttributeDict({})
269 270 rc_config = RhodeCodeSetting.get_app_settings()
270 271 ## DB stored
271 272 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon'))
272 273 c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon'))
273 274 c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags'))
274 275 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100))
275 276 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
276 277 c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version'))
277 278
278 279 ## INI stored
279 280 self.cut_off_limit = int(config.get('cut_off_limit'))
280 281 c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True))
281 282
282 283 c.repo_name = get_repo_slug(request) # can be empty
283 284 c.backends = BACKENDS.keys()
284 285 c.unread_notifications = NotificationModel()\
285 286 .get_unread_cnt_for_user(c.rhodecode_user.user_id)
286 287 self.sa = meta.Session
287 288 self.scm_model = ScmModel(self.sa)
288 289
289 290 def __call__(self, environ, start_response):
290 291 """Invoke the Controller"""
291 292 # WSGIController.__call__ dispatches to the Controller method
292 293 # the request is routed to. This routing information is
293 294 # available in environ['pylons.routes_dict']
294 295 try:
295 296 self.ip_addr = _get_ip_addr(environ)
296 297 # make sure that we update permissions each time we call controller
297 298 api_key = request.GET.get('api_key')
298 299 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
299 300 user_id = cookie_store.get('user_id', None)
300 301 username = get_container_username(environ, config)
301 302 auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
302 303 request.user = auth_user
303 304 self.rhodecode_user = c.rhodecode_user = auth_user
304 305 if not self.rhodecode_user.is_authenticated and \
305 306 self.rhodecode_user.user_id is not None:
306 307 self.rhodecode_user.set_authenticated(
307 308 cookie_store.get('is_authenticated')
308 309 )
309 310 log.info('IP: %s User: %s accessed %s' % (
310 311 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
311 312 )
312 313 return WSGIController.__call__(self, environ, start_response)
313 314 finally:
314 315 meta.Session.remove()
315 316
316 317
317 318 class BaseRepoController(BaseController):
318 319 """
319 320 Base class for controllers responsible for loading all needed data for
320 321 repository loaded items are
321 322
322 323 c.rhodecode_repo: instance of scm repository
323 324 c.rhodecode_db_repo: instance of db
324 325 c.repository_followers: number of followers
325 326 c.repository_forks: number of forks
326 327 c.repository_following: weather the current user is following the current repo
327 328 """
328 329
329 330 def __before__(self):
330 331 super(BaseRepoController, self).__before__()
331 332 if c.repo_name:
332 333
333 334 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
334 335 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
335 336 # update last change according to VCS data
336 337 dbr.update_changeset_cache(dbr.get_changeset())
337 338 if c.rhodecode_repo is None:
338 339 log.error('%s this repository is present in database but it '
339 340 'cannot be created as an scm instance', c.repo_name)
340 341
341 342 redirect(url('home'))
342 343
343 344 # some globals counter for menu
344 345 c.repository_followers = self.scm_model.get_followers(dbr)
345 346 c.repository_forks = self.scm_model.get_forks(dbr)
346 347 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
347 348 c.repository_following = self.scm_model.is_following_repo(c.repo_name,
348 349 self.rhodecode_user.user_id)
@@ -1,359 +1,361 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="root.html"/>
3 3
4 4 <!-- HEADER -->
5 5 <div id="header-dd"></div>
6 6 <div id="header">
7 7 <div id="header-inner" class="title">
8 8 <div id="logo">
9 9 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
10 10 </div>
11 11 <!-- MENU -->
12 12 ${self.page_nav()}
13 13 <!-- END MENU -->
14 14 ${self.body()}
15 15 </div>
16 16 </div>
17 17 <!-- END HEADER -->
18 18
19 19 <!-- CONTENT -->
20 20 <div id="content">
21 21 <div class="flash_msg">
22 22 <% messages = h.flash.pop_messages() %>
23 23 % if messages:
24 24 <ul id="flash-messages">
25 25 % for message in messages:
26 26 <li class="${message.category}_msg">${message}</li>
27 27 % endfor
28 28 </ul>
29 29 % endif
30 30 </div>
31 31 <div id="main">
32 32 ${next.main()}
33 33 </div>
34 34 </div>
35 35 <!-- END CONTENT -->
36 36
37 37 <!-- FOOTER -->
38 38 <div id="footer">
39 39 <div id="footer-inner" class="title">
40 40 <div>
41 41 <p class="footer-link">
42 42 ${_('Server instance: %s') % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}
43 43 </p>
44 44 <p class="footer-link-right">
45 45 <a href="${h.url('rhodecode_official')}">
46 46 RhodeCode
47 47 %if c.visual.show_version:
48 48 ${c.rhodecode_version}
49 49 %endif
50 50 </a>
51 51 &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski and others
52 &ndash; <a href="${h.url('bugtracker')}">${_('Report a bug')}</a>
52 %if c.rhodecode_bugtracker:
53 &ndash; <a href="${c.rhodecode_bugtracker}">${_('Report a bug')}</a>
54 %endif
53 55 </p>
54 56 </div>
55 57 </div>
56 58 </div>
57 59
58 60 <!-- END FOOTER -->
59 61
60 62 ### MAKO DEFS ###
61 63 <%def name="breadcrumbs()">
62 64 <div class="breadcrumbs">
63 65 ${self.breadcrumbs_links()}
64 66 </div>
65 67 </%def>
66 68
67 69 <%def name="admin_menu()">
68 70 <ul class="admin_menu">
69 71 <li>${h.link_to(_('Admin journal'),h.url('admin_home'),class_='journal ')}</li>
70 72 <li>${h.link_to(_('Repositories'),h.url('repos'),class_='repos')}</li>
71 73 <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
72 74 <li>${h.link_to(_('Users'),h.url('users'),class_='users')}</li>
73 75 <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
74 76 <li>${h.link_to(_('Permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
75 77 <li>${h.link_to(_('LDAP'),h.url('ldap_home'),class_='ldap')}</li>
76 78 <li>${h.link_to(_('Defaults'),h.url('defaults'),class_='defaults')}</li>
77 79 <li class="last">${h.link_to(_('Settings'),h.url('admin_settings'),class_='settings')}</li>
78 80 </ul>
79 81 </%def>
80 82
81 83 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
82 84 <ul>
83 85 %if repositories:
84 86 <li>${h.link_to(_('Repositories'),h.url('repos'),class_='repos')}</li>
85 87 %endif
86 88 %if repository_groups:
87 89 <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
88 90 %endif
89 91 %if user_groups:
90 92 <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
91 93 %endif
92 94 </ul>
93 95 </%def>
94 96
95 97 <%def name="repo_context_bar(current=None)">
96 98 <%
97 99 def follow_class():
98 100 if c.repository_following:
99 101 return h.literal('following')
100 102 else:
101 103 return h.literal('follow')
102 104 %>
103 105 <%
104 106 def is_current(selected):
105 107 if selected == current:
106 108 return h.literal('class="current"')
107 109 %>
108 110
109 111 <!--- CONTEXT BAR -->
110 112 <div id="context-bar" class="box">
111 113 <div id="breadcrumbs">
112 114 ${h.link_to(_(u'Repositories'),h.url('home'))}
113 115 &raquo;
114 116 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
115 117 </div>
116 118 <ul id="context-pages" class="horizontal-list">
117 119 <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}" class="summary">${_('Summary')}</a></li>
118 120 <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}" class="changelogs">${_('Changelog')}</a></li>
119 121 <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name)}" class="files"></span>${_('Files')}</a></li>
120 122 <li ${is_current('switch-to')}>
121 123 <a href="#" id="branch_tag_switcher_2" class="dropdown switch-to"></span>${_('Switch To')}</a>
122 124 <ul id="switch_to_list_2" class="switch_to submenu">
123 125 <li><a href="#">${_('Loading...')}</a></li>
124 126 </ul>
125 127 </li>
126 128 <li ${is_current('options')}>
127 129 <a href="#" class="dropdown options"></span>${_('Options')}</a>
128 130 <ul>
129 131 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
130 132 <li>${h.link_to(_('Settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
131 133 %endif
132 134 %if c.rhodecode_db_repo.fork:
133 135 <li>${h.link_to(_('Compare fork'),h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default', merge=1),class_='compare_request')}</li>
134 136 %endif
135 137 <li>${h.link_to(_('Search'),h.url('search_repo',repo_name=c.repo_name),class_='search')}</li>
136 138
137 139 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
138 140 %if c.rhodecode_db_repo.locked[0]:
139 141 <li>${h.link_to(_('Unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
140 142 %else:
141 143 <li>${h.link_to(_('Lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
142 144 %endif
143 145 %endif
144 146 ## TODO: this check feels wrong, it would be better to have a check for permissions
145 147 ## also it feels like a job for the controller
146 148 %if c.rhodecode_user.username != 'default':
147 149 <li>
148 150 <a class="${follow_class()}" onclick="javascript:toggleFollowingRepo(this,${c.rhodecode_db_repo.repo_id},'${str(h.get_token())}');">
149 151 <span class="show-follow">${_('Follow')}</span>
150 152 <span class="show-following">${_('Unfollow')}</span>
151 153 </a>
152 154 </li>
153 155 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}" class="fork">${_('Fork')}</a></li>
154 156 %if h.is_hg(c.rhodecode_repo):
155 157 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="pull-request">${_('Create Pull Request')}</a></li>
156 158 %endif
157 159 %endif
158 160 </ul>
159 161 </li>
160 162 <li ${is_current('showpullrequest')}>
161 163 <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests')}" class="pull-request">${_('Pull Requests')}
162 164 %if c.repository_pull_requests:
163 165 <span>${c.repository_pull_requests}</span>
164 166 %endif
165 167 </a>
166 168 </li>
167 169 </ul>
168 170 </div>
169 171 <script type="text/javascript">
170 172 YUE.on('branch_tag_switcher_2','mouseover',function(){
171 173 var loaded = YUD.hasClass('branch_tag_switcher_2','loaded');
172 174 if(!loaded){
173 175 YUD.addClass('branch_tag_switcher_2','loaded');
174 176 ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list_2',
175 177 function(o){},
176 178 function(o){YUD.removeClass('branch_tag_switcher_2','loaded');}
177 179 ,null);
178 180 }
179 181 return false;
180 182 });
181 183 </script>
182 184 <!--- END CONTEXT BAR -->
183 185 </%def>
184 186
185 187 <%def name="usermenu()">
186 188 ## USER MENU
187 189 <li>
188 190 <a class="menu_link childs" id="quick_login_link">
189 191 <span class="icon">
190 192 <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
191 193 </span>
192 194 %if c.rhodecode_user.username != 'default':
193 195 <span class="menu_link_user">${c.rhodecode_user.username}</span>
194 196 %if c.unread_notifications != 0:
195 197 <span class="menu_link_notifications">${c.unread_notifications}</span>
196 198 %endif
197 199 %else:
198 200 <span>${_('Not logged in')}</span>
199 201 %endif
200 202 </a>
201 203
202 204 <div class="user-menu">
203 205 <div id="quick_login">
204 206 %if c.rhodecode_user.username == 'default':
205 207 <h4>${_('Login to your account')}</h4>
206 208 ${h.form(h.url('login_home',came_from=h.url.current()))}
207 209 <div class="form">
208 210 <div class="fields">
209 211 <div class="field">
210 212 <div class="label">
211 213 <label for="username">${_('Username')}:</label>
212 214 </div>
213 215 <div class="input">
214 216 ${h.text('username',class_='focus')}
215 217 </div>
216 218
217 219 </div>
218 220 <div class="field">
219 221 <div class="label">
220 222 <label for="password">${_('Password')}:</label>
221 223 </div>
222 224 <div class="input">
223 225 ${h.password('password',class_='focus')}
224 226 </div>
225 227
226 228 </div>
227 229 <div class="buttons">
228 230 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
229 231 <div class="register">
230 232 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
231 233 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
232 234 %endif
233 235 </div>
234 236 <div class="submit">
235 237 ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
236 238 </div>
237 239 </div>
238 240 </div>
239 241 </div>
240 242 ${h.end_form()}
241 243 %else:
242 244 <div class="links_left">
243 245 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
244 246 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
245 247 <div class="email">${c.rhodecode_user.email}</div>
246 248 </div>
247 249 <div class="links_right">
248 250 <ol class="links">
249 251 <li><a href="${h.url('notifications')}">${_('Notifications')}: ${c.unread_notifications}</a></li>
250 252 <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
251 253 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
252 254 </ol>
253 255 </div>
254 256 %endif
255 257 </div>
256 258 </div>
257 259
258 260 </li>
259 261 </%def>
260 262
261 263 <%def name="menu(current=None)">
262 264 <%
263 265 def is_current(selected):
264 266 if selected == current:
265 267 return h.literal('class="current"')
266 268 %>
267 269 <ul id="quick" class="horizontal-list">
268 270 <!-- repo switcher -->
269 271 <li ${is_current('repositories')}>
270 272 <a class="menu_link repo_switcher childs" id="repo_switcher" title="${_('Switch repository')}" href="${h.url('home')}">
271 273 ${_('Repositories')}
272 274 </a>
273 275 <ul id="repo_switcher_list" class="repo_switcher">
274 276 <li>
275 277 <a href="#">${_('Loading...')}</a>
276 278 </li>
277 279 </ul>
278 280 </li>
279 281 ##ROOT MENU
280 282 %if c.rhodecode_user.username != 'default':
281 283 <li ${is_current('journal')}>
282 284 <a class="menu_link journal" title="${_('Show recent activity')}" href="${h.url('journal')}">
283 285 ${_('Journal')}
284 286 </a>
285 287 </li>
286 288 %else:
287 289 <li ${is_current('journal')}>
288 290 <a class="menu_link journal" title="${_('Public journal')}" href="${h.url('public_journal')}">
289 291 ${_('Public journal')}
290 292 </a>
291 293 </li>
292 294 %endif
293 295 <li ${is_current('gists')}>
294 296 <a class="menu_link gists childs" title="${_('Show public gists')}" href="${h.url('gists')}">
295 297 ${_('Gists')}
296 298 </a>
297 299 <ul class="admin_menu">
298 300 <li>${h.link_to(_('Create new gist'),h.url('new_gist'),class_='gists-new ')}</li>
299 301 <li>${h.link_to(_('All public gists'),h.url('gists'),class_='gists ')}</li>
300 302 %if c.rhodecode_user.username != 'default':
301 303 <li>${h.link_to(_('My public gists'),h.url('gists', public=1),class_='gists')}</li>
302 304 <li>${h.link_to(_('My private gists'),h.url('gists', private=1),class_='gists-private ')}</li>
303 305 %endif
304 306 </ul>
305 307 </li>
306 308 <li ${is_current('search')}>
307 309 <a class="menu_link search" title="${_('Search in repositories')}" href="${h.url('search')}">
308 310 ${_('Search')}
309 311 </a>
310 312 </li>
311 313 % if h.HasPermissionAll('hg.admin')('access admin main page'):
312 314 <li ${is_current('admin')}>
313 315 <a class="menu_link admin childs" title="${_('Admin')}" href="${h.url('admin_home')}">
314 316 ${_('Admin')}
315 317 </a>
316 318 ${admin_menu()}
317 319 </li>
318 320 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
319 321 <li ${is_current('admin')}>
320 322 <a class="menu_link admin childs" title="${_('Admin')}">
321 323 ${_('Admin')}
322 324 </a>
323 325 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
324 326 c.rhodecode_user.repository_groups_admin,
325 327 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
326 328 </li>
327 329 % endif
328 330 ${usermenu()}
329 331 <script type="text/javascript">
330 332 YUE.on('repo_switcher','mouseover',function(){
331 333 var target = 'q_filter_rs';
332 334 var qfilter_activate = function(){
333 335 var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
334 336 var func = function(node){
335 337 return node.parentNode;
336 338 }
337 339 q_filter(target,nodes,func);
338 340 }
339 341
340 342 var loaded = YUD.hasClass('repo_switcher','loaded');
341 343 if(!loaded){
342 344 YUD.addClass('repo_switcher','loaded');
343 345 ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
344 346 function(o){qfilter_activate();YUD.get(target).focus()},
345 347 function(o){YUD.removeClass('repo_switcher','loaded');}
346 348 ,null);
347 349 }else{
348 350 YUD.get(target).focus();
349 351 }
350 352 return false;
351 353 });
352 354
353 355 YUE.on('header-dd', 'click',function(e){
354 356 YUD.addClass('header-inner', 'hover');
355 357 YUD.addClass('content', 'hover');
356 358 });
357 359
358 360 </script>
359 361 </%def>
General Comments 0
You need to be logged in to leave comments. Login now