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