##// END OF EJS Templates
added dashboard items config in visual settings
marcink -
r3904:fe053a42 beta
parent child Browse files
Show More
@@ -1,510 +1,507 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. Don't change that to more than 1
54 54 #workers = 1
55 55 ## process name
56 56 #proc_name = rhodecode
57 57 ## type of worker class, one of sync, eventlet, gevent, tornado
58 58 ## recommended for bigger setup is using of of other than sync one
59 59 #worker-class = sync
60 60 #max-requests = 5
61 61
62 62 ## COMMON ##
63 63 host = 0.0.0.0
64 64 port = 5000
65 65
66 66 ## prefix middleware for rc
67 67 #[filter:proxy-prefix]
68 68 #use = egg:PasteDeploy#prefix
69 69 #prefix = /<your-prefix>
70 70
71 71 [app:main]
72 72 use = egg:rhodecode
73 73 ## enable proxy prefix middleware
74 74 #filter-with = proxy-prefix
75 75
76 76 full_stack = true
77 77 static_files = true
78 78 ## Optional Languages
79 79 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
80 80 lang = en
81 81 cache_dir = %(here)s/data
82 82 index_dir = %(here)s/data/index
83 83
84 84 ## perform a full repository scan on each server start, this should be
85 85 ## set to false after first startup, to allow faster server restarts.
86 86 initial_repo_scan = true
87 87
88 88 ## uncomment and set this path to use archive download cache
89 89 #archive_cache_dir = /tmp/tarballcache
90 90
91 91 ## change this to unique ID for security
92 92 app_instance_uuid = rc-production
93 93
94 94 ## cut off limit for large diffs (size in bytes)
95 95 cut_off_limit = 256000
96 96
97 97 ## use cache version of scm repo everywhere
98 98 vcs_full_cache = true
99 99
100 100 ## force https in RhodeCode, fixes https redirects, assumes it's always https
101 101 force_https = false
102 102
103 103 ## use Strict-Transport-Security headers
104 104 use_htsts = false
105 105
106 106 ## number of commits stats will parse on each iteration
107 107 commit_parse_limit = 25
108 108
109 ## number of items displayed in lightweight dashboard before paginating is shown
110 dashboard_items = 100
111
112 109 ## use gravatar service to display avatars
113 110 use_gravatar = true
114 111
115 112 ## path to git executable
116 113 git_path = git
117 114
118 115 ## git rev filter option, --all is the default filter, if you need to
119 116 ## hide all refs in changelog switch this to --branches --tags
120 117 git_rev_filter=--all
121 118
122 119 ## RSS feed options
123 120 rss_cut_off_limit = 256000
124 121 rss_items_per_page = 10
125 122 rss_include_diff = false
126 123
127 124 ## options for showing and identifying changesets
128 125 show_sha_length = 12
129 126 show_revision_number = true
130 127
131 128 ## gist URL alias, used to create nicer urls for gist. This should be an
132 129 ## url that does rewrites to _admin/gists/<gistid>.
133 130 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
134 131 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
135 132 gist_alias_url =
136 133
137 134 ## white list of API enabled controllers. This allows to add list of
138 135 ## controllers to which access will be enabled by api_key. eg: to enable
139 136 ## api access to raw_files put `FilesController:raw`, to enable access to patches
140 137 ## add `ChangesetController:changeset_patch`. This list should be "," separated
141 138 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
142 139 api_access_controllers_whitelist =
143 140
144 141 ## alternative_gravatar_url allows you to use your own avatar server application
145 142 ## the following parts of the URL will be replaced
146 143 ## {email} user email
147 144 ## {md5email} md5 hash of the user email (like at gravatar.com)
148 145 ## {size} size of the image that is expected from the server application
149 146 ## {scheme} http/https from RhodeCode server
150 147 ## {netloc} network location from RhodeCode server
151 148 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
152 149 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
153 150
154 151
155 152 ## container auth options
156 153 container_auth_enabled = false
157 154 proxypass_auth_enabled = false
158 155
159 156 ## default encoding used to convert from and to unicode
160 157 ## can be also a comma seperated list of encoding in case of mixed encodings
161 158 default_encoding = utf8
162 159
163 160 ## overwrite schema of clone url
164 161 ## available vars:
165 162 ## scheme - http/https
166 163 ## user - current user
167 164 ## pass - password
168 165 ## netloc - network location
169 166 ## path - usually repo_name
170 167
171 168 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
172 169
173 170 ## issue tracking mapping for commits messages
174 171 ## comment out issue_pat, issue_server, issue_prefix to enable
175 172
176 173 ## pattern to get the issues from commit messages
177 174 ## default one used here is #<numbers> with a regex passive group for `#`
178 175 ## {id} will be all groups matched from this pattern
179 176
180 177 issue_pat = (?:\s*#)(\d+)
181 178
182 179 ## server url to the issue, each {id} will be replaced with match
183 180 ## fetched from the regex and {repo} is replaced with full repository name
184 181 ## including groups {repo_name} is replaced with just name of repo
185 182
186 183 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
187 184
188 185 ## prefix to add to link to indicate it's an url
189 186 ## #314 will be replaced by <issue_prefix><id>
190 187
191 188 issue_prefix = #
192 189
193 190 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
194 191 ## multiple patterns, to other issues server, wiki or others
195 192 ## below an example how to create a wiki pattern
196 193 # #wiki-some-id -> https://mywiki.com/some-id
197 194
198 195 #issue_pat_wiki = (?:wiki-)(.+)
199 196 #issue_server_link_wiki = https://mywiki.com/{id}
200 197 #issue_prefix_wiki = WIKI-
201 198
202 199
203 200 ## instance-id prefix
204 201 ## a prefix key for this instance used for cache invalidation when running
205 202 ## multiple instances of rhodecode, make sure it's globally unique for
206 203 ## all running rhodecode instances. Leave empty if you don't use it
207 204 instance_id =
208 205
209 206 ## alternative return HTTP header for failed authentication. Default HTTP
210 207 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
211 208 ## handling that. Set this variable to 403 to return HTTPForbidden
212 209 auth_ret_code =
213 210
214 211 ## locking return code. When repository is locked return this HTTP code. 2XX
215 212 ## codes don't break the transactions while 4XX codes do
216 213 lock_ret_code = 423
217 214
218 215
219 216 ####################################
220 217 ### CELERY CONFIG ####
221 218 ####################################
222 219 use_celery = false
223 220 broker.host = localhost
224 221 broker.vhost = rabbitmqhost
225 222 broker.port = 5672
226 223 broker.user = rabbitmq
227 224 broker.password = qweqwe
228 225
229 226 celery.imports = rhodecode.lib.celerylib.tasks
230 227
231 228 celery.result.backend = amqp
232 229 celery.result.dburi = amqp://
233 230 celery.result.serialier = json
234 231
235 232 #celery.send.task.error.emails = true
236 233 #celery.amqp.task.result.expires = 18000
237 234
238 235 celeryd.concurrency = 2
239 236 #celeryd.log.file = celeryd.log
240 237 celeryd.log.level = debug
241 238 celeryd.max.tasks.per.child = 1
242 239
243 240 ## tasks will never be sent to the queue, but executed locally instead.
244 241 celery.always.eager = false
245 242
246 243 ####################################
247 244 ### BEAKER CACHE ####
248 245 ####################################
249 246 beaker.cache.data_dir=%(here)s/data/cache/data
250 247 beaker.cache.lock_dir=%(here)s/data/cache/lock
251 248
252 249 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
253 250
254 251 beaker.cache.super_short_term.type=memory
255 252 beaker.cache.super_short_term.expire=10
256 253 beaker.cache.super_short_term.key_length = 256
257 254
258 255 beaker.cache.short_term.type=memory
259 256 beaker.cache.short_term.expire=60
260 257 beaker.cache.short_term.key_length = 256
261 258
262 259 beaker.cache.long_term.type=memory
263 260 beaker.cache.long_term.expire=36000
264 261 beaker.cache.long_term.key_length = 256
265 262
266 263 beaker.cache.sql_cache_short.type=memory
267 264 beaker.cache.sql_cache_short.expire=10
268 265 beaker.cache.sql_cache_short.key_length = 256
269 266
270 267 beaker.cache.sql_cache_med.type=memory
271 268 beaker.cache.sql_cache_med.expire=360
272 269 beaker.cache.sql_cache_med.key_length = 256
273 270
274 271 beaker.cache.sql_cache_long.type=file
275 272 beaker.cache.sql_cache_long.expire=3600
276 273 beaker.cache.sql_cache_long.key_length = 256
277 274
278 275 ####################################
279 276 ### BEAKER SESSION ####
280 277 ####################################
281 278 ## Type of storage used for the session, current types are
282 279 ## dbm, file, memcached, database, and memory.
283 280 ## The storage uses the Container API
284 281 ## that is also used by the cache system.
285 282
286 283 ## db session ##
287 284 #beaker.session.type = ext:database
288 285 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
289 286 #beaker.session.table_name = db_session
290 287
291 288 ## encrypted cookie client side session, good for many instances ##
292 289 #beaker.session.type = cookie
293 290
294 291 ## file based cookies (default) ##
295 292 #beaker.session.type = file
296 293
297 294
298 295 beaker.session.key = rhodecode
299 296 ## secure cookie requires AES python libraries
300 297 #beaker.session.encrypt_key = <key_for_encryption>
301 298 #beaker.session.validate_key = <validation_key>
302 299
303 300 ## sets session as invalid if it haven't been accessed for given amount of time
304 301 beaker.session.timeout = 2592000
305 302 beaker.session.httponly = true
306 303 #beaker.session.cookie_path = /<your-prefix>
307 304
308 305 ## uncomment for https secure cookie
309 306 beaker.session.secure = false
310 307
311 308 ## auto save the session to not to use .save()
312 309 beaker.session.auto = False
313 310
314 311 ## default cookie expiration time in seconds `true` expire at browser close ##
315 312 #beaker.session.cookie_expires = 3600
316 313
317 314
318 315 ############################
319 316 ## ERROR HANDLING SYSTEMS ##
320 317 ############################
321 318
322 319 ####################
323 320 ### [errormator] ###
324 321 ####################
325 322
326 323 ## Errormator is tailored to work with RhodeCode, see
327 324 ## http://errormator.com for details how to obtain an account
328 325 ## you must install python package `errormator_client` to make it work
329 326
330 327 ## errormator enabled
331 328 errormator = false
332 329
333 330 errormator.server_url = https://api.errormator.com
334 331 errormator.api_key = YOUR_API_KEY
335 332
336 333 ## TWEAK AMOUNT OF INFO SENT HERE
337 334
338 335 ## enables 404 error logging (default False)
339 336 errormator.report_404 = false
340 337
341 338 ## time in seconds after request is considered being slow (default 1)
342 339 errormator.slow_request_time = 1
343 340
344 341 ## record slow requests in application
345 342 ## (needs to be enabled for slow datastore recording and time tracking)
346 343 errormator.slow_requests = true
347 344
348 345 ## enable hooking to application loggers
349 346 # errormator.logging = true
350 347
351 348 ## minimum log level for log capture
352 349 # errormator.logging.level = WARNING
353 350
354 351 ## send logs only from erroneous/slow requests
355 352 ## (saves API quota for intensive logging)
356 353 errormator.logging_on_error = false
357 354
358 355 ## list of additonal keywords that should be grabbed from environ object
359 356 ## can be string with comma separated list of words in lowercase
360 357 ## (by default client will always send following info:
361 358 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
362 359 ## start with HTTP* this list be extended with additional keywords here
363 360 errormator.environ_keys_whitelist =
364 361
365 362
366 363 ## list of keywords that should be blanked from request object
367 364 ## can be string with comma separated list of words in lowercase
368 365 ## (by default client will always blank keys that contain following words
369 366 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
370 367 ## this list be extended with additional keywords set here
371 368 errormator.request_keys_blacklist =
372 369
373 370
374 371 ## list of namespaces that should be ignores when gathering log entries
375 372 ## can be string with comma separated list of namespaces
376 373 ## (by default the client ignores own entries: errormator_client.client)
377 374 errormator.log_namespace_blacklist =
378 375
379 376
380 377 ################
381 378 ### [sentry] ###
382 379 ################
383 380
384 381 ## sentry is a alternative open source error aggregator
385 382 ## you must install python packages `sentry` and `raven` to enable
386 383
387 384 sentry.dsn = YOUR_DNS
388 385 sentry.servers =
389 386 sentry.name =
390 387 sentry.key =
391 388 sentry.public_key =
392 389 sentry.secret_key =
393 390 sentry.project =
394 391 sentry.site =
395 392 sentry.include_paths =
396 393 sentry.exclude_paths =
397 394
398 395
399 396 ################################################################################
400 397 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
401 398 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
402 399 ## execute malicious code after an exception is raised. ##
403 400 ################################################################################
404 401 #set debug = false
405 402
406 403 ##################################
407 404 ### LOGVIEW CONFIG ###
408 405 ##################################
409 406 logview.sqlalchemy = #faa
410 407 logview.pylons.templating = #bfb
411 408 logview.pylons.util = #eee
412 409
413 410 #########################################################
414 411 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
415 412 #########################################################
416 413 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
417 414 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
418 415 sqlalchemy.db1.echo = false
419 416 sqlalchemy.db1.pool_recycle = 3600
420 417 sqlalchemy.db1.convert_unicode = true
421 418
422 419 ################################
423 420 ### LOGGING CONFIGURATION ####
424 421 ################################
425 422 [loggers]
426 423 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
427 424
428 425 [handlers]
429 426 keys = console, console_sql
430 427
431 428 [formatters]
432 429 keys = generic, color_formatter, color_formatter_sql
433 430
434 431 #############
435 432 ## LOGGERS ##
436 433 #############
437 434 [logger_root]
438 435 level = NOTSET
439 436 handlers = console
440 437
441 438 [logger_routes]
442 439 level = DEBUG
443 440 handlers =
444 441 qualname = routes.middleware
445 442 ## "level = DEBUG" logs the route matched and routing variables.
446 443 propagate = 1
447 444
448 445 [logger_beaker]
449 446 level = DEBUG
450 447 handlers =
451 448 qualname = beaker.container
452 449 propagate = 1
453 450
454 451 [logger_templates]
455 452 level = INFO
456 453 handlers =
457 454 qualname = pylons.templating
458 455 propagate = 1
459 456
460 457 [logger_rhodecode]
461 458 level = DEBUG
462 459 handlers =
463 460 qualname = rhodecode
464 461 propagate = 1
465 462
466 463 [logger_sqlalchemy]
467 464 level = INFO
468 465 handlers = console_sql
469 466 qualname = sqlalchemy.engine
470 467 propagate = 0
471 468
472 469 [logger_whoosh_indexer]
473 470 level = DEBUG
474 471 handlers =
475 472 qualname = whoosh_indexer
476 473 propagate = 1
477 474
478 475 ##############
479 476 ## HANDLERS ##
480 477 ##############
481 478
482 479 [handler_console]
483 480 class = StreamHandler
484 481 args = (sys.stderr,)
485 482 level = DEBUG
486 483 formatter = color_formatter
487 484
488 485 [handler_console_sql]
489 486 class = StreamHandler
490 487 args = (sys.stderr,)
491 488 level = DEBUG
492 489 formatter = color_formatter_sql
493 490
494 491 ################
495 492 ## FORMATTERS ##
496 493 ################
497 494
498 495 [formatter_generic]
499 496 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
500 497 datefmt = %Y-%m-%d %H:%M:%S
501 498
502 499 [formatter_color_formatter]
503 500 class=rhodecode.lib.colored_formatter.ColorFormatter
504 501 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
505 502 datefmt = %Y-%m-%d %H:%M:%S
506 503
507 504 [formatter_color_formatter_sql]
508 505 class=rhodecode.lib.colored_formatter.ColorFormatterSql
509 506 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
510 507 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,510 +1,507 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. Don't change that to more than 1
54 54 #workers = 1
55 55 ## process name
56 56 #proc_name = rhodecode
57 57 ## type of worker class, one of sync, eventlet, gevent, tornado
58 58 ## recommended for bigger setup is using of of other than sync one
59 59 #worker-class = sync
60 60 #max-requests = 5
61 61
62 62 ## COMMON ##
63 63 host = 127.0.0.1
64 64 port = 5000
65 65
66 66 ## prefix middleware for rc
67 67 #[filter:proxy-prefix]
68 68 #use = egg:PasteDeploy#prefix
69 69 #prefix = /<your-prefix>
70 70
71 71 [app:main]
72 72 use = egg:rhodecode
73 73 ## enable proxy prefix middleware
74 74 #filter-with = proxy-prefix
75 75
76 76 full_stack = true
77 77 static_files = true
78 78 ## Optional Languages
79 79 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
80 80 lang = en
81 81 cache_dir = %(here)s/data
82 82 index_dir = %(here)s/data/index
83 83
84 84 ## perform a full repository scan on each server start, this should be
85 85 ## set to false after first startup, to allow faster server restarts.
86 86 initial_repo_scan = true
87 87
88 88 ## uncomment and set this path to use archive download cache
89 89 #archive_cache_dir = /tmp/tarballcache
90 90
91 91 ## change this to unique ID for security
92 92 app_instance_uuid = rc-production
93 93
94 94 ## cut off limit for large diffs (size in bytes)
95 95 cut_off_limit = 256000
96 96
97 97 ## use cache version of scm repo everywhere
98 98 vcs_full_cache = true
99 99
100 100 ## force https in RhodeCode, fixes https redirects, assumes it's always https
101 101 force_https = false
102 102
103 103 ## use Strict-Transport-Security headers
104 104 use_htsts = false
105 105
106 106 ## number of commits stats will parse on each iteration
107 107 commit_parse_limit = 25
108 108
109 ## number of items displayed in lightweight dashboard before paginating is shown
110 dashboard_items = 100
111
112 109 ## use gravatar service to display avatars
113 110 use_gravatar = true
114 111
115 112 ## path to git executable
116 113 git_path = git
117 114
118 115 ## git rev filter option, --all is the default filter, if you need to
119 116 ## hide all refs in changelog switch this to --branches --tags
120 117 git_rev_filter=--all
121 118
122 119 ## RSS feed options
123 120 rss_cut_off_limit = 256000
124 121 rss_items_per_page = 10
125 122 rss_include_diff = false
126 123
127 124 ## options for showing and identifying changesets
128 125 show_sha_length = 12
129 126 show_revision_number = true
130 127
131 128 ## gist URL alias, used to create nicer urls for gist. This should be an
132 129 ## url that does rewrites to _admin/gists/<gistid>.
133 130 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
134 131 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
135 132 gist_alias_url =
136 133
137 134 ## white list of API enabled controllers. This allows to add list of
138 135 ## controllers to which access will be enabled by api_key. eg: to enable
139 136 ## api access to raw_files put `FilesController:raw`, to enable access to patches
140 137 ## add `ChangesetController:changeset_patch`. This list should be "," separated
141 138 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
142 139 api_access_controllers_whitelist =
143 140
144 141 ## alternative_gravatar_url allows you to use your own avatar server application
145 142 ## the following parts of the URL will be replaced
146 143 ## {email} user email
147 144 ## {md5email} md5 hash of the user email (like at gravatar.com)
148 145 ## {size} size of the image that is expected from the server application
149 146 ## {scheme} http/https from RhodeCode server
150 147 ## {netloc} network location from RhodeCode server
151 148 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
152 149 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
153 150
154 151
155 152 ## container auth options
156 153 container_auth_enabled = false
157 154 proxypass_auth_enabled = false
158 155
159 156 ## default encoding used to convert from and to unicode
160 157 ## can be also a comma seperated list of encoding in case of mixed encodings
161 158 default_encoding = utf8
162 159
163 160 ## overwrite schema of clone url
164 161 ## available vars:
165 162 ## scheme - http/https
166 163 ## user - current user
167 164 ## pass - password
168 165 ## netloc - network location
169 166 ## path - usually repo_name
170 167
171 168 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
172 169
173 170 ## issue tracking mapping for commits messages
174 171 ## comment out issue_pat, issue_server, issue_prefix to enable
175 172
176 173 ## pattern to get the issues from commit messages
177 174 ## default one used here is #<numbers> with a regex passive group for `#`
178 175 ## {id} will be all groups matched from this pattern
179 176
180 177 issue_pat = (?:\s*#)(\d+)
181 178
182 179 ## server url to the issue, each {id} will be replaced with match
183 180 ## fetched from the regex and {repo} is replaced with full repository name
184 181 ## including groups {repo_name} is replaced with just name of repo
185 182
186 183 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
187 184
188 185 ## prefix to add to link to indicate it's an url
189 186 ## #314 will be replaced by <issue_prefix><id>
190 187
191 188 issue_prefix = #
192 189
193 190 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
194 191 ## multiple patterns, to other issues server, wiki or others
195 192 ## below an example how to create a wiki pattern
196 193 # #wiki-some-id -> https://mywiki.com/some-id
197 194
198 195 #issue_pat_wiki = (?:wiki-)(.+)
199 196 #issue_server_link_wiki = https://mywiki.com/{id}
200 197 #issue_prefix_wiki = WIKI-
201 198
202 199
203 200 ## instance-id prefix
204 201 ## a prefix key for this instance used for cache invalidation when running
205 202 ## multiple instances of rhodecode, make sure it's globally unique for
206 203 ## all running rhodecode instances. Leave empty if you don't use it
207 204 instance_id =
208 205
209 206 ## alternative return HTTP header for failed authentication. Default HTTP
210 207 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
211 208 ## handling that. Set this variable to 403 to return HTTPForbidden
212 209 auth_ret_code =
213 210
214 211 ## locking return code. When repository is locked return this HTTP code. 2XX
215 212 ## codes don't break the transactions while 4XX codes do
216 213 lock_ret_code = 423
217 214
218 215
219 216 ####################################
220 217 ### CELERY CONFIG ####
221 218 ####################################
222 219 use_celery = false
223 220 broker.host = localhost
224 221 broker.vhost = rabbitmqhost
225 222 broker.port = 5672
226 223 broker.user = rabbitmq
227 224 broker.password = qweqwe
228 225
229 226 celery.imports = rhodecode.lib.celerylib.tasks
230 227
231 228 celery.result.backend = amqp
232 229 celery.result.dburi = amqp://
233 230 celery.result.serialier = json
234 231
235 232 #celery.send.task.error.emails = true
236 233 #celery.amqp.task.result.expires = 18000
237 234
238 235 celeryd.concurrency = 2
239 236 #celeryd.log.file = celeryd.log
240 237 celeryd.log.level = debug
241 238 celeryd.max.tasks.per.child = 1
242 239
243 240 ## tasks will never be sent to the queue, but executed locally instead.
244 241 celery.always.eager = false
245 242
246 243 ####################################
247 244 ### BEAKER CACHE ####
248 245 ####################################
249 246 beaker.cache.data_dir=%(here)s/data/cache/data
250 247 beaker.cache.lock_dir=%(here)s/data/cache/lock
251 248
252 249 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
253 250
254 251 beaker.cache.super_short_term.type=memory
255 252 beaker.cache.super_short_term.expire=10
256 253 beaker.cache.super_short_term.key_length = 256
257 254
258 255 beaker.cache.short_term.type=memory
259 256 beaker.cache.short_term.expire=60
260 257 beaker.cache.short_term.key_length = 256
261 258
262 259 beaker.cache.long_term.type=memory
263 260 beaker.cache.long_term.expire=36000
264 261 beaker.cache.long_term.key_length = 256
265 262
266 263 beaker.cache.sql_cache_short.type=memory
267 264 beaker.cache.sql_cache_short.expire=10
268 265 beaker.cache.sql_cache_short.key_length = 256
269 266
270 267 beaker.cache.sql_cache_med.type=memory
271 268 beaker.cache.sql_cache_med.expire=360
272 269 beaker.cache.sql_cache_med.key_length = 256
273 270
274 271 beaker.cache.sql_cache_long.type=file
275 272 beaker.cache.sql_cache_long.expire=3600
276 273 beaker.cache.sql_cache_long.key_length = 256
277 274
278 275 ####################################
279 276 ### BEAKER SESSION ####
280 277 ####################################
281 278 ## Type of storage used for the session, current types are
282 279 ## dbm, file, memcached, database, and memory.
283 280 ## The storage uses the Container API
284 281 ## that is also used by the cache system.
285 282
286 283 ## db session ##
287 284 #beaker.session.type = ext:database
288 285 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
289 286 #beaker.session.table_name = db_session
290 287
291 288 ## encrypted cookie client side session, good for many instances ##
292 289 #beaker.session.type = cookie
293 290
294 291 ## file based cookies (default) ##
295 292 #beaker.session.type = file
296 293
297 294
298 295 beaker.session.key = rhodecode
299 296 ## secure cookie requires AES python libraries
300 297 #beaker.session.encrypt_key = <key_for_encryption>
301 298 #beaker.session.validate_key = <validation_key>
302 299
303 300 ## sets session as invalid if it haven't been accessed for given amount of time
304 301 beaker.session.timeout = 2592000
305 302 beaker.session.httponly = true
306 303 #beaker.session.cookie_path = /<your-prefix>
307 304
308 305 ## uncomment for https secure cookie
309 306 beaker.session.secure = false
310 307
311 308 ## auto save the session to not to use .save()
312 309 beaker.session.auto = False
313 310
314 311 ## default cookie expiration time in seconds `true` expire at browser close ##
315 312 #beaker.session.cookie_expires = 3600
316 313
317 314
318 315 ############################
319 316 ## ERROR HANDLING SYSTEMS ##
320 317 ############################
321 318
322 319 ####################
323 320 ### [errormator] ###
324 321 ####################
325 322
326 323 ## Errormator is tailored to work with RhodeCode, see
327 324 ## http://errormator.com for details how to obtain an account
328 325 ## you must install python package `errormator_client` to make it work
329 326
330 327 ## errormator enabled
331 328 errormator = false
332 329
333 330 errormator.server_url = https://api.errormator.com
334 331 errormator.api_key = YOUR_API_KEY
335 332
336 333 ## TWEAK AMOUNT OF INFO SENT HERE
337 334
338 335 ## enables 404 error logging (default False)
339 336 errormator.report_404 = false
340 337
341 338 ## time in seconds after request is considered being slow (default 1)
342 339 errormator.slow_request_time = 1
343 340
344 341 ## record slow requests in application
345 342 ## (needs to be enabled for slow datastore recording and time tracking)
346 343 errormator.slow_requests = true
347 344
348 345 ## enable hooking to application loggers
349 346 # errormator.logging = true
350 347
351 348 ## minimum log level for log capture
352 349 # errormator.logging.level = WARNING
353 350
354 351 ## send logs only from erroneous/slow requests
355 352 ## (saves API quota for intensive logging)
356 353 errormator.logging_on_error = false
357 354
358 355 ## list of additonal keywords that should be grabbed from environ object
359 356 ## can be string with comma separated list of words in lowercase
360 357 ## (by default client will always send following info:
361 358 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
362 359 ## start with HTTP* this list be extended with additional keywords here
363 360 errormator.environ_keys_whitelist =
364 361
365 362
366 363 ## list of keywords that should be blanked from request object
367 364 ## can be string with comma separated list of words in lowercase
368 365 ## (by default client will always blank keys that contain following words
369 366 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
370 367 ## this list be extended with additional keywords set here
371 368 errormator.request_keys_blacklist =
372 369
373 370
374 371 ## list of namespaces that should be ignores when gathering log entries
375 372 ## can be string with comma separated list of namespaces
376 373 ## (by default the client ignores own entries: errormator_client.client)
377 374 errormator.log_namespace_blacklist =
378 375
379 376
380 377 ################
381 378 ### [sentry] ###
382 379 ################
383 380
384 381 ## sentry is a alternative open source error aggregator
385 382 ## you must install python packages `sentry` and `raven` to enable
386 383
387 384 sentry.dsn = YOUR_DNS
388 385 sentry.servers =
389 386 sentry.name =
390 387 sentry.key =
391 388 sentry.public_key =
392 389 sentry.secret_key =
393 390 sentry.project =
394 391 sentry.site =
395 392 sentry.include_paths =
396 393 sentry.exclude_paths =
397 394
398 395
399 396 ################################################################################
400 397 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
401 398 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
402 399 ## execute malicious code after an exception is raised. ##
403 400 ################################################################################
404 401 set debug = false
405 402
406 403 ##################################
407 404 ### LOGVIEW CONFIG ###
408 405 ##################################
409 406 logview.sqlalchemy = #faa
410 407 logview.pylons.templating = #bfb
411 408 logview.pylons.util = #eee
412 409
413 410 #########################################################
414 411 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
415 412 #########################################################
416 413 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
417 414 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
418 415 sqlalchemy.db1.echo = false
419 416 sqlalchemy.db1.pool_recycle = 3600
420 417 sqlalchemy.db1.convert_unicode = true
421 418
422 419 ################################
423 420 ### LOGGING CONFIGURATION ####
424 421 ################################
425 422 [loggers]
426 423 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
427 424
428 425 [handlers]
429 426 keys = console, console_sql
430 427
431 428 [formatters]
432 429 keys = generic, color_formatter, color_formatter_sql
433 430
434 431 #############
435 432 ## LOGGERS ##
436 433 #############
437 434 [logger_root]
438 435 level = NOTSET
439 436 handlers = console
440 437
441 438 [logger_routes]
442 439 level = DEBUG
443 440 handlers =
444 441 qualname = routes.middleware
445 442 ## "level = DEBUG" logs the route matched and routing variables.
446 443 propagate = 1
447 444
448 445 [logger_beaker]
449 446 level = DEBUG
450 447 handlers =
451 448 qualname = beaker.container
452 449 propagate = 1
453 450
454 451 [logger_templates]
455 452 level = INFO
456 453 handlers =
457 454 qualname = pylons.templating
458 455 propagate = 1
459 456
460 457 [logger_rhodecode]
461 458 level = DEBUG
462 459 handlers =
463 460 qualname = rhodecode
464 461 propagate = 1
465 462
466 463 [logger_sqlalchemy]
467 464 level = INFO
468 465 handlers = console_sql
469 466 qualname = sqlalchemy.engine
470 467 propagate = 0
471 468
472 469 [logger_whoosh_indexer]
473 470 level = DEBUG
474 471 handlers =
475 472 qualname = whoosh_indexer
476 473 propagate = 1
477 474
478 475 ##############
479 476 ## HANDLERS ##
480 477 ##############
481 478
482 479 [handler_console]
483 480 class = StreamHandler
484 481 args = (sys.stderr,)
485 482 level = INFO
486 483 formatter = generic
487 484
488 485 [handler_console_sql]
489 486 class = StreamHandler
490 487 args = (sys.stderr,)
491 488 level = WARN
492 489 formatter = generic
493 490
494 491 ################
495 492 ## FORMATTERS ##
496 493 ################
497 494
498 495 [formatter_generic]
499 496 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
500 497 datefmt = %Y-%m-%d %H:%M:%S
501 498
502 499 [formatter_color_formatter]
503 500 class=rhodecode.lib.colored_formatter.ColorFormatter
504 501 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
505 502 datefmt = %Y-%m-%d %H:%M:%S
506 503
507 504 [formatter_color_formatter_sql]
508 505 class=rhodecode.lib.colored_formatter.ColorFormatterSql
509 506 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
510 507 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,520 +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. Don't change that to more than 1
54 54 #workers = 1
55 55 ## process name
56 56 #proc_name = rhodecode
57 57 ## type of worker class, one of sync, eventlet, gevent, tornado
58 58 ## recommended for bigger setup is using of of other than sync one
59 59 #worker-class = sync
60 60 #max-requests = 5
61 61
62 62 ## COMMON ##
63 63 host = 127.0.0.1
64 64 port = 5000
65 65
66 66 ## prefix middleware for rc
67 67 #[filter:proxy-prefix]
68 68 #use = egg:PasteDeploy#prefix
69 69 #prefix = /<your-prefix>
70 70
71 71 [app:main]
72 72 use = egg:rhodecode
73 73 ## enable proxy prefix middleware
74 74 #filter-with = proxy-prefix
75 75
76 76 full_stack = true
77 77 static_files = true
78 78 ## Optional Languages
79 79 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
80 80 lang = en
81 81 cache_dir = %(here)s/data
82 82 index_dir = %(here)s/data/index
83 83
84 84 ## perform a full repository scan on each server start, this should be
85 85 ## set to false after first startup, to allow faster server restarts.
86 86 initial_repo_scan = true
87 87
88 88 ## uncomment and set this path to use archive download cache
89 89 #archive_cache_dir = /tmp/tarballcache
90 90
91 91 ## change this to unique ID for security
92 92 app_instance_uuid = ${app_instance_uuid}
93 93
94 94 ## cut off limit for large diffs (size in bytes)
95 95 cut_off_limit = 256000
96 96
97 97 ## use cache version of scm repo everywhere
98 98 vcs_full_cache = true
99 99
100 100 ## force https in RhodeCode, fixes https redirects, assumes it's always https
101 101 force_https = false
102 102
103 103 ## use Strict-Transport-Security headers
104 104 use_htsts = false
105 105
106 106 ## number of commits stats will parse on each iteration
107 107 commit_parse_limit = 25
108 108
109 ## number of items displayed in lightweight dashboard before paginating is shown
110 dashboard_items = 100
111
112 109 ## use gravatar service to display avatars
113 110 use_gravatar = true
114 111
115 112 ## path to git executable
116 113 git_path = git
117 114
118 115 ## git rev filter option, --all is the default filter, if you need to
119 116 ## hide all refs in changelog switch this to --branches --tags
120 117 git_rev_filter=--all
121 118
122 119 ## RSS feed options
123 120 rss_cut_off_limit = 256000
124 121 rss_items_per_page = 10
125 122 rss_include_diff = false
126 123
127 124 ## options for showing and identifying changesets
128 125 show_sha_length = 12
129 126 show_revision_number = true
130 127
131 128 ## gist URL alias, used to create nicer urls for gist. This should be an
132 129 ## url that does rewrites to _admin/gists/<gistid>.
133 130 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
134 131 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
135 132 gist_alias_url =
136 133
137 134 ## white list of API enabled controllers. This allows to add list of
138 135 ## controllers to which access will be enabled by api_key. eg: to enable
139 136 ## api access to raw_files put `FilesController:raw`, to enable access to patches
140 137 ## add `ChangesetController:changeset_patch`. This list should be "," separated
141 138 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
142 139 api_access_controllers_whitelist =
143 140
144 141 ## alternative_gravatar_url allows you to use your own avatar server application
145 142 ## the following parts of the URL will be replaced
146 143 ## {email} user email
147 144 ## {md5email} md5 hash of the user email (like at gravatar.com)
148 145 ## {size} size of the image that is expected from the server application
149 146 ## {scheme} http/https from RhodeCode server
150 147 ## {netloc} network location from RhodeCode server
151 148 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
152 149 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
153 150
154 151
155 152 ## container auth options
156 153 container_auth_enabled = false
157 154 proxypass_auth_enabled = false
158 155
159 156 ## default encoding used to convert from and to unicode
160 157 ## can be also a comma seperated list of encoding in case of mixed encodings
161 158 default_encoding = utf8
162 159
163 160 ## overwrite schema of clone url
164 161 ## available vars:
165 162 ## scheme - http/https
166 163 ## user - current user
167 164 ## pass - password
168 165 ## netloc - network location
169 166 ## path - usually repo_name
170 167
171 168 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
172 169
173 170 ## issue tracking mapping for commits messages
174 171 ## comment out issue_pat, issue_server, issue_prefix to enable
175 172
176 173 ## pattern to get the issues from commit messages
177 174 ## default one used here is #<numbers> with a regex passive group for `#`
178 175 ## {id} will be all groups matched from this pattern
179 176
180 177 issue_pat = (?:\s*#)(\d+)
181 178
182 179 ## server url to the issue, each {id} will be replaced with match
183 180 ## fetched from the regex and {repo} is replaced with full repository name
184 181 ## including groups {repo_name} is replaced with just name of repo
185 182
186 183 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
187 184
188 185 ## prefix to add to link to indicate it's an url
189 186 ## #314 will be replaced by <issue_prefix><id>
190 187
191 188 issue_prefix = #
192 189
193 190 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
194 191 ## multiple patterns, to other issues server, wiki or others
195 192 ## below an example how to create a wiki pattern
196 193 # #wiki-some-id -> https://mywiki.com/some-id
197 194
198 195 #issue_pat_wiki = (?:wiki-)(.+)
199 196 #issue_server_link_wiki = https://mywiki.com/{id}
200 197 #issue_prefix_wiki = WIKI-
201 198
202 199
203 200 ## instance-id prefix
204 201 ## a prefix key for this instance used for cache invalidation when running
205 202 ## multiple instances of rhodecode, make sure it's globally unique for
206 203 ## all running rhodecode instances. Leave empty if you don't use it
207 204 instance_id =
208 205
209 206 ## alternative return HTTP header for failed authentication. Default HTTP
210 207 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
211 208 ## handling that. Set this variable to 403 to return HTTPForbidden
212 209 auth_ret_code =
213 210
214 211 ## locking return code. When repository is locked return this HTTP code. 2XX
215 212 ## codes don't break the transactions while 4XX codes do
216 213 lock_ret_code = 423
217 214
218 215
219 216 ####################################
220 217 ### CELERY CONFIG ####
221 218 ####################################
222 219 use_celery = false
223 220 broker.host = localhost
224 221 broker.vhost = rabbitmqhost
225 222 broker.port = 5672
226 223 broker.user = rabbitmq
227 224 broker.password = qweqwe
228 225
229 226 celery.imports = rhodecode.lib.celerylib.tasks
230 227
231 228 celery.result.backend = amqp
232 229 celery.result.dburi = amqp://
233 230 celery.result.serialier = json
234 231
235 232 #celery.send.task.error.emails = true
236 233 #celery.amqp.task.result.expires = 18000
237 234
238 235 celeryd.concurrency = 2
239 236 #celeryd.log.file = celeryd.log
240 237 celeryd.log.level = debug
241 238 celeryd.max.tasks.per.child = 1
242 239
243 240 ## tasks will never be sent to the queue, but executed locally instead.
244 241 celery.always.eager = false
245 242
246 243 ####################################
247 244 ### BEAKER CACHE ####
248 245 ####################################
249 246 beaker.cache.data_dir=%(here)s/data/cache/data
250 247 beaker.cache.lock_dir=%(here)s/data/cache/lock
251 248
252 249 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
253 250
254 251 beaker.cache.super_short_term.type=memory
255 252 beaker.cache.super_short_term.expire=10
256 253 beaker.cache.super_short_term.key_length = 256
257 254
258 255 beaker.cache.short_term.type=memory
259 256 beaker.cache.short_term.expire=60
260 257 beaker.cache.short_term.key_length = 256
261 258
262 259 beaker.cache.long_term.type=memory
263 260 beaker.cache.long_term.expire=36000
264 261 beaker.cache.long_term.key_length = 256
265 262
266 263 beaker.cache.sql_cache_short.type=memory
267 264 beaker.cache.sql_cache_short.expire=10
268 265 beaker.cache.sql_cache_short.key_length = 256
269 266
270 267 beaker.cache.sql_cache_med.type=memory
271 268 beaker.cache.sql_cache_med.expire=360
272 269 beaker.cache.sql_cache_med.key_length = 256
273 270
274 271 beaker.cache.sql_cache_long.type=file
275 272 beaker.cache.sql_cache_long.expire=3600
276 273 beaker.cache.sql_cache_long.key_length = 256
277 274
278 275 ####################################
279 276 ### BEAKER SESSION ####
280 277 ####################################
281 278 ## Type of storage used for the session, current types are
282 279 ## dbm, file, memcached, database, and memory.
283 280 ## The storage uses the Container API
284 281 ## that is also used by the cache system.
285 282
286 283 ## db session ##
287 284 #beaker.session.type = ext:database
288 285 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
289 286 #beaker.session.table_name = db_session
290 287
291 288 ## encrypted cookie client side session, good for many instances ##
292 289 #beaker.session.type = cookie
293 290
294 291 ## file based cookies (default) ##
295 292 #beaker.session.type = file
296 293
297 294
298 295 beaker.session.key = rhodecode
299 296 ## secure cookie requires AES python libraries
300 297 #beaker.session.encrypt_key = <key_for_encryption>
301 298 #beaker.session.validate_key = <validation_key>
302 299
303 300 ## sets session as invalid if it haven't been accessed for given amount of time
304 301 beaker.session.timeout = 2592000
305 302 beaker.session.httponly = true
306 303 #beaker.session.cookie_path = /<your-prefix>
307 304
308 305 ## uncomment for https secure cookie
309 306 beaker.session.secure = false
310 307
311 308 ## auto save the session to not to use .save()
312 309 beaker.session.auto = False
313 310
314 311 ## default cookie expiration time in seconds `true` expire at browser close ##
315 312 #beaker.session.cookie_expires = 3600
316 313
317 314
318 315 ############################
319 316 ## ERROR HANDLING SYSTEMS ##
320 317 ############################
321 318
322 319 ####################
323 320 ### [errormator] ###
324 321 ####################
325 322
326 323 ## Errormator is tailored to work with RhodeCode, see
327 324 ## http://errormator.com for details how to obtain an account
328 325 ## you must install python package `errormator_client` to make it work
329 326
330 327 ## errormator enabled
331 328 errormator = false
332 329
333 330 errormator.server_url = https://api.errormator.com
334 331 errormator.api_key = YOUR_API_KEY
335 332
336 333 ## TWEAK AMOUNT OF INFO SENT HERE
337 334
338 335 ## enables 404 error logging (default False)
339 336 errormator.report_404 = false
340 337
341 338 ## time in seconds after request is considered being slow (default 1)
342 339 errormator.slow_request_time = 1
343 340
344 341 ## record slow requests in application
345 342 ## (needs to be enabled for slow datastore recording and time tracking)
346 343 errormator.slow_requests = true
347 344
348 345 ## enable hooking to application loggers
349 346 # errormator.logging = true
350 347
351 348 ## minimum log level for log capture
352 349 # errormator.logging.level = WARNING
353 350
354 351 ## send logs only from erroneous/slow requests
355 352 ## (saves API quota for intensive logging)
356 353 errormator.logging_on_error = false
357 354
358 355 ## list of additonal keywords that should be grabbed from environ object
359 356 ## can be string with comma separated list of words in lowercase
360 357 ## (by default client will always send following info:
361 358 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
362 359 ## start with HTTP* this list be extended with additional keywords here
363 360 errormator.environ_keys_whitelist =
364 361
365 362
366 363 ## list of keywords that should be blanked from request object
367 364 ## can be string with comma separated list of words in lowercase
368 365 ## (by default client will always blank keys that contain following words
369 366 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
370 367 ## this list be extended with additional keywords set here
371 368 errormator.request_keys_blacklist =
372 369
373 370
374 371 ## list of namespaces that should be ignores when gathering log entries
375 372 ## can be string with comma separated list of namespaces
376 373 ## (by default the client ignores own entries: errormator_client.client)
377 374 errormator.log_namespace_blacklist =
378 375
379 376
380 377 ################
381 378 ### [sentry] ###
382 379 ################
383 380
384 381 ## sentry is a alternative open source error aggregator
385 382 ## you must install python packages `sentry` and `raven` to enable
386 383
387 384 sentry.dsn = YOUR_DNS
388 385 sentry.servers =
389 386 sentry.name =
390 387 sentry.key =
391 388 sentry.public_key =
392 389 sentry.secret_key =
393 390 sentry.project =
394 391 sentry.site =
395 392 sentry.include_paths =
396 393 sentry.exclude_paths =
397 394
398 395
399 396 ################################################################################
400 397 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
401 398 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
402 399 ## execute malicious code after an exception is raised. ##
403 400 ################################################################################
404 401 set debug = false
405 402
406 403 ##################################
407 404 ### LOGVIEW CONFIG ###
408 405 ##################################
409 406 logview.sqlalchemy = #faa
410 407 logview.pylons.templating = #bfb
411 408 logview.pylons.util = #eee
412 409
413 410 #########################################################
414 411 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
415 412 #########################################################
416 413
417 414 # SQLITE [default]
418 415 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
419 416
420 417 # POSTGRESQL
421 418 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
422 419
423 420 # MySQL
424 421 # sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
425 422
426 423 # see sqlalchemy docs for others
427 424
428 425 sqlalchemy.db1.echo = false
429 426 sqlalchemy.db1.pool_recycle = 3600
430 427 sqlalchemy.db1.convert_unicode = true
431 428
432 429 ################################
433 430 ### LOGGING CONFIGURATION ####
434 431 ################################
435 432 [loggers]
436 433 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
437 434
438 435 [handlers]
439 436 keys = console, console_sql
440 437
441 438 [formatters]
442 439 keys = generic, color_formatter, color_formatter_sql
443 440
444 441 #############
445 442 ## LOGGERS ##
446 443 #############
447 444 [logger_root]
448 445 level = NOTSET
449 446 handlers = console
450 447
451 448 [logger_routes]
452 449 level = DEBUG
453 450 handlers =
454 451 qualname = routes.middleware
455 452 ## "level = DEBUG" logs the route matched and routing variables.
456 453 propagate = 1
457 454
458 455 [logger_beaker]
459 456 level = DEBUG
460 457 handlers =
461 458 qualname = beaker.container
462 459 propagate = 1
463 460
464 461 [logger_templates]
465 462 level = INFO
466 463 handlers =
467 464 qualname = pylons.templating
468 465 propagate = 1
469 466
470 467 [logger_rhodecode]
471 468 level = DEBUG
472 469 handlers =
473 470 qualname = rhodecode
474 471 propagate = 1
475 472
476 473 [logger_sqlalchemy]
477 474 level = INFO
478 475 handlers = console_sql
479 476 qualname = sqlalchemy.engine
480 477 propagate = 0
481 478
482 479 [logger_whoosh_indexer]
483 480 level = DEBUG
484 481 handlers =
485 482 qualname = whoosh_indexer
486 483 propagate = 1
487 484
488 485 ##############
489 486 ## HANDLERS ##
490 487 ##############
491 488
492 489 [handler_console]
493 490 class = StreamHandler
494 491 args = (sys.stderr,)
495 492 level = INFO
496 493 formatter = generic
497 494
498 495 [handler_console_sql]
499 496 class = StreamHandler
500 497 args = (sys.stderr,)
501 498 level = WARN
502 499 formatter = generic
503 500
504 501 ################
505 502 ## FORMATTERS ##
506 503 ################
507 504
508 505 [formatter_generic]
509 506 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
510 507 datefmt = %Y-%m-%d %H:%M:%S
511 508
512 509 [formatter_color_formatter]
513 510 class=rhodecode.lib.colored_formatter.ColorFormatter
514 511 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
515 512 datefmt = %Y-%m-%d %H:%M:%S
516 513
517 514 [formatter_color_formatter_sql]
518 515 class=rhodecode.lib.colored_formatter.ColorFormatterSql
519 516 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
520 517 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,508 +1,514 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.settings
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 settings controller for rhodecode admin
7 7
8 8 :created_on: Jul 14, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29 import pkg_resources
30 30 import platform
31 31
32 32 from sqlalchemy import func
33 33 from formencode import htmlfill
34 34 from pylons import request, session, tmpl_context as c, url, config
35 35 from pylons.controllers.util import abort, redirect
36 36 from pylons.i18n.translation import _
37 37
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 HasPermissionAnyDecorator, NotAnonymous, HasPermissionAny,\
41 41 HasReposGroupPermissionAll, HasReposGroupPermissionAny, AuthUser
42 42 from rhodecode.lib.base import BaseController, render
43 43 from rhodecode.lib.celerylib import tasks, run_task
44 44 from rhodecode.lib.utils import repo2db_mapper, set_rhodecode_config, \
45 45 check_git_version
46 46 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
47 47 RhodeCodeSetting, PullRequest, PullRequestReviewers
48 48 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
49 49 ApplicationUiSettingsForm, ApplicationVisualisationForm
50 50 from rhodecode.model.scm import ScmModel, RepoGroupList
51 51 from rhodecode.model.user import UserModel
52 52 from rhodecode.model.repo import RepoModel
53 53 from rhodecode.model.db import User
54 54 from rhodecode.model.notification import EmailNotificationModel
55 55 from rhodecode.model.meta import Session
56 56 from rhodecode.lib.utils2 import str2bool, safe_unicode
57 57 from rhodecode.lib.compat import json
58 58 log = logging.getLogger(__name__)
59 59
60 60
61 61 class SettingsController(BaseController):
62 62 """REST Controller styled on the Atom Publishing Protocol"""
63 63 # To properly map this controller, ensure your config/routing.py
64 64 # file has a resource setup:
65 65 # map.resource('setting', 'settings', controller='admin/settings',
66 66 # path_prefix='/admin', name_prefix='admin_')
67 67
68 68 @LoginRequired()
69 69 def __before__(self):
70 70 super(SettingsController, self).__before__()
71 71 c.modules = sorted([(p.project_name, p.version)
72 72 for p in pkg_resources.working_set]
73 73 + [('git', check_git_version())],
74 74 key=lambda k: k[0].lower())
75 75 c.py_version = platform.python_version()
76 76 c.platform = platform.platform()
77 77
78 78 @HasPermissionAllDecorator('hg.admin')
79 79 def index(self, format='html'):
80 80 """GET /admin/settings: All items in the collection"""
81 81 # url('admin_settings')
82 82
83 83 defaults = RhodeCodeSetting.get_app_settings()
84 84 defaults.update(self._get_hg_ui_settings())
85 85
86 86 return htmlfill.render(
87 87 render('admin/settings/settings.html'),
88 88 defaults=defaults,
89 89 encoding="UTF-8",
90 90 force_defaults=False
91 91 )
92 92
93 93 @HasPermissionAllDecorator('hg.admin')
94 94 def create(self):
95 95 """POST /admin/settings: Create a new item"""
96 96 # url('admin_settings')
97 97
98 98 @HasPermissionAllDecorator('hg.admin')
99 99 def new(self, format='html'):
100 100 """GET /admin/settings/new: Form to create a new item"""
101 101 # url('admin_new_setting')
102 102
103 103 @HasPermissionAllDecorator('hg.admin')
104 104 def update(self, setting_id):
105 105 """PUT /admin/settings/setting_id: Update an existing item"""
106 106 # Forms posted to this method should contain a hidden field:
107 107 # <input type="hidden" name="_method" value="PUT" />
108 108 # Or using helpers:
109 109 # h.form(url('admin_setting', setting_id=ID),
110 110 # method='put')
111 111 # url('admin_setting', setting_id=ID)
112 112
113 113 if setting_id == 'mapping':
114 114 rm_obsolete = request.POST.get('destroy', False)
115 115 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
116 116 initial = ScmModel().repo_scan()
117 117 log.debug('invalidating all repositories')
118 118 for repo_name in initial.keys():
119 119 ScmModel().mark_for_invalidation(repo_name)
120 120
121 121 added, removed = repo2db_mapper(initial, rm_obsolete)
122 122 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
123 123 h.flash(_('Repositories successfully '
124 124 'rescanned added: %s ; removed: %s') %
125 125 (_repr(added), _repr(removed)),
126 126 category='success')
127 127
128 128 if setting_id == 'whoosh':
129 129 repo_location = self._get_hg_ui_settings()['paths_root_path']
130 130 full_index = request.POST.get('full_index', False)
131 131 run_task(tasks.whoosh_index, repo_location, full_index)
132 132 h.flash(_('Whoosh reindex task scheduled'), category='success')
133 133
134 134 if setting_id == 'global':
135 135
136 136 application_form = ApplicationSettingsForm()()
137 137 try:
138 138 form_result = application_form.to_python(dict(request.POST))
139 139 except formencode.Invalid, errors:
140 140 return htmlfill.render(
141 141 render('admin/settings/settings.html'),
142 142 defaults=errors.value,
143 143 errors=errors.error_dict or {},
144 144 prefix_error=False,
145 145 encoding="UTF-8"
146 146 )
147 147
148 148 try:
149 149 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
150 150 sett1.app_settings_value = form_result['rhodecode_title']
151 151 Session().add(sett1)
152 152
153 153 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
154 154 sett2.app_settings_value = form_result['rhodecode_realm']
155 155 Session().add(sett2)
156 156
157 157 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
158 158 sett3.app_settings_value = form_result['rhodecode_ga_code']
159 159 Session().add(sett3)
160 160
161 161 Session().commit()
162 162 set_rhodecode_config(config)
163 163 h.flash(_('Updated application settings'), category='success')
164 164
165 165 except Exception:
166 166 log.error(traceback.format_exc())
167 167 h.flash(_('Error occurred during updating '
168 168 'application settings'),
169 169 category='error')
170 170
171 171 if setting_id == 'visual':
172 172
173 173 application_form = ApplicationVisualisationForm()()
174 174 try:
175 175 form_result = application_form.to_python(dict(request.POST))
176 176 except formencode.Invalid, errors:
177 177 return htmlfill.render(
178 178 render('admin/settings/settings.html'),
179 179 defaults=errors.value,
180 180 errors=errors.error_dict or {},
181 181 prefix_error=False,
182 182 encoding="UTF-8"
183 183 )
184 184
185 185 try:
186 #TODO: rewrite this to something less ugly
186 187 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
187 188 sett1.app_settings_value = \
188 189 form_result['rhodecode_show_public_icon']
189 190 Session().add(sett1)
190 191
191 192 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
192 193 sett2.app_settings_value = \
193 194 form_result['rhodecode_show_private_icon']
194 195 Session().add(sett2)
195 196
196 197 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
197 198 sett3.app_settings_value = \
198 199 form_result['rhodecode_stylify_metatags']
199 200 Session().add(sett3)
200 201
201 202 sett4 = RhodeCodeSetting.get_by_name_or_create('repository_fields')
202 203 sett4.app_settings_value = \
203 204 form_result['rhodecode_repository_fields']
204 205 Session().add(sett4)
205 206
207 sett5 = RhodeCodeSetting.get_by_name_or_create('dashboard_items')
208 sett5.app_settings_value = \
209 form_result['rhodecode_dashboard_items']
210 Session().add(sett5)
211
206 212 Session().commit()
207 213 set_rhodecode_config(config)
208 214 h.flash(_('Updated visualisation settings'),
209 215 category='success')
210 216
211 217 except Exception:
212 218 log.error(traceback.format_exc())
213 219 h.flash(_('Error occurred during updating '
214 220 'visualisation settings'),
215 221 category='error')
216 222
217 223 if setting_id == 'vcs':
218 224 application_form = ApplicationUiSettingsForm()()
219 225 try:
220 226 form_result = application_form.to_python(dict(request.POST))
221 227 except formencode.Invalid, errors:
222 228 return htmlfill.render(
223 229 render('admin/settings/settings.html'),
224 230 defaults=errors.value,
225 231 errors=errors.error_dict or {},
226 232 prefix_error=False,
227 233 encoding="UTF-8"
228 234 )
229 235
230 236 try:
231 237 sett = RhodeCodeUi.get_by_key('push_ssl')
232 238 sett.ui_value = form_result['web_push_ssl']
233 239 Session().add(sett)
234 240
235 241 sett = RhodeCodeUi.get_by_key('/')
236 242 sett.ui_value = form_result['paths_root_path']
237 243 Session().add(sett)
238 244
239 245 #HOOKS
240 246 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
241 247 sett.ui_active = form_result['hooks_changegroup_update']
242 248 Session().add(sett)
243 249
244 250 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
245 251 sett.ui_active = form_result['hooks_changegroup_repo_size']
246 252 Session().add(sett)
247 253
248 254 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
249 255 sett.ui_active = form_result['hooks_changegroup_push_logger']
250 256 Session().add(sett)
251 257
252 258 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
253 259 sett.ui_active = form_result['hooks_outgoing_pull_logger']
254 260
255 261 Session().add(sett)
256 262
257 263 ## EXTENSIONS
258 264 sett = RhodeCodeUi.get_by_key('largefiles')
259 265 if not sett:
260 266 #make one if it's not there !
261 267 sett = RhodeCodeUi()
262 268 sett.ui_key = 'largefiles'
263 269 sett.ui_section = 'extensions'
264 270 sett.ui_active = form_result['extensions_largefiles']
265 271 Session().add(sett)
266 272
267 273 sett = RhodeCodeUi.get_by_key('hgsubversion')
268 274 if not sett:
269 275 #make one if it's not there !
270 276 sett = RhodeCodeUi()
271 277 sett.ui_key = 'hgsubversion'
272 278 sett.ui_section = 'extensions'
273 279
274 280 sett.ui_active = form_result['extensions_hgsubversion']
275 281 Session().add(sett)
276 282
277 283 # sett = RhodeCodeUi.get_by_key('hggit')
278 284 # if not sett:
279 285 # #make one if it's not there !
280 286 # sett = RhodeCodeUi()
281 287 # sett.ui_key = 'hggit'
282 288 # sett.ui_section = 'extensions'
283 289 #
284 290 # sett.ui_active = form_result['extensions_hggit']
285 291 # Session().add(sett)
286 292
287 293 Session().commit()
288 294
289 295 h.flash(_('Updated VCS settings'), category='success')
290 296
291 297 except Exception:
292 298 log.error(traceback.format_exc())
293 299 h.flash(_('Error occurred during updating '
294 300 'application settings'), category='error')
295 301
296 302 if setting_id == 'hooks':
297 303 ui_key = request.POST.get('new_hook_ui_key')
298 304 ui_value = request.POST.get('new_hook_ui_value')
299 305 try:
300 306
301 307 if ui_value and ui_key:
302 308 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
303 309 h.flash(_('Added new hook'),
304 310 category='success')
305 311
306 312 # check for edits
307 313 update = False
308 314 _d = request.POST.dict_of_lists()
309 315 for k, v in zip(_d.get('hook_ui_key', []),
310 316 _d.get('hook_ui_value_new', [])):
311 317 RhodeCodeUi.create_or_update_hook(k, v)
312 318 update = True
313 319
314 320 if update:
315 321 h.flash(_('Updated hooks'), category='success')
316 322 Session().commit()
317 323 except Exception:
318 324 log.error(traceback.format_exc())
319 325 h.flash(_('Error occurred during hook creation'),
320 326 category='error')
321 327
322 328 return redirect(url('admin_edit_setting', setting_id='hooks'))
323 329
324 330 if setting_id == 'email':
325 331 test_email = request.POST.get('test_email')
326 332 test_email_subj = 'RhodeCode TestEmail'
327 333 test_email_body = 'RhodeCode Email test'
328 334
329 335 test_email_html_body = EmailNotificationModel()\
330 336 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
331 337 body=test_email_body)
332 338
333 339 recipients = [test_email] if test_email else None
334 340
335 341 run_task(tasks.send_email, recipients, test_email_subj,
336 342 test_email_body, test_email_html_body)
337 343
338 344 h.flash(_('Email task created'), category='success')
339 345 return redirect(url('admin_settings'))
340 346
341 347 @HasPermissionAllDecorator('hg.admin')
342 348 def delete(self, setting_id):
343 349 """DELETE /admin/settings/setting_id: Delete an existing item"""
344 350 # Forms posted to this method should contain a hidden field:
345 351 # <input type="hidden" name="_method" value="DELETE" />
346 352 # Or using helpers:
347 353 # h.form(url('admin_setting', setting_id=ID),
348 354 # method='delete')
349 355 # url('admin_setting', setting_id=ID)
350 356 if setting_id == 'hooks':
351 357 hook_id = request.POST.get('hook_id')
352 358 RhodeCodeUi.delete(hook_id)
353 359 Session().commit()
354 360
355 361 @HasPermissionAllDecorator('hg.admin')
356 362 def show(self, setting_id, format='html'):
357 363 """
358 364 GET /admin/settings/setting_id: Show a specific item"""
359 365 # url('admin_setting', setting_id=ID)
360 366
361 367 @HasPermissionAllDecorator('hg.admin')
362 368 def edit(self, setting_id, format='html'):
363 369 """
364 370 GET /admin/settings/setting_id/edit: Form to
365 371 edit an existing item"""
366 372 # url('admin_edit_setting', setting_id=ID)
367 373
368 374 c.hooks = RhodeCodeUi.get_builtin_hooks()
369 375 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
370 376
371 377 return htmlfill.render(
372 378 render('admin/settings/hooks.html'),
373 379 defaults={},
374 380 encoding="UTF-8",
375 381 force_defaults=False
376 382 )
377 383
378 384 def _load_my_repos_data(self):
379 385 repos_list = Session().query(Repository)\
380 386 .filter(Repository.user_id ==
381 387 self.rhodecode_user.user_id)\
382 388 .order_by(func.lower(Repository.repo_name)).all()
383 389
384 390 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
385 391 admin=True)
386 392 #json used to render the grid
387 393 return json.dumps(repos_data)
388 394
389 395 @NotAnonymous()
390 396 def my_account(self):
391 397 """
392 398 GET /_admin/my_account Displays info about my account
393 399 """
394 400 # url('admin_settings_my_account')
395 401
396 402 c.user = User.get(self.rhodecode_user.user_id)
397 403 c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
398 404 ip_addr=self.ip_addr)
399 405 c.ldap_dn = c.user.ldap_dn
400 406
401 407 if c.user.username == 'default':
402 408 h.flash(_("You can't edit this user since it's"
403 409 " crucial for entire application"), category='warning')
404 410 return redirect(url('users'))
405 411
406 412 #json used to render the grid
407 413 c.data = self._load_my_repos_data()
408 414
409 415 defaults = c.user.get_dict()
410 416
411 417 c.form = htmlfill.render(
412 418 render('admin/users/user_edit_my_account_form.html'),
413 419 defaults=defaults,
414 420 encoding="UTF-8",
415 421 force_defaults=False
416 422 )
417 423 return render('admin/users/user_edit_my_account.html')
418 424
419 425 @NotAnonymous()
420 426 def my_account_update(self):
421 427 """PUT /_admin/my_account_update: Update an existing item"""
422 428 # Forms posted to this method should contain a hidden field:
423 429 # <input type="hidden" name="_method" value="PUT" />
424 430 # Or using helpers:
425 431 # h.form(url('admin_settings_my_account_update'),
426 432 # method='put')
427 433 # url('admin_settings_my_account_update', id=ID)
428 434 uid = self.rhodecode_user.user_id
429 435 c.user = User.get(self.rhodecode_user.user_id)
430 436 c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
431 437 ip_addr=self.ip_addr)
432 438 c.ldap_dn = c.user.ldap_dn
433 439 email = self.rhodecode_user.email
434 440 _form = UserForm(edit=True,
435 441 old_data={'user_id': uid, 'email': email})()
436 442 form_result = {}
437 443 try:
438 444 form_result = _form.to_python(dict(request.POST))
439 445 skip_attrs = ['admin', 'active'] # skip attr for my account
440 446 if c.ldap_dn:
441 447 #forbid updating username for ldap accounts
442 448 skip_attrs.append('username')
443 449 UserModel().update(uid, form_result, skip_attrs=skip_attrs)
444 450 h.flash(_('Your account was updated successfully'),
445 451 category='success')
446 452 Session().commit()
447 453 except formencode.Invalid, errors:
448 454 #json used to render the grid
449 455 c.data = self._load_my_repos_data()
450 456 c.form = htmlfill.render(
451 457 render('admin/users/user_edit_my_account_form.html'),
452 458 defaults=errors.value,
453 459 errors=errors.error_dict or {},
454 460 prefix_error=False,
455 461 encoding="UTF-8")
456 462 return render('admin/users/user_edit_my_account.html')
457 463 except Exception:
458 464 log.error(traceback.format_exc())
459 465 h.flash(_('Error occurred during update of user %s') \
460 466 % form_result.get('username'), category='error')
461 467
462 468 return redirect(url('my_account'))
463 469
464 470 @NotAnonymous()
465 471 def my_account_my_pullrequests(self):
466 472 c.show_closed = request.GET.get('pr_show_closed')
467 473
468 474 def _filter(pr):
469 475 s = sorted(pr, key=lambda o: o.created_on, reverse=True)
470 476 if not c.show_closed:
471 477 s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
472 478 return s
473 479
474 480 c.my_pull_requests = _filter(PullRequest.query()\
475 481 .filter(PullRequest.user_id ==
476 482 self.rhodecode_user.user_id)\
477 483 .all())
478 484
479 485 c.participate_in_pull_requests = _filter([
480 486 x.pull_request for x in PullRequestReviewers.query()\
481 487 .filter(PullRequestReviewers.user_id ==
482 488 self.rhodecode_user.user_id).all()])
483 489
484 490 return render('admin/users/user_edit_my_account_pullrequests.html')
485 491
486 492 def _get_hg_ui_settings(self):
487 493 ret = RhodeCodeUi.query().all()
488 494
489 495 if not ret:
490 496 raise Exception('Could not get application ui settings !')
491 497 settings = {}
492 498 for each in ret:
493 499 k = each.ui_key
494 500 v = each.ui_value
495 501 if k == '/':
496 502 k = 'root_path'
497 503
498 504 if k == 'push_ssl':
499 505 v = str2bool(v)
500 506
501 507 if k.find('.') != -1:
502 508 k = k.replace('.', '_')
503 509
504 510 if each.ui_section in ['hooks', 'extensions']:
505 511 v = each.ui_active
506 512
507 513 settings[each.ui_section + '_' + k] = v
508 514 return settings
@@ -1,344 +1,345 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 mutliple 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 265 c.use_gravatar = str2bool(config.get('use_gravatar'))
266 266 c.ga_code = config.get('rhodecode_ga_code')
267 267 # Visual options
268 268 c.visual = AttributeDict({})
269 269 rc_config = RhodeCodeSetting.get_app_settings()
270
270 ## DB stored
271 271 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon'))
272 272 c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon'))
273 273 c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags'))
274 c.visual.dashboard_items = safe_int(config.get('dashboard_items', 100))
274 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100))
275 275 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
276 ## INI stored
277 self.cut_off_limit = int(config.get('cut_off_limit'))
278
276 279 c.repo_name = get_repo_slug(request) # can be empty
277 280 c.backends = BACKENDS.keys()
278 281 c.unread_notifications = NotificationModel()\
279 282 .get_unread_cnt_for_user(c.rhodecode_user.user_id)
280 self.cut_off_limit = int(config.get('cut_off_limit'))
281
282 283 self.sa = meta.Session
283 284 self.scm_model = ScmModel(self.sa)
284 285
285 286 def __call__(self, environ, start_response):
286 287 """Invoke the Controller"""
287 288 # WSGIController.__call__ dispatches to the Controller method
288 289 # the request is routed to. This routing information is
289 290 # available in environ['pylons.routes_dict']
290 291 try:
291 292 self.ip_addr = _get_ip_addr(environ)
292 293 # make sure that we update permissions each time we call controller
293 294 api_key = request.GET.get('api_key')
294 295 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
295 296 user_id = cookie_store.get('user_id', None)
296 297 username = get_container_username(environ, config)
297 298 auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
298 299 request.user = auth_user
299 300 self.rhodecode_user = c.rhodecode_user = auth_user
300 301 if not self.rhodecode_user.is_authenticated and \
301 302 self.rhodecode_user.user_id is not None:
302 303 self.rhodecode_user.set_authenticated(
303 304 cookie_store.get('is_authenticated')
304 305 )
305 306 log.info('IP: %s User: %s accessed %s' % (
306 307 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
307 308 )
308 309 return WSGIController.__call__(self, environ, start_response)
309 310 finally:
310 311 meta.Session.remove()
311 312
312 313
313 314 class BaseRepoController(BaseController):
314 315 """
315 316 Base class for controllers responsible for loading all needed data for
316 317 repository loaded items are
317 318
318 319 c.rhodecode_repo: instance of scm repository
319 320 c.rhodecode_db_repo: instance of db
320 321 c.repository_followers: number of followers
321 322 c.repository_forks: number of forks
322 323 c.repository_following: weather the current user is following the current repo
323 324 """
324 325
325 326 def __before__(self):
326 327 super(BaseRepoController, self).__before__()
327 328 if c.repo_name:
328 329
329 330 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
330 331 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
331 332 # update last change according to VCS data
332 333 dbr.update_changeset_cache(dbr.get_changeset())
333 334 if c.rhodecode_repo is None:
334 335 log.error('%s this repository is present in database but it '
335 336 'cannot be created as an scm instance', c.repo_name)
336 337
337 338 redirect(url('home'))
338 339
339 340 # some globals counter for menu
340 341 c.repository_followers = self.scm_model.get_followers(dbr)
341 342 c.repository_forks = self.scm_model.get_forks(dbr)
342 343 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
343 344 c.repository_following = self.scm_model.is_following_repo(c.repo_name,
344 345 self.rhodecode_user.user_id)
@@ -1,436 +1,437 b''
1 1 """ this is forms validation classes
2 2 http://formencode.org/module-formencode.validators.html
3 3 for list off all availible validators
4 4
5 5 we can create our own validators
6 6
7 7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 8 pre_validators [] These validators will be applied before the schema
9 9 chained_validators [] These validators will be applied after the schema
10 10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14 14
15 15
16 16 <name> = formencode.validators.<name of validator>
17 17 <name> must equal form name
18 18 list=[1,2,3,4,5]
19 19 for SELECT use formencode.All(OneOf(list), Int())
20 20
21 21 """
22 22 import logging
23 23
24 24 import formencode
25 25 from formencode import All
26 26
27 27 from pylons.i18n.translation import _
28 28
29 29 from rhodecode.model import validators as v
30 30 from rhodecode import BACKENDS
31 31
32 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 class LoginForm(formencode.Schema):
36 36 allow_extra_fields = True
37 37 filter_extra_fields = True
38 38 username = v.UnicodeString(
39 39 strip=True,
40 40 min=1,
41 41 not_empty=True,
42 42 messages={
43 43 'empty': _(u'Please enter a login'),
44 44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 45 )
46 46
47 47 password = v.UnicodeString(
48 48 strip=False,
49 49 min=3,
50 50 not_empty=True,
51 51 messages={
52 52 'empty': _(u'Please enter a password'),
53 53 'tooShort': _(u'Enter %(min)i characters or more')}
54 54 )
55 55
56 56 remember = v.StringBoolean(if_missing=False)
57 57
58 58 chained_validators = [v.ValidAuth()]
59 59
60 60
61 61 def UserForm(edit=False, old_data={}):
62 62 class _UserForm(formencode.Schema):
63 63 allow_extra_fields = True
64 64 filter_extra_fields = True
65 65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 66 v.ValidUsername(edit, old_data))
67 67 if edit:
68 68 new_password = All(
69 69 v.ValidPassword(),
70 70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 71 )
72 72 password_confirmation = All(
73 73 v.ValidPassword(),
74 74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 75 )
76 76 admin = v.StringBoolean(if_missing=False)
77 77 else:
78 78 password = All(
79 79 v.ValidPassword(),
80 80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 81 )
82 82 password_confirmation = All(
83 83 v.ValidPassword(),
84 84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 85 )
86 86
87 87 active = v.StringBoolean(if_missing=False)
88 88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91 91
92 92 chained_validators = [v.ValidPasswordsMatch()]
93 93
94 94 return _UserForm
95 95
96 96
97 97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
98 98 class _UserGroupForm(formencode.Schema):
99 99 allow_extra_fields = True
100 100 filter_extra_fields = True
101 101
102 102 users_group_name = All(
103 103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 104 v.ValidUserGroup(edit, old_data)
105 105 )
106 106
107 107 users_group_active = v.StringBoolean(if_missing=False)
108 108
109 109 if edit:
110 110 users_group_members = v.OneOf(
111 111 available_members, hideList=False, testValueList=True,
112 112 if_missing=None, not_empty=False
113 113 )
114 114
115 115 return _UserGroupForm
116 116
117 117
118 118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
119 119 can_create_in_root=False):
120 120 class _ReposGroupForm(formencode.Schema):
121 121 allow_extra_fields = True
122 122 filter_extra_fields = False
123 123
124 124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
125 125 v.SlugifyName())
126 126 group_description = v.UnicodeString(strip=True, min=1,
127 127 not_empty=False)
128 128 if edit:
129 129 #FIXME: do a special check that we cannot move a group to one of
130 130 #it's children
131 131 pass
132 132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
133 133 v.OneOf(available_groups, hideList=False,
134 134 testValueList=True,
135 135 if_missing=None, not_empty=True))
136 136 enable_locking = v.StringBoolean(if_missing=False)
137 137 chained_validators = [v.ValidReposGroup(edit, old_data)]
138 138
139 139 return _ReposGroupForm
140 140
141 141
142 142 def RegisterForm(edit=False, old_data={}):
143 143 class _RegisterForm(formencode.Schema):
144 144 allow_extra_fields = True
145 145 filter_extra_fields = True
146 146 username = All(
147 147 v.ValidUsername(edit, old_data),
148 148 v.UnicodeString(strip=True, min=1, not_empty=True)
149 149 )
150 150 password = All(
151 151 v.ValidPassword(),
152 152 v.UnicodeString(strip=False, min=6, not_empty=True)
153 153 )
154 154 password_confirmation = All(
155 155 v.ValidPassword(),
156 156 v.UnicodeString(strip=False, min=6, not_empty=True)
157 157 )
158 158 active = v.StringBoolean(if_missing=False)
159 159 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
160 160 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
161 161 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
162 162
163 163 chained_validators = [v.ValidPasswordsMatch()]
164 164
165 165 return _RegisterForm
166 166
167 167
168 168 def PasswordResetForm():
169 169 class _PasswordResetForm(formencode.Schema):
170 170 allow_extra_fields = True
171 171 filter_extra_fields = True
172 172 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
173 173 return _PasswordResetForm
174 174
175 175
176 176 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
177 177 repo_groups=[], landing_revs=[]):
178 178 class _RepoForm(formencode.Schema):
179 179 allow_extra_fields = True
180 180 filter_extra_fields = False
181 181 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
182 182 v.SlugifyName())
183 183 repo_group = All(v.CanWriteGroup(old_data),
184 184 v.OneOf(repo_groups, hideList=True))
185 185 repo_type = v.OneOf(supported_backends, required=False,
186 186 if_missing=old_data.get('repo_type'))
187 187 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
188 188 repo_private = v.StringBoolean(if_missing=False)
189 189 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
190 190 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
191 191
192 192 repo_enable_statistics = v.StringBoolean(if_missing=False)
193 193 repo_enable_downloads = v.StringBoolean(if_missing=False)
194 194 repo_enable_locking = v.StringBoolean(if_missing=False)
195 195
196 196 if edit:
197 197 #this is repo owner
198 198 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
199 199
200 200 chained_validators = [v.ValidCloneUri(),
201 201 v.ValidRepoName(edit, old_data)]
202 202 return _RepoForm
203 203
204 204
205 205 def RepoPermsForm():
206 206 class _RepoPermsForm(formencode.Schema):
207 207 allow_extra_fields = True
208 208 filter_extra_fields = False
209 209 chained_validators = [v.ValidPerms(type_='repo')]
210 210 return _RepoPermsForm
211 211
212 212
213 213 def RepoGroupPermsForm():
214 214 class _RepoGroupPermsForm(formencode.Schema):
215 215 allow_extra_fields = True
216 216 filter_extra_fields = False
217 217 recursive = v.StringBoolean(if_missing=False)
218 218 chained_validators = [v.ValidPerms(type_='repo_group')]
219 219 return _RepoGroupPermsForm
220 220
221 221
222 222 def UserGroupPermsForm():
223 223 class _UserPermsForm(formencode.Schema):
224 224 allow_extra_fields = True
225 225 filter_extra_fields = False
226 226 chained_validators = [v.ValidPerms(type_='user_group')]
227 227 return _UserPermsForm
228 228
229 229
230 230 def RepoFieldForm():
231 231 class _RepoFieldForm(formencode.Schema):
232 232 filter_extra_fields = True
233 233 allow_extra_fields = True
234 234
235 235 new_field_key = All(v.FieldKey(),
236 236 v.UnicodeString(strip=True, min=3, not_empty=True))
237 237 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
238 238 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
239 239 if_missing='str')
240 240 new_field_label = v.UnicodeString(not_empty=False)
241 241 new_field_desc = v.UnicodeString(not_empty=False)
242 242
243 243 return _RepoFieldForm
244 244
245 245
246 246 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
247 247 repo_groups=[], landing_revs=[]):
248 248 class _RepoForkForm(formencode.Schema):
249 249 allow_extra_fields = True
250 250 filter_extra_fields = False
251 251 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
252 252 v.SlugifyName())
253 253 repo_group = All(v.CanWriteGroup(),
254 254 v.OneOf(repo_groups, hideList=True))
255 255 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
256 256 description = v.UnicodeString(strip=True, min=1, not_empty=True)
257 257 private = v.StringBoolean(if_missing=False)
258 258 copy_permissions = v.StringBoolean(if_missing=False)
259 259 update_after_clone = v.StringBoolean(if_missing=False)
260 260 fork_parent_id = v.UnicodeString()
261 261 chained_validators = [v.ValidForkName(edit, old_data)]
262 262 landing_rev = v.OneOf(landing_revs, hideList=True)
263 263
264 264 return _RepoForkForm
265 265
266 266
267 267 def ApplicationSettingsForm():
268 268 class _ApplicationSettingsForm(formencode.Schema):
269 269 allow_extra_fields = True
270 270 filter_extra_fields = False
271 271 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
272 272 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
273 273 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
274 274
275 275 return _ApplicationSettingsForm
276 276
277 277
278 278 def ApplicationVisualisationForm():
279 279 class _ApplicationVisualisationForm(formencode.Schema):
280 280 allow_extra_fields = True
281 281 filter_extra_fields = False
282 282 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
283 283 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
284 284 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
285 285
286 286 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
287 287 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
288 rhodecode_dashboard_items = v.UnicodeString()
288 289
289 290 return _ApplicationVisualisationForm
290 291
291 292
292 293 def ApplicationUiSettingsForm():
293 294 class _ApplicationUiSettingsForm(formencode.Schema):
294 295 allow_extra_fields = True
295 296 filter_extra_fields = False
296 297 web_push_ssl = v.StringBoolean(if_missing=False)
297 298 paths_root_path = All(
298 299 v.ValidPath(),
299 300 v.UnicodeString(strip=True, min=1, not_empty=True)
300 301 )
301 302 hooks_changegroup_update = v.StringBoolean(if_missing=False)
302 303 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
303 304 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
304 305 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
305 306
306 307 extensions_largefiles = v.StringBoolean(if_missing=False)
307 308 extensions_hgsubversion = v.StringBoolean(if_missing=False)
308 309 extensions_hggit = v.StringBoolean(if_missing=False)
309 310
310 311 return _ApplicationUiSettingsForm
311 312
312 313
313 314 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
314 315 user_group_perms_choices, create_choices,
315 316 repo_group_create_choices, user_group_create_choices,
316 317 fork_choices, register_choices, extern_activate_choices):
317 318 class _DefaultPermissionsForm(formencode.Schema):
318 319 allow_extra_fields = True
319 320 filter_extra_fields = True
320 321 overwrite_default_repo = v.StringBoolean(if_missing=False)
321 322 overwrite_default_group = v.StringBoolean(if_missing=False)
322 323 overwrite_default_user_group = v.StringBoolean(if_missing=False)
323 324 anonymous = v.StringBoolean(if_missing=False)
324 325 default_repo_perm = v.OneOf(repo_perms_choices)
325 326 default_group_perm = v.OneOf(group_perms_choices)
326 327 default_user_group_perm = v.OneOf(user_group_perms_choices)
327 328
328 329 default_repo_create = v.OneOf(create_choices)
329 330 default_user_group_create = v.OneOf(user_group_create_choices)
330 331 #default_repo_group_create = v.OneOf(repo_group_create_choices) #not impl. yet
331 332 default_fork = v.OneOf(fork_choices)
332 333
333 334 default_register = v.OneOf(register_choices)
334 335 default_extern_activate = v.OneOf(extern_activate_choices)
335 336 return _DefaultPermissionsForm
336 337
337 338
338 339 def CustomDefaultPermissionsForm():
339 340 class _CustomDefaultPermissionsForm(formencode.Schema):
340 341 filter_extra_fields = True
341 342 allow_extra_fields = True
342 343 inherit_default_permissions = v.StringBoolean(if_missing=False)
343 344
344 345 create_repo_perm = v.StringBoolean(if_missing=False)
345 346 create_user_group_perm = v.StringBoolean(if_missing=False)
346 347 #create_repo_group_perm Impl. later
347 348
348 349 fork_repo_perm = v.StringBoolean(if_missing=False)
349 350
350 351 return _CustomDefaultPermissionsForm
351 352
352 353
353 354 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
354 355 class _DefaultsForm(formencode.Schema):
355 356 allow_extra_fields = True
356 357 filter_extra_fields = True
357 358 default_repo_type = v.OneOf(supported_backends)
358 359 default_repo_private = v.StringBoolean(if_missing=False)
359 360 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
360 361 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
361 362 default_repo_enable_locking = v.StringBoolean(if_missing=False)
362 363
363 364 return _DefaultsForm
364 365
365 366
366 367 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
367 368 tls_kind_choices):
368 369 class _LdapSettingsForm(formencode.Schema):
369 370 allow_extra_fields = True
370 371 filter_extra_fields = True
371 372 #pre_validators = [LdapLibValidator]
372 373 ldap_active = v.StringBoolean(if_missing=False)
373 374 ldap_host = v.UnicodeString(strip=True,)
374 375 ldap_port = v.Number(strip=True,)
375 376 ldap_tls_kind = v.OneOf(tls_kind_choices)
376 377 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
377 378 ldap_dn_user = v.UnicodeString(strip=True,)
378 379 ldap_dn_pass = v.UnicodeString(strip=True,)
379 380 ldap_base_dn = v.UnicodeString(strip=True,)
380 381 ldap_filter = v.UnicodeString(strip=True,)
381 382 ldap_search_scope = v.OneOf(search_scope_choices)
382 383 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
383 384 ldap_attr_firstname = v.UnicodeString(strip=True,)
384 385 ldap_attr_lastname = v.UnicodeString(strip=True,)
385 386 ldap_attr_email = v.UnicodeString(strip=True,)
386 387
387 388 return _LdapSettingsForm
388 389
389 390
390 391 def UserExtraEmailForm():
391 392 class _UserExtraEmailForm(formencode.Schema):
392 393 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
393 394 return _UserExtraEmailForm
394 395
395 396
396 397 def UserExtraIpForm():
397 398 class _UserExtraIpForm(formencode.Schema):
398 399 ip = v.ValidIp()(not_empty=True)
399 400 return _UserExtraIpForm
400 401
401 402
402 403 def PullRequestForm(repo_id):
403 404 class _PullRequestForm(formencode.Schema):
404 405 allow_extra_fields = True
405 406 filter_extra_fields = True
406 407
407 408 user = v.UnicodeString(strip=True, required=True)
408 409 org_repo = v.UnicodeString(strip=True, required=True)
409 410 org_ref = v.UnicodeString(strip=True, required=True)
410 411 other_repo = v.UnicodeString(strip=True, required=True)
411 412 other_ref = v.UnicodeString(strip=True, required=True)
412 413 revisions = All(#v.NotReviewedRevisions(repo_id)(),
413 414 v.UniqueList(not_empty=True))
414 415 review_members = v.UniqueList(not_empty=True)
415 416
416 417 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
417 418 pullrequest_desc = v.UnicodeString(strip=True, required=False)
418 419
419 420 ancestor_rev = v.UnicodeString(strip=True, required=True)
420 421 merge_rev = v.UnicodeString(strip=True, required=True)
421 422
422 423 return _PullRequestForm
423 424
424 425
425 426 def GistForm(lifetime_options):
426 427 class _GistForm(formencode.Schema):
427 428
428 429 filename = All(v.BasePath()(),
429 430 v.UnicodeString(strip=True, required=False))
430 431 description = v.UnicodeString(required=False, if_missing='')
431 432 lifetime = v.OneOf(lifetime_options)
432 433 content = v.UnicodeString(required=True, not_empty=True)
433 434 public = v.UnicodeString(required=False, if_missing='')
434 435 private = v.UnicodeString(required=False, if_missing='')
435 436
436 437 return _GistForm
@@ -1,341 +1,351 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Settings administration')} &middot; ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${_('Settings')}
12 12 </%def>
13 13
14 14 <%def name="page_nav()">
15 15 ${self.menu('admin')}
16 16 </%def>
17 17
18 18 <%def name="main()">
19 19 <div class="box">
20 20 <!-- box / title -->
21 21 <div class="title">
22 22 ${self.breadcrumbs()}
23 23 </div>
24 24 <!-- end box / title -->
25 25
26 26 <h3>${_('Remap and rescan repositories')}</h3>
27 27 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
28 28 <div class="form">
29 29 <!-- fields -->
30 30
31 31 <div class="fields">
32 32 <div class="field">
33 33 <div class="label label-checkbox">
34 34 <label for="destroy">${_('Rescan option')}:</label>
35 35 </div>
36 36 <div class="checkboxes">
37 37 <div class="checkbox">
38 38 ${h.checkbox('destroy',True)}
39 39 <label for="destroy">
40 40 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
41 41 ${_('Destroy old data')}</span> </label>
42 42 </div>
43 43 <span class="help-block">${_('Rescan repositories location for new repositories. Also deletes obsolete if `destroy` flag is checked ')}</span>
44 44 </div>
45 45 </div>
46 46
47 47 <div class="buttons">
48 48 ${h.submit('rescan',_('Rescan repositories'),class_="ui-btn large")}
49 49 </div>
50 50 </div>
51 51 </div>
52 52 ${h.end_form()}
53 53
54 54 <h3>${_('Whoosh indexing')}</h3>
55 55 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
56 56 <div class="form">
57 57 <!-- fields -->
58 58
59 59 <div class="fields">
60 60 <div class="field">
61 61 <div class="label label-checkbox">
62 62 <label>${_('Index build option')}:</label>
63 63 </div>
64 64 <div class="checkboxes">
65 65 <div class="checkbox">
66 66 ${h.checkbox('full_index',True)}
67 67 <label for="full_index">${_('Build from scratch')}</label>
68 68 </div>
69 69 </div>
70 70 </div>
71 71
72 72 <div class="buttons">
73 73 ${h.submit('reindex',_('Reindex'),class_="ui-btn large")}
74 74 </div>
75 75 </div>
76 76 </div>
77 77 ${h.end_form()}
78 78
79 79 <h3>${_('Global application settings')}</h3>
80 80 ${h.form(url('admin_setting', setting_id='global'),method='put')}
81 81 <div class="form">
82 82 <!-- fields -->
83 83
84 84 <div class="fields">
85 85
86 86 <div class="field">
87 87 <div class="label">
88 88 <label for="rhodecode_title">${_('Site branding')}:</label>
89 89 </div>
90 90 <div class="input">
91 91 ${h.text('rhodecode_title',size=30)}
92 92 </div>
93 93 </div>
94 94
95 95 <div class="field">
96 96 <div class="label">
97 97 <label for="rhodecode_realm">${_('HTTP authentication realm')}:</label>
98 98 </div>
99 99 <div class="input">
100 100 ${h.text('rhodecode_realm',size=30)}
101 101 </div>
102 102 </div>
103 103
104 104 <div class="field">
105 105 <div class="label">
106 106 <label for="rhodecode_ga_code">${_('Google Analytics code')}:</label>
107 107 </div>
108 108 <div class="input">
109 109 ${h.text('rhodecode_ga_code',size=30)}
110 110 </div>
111 111 </div>
112 112
113 113 <div class="buttons">
114 114 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
115 115 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
116 116 </div>
117 117 </div>
118 118 </div>
119 119 ${h.end_form()}
120 120
121 121 <h3>${_('Visualisation settings')}</h3>
122 122 ${h.form(url('admin_setting', setting_id='visual'),method='put')}
123 123 <div class="form">
124 124 <!-- fields -->
125 125
126 126 <div class="fields">
127 127 <div class="field">
128 128 <div class="label label-checkbox">
129 129 <label>${_('General')}:</label>
130 130 </div>
131 131 <div class="checkboxes">
132 132 <div class="checkbox">
133 133 ${h.checkbox('rhodecode_repository_fields','True')}
134 134 <label for="rhodecode_repository_fields">${_('Use repository extra fields')}</label>
135 135 </div>
136 <span class="help-block">${_('Allows storing additional customized fields per repository.')}</span>
136 137 </div>
137 138 </div>
138
139 <div class="field">
140 <div class="label">
141 <label for="rhodecode_realm">${_('Dashboard items')}:</label>
142 </div>
143 <div class="input">
144 ${h.text('rhodecode_dashboard_items',size=5)}
145 <span class="help-block">${_('Number of items displayed in lightweight dashboard before pagination is shown.')}</span>
146 </div>
147 </div>
139 148 <div class="field">
140 149 <div class="label label-checkbox">
141 150 <label>${_('Icons')}:</label>
142 151 </div>
143 152 <div class="checkboxes">
144 153 <div class="checkbox">
145 154 ${h.checkbox('rhodecode_show_public_icon','True')}
146 155 <label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label>
147 156 </div>
148 157 <div class="checkbox">
149 158 ${h.checkbox('rhodecode_show_private_icon','True')}
150 159 <label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label>
151 160 </div>
161 <span class="help-block">${_('Show public/private icons next to repositories names')}</span>
152 162 </div>
153 163 </div>
154 164
155 165 <div class="field">
156 166 <div class="label label-checkbox">
157 167 <label>${_('Meta-Tagging')}:</label>
158 168 </div>
159 169 <div class="checkboxes">
160 170 <div class="checkbox">
161 171 ${h.checkbox('rhodecode_stylify_metatags','True')}
162 172 <label for="rhodecode_stylify_metatags">${_('Stylify recognised metatags:')}</label>
163 173 </div>
164 174 <div style="padding-left: 20px;">
165 175 <ul> <!-- Fix style here -->
166 176 <li>[featured] <span class="metatag" tag="featured">featured</span></li>
167 177 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
168 178 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
169 179 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
170 180 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
171 181 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
172 182 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
173 183 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
174 184 </ul>
175 185 </div>
176 186 </div>
177 187 </div>
178 188
179 189 <div class="buttons">
180 190 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
181 191 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
182 192 </div>
183 193
184 194 </div>
185 195 </div>
186 196 ${h.end_form()}
187 197
188 198
189 199 <h3>${_('VCS settings')}</h3>
190 200 ${h.form(url('admin_setting', setting_id='vcs'),method='put')}
191 201 <div class="form">
192 202 <!-- fields -->
193 203
194 204 <div class="fields">
195 205
196 206 <div class="field">
197 207 <div class="label label-checkbox">
198 208 <label>${_('Web')}:</label>
199 209 </div>
200 210 <div class="checkboxes">
201 211 <div class="checkbox">
202 212 ${h.checkbox('web_push_ssl', 'True')}
203 213 <label for="web_push_ssl">${_('Require SSL for vcs operations')}</label>
204 214 </div>
205 215 <span class="help-block">${_('RhodeCode will require SSL for pushing or pulling. If SSL is missing it will return HTTP Error 406: Not Acceptable')}</span>
206 216 </div>
207 217 </div>
208 218
209 219 <div class="field">
210 220 <div class="label label-checkbox">
211 221 <label>${_('Hooks')}:</label>
212 222 </div>
213 223 <div class="checkboxes">
214 224 <div class="checkbox">
215 225 ${h.checkbox('hooks_changegroup_update','True')}
216 226 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
217 227 </div>
218 228 <div class="checkbox">
219 229 ${h.checkbox('hooks_changegroup_repo_size','True')}
220 230 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
221 231 </div>
222 232 <div class="checkbox">
223 233 ${h.checkbox('hooks_changegroup_push_logger','True')}
224 234 <label for="hooks_changegroup_push_logger">${_('Log user push commands')}</label>
225 235 </div>
226 236 <div class="checkbox">
227 237 ${h.checkbox('hooks_outgoing_pull_logger','True')}
228 238 <label for="hooks_outgoing_pull_logger">${_('Log user pull commands')}</label>
229 239 </div>
230 240 </div>
231 241 <div class="input" style="margin-top:10px">
232 242 ${h.link_to(_('Advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
233 243 </div>
234 244 </div>
235 245 <div class="field">
236 246 <div class="label label-checkbox">
237 247 <label>${_('Mercurial Extensions')}:</label>
238 248 </div>
239 249 <div class="checkboxes">
240 250 <div class="checkbox">
241 251 ${h.checkbox('extensions_largefiles','True')}
242 252 <label for="extensions_largefiles">${_('Enable largefiles extension')}</label>
243 253 </div>
244 254 <div class="checkbox">
245 255 ${h.checkbox('extensions_hgsubversion','True')}
246 256 <label for="extensions_hgsubversion">${_('Enable hgsubversion extension')}</label>
247 257 </div>
248 258 <span class="help-block">${_('Requires hgsubversion library installed. Allows cloning from svn remote locations')}</span>
249 259 ##<div class="checkbox">
250 260 ## ${h.checkbox('extensions_hggit','True')}
251 261 ## <label for="extensions_hggit">${_('Enable hg-git extension')}</label>
252 262 ##</div>
253 263 ##<span class="help-block">${_('Requires hg-git library installed. Allows cloning from git remote locations')}</span>
254 264 </div>
255 265 </div>
256 266 <div class="field">
257 267 <div class="label">
258 268 <label for="paths_root_path">${_('Repositories location')}:</label>
259 269 </div>
260 270 <div class="input">
261 271 ${h.text('paths_root_path',size=30,readonly="readonly")}
262 272 <span id="path_unlock" class="tooltip"
263 273 title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
264 274 ${_('Unlock')}
265 275 </span>
266 276 <span class="help-block">${_('Location where repositories are stored. After changing this value a restart, and rescan is required')}</span>
267 277 </div>
268 278 </div>
269 279
270 280 <div class="buttons">
271 281 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
272 282 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
273 283 </div>
274 284 </div>
275 285 </div>
276 286 ${h.end_form()}
277 287
278 288 <script type="text/javascript">
279 289 YAHOO.util.Event.onDOMReady(function(){
280 290 YAHOO.util.Event.addListener('path_unlock','click',function(){
281 291 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
282 292 });
283 293 });
284 294 </script>
285 295
286 296 <h3>${_('Test Email')}</h3>
287 297 ${h.form(url('admin_setting', setting_id='email'),method='put')}
288 298 <div class="form">
289 299 <!-- fields -->
290 300
291 301 <div class="fields">
292 302 <div class="field">
293 303 <div class="label">
294 304 <label for="test_email">${_('Email to')}:</label>
295 305 </div>
296 306 <div class="input">
297 307 ${h.text('test_email',size=30)}
298 308 </div>
299 309 </div>
300 310
301 311 <div class="buttons">
302 312 ${h.submit('send',_('Send'),class_="ui-btn large")}
303 313 </div>
304 314 </div>
305 315 </div>
306 316 ${h.end_form()}
307 317
308 318 <h3>${_('System Info and Packages')}</h3>
309 319 <div class="form">
310 320 <div>
311 321 <h5 id="expand_modules" style="cursor: pointer">&darr; ${_('Show')} &darr;</h5>
312 322 </div>
313 323 <div id="expand_modules_table" style="display:none">
314 324 <h5>Python - ${c.py_version}</h5>
315 325 <h5>System - ${c.platform}</h5>
316 326
317 327 <table class="table" style="margin:0px 0px 0px 20px">
318 328 <colgroup>
319 329 <col style="width:220px">
320 330 </colgroup>
321 331 <tbody>
322 332 %for key, value in c.modules:
323 333 <tr>
324 334 <th style="text-align: right;padding-right:5px;">${key}</th>
325 335 <td>${value}</td>
326 336 </tr>
327 337 %endfor
328 338 </tbody>
329 339 </table>
330 340 </div>
331 341 </div>
332 342
333 343 <script type="text/javascript">
334 344 YUE.on('expand_modules','click',function(e){
335 345 YUD.setStyle('expand_modules_table','display','');
336 346 YUD.setStyle('expand_modules','display','none');
337 347 })
338 348 </script>
339 349
340 350 </div>
341 351 </%def>
General Comments 0
You need to be logged in to leave comments. Login now