##// END OF EJS Templates
Implemented show_id function that is a configurable way to display sha hashes in the changelog.
marcink -
r3557:58dcef7e beta
parent child Browse files
Show More
@@ -1,454 +1,477 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 ##nr of threads to spawn
33 ## nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ## max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ## option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 ## WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 ## 100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 0.0.0.0
50 host = 0.0.0.0
51 port = 5000
51 port = 5000
52
52
53 [filter:proxy-prefix]
53 ## prefix middleware for rc
54 # prefix middleware for rc
54 #[filter:proxy-prefix]
55 use = egg:PasteDeploy#prefix
55 #use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 #prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 ## enable proxy prefix middleware
60 #filter-with = proxy-prefix
61 #filter-with = proxy-prefix
62
61 full_stack = true
63 full_stack = true
62 static_files = true
64 static_files = true
63 # Optional Languages
65 ## Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
66 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
67 lang = en
66 cache_dir = %(here)s/data
68 cache_dir = %(here)s/data
67 index_dir = %(here)s/data/index
69 index_dir = %(here)s/data/index
68 # set this path to use archive download cache
70
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
71 ## uncomment and set this path to use archive download cache
70 app_instance_uuid = rc-develop
72 #archive_cache_dir = /tmp/tarballcache
73
74 ## change this to unique ID for security
75 app_instance_uuid = rc-production
76
77 ## cut off limit for large diffs (size in bytes)
71 cut_off_limit = 256000
78 cut_off_limit = 256000
72 vcs_full_cache = True
79
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
80 ## use cache version of scm repo everywhere
81 vcs_full_cache = true
82
83 ## force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
84 force_https = false
75 # use Strict-Transport-Security headers
85
86 ## use Strict-Transport-Security headers
76 use_htsts = false
87 use_htsts = false
88
89 ## number of commits stats will parse on each iteration
77 commit_parse_limit = 25
90 commit_parse_limit = 25
78 # number of items displayed in lightweight dashboard before paginating
91
92 ## number of items displayed in lightweight dashboard before paginating is shown
79 dashboard_items = 100
93 dashboard_items = 100
94
95 ## use gravatar service to display avatars
80 use_gravatar = true
96 use_gravatar = true
81
97
82 # path to git executable
98 ## path to git executable
83 git_path = git
99 git_path = git
84
100
85 ## RSS feed options
101 ## RSS feed options
86
87 rss_cut_off_limit = 256000
102 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
103 rss_items_per_page = 10
89 rss_include_diff = false
104 rss_include_diff = false
90
105
106 ## show hash options for changelog
107 sha_len = 12
108 sha_rev = true
109
91
110
92 ## alternative_gravatar_url allows you to use your own avatar server application
111 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
112 ## the following parts of the URL will be replaced
94 ## {email} user email
113 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
114 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
115 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
116 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
117 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
118 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
119 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
120
121
122 ## container auth options
102 container_auth_enabled = false
123 container_auth_enabled = false
103 proxypass_auth_enabled = false
124 proxypass_auth_enabled = false
125
104 ## default encoding used to convert from and to unicode
126 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
127 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
128 default_encoding = utf8
107
129
108 ## overwrite schema of clone url
130 ## overwrite schema of clone url
109 ## available vars:
131 ## available vars:
110 ## scheme - http/https
132 ## scheme - http/https
111 ## user - current user
133 ## user - current user
112 ## pass - password
134 ## pass - password
113 ## netloc - network location
135 ## netloc - network location
114 ## path - usually repo_name
136 ## path - usually repo_name
115
137
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
138 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
139
118 ## issue tracking mapping for commits messages
140 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
141 ## comment out issue_pat, issue_server, issue_prefix to enable
120
142
121 ## pattern to get the issues from commit messages
143 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
144 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
145 ## {id} will be all groups matched from this pattern
124
146
125 issue_pat = (?:\s*#)(\d+)
147 issue_pat = (?:\s*#)(\d+)
126
148
127 ## server url to the issue, each {id} will be replaced with match
149 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
150 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
151 ## including groups {repo_name} is replaced with just name of repo
130
152
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
153 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
154
133 ## prefix to add to link to indicate it's an url
155 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
156 ## #314 will be replaced by <issue_prefix><id>
135
157
136 issue_prefix = #
158 issue_prefix = #
137
159
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
160 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
161 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
162 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
163 # #wiki-some-id -> https://mywiki.com/some-id
142
164
143 #issue_pat_wiki = (?:wiki-)(.+)
165 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
166 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
167 #issue_prefix_wiki = WIKI-
146
168
147
169
148 ## instance-id prefix
170 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
171 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
172 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
173 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
174 instance_id =
153
175
154 ## alternative return HTTP header for failed authentication. Default HTTP
176 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
177 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
178 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
179 auth_ret_code =
158
180
159 ## locking return code. When repository is locked return this HTTP code. 2XX
181 ## locking return code. When repository is locked return this HTTP code. 2XX
160 ## codes don't break the transactions while 4XX codes do
182 ## codes don't break the transactions while 4XX codes do
161 lock_ret_code = 423
183 lock_ret_code = 423
162
184
163
185
164 ####################################
186 ####################################
165 ### CELERY CONFIG ####
187 ### CELERY CONFIG ####
166 ####################################
188 ####################################
167 use_celery = false
189 use_celery = false
168 broker.host = localhost
190 broker.host = localhost
169 broker.vhost = rabbitmqhost
191 broker.vhost = rabbitmqhost
170 broker.port = 5672
192 broker.port = 5672
171 broker.user = rabbitmq
193 broker.user = rabbitmq
172 broker.password = qweqwe
194 broker.password = qweqwe
173
195
174 celery.imports = rhodecode.lib.celerylib.tasks
196 celery.imports = rhodecode.lib.celerylib.tasks
175
197
176 celery.result.backend = amqp
198 celery.result.backend = amqp
177 celery.result.dburi = amqp://
199 celery.result.dburi = amqp://
178 celery.result.serialier = json
200 celery.result.serialier = json
179
201
180 #celery.send.task.error.emails = true
202 #celery.send.task.error.emails = true
181 #celery.amqp.task.result.expires = 18000
203 #celery.amqp.task.result.expires = 18000
182
204
183 celeryd.concurrency = 2
205 celeryd.concurrency = 2
184 #celeryd.log.file = celeryd.log
206 #celeryd.log.file = celeryd.log
185 celeryd.log.level = debug
207 celeryd.log.level = debug
186 celeryd.max.tasks.per.child = 1
208 celeryd.max.tasks.per.child = 1
187
209
188 #tasks will never be sent to the queue, but executed locally instead.
210 ## tasks will never be sent to the queue, but executed locally instead.
189 celery.always.eager = false
211 celery.always.eager = false
190
212
191 ####################################
213 ####################################
192 ### BEAKER CACHE ####
214 ### BEAKER CACHE ####
193 ####################################
215 ####################################
194 beaker.cache.data_dir=%(here)s/data/cache/data
216 beaker.cache.data_dir=%(here)s/data/cache/data
195 beaker.cache.lock_dir=%(here)s/data/cache/lock
217 beaker.cache.lock_dir=%(here)s/data/cache/lock
196
218
197 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
219 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
198
220
199 beaker.cache.super_short_term.type=memory
221 beaker.cache.super_short_term.type=memory
200 beaker.cache.super_short_term.expire=10
222 beaker.cache.super_short_term.expire=10
201 beaker.cache.super_short_term.key_length = 256
223 beaker.cache.super_short_term.key_length = 256
202
224
203 beaker.cache.short_term.type=memory
225 beaker.cache.short_term.type=memory
204 beaker.cache.short_term.expire=60
226 beaker.cache.short_term.expire=60
205 beaker.cache.short_term.key_length = 256
227 beaker.cache.short_term.key_length = 256
206
228
207 beaker.cache.long_term.type=memory
229 beaker.cache.long_term.type=memory
208 beaker.cache.long_term.expire=36000
230 beaker.cache.long_term.expire=36000
209 beaker.cache.long_term.key_length = 256
231 beaker.cache.long_term.key_length = 256
210
232
211 beaker.cache.sql_cache_short.type=memory
233 beaker.cache.sql_cache_short.type=memory
212 beaker.cache.sql_cache_short.expire=10
234 beaker.cache.sql_cache_short.expire=10
213 beaker.cache.sql_cache_short.key_length = 256
235 beaker.cache.sql_cache_short.key_length = 256
214
236
215 beaker.cache.sql_cache_med.type=memory
237 beaker.cache.sql_cache_med.type=memory
216 beaker.cache.sql_cache_med.expire=360
238 beaker.cache.sql_cache_med.expire=360
217 beaker.cache.sql_cache_med.key_length = 256
239 beaker.cache.sql_cache_med.key_length = 256
218
240
219 beaker.cache.sql_cache_long.type=file
241 beaker.cache.sql_cache_long.type=file
220 beaker.cache.sql_cache_long.expire=3600
242 beaker.cache.sql_cache_long.expire=3600
221 beaker.cache.sql_cache_long.key_length = 256
243 beaker.cache.sql_cache_long.key_length = 256
222
244
223 ####################################
245 ####################################
224 ### BEAKER SESSION ####
246 ### BEAKER SESSION ####
225 ####################################
247 ####################################
226 ## Type of storage used for the session, current types are
248 ## Type of storage used for the session, current types are
227 ## dbm, file, memcached, database, and memory.
249 ## dbm, file, memcached, database, and memory.
228 ## The storage uses the Container API
250 ## The storage uses the Container API
229 ## that is also used by the cache system.
251 ## that is also used by the cache system.
230
252
231 ## db session ##
253 ## db session ##
232 #beaker.session.type = ext:database
254 #beaker.session.type = ext:database
233 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
255 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
234 #beaker.session.table_name = db_session
256 #beaker.session.table_name = db_session
235
257
236 ## encrypted cookie client side session, good for many instances ##
258 ## encrypted cookie client side session, good for many instances ##
237 #beaker.session.type = cookie
259 #beaker.session.type = cookie
238
260
239 ## file based cookies (default) ##
261 ## file based cookies (default) ##
240 #beaker.session.type = file
262 #beaker.session.type = file
241
263
242
264
243 beaker.session.key = rhodecode
265 beaker.session.key = rhodecode
244 ## secure cookie requires AES python libraries ##
266 ## secure cookie requires AES python libraries
245 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
267 #beaker.session.encrypt_key = <key_for_encryption>
246 #beaker.session.validate_key = 9712sds2212c--zxc123
268 #beaker.session.validate_key = <validation_key>
269
247 ## sets session as invalid if it haven't been accessed for given amount of time
270 ## sets session as invalid if it haven't been accessed for given amount of time
248 beaker.session.timeout = 2592000
271 beaker.session.timeout = 2592000
249 beaker.session.httponly = true
272 beaker.session.httponly = true
250 #beaker.session.cookie_path = /<your-prefix>
273 #beaker.session.cookie_path = /<your-prefix>
251
274
252 ## uncomment for https secure cookie ##
275 ## uncomment for https secure cookie
253 beaker.session.secure = false
276 beaker.session.secure = false
254
277
255 ## auto save the session to not to use .save() ##
278 ## auto save the session to not to use .save()
256 beaker.session.auto = False
279 beaker.session.auto = False
257
280
258 ## default cookie expiration time in seconds `true` expire at browser close ##
281 ## default cookie expiration time in seconds `true` expire at browser close ##
259 #beaker.session.cookie_expires = 3600
282 #beaker.session.cookie_expires = 3600
260
283
261
284
262 ############################
285 ############################
263 ## ERROR HANDLING SYSTEMS ##
286 ## ERROR HANDLING SYSTEMS ##
264 ############################
287 ############################
265
288
266 ####################
289 ####################
267 ### [errormator] ###
290 ### [errormator] ###
268 ####################
291 ####################
269
292
270 # Errormator is tailored to work with RhodeCode, see
293 ## Errormator is tailored to work with RhodeCode, see
271 # http://errormator.com for details how to obtain an account
294 ## http://errormator.com for details how to obtain an account
272 # you must install python package `errormator_client` to make it work
295 ## you must install python package `errormator_client` to make it work
273
296
274 # errormator enabled
297 ## errormator enabled
275 errormator = true
298 errormator = false
276
299
277 errormator.server_url = https://api.errormator.com
300 errormator.server_url = https://api.errormator.com
278 errormator.api_key = YOUR_API_KEY
301 errormator.api_key = YOUR_API_KEY
279
302
280 # TWEAK AMOUNT OF INFO SENT HERE
303 ## TWEAK AMOUNT OF INFO SENT HERE
281
304
282 # enables 404 error logging (default False)
305 ## enables 404 error logging (default False)
283 errormator.report_404 = false
306 errormator.report_404 = false
284
307
285 # time in seconds after request is considered being slow (default 1)
308 ## time in seconds after request is considered being slow (default 1)
286 errormator.slow_request_time = 1
309 errormator.slow_request_time = 1
287
310
288 # record slow requests in application
311 ## record slow requests in application
289 # (needs to be enabled for slow datastore recording and time tracking)
312 ## (needs to be enabled for slow datastore recording and time tracking)
290 errormator.slow_requests = true
313 errormator.slow_requests = true
291
314
292 # enable hooking to application loggers
315 ## enable hooking to application loggers
293 # errormator.logging = true
316 # errormator.logging = true
294
317
295 # minimum log level for log capture
318 ## minimum log level for log capture
296 # errormator.logging.level = WARNING
319 # errormator.logging.level = WARNING
297
320
298 # send logs only from erroneous/slow requests
321 ## send logs only from erroneous/slow requests
299 # (saves API quota for intensive logging)
322 ## (saves API quota for intensive logging)
300 errormator.logging_on_error = false
323 errormator.logging_on_error = false
301
324
302 # list of additonal keywords that should be grabbed from environ object
325 ## list of additonal keywords that should be grabbed from environ object
303 # can be string with comma separated list of words in lowercase
326 ## can be string with comma separated list of words in lowercase
304 # (by default client will always send following info:
327 ## (by default client will always send following info:
305 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
328 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
306 # start with HTTP* this list be extended with additional keywords here
329 ## start with HTTP* this list be extended with additional keywords here
307 errormator.environ_keys_whitelist =
330 errormator.environ_keys_whitelist =
308
331
309
332
310 # list of keywords that should be blanked from request object
333 ## list of keywords that should be blanked from request object
311 # can be string with comma separated list of words in lowercase
334 ## can be string with comma separated list of words in lowercase
312 # (by default client will always blank keys that contain following words
335 ## (by default client will always blank keys that contain following words
313 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
336 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
314 # this list be extended with additional keywords set here
337 ## this list be extended with additional keywords set here
315 errormator.request_keys_blacklist =
338 errormator.request_keys_blacklist =
316
339
317
340
318 # list of namespaces that should be ignores when gathering log entries
341 ## list of namespaces that should be ignores when gathering log entries
319 # can be string with comma separated list of namespaces
342 ## can be string with comma separated list of namespaces
320 # (by default the client ignores own entries: errormator_client.client)
343 ## (by default the client ignores own entries: errormator_client.client)
321 errormator.log_namespace_blacklist =
344 errormator.log_namespace_blacklist =
322
345
323
346
324 ################
347 ################
325 ### [sentry] ###
348 ### [sentry] ###
326 ################
349 ################
327
350
328 # sentry is a alternative open source error aggregator
351 ## sentry is a alternative open source error aggregator
329 # you must install python packages `sentry` and `raven` to enable
352 ## you must install python packages `sentry` and `raven` to enable
330
353
331 sentry.dsn = YOUR_DNS
354 sentry.dsn = YOUR_DNS
332 sentry.servers =
355 sentry.servers =
333 sentry.name =
356 sentry.name =
334 sentry.key =
357 sentry.key =
335 sentry.public_key =
358 sentry.public_key =
336 sentry.secret_key =
359 sentry.secret_key =
337 sentry.project =
360 sentry.project =
338 sentry.site =
361 sentry.site =
339 sentry.include_paths =
362 sentry.include_paths =
340 sentry.exclude_paths =
363 sentry.exclude_paths =
341
364
342
365
343 ################################################################################
366 ################################################################################
344 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
367 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
345 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
368 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
346 ## execute malicious code after an exception is raised. ##
369 ## execute malicious code after an exception is raised. ##
347 ################################################################################
370 ################################################################################
348 #set debug = false
371 #set debug = false
349
372
350 ##################################
373 ##################################
351 ### LOGVIEW CONFIG ###
374 ### LOGVIEW CONFIG ###
352 ##################################
375 ##################################
353 logview.sqlalchemy = #faa
376 logview.sqlalchemy = #faa
354 logview.pylons.templating = #bfb
377 logview.pylons.templating = #bfb
355 logview.pylons.util = #eee
378 logview.pylons.util = #eee
356
379
357 #########################################################
380 #########################################################
358 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
381 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
359 #########################################################
382 #########################################################
360 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
383 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
361 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
384 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
362 sqlalchemy.db1.echo = false
385 sqlalchemy.db1.echo = false
363 sqlalchemy.db1.pool_recycle = 3600
386 sqlalchemy.db1.pool_recycle = 3600
364 sqlalchemy.db1.convert_unicode = true
387 sqlalchemy.db1.convert_unicode = true
365
388
366 ################################
389 ################################
367 ### LOGGING CONFIGURATION ####
390 ### LOGGING CONFIGURATION ####
368 ################################
391 ################################
369 [loggers]
392 [loggers]
370 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
393 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
371
394
372 [handlers]
395 [handlers]
373 keys = console, console_sql
396 keys = console, console_sql
374
397
375 [formatters]
398 [formatters]
376 keys = generic, color_formatter, color_formatter_sql
399 keys = generic, color_formatter, color_formatter_sql
377
400
378 #############
401 #############
379 ## LOGGERS ##
402 ## LOGGERS ##
380 #############
403 #############
381 [logger_root]
404 [logger_root]
382 level = NOTSET
405 level = NOTSET
383 handlers = console
406 handlers = console
384
407
385 [logger_routes]
408 [logger_routes]
386 level = DEBUG
409 level = DEBUG
387 handlers =
410 handlers =
388 qualname = routes.middleware
411 qualname = routes.middleware
389 # "level = DEBUG" logs the route matched and routing variables.
412 ## "level = DEBUG" logs the route matched and routing variables.
390 propagate = 1
413 propagate = 1
391
414
392 [logger_beaker]
415 [logger_beaker]
393 level = DEBUG
416 level = DEBUG
394 handlers =
417 handlers =
395 qualname = beaker.container
418 qualname = beaker.container
396 propagate = 1
419 propagate = 1
397
420
398 [logger_templates]
421 [logger_templates]
399 level = INFO
422 level = INFO
400 handlers =
423 handlers =
401 qualname = pylons.templating
424 qualname = pylons.templating
402 propagate = 1
425 propagate = 1
403
426
404 [logger_rhodecode]
427 [logger_rhodecode]
405 level = DEBUG
428 level = DEBUG
406 handlers =
429 handlers =
407 qualname = rhodecode
430 qualname = rhodecode
408 propagate = 1
431 propagate = 1
409
432
410 [logger_sqlalchemy]
433 [logger_sqlalchemy]
411 level = INFO
434 level = INFO
412 handlers = console_sql
435 handlers = console_sql
413 qualname = sqlalchemy.engine
436 qualname = sqlalchemy.engine
414 propagate = 0
437 propagate = 0
415
438
416 [logger_whoosh_indexer]
439 [logger_whoosh_indexer]
417 level = DEBUG
440 level = DEBUG
418 handlers =
441 handlers =
419 qualname = whoosh_indexer
442 qualname = whoosh_indexer
420 propagate = 1
443 propagate = 1
421
444
422 ##############
445 ##############
423 ## HANDLERS ##
446 ## HANDLERS ##
424 ##############
447 ##############
425
448
426 [handler_console]
449 [handler_console]
427 class = StreamHandler
450 class = StreamHandler
428 args = (sys.stderr,)
451 args = (sys.stderr,)
429 level = DEBUG
452 level = DEBUG
430 formatter = color_formatter
453 formatter = color_formatter
431
454
432 [handler_console_sql]
455 [handler_console_sql]
433 class = StreamHandler
456 class = StreamHandler
434 args = (sys.stderr,)
457 args = (sys.stderr,)
435 level = DEBUG
458 level = DEBUG
436 formatter = color_formatter_sql
459 formatter = color_formatter_sql
437
460
438 ################
461 ################
439 ## FORMATTERS ##
462 ## FORMATTERS ##
440 ################
463 ################
441
464
442 [formatter_generic]
465 [formatter_generic]
443 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
466 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
444 datefmt = %Y-%m-%d %H:%M:%S
467 datefmt = %Y-%m-%d %H:%M:%S
445
468
446 [formatter_color_formatter]
469 [formatter_color_formatter]
447 class=rhodecode.lib.colored_formatter.ColorFormatter
470 class=rhodecode.lib.colored_formatter.ColorFormatter
448 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
471 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
449 datefmt = %Y-%m-%d %H:%M:%S
472 datefmt = %Y-%m-%d %H:%M:%S
450
473
451 [formatter_color_formatter_sql]
474 [formatter_color_formatter_sql]
452 class=rhodecode.lib.colored_formatter.ColorFormatterSql
475 class=rhodecode.lib.colored_formatter.ColorFormatterSql
453 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
476 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
454 datefmt = %Y-%m-%d %H:%M:%S
477 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,454 +1,477 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 ##nr of threads to spawn
33 ## nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ## max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ## option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 ## WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 ## 100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 127.0.0.1
50 host = 127.0.0.1
51 port = 8001
51 port = 8001
52
52
53 [filter:proxy-prefix]
53 ## prefix middleware for rc
54 # prefix middleware for rc
54 #[filter:proxy-prefix]
55 use = egg:PasteDeploy#prefix
55 #use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 #prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 ## enable proxy prefix middleware
60 #filter-with = proxy-prefix
61 #filter-with = proxy-prefix
62
61 full_stack = true
63 full_stack = true
62 static_files = true
64 static_files = true
63 # Optional Languages
65 ## Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
66 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
67 lang = en
66 cache_dir = %(here)s/data
68 cache_dir = %(here)s/data
67 index_dir = %(here)s/data/index
69 index_dir = %(here)s/data/index
68 # set this path to use archive download cache
70
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
71 ## uncomment and set this path to use archive download cache
72 #archive_cache_dir = /tmp/tarballcache
73
74 ## change this to unique ID for security
70 app_instance_uuid = rc-production
75 app_instance_uuid = rc-production
76
77 ## cut off limit for large diffs (size in bytes)
71 cut_off_limit = 256000
78 cut_off_limit = 256000
72 vcs_full_cache = True
79
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
80 ## use cache version of scm repo everywhere
81 vcs_full_cache = true
82
83 ## force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
84 force_https = false
75 # use Strict-Transport-Security headers
85
86 ## use Strict-Transport-Security headers
76 use_htsts = false
87 use_htsts = false
77 commit_parse_limit = 50
88
78 # number of items displayed in lightweight dashboard before paginating
89 ## number of commits stats will parse on each iteration
90 commit_parse_limit = 25
91
92 ## number of items displayed in lightweight dashboard before paginating is shown
79 dashboard_items = 100
93 dashboard_items = 100
94
95 ## use gravatar service to display avatars
80 use_gravatar = true
96 use_gravatar = true
81
97
82 # path to git executable
98 ## path to git executable
83 git_path = git
99 git_path = git
84
100
85 ## RSS feed options
101 ## RSS feed options
86
87 rss_cut_off_limit = 256000
102 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
103 rss_items_per_page = 10
89 rss_include_diff = false
104 rss_include_diff = false
90
105
106 ## show hash options for changelog
107 sha_len = 12
108 sha_rev = true
109
91
110
92 ## alternative_gravatar_url allows you to use your own avatar server application
111 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
112 ## the following parts of the URL will be replaced
94 ## {email} user email
113 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
114 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
115 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
116 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
117 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
118 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
119 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
120
121
122 ## container auth options
102 container_auth_enabled = false
123 container_auth_enabled = false
103 proxypass_auth_enabled = false
124 proxypass_auth_enabled = false
125
104 ## default encoding used to convert from and to unicode
126 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
127 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
128 default_encoding = utf8
107
129
108 ## overwrite schema of clone url
130 ## overwrite schema of clone url
109 ## available vars:
131 ## available vars:
110 ## scheme - http/https
132 ## scheme - http/https
111 ## user - current user
133 ## user - current user
112 ## pass - password
134 ## pass - password
113 ## netloc - network location
135 ## netloc - network location
114 ## path - usually repo_name
136 ## path - usually repo_name
115
137
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
138 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
139
118 ## issue tracking mapping for commits messages
140 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
141 ## comment out issue_pat, issue_server, issue_prefix to enable
120
142
121 ## pattern to get the issues from commit messages
143 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
144 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
145 ## {id} will be all groups matched from this pattern
124
146
125 issue_pat = (?:\s*#)(\d+)
147 issue_pat = (?:\s*#)(\d+)
126
148
127 ## server url to the issue, each {id} will be replaced with match
149 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
150 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
151 ## including groups {repo_name} is replaced with just name of repo
130
152
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
153 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
154
133 ## prefix to add to link to indicate it's an url
155 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
156 ## #314 will be replaced by <issue_prefix><id>
135
157
136 issue_prefix = #
158 issue_prefix = #
137
159
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
160 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
161 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
162 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
163 # #wiki-some-id -> https://mywiki.com/some-id
142
164
143 #issue_pat_wiki = (?:wiki-)(.+)
165 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
166 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
167 #issue_prefix_wiki = WIKI-
146
168
147
169
148 ## instance-id prefix
170 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
171 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
172 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
173 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
174 instance_id =
153
175
154 ## alternative return HTTP header for failed authentication. Default HTTP
176 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
177 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
178 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
179 auth_ret_code =
158
180
159 ## locking return code. When repository is locked return this HTTP code. 2XX
181 ## locking return code. When repository is locked return this HTTP code. 2XX
160 ## codes don't break the transactions while 4XX codes do
182 ## codes don't break the transactions while 4XX codes do
161 lock_ret_code = 423
183 lock_ret_code = 423
162
184
163
185
164 ####################################
186 ####################################
165 ### CELERY CONFIG ####
187 ### CELERY CONFIG ####
166 ####################################
188 ####################################
167 use_celery = false
189 use_celery = false
168 broker.host = localhost
190 broker.host = localhost
169 broker.vhost = rabbitmqhost
191 broker.vhost = rabbitmqhost
170 broker.port = 5672
192 broker.port = 5672
171 broker.user = rabbitmq
193 broker.user = rabbitmq
172 broker.password = qweqwe
194 broker.password = qweqwe
173
195
174 celery.imports = rhodecode.lib.celerylib.tasks
196 celery.imports = rhodecode.lib.celerylib.tasks
175
197
176 celery.result.backend = amqp
198 celery.result.backend = amqp
177 celery.result.dburi = amqp://
199 celery.result.dburi = amqp://
178 celery.result.serialier = json
200 celery.result.serialier = json
179
201
180 #celery.send.task.error.emails = true
202 #celery.send.task.error.emails = true
181 #celery.amqp.task.result.expires = 18000
203 #celery.amqp.task.result.expires = 18000
182
204
183 celeryd.concurrency = 2
205 celeryd.concurrency = 2
184 #celeryd.log.file = celeryd.log
206 #celeryd.log.file = celeryd.log
185 celeryd.log.level = debug
207 celeryd.log.level = debug
186 celeryd.max.tasks.per.child = 1
208 celeryd.max.tasks.per.child = 1
187
209
188 #tasks will never be sent to the queue, but executed locally instead.
210 ## tasks will never be sent to the queue, but executed locally instead.
189 celery.always.eager = false
211 celery.always.eager = false
190
212
191 ####################################
213 ####################################
192 ### BEAKER CACHE ####
214 ### BEAKER CACHE ####
193 ####################################
215 ####################################
194 beaker.cache.data_dir=%(here)s/data/cache/data
216 beaker.cache.data_dir=%(here)s/data/cache/data
195 beaker.cache.lock_dir=%(here)s/data/cache/lock
217 beaker.cache.lock_dir=%(here)s/data/cache/lock
196
218
197 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
219 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
198
220
199 beaker.cache.super_short_term.type=memory
221 beaker.cache.super_short_term.type=memory
200 beaker.cache.super_short_term.expire=10
222 beaker.cache.super_short_term.expire=10
201 beaker.cache.super_short_term.key_length = 256
223 beaker.cache.super_short_term.key_length = 256
202
224
203 beaker.cache.short_term.type=memory
225 beaker.cache.short_term.type=memory
204 beaker.cache.short_term.expire=60
226 beaker.cache.short_term.expire=60
205 beaker.cache.short_term.key_length = 256
227 beaker.cache.short_term.key_length = 256
206
228
207 beaker.cache.long_term.type=memory
229 beaker.cache.long_term.type=memory
208 beaker.cache.long_term.expire=36000
230 beaker.cache.long_term.expire=36000
209 beaker.cache.long_term.key_length = 256
231 beaker.cache.long_term.key_length = 256
210
232
211 beaker.cache.sql_cache_short.type=memory
233 beaker.cache.sql_cache_short.type=memory
212 beaker.cache.sql_cache_short.expire=10
234 beaker.cache.sql_cache_short.expire=10
213 beaker.cache.sql_cache_short.key_length = 256
235 beaker.cache.sql_cache_short.key_length = 256
214
236
215 beaker.cache.sql_cache_med.type=memory
237 beaker.cache.sql_cache_med.type=memory
216 beaker.cache.sql_cache_med.expire=360
238 beaker.cache.sql_cache_med.expire=360
217 beaker.cache.sql_cache_med.key_length = 256
239 beaker.cache.sql_cache_med.key_length = 256
218
240
219 beaker.cache.sql_cache_long.type=file
241 beaker.cache.sql_cache_long.type=file
220 beaker.cache.sql_cache_long.expire=3600
242 beaker.cache.sql_cache_long.expire=3600
221 beaker.cache.sql_cache_long.key_length = 256
243 beaker.cache.sql_cache_long.key_length = 256
222
244
223 ####################################
245 ####################################
224 ### BEAKER SESSION ####
246 ### BEAKER SESSION ####
225 ####################################
247 ####################################
226 ## Type of storage used for the session, current types are
248 ## Type of storage used for the session, current types are
227 ## dbm, file, memcached, database, and memory.
249 ## dbm, file, memcached, database, and memory.
228 ## The storage uses the Container API
250 ## The storage uses the Container API
229 ## that is also used by the cache system.
251 ## that is also used by the cache system.
230
252
231 ## db session ##
253 ## db session ##
232 #beaker.session.type = ext:database
254 #beaker.session.type = ext:database
233 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
255 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
234 #beaker.session.table_name = db_session
256 #beaker.session.table_name = db_session
235
257
236 ## encrypted cookie client side session, good for many instances ##
258 ## encrypted cookie client side session, good for many instances ##
237 #beaker.session.type = cookie
259 #beaker.session.type = cookie
238
260
239 ## file based cookies (default) ##
261 ## file based cookies (default) ##
240 #beaker.session.type = file
262 #beaker.session.type = file
241
263
242
264
243 beaker.session.key = rhodecode
265 beaker.session.key = rhodecode
244 ## secure cookie requires AES python libraries ##
266 ## secure cookie requires AES python libraries
245 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
267 #beaker.session.encrypt_key = <key_for_encryption>
246 #beaker.session.validate_key = 9712sds2212c--zxc123
268 #beaker.session.validate_key = <validation_key>
269
247 ## sets session as invalid if it haven't been accessed for given amount of time
270 ## sets session as invalid if it haven't been accessed for given amount of time
248 beaker.session.timeout = 2592000
271 beaker.session.timeout = 2592000
249 beaker.session.httponly = true
272 beaker.session.httponly = true
250 #beaker.session.cookie_path = /<your-prefix>
273 #beaker.session.cookie_path = /<your-prefix>
251
274
252 ## uncomment for https secure cookie ##
275 ## uncomment for https secure cookie
253 beaker.session.secure = false
276 beaker.session.secure = false
254
277
255 ## auto save the session to not to use .save() ##
278 ## auto save the session to not to use .save()
256 beaker.session.auto = False
279 beaker.session.auto = False
257
280
258 ## default cookie expiration time in seconds `true` expire at browser close ##
281 ## default cookie expiration time in seconds `true` expire at browser close ##
259 #beaker.session.cookie_expires = 3600
282 #beaker.session.cookie_expires = 3600
260
283
261
284
262 ############################
285 ############################
263 ## ERROR HANDLING SYSTEMS ##
286 ## ERROR HANDLING SYSTEMS ##
264 ############################
287 ############################
265
288
266 ####################
289 ####################
267 ### [errormator] ###
290 ### [errormator] ###
268 ####################
291 ####################
269
292
270 # Errormator is tailored to work with RhodeCode, see
293 ## Errormator is tailored to work with RhodeCode, see
271 # http://errormator.com for details how to obtain an account
294 ## http://errormator.com for details how to obtain an account
272 # you must install python package `errormator_client` to make it work
295 ## you must install python package `errormator_client` to make it work
273
296
274 # errormator enabled
297 ## errormator enabled
275 errormator = true
298 errormator = false
276
299
277 errormator.server_url = https://api.errormator.com
300 errormator.server_url = https://api.errormator.com
278 errormator.api_key = YOUR_API_KEY
301 errormator.api_key = YOUR_API_KEY
279
302
280 # TWEAK AMOUNT OF INFO SENT HERE
303 ## TWEAK AMOUNT OF INFO SENT HERE
281
304
282 # enables 404 error logging (default False)
305 ## enables 404 error logging (default False)
283 errormator.report_404 = false
306 errormator.report_404 = false
284
307
285 # time in seconds after request is considered being slow (default 1)
308 ## time in seconds after request is considered being slow (default 1)
286 errormator.slow_request_time = 1
309 errormator.slow_request_time = 1
287
310
288 # record slow requests in application
311 ## record slow requests in application
289 # (needs to be enabled for slow datastore recording and time tracking)
312 ## (needs to be enabled for slow datastore recording and time tracking)
290 errormator.slow_requests = true
313 errormator.slow_requests = true
291
314
292 # enable hooking to application loggers
315 ## enable hooking to application loggers
293 # errormator.logging = true
316 # errormator.logging = true
294
317
295 # minimum log level for log capture
318 ## minimum log level for log capture
296 # errormator.logging.level = WARNING
319 # errormator.logging.level = WARNING
297
320
298 # send logs only from erroneous/slow requests
321 ## send logs only from erroneous/slow requests
299 # (saves API quota for intensive logging)
322 ## (saves API quota for intensive logging)
300 errormator.logging_on_error = false
323 errormator.logging_on_error = false
301
324
302 # list of additonal keywords that should be grabbed from environ object
325 ## list of additonal keywords that should be grabbed from environ object
303 # can be string with comma separated list of words in lowercase
326 ## can be string with comma separated list of words in lowercase
304 # (by default client will always send following info:
327 ## (by default client will always send following info:
305 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
328 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
306 # start with HTTP* this list be extended with additional keywords here
329 ## start with HTTP* this list be extended with additional keywords here
307 errormator.environ_keys_whitelist =
330 errormator.environ_keys_whitelist =
308
331
309
332
310 # list of keywords that should be blanked from request object
333 ## list of keywords that should be blanked from request object
311 # can be string with comma separated list of words in lowercase
334 ## can be string with comma separated list of words in lowercase
312 # (by default client will always blank keys that contain following words
335 ## (by default client will always blank keys that contain following words
313 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
336 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
314 # this list be extended with additional keywords set here
337 ## this list be extended with additional keywords set here
315 errormator.request_keys_blacklist =
338 errormator.request_keys_blacklist =
316
339
317
340
318 # list of namespaces that should be ignores when gathering log entries
341 ## list of namespaces that should be ignores when gathering log entries
319 # can be string with comma separated list of namespaces
342 ## can be string with comma separated list of namespaces
320 # (by default the client ignores own entries: errormator_client.client)
343 ## (by default the client ignores own entries: errormator_client.client)
321 errormator.log_namespace_blacklist =
344 errormator.log_namespace_blacklist =
322
345
323
346
324 ################
347 ################
325 ### [sentry] ###
348 ### [sentry] ###
326 ################
349 ################
327
350
328 # sentry is a alternative open source error aggregator
351 ## sentry is a alternative open source error aggregator
329 # you must install python packages `sentry` and `raven` to enable
352 ## you must install python packages `sentry` and `raven` to enable
330
353
331 sentry.dsn = YOUR_DNS
354 sentry.dsn = YOUR_DNS
332 sentry.servers =
355 sentry.servers =
333 sentry.name =
356 sentry.name =
334 sentry.key =
357 sentry.key =
335 sentry.public_key =
358 sentry.public_key =
336 sentry.secret_key =
359 sentry.secret_key =
337 sentry.project =
360 sentry.project =
338 sentry.site =
361 sentry.site =
339 sentry.include_paths =
362 sentry.include_paths =
340 sentry.exclude_paths =
363 sentry.exclude_paths =
341
364
342
365
343 ################################################################################
366 ################################################################################
344 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
367 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
345 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
368 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
346 ## execute malicious code after an exception is raised. ##
369 ## execute malicious code after an exception is raised. ##
347 ################################################################################
370 ################################################################################
348 set debug = false
371 set debug = false
349
372
350 ##################################
373 ##################################
351 ### LOGVIEW CONFIG ###
374 ### LOGVIEW CONFIG ###
352 ##################################
375 ##################################
353 logview.sqlalchemy = #faa
376 logview.sqlalchemy = #faa
354 logview.pylons.templating = #bfb
377 logview.pylons.templating = #bfb
355 logview.pylons.util = #eee
378 logview.pylons.util = #eee
356
379
357 #########################################################
380 #########################################################
358 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
381 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
359 #########################################################
382 #########################################################
360 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
383 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
361 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
384 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
362 sqlalchemy.db1.echo = false
385 sqlalchemy.db1.echo = false
363 sqlalchemy.db1.pool_recycle = 3600
386 sqlalchemy.db1.pool_recycle = 3600
364 sqlalchemy.db1.convert_unicode = true
387 sqlalchemy.db1.convert_unicode = true
365
388
366 ################################
389 ################################
367 ### LOGGING CONFIGURATION ####
390 ### LOGGING CONFIGURATION ####
368 ################################
391 ################################
369 [loggers]
392 [loggers]
370 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
393 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
371
394
372 [handlers]
395 [handlers]
373 keys = console, console_sql
396 keys = console, console_sql
374
397
375 [formatters]
398 [formatters]
376 keys = generic, color_formatter, color_formatter_sql
399 keys = generic, color_formatter, color_formatter_sql
377
400
378 #############
401 #############
379 ## LOGGERS ##
402 ## LOGGERS ##
380 #############
403 #############
381 [logger_root]
404 [logger_root]
382 level = NOTSET
405 level = NOTSET
383 handlers = console
406 handlers = console
384
407
385 [logger_routes]
408 [logger_routes]
386 level = DEBUG
409 level = DEBUG
387 handlers =
410 handlers =
388 qualname = routes.middleware
411 qualname = routes.middleware
389 # "level = DEBUG" logs the route matched and routing variables.
412 ## "level = DEBUG" logs the route matched and routing variables.
390 propagate = 1
413 propagate = 1
391
414
392 [logger_beaker]
415 [logger_beaker]
393 level = DEBUG
416 level = DEBUG
394 handlers =
417 handlers =
395 qualname = beaker.container
418 qualname = beaker.container
396 propagate = 1
419 propagate = 1
397
420
398 [logger_templates]
421 [logger_templates]
399 level = INFO
422 level = INFO
400 handlers =
423 handlers =
401 qualname = pylons.templating
424 qualname = pylons.templating
402 propagate = 1
425 propagate = 1
403
426
404 [logger_rhodecode]
427 [logger_rhodecode]
405 level = DEBUG
428 level = DEBUG
406 handlers =
429 handlers =
407 qualname = rhodecode
430 qualname = rhodecode
408 propagate = 1
431 propagate = 1
409
432
410 [logger_sqlalchemy]
433 [logger_sqlalchemy]
411 level = INFO
434 level = INFO
412 handlers = console_sql
435 handlers = console_sql
413 qualname = sqlalchemy.engine
436 qualname = sqlalchemy.engine
414 propagate = 0
437 propagate = 0
415
438
416 [logger_whoosh_indexer]
439 [logger_whoosh_indexer]
417 level = DEBUG
440 level = DEBUG
418 handlers =
441 handlers =
419 qualname = whoosh_indexer
442 qualname = whoosh_indexer
420 propagate = 1
443 propagate = 1
421
444
422 ##############
445 ##############
423 ## HANDLERS ##
446 ## HANDLERS ##
424 ##############
447 ##############
425
448
426 [handler_console]
449 [handler_console]
427 class = StreamHandler
450 class = StreamHandler
428 args = (sys.stderr,)
451 args = (sys.stderr,)
429 level = INFO
452 level = INFO
430 formatter = generic
453 formatter = generic
431
454
432 [handler_console_sql]
455 [handler_console_sql]
433 class = StreamHandler
456 class = StreamHandler
434 args = (sys.stderr,)
457 args = (sys.stderr,)
435 level = WARN
458 level = WARN
436 formatter = generic
459 formatter = generic
437
460
438 ################
461 ################
439 ## FORMATTERS ##
462 ## FORMATTERS ##
440 ################
463 ################
441
464
442 [formatter_generic]
465 [formatter_generic]
443 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
466 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
444 datefmt = %Y-%m-%d %H:%M:%S
467 datefmt = %Y-%m-%d %H:%M:%S
445
468
446 [formatter_color_formatter]
469 [formatter_color_formatter]
447 class=rhodecode.lib.colored_formatter.ColorFormatter
470 class=rhodecode.lib.colored_formatter.ColorFormatter
448 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
471 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
449 datefmt = %Y-%m-%d %H:%M:%S
472 datefmt = %Y-%m-%d %H:%M:%S
450
473
451 [formatter_color_formatter_sql]
474 [formatter_color_formatter_sql]
452 class=rhodecode.lib.colored_formatter.ColorFormatterSql
475 class=rhodecode.lib.colored_formatter.ColorFormatterSql
453 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
476 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
454 datefmt = %Y-%m-%d %H:%M:%S
477 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,464 +1,487 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 ##nr of threads to spawn
33 ## nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ## max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ## option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 ## WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 ## 100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 127.0.0.1
50 host = 127.0.0.1
51 port = 5000
51 port = 5000
52
52
53 [filter:proxy-prefix]
53 ## prefix middleware for rc
54 # prefix middleware for rc
54 #[filter:proxy-prefix]
55 use = egg:PasteDeploy#prefix
55 #use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 #prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 ## enable proxy prefix middleware
60 #filter-with = proxy-prefix
61 #filter-with = proxy-prefix
62
61 full_stack = true
63 full_stack = true
62 static_files = true
64 static_files = true
63 # Optional Languages
65 ## Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
66 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
67 lang = en
66 cache_dir = %(here)s/data
68 cache_dir = %(here)s/data
67 index_dir = %(here)s/data/index
69 index_dir = %(here)s/data/index
68 # set this path to use archive download cache
70
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
71 ## uncomment and set this path to use archive download cache
72 #archive_cache_dir = /tmp/tarballcache
73
74 ## change this to unique ID for security
70 app_instance_uuid = ${app_instance_uuid}
75 app_instance_uuid = ${app_instance_uuid}
76
77 ## cut off limit for large diffs (size in bytes)
71 cut_off_limit = 256000
78 cut_off_limit = 256000
72 vcs_full_cache = True
79
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
80 ## use cache version of scm repo everywhere
81 vcs_full_cache = true
82
83 ## force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
84 force_https = false
75 # use Strict-Transport-Security headers
85
86 ## use Strict-Transport-Security headers
76 use_htsts = false
87 use_htsts = false
77 commit_parse_limit = 50
88
78 # number of items displayed in lightweight dashboard before paginating
89 ## number of commits stats will parse on each iteration
90 commit_parse_limit = 25
91
92 ## number of items displayed in lightweight dashboard before paginating is shown
79 dashboard_items = 100
93 dashboard_items = 100
94
95 ## use gravatar service to display avatars
80 use_gravatar = true
96 use_gravatar = true
81
97
82 # path to git executable
98 ## path to git executable
83 git_path = git
99 git_path = git
84
100
85 ## RSS feed options
101 ## RSS feed options
86
87 rss_cut_off_limit = 256000
102 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
103 rss_items_per_page = 10
89 rss_include_diff = false
104 rss_include_diff = false
90
105
106 ## show hash options for changelog
107 sha_len = 12
108 sha_rev = true
109
91
110
92 ## alternative_gravatar_url allows you to use your own avatar server application
111 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
112 ## the following parts of the URL will be replaced
94 ## {email} user email
113 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
114 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
115 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
116 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
117 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
118 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
119 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
120
121
122 ## container auth options
102 container_auth_enabled = false
123 container_auth_enabled = false
103 proxypass_auth_enabled = false
124 proxypass_auth_enabled = false
125
104 ## default encoding used to convert from and to unicode
126 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
127 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
128 default_encoding = utf8
107
129
108 ## overwrite schema of clone url
130 ## overwrite schema of clone url
109 ## available vars:
131 ## available vars:
110 ## scheme - http/https
132 ## scheme - http/https
111 ## user - current user
133 ## user - current user
112 ## pass - password
134 ## pass - password
113 ## netloc - network location
135 ## netloc - network location
114 ## path - usually repo_name
136 ## path - usually repo_name
115
137
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
138 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
139
118 ## issue tracking mapping for commits messages
140 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
141 ## comment out issue_pat, issue_server, issue_prefix to enable
120
142
121 ## pattern to get the issues from commit messages
143 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
144 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
145 ## {id} will be all groups matched from this pattern
124
146
125 issue_pat = (?:\s*#)(\d+)
147 issue_pat = (?:\s*#)(\d+)
126
148
127 ## server url to the issue, each {id} will be replaced with match
149 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
150 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
151 ## including groups {repo_name} is replaced with just name of repo
130
152
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
153 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
154
133 ## prefix to add to link to indicate it's an url
155 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
156 ## #314 will be replaced by <issue_prefix><id>
135
157
136 issue_prefix = #
158 issue_prefix = #
137
159
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
160 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
161 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
162 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
163 # #wiki-some-id -> https://mywiki.com/some-id
142
164
143 #issue_pat_wiki = (?:wiki-)(.+)
165 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
166 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
167 #issue_prefix_wiki = WIKI-
146
168
147
169
148 ## instance-id prefix
170 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
171 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
172 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
173 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
174 instance_id =
153
175
154 ## alternative return HTTP header for failed authentication. Default HTTP
176 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
177 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
178 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
179 auth_ret_code =
158
180
159 ## locking return code. When repository is locked return this HTTP code. 2XX
181 ## locking return code. When repository is locked return this HTTP code. 2XX
160 ## codes don't break the transactions while 4XX codes do
182 ## codes don't break the transactions while 4XX codes do
161 lock_ret_code = 423
183 lock_ret_code = 423
162
184
163
185
164 ####################################
186 ####################################
165 ### CELERY CONFIG ####
187 ### CELERY CONFIG ####
166 ####################################
188 ####################################
167 use_celery = false
189 use_celery = false
168 broker.host = localhost
190 broker.host = localhost
169 broker.vhost = rabbitmqhost
191 broker.vhost = rabbitmqhost
170 broker.port = 5672
192 broker.port = 5672
171 broker.user = rabbitmq
193 broker.user = rabbitmq
172 broker.password = qweqwe
194 broker.password = qweqwe
173
195
174 celery.imports = rhodecode.lib.celerylib.tasks
196 celery.imports = rhodecode.lib.celerylib.tasks
175
197
176 celery.result.backend = amqp
198 celery.result.backend = amqp
177 celery.result.dburi = amqp://
199 celery.result.dburi = amqp://
178 celery.result.serialier = json
200 celery.result.serialier = json
179
201
180 #celery.send.task.error.emails = true
202 #celery.send.task.error.emails = true
181 #celery.amqp.task.result.expires = 18000
203 #celery.amqp.task.result.expires = 18000
182
204
183 celeryd.concurrency = 2
205 celeryd.concurrency = 2
184 #celeryd.log.file = celeryd.log
206 #celeryd.log.file = celeryd.log
185 celeryd.log.level = debug
207 celeryd.log.level = debug
186 celeryd.max.tasks.per.child = 1
208 celeryd.max.tasks.per.child = 1
187
209
188 #tasks will never be sent to the queue, but executed locally instead.
210 ## tasks will never be sent to the queue, but executed locally instead.
189 celery.always.eager = false
211 celery.always.eager = false
190
212
191 ####################################
213 ####################################
192 ### BEAKER CACHE ####
214 ### BEAKER CACHE ####
193 ####################################
215 ####################################
194 beaker.cache.data_dir=%(here)s/data/cache/data
216 beaker.cache.data_dir=%(here)s/data/cache/data
195 beaker.cache.lock_dir=%(here)s/data/cache/lock
217 beaker.cache.lock_dir=%(here)s/data/cache/lock
196
218
197 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
219 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
198
220
199 beaker.cache.super_short_term.type=memory
221 beaker.cache.super_short_term.type=memory
200 beaker.cache.super_short_term.expire=10
222 beaker.cache.super_short_term.expire=10
201 beaker.cache.super_short_term.key_length = 256
223 beaker.cache.super_short_term.key_length = 256
202
224
203 beaker.cache.short_term.type=memory
225 beaker.cache.short_term.type=memory
204 beaker.cache.short_term.expire=60
226 beaker.cache.short_term.expire=60
205 beaker.cache.short_term.key_length = 256
227 beaker.cache.short_term.key_length = 256
206
228
207 beaker.cache.long_term.type=memory
229 beaker.cache.long_term.type=memory
208 beaker.cache.long_term.expire=36000
230 beaker.cache.long_term.expire=36000
209 beaker.cache.long_term.key_length = 256
231 beaker.cache.long_term.key_length = 256
210
232
211 beaker.cache.sql_cache_short.type=memory
233 beaker.cache.sql_cache_short.type=memory
212 beaker.cache.sql_cache_short.expire=10
234 beaker.cache.sql_cache_short.expire=10
213 beaker.cache.sql_cache_short.key_length = 256
235 beaker.cache.sql_cache_short.key_length = 256
214
236
215 beaker.cache.sql_cache_med.type=memory
237 beaker.cache.sql_cache_med.type=memory
216 beaker.cache.sql_cache_med.expire=360
238 beaker.cache.sql_cache_med.expire=360
217 beaker.cache.sql_cache_med.key_length = 256
239 beaker.cache.sql_cache_med.key_length = 256
218
240
219 beaker.cache.sql_cache_long.type=file
241 beaker.cache.sql_cache_long.type=file
220 beaker.cache.sql_cache_long.expire=3600
242 beaker.cache.sql_cache_long.expire=3600
221 beaker.cache.sql_cache_long.key_length = 256
243 beaker.cache.sql_cache_long.key_length = 256
222
244
223 ####################################
245 ####################################
224 ### BEAKER SESSION ####
246 ### BEAKER SESSION ####
225 ####################################
247 ####################################
226 ## Type of storage used for the session, current types are
248 ## Type of storage used for the session, current types are
227 ## dbm, file, memcached, database, and memory.
249 ## dbm, file, memcached, database, and memory.
228 ## The storage uses the Container API
250 ## The storage uses the Container API
229 ## that is also used by the cache system.
251 ## that is also used by the cache system.
230
252
231 ## db session ##
253 ## db session ##
232 #beaker.session.type = ext:database
254 #beaker.session.type = ext:database
233 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
255 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
234 #beaker.session.table_name = db_session
256 #beaker.session.table_name = db_session
235
257
236 ## encrypted cookie client side session, good for many instances ##
258 ## encrypted cookie client side session, good for many instances ##
237 #beaker.session.type = cookie
259 #beaker.session.type = cookie
238
260
239 ## file based cookies (default) ##
261 ## file based cookies (default) ##
240 #beaker.session.type = file
262 #beaker.session.type = file
241
263
242
264
243 beaker.session.key = rhodecode
265 beaker.session.key = rhodecode
244 ## secure cookie requires AES python libraries ##
266 ## secure cookie requires AES python libraries
245 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
267 #beaker.session.encrypt_key = <key_for_encryption>
246 #beaker.session.validate_key = 9712sds2212c--zxc123
268 #beaker.session.validate_key = <validation_key>
269
247 ## sets session as invalid if it haven't been accessed for given amount of time
270 ## sets session as invalid if it haven't been accessed for given amount of time
248 beaker.session.timeout = 2592000
271 beaker.session.timeout = 2592000
249 beaker.session.httponly = true
272 beaker.session.httponly = true
250 #beaker.session.cookie_path = /<your-prefix>
273 #beaker.session.cookie_path = /<your-prefix>
251
274
252 ## uncomment for https secure cookie ##
275 ## uncomment for https secure cookie
253 beaker.session.secure = false
276 beaker.session.secure = false
254
277
255 ## auto save the session to not to use .save() ##
278 ## auto save the session to not to use .save()
256 beaker.session.auto = False
279 beaker.session.auto = False
257
280
258 ## default cookie expiration time in seconds `true` expire at browser close ##
281 ## default cookie expiration time in seconds `true` expire at browser close ##
259 #beaker.session.cookie_expires = 3600
282 #beaker.session.cookie_expires = 3600
260
283
261
284
262 ############################
285 ############################
263 ## ERROR HANDLING SYSTEMS ##
286 ## ERROR HANDLING SYSTEMS ##
264 ############################
287 ############################
265
288
266 ####################
289 ####################
267 ### [errormator] ###
290 ### [errormator] ###
268 ####################
291 ####################
269
292
270 # Errormator is tailored to work with RhodeCode, see
293 ## Errormator is tailored to work with RhodeCode, see
271 # http://errormator.com for details how to obtain an account
294 ## http://errormator.com for details how to obtain an account
272 # you must install python package `errormator_client` to make it work
295 ## you must install python package `errormator_client` to make it work
273
296
274 # errormator enabled
297 ## errormator enabled
275 errormator = true
298 errormator = false
276
299
277 errormator.server_url = https://api.errormator.com
300 errormator.server_url = https://api.errormator.com
278 errormator.api_key = YOUR_API_KEY
301 errormator.api_key = YOUR_API_KEY
279
302
280 # TWEAK AMOUNT OF INFO SENT HERE
303 ## TWEAK AMOUNT OF INFO SENT HERE
281
304
282 # enables 404 error logging (default False)
305 ## enables 404 error logging (default False)
283 errormator.report_404 = false
306 errormator.report_404 = false
284
307
285 # time in seconds after request is considered being slow (default 1)
308 ## time in seconds after request is considered being slow (default 1)
286 errormator.slow_request_time = 1
309 errormator.slow_request_time = 1
287
310
288 # record slow requests in application
311 ## record slow requests in application
289 # (needs to be enabled for slow datastore recording and time tracking)
312 ## (needs to be enabled for slow datastore recording and time tracking)
290 errormator.slow_requests = true
313 errormator.slow_requests = true
291
314
292 # enable hooking to application loggers
315 ## enable hooking to application loggers
293 # errormator.logging = true
316 # errormator.logging = true
294
317
295 # minimum log level for log capture
318 ## minimum log level for log capture
296 # errormator.logging.level = WARNING
319 # errormator.logging.level = WARNING
297
320
298 # send logs only from erroneous/slow requests
321 ## send logs only from erroneous/slow requests
299 # (saves API quota for intensive logging)
322 ## (saves API quota for intensive logging)
300 errormator.logging_on_error = false
323 errormator.logging_on_error = false
301
324
302 # list of additonal keywords that should be grabbed from environ object
325 ## list of additonal keywords that should be grabbed from environ object
303 # can be string with comma separated list of words in lowercase
326 ## can be string with comma separated list of words in lowercase
304 # (by default client will always send following info:
327 ## (by default client will always send following info:
305 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
328 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
306 # start with HTTP* this list be extended with additional keywords here
329 ## start with HTTP* this list be extended with additional keywords here
307 errormator.environ_keys_whitelist =
330 errormator.environ_keys_whitelist =
308
331
309
332
310 # list of keywords that should be blanked from request object
333 ## list of keywords that should be blanked from request object
311 # can be string with comma separated list of words in lowercase
334 ## can be string with comma separated list of words in lowercase
312 # (by default client will always blank keys that contain following words
335 ## (by default client will always blank keys that contain following words
313 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
336 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
314 # this list be extended with additional keywords set here
337 ## this list be extended with additional keywords set here
315 errormator.request_keys_blacklist =
338 errormator.request_keys_blacklist =
316
339
317
340
318 # list of namespaces that should be ignores when gathering log entries
341 ## list of namespaces that should be ignores when gathering log entries
319 # can be string with comma separated list of namespaces
342 ## can be string with comma separated list of namespaces
320 # (by default the client ignores own entries: errormator_client.client)
343 ## (by default the client ignores own entries: errormator_client.client)
321 errormator.log_namespace_blacklist =
344 errormator.log_namespace_blacklist =
322
345
323
346
324 ################
347 ################
325 ### [sentry] ###
348 ### [sentry] ###
326 ################
349 ################
327
350
328 # sentry is a alternative open source error aggregator
351 ## sentry is a alternative open source error aggregator
329 # you must install python packages `sentry` and `raven` to enable
352 ## you must install python packages `sentry` and `raven` to enable
330
353
331 sentry.dsn = YOUR_DNS
354 sentry.dsn = YOUR_DNS
332 sentry.servers =
355 sentry.servers =
333 sentry.name =
356 sentry.name =
334 sentry.key =
357 sentry.key =
335 sentry.public_key =
358 sentry.public_key =
336 sentry.secret_key =
359 sentry.secret_key =
337 sentry.project =
360 sentry.project =
338 sentry.site =
361 sentry.site =
339 sentry.include_paths =
362 sentry.include_paths =
340 sentry.exclude_paths =
363 sentry.exclude_paths =
341
364
342
365
343 ################################################################################
366 ################################################################################
344 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
367 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
345 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
368 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
346 ## execute malicious code after an exception is raised. ##
369 ## execute malicious code after an exception is raised. ##
347 ################################################################################
370 ################################################################################
348 set debug = false
371 set debug = false
349
372
350 ##################################
373 ##################################
351 ### LOGVIEW CONFIG ###
374 ### LOGVIEW CONFIG ###
352 ##################################
375 ##################################
353 logview.sqlalchemy = #faa
376 logview.sqlalchemy = #faa
354 logview.pylons.templating = #bfb
377 logview.pylons.templating = #bfb
355 logview.pylons.util = #eee
378 logview.pylons.util = #eee
356
379
357 #########################################################
380 #########################################################
358 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
381 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
359 #########################################################
382 #########################################################
360
383
361 # SQLITE [default]
384 # SQLITE [default]
362 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
385 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
363
386
364 # POSTGRESQL
387 # POSTGRESQL
365 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
388 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
366
389
367 # MySQL
390 # MySQL
368 # sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
391 # sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
369
392
370 # see sqlalchemy docs for others
393 # see sqlalchemy docs for others
371
394
372 sqlalchemy.db1.echo = false
395 sqlalchemy.db1.echo = false
373 sqlalchemy.db1.pool_recycle = 3600
396 sqlalchemy.db1.pool_recycle = 3600
374 sqlalchemy.db1.convert_unicode = true
397 sqlalchemy.db1.convert_unicode = true
375
398
376 ################################
399 ################################
377 ### LOGGING CONFIGURATION ####
400 ### LOGGING CONFIGURATION ####
378 ################################
401 ################################
379 [loggers]
402 [loggers]
380 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
403 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
381
404
382 [handlers]
405 [handlers]
383 keys = console, console_sql
406 keys = console, console_sql
384
407
385 [formatters]
408 [formatters]
386 keys = generic, color_formatter, color_formatter_sql
409 keys = generic, color_formatter, color_formatter_sql
387
410
388 #############
411 #############
389 ## LOGGERS ##
412 ## LOGGERS ##
390 #############
413 #############
391 [logger_root]
414 [logger_root]
392 level = NOTSET
415 level = NOTSET
393 handlers = console
416 handlers = console
394
417
395 [logger_routes]
418 [logger_routes]
396 level = DEBUG
419 level = DEBUG
397 handlers =
420 handlers =
398 qualname = routes.middleware
421 qualname = routes.middleware
399 # "level = DEBUG" logs the route matched and routing variables.
422 ## "level = DEBUG" logs the route matched and routing variables.
400 propagate = 1
423 propagate = 1
401
424
402 [logger_beaker]
425 [logger_beaker]
403 level = DEBUG
426 level = DEBUG
404 handlers =
427 handlers =
405 qualname = beaker.container
428 qualname = beaker.container
406 propagate = 1
429 propagate = 1
407
430
408 [logger_templates]
431 [logger_templates]
409 level = INFO
432 level = INFO
410 handlers =
433 handlers =
411 qualname = pylons.templating
434 qualname = pylons.templating
412 propagate = 1
435 propagate = 1
413
436
414 [logger_rhodecode]
437 [logger_rhodecode]
415 level = DEBUG
438 level = DEBUG
416 handlers =
439 handlers =
417 qualname = rhodecode
440 qualname = rhodecode
418 propagate = 1
441 propagate = 1
419
442
420 [logger_sqlalchemy]
443 [logger_sqlalchemy]
421 level = INFO
444 level = INFO
422 handlers = console_sql
445 handlers = console_sql
423 qualname = sqlalchemy.engine
446 qualname = sqlalchemy.engine
424 propagate = 0
447 propagate = 0
425
448
426 [logger_whoosh_indexer]
449 [logger_whoosh_indexer]
427 level = DEBUG
450 level = DEBUG
428 handlers =
451 handlers =
429 qualname = whoosh_indexer
452 qualname = whoosh_indexer
430 propagate = 1
453 propagate = 1
431
454
432 ##############
455 ##############
433 ## HANDLERS ##
456 ## HANDLERS ##
434 ##############
457 ##############
435
458
436 [handler_console]
459 [handler_console]
437 class = StreamHandler
460 class = StreamHandler
438 args = (sys.stderr,)
461 args = (sys.stderr,)
439 level = INFO
462 level = INFO
440 formatter = generic
463 formatter = generic
441
464
442 [handler_console_sql]
465 [handler_console_sql]
443 class = StreamHandler
466 class = StreamHandler
444 args = (sys.stderr,)
467 args = (sys.stderr,)
445 level = WARN
468 level = WARN
446 formatter = generic
469 formatter = generic
447
470
448 ################
471 ################
449 ## FORMATTERS ##
472 ## FORMATTERS ##
450 ################
473 ################
451
474
452 [formatter_generic]
475 [formatter_generic]
453 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
476 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
454 datefmt = %Y-%m-%d %H:%M:%S
477 datefmt = %Y-%m-%d %H:%M:%S
455
478
456 [formatter_color_formatter]
479 [formatter_color_formatter]
457 class=rhodecode.lib.colored_formatter.ColorFormatter
480 class=rhodecode.lib.colored_formatter.ColorFormatter
458 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
481 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
459 datefmt = %Y-%m-%d %H:%M:%S
482 datefmt = %Y-%m-%d %H:%M:%S
460
483
461 [formatter_color_formatter_sql]
484 [formatter_color_formatter_sql]
462 class=rhodecode.lib.colored_formatter.ColorFormatterSql
485 class=rhodecode.lib.colored_formatter.ColorFormatterSql
463 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
486 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
464 datefmt = %Y-%m-%d %H:%M:%S
487 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,1195 +1,1214 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 import StringIO
8 import StringIO
9 import urllib
9 import urllib
10 import math
10 import math
11 import logging
11 import logging
12 import re
12 import re
13 import urlparse
13 import urlparse
14 import textwrap
14 import textwrap
15
15
16 from datetime import datetime
16 from datetime import datetime
17 from pygments.formatters.html import HtmlFormatter
17 from pygments.formatters.html import HtmlFormatter
18 from pygments import highlight as code_highlight
18 from pygments import highlight as code_highlight
19 from pylons import url, request, config
19 from pylons import url, request, config
20 from pylons.i18n.translation import _, ungettext
20 from pylons.i18n.translation import _, ungettext
21 from hashlib import md5
21 from hashlib import md5
22
22
23 from webhelpers.html import literal, HTML, escape
23 from webhelpers.html import literal, HTML, escape
24 from webhelpers.html.tools import *
24 from webhelpers.html.tools import *
25 from webhelpers.html.builder import make_tag
25 from webhelpers.html.builder import make_tag
26 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
26 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
27 end_form, file, form, hidden, image, javascript_link, link_to, \
27 end_form, file, form, hidden, image, javascript_link, link_to, \
28 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
28 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
29 submit, text, password, textarea, title, ul, xml_declaration, radio
29 submit, text, password, textarea, title, ul, xml_declaration, radio
30 from webhelpers.html.tools import auto_link, button_to, highlight, \
30 from webhelpers.html.tools import auto_link, button_to, highlight, \
31 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
31 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
32 from webhelpers.number import format_byte_size, format_bit_size
32 from webhelpers.number import format_byte_size, format_bit_size
33 from webhelpers.pylonslib import Flash as _Flash
33 from webhelpers.pylonslib import Flash as _Flash
34 from webhelpers.pylonslib.secure_form import secure_form
34 from webhelpers.pylonslib.secure_form import secure_form
35 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
35 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
36 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
36 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
37 replace_whitespace, urlify, truncate, wrap_paragraphs
37 replace_whitespace, urlify, truncate, wrap_paragraphs
38 from webhelpers.date import time_ago_in_words
38 from webhelpers.date import time_ago_in_words
39 from webhelpers.paginate import Page
39 from webhelpers.paginate import Page
40 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
40 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
41 convert_boolean_attrs, NotGiven, _make_safe_id_component
41 convert_boolean_attrs, NotGiven, _make_safe_id_component
42
42
43 from rhodecode.lib.annotate import annotate_highlight
43 from rhodecode.lib.annotate import annotate_highlight
44 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
44 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
45 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
45 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
46 get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict
46 get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict,\
47 safe_int
47 from rhodecode.lib.markup_renderer import MarkupRenderer
48 from rhodecode.lib.markup_renderer import MarkupRenderer
48 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
49 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
49 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
50 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
50 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
51 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
51 from rhodecode.model.changeset_status import ChangesetStatusModel
52 from rhodecode.model.changeset_status import ChangesetStatusModel
52 from rhodecode.model.db import URL_SEP, Permission
53 from rhodecode.model.db import URL_SEP, Permission
53
54
54 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
55
56
56
57
57 html_escape_table = {
58 html_escape_table = {
58 "&": "&amp;",
59 "&": "&amp;",
59 '"': "&quot;",
60 '"': "&quot;",
60 "'": "&apos;",
61 "'": "&apos;",
61 ">": "&gt;",
62 ">": "&gt;",
62 "<": "&lt;",
63 "<": "&lt;",
63 }
64 }
64
65
65
66
66 def html_escape(text):
67 def html_escape(text):
67 """Produce entities within text."""
68 """Produce entities within text."""
68 return "".join(html_escape_table.get(c, c) for c in text)
69 return "".join(html_escape_table.get(c, c) for c in text)
69
70
70
71
71 def shorter(text, size=20):
72 def shorter(text, size=20):
72 postfix = '...'
73 postfix = '...'
73 if len(text) > size:
74 if len(text) > size:
74 return text[:size - len(postfix)] + postfix
75 return text[:size - len(postfix)] + postfix
75 return text
76 return text
76
77
77
78
78 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
79 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
79 """
80 """
80 Reset button
81 Reset button
81 """
82 """
82 _set_input_attrs(attrs, type, name, value)
83 _set_input_attrs(attrs, type, name, value)
83 _set_id_attr(attrs, id, name)
84 _set_id_attr(attrs, id, name)
84 convert_boolean_attrs(attrs, ["disabled"])
85 convert_boolean_attrs(attrs, ["disabled"])
85 return HTML.input(**attrs)
86 return HTML.input(**attrs)
86
87
87 reset = _reset
88 reset = _reset
88 safeid = _make_safe_id_component
89 safeid = _make_safe_id_component
89
90
90
91
91 def FID(raw_id, path):
92 def FID(raw_id, path):
92 """
93 """
93 Creates a uniqe ID for filenode based on it's hash of path and revision
94 Creates a uniqe ID for filenode based on it's hash of path and revision
94 it's safe to use in urls
95 it's safe to use in urls
95
96
96 :param raw_id:
97 :param raw_id:
97 :param path:
98 :param path:
98 """
99 """
99
100
100 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
101 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
101
102
102
103
103 def get_token():
104 def get_token():
104 """Return the current authentication token, creating one if one doesn't
105 """Return the current authentication token, creating one if one doesn't
105 already exist.
106 already exist.
106 """
107 """
107 token_key = "_authentication_token"
108 token_key = "_authentication_token"
108 from pylons import session
109 from pylons import session
109 if not token_key in session:
110 if not token_key in session:
110 try:
111 try:
111 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
112 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
112 except AttributeError: # Python < 2.4
113 except AttributeError: # Python < 2.4
113 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
114 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
114 session[token_key] = token
115 session[token_key] = token
115 if hasattr(session, 'save'):
116 if hasattr(session, 'save'):
116 session.save()
117 session.save()
117 return session[token_key]
118 return session[token_key]
118
119
119
120
120 class _GetError(object):
121 class _GetError(object):
121 """Get error from form_errors, and represent it as span wrapped error
122 """Get error from form_errors, and represent it as span wrapped error
122 message
123 message
123
124
124 :param field_name: field to fetch errors for
125 :param field_name: field to fetch errors for
125 :param form_errors: form errors dict
126 :param form_errors: form errors dict
126 """
127 """
127
128
128 def __call__(self, field_name, form_errors):
129 def __call__(self, field_name, form_errors):
129 tmpl = """<span class="error_msg">%s</span>"""
130 tmpl = """<span class="error_msg">%s</span>"""
130 if form_errors and field_name in form_errors:
131 if form_errors and field_name in form_errors:
131 return literal(tmpl % form_errors.get(field_name))
132 return literal(tmpl % form_errors.get(field_name))
132
133
133 get_error = _GetError()
134 get_error = _GetError()
134
135
135
136
136 class _ToolTip(object):
137 class _ToolTip(object):
137
138
138 def __call__(self, tooltip_title, trim_at=50):
139 def __call__(self, tooltip_title, trim_at=50):
139 """
140 """
140 Special function just to wrap our text into nice formatted
141 Special function just to wrap our text into nice formatted
141 autowrapped text
142 autowrapped text
142
143
143 :param tooltip_title:
144 :param tooltip_title:
144 """
145 """
145 tooltip_title = escape(tooltip_title)
146 tooltip_title = escape(tooltip_title)
146 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
147 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
147 return tooltip_title
148 return tooltip_title
148 tooltip = _ToolTip()
149 tooltip = _ToolTip()
149
150
150
151
151 class _FilesBreadCrumbs(object):
152 class _FilesBreadCrumbs(object):
152
153
153 def __call__(self, repo_name, rev, paths):
154 def __call__(self, repo_name, rev, paths):
154 if isinstance(paths, str):
155 if isinstance(paths, str):
155 paths = safe_unicode(paths)
156 paths = safe_unicode(paths)
156 url_l = [link_to(repo_name, url('files_home',
157 url_l = [link_to(repo_name, url('files_home',
157 repo_name=repo_name,
158 repo_name=repo_name,
158 revision=rev, f_path=''),
159 revision=rev, f_path=''),
159 class_='ypjax-link')]
160 class_='ypjax-link')]
160 paths_l = paths.split('/')
161 paths_l = paths.split('/')
161 for cnt, p in enumerate(paths_l):
162 for cnt, p in enumerate(paths_l):
162 if p != '':
163 if p != '':
163 url_l.append(link_to(p,
164 url_l.append(link_to(p,
164 url('files_home',
165 url('files_home',
165 repo_name=repo_name,
166 repo_name=repo_name,
166 revision=rev,
167 revision=rev,
167 f_path='/'.join(paths_l[:cnt + 1])
168 f_path='/'.join(paths_l[:cnt + 1])
168 ),
169 ),
169 class_='ypjax-link'
170 class_='ypjax-link'
170 )
171 )
171 )
172 )
172
173
173 return literal('/'.join(url_l))
174 return literal('/'.join(url_l))
174
175
175 files_breadcrumbs = _FilesBreadCrumbs()
176 files_breadcrumbs = _FilesBreadCrumbs()
176
177
177
178
178 class CodeHtmlFormatter(HtmlFormatter):
179 class CodeHtmlFormatter(HtmlFormatter):
179 """
180 """
180 My code Html Formatter for source codes
181 My code Html Formatter for source codes
181 """
182 """
182
183
183 def wrap(self, source, outfile):
184 def wrap(self, source, outfile):
184 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
185 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
185
186
186 def _wrap_code(self, source):
187 def _wrap_code(self, source):
187 for cnt, it in enumerate(source):
188 for cnt, it in enumerate(source):
188 i, t = it
189 i, t = it
189 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
190 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
190 yield i, t
191 yield i, t
191
192
192 def _wrap_tablelinenos(self, inner):
193 def _wrap_tablelinenos(self, inner):
193 dummyoutfile = StringIO.StringIO()
194 dummyoutfile = StringIO.StringIO()
194 lncount = 0
195 lncount = 0
195 for t, line in inner:
196 for t, line in inner:
196 if t:
197 if t:
197 lncount += 1
198 lncount += 1
198 dummyoutfile.write(line)
199 dummyoutfile.write(line)
199
200
200 fl = self.linenostart
201 fl = self.linenostart
201 mw = len(str(lncount + fl - 1))
202 mw = len(str(lncount + fl - 1))
202 sp = self.linenospecial
203 sp = self.linenospecial
203 st = self.linenostep
204 st = self.linenostep
204 la = self.lineanchors
205 la = self.lineanchors
205 aln = self.anchorlinenos
206 aln = self.anchorlinenos
206 nocls = self.noclasses
207 nocls = self.noclasses
207 if sp:
208 if sp:
208 lines = []
209 lines = []
209
210
210 for i in range(fl, fl + lncount):
211 for i in range(fl, fl + lncount):
211 if i % st == 0:
212 if i % st == 0:
212 if i % sp == 0:
213 if i % sp == 0:
213 if aln:
214 if aln:
214 lines.append('<a href="#%s%d" class="special">%*d</a>' %
215 lines.append('<a href="#%s%d" class="special">%*d</a>' %
215 (la, i, mw, i))
216 (la, i, mw, i))
216 else:
217 else:
217 lines.append('<span class="special">%*d</span>' % (mw, i))
218 lines.append('<span class="special">%*d</span>' % (mw, i))
218 else:
219 else:
219 if aln:
220 if aln:
220 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
221 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
221 else:
222 else:
222 lines.append('%*d' % (mw, i))
223 lines.append('%*d' % (mw, i))
223 else:
224 else:
224 lines.append('')
225 lines.append('')
225 ls = '\n'.join(lines)
226 ls = '\n'.join(lines)
226 else:
227 else:
227 lines = []
228 lines = []
228 for i in range(fl, fl + lncount):
229 for i in range(fl, fl + lncount):
229 if i % st == 0:
230 if i % st == 0:
230 if aln:
231 if aln:
231 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
232 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
232 else:
233 else:
233 lines.append('%*d' % (mw, i))
234 lines.append('%*d' % (mw, i))
234 else:
235 else:
235 lines.append('')
236 lines.append('')
236 ls = '\n'.join(lines)
237 ls = '\n'.join(lines)
237
238
238 # in case you wonder about the seemingly redundant <div> here: since the
239 # in case you wonder about the seemingly redundant <div> here: since the
239 # content in the other cell also is wrapped in a div, some browsers in
240 # content in the other cell also is wrapped in a div, some browsers in
240 # some configurations seem to mess up the formatting...
241 # some configurations seem to mess up the formatting...
241 if nocls:
242 if nocls:
242 yield 0, ('<table class="%stable">' % self.cssclass +
243 yield 0, ('<table class="%stable">' % self.cssclass +
243 '<tr><td><div class="linenodiv" '
244 '<tr><td><div class="linenodiv" '
244 'style="background-color: #f0f0f0; padding-right: 10px">'
245 'style="background-color: #f0f0f0; padding-right: 10px">'
245 '<pre style="line-height: 125%">' +
246 '<pre style="line-height: 125%">' +
246 ls + '</pre></div></td><td id="hlcode" class="code">')
247 ls + '</pre></div></td><td id="hlcode" class="code">')
247 else:
248 else:
248 yield 0, ('<table class="%stable">' % self.cssclass +
249 yield 0, ('<table class="%stable">' % self.cssclass +
249 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
250 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
250 ls + '</pre></div></td><td id="hlcode" class="code">')
251 ls + '</pre></div></td><td id="hlcode" class="code">')
251 yield 0, dummyoutfile.getvalue()
252 yield 0, dummyoutfile.getvalue()
252 yield 0, '</td></tr></table>'
253 yield 0, '</td></tr></table>'
253
254
254
255
255 def pygmentize(filenode, **kwargs):
256 def pygmentize(filenode, **kwargs):
256 """
257 """
257 pygmentize function using pygments
258 pygmentize function using pygments
258
259
259 :param filenode:
260 :param filenode:
260 """
261 """
261 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
262 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
262 return literal(code_highlight(filenode.content, lexer,
263 return literal(code_highlight(filenode.content, lexer,
263 CodeHtmlFormatter(**kwargs)))
264 CodeHtmlFormatter(**kwargs)))
264
265
265
266
266 def pygmentize_annotation(repo_name, filenode, **kwargs):
267 def pygmentize_annotation(repo_name, filenode, **kwargs):
267 """
268 """
268 pygmentize function for annotation
269 pygmentize function for annotation
269
270
270 :param filenode:
271 :param filenode:
271 """
272 """
272
273
273 color_dict = {}
274 color_dict = {}
274
275
275 def gen_color(n=10000):
276 def gen_color(n=10000):
276 """generator for getting n of evenly distributed colors using
277 """generator for getting n of evenly distributed colors using
277 hsv color and golden ratio. It always return same order of colors
278 hsv color and golden ratio. It always return same order of colors
278
279
279 :returns: RGB tuple
280 :returns: RGB tuple
280 """
281 """
281
282
282 def hsv_to_rgb(h, s, v):
283 def hsv_to_rgb(h, s, v):
283 if s == 0.0:
284 if s == 0.0:
284 return v, v, v
285 return v, v, v
285 i = int(h * 6.0) # XXX assume int() truncates!
286 i = int(h * 6.0) # XXX assume int() truncates!
286 f = (h * 6.0) - i
287 f = (h * 6.0) - i
287 p = v * (1.0 - s)
288 p = v * (1.0 - s)
288 q = v * (1.0 - s * f)
289 q = v * (1.0 - s * f)
289 t = v * (1.0 - s * (1.0 - f))
290 t = v * (1.0 - s * (1.0 - f))
290 i = i % 6
291 i = i % 6
291 if i == 0:
292 if i == 0:
292 return v, t, p
293 return v, t, p
293 if i == 1:
294 if i == 1:
294 return q, v, p
295 return q, v, p
295 if i == 2:
296 if i == 2:
296 return p, v, t
297 return p, v, t
297 if i == 3:
298 if i == 3:
298 return p, q, v
299 return p, q, v
299 if i == 4:
300 if i == 4:
300 return t, p, v
301 return t, p, v
301 if i == 5:
302 if i == 5:
302 return v, p, q
303 return v, p, q
303
304
304 golden_ratio = 0.618033988749895
305 golden_ratio = 0.618033988749895
305 h = 0.22717784590367374
306 h = 0.22717784590367374
306
307
307 for _ in xrange(n):
308 for _ in xrange(n):
308 h += golden_ratio
309 h += golden_ratio
309 h %= 1
310 h %= 1
310 HSV_tuple = [h, 0.95, 0.95]
311 HSV_tuple = [h, 0.95, 0.95]
311 RGB_tuple = hsv_to_rgb(*HSV_tuple)
312 RGB_tuple = hsv_to_rgb(*HSV_tuple)
312 yield map(lambda x: str(int(x * 256)), RGB_tuple)
313 yield map(lambda x: str(int(x * 256)), RGB_tuple)
313
314
314 cgenerator = gen_color()
315 cgenerator = gen_color()
315
316
316 def get_color_string(cs):
317 def get_color_string(cs):
317 if cs in color_dict:
318 if cs in color_dict:
318 col = color_dict[cs]
319 col = color_dict[cs]
319 else:
320 else:
320 col = color_dict[cs] = cgenerator.next()
321 col = color_dict[cs] = cgenerator.next()
321 return "color: rgb(%s)! important;" % (', '.join(col))
322 return "color: rgb(%s)! important;" % (', '.join(col))
322
323
323 def url_func(repo_name):
324 def url_func(repo_name):
324
325
325 def _url_func(changeset):
326 def _url_func(changeset):
326 author = changeset.author
327 author = changeset.author
327 date = changeset.date
328 date = changeset.date
328 message = tooltip(changeset.message)
329 message = tooltip(changeset.message)
329
330
330 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
331 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
331 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
332 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
332 "</b> %s<br/></div>")
333 "</b> %s<br/></div>")
333
334
334 tooltip_html = tooltip_html % (author, date, message)
335 tooltip_html = tooltip_html % (author, date, message)
335 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
336 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
336 short_id(changeset.raw_id))
337 short_id(changeset.raw_id))
337 uri = link_to(
338 uri = link_to(
338 lnk_format,
339 lnk_format,
339 url('changeset_home', repo_name=repo_name,
340 url('changeset_home', repo_name=repo_name,
340 revision=changeset.raw_id),
341 revision=changeset.raw_id),
341 style=get_color_string(changeset.raw_id),
342 style=get_color_string(changeset.raw_id),
342 class_='tooltip',
343 class_='tooltip',
343 title=tooltip_html
344 title=tooltip_html
344 )
345 )
345
346
346 uri += '\n'
347 uri += '\n'
347 return uri
348 return uri
348 return _url_func
349 return _url_func
349
350
350 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
351 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
351
352
352
353
353 def is_following_repo(repo_name, user_id):
354 def is_following_repo(repo_name, user_id):
354 from rhodecode.model.scm import ScmModel
355 from rhodecode.model.scm import ScmModel
355 return ScmModel().is_following_repo(repo_name, user_id)
356 return ScmModel().is_following_repo(repo_name, user_id)
356
357
357 flash = _Flash()
358 flash = _Flash()
358
359
359 #==============================================================================
360 #==============================================================================
360 # SCM FILTERS available via h.
361 # SCM FILTERS available via h.
361 #==============================================================================
362 #==============================================================================
362 from rhodecode.lib.vcs.utils import author_name, author_email
363 from rhodecode.lib.vcs.utils import author_name, author_email
363 from rhodecode.lib.utils2 import credentials_filter, age as _age
364 from rhodecode.lib.utils2 import credentials_filter, age as _age
364 from rhodecode.model.db import User, ChangesetStatus
365 from rhodecode.model.db import User, ChangesetStatus
365
366
366 age = lambda x,y=False: _age(x,y)
367 age = lambda x, y=False: _age(x, y)
367 capitalize = lambda x: x.capitalize()
368 capitalize = lambda x: x.capitalize()
368 email = author_email
369 email = author_email
369 short_id = lambda x: x[:12]
370 short_id = lambda x: x[:12]
370 hide_credentials = lambda x: ''.join(credentials_filter(x))
371 hide_credentials = lambda x: ''.join(credentials_filter(x))
371
372
372
373
374 def show_id(cs):
375 """
376 Configurable function that shows ID
377 by default it's r123:fffeeefffeee
378
379 :param cs: changeset instance
380 """
381 from rhodecode import CONFIG
382 def_len = safe_int(CONFIG['sha_len'])
383 show_rev = str2bool(CONFIG['sha_rev'])
384
385 raw_id = cs.raw_id[:def_len]
386 if show_rev:
387 return 'r%s:%s' % (cs.revision, raw_id)
388 else:
389 return '%s' % (raw_id)
390
391
373 def fmt_date(date):
392 def fmt_date(date):
374 if date:
393 if date:
375 _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
394 _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
376 return date.strftime(_fmt).decode('utf8')
395 return date.strftime(_fmt).decode('utf8')
377
396
378 return ""
397 return ""
379
398
380
399
381 def is_git(repository):
400 def is_git(repository):
382 if hasattr(repository, 'alias'):
401 if hasattr(repository, 'alias'):
383 _type = repository.alias
402 _type = repository.alias
384 elif hasattr(repository, 'repo_type'):
403 elif hasattr(repository, 'repo_type'):
385 _type = repository.repo_type
404 _type = repository.repo_type
386 else:
405 else:
387 _type = repository
406 _type = repository
388 return _type == 'git'
407 return _type == 'git'
389
408
390
409
391 def is_hg(repository):
410 def is_hg(repository):
392 if hasattr(repository, 'alias'):
411 if hasattr(repository, 'alias'):
393 _type = repository.alias
412 _type = repository.alias
394 elif hasattr(repository, 'repo_type'):
413 elif hasattr(repository, 'repo_type'):
395 _type = repository.repo_type
414 _type = repository.repo_type
396 else:
415 else:
397 _type = repository
416 _type = repository
398 return _type == 'hg'
417 return _type == 'hg'
399
418
400
419
401 def email_or_none(author):
420 def email_or_none(author):
402 # extract email from the commit string
421 # extract email from the commit string
403 _email = email(author)
422 _email = email(author)
404 if _email != '':
423 if _email != '':
405 # check it against RhodeCode database, and use the MAIN email for this
424 # check it against RhodeCode database, and use the MAIN email for this
406 # user
425 # user
407 user = User.get_by_email(_email, case_insensitive=True, cache=True)
426 user = User.get_by_email(_email, case_insensitive=True, cache=True)
408 if user is not None:
427 if user is not None:
409 return user.email
428 return user.email
410 return _email
429 return _email
411
430
412 # See if it contains a username we can get an email from
431 # See if it contains a username we can get an email from
413 user = User.get_by_username(author_name(author), case_insensitive=True,
432 user = User.get_by_username(author_name(author), case_insensitive=True,
414 cache=True)
433 cache=True)
415 if user is not None:
434 if user is not None:
416 return user.email
435 return user.email
417
436
418 # No valid email, not a valid user in the system, none!
437 # No valid email, not a valid user in the system, none!
419 return None
438 return None
420
439
421
440
422 def person(author, show_attr="username_and_name"):
441 def person(author, show_attr="username_and_name"):
423 # attr to return from fetched user
442 # attr to return from fetched user
424 person_getter = lambda usr: getattr(usr, show_attr)
443 person_getter = lambda usr: getattr(usr, show_attr)
425
444
426 # Valid email in the attribute passed, see if they're in the system
445 # Valid email in the attribute passed, see if they're in the system
427 _email = email(author)
446 _email = email(author)
428 if _email != '':
447 if _email != '':
429 user = User.get_by_email(_email, case_insensitive=True, cache=True)
448 user = User.get_by_email(_email, case_insensitive=True, cache=True)
430 if user is not None:
449 if user is not None:
431 return person_getter(user)
450 return person_getter(user)
432 return _email
451 return _email
433
452
434 # Maybe it's a username?
453 # Maybe it's a username?
435 _author = author_name(author)
454 _author = author_name(author)
436 user = User.get_by_username(_author, case_insensitive=True,
455 user = User.get_by_username(_author, case_insensitive=True,
437 cache=True)
456 cache=True)
438 if user is not None:
457 if user is not None:
439 return person_getter(user)
458 return person_getter(user)
440
459
441 # Still nothing? Just pass back the author name then
460 # Still nothing? Just pass back the author name then
442 return _author
461 return _author
443
462
444
463
445 def person_by_id(id_, show_attr="username_and_name"):
464 def person_by_id(id_, show_attr="username_and_name"):
446 # attr to return from fetched user
465 # attr to return from fetched user
447 person_getter = lambda usr: getattr(usr, show_attr)
466 person_getter = lambda usr: getattr(usr, show_attr)
448
467
449 #maybe it's an ID ?
468 #maybe it's an ID ?
450 if str(id_).isdigit() or isinstance(id_, int):
469 if str(id_).isdigit() or isinstance(id_, int):
451 id_ = int(id_)
470 id_ = int(id_)
452 user = User.get(id_)
471 user = User.get(id_)
453 if user is not None:
472 if user is not None:
454 return person_getter(user)
473 return person_getter(user)
455 return id_
474 return id_
456
475
457
476
458 def desc_stylize(value):
477 def desc_stylize(value):
459 """
478 """
460 converts tags from value into html equivalent
479 converts tags from value into html equivalent
461
480
462 :param value:
481 :param value:
463 """
482 """
464 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
483 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
465 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
484 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
466 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
485 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
467 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
486 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
468 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]',
487 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]',
469 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
488 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
470 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
489 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
471 '<div class="metatag" tag="lang">\\2</div>', value)
490 '<div class="metatag" tag="lang">\\2</div>', value)
472 value = re.sub(r'\[([a-z]+)\]',
491 value = re.sub(r'\[([a-z]+)\]',
473 '<div class="metatag" tag="\\1">\\1</div>', value)
492 '<div class="metatag" tag="\\1">\\1</div>', value)
474
493
475 return value
494 return value
476
495
477
496
478 def bool2icon(value):
497 def bool2icon(value):
479 """Returns True/False values represented as small html image of true/false
498 """Returns True/False values represented as small html image of true/false
480 icons
499 icons
481
500
482 :param value: bool value
501 :param value: bool value
483 """
502 """
484
503
485 if value is True:
504 if value is True:
486 return HTML.tag('img', src=url("/images/icons/accept.png"),
505 return HTML.tag('img', src=url("/images/icons/accept.png"),
487 alt=_('True'))
506 alt=_('True'))
488
507
489 if value is False:
508 if value is False:
490 return HTML.tag('img', src=url("/images/icons/cancel.png"),
509 return HTML.tag('img', src=url("/images/icons/cancel.png"),
491 alt=_('False'))
510 alt=_('False'))
492
511
493 return value
512 return value
494
513
495
514
496 def action_parser(user_log, feed=False, parse_cs=False):
515 def action_parser(user_log, feed=False, parse_cs=False):
497 """
516 """
498 This helper will action_map the specified string action into translated
517 This helper will action_map the specified string action into translated
499 fancy names with icons and links
518 fancy names with icons and links
500
519
501 :param user_log: user log instance
520 :param user_log: user log instance
502 :param feed: use output for feeds (no html and fancy icons)
521 :param feed: use output for feeds (no html and fancy icons)
503 :param parse_cs: parse Changesets into VCS instances
522 :param parse_cs: parse Changesets into VCS instances
504 """
523 """
505
524
506 action = user_log.action
525 action = user_log.action
507 action_params = ' '
526 action_params = ' '
508
527
509 x = action.split(':')
528 x = action.split(':')
510
529
511 if len(x) > 1:
530 if len(x) > 1:
512 action, action_params = x
531 action, action_params = x
513
532
514 def get_cs_links():
533 def get_cs_links():
515 revs_limit = 3 # display this amount always
534 revs_limit = 3 # display this amount always
516 revs_top_limit = 50 # show upto this amount of changesets hidden
535 revs_top_limit = 50 # show upto this amount of changesets hidden
517 revs_ids = action_params.split(',')
536 revs_ids = action_params.split(',')
518 deleted = user_log.repository is None
537 deleted = user_log.repository is None
519 if deleted:
538 if deleted:
520 return ','.join(revs_ids)
539 return ','.join(revs_ids)
521
540
522 repo_name = user_log.repository.repo_name
541 repo_name = user_log.repository.repo_name
523
542
524 def lnk(rev, repo_name):
543 def lnk(rev, repo_name):
525 if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
544 if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
526 lazy_cs = True
545 lazy_cs = True
527 if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
546 if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
528 lazy_cs = False
547 lazy_cs = False
529 lbl = '?'
548 lbl = '?'
530 if rev.op == 'delete_branch':
549 if rev.op == 'delete_branch':
531 lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
550 lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
532 title = ''
551 title = ''
533 elif rev.op == 'tag':
552 elif rev.op == 'tag':
534 lbl = '%s' % _('Created tag: %s') % rev.ref_name
553 lbl = '%s' % _('Created tag: %s') % rev.ref_name
535 title = ''
554 title = ''
536 _url = '#'
555 _url = '#'
537
556
538 else:
557 else:
539 lbl = '%s' % (rev.short_id[:8])
558 lbl = '%s' % (rev.short_id[:8])
540 _url = url('changeset_home', repo_name=repo_name,
559 _url = url('changeset_home', repo_name=repo_name,
541 revision=rev.raw_id)
560 revision=rev.raw_id)
542 title = tooltip(rev.message)
561 title = tooltip(rev.message)
543 else:
562 else:
544 ## changeset cannot be found/striped/removed etc.
563 ## changeset cannot be found/striped/removed etc.
545 lbl = ('%s' % rev)[:12]
564 lbl = ('%s' % rev)[:12]
546 _url = '#'
565 _url = '#'
547 title = _('Changeset not found')
566 title = _('Changeset not found')
548 if parse_cs:
567 if parse_cs:
549 return link_to(lbl, _url, title=title, class_='tooltip')
568 return link_to(lbl, _url, title=title, class_='tooltip')
550 return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
569 return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
551 class_='lazy-cs' if lazy_cs else '')
570 class_='lazy-cs' if lazy_cs else '')
552
571
553 def _get_op(rev_txt):
572 def _get_op(rev_txt):
554 _op = None
573 _op = None
555 _name = rev_txt
574 _name = rev_txt
556 if len(rev_txt.split('=>')) == 2:
575 if len(rev_txt.split('=>')) == 2:
557 _op, _name = rev_txt.split('=>')
576 _op, _name = rev_txt.split('=>')
558 return _op, _name
577 return _op, _name
559
578
560 revs = []
579 revs = []
561 if len(filter(lambda v: v != '', revs_ids)) > 0:
580 if len(filter(lambda v: v != '', revs_ids)) > 0:
562 repo = None
581 repo = None
563 for rev in revs_ids[:revs_top_limit]:
582 for rev in revs_ids[:revs_top_limit]:
564 _op, _name = _get_op(rev)
583 _op, _name = _get_op(rev)
565
584
566 # we want parsed changesets, or new log store format is bad
585 # we want parsed changesets, or new log store format is bad
567 if parse_cs:
586 if parse_cs:
568 try:
587 try:
569 if repo is None:
588 if repo is None:
570 repo = user_log.repository.scm_instance
589 repo = user_log.repository.scm_instance
571 _rev = repo.get_changeset(rev)
590 _rev = repo.get_changeset(rev)
572 revs.append(_rev)
591 revs.append(_rev)
573 except ChangesetDoesNotExistError:
592 except ChangesetDoesNotExistError:
574 log.error('cannot find revision %s in this repo' % rev)
593 log.error('cannot find revision %s in this repo' % rev)
575 revs.append(rev)
594 revs.append(rev)
576 continue
595 continue
577 else:
596 else:
578 _rev = AttributeDict({
597 _rev = AttributeDict({
579 'short_id': rev[:12],
598 'short_id': rev[:12],
580 'raw_id': rev,
599 'raw_id': rev,
581 'message': '',
600 'message': '',
582 'op': _op,
601 'op': _op,
583 'ref_name': _name
602 'ref_name': _name
584 })
603 })
585 revs.append(_rev)
604 revs.append(_rev)
586 cs_links = []
605 cs_links = []
587 cs_links.append(" " + ', '.join(
606 cs_links.append(" " + ', '.join(
588 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
607 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
589 )
608 )
590 )
609 )
591 _op1, _name1 = _get_op(revs_ids[0])
610 _op1, _name1 = _get_op(revs_ids[0])
592 _op2, _name2 = _get_op(revs_ids[-1])
611 _op2, _name2 = _get_op(revs_ids[-1])
593
612
594 _rev = '%s...%s' % (_name1, _name2)
613 _rev = '%s...%s' % (_name1, _name2)
595
614
596 compare_view = (
615 compare_view = (
597 ' <div class="compare_view tooltip" title="%s">'
616 ' <div class="compare_view tooltip" title="%s">'
598 '<a href="%s">%s</a> </div>' % (
617 '<a href="%s">%s</a> </div>' % (
599 _('Show all combined changesets %s->%s') % (
618 _('Show all combined changesets %s->%s') % (
600 revs_ids[0][:12], revs_ids[-1][:12]
619 revs_ids[0][:12], revs_ids[-1][:12]
601 ),
620 ),
602 url('changeset_home', repo_name=repo_name,
621 url('changeset_home', repo_name=repo_name,
603 revision=_rev
622 revision=_rev
604 ),
623 ),
605 _('compare view')
624 _('compare view')
606 )
625 )
607 )
626 )
608
627
609 # if we have exactly one more than normally displayed
628 # if we have exactly one more than normally displayed
610 # just display it, takes less space than displaying
629 # just display it, takes less space than displaying
611 # "and 1 more revisions"
630 # "and 1 more revisions"
612 if len(revs_ids) == revs_limit + 1:
631 if len(revs_ids) == revs_limit + 1:
613 rev = revs[revs_limit]
632 rev = revs[revs_limit]
614 cs_links.append(", " + lnk(rev, repo_name))
633 cs_links.append(", " + lnk(rev, repo_name))
615
634
616 # hidden-by-default ones
635 # hidden-by-default ones
617 if len(revs_ids) > revs_limit + 1:
636 if len(revs_ids) > revs_limit + 1:
618 uniq_id = revs_ids[0]
637 uniq_id = revs_ids[0]
619 html_tmpl = (
638 html_tmpl = (
620 '<span> %s <a class="show_more" id="_%s" '
639 '<span> %s <a class="show_more" id="_%s" '
621 'href="#more">%s</a> %s</span>'
640 'href="#more">%s</a> %s</span>'
622 )
641 )
623 if not feed:
642 if not feed:
624 cs_links.append(html_tmpl % (
643 cs_links.append(html_tmpl % (
625 _('and'),
644 _('and'),
626 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
645 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
627 _('revisions')
646 _('revisions')
628 )
647 )
629 )
648 )
630
649
631 if not feed:
650 if not feed:
632 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
651 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
633 else:
652 else:
634 html_tmpl = '<span id="%s"> %s </span>'
653 html_tmpl = '<span id="%s"> %s </span>'
635
654
636 morelinks = ', '.join(
655 morelinks = ', '.join(
637 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
656 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
638 )
657 )
639
658
640 if len(revs_ids) > revs_top_limit:
659 if len(revs_ids) > revs_top_limit:
641 morelinks += ', ...'
660 morelinks += ', ...'
642
661
643 cs_links.append(html_tmpl % (uniq_id, morelinks))
662 cs_links.append(html_tmpl % (uniq_id, morelinks))
644 if len(revs) > 1:
663 if len(revs) > 1:
645 cs_links.append(compare_view)
664 cs_links.append(compare_view)
646 return ''.join(cs_links)
665 return ''.join(cs_links)
647
666
648 def get_fork_name():
667 def get_fork_name():
649 repo_name = action_params
668 repo_name = action_params
650 _url = url('summary_home', repo_name=repo_name)
669 _url = url('summary_home', repo_name=repo_name)
651 return _('fork name %s') % link_to(action_params, _url)
670 return _('fork name %s') % link_to(action_params, _url)
652
671
653 def get_user_name():
672 def get_user_name():
654 user_name = action_params
673 user_name = action_params
655 return user_name
674 return user_name
656
675
657 def get_users_group():
676 def get_users_group():
658 group_name = action_params
677 group_name = action_params
659 return group_name
678 return group_name
660
679
661 def get_pull_request():
680 def get_pull_request():
662 pull_request_id = action_params
681 pull_request_id = action_params
663 deleted = user_log.repository is None
682 deleted = user_log.repository is None
664 if deleted:
683 if deleted:
665 repo_name = user_log.repository_name
684 repo_name = user_log.repository_name
666 else:
685 else:
667 repo_name = user_log.repository.repo_name
686 repo_name = user_log.repository.repo_name
668 return link_to(_('Pull request #%s') % pull_request_id,
687 return link_to(_('Pull request #%s') % pull_request_id,
669 url('pullrequest_show', repo_name=repo_name,
688 url('pullrequest_show', repo_name=repo_name,
670 pull_request_id=pull_request_id))
689 pull_request_id=pull_request_id))
671
690
672 # action : translated str, callback(extractor), icon
691 # action : translated str, callback(extractor), icon
673 action_map = {
692 action_map = {
674 'user_deleted_repo': (_('[deleted] repository'),
693 'user_deleted_repo': (_('[deleted] repository'),
675 None, 'database_delete.png'),
694 None, 'database_delete.png'),
676 'user_created_repo': (_('[created] repository'),
695 'user_created_repo': (_('[created] repository'),
677 None, 'database_add.png'),
696 None, 'database_add.png'),
678 'user_created_fork': (_('[created] repository as fork'),
697 'user_created_fork': (_('[created] repository as fork'),
679 None, 'arrow_divide.png'),
698 None, 'arrow_divide.png'),
680 'user_forked_repo': (_('[forked] repository'),
699 'user_forked_repo': (_('[forked] repository'),
681 get_fork_name, 'arrow_divide.png'),
700 get_fork_name, 'arrow_divide.png'),
682 'user_updated_repo': (_('[updated] repository'),
701 'user_updated_repo': (_('[updated] repository'),
683 None, 'database_edit.png'),
702 None, 'database_edit.png'),
684 'admin_deleted_repo': (_('[delete] repository'),
703 'admin_deleted_repo': (_('[delete] repository'),
685 None, 'database_delete.png'),
704 None, 'database_delete.png'),
686 'admin_created_repo': (_('[created] repository'),
705 'admin_created_repo': (_('[created] repository'),
687 None, 'database_add.png'),
706 None, 'database_add.png'),
688 'admin_forked_repo': (_('[forked] repository'),
707 'admin_forked_repo': (_('[forked] repository'),
689 None, 'arrow_divide.png'),
708 None, 'arrow_divide.png'),
690 'admin_updated_repo': (_('[updated] repository'),
709 'admin_updated_repo': (_('[updated] repository'),
691 None, 'database_edit.png'),
710 None, 'database_edit.png'),
692 'admin_created_user': (_('[created] user'),
711 'admin_created_user': (_('[created] user'),
693 get_user_name, 'user_add.png'),
712 get_user_name, 'user_add.png'),
694 'admin_updated_user': (_('[updated] user'),
713 'admin_updated_user': (_('[updated] user'),
695 get_user_name, 'user_edit.png'),
714 get_user_name, 'user_edit.png'),
696 'admin_created_users_group': (_('[created] user group'),
715 'admin_created_users_group': (_('[created] user group'),
697 get_users_group, 'group_add.png'),
716 get_users_group, 'group_add.png'),
698 'admin_updated_users_group': (_('[updated] user group'),
717 'admin_updated_users_group': (_('[updated] user group'),
699 get_users_group, 'group_edit.png'),
718 get_users_group, 'group_edit.png'),
700 'user_commented_revision': (_('[commented] on revision in repository'),
719 'user_commented_revision': (_('[commented] on revision in repository'),
701 get_cs_links, 'comment_add.png'),
720 get_cs_links, 'comment_add.png'),
702 'user_commented_pull_request': (_('[commented] on pull request for'),
721 'user_commented_pull_request': (_('[commented] on pull request for'),
703 get_pull_request, 'comment_add.png'),
722 get_pull_request, 'comment_add.png'),
704 'user_closed_pull_request': (_('[closed] pull request for'),
723 'user_closed_pull_request': (_('[closed] pull request for'),
705 get_pull_request, 'tick.png'),
724 get_pull_request, 'tick.png'),
706 'push': (_('[pushed] into'),
725 'push': (_('[pushed] into'),
707 get_cs_links, 'script_add.png'),
726 get_cs_links, 'script_add.png'),
708 'push_local': (_('[committed via RhodeCode] into repository'),
727 'push_local': (_('[committed via RhodeCode] into repository'),
709 get_cs_links, 'script_edit.png'),
728 get_cs_links, 'script_edit.png'),
710 'push_remote': (_('[pulled from remote] into repository'),
729 'push_remote': (_('[pulled from remote] into repository'),
711 get_cs_links, 'connect.png'),
730 get_cs_links, 'connect.png'),
712 'pull': (_('[pulled] from'),
731 'pull': (_('[pulled] from'),
713 None, 'down_16.png'),
732 None, 'down_16.png'),
714 'started_following_repo': (_('[started following] repository'),
733 'started_following_repo': (_('[started following] repository'),
715 None, 'heart_add.png'),
734 None, 'heart_add.png'),
716 'stopped_following_repo': (_('[stopped following] repository'),
735 'stopped_following_repo': (_('[stopped following] repository'),
717 None, 'heart_delete.png'),
736 None, 'heart_delete.png'),
718 }
737 }
719
738
720 action_str = action_map.get(action, action)
739 action_str = action_map.get(action, action)
721 if feed:
740 if feed:
722 action = action_str[0].replace('[', '').replace(']', '')
741 action = action_str[0].replace('[', '').replace(']', '')
723 else:
742 else:
724 action = action_str[0]\
743 action = action_str[0]\
725 .replace('[', '<span class="journal_highlight">')\
744 .replace('[', '<span class="journal_highlight">')\
726 .replace(']', '</span>')
745 .replace(']', '</span>')
727
746
728 action_params_func = lambda: ""
747 action_params_func = lambda: ""
729
748
730 if callable(action_str[1]):
749 if callable(action_str[1]):
731 action_params_func = action_str[1]
750 action_params_func = action_str[1]
732
751
733 def action_parser_icon():
752 def action_parser_icon():
734 action = user_log.action
753 action = user_log.action
735 action_params = None
754 action_params = None
736 x = action.split(':')
755 x = action.split(':')
737
756
738 if len(x) > 1:
757 if len(x) > 1:
739 action, action_params = x
758 action, action_params = x
740
759
741 tmpl = """<img src="%s%s" alt="%s"/>"""
760 tmpl = """<img src="%s%s" alt="%s"/>"""
742 ico = action_map.get(action, ['', '', ''])[2]
761 ico = action_map.get(action, ['', '', ''])[2]
743 return literal(tmpl % ((url('/images/icons/')), ico, action))
762 return literal(tmpl % ((url('/images/icons/')), ico, action))
744
763
745 # returned callbacks we need to call to get
764 # returned callbacks we need to call to get
746 return [lambda: literal(action), action_params_func, action_parser_icon]
765 return [lambda: literal(action), action_params_func, action_parser_icon]
747
766
748
767
749
768
750 #==============================================================================
769 #==============================================================================
751 # PERMS
770 # PERMS
752 #==============================================================================
771 #==============================================================================
753 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
772 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
754 HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \
773 HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \
755 HasReposGroupPermissionAny
774 HasReposGroupPermissionAny
756
775
757
776
758 #==============================================================================
777 #==============================================================================
759 # GRAVATAR URL
778 # GRAVATAR URL
760 #==============================================================================
779 #==============================================================================
761
780
762 def gravatar_url(email_address, size=30):
781 def gravatar_url(email_address, size=30):
763 from pylons import url # doh, we need to re-import url to mock it later
782 from pylons import url # doh, we need to re-import url to mock it later
764 _def = 'anonymous@rhodecode.org'
783 _def = 'anonymous@rhodecode.org'
765 use_gravatar = str2bool(config['app_conf'].get('use_gravatar'))
784 use_gravatar = str2bool(config['app_conf'].get('use_gravatar'))
766 email_address = email_address or _def
785 email_address = email_address or _def
767 if (not use_gravatar or not email_address or email_address == _def):
786 if (not use_gravatar or not email_address or email_address == _def):
768 f = lambda a, l: min(l, key=lambda x: abs(x - a))
787 f = lambda a, l: min(l, key=lambda x: abs(x - a))
769 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
788 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
770
789
771 if use_gravatar and config['app_conf'].get('alternative_gravatar_url'):
790 if use_gravatar and config['app_conf'].get('alternative_gravatar_url'):
772 tmpl = config['app_conf'].get('alternative_gravatar_url', '')
791 tmpl = config['app_conf'].get('alternative_gravatar_url', '')
773 parsed_url = urlparse.urlparse(url.current(qualified=True))
792 parsed_url = urlparse.urlparse(url.current(qualified=True))
774 tmpl = tmpl.replace('{email}', email_address)\
793 tmpl = tmpl.replace('{email}', email_address)\
775 .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
794 .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
776 .replace('{netloc}', parsed_url.netloc)\
795 .replace('{netloc}', parsed_url.netloc)\
777 .replace('{scheme}', parsed_url.scheme)\
796 .replace('{scheme}', parsed_url.scheme)\
778 .replace('{size}', str(size))
797 .replace('{size}', str(size))
779 return tmpl
798 return tmpl
780
799
781 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
800 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
782 default = 'identicon'
801 default = 'identicon'
783 baseurl_nossl = "http://www.gravatar.com/avatar/"
802 baseurl_nossl = "http://www.gravatar.com/avatar/"
784 baseurl_ssl = "https://secure.gravatar.com/avatar/"
803 baseurl_ssl = "https://secure.gravatar.com/avatar/"
785 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
804 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
786
805
787 if isinstance(email_address, unicode):
806 if isinstance(email_address, unicode):
788 #hashlib crashes on unicode items
807 #hashlib crashes on unicode items
789 email_address = safe_str(email_address)
808 email_address = safe_str(email_address)
790 # construct the url
809 # construct the url
791 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
810 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
792 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
811 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
793
812
794 return gravatar_url
813 return gravatar_url
795
814
796
815
797 #==============================================================================
816 #==============================================================================
798 # REPO PAGER, PAGER FOR REPOSITORY
817 # REPO PAGER, PAGER FOR REPOSITORY
799 #==============================================================================
818 #==============================================================================
800 class RepoPage(Page):
819 class RepoPage(Page):
801
820
802 def __init__(self, collection, page=1, items_per_page=20,
821 def __init__(self, collection, page=1, items_per_page=20,
803 item_count=None, url=None, **kwargs):
822 item_count=None, url=None, **kwargs):
804
823
805 """Create a "RepoPage" instance. special pager for paging
824 """Create a "RepoPage" instance. special pager for paging
806 repository
825 repository
807 """
826 """
808 self._url_generator = url
827 self._url_generator = url
809
828
810 # Safe the kwargs class-wide so they can be used in the pager() method
829 # Safe the kwargs class-wide so they can be used in the pager() method
811 self.kwargs = kwargs
830 self.kwargs = kwargs
812
831
813 # Save a reference to the collection
832 # Save a reference to the collection
814 self.original_collection = collection
833 self.original_collection = collection
815
834
816 self.collection = collection
835 self.collection = collection
817
836
818 # The self.page is the number of the current page.
837 # The self.page is the number of the current page.
819 # The first page has the number 1!
838 # The first page has the number 1!
820 try:
839 try:
821 self.page = int(page) # make it int() if we get it as a string
840 self.page = int(page) # make it int() if we get it as a string
822 except (ValueError, TypeError):
841 except (ValueError, TypeError):
823 self.page = 1
842 self.page = 1
824
843
825 self.items_per_page = items_per_page
844 self.items_per_page = items_per_page
826
845
827 # Unless the user tells us how many items the collections has
846 # Unless the user tells us how many items the collections has
828 # we calculate that ourselves.
847 # we calculate that ourselves.
829 if item_count is not None:
848 if item_count is not None:
830 self.item_count = item_count
849 self.item_count = item_count
831 else:
850 else:
832 self.item_count = len(self.collection)
851 self.item_count = len(self.collection)
833
852
834 # Compute the number of the first and last available page
853 # Compute the number of the first and last available page
835 if self.item_count > 0:
854 if self.item_count > 0:
836 self.first_page = 1
855 self.first_page = 1
837 self.page_count = int(math.ceil(float(self.item_count) /
856 self.page_count = int(math.ceil(float(self.item_count) /
838 self.items_per_page))
857 self.items_per_page))
839 self.last_page = self.first_page + self.page_count - 1
858 self.last_page = self.first_page + self.page_count - 1
840
859
841 # Make sure that the requested page number is the range of
860 # Make sure that the requested page number is the range of
842 # valid pages
861 # valid pages
843 if self.page > self.last_page:
862 if self.page > self.last_page:
844 self.page = self.last_page
863 self.page = self.last_page
845 elif self.page < self.first_page:
864 elif self.page < self.first_page:
846 self.page = self.first_page
865 self.page = self.first_page
847
866
848 # Note: the number of items on this page can be less than
867 # Note: the number of items on this page can be less than
849 # items_per_page if the last page is not full
868 # items_per_page if the last page is not full
850 self.first_item = max(0, (self.item_count) - (self.page *
869 self.first_item = max(0, (self.item_count) - (self.page *
851 items_per_page))
870 items_per_page))
852 self.last_item = ((self.item_count - 1) - items_per_page *
871 self.last_item = ((self.item_count - 1) - items_per_page *
853 (self.page - 1))
872 (self.page - 1))
854
873
855 self.items = list(self.collection[self.first_item:self.last_item + 1])
874 self.items = list(self.collection[self.first_item:self.last_item + 1])
856
875
857 # Links to previous and next page
876 # Links to previous and next page
858 if self.page > self.first_page:
877 if self.page > self.first_page:
859 self.previous_page = self.page - 1
878 self.previous_page = self.page - 1
860 else:
879 else:
861 self.previous_page = None
880 self.previous_page = None
862
881
863 if self.page < self.last_page:
882 if self.page < self.last_page:
864 self.next_page = self.page + 1
883 self.next_page = self.page + 1
865 else:
884 else:
866 self.next_page = None
885 self.next_page = None
867
886
868 # No items available
887 # No items available
869 else:
888 else:
870 self.first_page = None
889 self.first_page = None
871 self.page_count = 0
890 self.page_count = 0
872 self.last_page = None
891 self.last_page = None
873 self.first_item = None
892 self.first_item = None
874 self.last_item = None
893 self.last_item = None
875 self.previous_page = None
894 self.previous_page = None
876 self.next_page = None
895 self.next_page = None
877 self.items = []
896 self.items = []
878
897
879 # This is a subclass of the 'list' type. Initialise the list now.
898 # This is a subclass of the 'list' type. Initialise the list now.
880 list.__init__(self, reversed(self.items))
899 list.__init__(self, reversed(self.items))
881
900
882
901
883 def changed_tooltip(nodes):
902 def changed_tooltip(nodes):
884 """
903 """
885 Generates a html string for changed nodes in changeset page.
904 Generates a html string for changed nodes in changeset page.
886 It limits the output to 30 entries
905 It limits the output to 30 entries
887
906
888 :param nodes: LazyNodesGenerator
907 :param nodes: LazyNodesGenerator
889 """
908 """
890 if nodes:
909 if nodes:
891 pref = ': <br/> '
910 pref = ': <br/> '
892 suf = ''
911 suf = ''
893 if len(nodes) > 30:
912 if len(nodes) > 30:
894 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
913 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
895 return literal(pref + '<br/> '.join([safe_unicode(x.path)
914 return literal(pref + '<br/> '.join([safe_unicode(x.path)
896 for x in nodes[:30]]) + suf)
915 for x in nodes[:30]]) + suf)
897 else:
916 else:
898 return ': ' + _('No Files')
917 return ': ' + _('No Files')
899
918
900
919
901 def repo_link(groups_and_repos, last_url=None):
920 def repo_link(groups_and_repos, last_url=None):
902 """
921 """
903 Makes a breadcrumbs link to repo within a group
922 Makes a breadcrumbs link to repo within a group
904 joins &raquo; on each group to create a fancy link
923 joins &raquo; on each group to create a fancy link
905
924
906 ex::
925 ex::
907 group >> subgroup >> repo
926 group >> subgroup >> repo
908
927
909 :param groups_and_repos:
928 :param groups_and_repos:
910 :param last_url:
929 :param last_url:
911 """
930 """
912 groups, repo_name = groups_and_repos
931 groups, repo_name = groups_and_repos
913 last_link = link_to(repo_name, last_url) if last_url else repo_name
932 last_link = link_to(repo_name, last_url) if last_url else repo_name
914
933
915 if not groups:
934 if not groups:
916 if last_url:
935 if last_url:
917 return literal('<span>%s</span>' % last_link)
936 return literal('<span>%s</span>' % last_link)
918 return literal('<span>%s</span>' % repo_name)
937 return literal('<span>%s</span>' % repo_name)
919 else:
938 else:
920 def make_link(group):
939 def make_link(group):
921 return link_to(group.name,
940 return link_to(group.name,
922 url('repos_group_home', group_name=group.group_name))
941 url('repos_group_home', group_name=group.group_name))
923 return literal(' &raquo; '.join(map(make_link, groups) + ['<span>' + last_link + '</span>']))
942 return literal(' &raquo; '.join(map(make_link, groups) + ['<span>' + last_link + '</span>']))
924
943
925
944
926 def fancy_file_stats(stats):
945 def fancy_file_stats(stats):
927 """
946 """
928 Displays a fancy two colored bar for number of added/deleted
947 Displays a fancy two colored bar for number of added/deleted
929 lines of code on file
948 lines of code on file
930
949
931 :param stats: two element list of added/deleted lines of code
950 :param stats: two element list of added/deleted lines of code
932 """
951 """
933 def cgen(l_type, a_v, d_v):
952 def cgen(l_type, a_v, d_v):
934 mapping = {'tr': 'top-right-rounded-corner-mid',
953 mapping = {'tr': 'top-right-rounded-corner-mid',
935 'tl': 'top-left-rounded-corner-mid',
954 'tl': 'top-left-rounded-corner-mid',
936 'br': 'bottom-right-rounded-corner-mid',
955 'br': 'bottom-right-rounded-corner-mid',
937 'bl': 'bottom-left-rounded-corner-mid'}
956 'bl': 'bottom-left-rounded-corner-mid'}
938 map_getter = lambda x: mapping[x]
957 map_getter = lambda x: mapping[x]
939
958
940 if l_type == 'a' and d_v:
959 if l_type == 'a' and d_v:
941 #case when added and deleted are present
960 #case when added and deleted are present
942 return ' '.join(map(map_getter, ['tl', 'bl']))
961 return ' '.join(map(map_getter, ['tl', 'bl']))
943
962
944 if l_type == 'a' and not d_v:
963 if l_type == 'a' and not d_v:
945 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
964 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
946
965
947 if l_type == 'd' and a_v:
966 if l_type == 'd' and a_v:
948 return ' '.join(map(map_getter, ['tr', 'br']))
967 return ' '.join(map(map_getter, ['tr', 'br']))
949
968
950 if l_type == 'd' and not a_v:
969 if l_type == 'd' and not a_v:
951 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
970 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
952
971
953 a, d = stats[0], stats[1]
972 a, d = stats[0], stats[1]
954 width = 100
973 width = 100
955
974
956 if a == 'b':
975 if a == 'b':
957 #binary mode
976 #binary mode
958 b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin')
977 b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin')
959 b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin')
978 b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin')
960 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
979 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
961
980
962 t = stats[0] + stats[1]
981 t = stats[0] + stats[1]
963 unit = float(width) / (t or 1)
982 unit = float(width) / (t or 1)
964
983
965 # needs > 9% of width to be visible or 0 to be hidden
984 # needs > 9% of width to be visible or 0 to be hidden
966 a_p = max(9, unit * a) if a > 0 else 0
985 a_p = max(9, unit * a) if a > 0 else 0
967 d_p = max(9, unit * d) if d > 0 else 0
986 d_p = max(9, unit * d) if d > 0 else 0
968 p_sum = a_p + d_p
987 p_sum = a_p + d_p
969
988
970 if p_sum > width:
989 if p_sum > width:
971 #adjust the percentage to be == 100% since we adjusted to 9
990 #adjust the percentage to be == 100% since we adjusted to 9
972 if a_p > d_p:
991 if a_p > d_p:
973 a_p = a_p - (p_sum - width)
992 a_p = a_p - (p_sum - width)
974 else:
993 else:
975 d_p = d_p - (p_sum - width)
994 d_p = d_p - (p_sum - width)
976
995
977 a_v = a if a > 0 else ''
996 a_v = a if a > 0 else ''
978 d_v = d if d > 0 else ''
997 d_v = d if d > 0 else ''
979
998
980 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
999 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
981 cgen('a', a_v, d_v), a_p, a_v
1000 cgen('a', a_v, d_v), a_p, a_v
982 )
1001 )
983 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
1002 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
984 cgen('d', a_v, d_v), d_p, d_v
1003 cgen('d', a_v, d_v), d_p, d_v
985 )
1004 )
986 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
1005 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
987
1006
988
1007
989 def urlify_text(text_, safe=True):
1008 def urlify_text(text_, safe=True):
990 """
1009 """
991 Extrac urls from text and make html links out of them
1010 Extrac urls from text and make html links out of them
992
1011
993 :param text_:
1012 :param text_:
994 """
1013 """
995
1014
996 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
1015 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
997 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
1016 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
998
1017
999 def url_func(match_obj):
1018 def url_func(match_obj):
1000 url_full = match_obj.groups()[0]
1019 url_full = match_obj.groups()[0]
1001 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
1020 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
1002 _newtext = url_pat.sub(url_func, text_)
1021 _newtext = url_pat.sub(url_func, text_)
1003 if safe:
1022 if safe:
1004 return literal(_newtext)
1023 return literal(_newtext)
1005 return _newtext
1024 return _newtext
1006
1025
1007
1026
1008 def urlify_changesets(text_, repository):
1027 def urlify_changesets(text_, repository):
1009 """
1028 """
1010 Extract revision ids from changeset and make link from them
1029 Extract revision ids from changeset and make link from them
1011
1030
1012 :param text_:
1031 :param text_:
1013 :param repository: repo name to build the URL with
1032 :param repository: repo name to build the URL with
1014 """
1033 """
1015 from pylons import url # doh, we need to re-import url to mock it later
1034 from pylons import url # doh, we need to re-import url to mock it later
1016 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1035 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1017
1036
1018 def url_func(match_obj):
1037 def url_func(match_obj):
1019 rev = match_obj.groups()[1]
1038 rev = match_obj.groups()[1]
1020 pref = match_obj.groups()[0]
1039 pref = match_obj.groups()[0]
1021 suf = match_obj.groups()[2]
1040 suf = match_obj.groups()[2]
1022
1041
1023 tmpl = (
1042 tmpl = (
1024 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1043 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1025 '%(rev)s</a>%(suf)s'
1044 '%(rev)s</a>%(suf)s'
1026 )
1045 )
1027 return tmpl % {
1046 return tmpl % {
1028 'pref': pref,
1047 'pref': pref,
1029 'cls': 'revision-link',
1048 'cls': 'revision-link',
1030 'url': url('changeset_home', repo_name=repository, revision=rev),
1049 'url': url('changeset_home', repo_name=repository, revision=rev),
1031 'rev': rev,
1050 'rev': rev,
1032 'suf': suf
1051 'suf': suf
1033 }
1052 }
1034
1053
1035 newtext = URL_PAT.sub(url_func, text_)
1054 newtext = URL_PAT.sub(url_func, text_)
1036
1055
1037 return newtext
1056 return newtext
1038
1057
1039
1058
1040 def urlify_commit(text_, repository=None, link_=None):
1059 def urlify_commit(text_, repository=None, link_=None):
1041 """
1060 """
1042 Parses given text message and makes proper links.
1061 Parses given text message and makes proper links.
1043 issues are linked to given issue-server, and rest is a changeset link
1062 issues are linked to given issue-server, and rest is a changeset link
1044 if link_ is given, in other case it's a plain text
1063 if link_ is given, in other case it's a plain text
1045
1064
1046 :param text_:
1065 :param text_:
1047 :param repository:
1066 :param repository:
1048 :param link_: changeset link
1067 :param link_: changeset link
1049 """
1068 """
1050 import traceback
1069 import traceback
1051 from pylons import url # doh, we need to re-import url to mock it later
1070 from pylons import url # doh, we need to re-import url to mock it later
1052
1071
1053 def escaper(string):
1072 def escaper(string):
1054 return string.replace('<', '&lt;').replace('>', '&gt;')
1073 return string.replace('<', '&lt;').replace('>', '&gt;')
1055
1074
1056 def linkify_others(t, l):
1075 def linkify_others(t, l):
1057 urls = re.compile(r'(\<a.*?\<\/a\>)',)
1076 urls = re.compile(r'(\<a.*?\<\/a\>)',)
1058 links = []
1077 links = []
1059 for e in urls.split(t):
1078 for e in urls.split(t):
1060 if not urls.match(e):
1079 if not urls.match(e):
1061 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
1080 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
1062 else:
1081 else:
1063 links.append(e)
1082 links.append(e)
1064
1083
1065 return ''.join(links)
1084 return ''.join(links)
1066
1085
1067 # urlify changesets - extrac revisions and make link out of them
1086 # urlify changesets - extrac revisions and make link out of them
1068 newtext = urlify_changesets(escaper(text_), repository)
1087 newtext = urlify_changesets(escaper(text_), repository)
1069
1088
1070 # extract http/https links and make them real urls
1089 # extract http/https links and make them real urls
1071 newtext = urlify_text(newtext, safe=False)
1090 newtext = urlify_text(newtext, safe=False)
1072
1091
1073 try:
1092 try:
1074 from rhodecode import CONFIG
1093 from rhodecode import CONFIG
1075 conf = CONFIG
1094 conf = CONFIG
1076
1095
1077 # allow multiple issue servers to be used
1096 # allow multiple issue servers to be used
1078 valid_indices = [
1097 valid_indices = [
1079 x.group(1)
1098 x.group(1)
1080 for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys())
1099 for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys())
1081 if x and 'issue_server_link%s' % x.group(1) in conf
1100 if x and 'issue_server_link%s' % x.group(1) in conf
1082 and 'issue_prefix%s' % x.group(1) in conf
1101 and 'issue_prefix%s' % x.group(1) in conf
1083 ]
1102 ]
1084
1103
1085 log.debug('found issue server suffixes `%s` during valuation of: %s'
1104 log.debug('found issue server suffixes `%s` during valuation of: %s'
1086 % (','.join(valid_indices), newtext))
1105 % (','.join(valid_indices), newtext))
1087
1106
1088 for pattern_index in valid_indices:
1107 for pattern_index in valid_indices:
1089 ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
1108 ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
1090 ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
1109 ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
1091 ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
1110 ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
1092
1111
1093 log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
1112 log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
1094 % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
1113 % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
1095 ISSUE_PREFIX))
1114 ISSUE_PREFIX))
1096
1115
1097 URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
1116 URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
1098
1117
1099 def url_func(match_obj):
1118 def url_func(match_obj):
1100 pref = ''
1119 pref = ''
1101 if match_obj.group().startswith(' '):
1120 if match_obj.group().startswith(' '):
1102 pref = ' '
1121 pref = ' '
1103
1122
1104 issue_id = ''.join(match_obj.groups())
1123 issue_id = ''.join(match_obj.groups())
1105 tmpl = (
1124 tmpl = (
1106 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1125 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1107 '%(issue-prefix)s%(id-repr)s'
1126 '%(issue-prefix)s%(id-repr)s'
1108 '</a>'
1127 '</a>'
1109 )
1128 )
1110 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
1129 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
1111 if repository:
1130 if repository:
1112 url = url.replace('{repo}', repository)
1131 url = url.replace('{repo}', repository)
1113 repo_name = repository.split(URL_SEP)[-1]
1132 repo_name = repository.split(URL_SEP)[-1]
1114 url = url.replace('{repo_name}', repo_name)
1133 url = url.replace('{repo_name}', repo_name)
1115
1134
1116 return tmpl % {
1135 return tmpl % {
1117 'pref': pref,
1136 'pref': pref,
1118 'cls': 'issue-tracker-link',
1137 'cls': 'issue-tracker-link',
1119 'url': url,
1138 'url': url,
1120 'id-repr': issue_id,
1139 'id-repr': issue_id,
1121 'issue-prefix': ISSUE_PREFIX,
1140 'issue-prefix': ISSUE_PREFIX,
1122 'serv': ISSUE_SERVER_LNK,
1141 'serv': ISSUE_SERVER_LNK,
1123 }
1142 }
1124 newtext = URL_PAT.sub(url_func, newtext)
1143 newtext = URL_PAT.sub(url_func, newtext)
1125 log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
1144 log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
1126
1145
1127 # if we actually did something above
1146 # if we actually did something above
1128 if link_:
1147 if link_:
1129 # wrap not links into final link => link_
1148 # wrap not links into final link => link_
1130 newtext = linkify_others(newtext, link_)
1149 newtext = linkify_others(newtext, link_)
1131 except:
1150 except:
1132 log.error(traceback.format_exc())
1151 log.error(traceback.format_exc())
1133 pass
1152 pass
1134
1153
1135 return literal(newtext)
1154 return literal(newtext)
1136
1155
1137
1156
1138 def rst(source):
1157 def rst(source):
1139 return literal('<div class="rst-block">%s</div>' %
1158 return literal('<div class="rst-block">%s</div>' %
1140 MarkupRenderer.rst(source))
1159 MarkupRenderer.rst(source))
1141
1160
1142
1161
1143 def rst_w_mentions(source):
1162 def rst_w_mentions(source):
1144 """
1163 """
1145 Wrapped rst renderer with @mention highlighting
1164 Wrapped rst renderer with @mention highlighting
1146
1165
1147 :param source:
1166 :param source:
1148 """
1167 """
1149 return literal('<div class="rst-block">%s</div>' %
1168 return literal('<div class="rst-block">%s</div>' %
1150 MarkupRenderer.rst_with_mentions(source))
1169 MarkupRenderer.rst_with_mentions(source))
1151
1170
1152
1171
1153 def changeset_status(repo, revision):
1172 def changeset_status(repo, revision):
1154 return ChangesetStatusModel().get_status(repo, revision)
1173 return ChangesetStatusModel().get_status(repo, revision)
1155
1174
1156
1175
1157 def changeset_status_lbl(changeset_status):
1176 def changeset_status_lbl(changeset_status):
1158 return dict(ChangesetStatus.STATUSES).get(changeset_status)
1177 return dict(ChangesetStatus.STATUSES).get(changeset_status)
1159
1178
1160
1179
1161 def get_permission_name(key):
1180 def get_permission_name(key):
1162 return dict(Permission.PERMS).get(key)
1181 return dict(Permission.PERMS).get(key)
1163
1182
1164
1183
1165 def journal_filter_help():
1184 def journal_filter_help():
1166 return _(textwrap.dedent('''
1185 return _(textwrap.dedent('''
1167 Example filter terms:
1186 Example filter terms:
1168 repository:vcs
1187 repository:vcs
1169 username:marcin
1188 username:marcin
1170 action:*push*
1189 action:*push*
1171 ip:127.0.0.1
1190 ip:127.0.0.1
1172 date:20120101
1191 date:20120101
1173 date:[20120101100000 TO 20120102]
1192 date:[20120101100000 TO 20120102]
1174
1193
1175 Generate wildcards using '*' character:
1194 Generate wildcards using '*' character:
1176 "repositroy:vcs*" - search everything starting with 'vcs'
1195 "repositroy:vcs*" - search everything starting with 'vcs'
1177 "repository:*vcs*" - search for repository containing 'vcs'
1196 "repository:*vcs*" - search for repository containing 'vcs'
1178
1197
1179 Optional AND / OR operators in queries
1198 Optional AND / OR operators in queries
1180 "repository:vcs OR repository:test"
1199 "repository:vcs OR repository:test"
1181 "username:test AND repository:test*"
1200 "username:test AND repository:test*"
1182 '''))
1201 '''))
1183
1202
1184
1203
1185 def not_mapped_error(repo_name):
1204 def not_mapped_error(repo_name):
1186 flash(_('%s repository is not mapped to db perhaps'
1205 flash(_('%s repository is not mapped to db perhaps'
1187 ' it was created or renamed from the filesystem'
1206 ' it was created or renamed from the filesystem'
1188 ' please run the application again'
1207 ' please run the application again'
1189 ' in order to rescan repositories') % repo_name, category='error')
1208 ' in order to rescan repositories') % repo_name, category='error')
1190
1209
1191
1210
1192 def ip_range(ip_addr):
1211 def ip_range(ip_addr):
1193 from rhodecode.model.db import UserIpMap
1212 from rhodecode.model.db import UserIpMap
1194 s, e = UserIpMap._get_ip_range(ip_addr)
1213 s, e = UserIpMap._get_ip_range(ip_addr)
1195 return '%s - %s' % (s, e)
1214 return '%s - %s' % (s, e)
@@ -1,263 +1,262 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
6 ${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
7 </%def>
7 </%def>
8
8
9 <%def name="breadcrumbs_links()">
9 <%def name="breadcrumbs_links()">
10 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
10 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
11 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
11 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
12 </%def>
12 </%def>
13
13
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('changelog')}
15 ${self.menu('changelog')}
16 </%def>
16 </%def>
17
17
18 <%def name="main()">
18 <%def name="main()">
19 ${self.context_bar('changelog')}
19 ${self.context_bar('changelog')}
20 <div class="box">
20 <div class="box">
21 <!-- box / title -->
21 <!-- box / title -->
22 <div class="title">
22 <div class="title">
23 ${self.breadcrumbs()}
23 ${self.breadcrumbs()}
24 </div>
24 </div>
25 <div class="table">
25 <div class="table">
26 % if c.pagination:
26 % if c.pagination:
27 <div id="graph">
27 <div id="graph">
28 <div class="info_box" style="clear: both;padding: 10px 6px;min-height: 12px;text-align: right;">
28 <div class="info_box" style="clear: both;padding: 10px 6px;min-height: 12px;text-align: right;">
29 <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
29 <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
30 <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
30 <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
31
31
32 %if c.rhodecode_db_repo.fork:
32 %if c.rhodecode_db_repo.fork:
33 <a id="compare_fork" title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${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="ui-btn small">${_('Compare fork with parent')}</a>
33 <a id="compare_fork" title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${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="ui-btn small">${_('Compare fork with parent')}</a>
34 %endif
34 %endif
35 %if h.is_hg(c.rhodecode_repo):
35 %if h.is_hg(c.rhodecode_repo):
36 <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
36 <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
37 %endif
37 %endif
38 </div>
38 </div>
39 <div class="container_header">
39 <div class="container_header">
40 ${h.form(h.url.current(),method='get')}
40 ${h.form(h.url.current(),method='get')}
41 <div style="float:left">
41 <div style="float:left">
42 ${h.submit('set',_('Show'),class_="ui-btn")}
42 ${h.submit('set',_('Show'),class_="ui-btn")}
43 ${h.text('size',size=1,value=c.size)}
43 ${h.text('size',size=1,value=c.size)}
44 ${_('revisions')}
44 ${_('revisions')}
45 </div>
45 </div>
46 ${h.end_form()}
46 ${h.end_form()}
47 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
47 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
48 </div>
48 </div>
49 <div id="graph_nodes">
49 <div id="graph_nodes">
50 <canvas id="graph_canvas"></canvas>
50 <canvas id="graph_canvas"></canvas>
51 </div>
51 </div>
52 <div id="graph_content">
52 <div id="graph_content">
53
53
54 <table id="changesets">
54 <table id="changesets">
55 <tbody>
55 <tbody>
56 %for cnt,cs in enumerate(c.pagination):
56 %for cnt,cs in enumerate(c.pagination):
57 <tr id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
57 <tr id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
58 <td class="checkbox">
58 <td class="checkbox">
59 ${h.checkbox(cs.raw_id,class_="changeset_range")}
59 ${h.checkbox(cs.raw_id,class_="changeset_range")}
60 </td>
60 </td>
61 <td class="author">
61 <td class="author">
62 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
62 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
63 <span title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</span>
63 <span title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</span>
64 </td>
64 </td>
65 <td class="hash">
65 <td class="hash">
66 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
66 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
67 <span class="changeset_id">${cs.revision}:</span>
67 <span class="changeset_hash">${h.show_id(cs)}</span>
68 <span class="changeset_hash">${h.short_id(cs.raw_id)}</span>
69 </a>
68 </a>
70 </td>
69 </td>
71 <td class="date">
70 <td class="date">
72 <div class="date">${h.age(cs.date,True)}</div>
71 <div class="date">${h.age(cs.date,True)}</div>
73 </td>
72 </td>
74 <td class="mid">
73 <td class="mid">
75 <div class="log-container">
74 <div class="log-container">
76 <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
75 <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
77 <div class="expand"><span class="expandtext">&darr; ${_('Show more')} &darr;</span></div>
76 <div class="expand"><span class="expandtext">&darr; ${_('Show more')} &darr;</span></div>
78 <div class="extra-container">
77 <div class="extra-container">
79 %if c.comments.get(cs.raw_id,[]):
78 %if c.comments.get(cs.raw_id,[]):
80 <div class="comments-container">
79 <div class="comments-container">
81 <div class="comments-cnt" title="${('comments')}">
80 <div class="comments-cnt" title="${('comments')}">
82 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
81 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
83 ${len(c.comments[cs.raw_id])}
82 ${len(c.comments[cs.raw_id])}
84 </a>
83 </a>
85 </div>
84 </div>
86 </div>
85 </div>
87 %endif
86 %endif
88 %if h.is_hg(c.rhodecode_repo):
87 %if h.is_hg(c.rhodecode_repo):
89 %for book in cs.bookmarks:
88 %for book in cs.bookmarks:
90 <div class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
89 <div class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
91 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
90 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
92 </div>
91 </div>
93 %endfor
92 %endfor
94 %endif
93 %endif
95 %for tag in cs.tags:
94 %for tag in cs.tags:
96 <div class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
95 <div class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
97 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
96 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
98 </div>
97 </div>
99 %endfor
98 %endfor
100 %if (not c.branch_name) and cs.branch:
99 %if (not c.branch_name) and cs.branch:
101 <div class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
100 <div class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
102 ${h.link_to(h.shorter(cs.branch),h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch))}
101 ${h.link_to(h.shorter(cs.branch),h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch))}
103 </div>
102 </div>
104 %endif
103 %endif
105 </div>
104 </div>
106 </div>
105 </div>
107 </td>
106 </td>
108 </tr>
107 </tr>
109 %endfor
108 %endfor
110 </tbody>
109 </tbody>
111 </table>
110 </table>
112
111
113 <div class="pagination-wh pagination-left">
112 <div class="pagination-wh pagination-left">
114 ${c.pagination.pager('$link_previous ~2~ $link_next')}
113 ${c.pagination.pager('$link_previous ~2~ $link_next')}
115 </div>
114 </div>
116 </div>
115 </div>
117 </div>
116 </div>
118
117
119 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
118 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
120 <script type="text/javascript">
119 <script type="text/javascript">
121 YAHOO.util.Event.onDOMReady(function(){
120 YAHOO.util.Event.onDOMReady(function(){
122
121
123 //Monitor range checkboxes and build a link to changesets
122 //Monitor range checkboxes and build a link to changesets
124 //ranges
123 //ranges
125 var checkboxes = YUD.getElementsByClassName('changeset_range');
124 var checkboxes = YUD.getElementsByClassName('changeset_range');
126 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
125 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
127 var pr_tmpl = "${h.url('pullrequest_home',repo_name=c.repo_name)}";
126 var pr_tmpl = "${h.url('pullrequest_home',repo_name=c.repo_name)}";
128
127
129 var checkbox_checker = function(e){
128 var checkbox_checker = function(e){
130 var checked_checkboxes = [];
129 var checked_checkboxes = [];
131 for (pos in checkboxes){
130 for (pos in checkboxes){
132 if(checkboxes[pos].checked){
131 if(checkboxes[pos].checked){
133 checked_checkboxes.push(checkboxes[pos]);
132 checked_checkboxes.push(checkboxes[pos]);
134 }
133 }
135 }
134 }
136 if(YUD.get('open_new_pr')){
135 if(YUD.get('open_new_pr')){
137 if(checked_checkboxes.length>1){
136 if(checked_checkboxes.length>1){
138 YUD.setStyle('open_new_pr','display','none');
137 YUD.setStyle('open_new_pr','display','none');
139 } else {
138 } else {
140 YUD.setStyle('open_new_pr','display','');
139 YUD.setStyle('open_new_pr','display','');
141 if(checked_checkboxes.length>0){
140 if(checked_checkboxes.length>0){
142 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
141 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
143 }else{
142 }else{
144 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
143 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
145 }
144 }
146 }
145 }
147 }
146 }
148
147
149 if(checked_checkboxes.length>0){
148 if(checked_checkboxes.length>0){
150 var rev_end = checked_checkboxes[0].name;
149 var rev_end = checked_checkboxes[0].name;
151 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
150 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
152 var url = url_tmpl.replace('__REVRANGE__',
151 var url = url_tmpl.replace('__REVRANGE__',
153 rev_start+'...'+rev_end);
152 rev_start+'...'+rev_end);
154
153
155 var link = (rev_start == rev_end)
154 var link = (rev_start == rev_end)
156 ? _TM['Show selected change __S']
155 ? _TM['Show selected change __S']
157 : _TM['Show selected changes __S -> __E'];
156 : _TM['Show selected changes __S -> __E'];
158
157
159 link = link.replace('__S',rev_start.substr(0,6));
158 link = link.replace('__S',rev_start.substr(0,6));
160 link = link.replace('__E',rev_end.substr(0,6));
159 link = link.replace('__E',rev_end.substr(0,6));
161 YUD.get('rev_range_container').href = url;
160 YUD.get('rev_range_container').href = url;
162 YUD.get('rev_range_container').innerHTML = link;
161 YUD.get('rev_range_container').innerHTML = link;
163 YUD.setStyle('rev_range_container','display','');
162 YUD.setStyle('rev_range_container','display','');
164 YUD.setStyle('rev_range_clear','display','');
163 YUD.setStyle('rev_range_clear','display','');
165
164
166 YUD.get('open_new_pr').href = pr_tmpl + '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
165 YUD.get('open_new_pr').href = pr_tmpl + '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
167 YUD.setStyle('compare_fork','display','none');
166 YUD.setStyle('compare_fork','display','none');
168 }else{
167 }else{
169 YUD.setStyle('rev_range_container','display','none');
168 YUD.setStyle('rev_range_container','display','none');
170 YUD.setStyle('rev_range_clear','display','none');
169 YUD.setStyle('rev_range_clear','display','none');
171 if (checkboxes){
170 if (checkboxes){
172 YUD.get('open_new_pr').href = pr_tmpl + '?rev_end={0}'.format(checkboxes[0].name);
171 YUD.get('open_new_pr').href = pr_tmpl + '?rev_end={0}'.format(checkboxes[0].name);
173 }
172 }
174 YUD.setStyle('compare_fork','display','');
173 YUD.setStyle('compare_fork','display','');
175 }
174 }
176 };
175 };
177 YUE.onDOMReady(checkbox_checker);
176 YUE.onDOMReady(checkbox_checker);
178 YUE.on(checkboxes,'click', checkbox_checker);
177 YUE.on(checkboxes,'click', checkbox_checker);
179
178
180 YUE.on('rev_range_clear','click',function(e){
179 YUE.on('rev_range_clear','click',function(e){
181 for (var i=0; i<checkboxes.length; i++){
180 for (var i=0; i<checkboxes.length; i++){
182 var cb = checkboxes[i];
181 var cb = checkboxes[i];
183 cb.checked = false;
182 cb.checked = false;
184 }
183 }
185 checkbox_checker();
184 checkbox_checker();
186 YUE.preventDefault(e);
185 YUE.preventDefault(e);
187 });
186 });
188
187
189 var msgs = YUQ('.message');
188 var msgs = YUQ('.message');
190 // get first element height
189 // get first element height
191 var el = YUQ('#graph_content .container')[0];
190 var el = YUQ('#graph_content .container')[0];
192 var row_h = el.clientHeight;
191 var row_h = el.clientHeight;
193 for(var i=0;i<msgs.length;i++){
192 for(var i=0;i<msgs.length;i++){
194 var m = msgs[i];
193 var m = msgs[i];
195
194
196 var h = m.clientHeight;
195 var h = m.clientHeight;
197 var pad = YUD.getStyle(m,'padding');
196 var pad = YUD.getStyle(m,'padding');
198 if(h > row_h){
197 if(h > row_h){
199 var offset = row_h - (h+12);
198 var offset = row_h - (h+12);
200 YUD.setStyle(m.nextElementSibling,'display','block');
199 YUD.setStyle(m.nextElementSibling,'display','block');
201 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
200 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
202 };
201 };
203 }
202 }
204 YUE.on(YUQ('.expand'),'click',function(e){
203 YUE.on(YUQ('.expand'),'click',function(e){
205 var elem = e.currentTarget.parentNode.parentNode;
204 var elem = e.currentTarget.parentNode.parentNode;
206 YUD.setStyle(e.currentTarget,'display','none');
205 YUD.setStyle(e.currentTarget,'display','none');
207 YUD.setStyle(elem,'height','auto');
206 YUD.setStyle(elem,'height','auto');
208
207
209 //redraw the graph, line_count and jsdata are global vars
208 //redraw the graph, line_count and jsdata are global vars
210 set_canvas(100);
209 set_canvas(100);
211
210
212 var r = new BranchRenderer();
211 var r = new BranchRenderer();
213 r.render(jsdata,100,line_count);
212 r.render(jsdata,100,line_count);
214
213
215 });
214 });
216
215
217 // change branch filter
216 // change branch filter
218 YUE.on(YUD.get('branch_filter'),'change',function(e){
217 YUE.on(YUD.get('branch_filter'),'change',function(e){
219 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
218 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
220 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
219 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
221 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
220 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
222 var url = url.replace('__BRANCH__',selected_branch);
221 var url = url.replace('__BRANCH__',selected_branch);
223 if(selected_branch != ''){
222 if(selected_branch != ''){
224 window.location = url;
223 window.location = url;
225 }else{
224 }else{
226 window.location = url_main;
225 window.location = url_main;
227 }
226 }
228
227
229 });
228 });
230
229
231 function set_canvas(width) {
230 function set_canvas(width) {
232 var c = document.getElementById('graph_nodes');
231 var c = document.getElementById('graph_nodes');
233 var t = document.getElementById('graph_content');
232 var t = document.getElementById('graph_content');
234 canvas = document.getElementById('graph_canvas');
233 canvas = document.getElementById('graph_canvas');
235 var div_h = t.clientHeight;
234 var div_h = t.clientHeight;
236 canvas.setAttribute('height',div_h);
235 canvas.setAttribute('height',div_h);
237 canvas.setAttribute('width',width);
236 canvas.setAttribute('width',width);
238 };
237 };
239 var heads = 1;
238 var heads = 1;
240 var line_count = 0;
239 var line_count = 0;
241 var jsdata = ${c.jsdata|n};
240 var jsdata = ${c.jsdata|n};
242
241
243 for (var i=0;i<jsdata.length;i++) {
242 for (var i=0;i<jsdata.length;i++) {
244 var in_l = jsdata[i][2];
243 var in_l = jsdata[i][2];
245 for (var j in in_l) {
244 for (var j in in_l) {
246 var m = in_l[j][1];
245 var m = in_l[j][1];
247 if (m > line_count)
246 if (m > line_count)
248 line_count = m;
247 line_count = m;
249 }
248 }
250 }
249 }
251 set_canvas(100);
250 set_canvas(100);
252
251
253 var r = new BranchRenderer();
252 var r = new BranchRenderer();
254 r.render(jsdata,100,line_count);
253 r.render(jsdata,100,line_count);
255
254
256 });
255 });
257 </script>
256 </script>
258 %else:
257 %else:
259 ${_('There are no changes yet')}
258 ${_('There are no changes yet')}
260 %endif
259 %endif
261 </div>
260 </div>
262 </div>
261 </div>
263 </%def>
262 </%def>
@@ -1,74 +1,126 b''
1 from rhodecode.tests import *
1 from rhodecode.tests import *
2
2
3
3
4 class TestChangelogController(TestController):
4 class TestChangelogController(TestController):
5
5
6 def test_index_hg(self):
6 def test_index_hg(self):
7 self.log_user()
7 self.log_user()
8 response = self.app.get(url(controller='changelog', action='index',
8 response = self.app.get(url(controller='changelog', action='index',
9 repo_name=HG_REPO))
9 repo_name=HG_REPO))
10
10
11 response.mustcontain('''id="chg_20" class="container tablerow1"''')
11 response.mustcontain('''id="chg_20" class="container tablerow1"''')
12 response.mustcontain(
12 response.mustcontain(
13 """<input class="changeset_range" """
13 """<input class="changeset_range" """
14 """id="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
14 """id="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
15 """name="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
15 """name="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
16 """type="checkbox" value="1" />"""
16 """type="checkbox" value="1" />"""
17 )
17 )
18
18 response.mustcontain(
19 response.mustcontain(
19 """<span class="changeset_id">154:</span>"""
20 """<span class="changeset_hash">r154:5e204e7583b9</span>"""
20 )
21 response.mustcontain(
22 """<span class="changeset_hash">5e204e7583b9</span>"""
23 )
21 )
24
22
25 response.mustcontain("""Small update at simplevcs app""")
23 response.mustcontain("""Small update at simplevcs app""")
26
24
27 # response.mustcontain(
25 # response.mustcontain(
28 # """<div id="changed_total_5e204e7583b9c8e7b93a020bd036564b1e731dae" """
26 # """<div id="changed_total_5e204e7583b9c8e7b93a020bd036564b1e731dae" """
29 # """style="float:right;" class="changed_total tooltip" """
27 # """style="float:right;" class="changed_total tooltip" """
30 # """title="Affected number of files, click to show """
28 # """title="Affected number of files, click to show """
31 # """more details">3</div>"""
29 # """more details">3</div>"""
32 # )
30 # )
33
31
32 def test_index_pagination_hg(self):
33 self.log_user()
34 #pagination
34 #pagination
35 response = self.app.get(url(controller='changelog', action='index',
35 self.app.get(url(controller='changelog', action='index',
36 repo_name=HG_REPO), {'page': 1})
36 repo_name=HG_REPO), {'page': 1})
37 response = self.app.get(url(controller='changelog', action='index',
37 self.app.get(url(controller='changelog', action='index',
38 repo_name=HG_REPO), {'page': 2})
38 repo_name=HG_REPO), {'page': 2})
39 response = self.app.get(url(controller='changelog', action='index',
39 self.app.get(url(controller='changelog', action='index',
40 repo_name=HG_REPO), {'page': 3})
40 repo_name=HG_REPO), {'page': 3})
41 response = self.app.get(url(controller='changelog', action='index',
41 self.app.get(url(controller='changelog', action='index',
42 repo_name=HG_REPO), {'page': 4})
42 repo_name=HG_REPO), {'page': 4})
43 response = self.app.get(url(controller='changelog', action='index',
43 self.app.get(url(controller='changelog', action='index',
44 repo_name=HG_REPO), {'page': 5})
44 repo_name=HG_REPO), {'page': 5})
45 response = self.app.get(url(controller='changelog', action='index',
45 response = self.app.get(url(controller='changelog', action='index',
46 repo_name=HG_REPO), {'page': 6})
46 repo_name=HG_REPO), {'page': 6})
47
47
48 # Test response after pagination...
48 # Test response after pagination...
49 response.mustcontain(
49 response.mustcontain(
50 """<input class="changeset_range" """
50 """<input class="changeset_range" """
51 """id="46ad32a4f974e45472a898c6b0acb600320579b1" """
51 """id="46ad32a4f974e45472a898c6b0acb600320579b1" """
52 """name="46ad32a4f974e45472a898c6b0acb600320579b1" """
52 """name="46ad32a4f974e45472a898c6b0acb600320579b1" """
53 """type="checkbox" value="1" />"""
53 """type="checkbox" value="1" />"""
54 )
54 )
55
55 response.mustcontain(
56 response.mustcontain(
56 """<span class="changeset_id">64:</span>"""
57 """<span class="changeset_hash">r64:46ad32a4f974</span>"""
57 )
58 response.mustcontain(
59 """<span class="changeset_hash">46ad32a4f974</span>"""
60 )
58 )
61
59
62 # response.mustcontain(
60 # response.mustcontain(
63 # """<div id="changed_total_46ad32a4f974e45472a898c6b0acb600320579b1" """
61 # """<div id="changed_total_46ad32a4f974e45472a898c6b0acb600320579b1" """
64 # """style="float:right;" class="changed_total tooltip" """
62 # """style="float:right;" class="changed_total tooltip" """
65 # """title="Affected number of files, click to show """
63 # """title="Affected number of files, click to show """
66 # """more details">21</div>"""
64 # """more details">21</div>"""
67 # )
65 # )
68 #
66 #
69 # response.mustcontain(
67 # response.mustcontain(
70 # """<a href="/%s/changeset/"""
68 # """<a href="/%s/changeset/"""
71 # """46ad32a4f974e45472a898c6b0acb600320579b1" """
69 # """46ad32a4f974e45472a898c6b0acb600320579b1" """
72 # """title="Merge with 2e6a2bf9356ca56df08807f4ad86d480da72a8f4">"""
70 # """title="Merge with 2e6a2bf9356ca56df08807f4ad86d480da72a8f4">"""
73 # """46ad32a4f974</a>""" % HG_REPO
71 # """46ad32a4f974</a>""" % HG_REPO
74 # )
72 # )
73
74 def test_index_git(self):
75 self.log_user()
76 response = self.app.get(url(controller='changelog', action='index',
77 repo_name=GIT_REPO))
78
79 response.mustcontain('''id="chg_20" class="container tablerow1"''')
80 response.mustcontain(
81 """<input class="changeset_range" """
82 """id="95f9a91d775b0084b2368ae7779e44931c849c0e" """
83 """name="95f9a91d775b0084b2368ae7779e44931c849c0e" """
84 """type="checkbox" value="1" />"""
85 )
86
87 response.mustcontain(
88 """<span class="changeset_hash">r613:95f9a91d775b</span>"""
89 )
90
91 response.mustcontain("""fixing stupid typo in context for mercurial""")
92
93 # response.mustcontain(
94 # """<div id="changed_total_5e204e7583b9c8e7b93a020bd036564b1e731dae" """
95 # """style="float:right;" class="changed_total tooltip" """
96 # """title="Affected number of files, click to show """
97 # """more details">3</div>"""
98 # )
99
100 def test_index_pagination_git(self):
101 self.log_user()
102 #pagination
103 self.app.get(url(controller='changelog', action='index',
104 repo_name=GIT_REPO), {'page': 1})
105 self.app.get(url(controller='changelog', action='index',
106 repo_name=GIT_REPO), {'page': 2})
107 self.app.get(url(controller='changelog', action='index',
108 repo_name=GIT_REPO), {'page': 3})
109 self.app.get(url(controller='changelog', action='index',
110 repo_name=GIT_REPO), {'page': 4})
111 self.app.get(url(controller='changelog', action='index',
112 repo_name=GIT_REPO), {'page': 5})
113 response = self.app.get(url(controller='changelog', action='index',
114 repo_name=GIT_REPO), {'page': 6})
115
116 # Test response after pagination...
117 response.mustcontain(
118 """<input class="changeset_range" """
119 """id="636ed213f2f11ef91071b9c24f2d5e6bd01a6ed5" """
120 """name="636ed213f2f11ef91071b9c24f2d5e6bd01a6ed5" """
121 """type="checkbox" value="1" />"""
122 )
123
124 response.mustcontain(
125 """<span class="changeset_hash">r515:636ed213f2f1</span>"""
126 )
@@ -1,439 +1,478 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 ##nr of threads to spawn
33 ## nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ## max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ## option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 ## WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 ## 100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 127.0.0.1
50 host = 127.0.0.1
51 port = 5000
51 port = 5000
52
52
53 [filter:proxy-prefix]
53 ## prefix middleware for rc
54 # prefix middleware for rc
54 #[filter:proxy-prefix]
55 use = egg:PasteDeploy#prefix
55 #use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 #prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 ## enable proxy prefix middleware
60 #filter-with = proxy-prefix
61 #filter-with = proxy-prefix
62
61 full_stack = true
63 full_stack = true
62 static_files = true
64 static_files = true
63 # Optional Languages
65 ## Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
66 ## en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
67 lang = en
66 cache_dir = /tmp/rc/data
68 cache_dir = /tmp/rc/data
67 index_dir = /tmp/rc/index
69 index_dir = /tmp/rc/index
68 # set this path to use archive download cache
70
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
71 ## uncomment and set this path to use archive download cache
70 app_instance_uuid = develop-test
72 #archive_cache_dir = /tmp/tarballcache
73
74 ## change this to unique ID for security
75 app_instance_uuid = rc-production
76
77 ## cut off limit for large diffs (size in bytes)
71 cut_off_limit = 256000
78 cut_off_limit = 256000
72 vcs_full_cache = False
79
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
80 ## use cache version of scm repo everywhere
81 vcs_full_cache = false
82
83 ## force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
84 force_https = false
75 # use Strict-Transport-Security headers
85
86 ## use Strict-Transport-Security headers
76 use_htsts = false
87 use_htsts = false
88
89 ## number of commits stats will parse on each iteration
77 commit_parse_limit = 25
90 commit_parse_limit = 25
78 # number of items displayed in lightweight dashboard before paginating
91
92 ## number of items displayed in lightweight dashboard before paginating is shown
79 dashboard_items = 100
93 dashboard_items = 100
94
95 ## use gravatar service to display avatars
80 use_gravatar = true
96 use_gravatar = true
81
97
82 # path to git executable
98 ## path to git executable
83 git_path = git
99 git_path = git
84
100
85 ## RSS feed options
101 ## RSS feed options
86
87 rss_cut_off_limit = 256000
102 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
103 rss_items_per_page = 10
89 rss_include_diff = false
104 rss_include_diff = false
90
105
106 ## show hash options for changelog
107 sha_len = 12
108 sha_rev = true
109
91
110
92 ## alternative_gravatar_url allows you to use your own avatar server application
111 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
112 ## the following parts of the URL will be replaced
94 ## {email} user email
113 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
114 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
115 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
116 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
117 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
118 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
119 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
120
121
122 ## container auth options
102 container_auth_enabled = false
123 container_auth_enabled = false
103 proxypass_auth_enabled = false
124 proxypass_auth_enabled = false
125
104 ## default encoding used to convert from and to unicode
126 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
127 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
128 default_encoding = utf8
107
129
108 ## overwrite schema of clone url
130 ## overwrite schema of clone url
109 ## available vars:
131 ## available vars:
110 ## scheme - http/https
132 ## scheme - http/https
111 ## user - current user
133 ## user - current user
112 ## pass - password
134 ## pass - password
113 ## netloc - network location
135 ## netloc - network location
114 ## path - usually repo_name
136 ## path - usually repo_name
115
137
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
138 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
139
118 ## issue tracking mapping for commits messages
140 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
141 ## comment out issue_pat, issue_server, issue_prefix to enable
120
142
121 ## pattern to get the issues from commit messages
143 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
144 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
145 ## {id} will be all groups matched from this pattern
124
146
125 issue_pat = (?:\s*#)(\d+)
147 issue_pat = (?:\s*#)(\d+)
126
148
127 ## server url to the issue, each {id} will be replaced with match
149 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
150 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
151 ## including groups {repo_name} is replaced with just name of repo
130
152
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
153 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
154
133 ## prefix to add to link to indicate it's an url
155 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
156 ## #314 will be replaced by <issue_prefix><id>
135
157
136 issue_prefix = #
158 issue_prefix = #
137
159
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
160 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
161 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
162 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
163 # #wiki-some-id -> https://mywiki.com/some-id
142
164
143 #issue_pat_wiki = (?:wiki-)(.+)
165 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
166 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
167 #issue_prefix_wiki = WIKI-
146
168
147
169
148 ## instance-id prefix
170 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
171 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
172 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
173 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
174 instance_id =
153
175
154 ## alternative return HTTP header for failed authentication. Default HTTP
176 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
177 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
178 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
179 auth_ret_code =
158
180
181 ## locking return code. When repository is locked return this HTTP code. 2XX
182 ## codes don't break the transactions while 4XX codes do
183 lock_ret_code = 423
184
185
159 ####################################
186 ####################################
160 ### CELERY CONFIG ####
187 ### CELERY CONFIG ####
161 ####################################
188 ####################################
162 use_celery = false
189 use_celery = false
163 broker.host = localhost
190 broker.host = localhost
164 broker.vhost = rabbitmqhost
191 broker.vhost = rabbitmqhost
165 broker.port = 5672
192 broker.port = 5672
166 broker.user = rabbitmq
193 broker.user = rabbitmq
167 broker.password = qweqwe
194 broker.password = qweqwe
168
195
169 celery.imports = rhodecode.lib.celerylib.tasks
196 celery.imports = rhodecode.lib.celerylib.tasks
170
197
171 celery.result.backend = amqp
198 celery.result.backend = amqp
172 celery.result.dburi = amqp://
199 celery.result.dburi = amqp://
173 celery.result.serialier = json
200 celery.result.serialier = json
174
201
175 #celery.send.task.error.emails = true
202 #celery.send.task.error.emails = true
176 #celery.amqp.task.result.expires = 18000
203 #celery.amqp.task.result.expires = 18000
177
204
178 celeryd.concurrency = 2
205 celeryd.concurrency = 2
179 #celeryd.log.file = celeryd.log
206 #celeryd.log.file = celeryd.log
180 celeryd.log.level = debug
207 celeryd.log.level = debug
181 celeryd.max.tasks.per.child = 1
208 celeryd.max.tasks.per.child = 1
182
209
183 #tasks will never be sent to the queue, but executed locally instead.
210 ## tasks will never be sent to the queue, but executed locally instead.
184 celery.always.eager = false
211 celery.always.eager = false
185
212
186 ####################################
213 ####################################
187 ### BEAKER CACHE ####
214 ### BEAKER CACHE ####
188 ####################################
215 ####################################
189 beaker.cache.data_dir=/tmp/rc/data/cache/data
216 beaker.cache.data_dir=/tmp/rc/data/cache/data
190 beaker.cache.lock_dir=/tmp/rc/data/cache/lock
217 beaker.cache.lock_dir=/tmp/rc/data/cache/lock
191
218
192 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
219 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
193
220
194 beaker.cache.super_short_term.type=memory
221 beaker.cache.super_short_term.type=memory
195 beaker.cache.super_short_term.expire=1
222 beaker.cache.super_short_term.expire=1
196 beaker.cache.super_short_term.key_length = 256
223 beaker.cache.super_short_term.key_length = 256
197
224
198 beaker.cache.short_term.type=memory
225 beaker.cache.short_term.type=memory
199 beaker.cache.short_term.expire=60
226 beaker.cache.short_term.expire=60
200 beaker.cache.short_term.key_length = 256
227 beaker.cache.short_term.key_length = 256
201
228
202 beaker.cache.long_term.type=memory
229 beaker.cache.long_term.type=memory
203 beaker.cache.long_term.expire=36000
230 beaker.cache.long_term.expire=36000
204 beaker.cache.long_term.key_length = 256
231 beaker.cache.long_term.key_length = 256
205
232
206 beaker.cache.sql_cache_short.type=memory
233 beaker.cache.sql_cache_short.type=memory
207 beaker.cache.sql_cache_short.expire=1
234 beaker.cache.sql_cache_short.expire=1
208 beaker.cache.sql_cache_short.key_length = 256
235 beaker.cache.sql_cache_short.key_length = 256
209
236
210 beaker.cache.sql_cache_med.type=memory
237 beaker.cache.sql_cache_med.type=memory
211 beaker.cache.sql_cache_med.expire=360
238 beaker.cache.sql_cache_med.expire=360
212 beaker.cache.sql_cache_med.key_length = 256
239 beaker.cache.sql_cache_med.key_length = 256
213
240
214 beaker.cache.sql_cache_long.type=file
241 beaker.cache.sql_cache_long.type=file
215 beaker.cache.sql_cache_long.expire=3600
242 beaker.cache.sql_cache_long.expire=3600
216 beaker.cache.sql_cache_long.key_length = 256
243 beaker.cache.sql_cache_long.key_length = 256
217
244
218 ####################################
245 ####################################
219 ### BEAKER SESSION ####
246 ### BEAKER SESSION ####
220 ####################################
247 ####################################
221 ## Type of storage used for the session, current types are
248 ## Type of storage used for the session, current types are
222 ## dbm, file, memcached, database, and memory.
249 ## dbm, file, memcached, database, and memory.
223 ## The storage uses the Container API
250 ## The storage uses the Container API
224 ## that is also used by the cache system.
251 ## that is also used by the cache system.
225
252
226 ## db session ##
253 ## db session ##
227 #beaker.session.type = ext:database
254 #beaker.session.type = ext:database
228 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
255 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
229 #beaker.session.table_name = db_session
256 #beaker.session.table_name = db_session
230
257
231 ## encrypted cookie client side session, good for many instances ##
258 ## encrypted cookie client side session, good for many instances ##
232 #beaker.session.type = cookie
259 #beaker.session.type = cookie
233
260
234 ## file based cookies (default) ##
261 ## file based cookies (default) ##
235 #beaker.session.type = file
262 #beaker.session.type = file
236
263
237
264
238 beaker.session.key = rhodecode
265 beaker.session.key = rhodecode
239 ## secure cookie requires AES python libraries ##
266 ## secure cookie requires AES python libraries
240 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
267 #beaker.session.encrypt_key = <key_for_encryption>
241 #beaker.session.validate_key = 9712sds2212c--zxc123
268 #beaker.session.validate_key = <validation_key>
269
242 ## sets session as invalid if it haven't been accessed for given amount of time
270 ## sets session as invalid if it haven't been accessed for given amount of time
243 beaker.session.timeout = 3600
271 beaker.session.timeout = 3600
244 beaker.session.httponly = true
272 beaker.session.httponly = true
245 #beaker.session.cookie_path = /<your-prefix>
273 #beaker.session.cookie_path = /<your-prefix>
246
274
247 ## uncomment for https secure cookie ##
275 ## uncomment for https secure cookie
248 beaker.session.secure = false
276 beaker.session.secure = false
249
277
250 ## auto save the session to not to use .save() ##
278 ## auto save the session to not to use .save()
251 beaker.session.auto = False
279 beaker.session.auto = False
252
280
253 ## default cookie expiration time in seconds `true` expire at browser close ##
281 ## default cookie expiration time in seconds `true` expire at browser close ##
254 #beaker.session.cookie_expires = 3600
282 #beaker.session.cookie_expires = 3600
255
283
256
284
257 ############################
285 ############################
258 ## ERROR HANDLING SYSTEMS ##
286 ## ERROR HANDLING SYSTEMS ##
259 ############################
287 ############################
260
288
261 ####################
289 ####################
262 ### [errormator] ###
290 ### [errormator] ###
263 ####################
291 ####################
264
292
265 # Errormator is tailored to work with RhodeCode, see
293 ## Errormator is tailored to work with RhodeCode, see
266 # http://errormator.com for details how to obtain an account
294 ## http://errormator.com for details how to obtain an account
267 # you must install python package `errormator_client` to make it work
295 ## you must install python package `errormator_client` to make it work
268
296
269 # errormator enabled
297 ## errormator enabled
270 errormator = true
298 errormator = false
271
299
272 errormator.server_url = https://api.errormator.com
300 errormator.server_url = https://api.errormator.com
273 errormator.api_key = YOUR_API_KEY
301 errormator.api_key = YOUR_API_KEY
274
302
275 # TWEAK AMOUNT OF INFO SENT HERE
303 ## TWEAK AMOUNT OF INFO SENT HERE
276
304
277 # enables 404 error logging (default False)
305 ## enables 404 error logging (default False)
278 errormator.report_404 = false
306 errormator.report_404 = false
279
307
280 # time in seconds after request is considered being slow (default 1)
308 ## time in seconds after request is considered being slow (default 1)
281 errormator.slow_request_time = 1
309 errormator.slow_request_time = 1
282
310
283 # record slow requests in application
311 ## record slow requests in application
284 # (needs to be enabled for slow datastore recording and time tracking)
312 ## (needs to be enabled for slow datastore recording and time tracking)
285 errormator.slow_requests = true
313 errormator.slow_requests = true
286
314
287 # enable hooking to application loggers
315 ## enable hooking to application loggers
288 # errormator.logging = true
316 # errormator.logging = true
289
317
290 # minimum log level for log capture
318 ## minimum log level for log capture
291 # errormator.logging.level = WARNING
319 # errormator.logging.level = WARNING
292
320
293 # send logs only from erroneous/slow requests
321 ## send logs only from erroneous/slow requests
294 # (saves API quota for intensive logging)
322 ## (saves API quota for intensive logging)
295 errormator.logging_on_error = false
323 errormator.logging_on_error = false
296
324
297 # list of additonal keywords that should be grabbed from environ object
325 ## list of additonal keywords that should be grabbed from environ object
298 # can be string with comma separated list of words in lowercase
326 ## can be string with comma separated list of words in lowercase
299 # (by default client will always send following info:
327 ## (by default client will always send following info:
300 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
328 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
301 # start with HTTP* this list be extended with additional keywords here
329 ## start with HTTP* this list be extended with additional keywords here
302 errormator.environ_keys_whitelist =
330 errormator.environ_keys_whitelist =
303
331
304
332
305 # list of keywords that should be blanked from request object
333 ## list of keywords that should be blanked from request object
306 # can be string with comma separated list of words in lowercase
334 ## can be string with comma separated list of words in lowercase
307 # (by default client will always blank keys that contain following words
335 ## (by default client will always blank keys that contain following words
308 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
336 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
309 # this list be extended with additional keywords set here
337 ## this list be extended with additional keywords set here
310 errormator.request_keys_blacklist =
338 errormator.request_keys_blacklist =
311
339
312
340
313 # list of namespaces that should be ignores when gathering log entries
341 ## list of namespaces that should be ignores when gathering log entries
314 # can be string with comma separated list of namespaces
342 ## can be string with comma separated list of namespaces
315 # (by default the client ignores own entries: errormator_client.client)
343 ## (by default the client ignores own entries: errormator_client.client)
316 errormator.log_namespace_blacklist =
344 errormator.log_namespace_blacklist =
317
345
318
346
319 ################
347 ################
320 ### [sentry] ###
348 ### [sentry] ###
321 ################
349 ################
322
350
323 # sentry is a alternative open source error aggregator
351 ## sentry is a alternative open source error aggregator
324 # you must install python packages `sentry` and `raven` to enable
352 ## you must install python packages `sentry` and `raven` to enable
325
353
326 sentry.dsn = YOUR_DNS
354 sentry.dsn = YOUR_DNS
327 sentry.servers =
355 sentry.servers =
328 sentry.name =
356 sentry.name =
329 sentry.key =
357 sentry.key =
330 sentry.public_key =
358 sentry.public_key =
331 sentry.secret_key =
359 sentry.secret_key =
332 sentry.project =
360 sentry.project =
333 sentry.site =
361 sentry.site =
334 sentry.include_paths =
362 sentry.include_paths =
335 sentry.exclude_paths =
363 sentry.exclude_paths =
336
364
337
365
338 ################################################################################
366 ################################################################################
339 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
367 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
340 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
368 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
341 ## execute malicious code after an exception is raised. ##
369 ## execute malicious code after an exception is raised. ##
342 ################################################################################
370 ################################################################################
343 set debug = false
371 set debug = false
344
372
345 ##################################
373 ##################################
346 ### LOGVIEW CONFIG ###
374 ### LOGVIEW CONFIG ###
347 ##################################
375 ##################################
348 logview.sqlalchemy = #faa
376 logview.sqlalchemy = #faa
349 logview.pylons.templating = #bfb
377 logview.pylons.templating = #bfb
350 logview.pylons.util = #eee
378 logview.pylons.util = #eee
351
379
352 #########################################################
380 #########################################################
353 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
381 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
354 #########################################################
382 #########################################################
355 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.sqlite
383 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.sqlite
356 #sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_test
384 #sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_test
357 #sqlalchemy.db1.url = mysql://root:qwe@localhost/rhodecode_test
385 #sqlalchemy.db1.url = mysql://root:qwe@localhost/rhodecode_test
358 sqlalchemy.db1.echo = false
386 sqlalchemy.db1.echo = false
359 sqlalchemy.db1.pool_recycle = 3600
387 sqlalchemy.db1.pool_recycle = 3600
360 sqlalchemy.db1.convert_unicode = true
388 sqlalchemy.db1.convert_unicode = true
361
389
362 ################################
390 ################################
363 ### LOGGING CONFIGURATION ####
391 ### LOGGING CONFIGURATION ####
364 ################################
392 ################################
365 [loggers]
393 [loggers]
366 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
394 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
367
395
368 [handlers]
396 [handlers]
369 keys = console
397 keys = console, console_sql
370
398
371 [formatters]
399 [formatters]
372 keys = generic, color_formatter
400 keys = generic, color_formatter, color_formatter_sql
373
401
374 #############
402 #############
375 ## LOGGERS ##
403 ## LOGGERS ##
376 #############
404 #############
377 [logger_root]
405 [logger_root]
378 level = DEBUG
406 level = DEBUG
379 handlers = console
407 handlers = console
380
408
381 [logger_routes]
409 [logger_routes]
382 level = DEBUG
410 level = DEBUG
383 handlers =
411 handlers =
384 qualname = routes.middleware
412 qualname = routes.middleware
385 # "level = DEBUG" logs the route matched and routing variables.
413 ## "level = DEBUG" logs the route matched and routing variables.
386 propagate = 1
414 propagate = 1
387
415
388 [logger_beaker]
416 [logger_beaker]
389 level = DEBUG
417 level = DEBUG
390 handlers =
418 handlers =
391 qualname = beaker.container
419 qualname = beaker.container
392 propagate = 1
420 propagate = 1
393
421
394 [logger_templates]
422 [logger_templates]
395 level = INFO
423 level = INFO
396 handlers =
424 handlers =
397 qualname = pylons.templating
425 qualname = pylons.templating
398 propagate = 1
426 propagate = 1
399
427
400 [logger_rhodecode]
428 [logger_rhodecode]
401 level = DEBUG
429 level = DEBUG
402 handlers =
430 handlers =
403 qualname = rhodecode
431 qualname = rhodecode
404 propagate = 1
432 propagate = 1
405
433
406 [logger_sqlalchemy]
434 [logger_sqlalchemy]
407 level = ERROR
435 level = ERROR
408 handlers = console
436 handlers = console
409 qualname = sqlalchemy.engine
437 qualname = sqlalchemy.engine
410 propagate = 0
438 propagate = 0
411
439
412 [logger_whoosh_indexer]
440 [logger_whoosh_indexer]
413 level = DEBUG
441 level = DEBUG
414 handlers =
442 handlers =
415 qualname = whoosh_indexer
443 qualname = whoosh_indexer
416 propagate = 1
444 propagate = 1
417
445
418 ##############
446 ##############
419 ## HANDLERS ##
447 ## HANDLERS ##
420 ##############
448 ##############
421
449
422 [handler_console]
450 [handler_console]
423 class = StreamHandler
451 class = StreamHandler
424 args = (sys.stderr,)
452 args = (sys.stderr,)
425 level = NOTSET
453 level = NOTSET
426 formatter = generic
454 formatter = generic
427
455
456 [handler_console_sql]
457 class = StreamHandler
458 args = (sys.stderr,)
459 level = WARN
460 formatter = generic
461
428 ################
462 ################
429 ## FORMATTERS ##
463 ## FORMATTERS ##
430 ################
464 ################
431
465
432 [formatter_generic]
466 [formatter_generic]
433 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
467 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
434 datefmt = %Y-%m-%d %H:%M:%S
468 datefmt = %Y-%m-%d %H:%M:%S
435
469
436 [formatter_color_formatter]
470 [formatter_color_formatter]
437 class=rhodecode.lib.colored_formatter.ColorFormatter
471 class=rhodecode.lib.colored_formatter.ColorFormatter
438 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
472 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
439 datefmt = %Y-%m-%d %H:%M:%S
473 datefmt = %Y-%m-%d %H:%M:%S
474
475 [formatter_color_formatter_sql]
476 class=rhodecode.lib.colored_formatter.ColorFormatterSql
477 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
478 datefmt = %Y-%m-%d %H:%M:%S
General Comments 0
You need to be logged in to leave comments. Login now