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