##// END OF EJS Templates
coding style: fix trailing and leading spaces and tabs
Mads Kiilerich -
r3267:7b74079b beta
parent child Browse files
Show More
@@ -1,981 +1,981 b''
1 .. _api:
1 .. _api:
2
2
3 ===
3 ===
4 API
4 API
5 ===
5 ===
6
6
7
7
8 Starting from RhodeCode version 1.2 a simple API was implemented.
8 Starting from RhodeCode version 1.2 a simple API was implemented.
9 There's a single schema for calling all api methods. API is implemented
9 There's a single schema for calling all api methods. API is implemented
10 with JSON protocol both ways. An url to send API request to RhodeCode is
10 with JSON protocol both ways. An url to send API request to RhodeCode is
11 <your_server>/_admin/api
11 <your_server>/_admin/api
12
12
13 API ACCESS FOR WEB VIEWS
13 API ACCESS FOR WEB VIEWS
14 ++++++++++++++++++++++++
14 ++++++++++++++++++++++++
15
15
16 API access can also be turned on for each web view in RhodeCode that is
16 API access can also be turned on for each web view in RhodeCode that is
17 decorated with `@LoginRequired` decorator. To enable API access simple change
17 decorated with `@LoginRequired` decorator. To enable API access simple change
18 the standard login decorator to `@LoginRequired(api_access=True)`.
18 the standard login decorator to `@LoginRequired(api_access=True)`.
19 After this change, a rhodecode view can be accessed without login by adding a
19 After this change, a rhodecode view can be accessed without login by adding a
20 GET parameter `?api_key=<api_key>` to url. By default this is only
20 GET parameter `?api_key=<api_key>` to url. By default this is only
21 enabled on RSS/ATOM feed views.
21 enabled on RSS/ATOM feed views.
22
22
23
23
24 API ACCESS
24 API ACCESS
25 ++++++++++
25 ++++++++++
26
26
27 All clients are required to send JSON-RPC spec JSON data::
27 All clients are required to send JSON-RPC spec JSON data::
28
28
29 {
29 {
30 "id:"<id>",
30 "id:"<id>",
31 "api_key":"<api_key>",
31 "api_key":"<api_key>",
32 "method":"<method_name>",
32 "method":"<method_name>",
33 "args":{"<arg_key>":"<arg_val>"}
33 "args":{"<arg_key>":"<arg_val>"}
34 }
34 }
35
35
36 Example call for autopulling remotes repos using curl::
36 Example call for autopulling remotes repos using curl::
37 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
37 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
38
38
39 Simply provide
39 Simply provide
40 - *id* A value of any type, which is used to match the response with the request that it is replying to.
40 - *id* A value of any type, which is used to match the response with the request that it is replying to.
41 - *api_key* for access and permission validation.
41 - *api_key* for access and permission validation.
42 - *method* is name of method to call
42 - *method* is name of method to call
43 - *args* is an key:value list of arguments to pass to method
43 - *args* is an key:value list of arguments to pass to method
44
44
45 .. note::
45 .. note::
46
46
47 api_key can be found in your user account page
47 api_key can be found in your user account page
48
48
49
49
50 RhodeCode API will return always a JSON-RPC response::
50 RhodeCode API will return always a JSON-RPC response::
51
51
52 {
52 {
53 "id":<id>, # matching id sent by request
53 "id":<id>, # matching id sent by request
54 "result": "<result>"|null, # JSON formatted result, null if any errors
54 "result": "<result>"|null, # JSON formatted result, null if any errors
55 "error": "null"|<error_message> # JSON formatted error (if any)
55 "error": "null"|<error_message> # JSON formatted error (if any)
56 }
56 }
57
57
58 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
58 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
59 calling api *error* key from response will contain failure description
59 calling api *error* key from response will contain failure description
60 and result will be null.
60 and result will be null.
61
61
62
62
63 API CLIENT
63 API CLIENT
64 ++++++++++
64 ++++++++++
65
65
66 From version 1.4 RhodeCode adds a script that allows to easily
66 From version 1.4 RhodeCode adds a script that allows to easily
67 communicate with API. After installing RhodeCode a `rhodecode-api` script
67 communicate with API. After installing RhodeCode a `rhodecode-api` script
68 will be available.
68 will be available.
69
69
70 To get started quickly simply run::
70 To get started quickly simply run::
71
71
72 rhodecode-api _create_config --apikey=<youapikey> --apihost=<rhodecode host>
72 rhodecode-api _create_config --apikey=<youapikey> --apihost=<rhodecode host>
73
73
74 This will create a file named .config in the directory you executed it storing
74 This will create a file named .config in the directory you executed it storing
75 json config file with credentials. You can skip this step and always provide
75 json config file with credentials. You can skip this step and always provide
76 both of the arguments to be able to communicate with server
76 both of the arguments to be able to communicate with server
77
77
78
78
79 after that simply run any api command for example get_repo::
79 after that simply run any api command for example get_repo::
80
80
81 rhodecode-api get_repo
81 rhodecode-api get_repo
82
82
83 calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
83 calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
84 rhodecode said:
84 rhodecode said:
85 {'error': 'Missing non optional `repoid` arg in JSON DATA',
85 {'error': 'Missing non optional `repoid` arg in JSON DATA',
86 'id': 75,
86 'id': 75,
87 'result': None}
87 'result': None}
88
88
89 Ups looks like we forgot to add an argument
89 Ups looks like we forgot to add an argument
90
90
91 Let's try again now giving the repoid as parameters::
91 Let's try again now giving the repoid as parameters::
92
92
93 rhodecode-api get_repo repoid:rhodecode
93 rhodecode-api get_repo repoid:rhodecode
94
94
95 calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
95 calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
96 rhodecode said:
96 rhodecode said:
97 {'error': None,
97 {'error': None,
98 'id': 39,
98 'id': 39,
99 'result': <json data...>}
99 'result': <json data...>}
100
100
101
101
102
102
103 API METHODS
103 API METHODS
104 +++++++++++
104 +++++++++++
105
105
106
106
107 pull
107 pull
108 ----
108 ----
109
109
110 Pulls given repo from remote location. Can be used to automatically keep
110 Pulls given repo from remote location. Can be used to automatically keep
111 remote repos up to date. This command can be executed only using api_key
111 remote repos up to date. This command can be executed only using api_key
112 belonging to user with admin rights
112 belonging to user with admin rights
113
113
114 INPUT::
114 INPUT::
115
115
116 id : <id_for_response>
116 id : <id_for_response>
117 api_key : "<api_key>"
117 api_key : "<api_key>"
118 method : "pull"
118 method : "pull"
119 args : {
119 args : {
120 "repoid" : "<reponame or repo_id>"
120 "repoid" : "<reponame or repo_id>"
121 }
121 }
122
122
123 OUTPUT::
123 OUTPUT::
124
124
125 id : <id_given_in_input>
125 id : <id_given_in_input>
126 result : "Pulled from `<reponame>`"
126 result : "Pulled from `<reponame>`"
127 error : null
127 error : null
128
128
129
129
130 rescan_repos
130 rescan_repos
131 ------------
131 ------------
132
132
133 Dispatch rescan repositories action. If remove_obsolete is set
133 Dispatch rescan repositories action. If remove_obsolete is set
134 RhodeCode will delete repos that are in database but not in the filesystem.
134 RhodeCode will delete repos that are in database but not in the filesystem.
135 This command can be executed only using api_key belonging to user with admin
135 This command can be executed only using api_key belonging to user with admin
136 rights.
136 rights.
137
137
138 INPUT::
138 INPUT::
139
139
140 id : <id_for_response>
140 id : <id_for_response>
141 api_key : "<api_key>"
141 api_key : "<api_key>"
142 method : "rescan_repos"
142 method : "rescan_repos"
143 args : {
143 args : {
144 "remove_obsolete" : "<boolean = Optional(False)>"
144 "remove_obsolete" : "<boolean = Optional(False)>"
145 }
145 }
146
146
147 OUTPUT::
147 OUTPUT::
148
148
149 id : <id_given_in_input>
149 id : <id_given_in_input>
150 result : "{'added': [<list of names of added repos>],
150 result : "{'added': [<list of names of added repos>],
151 'removed': [<list of names of removed repos>]}"
151 'removed': [<list of names of removed repos>]}"
152 error : null
152 error : null
153
153
154
154
155 invalidate_cache
155 invalidate_cache
156 ----------------
156 ----------------
157
157
158 Invalidate cache for repository.
158 Invalidate cache for repository.
159 This command can be executed only using api_key belonging to user with admin
159 This command can be executed only using api_key belonging to user with admin
160 rights or regular user that have write or admin or write access to repository.
160 rights or regular user that have write or admin or write access to repository.
161
161
162 INPUT::
162 INPUT::
163
163
164 id : <id_for_response>
164 id : <id_for_response>
165 api_key : "<api_key>"
165 api_key : "<api_key>"
166 method : "invalidate_cache"
166 method : "invalidate_cache"
167 args : {
167 args : {
168 "repoid" : "<reponame or repo_id>"
168 "repoid" : "<reponame or repo_id>"
169 }
169 }
170
170
171 OUTPUT::
171 OUTPUT::
172
172
173 id : <id_given_in_input>
173 id : <id_given_in_input>
174 result : "Cache for repository `<reponame>` was invalidated: invalidated cache keys: <list_of_cache_keys>"
174 result : "Cache for repository `<reponame>` was invalidated: invalidated cache keys: <list_of_cache_keys>"
175 error : null
175 error : null
176
176
177 lock
177 lock
178 ----
178 ----
179
179
180 Set locking state on given repository by given user. If userid param is skipped
180 Set locking state on given repository by given user. If userid param is skipped
181 , then it is set to id of user whos calling this method.
181 , then it is set to id of user whos calling this method.
182 This command can be executed only using api_key belonging to user with admin
182 This command can be executed only using api_key belonging to user with admin
183 rights or regular user that have admin or write access to repository.
183 rights or regular user that have admin or write access to repository.
184
184
185 INPUT::
185 INPUT::
186
186
187 id : <id_for_response>
187 id : <id_for_response>
188 api_key : "<api_key>"
188 api_key : "<api_key>"
189 method : "lock"
189 method : "lock"
190 args : {
190 args : {
191 "repoid" : "<reponame or repo_id>"
191 "repoid" : "<reponame or repo_id>"
192 "userid" : "<user_id or username = Optional(=apiuser)>",
192 "userid" : "<user_id or username = Optional(=apiuser)>",
193 "locked" : "<bool true|false>"
193 "locked" : "<bool true|false>"
194 }
194 }
195
195
196 OUTPUT::
196 OUTPUT::
197
197
198 id : <id_given_in_input>
198 id : <id_given_in_input>
199 result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
199 result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
200 error : null
200 error : null
201
201
202
202
203 show_ip
203 show_ip
204 -------
204 -------
205
205
206 Shows IP address as seen from RhodeCode server, together with all
206 Shows IP address as seen from RhodeCode server, together with all
207 defined IP addresses for given user.
207 defined IP addresses for given user.
208 This command can be executed only using api_key belonging to user with admin
208 This command can be executed only using api_key belonging to user with admin
209 rights.
209 rights.
210
210
211 INPUT::
211 INPUT::
212
212
213 id : <id_for_response>
213 id : <id_for_response>
214 api_key : "<api_key>"
214 api_key : "<api_key>"
215 method : "show_ip"
215 method : "show_ip"
216 args : {
216 args : {
217 "userid" : "<user_id or username>",
217 "userid" : "<user_id or username>",
218 }
218 }
219
219
220 OUTPUT::
220 OUTPUT::
221
221
222 id : <id_given_in_input>
222 id : <id_given_in_input>
223 result : {
223 result : {
224 "ip_addr_server": <ip_from_clien>",
224 "ip_addr_server": <ip_from_clien>",
225 "user_ips": [
225 "user_ips": [
226 {
226 {
227 "ip_addr": "<ip_with_mask>",
227 "ip_addr": "<ip_with_mask>",
228 "ip_range": ["<start_ip>", "<end_ip>"],
228 "ip_range": ["<start_ip>", "<end_ip>"],
229 },
229 },
230 ...
230 ...
231 ]
231 ]
232 }
232 }
233
233
234 error : null
234 error : null
235
235
236
236
237 get_user
237 get_user
238 --------
238 --------
239
239
240 Get's an user by username or user_id, Returns empty result if user is not found.
240 Get's an user by username or user_id, Returns empty result if user is not found.
241 If userid param is skipped it is set to id of user who is calling this method.
241 If userid param is skipped it is set to id of user who is calling this method.
242 This command can be executed only using api_key belonging to user with admin
242 This command can be executed only using api_key belonging to user with admin
243 rights, or regular users that cannot specify different userid than theirs
243 rights, or regular users that cannot specify different userid than theirs
244
244
245
245
246 INPUT::
246 INPUT::
247
247
248 id : <id_for_response>
248 id : <id_for_response>
249 api_key : "<api_key>"
249 api_key : "<api_key>"
250 method : "get_user"
250 method : "get_user"
251 args : {
251 args : {
252 "userid" : "<username or user_id Optional(=apiuser)>"
252 "userid" : "<username or user_id Optional(=apiuser)>"
253 }
253 }
254
254
255 OUTPUT::
255 OUTPUT::
256
256
257 id : <id_given_in_input>
257 id : <id_given_in_input>
258 result: None if user does not exist or
258 result: None if user does not exist or
259 {
259 {
260 "user_id" : "<user_id>",
260 "user_id" : "<user_id>",
261 "api_key" : "<api_key>",
261 "api_key" : "<api_key>",
262 "username" : "<username>",
262 "username" : "<username>",
263 "firstname": "<firstname>",
263 "firstname": "<firstname>",
264 "lastname" : "<lastname>",
264 "lastname" : "<lastname>",
265 "email" : "<email>",
265 "email" : "<email>",
266 "emails": "<list_of_all_additional_emails>",
266 "emails": "<list_of_all_additional_emails>",
267 "ip_addresses": "<list_of_ip_addresses_for_user>",
267 "ip_addresses": "<list_of_ip_addresses_for_user>",
268 "active" : "<bool>",
268 "active" : "<bool>",
269 "admin" :Β  "<bool>",
269 "admin" :Β  "<bool>",
270 "ldap_dn" : "<ldap_dn>",
270 "ldap_dn" : "<ldap_dn>",
271 "last_login": "<last_login>",
271 "last_login": "<last_login>",
272 "permissions": {
272 "permissions": {
273 "global": ["hg.create.repository",
273 "global": ["hg.create.repository",
274 "repository.read",
274 "repository.read",
275 "hg.register.manual_activate"],
275 "hg.register.manual_activate"],
276 "repositories": {"repo1": "repository.none"},
276 "repositories": {"repo1": "repository.none"},
277 "repositories_groups": {"Group1": "group.read"}
277 "repositories_groups": {"Group1": "group.read"}
278 },
278 },
279 }
279 }
280
280
281 error: null
281 error: null
282
282
283
283
284 get_users
284 get_users
285 ---------
285 ---------
286
286
287 Lists all existing users. This command can be executed only using api_key
287 Lists all existing users. This command can be executed only using api_key
288 belonging to user with admin rights.
288 belonging to user with admin rights.
289
289
290
290
291 INPUT::
291 INPUT::
292
292
293 id : <id_for_response>
293 id : <id_for_response>
294 api_key : "<api_key>"
294 api_key : "<api_key>"
295 method : "get_users"
295 method : "get_users"
296 args : { }
296 args : { }
297
297
298 OUTPUT::
298 OUTPUT::
299
299
300 id : <id_given_in_input>
300 id : <id_given_in_input>
301 result: [
301 result: [
302 {
302 {
303 "user_id" : "<user_id>",
303 "user_id" : "<user_id>",
304 "username" : "<username>",
304 "username" : "<username>",
305 "firstname": "<firstname>",
305 "firstname": "<firstname>",
306 "lastname" : "<lastname>",
306 "lastname" : "<lastname>",
307 "email" : "<email>",
307 "email" : "<email>",
308 "emails": "<list_of_all_additional_emails>",
308 "emails": "<list_of_all_additional_emails>",
309 "ip_addresses": "<list_of_ip_addresses_for_user>",
309 "ip_addresses": "<list_of_ip_addresses_for_user>",
310 "active" : "<bool>",
310 "active" : "<bool>",
311 "admin" :Β  "<bool>",
311 "admin" :Β  "<bool>",
312 "ldap_dn" : "<ldap_dn>",
312 "ldap_dn" : "<ldap_dn>",
313 "last_login": "<last_login>",
313 "last_login": "<last_login>",
314 },
314 },
315 …
315 …
316 ]
316 ]
317 error: null
317 error: null
318
318
319
319
320 create_user
320 create_user
321 -----------
321 -----------
322
322
323 Creates new user. This command can
323 Creates new user. This command can
324 be executed only using api_key belonging to user with admin rights.
324 be executed only using api_key belonging to user with admin rights.
325
325
326
326
327 INPUT::
327 INPUT::
328
328
329 id : <id_for_response>
329 id : <id_for_response>
330 api_key : "<api_key>"
330 api_key : "<api_key>"
331 method : "create_user"
331 method : "create_user"
332 args : {
332 args : {
333 "username" : "<username>",
333 "username" : "<username>",
334 "email" : "<useremail>",
334 "email" : "<useremail>",
335 "password" : "<password>",
335 "password" : "<password>",
336 "firstname" : "<firstname> = Optional(None)",
336 "firstname" : "<firstname> = Optional(None)",
337 "lastname" : "<lastname> = Optional(None)",
337 "lastname" : "<lastname> = Optional(None)",
338 "active" : "<bool> = Optional(True)",
338 "active" : "<bool> = Optional(True)",
339 "admin" : "<bool> = Optional(False)",
339 "admin" : "<bool> = Optional(False)",
340 "ldap_dn" : "<ldap_dn> = Optional(None)"
340 "ldap_dn" : "<ldap_dn> = Optional(None)"
341 }
341 }
342
342
343 OUTPUT::
343 OUTPUT::
344
344
345 id : <id_given_in_input>
345 id : <id_given_in_input>
346 result: {
346 result: {
347 "msg" : "created new user `<username>`",
347 "msg" : "created new user `<username>`",
348 "user": {
348 "user": {
349 "user_id" : "<user_id>",
349 "user_id" : "<user_id>",
350 "username" : "<username>",
350 "username" : "<username>",
351 "firstname": "<firstname>",
351 "firstname": "<firstname>",
352 "lastname" : "<lastname>",
352 "lastname" : "<lastname>",
353 "email" : "<email>",
353 "email" : "<email>",
354 "emails": "<list_of_all_additional_emails>",
354 "emails": "<list_of_all_additional_emails>",
355 "active" : "<bool>",
355 "active" : "<bool>",
356 "admin" :Β  "<bool>",
356 "admin" :Β  "<bool>",
357 "ldap_dn" : "<ldap_dn>",
357 "ldap_dn" : "<ldap_dn>",
358 "last_login": "<last_login>",
358 "last_login": "<last_login>",
359 },
359 },
360 }
360 }
361 error: null
361 error: null
362
362
363
363
364 update_user
364 update_user
365 -----------
365 -----------
366
366
367 updates given user if such user exists. This command can
367 updates given user if such user exists. This command can
368 be executed only using api_key belonging to user with admin rights.
368 be executed only using api_key belonging to user with admin rights.
369
369
370
370
371 INPUT::
371 INPUT::
372
372
373 id : <id_for_response>
373 id : <id_for_response>
374 api_key : "<api_key>"
374 api_key : "<api_key>"
375 method : "update_user"
375 method : "update_user"
376 args : {
376 args : {
377 "userid" : "<user_id or username>",
377 "userid" : "<user_id or username>",
378 "username" : "<username> = Optional(None)",
378 "username" : "<username> = Optional(None)",
379 "email" : "<useremail> = Optional(None)",
379 "email" : "<useremail> = Optional(None)",
380 "password" : "<password> = Optional(None)",
380 "password" : "<password> = Optional(None)",
381 "firstname" : "<firstname> = Optional(None)",
381 "firstname" : "<firstname> = Optional(None)",
382 "lastname" : "<lastname> = Optional(None)",
382 "lastname" : "<lastname> = Optional(None)",
383 "active" : "<bool> = Optional(None)",
383 "active" : "<bool> = Optional(None)",
384 "admin" : "<bool> = Optional(None)",
384 "admin" : "<bool> = Optional(None)",
385 "ldap_dn" : "<ldap_dn> = Optional(None)"
385 "ldap_dn" : "<ldap_dn> = Optional(None)"
386 }
386 }
387
387
388 OUTPUT::
388 OUTPUT::
389
389
390 id : <id_given_in_input>
390 id : <id_given_in_input>
391 result: {
391 result: {
392 "msg" : "updated user ID:<userid> <username>",
392 "msg" : "updated user ID:<userid> <username>",
393 "user": {
393 "user": {
394 "user_id" : "<user_id>",
394 "user_id" : "<user_id>",
395 "username" : "<username>",
395 "username" : "<username>",
396 "firstname": "<firstname>",
396 "firstname": "<firstname>",
397 "lastname" : "<lastname>",
397 "lastname" : "<lastname>",
398 "email" : "<email>",
398 "email" : "<email>",
399 "emails": "<list_of_all_additional_emails>",
399 "emails": "<list_of_all_additional_emails>",
400 "active" : "<bool>",
400 "active" : "<bool>",
401 "admin" :Β  "<bool>",
401 "admin" :Β  "<bool>",
402 "ldap_dn" : "<ldap_dn>",
402 "ldap_dn" : "<ldap_dn>",
403 "last_login": "<last_login>",
403 "last_login": "<last_login>",
404 },
404 },
405 }
405 }
406 error: null
406 error: null
407
407
408
408
409 delete_user
409 delete_user
410 -----------
410 -----------
411
411
412
412
413 deletes givenuser if such user exists. This command can
413 deletes givenuser if such user exists. This command can
414 be executed only using api_key belonging to user with admin rights.
414 be executed only using api_key belonging to user with admin rights.
415
415
416
416
417 INPUT::
417 INPUT::
418
418
419 id : <id_for_response>
419 id : <id_for_response>
420 api_key : "<api_key>"
420 api_key : "<api_key>"
421 method : "delete_user"
421 method : "delete_user"
422 args : {
422 args : {
423 "userid" : "<user_id or username>",
423 "userid" : "<user_id or username>",
424 }
424 }
425
425
426 OUTPUT::
426 OUTPUT::
427
427
428 id : <id_given_in_input>
428 id : <id_given_in_input>
429 result: {
429 result: {
430 "msg" : "deleted user ID:<userid> <username>",
430 "msg" : "deleted user ID:<userid> <username>",
431 "user": null
431 "user": null
432 }
432 }
433 error: null
433 error: null
434
434
435
435
436 get_users_group
436 get_users_group
437 ---------------
437 ---------------
438
438
439 Gets an existing users group. This command can be executed only using api_key
439 Gets an existing users group. This command can be executed only using api_key
440 belonging to user with admin rights.
440 belonging to user with admin rights.
441
441
442
442
443 INPUT::
443 INPUT::
444
444
445 id : <id_for_response>
445 id : <id_for_response>
446 api_key : "<api_key>"
446 api_key : "<api_key>"
447 method : "get_users_group"
447 method : "get_users_group"
448 args : {
448 args : {
449 "usersgroupid" : "<users group id or name>"
449 "usersgroupid" : "<users group id or name>"
450 }
450 }
451
451
452 OUTPUT::
452 OUTPUT::
453
453
454 id : <id_given_in_input>
454 id : <id_given_in_input>
455 result : None if group not exist
455 result : None if group not exist
456 {
456 {
457 "users_group_id" : "<id>",
457 "users_group_id" : "<id>",
458 "group_name" : "<groupname>",
458 "group_name" : "<groupname>",
459 "active": "<bool>",
459 "active": "<bool>",
460 "members" : [
460 "members" : [
461 {
461 {
462 "user_id" : "<user_id>",
462 "user_id" : "<user_id>",
463 "username" : "<username>",
463 "username" : "<username>",
464 "firstname": "<firstname>",
464 "firstname": "<firstname>",
465 "lastname" : "<lastname>",
465 "lastname" : "<lastname>",
466 "email" : "<email>",
466 "email" : "<email>",
467 "emails": "<list_of_all_additional_emails>",
467 "emails": "<list_of_all_additional_emails>",
468 "active" : "<bool>",
468 "active" : "<bool>",
469 "admin" :Β  "<bool>",
469 "admin" :Β  "<bool>",
470 "ldap_dn" : "<ldap_dn>",
470 "ldap_dn" : "<ldap_dn>",
471 "last_login": "<last_login>",
471 "last_login": "<last_login>",
472 },
472 },
473 …
473 …
474 ]
474 ]
475 }
475 }
476 error : null
476 error : null
477
477
478
478
479 get_users_groups
479 get_users_groups
480 ----------------
480 ----------------
481
481
482 Lists all existing users groups. This command can be executed only using
482 Lists all existing users groups. This command can be executed only using
483 api_key belonging to user with admin rights.
483 api_key belonging to user with admin rights.
484
484
485
485
486 INPUT::
486 INPUT::
487
487
488 id : <id_for_response>
488 id : <id_for_response>
489 api_key : "<api_key>"
489 api_key : "<api_key>"
490 method : "get_users_groups"
490 method : "get_users_groups"
491 args : { }
491 args : { }
492
492
493 OUTPUT::
493 OUTPUT::
494
494
495 id : <id_given_in_input>
495 id : <id_given_in_input>
496 result : [
496 result : [
497 {
497 {
498 "users_group_id" : "<id>",
498 "users_group_id" : "<id>",
499 "group_name" : "<groupname>",
499 "group_name" : "<groupname>",
500 "active": "<bool>",
500 "active": "<bool>",
501 },
501 },
502 …
502 …
503 ]
503 ]
504 error : null
504 error : null
505
505
506
506
507 create_users_group
507 create_users_group
508 ------------------
508 ------------------
509
509
510 Creates new users group. This command can be executed only using api_key
510 Creates new users group. This command can be executed only using api_key
511 belonging to user with admin rights
511 belonging to user with admin rights
512
512
513
513
514 INPUT::
514 INPUT::
515
515
516 id : <id_for_response>
516 id : <id_for_response>
517 api_key : "<api_key>"
517 api_key : "<api_key>"
518 method : "create_users_group"
518 method : "create_users_group"
519 args: {
519 args: {
520 "group_name": "<groupname>",
520 "group_name": "<groupname>",
521 "active":"<bool> = Optional(True)"
521 "active":"<bool> = Optional(True)"
522 }
522 }
523
523
524 OUTPUT::
524 OUTPUT::
525
525
526 id : <id_given_in_input>
526 id : <id_given_in_input>
527 result: {
527 result: {
528 "msg": "created new users group `<groupname>`",
528 "msg": "created new users group `<groupname>`",
529 "users_group": {
529 "users_group": {
530 "users_group_id" : "<id>",
530 "users_group_id" : "<id>",
531 "group_name" : "<groupname>",
531 "group_name" : "<groupname>",
532 "active": "<bool>",
532 "active": "<bool>",
533 },
533 },
534 }
534 }
535 error: null
535 error: null
536
536
537
537
538 add_user_to_users_group
538 add_user_to_users_group
539 -----------------------
539 -----------------------
540
540
541 Adds a user to a users group. If user exists in that group success will be
541 Adds a user to a users group. If user exists in that group success will be
542 `false`. This command can be executed only using api_key
542 `false`. This command can be executed only using api_key
543 belonging to user with admin rights
543 belonging to user with admin rights
544
544
545
545
546 INPUT::
546 INPUT::
547
547
548 id : <id_for_response>
548 id : <id_for_response>
549 api_key : "<api_key>"
549 api_key : "<api_key>"
550 method : "add_user_users_group"
550 method : "add_user_users_group"
551 args: {
551 args: {
552 "usersgroupid" : "<users group id or name>",
552 "usersgroupid" : "<users group id or name>",
553 "userid" : "<user_id or username>",
553 "userid" : "<user_id or username>",
554 }
554 }
555
555
556 OUTPUT::
556 OUTPUT::
557
557
558 id : <id_given_in_input>
558 id : <id_given_in_input>
559 result: {
559 result: {
560 "success": True|False # depends on if member is in group
560 "success": True|False # depends on if member is in group
561 "msg": "added member `<username>` to users group `<groupname>` |
561 "msg": "added member `<username>` to users group `<groupname>` |
562 User is already in that group"
562 User is already in that group"
563 }
563 }
564 error: null
564 error: null
565
565
566
566
567 remove_user_from_users_group
567 remove_user_from_users_group
568 ----------------------------
568 ----------------------------
569
569
570 Removes a user from a users group. If user is not in given group success will
570 Removes a user from a users group. If user is not in given group success will
571 be `false`. This command can be executed only
571 be `false`. This command can be executed only
572 using api_key belonging to user with admin rights
572 using api_key belonging to user with admin rights
573
573
574
574
575 INPUT::
575 INPUT::
576
576
577 id : <id_for_response>
577 id : <id_for_response>
578 api_key : "<api_key>"
578 api_key : "<api_key>"
579 method : "remove_user_from_users_group"
579 method : "remove_user_from_users_group"
580 args: {
580 args: {
581 "usersgroupid" : "<users group id or name>",
581 "usersgroupid" : "<users group id or name>",
582 "userid" : "<user_id or username>",
582 "userid" : "<user_id or username>",
583 }
583 }
584
584
585 OUTPUT::
585 OUTPUT::
586
586
587 id : <id_given_in_input>
587 id : <id_given_in_input>
588 result: {
588 result: {
589 "success": True|False, # depends on if member is in group
589 "success": True|False, # depends on if member is in group
590 "msg": "removed member <username> from users group <groupname> |
590 "msg": "removed member <username> from users group <groupname> |
591 User wasn't in group"
591 User wasn't in group"
592 }
592 }
593 error: null
593 error: null
594
594
595
595
596 get_repo
596 get_repo
597 --------
597 --------
598
598
599 Gets an existing repository by it's name or repository_id. Members will return
599 Gets an existing repository by it's name or repository_id. Members will return
600 either users_group or user associated to that repository. This command can be
600 either users_group or user associated to that repository. This command can be
601 executed only using api_key belonging to user with admin
601 executed only using api_key belonging to user with admin
602 rights or regular user that have at least read access to repository.
602 rights or regular user that have at least read access to repository.
603
603
604
604
605 INPUT::
605 INPUT::
606
606
607 id : <id_for_response>
607 id : <id_for_response>
608 api_key : "<api_key>"
608 api_key : "<api_key>"
609 method : "get_repo"
609 method : "get_repo"
610 args: {
610 args: {
611 "repoid" : "<reponame or repo_id>"
611 "repoid" : "<reponame or repo_id>"
612 }
612 }
613
613
614 OUTPUT::
614 OUTPUT::
615
615
616 id : <id_given_in_input>
616 id : <id_given_in_input>
617 result: None if repository does not exist or
617 result: None if repository does not exist or
618 {
618 {
619 "repo_id" : "<repo_id>",
619 "repo_id" : "<repo_id>",
620 "repo_name" : "<reponame>"
620 "repo_name" : "<reponame>"
621 "repo_type" : "<repo_type>",
621 "repo_type" : "<repo_type>",
622 "clone_uri" : "<clone_uri>",
622 "clone_uri" : "<clone_uri>",
623 "enable_downloads": "<bool>",
623 "enable_downloads": "<bool>",
624 "enable_locking": "<bool>",
624 "enable_locking": "<bool>",
625 "enable_statistics": "<bool>",
625 "enable_statistics": "<bool>",
626 "private": "<bool>",
626 "private": "<bool>",
627 "created_on" : "<date_time_created>",
627 "created_on" : "<date_time_created>",
628 "description" : "<description>",
628 "description" : "<description>",
629 "landing_rev": "<landing_rev>",
629 "landing_rev": "<landing_rev>",
630 "last_changeset": {
630 "last_changeset": {
631 "author": "<full_author>",
631 "author": "<full_author>",
632 "date": "<date_time_of_commit>",
632 "date": "<date_time_of_commit>",
633 "message": "<commit_message>",
633 "message": "<commit_message>",
634 "raw_id": "<raw_id>",
634 "raw_id": "<raw_id>",
635 "revision": "<numeric_revision>",
635 "revision": "<numeric_revision>",
636 "short_id": "<short_id>"
636 "short_id": "<short_id>"
637 }
637 }
638 "owner": "<repo_owner>",
638 "owner": "<repo_owner>",
639 "fork_of": "<name_of_fork_parent>",
639 "fork_of": "<name_of_fork_parent>",
640 "members" : [
640 "members" : [
641 {
641 {
642 "type": "user",
642 "type": "user",
643 "user_id" : "<user_id>",
643 "user_id" : "<user_id>",
644 "username" : "<username>",
644 "username" : "<username>",
645 "firstname": "<firstname>",
645 "firstname": "<firstname>",
646 "lastname" : "<lastname>",
646 "lastname" : "<lastname>",
647 "email" : "<email>",
647 "email" : "<email>",
648 "emails": "<list_of_all_additional_emails>",
648 "emails": "<list_of_all_additional_emails>",
649 "active" : "<bool>",
649 "active" : "<bool>",
650 "admin" :Β  "<bool>",
650 "admin" :Β  "<bool>",
651 "ldap_dn" : "<ldap_dn>",
651 "ldap_dn" : "<ldap_dn>",
652 "last_login": "<last_login>",
652 "last_login": "<last_login>",
653 "permission" : "repository.(read|write|admin)"
653 "permission" : "repository.(read|write|admin)"
654 },
654 },
655 …
655 …
656 {
656 {
657 "type": "users_group",
657 "type": "users_group",
658 "id" : "<usersgroupid>",
658 "id" : "<usersgroupid>",
659 "name" : "<usersgroupname>",
659 "name" : "<usersgroupname>",
660 "active": "<bool>",
660 "active": "<bool>",
661 "permission" : "repository.(read|write|admin)"
661 "permission" : "repository.(read|write|admin)"
662 },
662 },
663 …
663 …
664 ]
664 ]
665 "followers": [
665 "followers": [
666 {
666 {
667 "user_id" : "<user_id>",
667 "user_id" : "<user_id>",
668 "username" : "<username>",
668 "username" : "<username>",
669 "firstname": "<firstname>",
669 "firstname": "<firstname>",
670 "lastname" : "<lastname>",
670 "lastname" : "<lastname>",
671 "email" : "<email>",
671 "email" : "<email>",
672 "emails": "<list_of_all_additional_emails>",
672 "emails": "<list_of_all_additional_emails>",
673 "ip_addresses": "<list_of_ip_addresses_for_user>",
673 "ip_addresses": "<list_of_ip_addresses_for_user>",
674 "active" : "<bool>",
674 "active" : "<bool>",
675 "admin" :Β  "<bool>",
675 "admin" :Β  "<bool>",
676 "ldap_dn" : "<ldap_dn>",
676 "ldap_dn" : "<ldap_dn>",
677 "last_login": "<last_login>",
677 "last_login": "<last_login>",
678 },
678 },
679 …
679 …
680 ]
680 ]
681 }
681 }
682 error: null
682 error: null
683
683
684
684
685 get_repos
685 get_repos
686 ---------
686 ---------
687
687
688 Lists all existing repositories. This command can be executed only using
688 Lists all existing repositories. This command can be executed only using
689 api_key belonging to user with admin rights or regular user that have
689 api_key belonging to user with admin rights or regular user that have
690 admin, write or read access to repository.
690 admin, write or read access to repository.
691
691
692
692
693 INPUT::
693 INPUT::
694
694
695 id : <id_for_response>
695 id : <id_for_response>
696 api_key : "<api_key>"
696 api_key : "<api_key>"
697 method : "get_repos"
697 method : "get_repos"
698 args: { }
698 args: { }
699
699
700 OUTPUT::
700 OUTPUT::
701
701
702 id : <id_given_in_input>
702 id : <id_given_in_input>
703 result: [
703 result: [
704 {
704 {
705 "repo_id" : "<repo_id>",
705 "repo_id" : "<repo_id>",
706 "repo_name" : "<reponame>"
706 "repo_name" : "<reponame>"
707 "repo_type" : "<repo_type>",
707 "repo_type" : "<repo_type>",
708 "clone_uri" : "<clone_uri>",
708 "clone_uri" : "<clone_uri>",
709 "private": : "<bool>",
709 "private": : "<bool>",
710 "created_on" : "<datetimecreated>",
710 "created_on" : "<datetimecreated>",
711 "description" : "<description>",
711 "description" : "<description>",
712 "landing_rev": "<landing_rev>",
712 "landing_rev": "<landing_rev>",
713 "owner": "<repo_owner>",
713 "owner": "<repo_owner>",
714 "fork_of": "<name_of_fork_parent>",
714 "fork_of": "<name_of_fork_parent>",
715 "enable_downloads": "<bool>",
715 "enable_downloads": "<bool>",
716 "enable_locking": "<bool>",
716 "enable_locking": "<bool>",
717 "enable_statistics": "<bool>",
717 "enable_statistics": "<bool>",
718 },
718 },
719 …
719 …
720 ]
720 ]
721 error: null
721 error: null
722
722
723
723
724 get_repo_nodes
724 get_repo_nodes
725 --------------
725 --------------
726
726
727 returns a list of nodes and it's children in a flat list for a given path
727 returns a list of nodes and it's children in a flat list for a given path
728 at given revision. It's possible to specify ret_type to show only `files` or
728 at given revision. It's possible to specify ret_type to show only `files` or
729 `dirs`. This command can be executed only using api_key belonging to user
729 `dirs`. This command can be executed only using api_key belonging to user
730 with admin rights
730 with admin rights
731
731
732
732
733 INPUT::
733 INPUT::
734
734
735 id : <id_for_response>
735 id : <id_for_response>
736 api_key : "<api_key>"
736 api_key : "<api_key>"
737 method : "get_repo_nodes"
737 method : "get_repo_nodes"
738 args: {
738 args: {
739 "repoid" : "<reponame or repo_id>"
739 "repoid" : "<reponame or repo_id>"
740 "revision" : "<revision>",
740 "revision" : "<revision>",
741 "root_path" : "<root_path>",
741 "root_path" : "<root_path>",
742 "ret_type" : "<ret_type> = Optional('all')"
742 "ret_type" : "<ret_type> = Optional('all')"
743 }
743 }
744
744
745 OUTPUT::
745 OUTPUT::
746
746
747 id : <id_given_in_input>
747 id : <id_given_in_input>
748 result: [
748 result: [
749 {
749 {
750 "name" : "<name>"
750 "name" : "<name>"
751 "type" : "<type>",
751 "type" : "<type>",
752 },
752 },
753 …
753 …
754 ]
754 ]
755 error: null
755 error: null
756
756
757
757
758 create_repo
758 create_repo
759 -----------
759 -----------
760
760
761 Creates a repository. If repository name contains "/", all needed repository
761 Creates a repository. If repository name contains "/", all needed repository
762 groups will be created. For example "foo/bar/baz" will create groups
762 groups will be created. For example "foo/bar/baz" will create groups
763 "foo", "bar" (with "foo" as parent), and create "baz" repository with
763 "foo", "bar" (with "foo" as parent), and create "baz" repository with
764 "bar" as group. This command can be executed only using api_key belonging to user with admin
764 "bar" as group. This command can be executed only using api_key belonging to user with admin
765 rights or regular user that have create repository permission. Regular users
765 rights or regular user that have create repository permission. Regular users
766 cannot specify owner parameter
766 cannot specify owner parameter
767
767
768
768
769 INPUT::
769 INPUT::
770
770
771 id : <id_for_response>
771 id : <id_for_response>
772 api_key : "<api_key>"
772 api_key : "<api_key>"
773 method : "create_repo"
773 method : "create_repo"
774 args: {
774 args: {
775 "repo_name" : "<reponame>",
775 "repo_name" : "<reponame>",
776 "owner" : "<onwer_name_or_id = Optional(=apiuser)>",
776 "owner" : "<onwer_name_or_id = Optional(=apiuser)>",
777 "repo_type" : "<repo_type> = Optional('hg')",
777 "repo_type" : "<repo_type> = Optional('hg')",
778 "description" : "<description> = Optional('')",
778 "description" : "<description> = Optional('')",
779 "private" : "<bool> = Optional(False)",
779 "private" : "<bool> = Optional(False)",
780 "clone_uri" : "<clone_uri> = Optional(None)",
780 "clone_uri" : "<clone_uri> = Optional(None)",
781 "landing_rev" : "<landing_rev> = Optional('tip')",
781 "landing_rev" : "<landing_rev> = Optional('tip')",
782 "enable_downloads": "<bool> = Optional(False)",
782 "enable_downloads": "<bool> = Optional(False)",
783 "enable_locking": "<bool> = Optional(False)",
783 "enable_locking": "<bool> = Optional(False)",
784 "enable_statistics": "<bool> = Optional(False)",
784 "enable_statistics": "<bool> = Optional(False)",
785 }
785 }
786
786
787 OUTPUT::
787 OUTPUT::
788
788
789 id : <id_given_in_input>
789 id : <id_given_in_input>
790 result: {
790 result: {
791 "msg": "Created new repository `<reponame>`",
791 "msg": "Created new repository `<reponame>`",
792 "repo": {
792 "repo": {
793 "repo_id" : "<repo_id>",
793 "repo_id" : "<repo_id>",
794 "repo_name" : "<reponame>"
794 "repo_name" : "<reponame>"
795 "repo_type" : "<repo_type>",
795 "repo_type" : "<repo_type>",
796 "clone_uri" : "<clone_uri>",
796 "clone_uri" : "<clone_uri>",
797 "private": : "<bool>",
797 "private": : "<bool>",
798 "created_on" : "<datetimecreated>",
798 "created_on" : "<datetimecreated>",
799 "description" : "<description>",
799 "description" : "<description>",
800 "landing_rev": "<landing_rev>",
800 "landing_rev": "<landing_rev>",
801 "owner": "<username or user_id>",
801 "owner": "<username or user_id>",
802 "fork_of": "<name_of_fork_parent>",
802 "fork_of": "<name_of_fork_parent>",
803 "enable_downloads": "<bool>",
803 "enable_downloads": "<bool>",
804 "enable_locking": "<bool>",
804 "enable_locking": "<bool>",
805 "enable_statistics": "<bool>",
805 "enable_statistics": "<bool>",
806 },
806 },
807 }
807 }
808 error: null
808 error: null
809
809
810
810
811 fork_repo
811 fork_repo
812 ---------
812 ---------
813
813
814 Creates a fork of given repo. In case of using celery this will
814 Creates a fork of given repo. In case of using celery this will
815 immidiatelly return success message, while fork is going to be created
815 immidiatelly return success message, while fork is going to be created
816 asynchronous. This command can be executed only using api_key belonging to
816 asynchronous. This command can be executed only using api_key belonging to
817 user with admin rights or regular user that have fork permission, and at least
817 user with admin rights or regular user that have fork permission, and at least
818 read access to forking repository. Regular users cannot specify owner parameter.
818 read access to forking repository. Regular users cannot specify owner parameter.
819
819
820
820
821 INPUT::
821 INPUT::
822
822
823 id : <id_for_response>
823 id : <id_for_response>
824 api_key : "<api_key>"
824 api_key : "<api_key>"
825 method : "fork_repo"
825 method : "fork_repo"
826 args: {
826 args: {
827 "repoid" : "<reponame or repo_id>",
827 "repoid" : "<reponame or repo_id>",
828 "fork_name": "<forkname>",
828 "fork_name": "<forkname>",
829 "owner": "<username or user_id = Optional(=apiuser)>",
829 "owner": "<username or user_id = Optional(=apiuser)>",
830 "description": "<description>",
830 "description": "<description>",
831 "copy_permissions": "<bool>",
831 "copy_permissions": "<bool>",
832 "private": "<bool>",
832 "private": "<bool>",
833 "landing_rev": "<landing_rev>"
833 "landing_rev": "<landing_rev>"
834
834
835 }
835 }
836
836
837 OUTPUT::
837 OUTPUT::
838
838
839 id : <id_given_in_input>
839 id : <id_given_in_input>
840 result: {
840 result: {
841 "msg": "Created fork of `<reponame>` as `<forkname>`",
841 "msg": "Created fork of `<reponame>` as `<forkname>`",
842 "success": true
842 "success": true
843 }
843 }
844 error: null
844 error: null
845
845
846
846
847 delete_repo
847 delete_repo
848 -----------
848 -----------
849
849
850 Deletes a repository. This command can be executed only using api_key belonging to user with admin
850 Deletes a repository. This command can be executed only using api_key belonging to user with admin
851 rights or regular user that have admin access to repository.
851 rights or regular user that have admin access to repository.
852
852
853
853
854 INPUT::
854 INPUT::
855
855
856 id : <id_for_response>
856 id : <id_for_response>
857 api_key : "<api_key>"
857 api_key : "<api_key>"
858 method : "delete_repo"
858 method : "delete_repo"
859 args: {
859 args: {
860 "repoid" : "<reponame or repo_id>"
860 "repoid" : "<reponame or repo_id>"
861 }
861 }
862
862
863 OUTPUT::
863 OUTPUT::
864
864
865 id : <id_given_in_input>
865 id : <id_given_in_input>
866 result: {
866 result: {
867 "msg": "Deleted repository `<reponame>`",
867 "msg": "Deleted repository `<reponame>`",
868 "success": true
868 "success": true
869 }
869 }
870 error: null
870 error: null
871
871
872
872
873 grant_user_permission
873 grant_user_permission
874 ---------------------
874 ---------------------
875
875
876 Grant permission for user on given repository, or update existing one
876 Grant permission for user on given repository, or update existing one
877 if found. This command can be executed only using api_key belonging to user
877 if found. This command can be executed only using api_key belonging to user
878 with admin rights.
878 with admin rights.
879
879
880
880
881 INPUT::
881 INPUT::
882
882
883 id : <id_for_response>
883 id : <id_for_response>
884 api_key : "<api_key>"
884 api_key : "<api_key>"
885 method : "grant_user_permission"
885 method : "grant_user_permission"
886 args: {
886 args: {
887 "repoid" : "<reponame or repo_id>"
887 "repoid" : "<reponame or repo_id>"
888 "userid" : "<username or user_id>"
888 "userid" : "<username or user_id>"
889 "perm" : "(repository.(none|read|write|admin))",
889 "perm" : "(repository.(none|read|write|admin))",
890 }
890 }
891
891
892 OUTPUT::
892 OUTPUT::
893
893
894 id : <id_given_in_input>
894 id : <id_given_in_input>
895 result: {
895 result: {
896 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
896 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
897 "success": true
897 "success": true
898 }
898 }
899 error: null
899 error: null
900
900
901
901
902 revoke_user_permission
902 revoke_user_permission
903 ----------------------
903 ----------------------
904
904
905 Revoke permission for user on given repository. This command can be executed
905 Revoke permission for user on given repository. This command can be executed
906 only using api_key belonging to user with admin rights.
906 only using api_key belonging to user with admin rights.
907
907
908
908
909 INPUT::
909 INPUT::
910
910
911 id : <id_for_response>
911 id : <id_for_response>
912 api_key : "<api_key>"
912 api_key : "<api_key>"
913 method : "revoke_user_permission"
913 method : "revoke_user_permission"
914 args: {
914 args: {
915 "repoid" : "<reponame or repo_id>"
915 "repoid" : "<reponame or repo_id>"
916 "userid" : "<username or user_id>"
916 "userid" : "<username or user_id>"
917 }
917 }
918
918
919 OUTPUT::
919 OUTPUT::
920
920
921 id : <id_given_in_input>
921 id : <id_given_in_input>
922 result: {
922 result: {
923 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
923 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
924 "success": true
924 "success": true
925 }
925 }
926 error: null
926 error: null
927
927
928
928
929 grant_users_group_permission
929 grant_users_group_permission
930 ----------------------------
930 ----------------------------
931
931
932 Grant permission for users group on given repository, or update
932 Grant permission for users group on given repository, or update
933 existing one if found. This command can be executed only using
933 existing one if found. This command can be executed only using
934 api_key belonging to user with admin rights.
934 api_key belonging to user with admin rights.
935
935
936
936
937 INPUT::
937 INPUT::
938
938
939 id : <id_for_response>
939 id : <id_for_response>
940 api_key : "<api_key>"
940 api_key : "<api_key>"
941 method : "grant_users_group_permission"
941 method : "grant_users_group_permission"
942 args: {
942 args: {
943 "repoid" : "<reponame or repo_id>"
943 "repoid" : "<reponame or repo_id>"
944 "usersgroupid" : "<users group id or name>"
944 "usersgroupid" : "<users group id or name>"
945 "perm" : "(repository.(none|read|write|admin))",
945 "perm" : "(repository.(none|read|write|admin))",
946 }
946 }
947
947
948 OUTPUT::
948 OUTPUT::
949
949
950 id : <id_given_in_input>
950 id : <id_given_in_input>
951 result: {
951 result: {
952 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
952 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
953 "success": true
953 "success": true
954 }
954 }
955 error: null
955 error: null
956
956
957
957
958 revoke_users_group_permission
958 revoke_users_group_permission
959 -----------------------------
959 -----------------------------
960
960
961 Revoke permission for users group on given repository.This command can be
961 Revoke permission for users group on given repository.This command can be
962 executed only using api_key belonging to user with admin rights.
962 executed only using api_key belonging to user with admin rights.
963
963
964 INPUT::
964 INPUT::
965
965
966 id : <id_for_response>
966 id : <id_for_response>
967 api_key : "<api_key>"
967 api_key : "<api_key>"
968 method : "revoke_users_group_permission"
968 method : "revoke_users_group_permission"
969 args: {
969 args: {
970 "repoid" : "<reponame or repo_id>"
970 "repoid" : "<reponame or repo_id>"
971 "usersgroupid" : "<users group id or name>"
971 "usersgroupid" : "<users group id or name>"
972 }
972 }
973
973
974 OUTPUT::
974 OUTPUT::
975
975
976 id : <id_given_in_input>
976 id : <id_given_in_input>
977 result: {
977 result: {
978 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
978 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
979 "success": true
979 "success": true
980 }
980 }
981 error: null
981 error: null
@@ -1,254 +1,254 b''
1 .. _installation_win:
1 .. _installation_win:
2
2
3
3
4 Step by step Installation for Windows
4 Step by step Installation for Windows
5 =====================================
5 =====================================
6
6
7
7
8 RhodeCode step-by-step install Guide for Windows
8 RhodeCode step-by-step install Guide for Windows
9
9
10 Target OS: Windows XP SP3 32bit English (Clean installation)
10 Target OS: Windows XP SP3 32bit English (Clean installation)
11 + All Windows Updates until 24-may-2012
11 + All Windows Updates until 24-may-2012
12
12
13 .. note::
13 .. note::
14
14
15 This installation is for 32bit systems, for 64bit windows you might need
15 This installation is for 32bit systems, for 64bit windows you might need
16 to download proper 64bit version of "Windows Installer" and Win32py
16 to download proper 64bit version of "Windows Installer" and Win32py
17 extensions
17 extensions
18
18
19 Step1 - Install Visual Studio 2008 Express
19 Step1 - Install Visual Studio 2008 Express
20 ------------------------------------------
20 ------------------------------------------
21
21
22
22
23 Optional: You can also install MingW, but VS2008 installation is easier
23 Optional: You can also install MingW, but VS2008 installation is easier
24
24
25 Download "Visual C++ 2008 Express Edition with SP1" from:
25 Download "Visual C++ 2008 Express Edition with SP1" from:
26 http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express
26 http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express
27 (if not found or relocated, google for "visual studio 2008 express" for
27 (if not found or relocated, google for "visual studio 2008 express" for
28 updated link)
28 updated link)
29
29
30 You can also download full ISO file for offline installation, just
30 You can also download full ISO file for offline installation, just
31 choose "All - Offline Install ISO image file" in the previous page and
31 choose "All - Offline Install ISO image file" in the previous page and
32 choose "Visual C++ 2008 Express" when installing.
32 choose "Visual C++ 2008 Express" when installing.
33
33
34 .. note::
34 .. note::
35
35
36 Using other versions of Visual Studio will lead to random crashes.
36 Using other versions of Visual Studio will lead to random crashes.
37 You must use Visual Studio 2008!"
37 You must use Visual Studio 2008!"
38
38
39 .. note::
39 .. note::
40
40
41 Silverlight Runtime and SQL Server 2008 Express Edition are not
41 Silverlight Runtime and SQL Server 2008 Express Edition are not
42 required, you can uncheck them
42 required, you can uncheck them
43
43
44
44
45 Step2 - Install Python
45 Step2 - Install Python
46 ----------------------
46 ----------------------
47
47
48 Install Python 2.x.y (x >= 5) x86 version (32bit). DO NOT USE A 3.x version.
48 Install Python 2.x.y (x >= 5) x86 version (32bit). DO NOT USE A 3.x version.
49 Download Python 2.x.y from:
49 Download Python 2.x.y from:
50 http://www.python.org/download/
50 http://www.python.org/download/
51
51
52 Choose "Windows Installer" (32bit version) not "Windows X86-64
52 Choose "Windows Installer" (32bit version) not "Windows X86-64
53 Installer". While writing this guide, the latest version was v2.7.3.
53 Installer". While writing this guide, the latest version was v2.7.3.
54 Remember the specific major and minor version installed, because it will
54 Remember the specific major and minor version installed, because it will
55 be needed in the next step. In this case, it is "2.7".
55 be needed in the next step. In this case, it is "2.7".
56
56
57
57
58 Step3 - Install Win32py extensions
58 Step3 - Install Win32py extensions
59 ----------------------------------
59 ----------------------------------
60
60
61 Download pywin32 from:
61 Download pywin32 from:
62 http://sourceforge.net/projects/pywin32/files/
62 http://sourceforge.net/projects/pywin32/files/
63
63
64 - Click on "pywin32" folder
64 - Click on "pywin32" folder
65 - Click on the first folder (in this case, Build 217, maybe newer when you try)
65 - Click on the first folder (in this case, Build 217, maybe newer when you try)
66 - Choose the file ending with ".win32-py2.x.exe" -> x being the minor
66 - Choose the file ending with ".win32-py2.x.exe" -> x being the minor
67 version of Python you installed (in this case, 7)
67 version of Python you installed (in this case, 7)
68 When writing this guide, the file was:
68 When writing this guide, the file was:
69 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download
69 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download
70
70
71
71
72 Step4 - Python BIN
72 Step4 - Python BIN
73 ------------------
73 ------------------
74
74
75 Add Python BIN folder to the path
75 Add Python BIN folder to the path
76
76
77 You have to add the Python folder to the path, you can do it manually
77 You have to add the Python folder to the path, you can do it manually
78 (editing "PATH" environment variable) or using Windows Support Tools
78 (editing "PATH" environment variable) or using Windows Support Tools
79 that came preinstalled in Vista/7 and can be installed in Windows XP.
79 that came preinstalled in Vista/7 and can be installed in Windows XP.
80
80
81 - Using support tools on WINDOWS XP:
81 - Using support tools on WINDOWS XP:
82 If you use Windows XP you can install them using Windows XP CD and
82 If you use Windows XP you can install them using Windows XP CD and
83 navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI).
83 navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI).
84 Afterwards, open a CMD and type::
84 Afterwards, open a CMD and type::
85
85
86 SETX PATH "%PATH%;[your-python-path]" -M
86 SETX PATH "%PATH%;[your-python-path]" -M
87
87
88 Close CMD (the path variable will be updated then)
88 Close CMD (the path variable will be updated then)
89
89
90 - Using support tools on WINDOWS Vista/7:
90 - Using support tools on WINDOWS Vista/7:
91
91
92 Open a CMD and type::
92 Open a CMD and type::
93
93
94 SETX PATH "%PATH%;[your-python-path]" /M
94 SETX PATH "%PATH%;[your-python-path]" /M
95
95
96 Please substitute [your-python-path] with your Python installation path.
96 Please substitute [your-python-path] with your Python installation path.
97 Typically: C:\\Python27
97 Typically: C:\\Python27
98
98
99
99
100 Step5 - RhodeCode folder structure
100 Step5 - RhodeCode folder structure
101 ----------------------------------
101 ----------------------------------
102
102
103 Create a RhodeCode folder structure
103 Create a RhodeCode folder structure
104
104
105 This is only a example to install RhodeCode, you can of course change
105 This is only a example to install RhodeCode, you can of course change
106 it. However, this guide will follow the proposed structure, so please
106 it. However, this guide will follow the proposed structure, so please
107 later adapt the paths if you change them. My recommendation is to use
107 later adapt the paths if you change them. My recommendation is to use
108 folders with NO SPACES. But you can try if you are brave...
108 folders with NO SPACES. But you can try if you are brave...
109
109
110 Create the following folder structure::
110 Create the following folder structure::
111
111
112 C:\RhodeCode
112 C:\RhodeCode
113 C:\RhodeCode\Bin
113 C:\RhodeCode\Bin
114 C:\RhodeCode\Env
114 C:\RhodeCode\Env
115 C:\RhodeCode\Repos
115 C:\RhodeCode\Repos
116
116
117
117
118 Step6 - Install virtualenv
118 Step6 - Install virtualenv
119 ---------------------------
119 ---------------------------
120
120
121 Install Virtual Env for Python
121 Install Virtual Env for Python
122
122
123 Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
123 Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
124 Right click on "virtualenv.py" file and choose "Save link as...".
124 Right click on "virtualenv.py" file and choose "Save link as...".
125 Download to C:\\RhodeCode (or whatever you want)
125 Download to C:\\RhodeCode (or whatever you want)
126 (the file is located at
126 (the file is located at
127 https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
127 https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
128
128
129 Create a virtual Python environment in C:\\RhodeCode\\Env (or similar). To
129 Create a virtual Python environment in C:\\RhodeCode\\Env (or similar). To
130 do so, open a CMD (Python Path should be included in Step3), navigate
130 do so, open a CMD (Python Path should be included in Step3), navigate
131 where you downloaded "virtualenv.py", and write::
131 where you downloaded "virtualenv.py", and write::
132
132
133 python virtualenv.py C:\RhodeCode\Env
133 python virtualenv.py C:\RhodeCode\Env
134
134
135 (--no-site-packages is now the default behaviour of virtualenv, no need
135 (--no-site-packages is now the default behaviour of virtualenv, no need
136 to include it)
136 to include it)
137
137
138
138
139 Step7 - Install RhodeCode
139 Step7 - Install RhodeCode
140 -------------------------
140 -------------------------
141
141
142 Finally, install RhodeCode
142 Finally, install RhodeCode
143
143
144 Close previously opened command prompt/s, and open a Visual Studio 2008
144 Close previously opened command prompt/s, and open a Visual Studio 2008
145 Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
145 Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
146 "Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
146 "Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
147 "Visual Studio 2008 Command Prompt"
147 "Visual Studio 2008 Command Prompt"
148
148
149 In that CMD (loaded with VS2008 PATHs) type::
149 In that CMD (loaded with VS2008 PATHs) type::
150
150
151 cd C:\RhodeCode\Env\Scripts (or similar)
151 cd C:\RhodeCode\Env\Scripts (or similar)
152 activate
152 activate
153
153
154 The prompt will change into "(Env) C:\\RhodeCode\\Env\\Scripts" or similar
154 The prompt will change into "(Env) C:\\RhodeCode\\Env\\Scripts" or similar
155 (depending of your folder structure). Then type::
155 (depending of your folder structure). Then type::
156
156
157 pip install rhodecode
157 pip install rhodecode
158
158
159 (long step, please wait until fully complete)
159 (long step, please wait until fully complete)
160
160
161 Some warnings will appear, don't worry as they are normal.
161 Some warnings will appear, don't worry as they are normal.
162
162
163
163
164 Step8 - Configuring RhodeCode
164 Step8 - Configuring RhodeCode
165 -----------------------------
165 -----------------------------
166
166
167
167
168 steps taken from http://packages.python.org/RhodeCode/setup.html
168 steps taken from http://packages.python.org/RhodeCode/setup.html
169
169
170 You have to use the same Visual Studio 2008 command prompt as Step7, so
170 You have to use the same Visual Studio 2008 command prompt as Step7, so
171 if you closed it reopen it following the same commands (including the
171 if you closed it reopen it following the same commands (including the
172 "activate" one). When ready, just type::
172 "activate" one). When ready, just type::
173
173
174 cd C:\RhodeCode\Bin
174 cd C:\RhodeCode\Bin
175 paster make-config RhodeCode production.ini
175 paster make-config RhodeCode production.ini
176
176
177 Then, you must edit production.ini to fit your needs (ip address, ip
177 Then, you must edit production.ini to fit your needs (ip address, ip
178 port, mail settings, database, whatever). I recommend using NotePad++
178 port, mail settings, database, whatever). I recommend using NotePad++
179 (free) or similar text editor, as it handles well the EndOfLine
179 (free) or similar text editor, as it handles well the EndOfLine
180 character differences between Unix and Windows
180 character differences between Unix and Windows
181 (http://notepad-plus-plus.org/)
181 (http://notepad-plus-plus.org/)
182
182
183 For the sake of simplicity lets run it with the default settings. After
183 For the sake of simplicity lets run it with the default settings. After
184 your edits (if any), in the previous Command Prompt, type::
184 your edits (if any), in the previous Command Prompt, type::
185
185
186 paster setup-rhodecode production.ini
186 paster setup-rhodecode production.ini
187
187
188 (this time a NEW database will be installed, you must follow a different
188 (this time a NEW database will be installed, you must follow a different
189 step to later UPGRADE to a newer RhodeCode version)
189 step to later UPGRADE to a newer RhodeCode version)
190
190
191 The script will ask you for confirmation about creating a NEW database,
191 The script will ask you for confirmation about creating a NEW database,
192 answer yes (y)
192 answer yes (y)
193 The script will ask you for repository path, answer C:\\RhodeCode\\Repos
193 The script will ask you for repository path, answer C:\\RhodeCode\\Repos
194 (or similar)
194 (or similar)
195 The script will ask you for admin username and password, answer "admin"
195 The script will ask you for admin username and password, answer "admin"
196 + "123456" (or whatever you want)
196 + "123456" (or whatever you want)
197 The script will ask you for admin mail, answer "admin@xxxx.com" (or
197 The script will ask you for admin mail, answer "admin@xxxx.com" (or
198 whatever you want)
198 whatever you want)
199
199
200 If you make some mistake and the script does not end, don't worry, start
200 If you make some mistake and the script does not end, don't worry, start
201 it again.
201 it again.
202
202
203
203
204 Step9 - Running RhodeCode
204 Step9 - Running RhodeCode
205 -------------------------
205 -------------------------
206
206
207
207
208 In the previous command prompt, being in the C:\\RhodeCode\\Bin folder,
208 In the previous command prompt, being in the C:\\RhodeCode\\Bin folder,
209 just type::
209 just type::
210
210
211 paster serve production.ini
211 paster serve production.ini
212
212
213 Open yout web server, and go to http://127.0.0.1:5000
213 Open yout web server, and go to http://127.0.0.1:5000
214
214
215 It works!! :-)
215 It works!! :-)
216
216
217 Remark:
217 Remark:
218 If it does not work first time, just Ctrl-C the CMD process and start it
218 If it does not work first time, just Ctrl-C the CMD process and start it
219 again. Don't forget the "http://" in Internet Explorer
219 again. Don't forget the "http://" in Internet Explorer
220
220
221
221
222
222
223 What this Guide does not cover:
223 What this Guide does not cover:
224
224
225 - Installing Celery
225 - Installing Celery
226 - Running RhodeCode as Windows Service. You can investigate here:
226 - Running RhodeCode as Windows Service. You can investigate here:
227
227
228 - http://pypi.python.org/pypi/wsgisvc
228 - http://pypi.python.org/pypi/wsgisvc
229 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
229 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
230 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
230 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
231
231
232 - Using Apache. You can investigate here:
232 - Using Apache. You can investigate here:
233
233
234 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
234 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
235
235
236
236
237 Upgrading
237 Upgrading
238 =========
238 =========
239
239
240 Stop running RhodeCode
240 Stop running RhodeCode
241 Open a CommandPrompt like in Step7 (VS2008 path + activate) and type::
241 Open a CommandPrompt like in Step7 (VS2008 path + activate) and type::
242
242
243 easy_install -U rhodecode
243 easy_install -U rhodecode
244 cd \RhodeCode\Bin
244 cd \RhodeCode\Bin
245
245
246 { backup your production.ini file now} ::
246 { backup your production.ini file now} ::
247
247
248 paster make-config RhodeCode production.ini
248 paster make-config RhodeCode production.ini
249
249
250 (check changes and update your production.ini accordingly) ::
250 (check changes and update your production.ini accordingly) ::
251
251
252 paster upgrade-db production.ini (update database)
252 paster upgrade-db production.ini (update database)
253
253
254 Full steps in http://packages.python.org/RhodeCode/upgrade.html
254 Full steps in http://packages.python.org/RhodeCode/upgrade.html
@@ -1,735 +1,735 b''
1 .. _setup:
1 .. _setup:
2
2
3 =====
3 =====
4 Setup
4 Setup
5 =====
5 =====
6
6
7
7
8 Setting up RhodeCode
8 Setting up RhodeCode
9 --------------------
9 --------------------
10
10
11 First, you will need to create a RhodeCode configuration file. Run the
11 First, you will need to create a RhodeCode configuration file. Run the
12 following command to do this::
12 following command to do this::
13
13
14 paster make-config RhodeCode production.ini
14 paster make-config RhodeCode production.ini
15
15
16 - This will create the file `production.ini` in the current directory. This
16 - This will create the file `production.ini` in the current directory. This
17 configuration file contains the various settings for RhodeCode, e.g proxy
17 configuration file contains the various settings for RhodeCode, e.g proxy
18 port, email settings, usage of static files, cache, celery settings and
18 port, email settings, usage of static files, cache, celery settings and
19 logging.
19 logging.
20
20
21
21
22 Next, you need to create the databases used by RhodeCode. I recommend that you
22 Next, you need to create the databases used by RhodeCode. I recommend that you
23 use postgresql or sqlite (default). If you choose a database other than the
23 use postgresql or sqlite (default). If you choose a database other than the
24 default ensure you properly adjust the db url in your production.ini
24 default ensure you properly adjust the db url in your production.ini
25 configuration file to use this other database. RhodeCode currently supports
25 configuration file to use this other database. RhodeCode currently supports
26 postgresql, sqlite and mysql databases. Create the database by running
26 postgresql, sqlite and mysql databases. Create the database by running
27 the following command::
27 the following command::
28
28
29 paster setup-rhodecode production.ini
29 paster setup-rhodecode production.ini
30
30
31 This will prompt you for a "root" path. This "root" path is the location where
31 This will prompt you for a "root" path. This "root" path is the location where
32 RhodeCode will store all of its repositories on the current machine. After
32 RhodeCode will store all of its repositories on the current machine. After
33 entering this "root" path ``setup-rhodecode`` will also prompt you for a username
33 entering this "root" path ``setup-rhodecode`` will also prompt you for a username
34 and password for the initial admin account which ``setup-rhodecode`` sets
34 and password for the initial admin account which ``setup-rhodecode`` sets
35 up for you.
35 up for you.
36
36
37 setup process can be fully automated, example for lazy::
37 setup process can be fully automated, example for lazy::
38
38
39 paster setup-rhodecode production.ini --user=marcink --password=secret --email=marcin@rhodecode.org --repos=/home/marcink/my_repos
39 paster setup-rhodecode production.ini --user=marcink --password=secret --email=marcin@rhodecode.org --repos=/home/marcink/my_repos
40
40
41
41
42 - The ``setup-rhodecode`` command will create all of the needed tables and an
42 - The ``setup-rhodecode`` command will create all of the needed tables and an
43 admin account. When choosing a root path you can either use a new empty
43 admin account. When choosing a root path you can either use a new empty
44 location, or a location which already contains existing repositories. If you
44 location, or a location which already contains existing repositories. If you
45 choose a location which contains existing repositories RhodeCode will simply
45 choose a location which contains existing repositories RhodeCode will simply
46 add all of the repositories at the chosen location to it's database.
46 add all of the repositories at the chosen location to it's database.
47 (Note: make sure you specify the correct path to the root).
47 (Note: make sure you specify the correct path to the root).
48 - Note: the given path for mercurial_ repositories **must** be write accessible
48 - Note: the given path for mercurial_ repositories **must** be write accessible
49 for the application. It's very important since the RhodeCode web interface
49 for the application. It's very important since the RhodeCode web interface
50 will work without write access, but when trying to do a push it will
50 will work without write access, but when trying to do a push it will
51 eventually fail with permission denied errors unless it has write access.
51 eventually fail with permission denied errors unless it has write access.
52
52
53 You are now ready to use RhodeCode, to run it simply execute::
53 You are now ready to use RhodeCode, to run it simply execute::
54
54
55 paster serve production.ini
55 paster serve production.ini
56
56
57 - This command runs the RhodeCode server. The web app should be available at the
57 - This command runs the RhodeCode server. The web app should be available at the
58 127.0.0.1:5000. This ip and port is configurable via the production.ini
58 127.0.0.1:5000. This ip and port is configurable via the production.ini
59 file created in previous step
59 file created in previous step
60 - Use the admin account you created above when running ``setup-rhodecode``
60 - Use the admin account you created above when running ``setup-rhodecode``
61 to login to the web app.
61 to login to the web app.
62 - The default permissions on each repository is read, and the owner is admin.
62 - The default permissions on each repository is read, and the owner is admin.
63 Remember to update these if needed.
63 Remember to update these if needed.
64 - In the admin panel you can toggle ldap, anonymous, permissions settings. As
64 - In the admin panel you can toggle ldap, anonymous, permissions settings. As
65 well as edit more advanced options on users and repositories
65 well as edit more advanced options on users and repositories
66
66
67 Optionally users can create `rcextensions` package that extends RhodeCode
67 Optionally users can create `rcextensions` package that extends RhodeCode
68 functionality. To do this simply execute::
68 functionality. To do this simply execute::
69
69
70 paster make-rcext production.ini
70 paster make-rcext production.ini
71
71
72 This will create `rcextensions` package in the same place that your `ini` file
72 This will create `rcextensions` package in the same place that your `ini` file
73 lives. With `rcextensions` it's possible to add additional mapping for whoosh,
73 lives. With `rcextensions` it's possible to add additional mapping for whoosh,
74 stats and add additional code into the push/pull/create/delete repo hooks.
74 stats and add additional code into the push/pull/create/delete repo hooks.
75 For example for sending signals to build-bots such as jenkins.
75 For example for sending signals to build-bots such as jenkins.
76 Please see the `__init__.py` file inside `rcextensions` package
76 Please see the `__init__.py` file inside `rcextensions` package
77 for more details.
77 for more details.
78
78
79
79
80 Using RhodeCode with SSH
80 Using RhodeCode with SSH
81 ------------------------
81 ------------------------
82
82
83 RhodeCode currently only hosts repositories using http and https. (The addition
83 RhodeCode currently only hosts repositories using http and https. (The addition
84 of ssh hosting is a planned future feature.) However you can easily use ssh in
84 of ssh hosting is a planned future feature.) However you can easily use ssh in
85 parallel with RhodeCode. (Repository access via ssh is a standard "out of
85 parallel with RhodeCode. (Repository access via ssh is a standard "out of
86 the box" feature of mercurial_ and you can use this to access any of the
86 the box" feature of mercurial_ and you can use this to access any of the
87 repositories that RhodeCode is hosting. See PublishingRepositories_)
87 repositories that RhodeCode is hosting. See PublishingRepositories_)
88
88
89 RhodeCode repository structures are kept in directories with the same name
89 RhodeCode repository structures are kept in directories with the same name
90 as the project. When using repository groups, each group is a subdirectory.
90 as the project. When using repository groups, each group is a subdirectory.
91 This allows you to easily use ssh for accessing repositories.
91 This allows you to easily use ssh for accessing repositories.
92
92
93 In order to use ssh you need to make sure that your web-server and the users
93 In order to use ssh you need to make sure that your web-server and the users
94 login accounts have the correct permissions set on the appropriate directories.
94 login accounts have the correct permissions set on the appropriate directories.
95 (Note that these permissions are independent of any permissions you have set up
95 (Note that these permissions are independent of any permissions you have set up
96 using the RhodeCode web interface.)
96 using the RhodeCode web interface.)
97
97
98 If your main directory (the same as set in RhodeCode settings) is for example
98 If your main directory (the same as set in RhodeCode settings) is for example
99 set to **/home/hg** and the repository you are using is named `rhodecode`, then
99 set to **/home/hg** and the repository you are using is named `rhodecode`, then
100 to clone via ssh you should run::
100 to clone via ssh you should run::
101
101
102 hg clone ssh://user@server.com/home/hg/rhodecode
102 hg clone ssh://user@server.com/home/hg/rhodecode
103
103
104 Using other external tools such as mercurial-server_ or using ssh key based
104 Using other external tools such as mercurial-server_ or using ssh key based
105 authentication is fully supported.
105 authentication is fully supported.
106
106
107 Note: In an advanced setup, in order for your ssh access to use the same
107 Note: In an advanced setup, in order for your ssh access to use the same
108 permissions as set up via the RhodeCode web interface, you can create an
108 permissions as set up via the RhodeCode web interface, you can create an
109 authentication hook to connect to the rhodecode db and runs check functions for
109 authentication hook to connect to the rhodecode db and runs check functions for
110 permissions against that.
110 permissions against that.
111
111
112 Setting up Whoosh full text search
112 Setting up Whoosh full text search
113 ----------------------------------
113 ----------------------------------
114
114
115 Starting from version 1.1 the whoosh index can be build by using the paster
115 Starting from version 1.1 the whoosh index can be build by using the paster
116 command ``make-index``. To use ``make-index`` you must specify the configuration
116 command ``make-index``. To use ``make-index`` you must specify the configuration
117 file that stores the location of the index. You may specify the location of the
117 file that stores the location of the index. You may specify the location of the
118 repositories (`--repo-location`). If not specified, this value is retrieved
118 repositories (`--repo-location`). If not specified, this value is retrieved
119 from the RhodeCode database. This was required prior to 1.2. Starting from
119 from the RhodeCode database. This was required prior to 1.2. Starting from
120 version 1.2 it is also possible to specify a comma separated list of
120 version 1.2 it is also possible to specify a comma separated list of
121 repositories (`--index-only`) to build index only on chooses repositories
121 repositories (`--index-only`) to build index only on chooses repositories
122 skipping any other found in repos location
122 skipping any other found in repos location
123
123
124 You may optionally pass the option `-f` to enable a full index rebuild. Without
124 You may optionally pass the option `-f` to enable a full index rebuild. Without
125 the `-f` option, indexing will run always in "incremental" mode.
125 the `-f` option, indexing will run always in "incremental" mode.
126
126
127 For an incremental index build use::
127 For an incremental index build use::
128
128
129 paster make-index production.ini
129 paster make-index production.ini
130
130
131 For a full index rebuild use::
131 For a full index rebuild use::
132
132
133 paster make-index production.ini -f
133 paster make-index production.ini -f
134
134
135
135
136 building index just for chosen repositories is possible with such command::
136 building index just for chosen repositories is possible with such command::
137
137
138 paster make-index production.ini --index-only=vcs,rhodecode
138 paster make-index production.ini --index-only=vcs,rhodecode
139
139
140
140
141 In order to do periodical index builds and keep your index always up to date.
141 In order to do periodical index builds and keep your index always up to date.
142 It's recommended to do a crontab entry for incremental indexing.
142 It's recommended to do a crontab entry for incremental indexing.
143 An example entry might look like this::
143 An example entry might look like this::
144
144
145 /path/to/python/bin/paster make-index /path/to/rhodecode/production.ini
145 /path/to/python/bin/paster make-index /path/to/rhodecode/production.ini
146
146
147 When using incremental mode (the default) whoosh will check the last
147 When using incremental mode (the default) whoosh will check the last
148 modification date of each file and add it to be reindexed if a newer file is
148 modification date of each file and add it to be reindexed if a newer file is
149 available. The indexing daemon checks for any removed files and removes them
149 available. The indexing daemon checks for any removed files and removes them
150 from index.
150 from index.
151
151
152 If you want to rebuild index from scratch, you can use the `-f` flag as above,
152 If you want to rebuild index from scratch, you can use the `-f` flag as above,
153 or in the admin panel you can check `build from scratch` flag.
153 or in the admin panel you can check `build from scratch` flag.
154
154
155
155
156 Setting up LDAP support
156 Setting up LDAP support
157 -----------------------
157 -----------------------
158
158
159 RhodeCode starting from version 1.1 supports ldap authentication. In order
159 RhodeCode starting from version 1.1 supports ldap authentication. In order
160 to use LDAP, you have to install the python-ldap_ package. This package is
160 to use LDAP, you have to install the python-ldap_ package. This package is
161 available via pypi, so you can install it by running
161 available via pypi, so you can install it by running
162
162
163 using easy_install::
163 using easy_install::
164
164
165 easy_install python-ldap
165 easy_install python-ldap
166
166
167 using pip::
167 using pip::
168
168
169 pip install python-ldap
169 pip install python-ldap
170
170
171 .. note::
171 .. note::
172 python-ldap requires some certain libs on your system, so before installing
172 python-ldap requires some certain libs on your system, so before installing
173 it check that you have at least `openldap`, and `sasl` libraries.
173 it check that you have at least `openldap`, and `sasl` libraries.
174
174
175 LDAP settings are located in admin->ldap section,
175 LDAP settings are located in admin->ldap section,
176
176
177 Here's a typical ldap setup::
177 Here's a typical ldap setup::
178
178
179 Connection settings
179 Connection settings
180 Enable LDAP = checked
180 Enable LDAP = checked
181 Host = host.example.org
181 Host = host.example.org
182 Port = 389
182 Port = 389
183 Account = <account>
183 Account = <account>
184 Password = <password>
184 Password = <password>
185 Connection Security = LDAPS connection
185 Connection Security = LDAPS connection
186 Certificate Checks = DEMAND
186 Certificate Checks = DEMAND
187
187
188 Search settings
188 Search settings
189 Base DN = CN=users,DC=host,DC=example,DC=org
189 Base DN = CN=users,DC=host,DC=example,DC=org
190 LDAP Filter = (&(objectClass=user)(!(objectClass=computer)))
190 LDAP Filter = (&(objectClass=user)(!(objectClass=computer)))
191 LDAP Search Scope = SUBTREE
191 LDAP Search Scope = SUBTREE
192
192
193 Attribute mappings
193 Attribute mappings
194 Login Attribute = uid
194 Login Attribute = uid
195 First Name Attribute = firstName
195 First Name Attribute = firstName
196 Last Name Attribute = lastName
196 Last Name Attribute = lastName
197 E-mail Attribute = mail
197 E-mail Attribute = mail
198
198
199 .. _enable_ldap:
199 .. _enable_ldap:
200
200
201 Enable LDAP : required
201 Enable LDAP : required
202 Whether to use LDAP for authenticating users.
202 Whether to use LDAP for authenticating users.
203
203
204 .. _ldap_host:
204 .. _ldap_host:
205
205
206 Host : required
206 Host : required
207 LDAP server hostname or IP address. Can be also a comma separated
207 LDAP server hostname or IP address. Can be also a comma separated
208 list of servers to support LDAP fail-over.
208 list of servers to support LDAP fail-over.
209
209
210 .. _Port:
210 .. _Port:
211
211
212 Port : required
212 Port : required
213 389 for un-encrypted LDAP, 636 for SSL-encrypted LDAP.
213 389 for un-encrypted LDAP, 636 for SSL-encrypted LDAP.
214
214
215 .. _ldap_account:
215 .. _ldap_account:
216
216
217 Account : optional
217 Account : optional
218 Only required if the LDAP server does not allow anonymous browsing of
218 Only required if the LDAP server does not allow anonymous browsing of
219 records. This should be a special account for record browsing. This
219 records. This should be a special account for record browsing. This
220 will require `LDAP Password`_ below.
220 will require `LDAP Password`_ below.
221
221
222 .. _LDAP Password:
222 .. _LDAP Password:
223
223
224 Password : optional
224 Password : optional
225 Only required if the LDAP server does not allow anonymous browsing of
225 Only required if the LDAP server does not allow anonymous browsing of
226 records.
226 records.
227
227
228 .. _Enable LDAPS:
228 .. _Enable LDAPS:
229
229
230 Connection Security : required
230 Connection Security : required
231 Defines the connection to LDAP server
231 Defines the connection to LDAP server
232
232
233 No encryption
233 No encryption
234 Plain non encrypted connection
234 Plain non encrypted connection
235
235
236 LDAPS connection
236 LDAPS connection
237 Enable ldaps connection. It will likely require `Port`_ to be set to
237 Enable ldaps connection. It will likely require `Port`_ to be set to
238 a different value (standard LDAPS port is 636). When LDAPS is enabled
238 a different value (standard LDAPS port is 636). When LDAPS is enabled
239 then `Certificate Checks`_ is required.
239 then `Certificate Checks`_ is required.
240
240
241 START_TLS on LDAP connection
241 START_TLS on LDAP connection
242 START TLS connection
242 START TLS connection
243
243
244 .. _Certificate Checks:
244 .. _Certificate Checks:
245
245
246 Certificate Checks : optional
246 Certificate Checks : optional
247 How SSL certificates verification is handled - this is only useful when
247 How SSL certificates verification is handled - this is only useful when
248 `Enable LDAPS`_ is enabled. Only DEMAND or HARD offer full SSL security
248 `Enable LDAPS`_ is enabled. Only DEMAND or HARD offer full SSL security
249 while the other options are susceptible to man-in-the-middle attacks. SSL
249 while the other options are susceptible to man-in-the-middle attacks. SSL
250 certificates can be installed to /etc/openldap/cacerts so that the
250 certificates can be installed to /etc/openldap/cacerts so that the
251 DEMAND or HARD options can be used with self-signed certificates or
251 DEMAND or HARD options can be used with self-signed certificates or
252 certificates that do not have traceable certificates of authority.
252 certificates that do not have traceable certificates of authority.
253
253
254 NEVER
254 NEVER
255 A serve certificate will never be requested or checked.
255 A serve certificate will never be requested or checked.
256
256
257 ALLOW
257 ALLOW
258 A server certificate is requested. Failure to provide a
258 A server certificate is requested. Failure to provide a
259 certificate or providing a bad certificate will not terminate the
259 certificate or providing a bad certificate will not terminate the
260 session.
260 session.
261
261
262 TRY
262 TRY
263 A server certificate is requested. Failure to provide a
263 A server certificate is requested. Failure to provide a
264 certificate does not halt the session; providing a bad certificate
264 certificate does not halt the session; providing a bad certificate
265 halts the session.
265 halts the session.
266
266
267 DEMAND
267 DEMAND
268 A server certificate is requested and must be provided and
268 A server certificate is requested and must be provided and
269 authenticated for the session to proceed.
269 authenticated for the session to proceed.
270
270
271 HARD
271 HARD
272 The same as DEMAND.
272 The same as DEMAND.
273
273
274 .. _Base DN:
274 .. _Base DN:
275
275
276 Base DN : required
276 Base DN : required
277 The Distinguished Name (DN) where searches for users will be performed.
277 The Distinguished Name (DN) where searches for users will be performed.
278 Searches can be controlled by `LDAP Filter`_ and `LDAP Search Scope`_.
278 Searches can be controlled by `LDAP Filter`_ and `LDAP Search Scope`_.
279
279
280 .. _LDAP Filter:
280 .. _LDAP Filter:
281
281
282 LDAP Filter : optional
282 LDAP Filter : optional
283 A LDAP filter defined by RFC 2254. This is more useful when `LDAP
283 A LDAP filter defined by RFC 2254. This is more useful when `LDAP
284 Search Scope`_ is set to SUBTREE. The filter is useful for limiting
284 Search Scope`_ is set to SUBTREE. The filter is useful for limiting
285 which LDAP objects are identified as representing Users for
285 which LDAP objects are identified as representing Users for
286 authentication. The filter is augmented by `Login Attribute`_ below.
286 authentication. The filter is augmented by `Login Attribute`_ below.
287 This can commonly be left blank.
287 This can commonly be left blank.
288
288
289 .. _LDAP Search Scope:
289 .. _LDAP Search Scope:
290
290
291 LDAP Search Scope : required
291 LDAP Search Scope : required
292 This limits how far LDAP will search for a matching object.
292 This limits how far LDAP will search for a matching object.
293
293
294 BASE
294 BASE
295 Only allows searching of `Base DN`_ and is usually not what you
295 Only allows searching of `Base DN`_ and is usually not what you
296 want.
296 want.
297
297
298 ONELEVEL
298 ONELEVEL
299 Searches all entries under `Base DN`_, but not Base DN itself.
299 Searches all entries under `Base DN`_, but not Base DN itself.
300
300
301 SUBTREE
301 SUBTREE
302 Searches all entries below `Base DN`_, but not Base DN itself.
302 Searches all entries below `Base DN`_, but not Base DN itself.
303 When using SUBTREE `LDAP Filter`_ is useful to limit object
303 When using SUBTREE `LDAP Filter`_ is useful to limit object
304 location.
304 location.
305
305
306 .. _Login Attribute:
306 .. _Login Attribute:
307
307
308 Login Attribute : required
308 Login Attribute : required
309 The LDAP record attribute that will be matched as the USERNAME or
309 The LDAP record attribute that will be matched as the USERNAME or
310 ACCOUNT used to connect to RhodeCode. This will be added to `LDAP
310 ACCOUNT used to connect to RhodeCode. This will be added to `LDAP
311 Filter`_ for locating the User object. If `LDAP Filter`_ is specified as
311 Filter`_ for locating the User object. If `LDAP Filter`_ is specified as
312 "LDAPFILTER", `Login Attribute`_ is specified as "uid" and the user has
312 "LDAPFILTER", `Login Attribute`_ is specified as "uid" and the user has
313 connected as "jsmith" then the `LDAP Filter`_ will be augmented as below
313 connected as "jsmith" then the `LDAP Filter`_ will be augmented as below
314 ::
314 ::
315
315
316 (&(LDAPFILTER)(uid=jsmith))
316 (&(LDAPFILTER)(uid=jsmith))
317
317
318 .. _ldap_attr_firstname:
318 .. _ldap_attr_firstname:
319
319
320 First Name Attribute : required
320 First Name Attribute : required
321 The LDAP record attribute which represents the user's first name.
321 The LDAP record attribute which represents the user's first name.
322
322
323 .. _ldap_attr_lastname:
323 .. _ldap_attr_lastname:
324
324
325 Last Name Attribute : required
325 Last Name Attribute : required
326 The LDAP record attribute which represents the user's last name.
326 The LDAP record attribute which represents the user's last name.
327
327
328 .. _ldap_attr_email:
328 .. _ldap_attr_email:
329
329
330 Email Attribute : required
330 Email Attribute : required
331 The LDAP record attribute which represents the user's email address.
331 The LDAP record attribute which represents the user's email address.
332
332
333 If all data are entered correctly, and python-ldap_ is properly installed
333 If all data are entered correctly, and python-ldap_ is properly installed
334 users should be granted access to RhodeCode with ldap accounts. At this
334 users should be granted access to RhodeCode with ldap accounts. At this
335 time user information is copied from LDAP into the RhodeCode user database.
335 time user information is copied from LDAP into the RhodeCode user database.
336 This means that updates of an LDAP user object may not be reflected as a
336 This means that updates of an LDAP user object may not be reflected as a
337 user update in RhodeCode.
337 user update in RhodeCode.
338
338
339 If You have problems with LDAP access and believe You entered correct
339 If You have problems with LDAP access and believe You entered correct
340 information check out the RhodeCode logs, any error messages sent from LDAP
340 information check out the RhodeCode logs, any error messages sent from LDAP
341 will be saved there.
341 will be saved there.
342
342
343 Active Directory
343 Active Directory
344 ''''''''''''''''
344 ''''''''''''''''
345
345
346 RhodeCode can use Microsoft Active Directory for user authentication. This
346 RhodeCode can use Microsoft Active Directory for user authentication. This
347 is done through an LDAP or LDAPS connection to Active Directory. The
347 is done through an LDAP or LDAPS connection to Active Directory. The
348 following LDAP configuration settings are typical for using Active
348 following LDAP configuration settings are typical for using Active
349 Directory ::
349 Directory ::
350
350
351 Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local
351 Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local
352 Login Attribute = sAMAccountName
352 Login Attribute = sAMAccountName
353 First Name Attribute = givenName
353 First Name Attribute = givenName
354 Last Name Attribute = sn
354 Last Name Attribute = sn
355 E-mail Attribute = mail
355 E-mail Attribute = mail
356
356
357 All other LDAP settings will likely be site-specific and should be
357 All other LDAP settings will likely be site-specific and should be
358 appropriately configured.
358 appropriately configured.
359
359
360
360
361 Authentication by container or reverse-proxy
361 Authentication by container or reverse-proxy
362 --------------------------------------------
362 --------------------------------------------
363
363
364 Starting with version 1.3, RhodeCode supports delegating the authentication
364 Starting with version 1.3, RhodeCode supports delegating the authentication
365 of users to its WSGI container, or to a reverse-proxy server through which all
365 of users to its WSGI container, or to a reverse-proxy server through which all
366 clients access the application.
366 clients access the application.
367
367
368 When these authentication methods are enabled in RhodeCode, it uses the
368 When these authentication methods are enabled in RhodeCode, it uses the
369 username that the container/proxy (Apache/Nginx/etc) authenticated and doesn't
369 username that the container/proxy (Apache/Nginx/etc) authenticated and doesn't
370 perform the authentication itself. The authorization, however, is still done by
370 perform the authentication itself. The authorization, however, is still done by
371 RhodeCode according to its settings.
371 RhodeCode according to its settings.
372
372
373 When a user logs in for the first time using these authentication methods,
373 When a user logs in for the first time using these authentication methods,
374 a matching user account is created in RhodeCode with default permissions. An
374 a matching user account is created in RhodeCode with default permissions. An
375 administrator can then modify it using RhodeCode's admin interface.
375 administrator can then modify it using RhodeCode's admin interface.
376 It's also possible for an administrator to create accounts and configure their
376 It's also possible for an administrator to create accounts and configure their
377 permissions before the user logs in for the first time.
377 permissions before the user logs in for the first time.
378
378
379 Container-based authentication
379 Container-based authentication
380 ''''''''''''''''''''''''''''''
380 ''''''''''''''''''''''''''''''
381
381
382 In a container-based authentication setup, RhodeCode reads the user name from
382 In a container-based authentication setup, RhodeCode reads the user name from
383 the ``REMOTE_USER`` server variable provided by the WSGI container.
383 the ``REMOTE_USER`` server variable provided by the WSGI container.
384
384
385 After setting up your container (see `Apache's WSGI config`_), you'd need
385 After setting up your container (see `Apache's WSGI config`_), you'd need
386 to configure it to require authentication on the location configured for
386 to configure it to require authentication on the location configured for
387 RhodeCode.
387 RhodeCode.
388
388
389 In order for RhodeCode to start using the provided username, you should set the
389 In order for RhodeCode to start using the provided username, you should set the
390 following in the [app:main] section of your .ini file::
390 following in the [app:main] section of your .ini file::
391
391
392 container_auth_enabled = true
392 container_auth_enabled = true
393
393
394
394
395 Proxy pass-through authentication
395 Proxy pass-through authentication
396 '''''''''''''''''''''''''''''''''
396 '''''''''''''''''''''''''''''''''
397
397
398 In a proxy pass-through authentication setup, RhodeCode reads the user name
398 In a proxy pass-through authentication setup, RhodeCode reads the user name
399 from the ``X-Forwarded-User`` request header, which should be configured to be
399 from the ``X-Forwarded-User`` request header, which should be configured to be
400 sent by the reverse-proxy server.
400 sent by the reverse-proxy server.
401
401
402 After setting up your proxy solution (see `Apache virtual host reverse proxy example`_,
402 After setting up your proxy solution (see `Apache virtual host reverse proxy example`_,
403 `Apache as subdirectory`_ or `Nginx virtual host example`_), you'd need to
403 `Apache as subdirectory`_ or `Nginx virtual host example`_), you'd need to
404 configure the authentication and add the username in a request header named
404 configure the authentication and add the username in a request header named
405 ``X-Forwarded-User``.
405 ``X-Forwarded-User``.
406
406
407 For example, the following config section for Apache sets a subdirectory in a
407 For example, the following config section for Apache sets a subdirectory in a
408 reverse-proxy setup with basic auth::
408 reverse-proxy setup with basic auth::
409
409
410 <Location /<someprefix> >
410 <Location /<someprefix> >
411 ProxyPass http://127.0.0.1:5000/<someprefix>
411 ProxyPass http://127.0.0.1:5000/<someprefix>
412 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
412 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
413 SetEnvIf X-Url-Scheme https HTTPS=1
413 SetEnvIf X-Url-Scheme https HTTPS=1
414
414
415 AuthType Basic
415 AuthType Basic
416 AuthName "RhodeCode authentication"
416 AuthName "RhodeCode authentication"
417 AuthUserFile /home/web/rhodecode/.htpasswd
417 AuthUserFile /home/web/rhodecode/.htpasswd
418 require valid-user
418 require valid-user
419
419
420 RequestHeader unset X-Forwarded-User
420 RequestHeader unset X-Forwarded-User
421
421
422 RewriteEngine On
422 RewriteEngine On
423 RewriteCond %{LA-U:REMOTE_USER} (.+)
423 RewriteCond %{LA-U:REMOTE_USER} (.+)
424 RewriteRule .* - [E=RU:%1]
424 RewriteRule .* - [E=RU:%1]
425 RequestHeader set X-Forwarded-User %{RU}e
425 RequestHeader set X-Forwarded-User %{RU}e
426 </Location>
426 </Location>
427
427
428 In order for RhodeCode to start using the forwarded username, you should set
428 In order for RhodeCode to start using the forwarded username, you should set
429 the following in the [app:main] section of your .ini file::
429 the following in the [app:main] section of your .ini file::
430
430
431 proxypass_auth_enabled = true
431 proxypass_auth_enabled = true
432
432
433 .. note::
433 .. note::
434 If you enable proxy pass-through authentication, make sure your server is
434 If you enable proxy pass-through authentication, make sure your server is
435 only accessible through the proxy. Otherwise, any client would be able to
435 only accessible through the proxy. Otherwise, any client would be able to
436 forge the authentication header and could effectively become authenticated
436 forge the authentication header and could effectively become authenticated
437 using any account of their liking.
437 using any account of their liking.
438
438
439 Integration with Issue trackers
439 Integration with Issue trackers
440 -------------------------------
440 -------------------------------
441
441
442 RhodeCode provides a simple integration with issue trackers. It's possible
442 RhodeCode provides a simple integration with issue trackers. It's possible
443 to define a regular expression that will fetch issue id stored in commit
443 to define a regular expression that will fetch issue id stored in commit
444 messages and replace that with an url to this issue. To enable this simply
444 messages and replace that with an url to this issue. To enable this simply
445 uncomment following variables in the ini file::
445 uncomment following variables in the ini file::
446
446
447 url_pat = (?:^#|\s#)(\w+)
447 url_pat = (?:^#|\s#)(\w+)
448 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
448 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
449 issue_prefix = #
449 issue_prefix = #
450
450
451 `url_pat` is the regular expression that will fetch issues from commit messages.
451 `url_pat` is the regular expression that will fetch issues from commit messages.
452 Default regex will match issues in format of #<number> eg. #300.
452 Default regex will match issues in format of #<number> eg. #300.
453
453
454 Matched issues will be replace with the link specified as `issue_server_link`
454 Matched issues will be replace with the link specified as `issue_server_link`
455 {id} will be replaced with issue id, and {repo} with repository name.
455 {id} will be replaced with issue id, and {repo} with repository name.
456 Since the # is striped `issue_prefix` is added as a prefix to url.
456 Since the # is striped `issue_prefix` is added as a prefix to url.
457 `issue_prefix` can be something different than # if you pass
457 `issue_prefix` can be something different than # if you pass
458 ISSUE- as issue prefix this will generate an url in format::
458 ISSUE- as issue prefix this will generate an url in format::
459
459
460 <a href="https://myissueserver.com/example_repo/issue/300">ISSUE-300</a>
460 <a href="https://myissueserver.com/example_repo/issue/300">ISSUE-300</a>
461
461
462 Hook management
462 Hook management
463 ---------------
463 ---------------
464
464
465 Hooks can be managed in similar way to this used in .hgrc files.
465 Hooks can be managed in similar way to this used in .hgrc files.
466 To access hooks setting click `advanced setup` on Hooks section of Mercurial
466 To access hooks setting click `advanced setup` on Hooks section of Mercurial
467 Settings in Admin.
467 Settings in Admin.
468
468
469 There are 4 built in hooks that cannot be changed (only enable/disable by
469 There are 4 built in hooks that cannot be changed (only enable/disable by
470 checkboxes on previos section).
470 checkboxes on previos section).
471 To add another custom hook simply fill in first section with
471 To add another custom hook simply fill in first section with
472 <name>.<hook_type> and the second one with hook path. Example hooks
472 <name>.<hook_type> and the second one with hook path. Example hooks
473 can be found at *rhodecode.lib.hooks*.
473 can be found at *rhodecode.lib.hooks*.
474
474
475
475
476 Changing default encoding
476 Changing default encoding
477 -------------------------
477 -------------------------
478
478
479 By default RhodeCode uses utf8 encoding, starting from 1.3 series this
479 By default RhodeCode uses utf8 encoding, starting from 1.3 series this
480 can be changed, simply edit default_encoding in .ini file to desired one.
480 can be changed, simply edit default_encoding in .ini file to desired one.
481 This affects many parts in rhodecode including commiters names, filenames,
481 This affects many parts in rhodecode including commiters names, filenames,
482 encoding of commit messages. In addition RhodeCode can detect if `chardet`
482 encoding of commit messages. In addition RhodeCode can detect if `chardet`
483 library is installed. If `chardet` is detected RhodeCode will fallback to it
483 library is installed. If `chardet` is detected RhodeCode will fallback to it
484 when there are encode/decode errors.
484 when there are encode/decode errors.
485
485
486
486
487 Setting Up Celery
487 Setting Up Celery
488 -----------------
488 -----------------
489
489
490 Since version 1.1 celery is configured by the rhodecode ini configuration files.
490 Since version 1.1 celery is configured by the rhodecode ini configuration files.
491 Simply set use_celery=true in the ini file then add / change the configuration
491 Simply set use_celery=true in the ini file then add / change the configuration
492 variables inside the ini file.
492 variables inside the ini file.
493
493
494 Remember that the ini files use the format with '.' not with '_' like celery.
494 Remember that the ini files use the format with '.' not with '_' like celery.
495 So for example setting `BROKER_HOST` in celery means setting `broker.host` in
495 So for example setting `BROKER_HOST` in celery means setting `broker.host` in
496 the config file.
496 the config file.
497
497
498 In order to start using celery run::
498 In order to start using celery run::
499
499
500 paster celeryd <configfile.ini>
500 paster celeryd <configfile.ini>
501
501
502
502
503 .. note::
503 .. note::
504 Make sure you run this command from the same virtualenv, and with the same
504 Make sure you run this command from the same virtualenv, and with the same
505 user that rhodecode runs.
505 user that rhodecode runs.
506
506
507 HTTPS support
507 HTTPS support
508 -------------
508 -------------
509
509
510 There are two ways to enable https:
510 There are two ways to enable https:
511
511
512 - Set HTTP_X_URL_SCHEME in your http server headers, than rhodecode will
512 - Set HTTP_X_URL_SCHEME in your http server headers, than rhodecode will
513 recognize this headers and make proper https redirections
513 recognize this headers and make proper https redirections
514 - Alternatively, change the `force_https = true` flag in the ini configuration
514 - Alternatively, change the `force_https = true` flag in the ini configuration
515 to force using https, no headers are needed than to enable https
515 to force using https, no headers are needed than to enable https
516
516
517
517
518 Nginx virtual host example
518 Nginx virtual host example
519 --------------------------
519 --------------------------
520
520
521 Sample config for nginx using proxy::
521 Sample config for nginx using proxy::
522
522
523 upstream rc {
523 upstream rc {
524 server 127.0.0.1:5000;
524 server 127.0.0.1:5000;
525 # add more instances for load balancing
525 # add more instances for load balancing
526 #server 127.0.0.1:5001;
526 #server 127.0.0.1:5001;
527 #server 127.0.0.1:5002;
527 #server 127.0.0.1:5002;
528 }
528 }
529
529
530 server {
530 server {
531 listen 443;
531 listen 443;
532 server_name rhodecode.myserver.com;
532 server_name rhodecode.myserver.com;
533 access_log /var/log/nginx/rhodecode.access.log;
533 access_log /var/log/nginx/rhodecode.access.log;
534 error_log /var/log/nginx/rhodecode.error.log;
534 error_log /var/log/nginx/rhodecode.error.log;
535
535
536 ssl on;
536 ssl on;
537 ssl_certificate rhodecode.myserver.com.crt;
537 ssl_certificate rhodecode.myserver.com.crt;
538 ssl_certificate_key rhodecode.myserver.com.key;
538 ssl_certificate_key rhodecode.myserver.com.key;
539
539
540 ssl_session_timeout 5m;
540 ssl_session_timeout 5m;
541
541
542 ssl_protocols SSLv3 TLSv1;
542 ssl_protocols SSLv3 TLSv1;
543 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
543 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
544 ssl_prefer_server_ciphers on;
544 ssl_prefer_server_ciphers on;
545
545
546 # uncomment if you have nginx with chunking module compiled
546 # uncomment if you have nginx with chunking module compiled
547 # fixes the issues of having to put postBuffer data for large git
547 # fixes the issues of having to put postBuffer data for large git
548 # pushes
548 # pushes
549 #chunkin on;
549 #chunkin on;
550 #error_page 411 = @my_411_error;
550 #error_page 411 = @my_411_error;
551 #location @my_411_error {
551 #location @my_411_error {
552 # chunkin_resume;
552 # chunkin_resume;
553 #}
553 #}
554
554
555 # uncomment if you want to serve static files by nginx
555 # uncomment if you want to serve static files by nginx
556 #root /path/to/installation/rhodecode/public;
556 #root /path/to/installation/rhodecode/public;
557
557
558 location / {
558 location / {
559 try_files $uri @rhode;
559 try_files $uri @rhode;
560 }
560 }
561
561
562 location @rhode {
562 location @rhode {
563 proxy_pass http://rc;
563 proxy_pass http://rc;
564 include /etc/nginx/proxy.conf;
564 include /etc/nginx/proxy.conf;
565 }
565 }
566
566
567 }
567 }
568
568
569 Here's the proxy.conf. It's tuned so it will not timeout on long
569 Here's the proxy.conf. It's tuned so it will not timeout on long
570 pushes or large pushes::
570 pushes or large pushes::
571
571
572 proxy_redirect off;
572 proxy_redirect off;
573 proxy_set_header Host $host;
573 proxy_set_header Host $host;
574 proxy_set_header X-Url-Scheme $scheme;
574 proxy_set_header X-Url-Scheme $scheme;
575 proxy_set_header X-Host $http_host;
575 proxy_set_header X-Host $http_host;
576 proxy_set_header X-Real-IP $remote_addr;
576 proxy_set_header X-Real-IP $remote_addr;
577 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
577 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
578 proxy_set_header Proxy-host $proxy_host;
578 proxy_set_header Proxy-host $proxy_host;
579 client_max_body_size 400m;
579 client_max_body_size 400m;
580 client_body_buffer_size 128k;
580 client_body_buffer_size 128k;
581 proxy_buffering off;
581 proxy_buffering off;
582 proxy_connect_timeout 7200;
582 proxy_connect_timeout 7200;
583 proxy_send_timeout 7200;
583 proxy_send_timeout 7200;
584 proxy_read_timeout 7200;
584 proxy_read_timeout 7200;
585 proxy_buffers 8 32k;
585 proxy_buffers 8 32k;
586
586
587 Also, when using root path with nginx you might set the static files to false
587 Also, when using root path with nginx you might set the static files to false
588 in the production.ini file::
588 in the production.ini file::
589
589
590 [app:main]
590 [app:main]
591 use = egg:rhodecode
591 use = egg:rhodecode
592 full_stack = true
592 full_stack = true
593 static_files = false
593 static_files = false
594 lang=en
594 lang=en
595 cache_dir = %(here)s/data
595 cache_dir = %(here)s/data
596
596
597 In order to not have the statics served by the application. This improves speed.
597 In order to not have the statics served by the application. This improves speed.
598
598
599
599
600 Apache virtual host reverse proxy example
600 Apache virtual host reverse proxy example
601 -----------------------------------------
601 -----------------------------------------
602
602
603 Here is a sample configuration file for apache using proxy::
603 Here is a sample configuration file for apache using proxy::
604
604
605 <VirtualHost *:80>
605 <VirtualHost *:80>
606 ServerName hg.myserver.com
606 ServerName hg.myserver.com
607 ServerAlias hg.myserver.com
607 ServerAlias hg.myserver.com
608
608
609 <Proxy *>
609 <Proxy *>
610 Order allow,deny
610 Order allow,deny
611 Allow from all
611 Allow from all
612 </Proxy>
612 </Proxy>
613
613
614 #important !
614 #important !
615 #Directive to properly generate url (clone url) for pylons
615 #Directive to properly generate url (clone url) for pylons
616 ProxyPreserveHost On
616 ProxyPreserveHost On
617
617
618 #rhodecode instance
618 #rhodecode instance
619 ProxyPass / http://127.0.0.1:5000/
619 ProxyPass / http://127.0.0.1:5000/
620 ProxyPassReverse / http://127.0.0.1:5000/
620 ProxyPassReverse / http://127.0.0.1:5000/
621
621
622 #to enable https use line below
622 #to enable https use line below
623 #SetEnvIf X-Url-Scheme https HTTPS=1
623 #SetEnvIf X-Url-Scheme https HTTPS=1
624
624
625 </VirtualHost>
625 </VirtualHost>
626
626
627
627
628 Additional tutorial
628 Additional tutorial
629 http://wiki.pylonshq.com/display/pylonscookbook/Apache+as+a+reverse+proxy+for+Pylons
629 http://wiki.pylonshq.com/display/pylonscookbook/Apache+as+a+reverse+proxy+for+Pylons
630
630
631
631
632 Apache as subdirectory
632 Apache as subdirectory
633 ----------------------
633 ----------------------
634
634
635 Apache subdirectory part::
635 Apache subdirectory part::
636
636
637 <Location /<someprefix> >
637 <Location /<someprefix> >
638 ProxyPass http://127.0.0.1:5000/<someprefix>
638 ProxyPass http://127.0.0.1:5000/<someprefix>
639 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
639 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
640 SetEnvIf X-Url-Scheme https HTTPS=1
640 SetEnvIf X-Url-Scheme https HTTPS=1
641 </Location>
641 </Location>
642
642
643 Besides the regular apache setup you will need to add the following line
643 Besides the regular apache setup you will need to add the following line
644 into [app:main] section of your .ini file::
644 into [app:main] section of your .ini file::
645
645
646 filter-with = proxy-prefix
646 filter-with = proxy-prefix
647
647
648 Add the following at the end of the .ini file::
648 Add the following at the end of the .ini file::
649
649
650 [filter:proxy-prefix]
650 [filter:proxy-prefix]
651 use = egg:PasteDeploy#prefix
651 use = egg:PasteDeploy#prefix
652 prefix = /<someprefix>
652 prefix = /<someprefix>
653
653
654
654
655 then change <someprefix> into your choosen prefix
655 then change <someprefix> into your choosen prefix
656
656
657 Apache's WSGI config
657 Apache's WSGI config
658 --------------------
658 --------------------
659
659
660 Alternatively, RhodeCode can be set up with Apache under mod_wsgi. For
660 Alternatively, RhodeCode can be set up with Apache under mod_wsgi. For
661 that, you'll need to:
661 that, you'll need to:
662
662
663 - Install mod_wsgi. If using a Debian-based distro, you can install
663 - Install mod_wsgi. If using a Debian-based distro, you can install
664 the package libapache2-mod-wsgi::
664 the package libapache2-mod-wsgi::
665
665
666 aptitude install libapache2-mod-wsgi
666 aptitude install libapache2-mod-wsgi
667
667
668 - Enable mod_wsgi::
668 - Enable mod_wsgi::
669
669
670 a2enmod wsgi
670 a2enmod wsgi
671
671
672 - Create a wsgi dispatch script, like the one below. Make sure you
672 - Create a wsgi dispatch script, like the one below. Make sure you
673 check the paths correctly point to where you installed RhodeCode
673 check the paths correctly point to where you installed RhodeCode
674 and its Python Virtual Environment.
674 and its Python Virtual Environment.
675 - Enable the WSGIScriptAlias directive for the wsgi dispatch script,
675 - Enable the WSGIScriptAlias directive for the wsgi dispatch script,
676 as in the following example. Once again, check the paths are
676 as in the following example. Once again, check the paths are
677 correctly specified.
677 correctly specified.
678
678
679 Here is a sample excerpt from an Apache Virtual Host configuration file::
679 Here is a sample excerpt from an Apache Virtual Host configuration file::
680
680
681 WSGIDaemonProcess pylons \
681 WSGIDaemonProcess pylons \
682 threads=4 \
682 threads=4 \
683 python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages
683 python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages
684 WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi
684 WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi
685 WSGIPassAuthorization On
685 WSGIPassAuthorization On
686
686
687 .. note::
687 .. note::
688 when running apache as root please add: `user=www-data group=www-data`
688 when running apache as root please add: `user=www-data group=www-data`
689 into above configuration
689 into above configuration
690
690
691 .. note::
691 .. note::
692 RhodeCode cannot be runned in multiprocess mode in apache, make sure
692 RhodeCode cannot be runned in multiprocess mode in apache, make sure
693 you don't specify `processes=num` directive in the config
693 you don't specify `processes=num` directive in the config
694
694
695
695
696 Example wsgi dispatch script::
696 Example wsgi dispatch script::
697
697
698 import os
698 import os
699 os.environ["HGENCODING"] = "UTF-8"
699 os.environ["HGENCODING"] = "UTF-8"
700 os.environ['PYTHON_EGG_CACHE'] = '/home/web/rhodecode/.egg-cache'
700 os.environ['PYTHON_EGG_CACHE'] = '/home/web/rhodecode/.egg-cache'
701
701
702 # sometimes it's needed to set the curent dir
702 # sometimes it's needed to set the curent dir
703 os.chdir('/home/web/rhodecode/')
703 os.chdir('/home/web/rhodecode/')
704
704
705 import site
705 import site
706 site.addsitedir("/home/web/rhodecode/pyenv/lib/python2.6/site-packages")
706 site.addsitedir("/home/web/rhodecode/pyenv/lib/python2.6/site-packages")
707
707
708 from paste.deploy import loadapp
708 from paste.deploy import loadapp
709 from paste.script.util.logging_config import fileConfig
709 from paste.script.util.logging_config import fileConfig
710
710
711 fileConfig('/home/web/rhodecode/production.ini')
711 fileConfig('/home/web/rhodecode/production.ini')
712 application = loadapp('config:/home/web/rhodecode/production.ini')
712 application = loadapp('config:/home/web/rhodecode/production.ini')
713
713
714 Note: when using mod_wsgi you'll need to install the same version of
714 Note: when using mod_wsgi you'll need to install the same version of
715 Mercurial that's inside RhodeCode's virtualenv also on the system's Python
715 Mercurial that's inside RhodeCode's virtualenv also on the system's Python
716 environment.
716 environment.
717
717
718
718
719 Other configuration files
719 Other configuration files
720 -------------------------
720 -------------------------
721
721
722 Some example init.d scripts can be found in init.d directory::
722 Some example init.d scripts can be found in init.d directory::
723
723
724 https://secure.rhodecode.org/rhodecode/files/beta/init.d
724 https://secure.rhodecode.org/rhodecode/files/beta/init.d
725
725
726 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
726 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
727 .. _python: http://www.python.org/
727 .. _python: http://www.python.org/
728 .. _mercurial: http://mercurial.selenic.com/
728 .. _mercurial: http://mercurial.selenic.com/
729 .. _celery: http://celeryproject.org/
729 .. _celery: http://celeryproject.org/
730 .. _rabbitmq: http://www.rabbitmq.com/
730 .. _rabbitmq: http://www.rabbitmq.com/
731 .. _python-ldap: http://www.python-ldap.org/
731 .. _python-ldap: http://www.python-ldap.org/
732 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
732 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
733 .. _PublishingRepositories: http://mercurial.selenic.com/wiki/PublishingRepositories
733 .. _PublishingRepositories: http://mercurial.selenic.com/wiki/PublishingRepositories
734 .. _Issues tracker: https://bitbucket.org/marcinkuzminski/rhodecode/issues
734 .. _Issues tracker: https://bitbucket.org/marcinkuzminski/rhodecode/issues
735 .. _google group rhodecode: http://groups.google.com/group/rhodecode
735 .. _google group rhodecode: http://groups.google.com/group/rhodecode
@@ -1,606 +1,606 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import tempfile
29 import tempfile
30
30
31 from pylons import request, response, tmpl_context as c, url
31 from pylons import request, response, tmpl_context as c, url
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from rhodecode.lib.utils import jsonify
34 from rhodecode.lib.utils import jsonify
35
35
36 from rhodecode.lib import diffs
36 from rhodecode.lib import diffs
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38
38
39 from rhodecode.lib.compat import OrderedDict
39 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
40 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
41 str2bool
41 str2bool
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
43 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.base import BaseRepoController, render
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.conf import settings
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,\
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,\
49 NodeDoesNotExistError, ChangesetError, NodeError
49 NodeDoesNotExistError, ChangesetError, NodeError
50 from rhodecode.lib.vcs.nodes import FileNode
50 from rhodecode.lib.vcs.nodes import FileNode
51
51
52 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.repo import RepoModel
53 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.scm import ScmModel
54 from rhodecode.model.db import Repository
54 from rhodecode.model.db import Repository
55
55
56 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
56 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
57 _context_url, get_line_ctx, get_ignore_ws
57 _context_url, get_line_ctx, get_ignore_ws
58
58
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class FilesController(BaseRepoController):
63 class FilesController(BaseRepoController):
64
64
65 def __before__(self):
65 def __before__(self):
66 super(FilesController, self).__before__()
66 super(FilesController, self).__before__()
67 c.cut_off_limit = self.cut_off_limit
67 c.cut_off_limit = self.cut_off_limit
68
68
69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
70 """
70 """
71 Safe way to get changeset if error occur it redirects to tip with
71 Safe way to get changeset if error occur it redirects to tip with
72 proper message
72 proper message
73
73
74 :param rev: revision to fetch
74 :param rev: revision to fetch
75 :param repo_name: repo name to redirect after
75 :param repo_name: repo name to redirect after
76 """
76 """
77
77
78 try:
78 try:
79 return c.rhodecode_repo.get_changeset(rev)
79 return c.rhodecode_repo.get_changeset(rev)
80 except EmptyRepositoryError, e:
80 except EmptyRepositoryError, e:
81 if not redirect_after:
81 if not redirect_after:
82 return None
82 return None
83 url_ = url('files_add_home',
83 url_ = url('files_add_home',
84 repo_name=c.repo_name,
84 repo_name=c.repo_name,
85 revision=0, f_path='')
85 revision=0, f_path='')
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
87 h.flash(h.literal(_('There are no files yet %s') % add_new),
87 h.flash(h.literal(_('There are no files yet %s') % add_new),
88 category='warning')
88 category='warning')
89 redirect(h.url('summary_home', repo_name=repo_name))
89 redirect(h.url('summary_home', repo_name=repo_name))
90
90
91 except RepositoryError, e:
91 except RepositoryError, e:
92 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
94
94
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
96 """
96 """
97 Returns file_node, if error occurs or given path is directory,
97 Returns file_node, if error occurs or given path is directory,
98 it'll redirect to top level path
98 it'll redirect to top level path
99
99
100 :param repo_name: repo_name
100 :param repo_name: repo_name
101 :param cs: given changeset
101 :param cs: given changeset
102 :param path: path to lookup
102 :param path: path to lookup
103 """
103 """
104
104
105 try:
105 try:
106 file_node = cs.get_node(path)
106 file_node = cs.get_node(path)
107 if file_node.is_dir():
107 if file_node.is_dir():
108 raise RepositoryError('given path is a directory')
108 raise RepositoryError('given path is a directory')
109 except RepositoryError, e:
109 except RepositoryError, e:
110 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
111 redirect(h.url('files_home', repo_name=repo_name,
111 redirect(h.url('files_home', repo_name=repo_name,
112 revision=cs.raw_id))
112 revision=cs.raw_id))
113
113
114 return file_node
114 return file_node
115
115
116 @LoginRequired()
116 @LoginRequired()
117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
118 'repository.admin')
118 'repository.admin')
119 def index(self, repo_name, revision, f_path, annotate=False):
119 def index(self, repo_name, revision, f_path, annotate=False):
120 # redirect to given revision from form if given
120 # redirect to given revision from form if given
121 post_revision = request.POST.get('at_rev', None)
121 post_revision = request.POST.get('at_rev', None)
122 if post_revision:
122 if post_revision:
123 cs = self.__get_cs_or_redirect(post_revision, repo_name)
123 cs = self.__get_cs_or_redirect(post_revision, repo_name)
124 redirect(url('files_home', repo_name=c.repo_name,
124 redirect(url('files_home', repo_name=c.repo_name,
125 revision=cs.raw_id, f_path=f_path))
125 revision=cs.raw_id, f_path=f_path))
126
126
127 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
128 c.branch = request.GET.get('branch', None)
128 c.branch = request.GET.get('branch', None)
129 c.f_path = f_path
129 c.f_path = f_path
130 c.annotate = annotate
130 c.annotate = annotate
131 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
131 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
132 cur_rev = c.changeset.revision
132 cur_rev = c.changeset.revision
133
133
134 # prev link
134 # prev link
135 try:
135 try:
136 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
136 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
137 c.url_prev = url('files_home', repo_name=c.repo_name,
137 c.url_prev = url('files_home', repo_name=c.repo_name,
138 revision=prev_rev.raw_id, f_path=f_path)
138 revision=prev_rev.raw_id, f_path=f_path)
139 if c.branch:
139 if c.branch:
140 c.url_prev += '?branch=%s' % c.branch
140 c.url_prev += '?branch=%s' % c.branch
141 except (ChangesetDoesNotExistError, VCSError):
141 except (ChangesetDoesNotExistError, VCSError):
142 c.url_prev = '#'
142 c.url_prev = '#'
143
143
144 # next link
144 # next link
145 try:
145 try:
146 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
146 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
147 c.url_next = url('files_home', repo_name=c.repo_name,
147 c.url_next = url('files_home', repo_name=c.repo_name,
148 revision=next_rev.raw_id, f_path=f_path)
148 revision=next_rev.raw_id, f_path=f_path)
149 if c.branch:
149 if c.branch:
150 c.url_next += '?branch=%s' % c.branch
150 c.url_next += '?branch=%s' % c.branch
151 except (ChangesetDoesNotExistError, VCSError):
151 except (ChangesetDoesNotExistError, VCSError):
152 c.url_next = '#'
152 c.url_next = '#'
153
153
154 # files or dirs
154 # files or dirs
155 try:
155 try:
156 c.file = c.changeset.get_node(f_path)
156 c.file = c.changeset.get_node(f_path)
157
157
158 if c.file.is_file():
158 if c.file.is_file():
159 c.load_full_history = False
159 c.load_full_history = False
160 file_last_cs = c.file.last_changeset
160 file_last_cs = c.file.last_changeset
161 c.file_changeset = (c.changeset
161 c.file_changeset = (c.changeset
162 if c.changeset.revision < file_last_cs.revision
162 if c.changeset.revision < file_last_cs.revision
163 else file_last_cs)
163 else file_last_cs)
164 #determine if we're on branch head
164 #determine if we're on branch head
165 _branches = c.rhodecode_repo.branches
165 _branches = c.rhodecode_repo.branches
166 c.on_branch_head = revision in _branches.keys() + _branches.values()
166 c.on_branch_head = revision in _branches.keys() + _branches.values()
167 _hist = []
167 _hist = []
168 c.file_history = []
168 c.file_history = []
169 if c.load_full_history:
169 if c.load_full_history:
170 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
170 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
171
171
172 c.authors = []
172 c.authors = []
173 for a in set([x.author for x in _hist]):
173 for a in set([x.author for x in _hist]):
174 c.authors.append((h.email(a), h.person(a)))
174 c.authors.append((h.email(a), h.person(a)))
175 else:
175 else:
176 c.authors = c.file_history = []
176 c.authors = c.file_history = []
177 except RepositoryError, e:
177 except RepositoryError, e:
178 h.flash(str(e), category='warning')
178 h.flash(str(e), category='warning')
179 redirect(h.url('files_home', repo_name=repo_name,
179 redirect(h.url('files_home', repo_name=repo_name,
180 revision='tip'))
180 revision='tip'))
181
181
182 if request.environ.get('HTTP_X_PARTIAL_XHR'):
182 if request.environ.get('HTTP_X_PARTIAL_XHR'):
183 return render('files/files_ypjax.html')
183 return render('files/files_ypjax.html')
184
184
185 return render('files/files.html')
185 return render('files/files.html')
186
186
187 def history(self, repo_name, revision, f_path, annotate=False):
187 def history(self, repo_name, revision, f_path, annotate=False):
188 if request.environ.get('HTTP_X_PARTIAL_XHR'):
188 if request.environ.get('HTTP_X_PARTIAL_XHR'):
189 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
189 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
190 c.f_path = f_path
190 c.f_path = f_path
191 c.annotate = annotate
191 c.annotate = annotate
192 c.file = c.changeset.get_node(f_path)
192 c.file = c.changeset.get_node(f_path)
193 if c.file.is_file():
193 if c.file.is_file():
194 file_last_cs = c.file.last_changeset
194 file_last_cs = c.file.last_changeset
195 c.file_changeset = (c.changeset
195 c.file_changeset = (c.changeset
196 if c.changeset.revision < file_last_cs.revision
196 if c.changeset.revision < file_last_cs.revision
197 else file_last_cs)
197 else file_last_cs)
198 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
198 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
199 c.authors = []
199 c.authors = []
200 for a in set([x.author for x in _hist]):
200 for a in set([x.author for x in _hist]):
201 c.authors.append((h.email(a), h.person(a)))
201 c.authors.append((h.email(a), h.person(a)))
202 return render('files/files_history_box.html')
202 return render('files/files_history_box.html')
203
203
204 @LoginRequired()
204 @LoginRequired()
205 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
205 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
206 'repository.admin')
206 'repository.admin')
207 def rawfile(self, repo_name, revision, f_path):
207 def rawfile(self, repo_name, revision, f_path):
208 cs = self.__get_cs_or_redirect(revision, repo_name)
208 cs = self.__get_cs_or_redirect(revision, repo_name)
209 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
209 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
210
210
211 response.content_disposition = 'attachment; filename=%s' % \
211 response.content_disposition = 'attachment; filename=%s' % \
212 safe_str(f_path.split(Repository.url_sep())[-1])
212 safe_str(f_path.split(Repository.url_sep())[-1])
213
213
214 response.content_type = file_node.mimetype
214 response.content_type = file_node.mimetype
215 return file_node.content
215 return file_node.content
216
216
217 @LoginRequired()
217 @LoginRequired()
218 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
218 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
219 'repository.admin')
219 'repository.admin')
220 def raw(self, repo_name, revision, f_path):
220 def raw(self, repo_name, revision, f_path):
221 cs = self.__get_cs_or_redirect(revision, repo_name)
221 cs = self.__get_cs_or_redirect(revision, repo_name)
222 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
222 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
223
223
224 raw_mimetype_mapping = {
224 raw_mimetype_mapping = {
225 # map original mimetype to a mimetype used for "show as raw"
225 # map original mimetype to a mimetype used for "show as raw"
226 # you can also provide a content-disposition to override the
226 # you can also provide a content-disposition to override the
227 # default "attachment" disposition.
227 # default "attachment" disposition.
228 # orig_type: (new_type, new_dispo)
228 # orig_type: (new_type, new_dispo)
229
229
230 # show images inline:
230 # show images inline:
231 'image/x-icon': ('image/x-icon', 'inline'),
231 'image/x-icon': ('image/x-icon', 'inline'),
232 'image/png': ('image/png', 'inline'),
232 'image/png': ('image/png', 'inline'),
233 'image/gif': ('image/gif', 'inline'),
233 'image/gif': ('image/gif', 'inline'),
234 'image/jpeg': ('image/jpeg', 'inline'),
234 'image/jpeg': ('image/jpeg', 'inline'),
235 'image/svg+xml': ('image/svg+xml', 'inline'),
235 'image/svg+xml': ('image/svg+xml', 'inline'),
236 }
236 }
237
237
238 mimetype = file_node.mimetype
238 mimetype = file_node.mimetype
239 try:
239 try:
240 mimetype, dispo = raw_mimetype_mapping[mimetype]
240 mimetype, dispo = raw_mimetype_mapping[mimetype]
241 except KeyError:
241 except KeyError:
242 # we don't know anything special about this, handle it safely
242 # we don't know anything special about this, handle it safely
243 if file_node.is_binary:
243 if file_node.is_binary:
244 # do same as download raw for binary files
244 # do same as download raw for binary files
245 mimetype, dispo = 'application/octet-stream', 'attachment'
245 mimetype, dispo = 'application/octet-stream', 'attachment'
246 else:
246 else:
247 # do not just use the original mimetype, but force text/plain,
247 # do not just use the original mimetype, but force text/plain,
248 # otherwise it would serve text/html and that might be unsafe.
248 # otherwise it would serve text/html and that might be unsafe.
249 # Note: underlying vcs library fakes text/plain mimetype if the
249 # Note: underlying vcs library fakes text/plain mimetype if the
250 # mimetype can not be determined and it thinks it is not
250 # mimetype can not be determined and it thinks it is not
251 # binary.This might lead to erroneous text display in some
251 # binary.This might lead to erroneous text display in some
252 # cases, but helps in other cases, like with text files
252 # cases, but helps in other cases, like with text files
253 # without extension.
253 # without extension.
254 mimetype, dispo = 'text/plain', 'inline'
254 mimetype, dispo = 'text/plain', 'inline'
255
255
256 if dispo == 'attachment':
256 if dispo == 'attachment':
257 dispo = 'attachment; filename=%s' % \
257 dispo = 'attachment; filename=%s' % \
258 safe_str(f_path.split(os.sep)[-1])
258 safe_str(f_path.split(os.sep)[-1])
259
259
260 response.content_disposition = dispo
260 response.content_disposition = dispo
261 response.content_type = mimetype
261 response.content_type = mimetype
262 return file_node.content
262 return file_node.content
263
263
264 @LoginRequired()
264 @LoginRequired()
265 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
265 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
266 def edit(self, repo_name, revision, f_path):
266 def edit(self, repo_name, revision, f_path):
267 repo = c.rhodecode_db_repo
267 repo = c.rhodecode_db_repo
268 if repo.enable_locking and repo.locked[0]:
268 if repo.enable_locking and repo.locked[0]:
269 h.flash(_('This repository is has been locked by %s on %s')
269 h.flash(_('This repository is has been locked by %s on %s')
270 % (h.person_by_id(repo.locked[0]),
270 % (h.person_by_id(repo.locked[0]),
271 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
271 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
272 'warning')
272 'warning')
273 return redirect(h.url('files_home',
273 return redirect(h.url('files_home',
274 repo_name=repo_name, revision='tip'))
274 repo_name=repo_name, revision='tip'))
275
275
276 # check if revision is a branch identifier- basically we cannot
276 # check if revision is a branch identifier- basically we cannot
277 # create multiple heads via file editing
277 # create multiple heads via file editing
278 _branches = repo.scm_instance.branches
278 _branches = repo.scm_instance.branches
279 # check if revision is a branch name or branch hash
279 # check if revision is a branch name or branch hash
280 if revision not in _branches.keys() + _branches.values():
280 if revision not in _branches.keys() + _branches.values():
281 h.flash(_('You can only edit files with revision '
281 h.flash(_('You can only edit files with revision '
282 'being a valid branch '), category='warning')
282 'being a valid branch '), category='warning')
283 return redirect(h.url('files_home',
283 return redirect(h.url('files_home',
284 repo_name=repo_name, revision='tip',
284 repo_name=repo_name, revision='tip',
285 f_path=f_path))
285 f_path=f_path))
286
286
287 r_post = request.POST
287 r_post = request.POST
288
288
289 c.cs = self.__get_cs_or_redirect(revision, repo_name)
289 c.cs = self.__get_cs_or_redirect(revision, repo_name)
290 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
290 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
291
291
292 if c.file.is_binary:
292 if c.file.is_binary:
293 return redirect(url('files_home', repo_name=c.repo_name,
293 return redirect(url('files_home', repo_name=c.repo_name,
294 revision=c.cs.raw_id, f_path=f_path))
294 revision=c.cs.raw_id, f_path=f_path))
295 c.default_message = _('Edited file %s via RhodeCode') % (f_path)
295 c.default_message = _('Edited file %s via RhodeCode') % (f_path)
296 c.f_path = f_path
296 c.f_path = f_path
297
297
298 if r_post:
298 if r_post:
299
299
300 old_content = c.file.content
300 old_content = c.file.content
301 sl = old_content.splitlines(1)
301 sl = old_content.splitlines(1)
302 first_line = sl[0] if sl else ''
302 first_line = sl[0] if sl else ''
303 # modes: 0 - Unix, 1 - Mac, 2 - DOS
303 # modes: 0 - Unix, 1 - Mac, 2 - DOS
304 mode = detect_mode(first_line, 0)
304 mode = detect_mode(first_line, 0)
305 content = convert_line_endings(r_post.get('content'), mode)
305 content = convert_line_endings(r_post.get('content'), mode)
306
306
307 message = r_post.get('message') or c.default_message
307 message = r_post.get('message') or c.default_message
308 author = self.rhodecode_user.full_contact
308 author = self.rhodecode_user.full_contact
309
309
310 if content == old_content:
310 if content == old_content:
311 h.flash(_('No changes'),
311 h.flash(_('No changes'),
312 category='warning')
312 category='warning')
313 return redirect(url('changeset_home', repo_name=c.repo_name,
313 return redirect(url('changeset_home', repo_name=c.repo_name,
314 revision='tip'))
314 revision='tip'))
315 try:
315 try:
316 self.scm_model.commit_change(repo=c.rhodecode_repo,
316 self.scm_model.commit_change(repo=c.rhodecode_repo,
317 repo_name=repo_name, cs=c.cs,
317 repo_name=repo_name, cs=c.cs,
318 user=self.rhodecode_user,
318 user=self.rhodecode_user,
319 author=author, message=message,
319 author=author, message=message,
320 content=content, f_path=f_path)
320 content=content, f_path=f_path)
321 h.flash(_('Successfully committed to %s') % f_path,
321 h.flash(_('Successfully committed to %s') % f_path,
322 category='success')
322 category='success')
323
323
324 except Exception:
324 except Exception:
325 log.error(traceback.format_exc())
325 log.error(traceback.format_exc())
326 h.flash(_('Error occurred during commit'), category='error')
326 h.flash(_('Error occurred during commit'), category='error')
327 return redirect(url('changeset_home',
327 return redirect(url('changeset_home',
328 repo_name=c.repo_name, revision='tip'))
328 repo_name=c.repo_name, revision='tip'))
329
329
330 return render('files/files_edit.html')
330 return render('files/files_edit.html')
331
331
332 @LoginRequired()
332 @LoginRequired()
333 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
333 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
334 def add(self, repo_name, revision, f_path):
334 def add(self, repo_name, revision, f_path):
335
335
336 repo = Repository.get_by_repo_name(repo_name)
336 repo = Repository.get_by_repo_name(repo_name)
337 if repo.enable_locking and repo.locked[0]:
337 if repo.enable_locking and repo.locked[0]:
338 h.flash(_('This repository is has been locked by %s on %s')
338 h.flash(_('This repository is has been locked by %s on %s')
339 % (h.person_by_id(repo.locked[0]),
339 % (h.person_by_id(repo.locked[0]),
340 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
340 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
341 'warning')
341 'warning')
342 return redirect(h.url('files_home',
342 return redirect(h.url('files_home',
343 repo_name=repo_name, revision='tip'))
343 repo_name=repo_name, revision='tip'))
344
344
345 r_post = request.POST
345 r_post = request.POST
346 c.cs = self.__get_cs_or_redirect(revision, repo_name,
346 c.cs = self.__get_cs_or_redirect(revision, repo_name,
347 redirect_after=False)
347 redirect_after=False)
348 if c.cs is None:
348 if c.cs is None:
349 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
349 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
350 c.default_message = (_('Added file via RhodeCode'))
350 c.default_message = (_('Added file via RhodeCode'))
351 c.f_path = f_path
351 c.f_path = f_path
352
352
353 if r_post:
353 if r_post:
354 unix_mode = 0
354 unix_mode = 0
355 content = convert_line_endings(r_post.get('content'), unix_mode)
355 content = convert_line_endings(r_post.get('content'), unix_mode)
356
356
357 message = r_post.get('message') or c.default_message
357 message = r_post.get('message') or c.default_message
358 location = r_post.get('location')
358 location = r_post.get('location')
359 filename = r_post.get('filename')
359 filename = r_post.get('filename')
360 file_obj = r_post.get('upload_file', None)
360 file_obj = r_post.get('upload_file', None)
361
361
362 if file_obj is not None and hasattr(file_obj, 'filename'):
362 if file_obj is not None and hasattr(file_obj, 'filename'):
363 filename = file_obj.filename
363 filename = file_obj.filename
364 content = file_obj.file
364 content = file_obj.file
365
365
366 node_path = os.path.join(location, filename)
366 node_path = os.path.join(location, filename)
367 author = self.rhodecode_user.full_contact
367 author = self.rhodecode_user.full_contact
368
368
369 if not content:
369 if not content:
370 h.flash(_('No content'), category='warning')
370 h.flash(_('No content'), category='warning')
371 return redirect(url('changeset_home', repo_name=c.repo_name,
371 return redirect(url('changeset_home', repo_name=c.repo_name,
372 revision='tip'))
372 revision='tip'))
373 if not filename:
373 if not filename:
374 h.flash(_('No filename'), category='warning')
374 h.flash(_('No filename'), category='warning')
375 return redirect(url('changeset_home', repo_name=c.repo_name,
375 return redirect(url('changeset_home', repo_name=c.repo_name,
376 revision='tip'))
376 revision='tip'))
377
377
378 try:
378 try:
379 self.scm_model.create_node(repo=c.rhodecode_repo,
379 self.scm_model.create_node(repo=c.rhodecode_repo,
380 repo_name=repo_name, cs=c.cs,
380 repo_name=repo_name, cs=c.cs,
381 user=self.rhodecode_user,
381 user=self.rhodecode_user,
382 author=author, message=message,
382 author=author, message=message,
383 content=content, f_path=node_path)
383 content=content, f_path=node_path)
384 h.flash(_('Successfully committed to %s') % node_path,
384 h.flash(_('Successfully committed to %s') % node_path,
385 category='success')
385 category='success')
386 except NodeAlreadyExistsError, e:
386 except NodeAlreadyExistsError, e:
387 h.flash(_(e), category='error')
387 h.flash(_(e), category='error')
388 except Exception:
388 except Exception:
389 log.error(traceback.format_exc())
389 log.error(traceback.format_exc())
390 h.flash(_('Error occurred during commit'), category='error')
390 h.flash(_('Error occurred during commit'), category='error')
391 return redirect(url('changeset_home',
391 return redirect(url('changeset_home',
392 repo_name=c.repo_name, revision='tip'))
392 repo_name=c.repo_name, revision='tip'))
393
393
394 return render('files/files_add.html')
394 return render('files/files_add.html')
395
395
396 @LoginRequired()
396 @LoginRequired()
397 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
397 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
398 'repository.admin')
398 'repository.admin')
399 def archivefile(self, repo_name, fname):
399 def archivefile(self, repo_name, fname):
400
400
401 fileformat = None
401 fileformat = None
402 revision = None
402 revision = None
403 ext = None
403 ext = None
404 subrepos = request.GET.get('subrepos') == 'true'
404 subrepos = request.GET.get('subrepos') == 'true'
405
405
406 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
406 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
407 archive_spec = fname.split(ext_data[1])
407 archive_spec = fname.split(ext_data[1])
408 if len(archive_spec) == 2 and archive_spec[1] == '':
408 if len(archive_spec) == 2 and archive_spec[1] == '':
409 fileformat = a_type or ext_data[1]
409 fileformat = a_type or ext_data[1]
410 revision = archive_spec[0]
410 revision = archive_spec[0]
411 ext = ext_data[1]
411 ext = ext_data[1]
412
412
413 try:
413 try:
414 dbrepo = RepoModel().get_by_repo_name(repo_name)
414 dbrepo = RepoModel().get_by_repo_name(repo_name)
415 if dbrepo.enable_downloads is False:
415 if dbrepo.enable_downloads is False:
416 return _('downloads disabled')
416 return _('downloads disabled')
417
417
418 if c.rhodecode_repo.alias == 'hg':
418 if c.rhodecode_repo.alias == 'hg':
419 # patch and reset hooks section of UI config to not run any
419 # patch and reset hooks section of UI config to not run any
420 # hooks on fetching archives with subrepos
420 # hooks on fetching archives with subrepos
421 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
421 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
422 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
422 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
423
423
424 cs = c.rhodecode_repo.get_changeset(revision)
424 cs = c.rhodecode_repo.get_changeset(revision)
425 content_type = settings.ARCHIVE_SPECS[fileformat][0]
425 content_type = settings.ARCHIVE_SPECS[fileformat][0]
426 except ChangesetDoesNotExistError:
426 except ChangesetDoesNotExistError:
427 return _('Unknown revision %s') % revision
427 return _('Unknown revision %s') % revision
428 except EmptyRepositoryError:
428 except EmptyRepositoryError:
429 return _('Empty repository')
429 return _('Empty repository')
430 except (ImproperArchiveTypeError, KeyError):
430 except (ImproperArchiveTypeError, KeyError):
431 return _('Unknown archive type')
431 return _('Unknown archive type')
432
432
433 fd, archive = tempfile.mkstemp()
433 fd, archive = tempfile.mkstemp()
434 t = open(archive, 'wb')
434 t = open(archive, 'wb')
435 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
435 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
436 t.close()
436 t.close()
437
437
438 def get_chunked_archive(archive):
438 def get_chunked_archive(archive):
439 stream = open(archive, 'rb')
439 stream = open(archive, 'rb')
440 while True:
440 while True:
441 data = stream.read(16 * 1024)
441 data = stream.read(16 * 1024)
442 if not data:
442 if not data:
443 stream.close()
443 stream.close()
444 os.close(fd)
444 os.close(fd)
445 os.remove(archive)
445 os.remove(archive)
446 break
446 break
447 yield data
447 yield data
448
448
449 response.content_disposition = str('attachment; filename=%s-%s%s' \
449 response.content_disposition = str('attachment; filename=%s-%s%s' \
450 % (repo_name, revision[:12], ext))
450 % (repo_name, revision[:12], ext))
451 response.content_type = str(content_type)
451 response.content_type = str(content_type)
452 return get_chunked_archive(archive)
452 return get_chunked_archive(archive)
453
453
454 @LoginRequired()
454 @LoginRequired()
455 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
455 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
456 'repository.admin')
456 'repository.admin')
457 def diff(self, repo_name, f_path):
457 def diff(self, repo_name, f_path):
458 ignore_whitespace = request.GET.get('ignorews') == '1'
458 ignore_whitespace = request.GET.get('ignorews') == '1'
459 line_context = request.GET.get('context', 3)
459 line_context = request.GET.get('context', 3)
460 diff1 = request.GET.get('diff1', '')
460 diff1 = request.GET.get('diff1', '')
461 diff2 = request.GET.get('diff2', '')
461 diff2 = request.GET.get('diff2', '')
462 c.action = request.GET.get('diff')
462 c.action = request.GET.get('diff')
463 c.no_changes = diff1 == diff2
463 c.no_changes = diff1 == diff2
464 c.f_path = f_path
464 c.f_path = f_path
465 c.big_diff = False
465 c.big_diff = False
466 c.anchor_url = anchor_url
466 c.anchor_url = anchor_url
467 c.ignorews_url = _ignorews_url
467 c.ignorews_url = _ignorews_url
468 c.context_url = _context_url
468 c.context_url = _context_url
469 c.changes = OrderedDict()
469 c.changes = OrderedDict()
470 c.changes[diff2] = []
470 c.changes[diff2] = []
471
471
472 #special case if we want a show rev only, it's impl here
472 #special case if we want a show rev only, it's impl here
473 #to reduce JS and callbacks
473 #to reduce JS and callbacks
474
474
475 if request.GET.get('show_rev'):
475 if request.GET.get('show_rev'):
476 if str2bool(request.GET.get('annotate', 'False')):
476 if str2bool(request.GET.get('annotate', 'False')):
477 _url = url('files_annotate_home', repo_name=c.repo_name,
477 _url = url('files_annotate_home', repo_name=c.repo_name,
478 revision=diff1, f_path=c.f_path)
478 revision=diff1, f_path=c.f_path)
479 else:
479 else:
480 _url = url('files_home', repo_name=c.repo_name,
480 _url = url('files_home', repo_name=c.repo_name,
481 revision=diff1, f_path=c.f_path)
481 revision=diff1, f_path=c.f_path)
482
482
483 return redirect(_url)
483 return redirect(_url)
484 try:
484 try:
485 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
485 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
486 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
486 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
487 try:
487 try:
488 node1 = c.changeset_1.get_node(f_path)
488 node1 = c.changeset_1.get_node(f_path)
489 except NodeDoesNotExistError:
489 except NodeDoesNotExistError:
490 c.changeset_1 = EmptyChangeset(cs=diff1,
490 c.changeset_1 = EmptyChangeset(cs=diff1,
491 revision=c.changeset_1.revision,
491 revision=c.changeset_1.revision,
492 repo=c.rhodecode_repo)
492 repo=c.rhodecode_repo)
493 node1 = FileNode(f_path, '', changeset=c.changeset_1)
493 node1 = FileNode(f_path, '', changeset=c.changeset_1)
494 else:
494 else:
495 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
495 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
496 node1 = FileNode(f_path, '', changeset=c.changeset_1)
496 node1 = FileNode(f_path, '', changeset=c.changeset_1)
497
497
498 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
498 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
499 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
499 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
500 try:
500 try:
501 node2 = c.changeset_2.get_node(f_path)
501 node2 = c.changeset_2.get_node(f_path)
502 except NodeDoesNotExistError:
502 except NodeDoesNotExistError:
503 c.changeset_2 = EmptyChangeset(cs=diff2,
503 c.changeset_2 = EmptyChangeset(cs=diff2,
504 revision=c.changeset_2.revision,
504 revision=c.changeset_2.revision,
505 repo=c.rhodecode_repo)
505 repo=c.rhodecode_repo)
506 node2 = FileNode(f_path, '', changeset=c.changeset_2)
506 node2 = FileNode(f_path, '', changeset=c.changeset_2)
507 else:
507 else:
508 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
508 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
509 node2 = FileNode(f_path, '', changeset=c.changeset_2)
509 node2 = FileNode(f_path, '', changeset=c.changeset_2)
510 except (RepositoryError, NodeError):
510 except (RepositoryError, NodeError):
511 log.error(traceback.format_exc())
511 log.error(traceback.format_exc())
512 return redirect(url('files_home', repo_name=c.repo_name,
512 return redirect(url('files_home', repo_name=c.repo_name,
513 f_path=f_path))
513 f_path=f_path))
514
514
515 if c.action == 'download':
515 if c.action == 'download':
516 _diff = diffs.get_gitdiff(node1, node2,
516 _diff = diffs.get_gitdiff(node1, node2,
517 ignore_whitespace=ignore_whitespace,
517 ignore_whitespace=ignore_whitespace,
518 context=line_context)
518 context=line_context)
519 diff = diffs.DiffProcessor(_diff, format='gitdiff')
519 diff = diffs.DiffProcessor(_diff, format='gitdiff')
520
520
521 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
521 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
522 response.content_type = 'text/plain'
522 response.content_type = 'text/plain'
523 response.content_disposition = (
523 response.content_disposition = (
524 'attachment; filename=%s' % diff_name
524 'attachment; filename=%s' % diff_name
525 )
525 )
526 return diff.as_raw()
526 return diff.as_raw()
527
527
528 elif c.action == 'raw':
528 elif c.action == 'raw':
529 _diff = diffs.get_gitdiff(node1, node2,
529 _diff = diffs.get_gitdiff(node1, node2,
530 ignore_whitespace=ignore_whitespace,
530 ignore_whitespace=ignore_whitespace,
531 context=line_context)
531 context=line_context)
532 diff = diffs.DiffProcessor(_diff, format='gitdiff')
532 diff = diffs.DiffProcessor(_diff, format='gitdiff')
533 response.content_type = 'text/plain'
533 response.content_type = 'text/plain'
534 return diff.as_raw()
534 return diff.as_raw()
535
535
536 else:
536 else:
537 fid = h.FID(diff2, node2.path)
537 fid = h.FID(diff2, node2.path)
538 line_context_lcl = get_line_ctx(fid, request.GET)
538 line_context_lcl = get_line_ctx(fid, request.GET)
539 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
539 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
540
540
541 lim = request.GET.get('fulldiff') or self.cut_off_limit
541 lim = request.GET.get('fulldiff') or self.cut_off_limit
542 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
542 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
543 filenode_new=node2,
543 filenode_new=node2,
544 cut_off_limit=lim,
544 cut_off_limit=lim,
545 ignore_whitespace=ign_whitespace_lcl,
545 ignore_whitespace=ign_whitespace_lcl,
546 line_context=line_context_lcl,
546 line_context=line_context_lcl,
547 enable_comments=False)
547 enable_comments=False)
548 op = ''
548 op = ''
549 filename = node1.path
549 filename = node1.path
550 cs_changes = {
550 cs_changes = {
551 'fid': [cs1, cs2, op, filename, diff, st]
551 'fid': [cs1, cs2, op, filename, diff, st]
552 }
552 }
553 c.changes = cs_changes
553 c.changes = cs_changes
554
554
555 return render('files/file_diff.html')
555 return render('files/file_diff.html')
556
556
557 def _get_node_history(self, cs, f_path, changesets=None):
557 def _get_node_history(self, cs, f_path, changesets=None):
558 """
558 """
559 get changesets history for given node
559 get changesets history for given node
560
560
561 :param cs: changeset to calculate history
561 :param cs: changeset to calculate history
562 :param f_path: path for node to calculate history for
562 :param f_path: path for node to calculate history for
563 :param changesets: if passed don't calculate history and take
563 :param changesets: if passed don't calculate history and take
564 changesets defined in this list
564 changesets defined in this list
565 """
565 """
566 # calculate history based on tip
566 # calculate history based on tip
567 tip_cs = c.rhodecode_repo.get_changeset()
567 tip_cs = c.rhodecode_repo.get_changeset()
568 if changesets is None:
568 if changesets is None:
569 try:
569 try:
570 changesets = tip_cs.get_file_history(f_path)
570 changesets = tip_cs.get_file_history(f_path)
571 except (NodeDoesNotExistError, ChangesetError):
571 except (NodeDoesNotExistError, ChangesetError):
572 #this node is not present at tip !
572 #this node is not present at tip !
573 changesets = cs.get_file_history(f_path)
573 changesets = cs.get_file_history(f_path)
574 hist_l = []
574 hist_l = []
575
575
576 changesets_group = ([], _("Changesets"))
576 changesets_group = ([], _("Changesets"))
577 branches_group = ([], _("Branches"))
577 branches_group = ([], _("Branches"))
578 tags_group = ([], _("Tags"))
578 tags_group = ([], _("Tags"))
579 _hg = cs.repository.alias == 'hg'
579 _hg = cs.repository.alias == 'hg'
580 for chs in changesets:
580 for chs in changesets:
581 #_branch = '(%s)' % chs.branch if _hg else ''
581 #_branch = '(%s)' % chs.branch if _hg else ''
582 _branch = chs.branch
582 _branch = chs.branch
583 n_desc = 'r%s:%s (%s)' % (chs.revision, chs.short_id, _branch)
583 n_desc = 'r%s:%s (%s)' % (chs.revision, chs.short_id, _branch)
584 changesets_group[0].append((chs.raw_id, n_desc,))
584 changesets_group[0].append((chs.raw_id, n_desc,))
585 hist_l.append(changesets_group)
585 hist_l.append(changesets_group)
586
586
587 for name, chs in c.rhodecode_repo.branches.items():
587 for name, chs in c.rhodecode_repo.branches.items():
588 branches_group[0].append((chs, name),)
588 branches_group[0].append((chs, name),)
589 hist_l.append(branches_group)
589 hist_l.append(branches_group)
590
590
591 for name, chs in c.rhodecode_repo.tags.items():
591 for name, chs in c.rhodecode_repo.tags.items():
592 tags_group[0].append((chs, name),)
592 tags_group[0].append((chs, name),)
593 hist_l.append(tags_group)
593 hist_l.append(tags_group)
594
594
595 return hist_l, changesets
595 return hist_l, changesets
596
596
597 @LoginRequired()
597 @LoginRequired()
598 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
598 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
599 'repository.admin')
599 'repository.admin')
600 @jsonify
600 @jsonify
601 def nodelist(self, repo_name, revision, f_path):
601 def nodelist(self, repo_name, revision, f_path):
602 if request.environ.get('HTTP_X_PARTIAL_XHR'):
602 if request.environ.get('HTTP_X_PARTIAL_XHR'):
603 cs = self.__get_cs_or_redirect(revision, repo_name)
603 cs = self.__get_cs_or_redirect(revision, repo_name)
604 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
604 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
605 flat=False)
605 flat=False)
606 return {'nodes': _d + _f}
606 return {'nodes': _d + _f}
@@ -1,1984 +1,1984 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import datetime
28 import datetime
29 import traceback
29 import traceback
30 import hashlib
30 import hashlib
31 import time
31 import time
32 from collections import defaultdict
32 from collections import defaultdict
33
33
34 from sqlalchemy import *
34 from sqlalchemy import *
35 from sqlalchemy.ext.hybrid import hybrid_property
35 from sqlalchemy.ext.hybrid import hybrid_property
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 from sqlalchemy.exc import DatabaseError
37 from sqlalchemy.exc import DatabaseError
38 from beaker.cache import cache_region, region_invalidate
38 from beaker.cache import cache_region, region_invalidate
39 from webob.exc import HTTPNotFound
39 from webob.exc import HTTPNotFound
40
40
41 from pylons.i18n.translation import lazy_ugettext as _
41 from pylons.i18n.translation import lazy_ugettext as _
42
42
43 from rhodecode.lib.vcs import get_backend
43 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs.utils.helpers import get_scm
44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 from rhodecode.lib.vcs.exceptions import VCSError
45 from rhodecode.lib.vcs.exceptions import VCSError
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47
47
48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 safe_unicode, remove_suffix, remove_prefix
49 safe_unicode, remove_suffix, remove_prefix
50 from rhodecode.lib.compat import json
50 from rhodecode.lib.compat import json
51 from rhodecode.lib.caching_query import FromCache
51 from rhodecode.lib.caching_query import FromCache
52
52
53 from rhodecode.model.meta import Base, Session
53 from rhodecode.model.meta import Base, Session
54
54
55 URL_SEP = '/'
55 URL_SEP = '/'
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58 #==============================================================================
58 #==============================================================================
59 # BASE CLASSES
59 # BASE CLASSES
60 #==============================================================================
60 #==============================================================================
61
61
62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63
63
64
64
65 class BaseModel(object):
65 class BaseModel(object):
66 """
66 """
67 Base Model for all classess
67 Base Model for all classess
68 """
68 """
69
69
70 @classmethod
70 @classmethod
71 def _get_keys(cls):
71 def _get_keys(cls):
72 """return column names for this model """
72 """return column names for this model """
73 return class_mapper(cls).c.keys()
73 return class_mapper(cls).c.keys()
74
74
75 def get_dict(self):
75 def get_dict(self):
76 """
76 """
77 return dict with keys and values corresponding
77 return dict with keys and values corresponding
78 to this model data """
78 to this model data """
79
79
80 d = {}
80 d = {}
81 for k in self._get_keys():
81 for k in self._get_keys():
82 d[k] = getattr(self, k)
82 d[k] = getattr(self, k)
83
83
84 # also use __json__() if present to get additional fields
84 # also use __json__() if present to get additional fields
85 _json_attr = getattr(self, '__json__', None)
85 _json_attr = getattr(self, '__json__', None)
86 if _json_attr:
86 if _json_attr:
87 # update with attributes from __json__
87 # update with attributes from __json__
88 if callable(_json_attr):
88 if callable(_json_attr):
89 _json_attr = _json_attr()
89 _json_attr = _json_attr()
90 for k, val in _json_attr.iteritems():
90 for k, val in _json_attr.iteritems():
91 d[k] = val
91 d[k] = val
92 return d
92 return d
93
93
94 def get_appstruct(self):
94 def get_appstruct(self):
95 """return list with keys and values tupples corresponding
95 """return list with keys and values tupples corresponding
96 to this model data """
96 to this model data """
97
97
98 l = []
98 l = []
99 for k in self._get_keys():
99 for k in self._get_keys():
100 l.append((k, getattr(self, k),))
100 l.append((k, getattr(self, k),))
101 return l
101 return l
102
102
103 def populate_obj(self, populate_dict):
103 def populate_obj(self, populate_dict):
104 """populate model with data from given populate_dict"""
104 """populate model with data from given populate_dict"""
105
105
106 for k in self._get_keys():
106 for k in self._get_keys():
107 if k in populate_dict:
107 if k in populate_dict:
108 setattr(self, k, populate_dict[k])
108 setattr(self, k, populate_dict[k])
109
109
110 @classmethod
110 @classmethod
111 def query(cls):
111 def query(cls):
112 return Session().query(cls)
112 return Session().query(cls)
113
113
114 @classmethod
114 @classmethod
115 def get(cls, id_):
115 def get(cls, id_):
116 if id_:
116 if id_:
117 return cls.query().get(id_)
117 return cls.query().get(id_)
118
118
119 @classmethod
119 @classmethod
120 def get_or_404(cls, id_):
120 def get_or_404(cls, id_):
121 try:
121 try:
122 id_ = int(id_)
122 id_ = int(id_)
123 except (TypeError, ValueError):
123 except (TypeError, ValueError):
124 raise HTTPNotFound
124 raise HTTPNotFound
125
125
126 res = cls.query().get(id_)
126 res = cls.query().get(id_)
127 if not res:
127 if not res:
128 raise HTTPNotFound
128 raise HTTPNotFound
129 return res
129 return res
130
130
131 @classmethod
131 @classmethod
132 def getAll(cls):
132 def getAll(cls):
133 return cls.query().all()
133 return cls.query().all()
134
134
135 @classmethod
135 @classmethod
136 def delete(cls, id_):
136 def delete(cls, id_):
137 obj = cls.query().get(id_)
137 obj = cls.query().get(id_)
138 Session().delete(obj)
138 Session().delete(obj)
139
139
140 def __repr__(self):
140 def __repr__(self):
141 if hasattr(self, '__unicode__'):
141 if hasattr(self, '__unicode__'):
142 # python repr needs to return str
142 # python repr needs to return str
143 return safe_str(self.__unicode__())
143 return safe_str(self.__unicode__())
144 return '<DB:%s>' % (self.__class__.__name__)
144 return '<DB:%s>' % (self.__class__.__name__)
145
145
146
146
147 class RhodeCodeSetting(Base, BaseModel):
147 class RhodeCodeSetting(Base, BaseModel):
148 __tablename__ = 'rhodecode_settings'
148 __tablename__ = 'rhodecode_settings'
149 __table_args__ = (
149 __table_args__ = (
150 UniqueConstraint('app_settings_name'),
150 UniqueConstraint('app_settings_name'),
151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 'mysql_charset': 'utf8'}
152 'mysql_charset': 'utf8'}
153 )
153 )
154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
157
157
158 def __init__(self, k='', v=''):
158 def __init__(self, k='', v=''):
159 self.app_settings_name = k
159 self.app_settings_name = k
160 self.app_settings_value = v
160 self.app_settings_value = v
161
161
162 @validates('_app_settings_value')
162 @validates('_app_settings_value')
163 def validate_settings_value(self, key, val):
163 def validate_settings_value(self, key, val):
164 assert type(val) == unicode
164 assert type(val) == unicode
165 return val
165 return val
166
166
167 @hybrid_property
167 @hybrid_property
168 def app_settings_value(self):
168 def app_settings_value(self):
169 v = self._app_settings_value
169 v = self._app_settings_value
170 if self.app_settings_name in ["ldap_active",
170 if self.app_settings_name in ["ldap_active",
171 "default_repo_enable_statistics",
171 "default_repo_enable_statistics",
172 "default_repo_enable_locking",
172 "default_repo_enable_locking",
173 "default_repo_private",
173 "default_repo_private",
174 "default_repo_enable_downloads"]:
174 "default_repo_enable_downloads"]:
175 v = str2bool(v)
175 v = str2bool(v)
176 return v
176 return v
177
177
178 @app_settings_value.setter
178 @app_settings_value.setter
179 def app_settings_value(self, val):
179 def app_settings_value(self, val):
180 """
180 """
181 Setter that will always make sure we use unicode in app_settings_value
181 Setter that will always make sure we use unicode in app_settings_value
182
182
183 :param val:
183 :param val:
184 """
184 """
185 self._app_settings_value = safe_unicode(val)
185 self._app_settings_value = safe_unicode(val)
186
186
187 def __unicode__(self):
187 def __unicode__(self):
188 return u"<%s('%s:%s')>" % (
188 return u"<%s('%s:%s')>" % (
189 self.__class__.__name__,
189 self.__class__.__name__,
190 self.app_settings_name, self.app_settings_value
190 self.app_settings_name, self.app_settings_value
191 )
191 )
192
192
193 @classmethod
193 @classmethod
194 def get_by_name(cls, key):
194 def get_by_name(cls, key):
195 return cls.query()\
195 return cls.query()\
196 .filter(cls.app_settings_name == key).scalar()
196 .filter(cls.app_settings_name == key).scalar()
197
197
198 @classmethod
198 @classmethod
199 def get_by_name_or_create(cls, key):
199 def get_by_name_or_create(cls, key):
200 res = cls.get_by_name(key)
200 res = cls.get_by_name(key)
201 if not res:
201 if not res:
202 res = cls(key)
202 res = cls(key)
203 return res
203 return res
204
204
205 @classmethod
205 @classmethod
206 def get_app_settings(cls, cache=False):
206 def get_app_settings(cls, cache=False):
207
207
208 ret = cls.query()
208 ret = cls.query()
209
209
210 if cache:
210 if cache:
211 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
211 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
212
212
213 if not ret:
213 if not ret:
214 raise Exception('Could not get application settings !')
214 raise Exception('Could not get application settings !')
215 settings = {}
215 settings = {}
216 for each in ret:
216 for each in ret:
217 settings['rhodecode_' + each.app_settings_name] = \
217 settings['rhodecode_' + each.app_settings_name] = \
218 each.app_settings_value
218 each.app_settings_value
219
219
220 return settings
220 return settings
221
221
222 @classmethod
222 @classmethod
223 def get_ldap_settings(cls, cache=False):
223 def get_ldap_settings(cls, cache=False):
224 ret = cls.query()\
224 ret = cls.query()\
225 .filter(cls.app_settings_name.startswith('ldap_')).all()
225 .filter(cls.app_settings_name.startswith('ldap_')).all()
226 fd = {}
226 fd = {}
227 for row in ret:
227 for row in ret:
228 fd.update({row.app_settings_name: row.app_settings_value})
228 fd.update({row.app_settings_name: row.app_settings_value})
229
229
230 return fd
230 return fd
231
231
232 @classmethod
232 @classmethod
233 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
233 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
234 ret = cls.query()\
234 ret = cls.query()\
235 .filter(cls.app_settings_name.startswith('default_')).all()
235 .filter(cls.app_settings_name.startswith('default_')).all()
236 fd = {}
236 fd = {}
237 for row in ret:
237 for row in ret:
238 key = row.app_settings_name
238 key = row.app_settings_name
239 if strip_prefix:
239 if strip_prefix:
240 key = remove_prefix(key, prefix='default_')
240 key = remove_prefix(key, prefix='default_')
241 fd.update({key: row.app_settings_value})
241 fd.update({key: row.app_settings_value})
242
242
243 return fd
243 return fd
244
244
245
245
246 class RhodeCodeUi(Base, BaseModel):
246 class RhodeCodeUi(Base, BaseModel):
247 __tablename__ = 'rhodecode_ui'
247 __tablename__ = 'rhodecode_ui'
248 __table_args__ = (
248 __table_args__ = (
249 UniqueConstraint('ui_key'),
249 UniqueConstraint('ui_key'),
250 {'extend_existing': True, 'mysql_engine': 'InnoDB',
250 {'extend_existing': True, 'mysql_engine': 'InnoDB',
251 'mysql_charset': 'utf8'}
251 'mysql_charset': 'utf8'}
252 )
252 )
253
253
254 HOOK_UPDATE = 'changegroup.update'
254 HOOK_UPDATE = 'changegroup.update'
255 HOOK_REPO_SIZE = 'changegroup.repo_size'
255 HOOK_REPO_SIZE = 'changegroup.repo_size'
256 HOOK_PUSH = 'changegroup.push_logger'
256 HOOK_PUSH = 'changegroup.push_logger'
257 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
257 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
258 HOOK_PULL = 'outgoing.pull_logger'
258 HOOK_PULL = 'outgoing.pull_logger'
259 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
259 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
260
260
261 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
261 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
262 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
262 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
265 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
265 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
266
266
267 @classmethod
267 @classmethod
268 def get_by_key(cls, key):
268 def get_by_key(cls, key):
269 return cls.query().filter(cls.ui_key == key).scalar()
269 return cls.query().filter(cls.ui_key == key).scalar()
270
270
271 @classmethod
271 @classmethod
272 def get_builtin_hooks(cls):
272 def get_builtin_hooks(cls):
273 q = cls.query()
273 q = cls.query()
274 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
274 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
275 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
275 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
276 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
276 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
277 return q.all()
277 return q.all()
278
278
279 @classmethod
279 @classmethod
280 def get_custom_hooks(cls):
280 def get_custom_hooks(cls):
281 q = cls.query()
281 q = cls.query()
282 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
282 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
283 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
283 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
284 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
284 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
285 q = q.filter(cls.ui_section == 'hooks')
285 q = q.filter(cls.ui_section == 'hooks')
286 return q.all()
286 return q.all()
287
287
288 @classmethod
288 @classmethod
289 def get_repos_location(cls):
289 def get_repos_location(cls):
290 return cls.get_by_key('/').ui_value
290 return cls.get_by_key('/').ui_value
291
291
292 @classmethod
292 @classmethod
293 def create_or_update_hook(cls, key, val):
293 def create_or_update_hook(cls, key, val):
294 new_ui = cls.get_by_key(key) or cls()
294 new_ui = cls.get_by_key(key) or cls()
295 new_ui.ui_section = 'hooks'
295 new_ui.ui_section = 'hooks'
296 new_ui.ui_active = True
296 new_ui.ui_active = True
297 new_ui.ui_key = key
297 new_ui.ui_key = key
298 new_ui.ui_value = val
298 new_ui.ui_value = val
299
299
300 Session().add(new_ui)
300 Session().add(new_ui)
301
301
302 def __repr__(self):
302 def __repr__(self):
303 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
303 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
304 self.ui_value)
304 self.ui_value)
305
305
306
306
307 class User(Base, BaseModel):
307 class User(Base, BaseModel):
308 __tablename__ = 'users'
308 __tablename__ = 'users'
309 __table_args__ = (
309 __table_args__ = (
310 UniqueConstraint('username'), UniqueConstraint('email'),
310 UniqueConstraint('username'), UniqueConstraint('email'),
311 Index('u_username_idx', 'username'),
311 Index('u_username_idx', 'username'),
312 Index('u_email_idx', 'email'),
312 Index('u_email_idx', 'email'),
313 {'extend_existing': True, 'mysql_engine': 'InnoDB',
313 {'extend_existing': True, 'mysql_engine': 'InnoDB',
314 'mysql_charset': 'utf8'}
314 'mysql_charset': 'utf8'}
315 )
315 )
316 DEFAULT_USER = 'default'
316 DEFAULT_USER = 'default'
317 DEFAULT_PERMISSIONS = [
317 DEFAULT_PERMISSIONS = [
318 'hg.register.manual_activate', 'hg.create.repository',
318 'hg.register.manual_activate', 'hg.create.repository',
319 'hg.fork.repository', 'repository.read', 'group.read'
319 'hg.fork.repository', 'repository.read', 'group.read'
320 ]
320 ]
321 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
321 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
322 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
322 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
323 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
323 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
324 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
324 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
325 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
325 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
326 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
329 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
330 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
330 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
332 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
332 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
333
333
334 user_log = relationship('UserLog')
334 user_log = relationship('UserLog')
335 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
335 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
336
336
337 repositories = relationship('Repository')
337 repositories = relationship('Repository')
338 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
338 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
339 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
339 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
340
340
341 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
341 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
342 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
342 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
343
343
344 group_member = relationship('UsersGroupMember', cascade='all')
344 group_member = relationship('UsersGroupMember', cascade='all')
345
345
346 notifications = relationship('UserNotification', cascade='all')
346 notifications = relationship('UserNotification', cascade='all')
347 # notifications assigned to this user
347 # notifications assigned to this user
348 user_created_notifications = relationship('Notification', cascade='all')
348 user_created_notifications = relationship('Notification', cascade='all')
349 # comments created by this user
349 # comments created by this user
350 user_comments = relationship('ChangesetComment', cascade='all')
350 user_comments = relationship('ChangesetComment', cascade='all')
351 #extra emails for this user
351 #extra emails for this user
352 user_emails = relationship('UserEmailMap', cascade='all')
352 user_emails = relationship('UserEmailMap', cascade='all')
353
353
354 @hybrid_property
354 @hybrid_property
355 def email(self):
355 def email(self):
356 return self._email
356 return self._email
357
357
358 @email.setter
358 @email.setter
359 def email(self, val):
359 def email(self, val):
360 self._email = val.lower() if val else None
360 self._email = val.lower() if val else None
361
361
362 @property
362 @property
363 def firstname(self):
363 def firstname(self):
364 # alias for future
364 # alias for future
365 return self.name
365 return self.name
366
366
367 @property
367 @property
368 def emails(self):
368 def emails(self):
369 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
369 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
370 return [self.email] + [x.email for x in other]
370 return [self.email] + [x.email for x in other]
371
371
372 @property
372 @property
373 def ip_addresses(self):
373 def ip_addresses(self):
374 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
374 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
375 return [x.ip_addr for x in ret]
375 return [x.ip_addr for x in ret]
376
376
377 @property
377 @property
378 def username_and_name(self):
378 def username_and_name(self):
379 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
379 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
380
380
381 @property
381 @property
382 def full_name(self):
382 def full_name(self):
383 return '%s %s' % (self.firstname, self.lastname)
383 return '%s %s' % (self.firstname, self.lastname)
384
384
385 @property
385 @property
386 def full_name_or_username(self):
386 def full_name_or_username(self):
387 return ('%s %s' % (self.firstname, self.lastname)
387 return ('%s %s' % (self.firstname, self.lastname)
388 if (self.firstname and self.lastname) else self.username)
388 if (self.firstname and self.lastname) else self.username)
389
389
390 @property
390 @property
391 def full_contact(self):
391 def full_contact(self):
392 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
392 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
393
393
394 @property
394 @property
395 def short_contact(self):
395 def short_contact(self):
396 return '%s %s' % (self.firstname, self.lastname)
396 return '%s %s' % (self.firstname, self.lastname)
397
397
398 @property
398 @property
399 def is_admin(self):
399 def is_admin(self):
400 return self.admin
400 return self.admin
401
401
402 def __unicode__(self):
402 def __unicode__(self):
403 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
403 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
404 self.user_id, self.username)
404 self.user_id, self.username)
405
405
406 @classmethod
406 @classmethod
407 def get_by_username(cls, username, case_insensitive=False, cache=False):
407 def get_by_username(cls, username, case_insensitive=False, cache=False):
408 if case_insensitive:
408 if case_insensitive:
409 q = cls.query().filter(cls.username.ilike(username))
409 q = cls.query().filter(cls.username.ilike(username))
410 else:
410 else:
411 q = cls.query().filter(cls.username == username)
411 q = cls.query().filter(cls.username == username)
412
412
413 if cache:
413 if cache:
414 q = q.options(FromCache(
414 q = q.options(FromCache(
415 "sql_cache_short",
415 "sql_cache_short",
416 "get_user_%s" % _hash_key(username)
416 "get_user_%s" % _hash_key(username)
417 )
417 )
418 )
418 )
419 return q.scalar()
419 return q.scalar()
420
420
421 @classmethod
421 @classmethod
422 def get_by_api_key(cls, api_key, cache=False):
422 def get_by_api_key(cls, api_key, cache=False):
423 q = cls.query().filter(cls.api_key == api_key)
423 q = cls.query().filter(cls.api_key == api_key)
424
424
425 if cache:
425 if cache:
426 q = q.options(FromCache("sql_cache_short",
426 q = q.options(FromCache("sql_cache_short",
427 "get_api_key_%s" % api_key))
427 "get_api_key_%s" % api_key))
428 return q.scalar()
428 return q.scalar()
429
429
430 @classmethod
430 @classmethod
431 def get_by_email(cls, email, case_insensitive=False, cache=False):
431 def get_by_email(cls, email, case_insensitive=False, cache=False):
432 if case_insensitive:
432 if case_insensitive:
433 q = cls.query().filter(cls.email.ilike(email))
433 q = cls.query().filter(cls.email.ilike(email))
434 else:
434 else:
435 q = cls.query().filter(cls.email == email)
435 q = cls.query().filter(cls.email == email)
436
436
437 if cache:
437 if cache:
438 q = q.options(FromCache("sql_cache_short",
438 q = q.options(FromCache("sql_cache_short",
439 "get_email_key_%s" % email))
439 "get_email_key_%s" % email))
440
440
441 ret = q.scalar()
441 ret = q.scalar()
442 if ret is None:
442 if ret is None:
443 q = UserEmailMap.query()
443 q = UserEmailMap.query()
444 # try fetching in alternate email map
444 # try fetching in alternate email map
445 if case_insensitive:
445 if case_insensitive:
446 q = q.filter(UserEmailMap.email.ilike(email))
446 q = q.filter(UserEmailMap.email.ilike(email))
447 else:
447 else:
448 q = q.filter(UserEmailMap.email == email)
448 q = q.filter(UserEmailMap.email == email)
449 q = q.options(joinedload(UserEmailMap.user))
449 q = q.options(joinedload(UserEmailMap.user))
450 if cache:
450 if cache:
451 q = q.options(FromCache("sql_cache_short",
451 q = q.options(FromCache("sql_cache_short",
452 "get_email_map_key_%s" % email))
452 "get_email_map_key_%s" % email))
453 ret = getattr(q.scalar(), 'user', None)
453 ret = getattr(q.scalar(), 'user', None)
454
454
455 return ret
455 return ret
456
456
457 @classmethod
457 @classmethod
458 def get_from_cs_author(cls, author):
458 def get_from_cs_author(cls, author):
459 """
459 """
460 Tries to get User objects out of commit author string
460 Tries to get User objects out of commit author string
461
461
462 :param author:
462 :param author:
463 """
463 """
464 from rhodecode.lib.helpers import email, author_name
464 from rhodecode.lib.helpers import email, author_name
465 # Valid email in the attribute passed, see if they're in the system
465 # Valid email in the attribute passed, see if they're in the system
466 _email = email(author)
466 _email = email(author)
467 if _email:
467 if _email:
468 user = cls.get_by_email(_email, case_insensitive=True)
468 user = cls.get_by_email(_email, case_insensitive=True)
469 if user:
469 if user:
470 return user
470 return user
471 # Maybe we can match by username?
471 # Maybe we can match by username?
472 _author = author_name(author)
472 _author = author_name(author)
473 user = cls.get_by_username(_author, case_insensitive=True)
473 user = cls.get_by_username(_author, case_insensitive=True)
474 if user:
474 if user:
475 return user
475 return user
476
476
477 def update_lastlogin(self):
477 def update_lastlogin(self):
478 """Update user lastlogin"""
478 """Update user lastlogin"""
479 self.last_login = datetime.datetime.now()
479 self.last_login = datetime.datetime.now()
480 Session().add(self)
480 Session().add(self)
481 log.debug('updated user %s lastlogin' % self.username)
481 log.debug('updated user %s lastlogin' % self.username)
482
482
483 def get_api_data(self):
483 def get_api_data(self):
484 """
484 """
485 Common function for generating user related data for API
485 Common function for generating user related data for API
486 """
486 """
487 user = self
487 user = self
488 data = dict(
488 data = dict(
489 user_id=user.user_id,
489 user_id=user.user_id,
490 username=user.username,
490 username=user.username,
491 firstname=user.name,
491 firstname=user.name,
492 lastname=user.lastname,
492 lastname=user.lastname,
493 email=user.email,
493 email=user.email,
494 emails=user.emails,
494 emails=user.emails,
495 api_key=user.api_key,
495 api_key=user.api_key,
496 active=user.active,
496 active=user.active,
497 admin=user.admin,
497 admin=user.admin,
498 ldap_dn=user.ldap_dn,
498 ldap_dn=user.ldap_dn,
499 last_login=user.last_login,
499 last_login=user.last_login,
500 ip_addresses=user.ip_addresses
500 ip_addresses=user.ip_addresses
501 )
501 )
502 return data
502 return data
503
503
504 def __json__(self):
504 def __json__(self):
505 data = dict(
505 data = dict(
506 full_name=self.full_name,
506 full_name=self.full_name,
507 full_name_or_username=self.full_name_or_username,
507 full_name_or_username=self.full_name_or_username,
508 short_contact=self.short_contact,
508 short_contact=self.short_contact,
509 full_contact=self.full_contact
509 full_contact=self.full_contact
510 )
510 )
511 data.update(self.get_api_data())
511 data.update(self.get_api_data())
512 return data
512 return data
513
513
514
514
515 class UserEmailMap(Base, BaseModel):
515 class UserEmailMap(Base, BaseModel):
516 __tablename__ = 'user_email_map'
516 __tablename__ = 'user_email_map'
517 __table_args__ = (
517 __table_args__ = (
518 Index('uem_email_idx', 'email'),
518 Index('uem_email_idx', 'email'),
519 UniqueConstraint('email'),
519 UniqueConstraint('email'),
520 {'extend_existing': True, 'mysql_engine': 'InnoDB',
520 {'extend_existing': True, 'mysql_engine': 'InnoDB',
521 'mysql_charset': 'utf8'}
521 'mysql_charset': 'utf8'}
522 )
522 )
523 __mapper_args__ = {}
523 __mapper_args__ = {}
524
524
525 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
525 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
526 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
526 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
527 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
527 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
528 user = relationship('User', lazy='joined')
528 user = relationship('User', lazy='joined')
529
529
530 @validates('_email')
530 @validates('_email')
531 def validate_email(self, key, email):
531 def validate_email(self, key, email):
532 # check if this email is not main one
532 # check if this email is not main one
533 main_email = Session().query(User).filter(User.email == email).scalar()
533 main_email = Session().query(User).filter(User.email == email).scalar()
534 if main_email is not None:
534 if main_email is not None:
535 raise AttributeError('email %s is present is user table' % email)
535 raise AttributeError('email %s is present is user table' % email)
536 return email
536 return email
537
537
538 @hybrid_property
538 @hybrid_property
539 def email(self):
539 def email(self):
540 return self._email
540 return self._email
541
541
542 @email.setter
542 @email.setter
543 def email(self, val):
543 def email(self, val):
544 self._email = val.lower() if val else None
544 self._email = val.lower() if val else None
545
545
546
546
547 class UserIpMap(Base, BaseModel):
547 class UserIpMap(Base, BaseModel):
548 __tablename__ = 'user_ip_map'
548 __tablename__ = 'user_ip_map'
549 __table_args__ = (
549 __table_args__ = (
550 UniqueConstraint('user_id', 'ip_addr'),
550 UniqueConstraint('user_id', 'ip_addr'),
551 {'extend_existing': True, 'mysql_engine': 'InnoDB',
551 {'extend_existing': True, 'mysql_engine': 'InnoDB',
552 'mysql_charset': 'utf8'}
552 'mysql_charset': 'utf8'}
553 )
553 )
554 __mapper_args__ = {}
554 __mapper_args__ = {}
555
555
556 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
556 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
557 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
557 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
558 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
558 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
559 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
559 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
560 user = relationship('User', lazy='joined')
560 user = relationship('User', lazy='joined')
561
561
562 @classmethod
562 @classmethod
563 def _get_ip_range(cls, ip_addr):
563 def _get_ip_range(cls, ip_addr):
564 from rhodecode.lib import ipaddr
564 from rhodecode.lib import ipaddr
565 net = ipaddr.IPNetwork(address=ip_addr)
565 net = ipaddr.IPNetwork(address=ip_addr)
566 return [str(net.network), str(net.broadcast)]
566 return [str(net.network), str(net.broadcast)]
567
567
568 def __json__(self):
568 def __json__(self):
569 return dict(
569 return dict(
570 ip_addr=self.ip_addr,
570 ip_addr=self.ip_addr,
571 ip_range=self._get_ip_range(self.ip_addr)
571 ip_range=self._get_ip_range(self.ip_addr)
572 )
572 )
573
573
574
574
575 class UserLog(Base, BaseModel):
575 class UserLog(Base, BaseModel):
576 __tablename__ = 'user_logs'
576 __tablename__ = 'user_logs'
577 __table_args__ = (
577 __table_args__ = (
578 {'extend_existing': True, 'mysql_engine': 'InnoDB',
578 {'extend_existing': True, 'mysql_engine': 'InnoDB',
579 'mysql_charset': 'utf8'},
579 'mysql_charset': 'utf8'},
580 )
580 )
581 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
581 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
582 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
582 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
583 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
583 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
584 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
584 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
585 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
585 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
586 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
586 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
587 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
587 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
588 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
588 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
589
589
590 @property
590 @property
591 def action_as_day(self):
591 def action_as_day(self):
592 return datetime.date(*self.action_date.timetuple()[:3])
592 return datetime.date(*self.action_date.timetuple()[:3])
593
593
594 user = relationship('User')
594 user = relationship('User')
595 repository = relationship('Repository', cascade='')
595 repository = relationship('Repository', cascade='')
596
596
597
597
598 class UsersGroup(Base, BaseModel):
598 class UsersGroup(Base, BaseModel):
599 __tablename__ = 'users_groups'
599 __tablename__ = 'users_groups'
600 __table_args__ = (
600 __table_args__ = (
601 {'extend_existing': True, 'mysql_engine': 'InnoDB',
601 {'extend_existing': True, 'mysql_engine': 'InnoDB',
602 'mysql_charset': 'utf8'},
602 'mysql_charset': 'utf8'},
603 )
603 )
604
604
605 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
605 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
606 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
606 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
607 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
607 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
608 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
608 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
609
609
610 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
610 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
611 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
611 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
612 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
612 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
613
613
614 def __unicode__(self):
614 def __unicode__(self):
615 return u'<userGroup(%s)>' % (self.users_group_name)
615 return u'<userGroup(%s)>' % (self.users_group_name)
616
616
617 @classmethod
617 @classmethod
618 def get_by_group_name(cls, group_name, cache=False,
618 def get_by_group_name(cls, group_name, cache=False,
619 case_insensitive=False):
619 case_insensitive=False):
620 if case_insensitive:
620 if case_insensitive:
621 q = cls.query().filter(cls.users_group_name.ilike(group_name))
621 q = cls.query().filter(cls.users_group_name.ilike(group_name))
622 else:
622 else:
623 q = cls.query().filter(cls.users_group_name == group_name)
623 q = cls.query().filter(cls.users_group_name == group_name)
624 if cache:
624 if cache:
625 q = q.options(FromCache(
625 q = q.options(FromCache(
626 "sql_cache_short",
626 "sql_cache_short",
627 "get_user_%s" % _hash_key(group_name)
627 "get_user_%s" % _hash_key(group_name)
628 )
628 )
629 )
629 )
630 return q.scalar()
630 return q.scalar()
631
631
632 @classmethod
632 @classmethod
633 def get(cls, users_group_id, cache=False):
633 def get(cls, users_group_id, cache=False):
634 users_group = cls.query()
634 users_group = cls.query()
635 if cache:
635 if cache:
636 users_group = users_group.options(FromCache("sql_cache_short",
636 users_group = users_group.options(FromCache("sql_cache_short",
637 "get_users_group_%s" % users_group_id))
637 "get_users_group_%s" % users_group_id))
638 return users_group.get(users_group_id)
638 return users_group.get(users_group_id)
639
639
640 def get_api_data(self):
640 def get_api_data(self):
641 users_group = self
641 users_group = self
642
642
643 data = dict(
643 data = dict(
644 users_group_id=users_group.users_group_id,
644 users_group_id=users_group.users_group_id,
645 group_name=users_group.users_group_name,
645 group_name=users_group.users_group_name,
646 active=users_group.users_group_active,
646 active=users_group.users_group_active,
647 )
647 )
648
648
649 return data
649 return data
650
650
651
651
652 class UsersGroupMember(Base, BaseModel):
652 class UsersGroupMember(Base, BaseModel):
653 __tablename__ = 'users_groups_members'
653 __tablename__ = 'users_groups_members'
654 __table_args__ = (
654 __table_args__ = (
655 {'extend_existing': True, 'mysql_engine': 'InnoDB',
655 {'extend_existing': True, 'mysql_engine': 'InnoDB',
656 'mysql_charset': 'utf8'},
656 'mysql_charset': 'utf8'},
657 )
657 )
658
658
659 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
659 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
660 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
660 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
661 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
661 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
662
662
663 user = relationship('User', lazy='joined')
663 user = relationship('User', lazy='joined')
664 users_group = relationship('UsersGroup')
664 users_group = relationship('UsersGroup')
665
665
666 def __init__(self, gr_id='', u_id=''):
666 def __init__(self, gr_id='', u_id=''):
667 self.users_group_id = gr_id
667 self.users_group_id = gr_id
668 self.user_id = u_id
668 self.user_id = u_id
669
669
670
670
671 class Repository(Base, BaseModel):
671 class Repository(Base, BaseModel):
672 __tablename__ = 'repositories'
672 __tablename__ = 'repositories'
673 __table_args__ = (
673 __table_args__ = (
674 UniqueConstraint('repo_name'),
674 UniqueConstraint('repo_name'),
675 Index('r_repo_name_idx', 'repo_name'),
675 Index('r_repo_name_idx', 'repo_name'),
676 {'extend_existing': True, 'mysql_engine': 'InnoDB',
676 {'extend_existing': True, 'mysql_engine': 'InnoDB',
677 'mysql_charset': 'utf8'},
677 'mysql_charset': 'utf8'},
678 )
678 )
679
679
680 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
680 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
681 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
681 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
682 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
682 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
683 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
683 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
684 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
684 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
685 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
685 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
686 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
686 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
687 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
687 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
688 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
688 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
689 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
689 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
690 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
690 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
691 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
691 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
692 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
692 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
693 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
693 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
694 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
694 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
695
695
696 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
696 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
697 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
697 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
698
698
699 user = relationship('User')
699 user = relationship('User')
700 fork = relationship('Repository', remote_side=repo_id)
700 fork = relationship('Repository', remote_side=repo_id)
701 group = relationship('RepoGroup')
701 group = relationship('RepoGroup')
702 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
702 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
703 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
703 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
704 stats = relationship('Statistics', cascade='all', uselist=False)
704 stats = relationship('Statistics', cascade='all', uselist=False)
705
705
706 followers = relationship('UserFollowing',
706 followers = relationship('UserFollowing',
707 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
707 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
708 cascade='all')
708 cascade='all')
709
709
710 logs = relationship('UserLog')
710 logs = relationship('UserLog')
711 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
711 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
712
712
713 pull_requests_org = relationship('PullRequest',
713 pull_requests_org = relationship('PullRequest',
714 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
714 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
715 cascade="all, delete, delete-orphan")
715 cascade="all, delete, delete-orphan")
716
716
717 pull_requests_other = relationship('PullRequest',
717 pull_requests_other = relationship('PullRequest',
718 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
718 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
719 cascade="all, delete, delete-orphan")
719 cascade="all, delete, delete-orphan")
720
720
721 def __unicode__(self):
721 def __unicode__(self):
722 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
722 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
723 self.repo_name)
723 self.repo_name)
724
724
725 @hybrid_property
725 @hybrid_property
726 def locked(self):
726 def locked(self):
727 # always should return [user_id, timelocked]
727 # always should return [user_id, timelocked]
728 if self._locked:
728 if self._locked:
729 _lock_info = self._locked.split(':')
729 _lock_info = self._locked.split(':')
730 return int(_lock_info[0]), _lock_info[1]
730 return int(_lock_info[0]), _lock_info[1]
731 return [None, None]
731 return [None, None]
732
732
733 @locked.setter
733 @locked.setter
734 def locked(self, val):
734 def locked(self, val):
735 if val and isinstance(val, (list, tuple)):
735 if val and isinstance(val, (list, tuple)):
736 self._locked = ':'.join(map(str, val))
736 self._locked = ':'.join(map(str, val))
737 else:
737 else:
738 self._locked = None
738 self._locked = None
739
739
740 @hybrid_property
740 @hybrid_property
741 def changeset_cache(self):
741 def changeset_cache(self):
742 from rhodecode.lib.vcs.backends.base import EmptyChangeset
742 from rhodecode.lib.vcs.backends.base import EmptyChangeset
743 dummy = EmptyChangeset().__json__()
743 dummy = EmptyChangeset().__json__()
744 if not self._changeset_cache:
744 if not self._changeset_cache:
745 return dummy
745 return dummy
746 try:
746 try:
747 return json.loads(self._changeset_cache)
747 return json.loads(self._changeset_cache)
748 except TypeError:
748 except TypeError:
749 return dummy
749 return dummy
750
750
751 @changeset_cache.setter
751 @changeset_cache.setter
752 def changeset_cache(self, val):
752 def changeset_cache(self, val):
753 try:
753 try:
754 self._changeset_cache = json.dumps(val)
754 self._changeset_cache = json.dumps(val)
755 except:
755 except:
756 log.error(traceback.format_exc())
756 log.error(traceback.format_exc())
757
757
758 @classmethod
758 @classmethod
759 def url_sep(cls):
759 def url_sep(cls):
760 return URL_SEP
760 return URL_SEP
761
761
762 @classmethod
762 @classmethod
763 def normalize_repo_name(cls, repo_name):
763 def normalize_repo_name(cls, repo_name):
764 """
764 """
765 Normalizes os specific repo_name to the format internally stored inside
765 Normalizes os specific repo_name to the format internally stored inside
766 dabatabase using URL_SEP
766 dabatabase using URL_SEP
767
767
768 :param cls:
768 :param cls:
769 :param repo_name:
769 :param repo_name:
770 """
770 """
771 return cls.url_sep().join(repo_name.split(os.sep))
771 return cls.url_sep().join(repo_name.split(os.sep))
772
772
773 @classmethod
773 @classmethod
774 def get_by_repo_name(cls, repo_name):
774 def get_by_repo_name(cls, repo_name):
775 q = Session().query(cls).filter(cls.repo_name == repo_name)
775 q = Session().query(cls).filter(cls.repo_name == repo_name)
776 q = q.options(joinedload(Repository.fork))\
776 q = q.options(joinedload(Repository.fork))\
777 .options(joinedload(Repository.user))\
777 .options(joinedload(Repository.user))\
778 .options(joinedload(Repository.group))
778 .options(joinedload(Repository.group))
779 return q.scalar()
779 return q.scalar()
780
780
781 @classmethod
781 @classmethod
782 def get_by_full_path(cls, repo_full_path):
782 def get_by_full_path(cls, repo_full_path):
783 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
783 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
784 repo_name = cls.normalize_repo_name(repo_name)
784 repo_name = cls.normalize_repo_name(repo_name)
785 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
785 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
786
786
787 @classmethod
787 @classmethod
788 def get_repo_forks(cls, repo_id):
788 def get_repo_forks(cls, repo_id):
789 return cls.query().filter(Repository.fork_id == repo_id)
789 return cls.query().filter(Repository.fork_id == repo_id)
790
790
791 @classmethod
791 @classmethod
792 def base_path(cls):
792 def base_path(cls):
793 """
793 """
794 Returns base path when all repos are stored
794 Returns base path when all repos are stored
795
795
796 :param cls:
796 :param cls:
797 """
797 """
798 q = Session().query(RhodeCodeUi)\
798 q = Session().query(RhodeCodeUi)\
799 .filter(RhodeCodeUi.ui_key == cls.url_sep())
799 .filter(RhodeCodeUi.ui_key == cls.url_sep())
800 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
800 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
801 return q.one().ui_value
801 return q.one().ui_value
802
802
803 @property
803 @property
804 def forks(self):
804 def forks(self):
805 """
805 """
806 Return forks of this repo
806 Return forks of this repo
807 """
807 """
808 return Repository.get_repo_forks(self.repo_id)
808 return Repository.get_repo_forks(self.repo_id)
809
809
810 @property
810 @property
811 def parent(self):
811 def parent(self):
812 """
812 """
813 Returns fork parent
813 Returns fork parent
814 """
814 """
815 return self.fork
815 return self.fork
816
816
817 @property
817 @property
818 def just_name(self):
818 def just_name(self):
819 return self.repo_name.split(Repository.url_sep())[-1]
819 return self.repo_name.split(Repository.url_sep())[-1]
820
820
821 @property
821 @property
822 def groups_with_parents(self):
822 def groups_with_parents(self):
823 groups = []
823 groups = []
824 if self.group is None:
824 if self.group is None:
825 return groups
825 return groups
826
826
827 cur_gr = self.group
827 cur_gr = self.group
828 groups.insert(0, cur_gr)
828 groups.insert(0, cur_gr)
829 while 1:
829 while 1:
830 gr = getattr(cur_gr, 'parent_group', None)
830 gr = getattr(cur_gr, 'parent_group', None)
831 cur_gr = cur_gr.parent_group
831 cur_gr = cur_gr.parent_group
832 if gr is None:
832 if gr is None:
833 break
833 break
834 groups.insert(0, gr)
834 groups.insert(0, gr)
835
835
836 return groups
836 return groups
837
837
838 @property
838 @property
839 def groups_and_repo(self):
839 def groups_and_repo(self):
840 return self.groups_with_parents, self.just_name
840 return self.groups_with_parents, self.just_name
841
841
842 @LazyProperty
842 @LazyProperty
843 def repo_path(self):
843 def repo_path(self):
844 """
844 """
845 Returns base full path for that repository means where it actually
845 Returns base full path for that repository means where it actually
846 exists on a filesystem
846 exists on a filesystem
847 """
847 """
848 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
848 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
849 Repository.url_sep())
849 Repository.url_sep())
850 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
850 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
851 return q.one().ui_value
851 return q.one().ui_value
852
852
853 @property
853 @property
854 def repo_full_path(self):
854 def repo_full_path(self):
855 p = [self.repo_path]
855 p = [self.repo_path]
856 # we need to split the name by / since this is how we store the
856 # we need to split the name by / since this is how we store the
857 # names in the database, but that eventually needs to be converted
857 # names in the database, but that eventually needs to be converted
858 # into a valid system path
858 # into a valid system path
859 p += self.repo_name.split(Repository.url_sep())
859 p += self.repo_name.split(Repository.url_sep())
860 return os.path.join(*p)
860 return os.path.join(*p)
861
861
862 @property
862 @property
863 def cache_keys(self):
863 def cache_keys(self):
864 """
864 """
865 Returns associated cache keys for that repo
865 Returns associated cache keys for that repo
866 """
866 """
867 return CacheInvalidation.query()\
867 return CacheInvalidation.query()\
868 .filter(CacheInvalidation.cache_args == self.repo_name)\
868 .filter(CacheInvalidation.cache_args == self.repo_name)\
869 .order_by(CacheInvalidation.cache_key)\
869 .order_by(CacheInvalidation.cache_key)\
870 .all()
870 .all()
871
871
872 def get_new_name(self, repo_name):
872 def get_new_name(self, repo_name):
873 """
873 """
874 returns new full repository name based on assigned group and new new
874 returns new full repository name based on assigned group and new new
875
875
876 :param group_name:
876 :param group_name:
877 """
877 """
878 path_prefix = self.group.full_path_splitted if self.group else []
878 path_prefix = self.group.full_path_splitted if self.group else []
879 return Repository.url_sep().join(path_prefix + [repo_name])
879 return Repository.url_sep().join(path_prefix + [repo_name])
880
880
881 @property
881 @property
882 def _ui(self):
882 def _ui(self):
883 """
883 """
884 Creates an db based ui object for this repository
884 Creates an db based ui object for this repository
885 """
885 """
886 from rhodecode.lib.utils import make_ui
886 from rhodecode.lib.utils import make_ui
887 return make_ui('db', clear_session=False)
887 return make_ui('db', clear_session=False)
888
888
889 @classmethod
889 @classmethod
890 def inject_ui(cls, repo, extras={}):
890 def inject_ui(cls, repo, extras={}):
891 from rhodecode.lib.vcs.backends.hg import MercurialRepository
891 from rhodecode.lib.vcs.backends.hg import MercurialRepository
892 from rhodecode.lib.vcs.backends.git import GitRepository
892 from rhodecode.lib.vcs.backends.git import GitRepository
893 required = (MercurialRepository, GitRepository)
893 required = (MercurialRepository, GitRepository)
894 if not isinstance(repo, required):
894 if not isinstance(repo, required):
895 raise Exception('repo must be instance of %s' % required)
895 raise Exception('repo must be instance of %s' % required)
896
896
897 # inject ui extra param to log this action via push logger
897 # inject ui extra param to log this action via push logger
898 for k, v in extras.items():
898 for k, v in extras.items():
899 repo._repo.ui.setconfig('rhodecode_extras', k, v)
899 repo._repo.ui.setconfig('rhodecode_extras', k, v)
900
900
901 @classmethod
901 @classmethod
902 def is_valid(cls, repo_name):
902 def is_valid(cls, repo_name):
903 """
903 """
904 returns True if given repo name is a valid filesystem repository
904 returns True if given repo name is a valid filesystem repository
905
905
906 :param cls:
906 :param cls:
907 :param repo_name:
907 :param repo_name:
908 """
908 """
909 from rhodecode.lib.utils import is_valid_repo
909 from rhodecode.lib.utils import is_valid_repo
910
910
911 return is_valid_repo(repo_name, cls.base_path())
911 return is_valid_repo(repo_name, cls.base_path())
912
912
913 def get_api_data(self):
913 def get_api_data(self):
914 """
914 """
915 Common function for generating repo api data
915 Common function for generating repo api data
916
916
917 """
917 """
918 repo = self
918 repo = self
919 data = dict(
919 data = dict(
920 repo_id=repo.repo_id,
920 repo_id=repo.repo_id,
921 repo_name=repo.repo_name,
921 repo_name=repo.repo_name,
922 repo_type=repo.repo_type,
922 repo_type=repo.repo_type,
923 clone_uri=repo.clone_uri,
923 clone_uri=repo.clone_uri,
924 private=repo.private,
924 private=repo.private,
925 created_on=repo.created_on,
925 created_on=repo.created_on,
926 description=repo.description,
926 description=repo.description,
927 landing_rev=repo.landing_rev,
927 landing_rev=repo.landing_rev,
928 owner=repo.user.username,
928 owner=repo.user.username,
929 fork_of=repo.fork.repo_name if repo.fork else None,
929 fork_of=repo.fork.repo_name if repo.fork else None,
930 enable_statistics=repo.enable_statistics,
930 enable_statistics=repo.enable_statistics,
931 enable_locking=repo.enable_locking,
931 enable_locking=repo.enable_locking,
932 enable_downloads=repo.enable_downloads,
932 enable_downloads=repo.enable_downloads,
933 last_changeset=repo.changeset_cache
933 last_changeset=repo.changeset_cache
934 )
934 )
935
935
936 return data
936 return data
937
937
938 @classmethod
938 @classmethod
939 def lock(cls, repo, user_id):
939 def lock(cls, repo, user_id):
940 repo.locked = [user_id, time.time()]
940 repo.locked = [user_id, time.time()]
941 Session().add(repo)
941 Session().add(repo)
942 Session().commit()
942 Session().commit()
943
943
944 @classmethod
944 @classmethod
945 def unlock(cls, repo):
945 def unlock(cls, repo):
946 repo.locked = None
946 repo.locked = None
947 Session().add(repo)
947 Session().add(repo)
948 Session().commit()
948 Session().commit()
949
949
950 @property
950 @property
951 def last_db_change(self):
951 def last_db_change(self):
952 return self.updated_on
952 return self.updated_on
953
953
954 def clone_url(self, **override):
954 def clone_url(self, **override):
955 from pylons import url
955 from pylons import url
956 from urlparse import urlparse
956 from urlparse import urlparse
957 import urllib
957 import urllib
958 parsed_url = urlparse(url('home', qualified=True))
958 parsed_url = urlparse(url('home', qualified=True))
959 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
959 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
960 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
960 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
961 args = {
961 args = {
962 'user': '',
962 'user': '',
963 'pass': '',
963 'pass': '',
964 'scheme': parsed_url.scheme,
964 'scheme': parsed_url.scheme,
965 'netloc': parsed_url.netloc,
965 'netloc': parsed_url.netloc,
966 'prefix': decoded_path,
966 'prefix': decoded_path,
967 'path': self.repo_name
967 'path': self.repo_name
968 }
968 }
969
969
970 args.update(override)
970 args.update(override)
971 return default_clone_uri % args
971 return default_clone_uri % args
972
972
973 #==========================================================================
973 #==========================================================================
974 # SCM PROPERTIES
974 # SCM PROPERTIES
975 #==========================================================================
975 #==========================================================================
976
976
977 def get_changeset(self, rev=None):
977 def get_changeset(self, rev=None):
978 return get_changeset_safe(self.scm_instance, rev)
978 return get_changeset_safe(self.scm_instance, rev)
979
979
980 def get_landing_changeset(self):
980 def get_landing_changeset(self):
981 """
981 """
982 Returns landing changeset, or if that doesn't exist returns the tip
982 Returns landing changeset, or if that doesn't exist returns the tip
983 """
983 """
984 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
984 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
985 return cs
985 return cs
986
986
987 def update_changeset_cache(self, cs_cache=None):
987 def update_changeset_cache(self, cs_cache=None):
988 """
988 """
989 Update cache of last changeset for repository, keys should be::
989 Update cache of last changeset for repository, keys should be::
990
990
991 short_id
991 short_id
992 raw_id
992 raw_id
993 revision
993 revision
994 message
994 message
995 date
995 date
996 author
996 author
997
997
998 :param cs_cache:
998 :param cs_cache:
999 """
999 """
1000 from rhodecode.lib.vcs.backends.base import BaseChangeset
1000 from rhodecode.lib.vcs.backends.base import BaseChangeset
1001 if cs_cache is None:
1001 if cs_cache is None:
1002 cs_cache = self.get_changeset()
1002 cs_cache = self.get_changeset()
1003 if isinstance(cs_cache, BaseChangeset):
1003 if isinstance(cs_cache, BaseChangeset):
1004 cs_cache = cs_cache.__json__()
1004 cs_cache = cs_cache.__json__()
1005
1005
1006 if (cs_cache != self.changeset_cache
1006 if (cs_cache != self.changeset_cache
1007 or not self.last_change
1007 or not self.last_change
1008 or not self.changeset_cache):
1008 or not self.changeset_cache):
1009 _default = datetime.datetime.fromtimestamp(0)
1009 _default = datetime.datetime.fromtimestamp(0)
1010 last_change = cs_cache.get('date') or self.last_change or _default
1010 last_change = cs_cache.get('date') or self.last_change or _default
1011 log.debug('updated repo %s with new cs cache %s' % (self, cs_cache))
1011 log.debug('updated repo %s with new cs cache %s' % (self, cs_cache))
1012 self.updated_on = last_change
1012 self.updated_on = last_change
1013 self.changeset_cache = cs_cache
1013 self.changeset_cache = cs_cache
1014 Session().add(self)
1014 Session().add(self)
1015 Session().commit()
1015 Session().commit()
1016 else:
1016 else:
1017 log.debug('Skipping repo:%s already with latest changes' % self)
1017 log.debug('Skipping repo:%s already with latest changes' % self)
1018
1018
1019 @property
1019 @property
1020 def tip(self):
1020 def tip(self):
1021 return self.get_changeset('tip')
1021 return self.get_changeset('tip')
1022
1022
1023 @property
1023 @property
1024 def author(self):
1024 def author(self):
1025 return self.tip.author
1025 return self.tip.author
1026
1026
1027 @property
1027 @property
1028 def last_change(self):
1028 def last_change(self):
1029 return self.scm_instance.last_change
1029 return self.scm_instance.last_change
1030
1030
1031 def get_comments(self, revisions=None):
1031 def get_comments(self, revisions=None):
1032 """
1032 """
1033 Returns comments for this repository grouped by revisions
1033 Returns comments for this repository grouped by revisions
1034
1034
1035 :param revisions: filter query by revisions only
1035 :param revisions: filter query by revisions only
1036 """
1036 """
1037 cmts = ChangesetComment.query()\
1037 cmts = ChangesetComment.query()\
1038 .filter(ChangesetComment.repo == self)
1038 .filter(ChangesetComment.repo == self)
1039 if revisions:
1039 if revisions:
1040 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1040 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1041 grouped = defaultdict(list)
1041 grouped = defaultdict(list)
1042 for cmt in cmts.all():
1042 for cmt in cmts.all():
1043 grouped[cmt.revision].append(cmt)
1043 grouped[cmt.revision].append(cmt)
1044 return grouped
1044 return grouped
1045
1045
1046 def statuses(self, revisions=None):
1046 def statuses(self, revisions=None):
1047 """
1047 """
1048 Returns statuses for this repository
1048 Returns statuses for this repository
1049
1049
1050 :param revisions: list of revisions to get statuses for
1050 :param revisions: list of revisions to get statuses for
1051 :type revisions: list
1051 :type revisions: list
1052 """
1052 """
1053
1053
1054 statuses = ChangesetStatus.query()\
1054 statuses = ChangesetStatus.query()\
1055 .filter(ChangesetStatus.repo == self)\
1055 .filter(ChangesetStatus.repo == self)\
1056 .filter(ChangesetStatus.version == 0)
1056 .filter(ChangesetStatus.version == 0)
1057 if revisions:
1057 if revisions:
1058 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1058 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1059 grouped = {}
1059 grouped = {}
1060
1060
1061 #maybe we have open new pullrequest without a status ?
1061 #maybe we have open new pullrequest without a status ?
1062 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1062 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1063 status_lbl = ChangesetStatus.get_status_lbl(stat)
1063 status_lbl = ChangesetStatus.get_status_lbl(stat)
1064 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1064 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1065 for rev in pr.revisions:
1065 for rev in pr.revisions:
1066 pr_id = pr.pull_request_id
1066 pr_id = pr.pull_request_id
1067 pr_repo = pr.other_repo.repo_name
1067 pr_repo = pr.other_repo.repo_name
1068 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1068 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1069
1069
1070 for stat in statuses.all():
1070 for stat in statuses.all():
1071 pr_id = pr_repo = None
1071 pr_id = pr_repo = None
1072 if stat.pull_request:
1072 if stat.pull_request:
1073 pr_id = stat.pull_request.pull_request_id
1073 pr_id = stat.pull_request.pull_request_id
1074 pr_repo = stat.pull_request.other_repo.repo_name
1074 pr_repo = stat.pull_request.other_repo.repo_name
1075 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1075 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1076 pr_id, pr_repo]
1076 pr_id, pr_repo]
1077 return grouped
1077 return grouped
1078
1078
1079 def _repo_size(self):
1079 def _repo_size(self):
1080 from rhodecode.lib import helpers as h
1080 from rhodecode.lib import helpers as h
1081 log.debug('calculating repository size...')
1081 log.debug('calculating repository size...')
1082 return h.format_byte_size(self.scm_instance.size)
1082 return h.format_byte_size(self.scm_instance.size)
1083
1083
1084 #==========================================================================
1084 #==========================================================================
1085 # SCM CACHE INSTANCE
1085 # SCM CACHE INSTANCE
1086 #==========================================================================
1086 #==========================================================================
1087
1087
1088 @property
1088 @property
1089 def invalidate(self):
1089 def invalidate(self):
1090 return CacheInvalidation.invalidate(self.repo_name)
1090 return CacheInvalidation.invalidate(self.repo_name)
1091
1091
1092 def set_invalidate(self):
1092 def set_invalidate(self):
1093 """
1093 """
1094 set a cache for invalidation for this instance
1094 set a cache for invalidation for this instance
1095 """
1095 """
1096 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
1096 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
1097
1097
1098 @LazyProperty
1098 @LazyProperty
1099 def scm_instance(self):
1099 def scm_instance(self):
1100 import rhodecode
1100 import rhodecode
1101 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1101 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1102 if full_cache:
1102 if full_cache:
1103 return self.scm_instance_cached()
1103 return self.scm_instance_cached()
1104 return self.__get_instance()
1104 return self.__get_instance()
1105
1105
1106 def scm_instance_cached(self, cache_map=None):
1106 def scm_instance_cached(self, cache_map=None):
1107 @cache_region('long_term')
1107 @cache_region('long_term')
1108 def _c(repo_name):
1108 def _c(repo_name):
1109 return self.__get_instance()
1109 return self.__get_instance()
1110 rn = self.repo_name
1110 rn = self.repo_name
1111 log.debug('Getting cached instance of repo')
1111 log.debug('Getting cached instance of repo')
1112
1112
1113 if cache_map:
1113 if cache_map:
1114 # get using prefilled cache_map
1114 # get using prefilled cache_map
1115 invalidate_repo = cache_map[self.repo_name]
1115 invalidate_repo = cache_map[self.repo_name]
1116 if invalidate_repo:
1116 if invalidate_repo:
1117 invalidate_repo = (None if invalidate_repo.cache_active
1117 invalidate_repo = (None if invalidate_repo.cache_active
1118 else invalidate_repo)
1118 else invalidate_repo)
1119 else:
1119 else:
1120 # get from invalidate
1120 # get from invalidate
1121 invalidate_repo = self.invalidate
1121 invalidate_repo = self.invalidate
1122
1122
1123 if invalidate_repo is not None:
1123 if invalidate_repo is not None:
1124 region_invalidate(_c, None, rn)
1124 region_invalidate(_c, None, rn)
1125 # update our cache
1125 # update our cache
1126 CacheInvalidation.set_valid(invalidate_repo.cache_key)
1126 CacheInvalidation.set_valid(invalidate_repo.cache_key)
1127 return _c(rn)
1127 return _c(rn)
1128
1128
1129 def __get_instance(self):
1129 def __get_instance(self):
1130 repo_full_path = self.repo_full_path
1130 repo_full_path = self.repo_full_path
1131 try:
1131 try:
1132 alias = get_scm(repo_full_path)[0]
1132 alias = get_scm(repo_full_path)[0]
1133 log.debug('Creating instance of %s repository' % alias)
1133 log.debug('Creating instance of %s repository' % alias)
1134 backend = get_backend(alias)
1134 backend = get_backend(alias)
1135 except VCSError:
1135 except VCSError:
1136 log.error(traceback.format_exc())
1136 log.error(traceback.format_exc())
1137 log.error('Perhaps this repository is in db and not in '
1137 log.error('Perhaps this repository is in db and not in '
1138 'filesystem run rescan repositories with '
1138 'filesystem run rescan repositories with '
1139 '"destroy old data " option from admin panel')
1139 '"destroy old data " option from admin panel')
1140 return
1140 return
1141
1141
1142 if alias == 'hg':
1142 if alias == 'hg':
1143
1143
1144 repo = backend(safe_str(repo_full_path), create=False,
1144 repo = backend(safe_str(repo_full_path), create=False,
1145 baseui=self._ui)
1145 baseui=self._ui)
1146 # skip hidden web repository
1146 # skip hidden web repository
1147 if repo._get_hidden():
1147 if repo._get_hidden():
1148 return
1148 return
1149 else:
1149 else:
1150 repo = backend(repo_full_path, create=False)
1150 repo = backend(repo_full_path, create=False)
1151
1151
1152 return repo
1152 return repo
1153
1153
1154
1154
1155 class RepoGroup(Base, BaseModel):
1155 class RepoGroup(Base, BaseModel):
1156 __tablename__ = 'groups'
1156 __tablename__ = 'groups'
1157 __table_args__ = (
1157 __table_args__ = (
1158 UniqueConstraint('group_name', 'group_parent_id'),
1158 UniqueConstraint('group_name', 'group_parent_id'),
1159 CheckConstraint('group_id != group_parent_id'),
1159 CheckConstraint('group_id != group_parent_id'),
1160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1161 'mysql_charset': 'utf8'},
1161 'mysql_charset': 'utf8'},
1162 )
1162 )
1163 __mapper_args__ = {'order_by': 'group_name'}
1163 __mapper_args__ = {'order_by': 'group_name'}
1164
1164
1165 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1165 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1166 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1166 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1167 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1167 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1168 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1168 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1169 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1169 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1170
1170
1171 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1171 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1172 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1172 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1173
1173
1174 parent_group = relationship('RepoGroup', remote_side=group_id)
1174 parent_group = relationship('RepoGroup', remote_side=group_id)
1175
1175
1176 def __init__(self, group_name='', parent_group=None):
1176 def __init__(self, group_name='', parent_group=None):
1177 self.group_name = group_name
1177 self.group_name = group_name
1178 self.parent_group = parent_group
1178 self.parent_group = parent_group
1179
1179
1180 def __unicode__(self):
1180 def __unicode__(self):
1181 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1181 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1182 self.group_name)
1182 self.group_name)
1183
1183
1184 @classmethod
1184 @classmethod
1185 def groups_choices(cls, groups=None, show_empty_group=True):
1185 def groups_choices(cls, groups=None, show_empty_group=True):
1186 from webhelpers.html import literal as _literal
1186 from webhelpers.html import literal as _literal
1187 if not groups:
1187 if not groups:
1188 groups = cls.query().all()
1188 groups = cls.query().all()
1189
1189
1190 repo_groups = []
1190 repo_groups = []
1191 if show_empty_group:
1191 if show_empty_group:
1192 repo_groups = [('-1', '-- no parent --')]
1192 repo_groups = [('-1', '-- no parent --')]
1193 sep = ' &raquo; '
1193 sep = ' &raquo; '
1194 _name = lambda k: _literal(sep.join(k))
1194 _name = lambda k: _literal(sep.join(k))
1195
1195
1196 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1196 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1197 for x in groups])
1197 for x in groups])
1198
1198
1199 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1199 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1200 return repo_groups
1200 return repo_groups
1201
1201
1202 @classmethod
1202 @classmethod
1203 def url_sep(cls):
1203 def url_sep(cls):
1204 return URL_SEP
1204 return URL_SEP
1205
1205
1206 @classmethod
1206 @classmethod
1207 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1207 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1208 if case_insensitive:
1208 if case_insensitive:
1209 gr = cls.query()\
1209 gr = cls.query()\
1210 .filter(cls.group_name.ilike(group_name))
1210 .filter(cls.group_name.ilike(group_name))
1211 else:
1211 else:
1212 gr = cls.query()\
1212 gr = cls.query()\
1213 .filter(cls.group_name == group_name)
1213 .filter(cls.group_name == group_name)
1214 if cache:
1214 if cache:
1215 gr = gr.options(FromCache(
1215 gr = gr.options(FromCache(
1216 "sql_cache_short",
1216 "sql_cache_short",
1217 "get_group_%s" % _hash_key(group_name)
1217 "get_group_%s" % _hash_key(group_name)
1218 )
1218 )
1219 )
1219 )
1220 return gr.scalar()
1220 return gr.scalar()
1221
1221
1222 @property
1222 @property
1223 def parents(self):
1223 def parents(self):
1224 parents_recursion_limit = 5
1224 parents_recursion_limit = 5
1225 groups = []
1225 groups = []
1226 if self.parent_group is None:
1226 if self.parent_group is None:
1227 return groups
1227 return groups
1228 cur_gr = self.parent_group
1228 cur_gr = self.parent_group
1229 groups.insert(0, cur_gr)
1229 groups.insert(0, cur_gr)
1230 cnt = 0
1230 cnt = 0
1231 while 1:
1231 while 1:
1232 cnt += 1
1232 cnt += 1
1233 gr = getattr(cur_gr, 'parent_group', None)
1233 gr = getattr(cur_gr, 'parent_group', None)
1234 cur_gr = cur_gr.parent_group
1234 cur_gr = cur_gr.parent_group
1235 if gr is None:
1235 if gr is None:
1236 break
1236 break
1237 if cnt == parents_recursion_limit:
1237 if cnt == parents_recursion_limit:
1238 # this will prevent accidental infinit loops
1238 # this will prevent accidental infinit loops
1239 log.error('group nested more than %s' %
1239 log.error('group nested more than %s' %
1240 parents_recursion_limit)
1240 parents_recursion_limit)
1241 break
1241 break
1242
1242
1243 groups.insert(0, gr)
1243 groups.insert(0, gr)
1244 return groups
1244 return groups
1245
1245
1246 @property
1246 @property
1247 def children(self):
1247 def children(self):
1248 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1248 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1249
1249
1250 @property
1250 @property
1251 def name(self):
1251 def name(self):
1252 return self.group_name.split(RepoGroup.url_sep())[-1]
1252 return self.group_name.split(RepoGroup.url_sep())[-1]
1253
1253
1254 @property
1254 @property
1255 def full_path(self):
1255 def full_path(self):
1256 return self.group_name
1256 return self.group_name
1257
1257
1258 @property
1258 @property
1259 def full_path_splitted(self):
1259 def full_path_splitted(self):
1260 return self.group_name.split(RepoGroup.url_sep())
1260 return self.group_name.split(RepoGroup.url_sep())
1261
1261
1262 @property
1262 @property
1263 def repositories(self):
1263 def repositories(self):
1264 return Repository.query()\
1264 return Repository.query()\
1265 .filter(Repository.group == self)\
1265 .filter(Repository.group == self)\
1266 .order_by(Repository.repo_name)
1266 .order_by(Repository.repo_name)
1267
1267
1268 @property
1268 @property
1269 def repositories_recursive_count(self):
1269 def repositories_recursive_count(self):
1270 cnt = self.repositories.count()
1270 cnt = self.repositories.count()
1271
1271
1272 def children_count(group):
1272 def children_count(group):
1273 cnt = 0
1273 cnt = 0
1274 for child in group.children:
1274 for child in group.children:
1275 cnt += child.repositories.count()
1275 cnt += child.repositories.count()
1276 cnt += children_count(child)
1276 cnt += children_count(child)
1277 return cnt
1277 return cnt
1278
1278
1279 return cnt + children_count(self)
1279 return cnt + children_count(self)
1280
1280
1281 def recursive_groups_and_repos(self):
1281 def recursive_groups_and_repos(self):
1282 """
1282 """
1283 Recursive return all groups, with repositories in those groups
1283 Recursive return all groups, with repositories in those groups
1284 """
1284 """
1285 all_ = []
1285 all_ = []
1286
1286
1287 def _get_members(root_gr):
1287 def _get_members(root_gr):
1288 for r in root_gr.repositories:
1288 for r in root_gr.repositories:
1289 all_.append(r)
1289 all_.append(r)
1290 childs = root_gr.children.all()
1290 childs = root_gr.children.all()
1291 if childs:
1291 if childs:
1292 for gr in childs:
1292 for gr in childs:
1293 all_.append(gr)
1293 all_.append(gr)
1294 _get_members(gr)
1294 _get_members(gr)
1295
1295
1296 _get_members(self)
1296 _get_members(self)
1297 return [self] + all_
1297 return [self] + all_
1298
1298
1299 def get_new_name(self, group_name):
1299 def get_new_name(self, group_name):
1300 """
1300 """
1301 returns new full group name based on parent and new name
1301 returns new full group name based on parent and new name
1302
1302
1303 :param group_name:
1303 :param group_name:
1304 """
1304 """
1305 path_prefix = (self.parent_group.full_path_splitted if
1305 path_prefix = (self.parent_group.full_path_splitted if
1306 self.parent_group else [])
1306 self.parent_group else [])
1307 return RepoGroup.url_sep().join(path_prefix + [group_name])
1307 return RepoGroup.url_sep().join(path_prefix + [group_name])
1308
1308
1309
1309
1310 class Permission(Base, BaseModel):
1310 class Permission(Base, BaseModel):
1311 __tablename__ = 'permissions'
1311 __tablename__ = 'permissions'
1312 __table_args__ = (
1312 __table_args__ = (
1313 Index('p_perm_name_idx', 'permission_name'),
1313 Index('p_perm_name_idx', 'permission_name'),
1314 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1314 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1315 'mysql_charset': 'utf8'},
1315 'mysql_charset': 'utf8'},
1316 )
1316 )
1317 PERMS = [
1317 PERMS = [
1318 ('repository.none', _('Repository no access')),
1318 ('repository.none', _('Repository no access')),
1319 ('repository.read', _('Repository read access')),
1319 ('repository.read', _('Repository read access')),
1320 ('repository.write', _('Repository write access')),
1320 ('repository.write', _('Repository write access')),
1321 ('repository.admin', _('Repository admin access')),
1321 ('repository.admin', _('Repository admin access')),
1322
1322
1323 ('group.none', _('Repositories Group no access')),
1323 ('group.none', _('Repositories Group no access')),
1324 ('group.read', _('Repositories Group read access')),
1324 ('group.read', _('Repositories Group read access')),
1325 ('group.write', _('Repositories Group write access')),
1325 ('group.write', _('Repositories Group write access')),
1326 ('group.admin', _('Repositories Group admin access')),
1326 ('group.admin', _('Repositories Group admin access')),
1327
1327
1328 ('hg.admin', _('RhodeCode Administrator')),
1328 ('hg.admin', _('RhodeCode Administrator')),
1329 ('hg.create.none', _('Repository creation disabled')),
1329 ('hg.create.none', _('Repository creation disabled')),
1330 ('hg.create.repository', _('Repository creation enabled')),
1330 ('hg.create.repository', _('Repository creation enabled')),
1331 ('hg.fork.none', _('Repository forking disabled')),
1331 ('hg.fork.none', _('Repository forking disabled')),
1332 ('hg.fork.repository', _('Repository forking enabled')),
1332 ('hg.fork.repository', _('Repository forking enabled')),
1333 ('hg.register.none', _('Register disabled')),
1333 ('hg.register.none', _('Register disabled')),
1334 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1334 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1335 'with manual activation')),
1335 'with manual activation')),
1336
1336
1337 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1337 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1338 'with auto activation')),
1338 'with auto activation')),
1339 ]
1339 ]
1340
1340
1341 # defines which permissions are more important higher the more important
1341 # defines which permissions are more important higher the more important
1342 PERM_WEIGHTS = {
1342 PERM_WEIGHTS = {
1343 'repository.none': 0,
1343 'repository.none': 0,
1344 'repository.read': 1,
1344 'repository.read': 1,
1345 'repository.write': 3,
1345 'repository.write': 3,
1346 'repository.admin': 4,
1346 'repository.admin': 4,
1347
1347
1348 'group.none': 0,
1348 'group.none': 0,
1349 'group.read': 1,
1349 'group.read': 1,
1350 'group.write': 3,
1350 'group.write': 3,
1351 'group.admin': 4,
1351 'group.admin': 4,
1352
1352
1353 'hg.fork.none': 0,
1353 'hg.fork.none': 0,
1354 'hg.fork.repository': 1,
1354 'hg.fork.repository': 1,
1355 'hg.create.none': 0,
1355 'hg.create.none': 0,
1356 'hg.create.repository':1
1356 'hg.create.repository':1
1357 }
1357 }
1358
1358
1359 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1359 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1360 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1360 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1361 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1361 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1362
1362
1363 def __unicode__(self):
1363 def __unicode__(self):
1364 return u"<%s('%s:%s')>" % (
1364 return u"<%s('%s:%s')>" % (
1365 self.__class__.__name__, self.permission_id, self.permission_name
1365 self.__class__.__name__, self.permission_id, self.permission_name
1366 )
1366 )
1367
1367
1368 @classmethod
1368 @classmethod
1369 def get_by_key(cls, key):
1369 def get_by_key(cls, key):
1370 return cls.query().filter(cls.permission_name == key).scalar()
1370 return cls.query().filter(cls.permission_name == key).scalar()
1371
1371
1372 @classmethod
1372 @classmethod
1373 def get_default_perms(cls, default_user_id):
1373 def get_default_perms(cls, default_user_id):
1374 q = Session().query(UserRepoToPerm, Repository, cls)\
1374 q = Session().query(UserRepoToPerm, Repository, cls)\
1375 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1375 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1376 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1376 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1377 .filter(UserRepoToPerm.user_id == default_user_id)
1377 .filter(UserRepoToPerm.user_id == default_user_id)
1378
1378
1379 return q.all()
1379 return q.all()
1380
1380
1381 @classmethod
1381 @classmethod
1382 def get_default_group_perms(cls, default_user_id):
1382 def get_default_group_perms(cls, default_user_id):
1383 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1383 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1384 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1384 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1385 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1385 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1386 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1386 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1387
1387
1388 return q.all()
1388 return q.all()
1389
1389
1390
1390
1391 class UserRepoToPerm(Base, BaseModel):
1391 class UserRepoToPerm(Base, BaseModel):
1392 __tablename__ = 'repo_to_perm'
1392 __tablename__ = 'repo_to_perm'
1393 __table_args__ = (
1393 __table_args__ = (
1394 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1394 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1395 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1395 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1396 'mysql_charset': 'utf8'}
1396 'mysql_charset': 'utf8'}
1397 )
1397 )
1398 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1398 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1399 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1399 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1400 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1400 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1401 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1401 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1402
1402
1403 user = relationship('User')
1403 user = relationship('User')
1404 repository = relationship('Repository')
1404 repository = relationship('Repository')
1405 permission = relationship('Permission')
1405 permission = relationship('Permission')
1406
1406
1407 @classmethod
1407 @classmethod
1408 def create(cls, user, repository, permission):
1408 def create(cls, user, repository, permission):
1409 n = cls()
1409 n = cls()
1410 n.user = user
1410 n.user = user
1411 n.repository = repository
1411 n.repository = repository
1412 n.permission = permission
1412 n.permission = permission
1413 Session().add(n)
1413 Session().add(n)
1414 return n
1414 return n
1415
1415
1416 def __unicode__(self):
1416 def __unicode__(self):
1417 return u'<user:%s => %s >' % (self.user, self.repository)
1417 return u'<user:%s => %s >' % (self.user, self.repository)
1418
1418
1419
1419
1420 class UserToPerm(Base, BaseModel):
1420 class UserToPerm(Base, BaseModel):
1421 __tablename__ = 'user_to_perm'
1421 __tablename__ = 'user_to_perm'
1422 __table_args__ = (
1422 __table_args__ = (
1423 UniqueConstraint('user_id', 'permission_id'),
1423 UniqueConstraint('user_id', 'permission_id'),
1424 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1424 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1425 'mysql_charset': 'utf8'}
1425 'mysql_charset': 'utf8'}
1426 )
1426 )
1427 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1427 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1428 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1428 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1429 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1429 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1430
1430
1431 user = relationship('User')
1431 user = relationship('User')
1432 permission = relationship('Permission', lazy='joined')
1432 permission = relationship('Permission', lazy='joined')
1433
1433
1434
1434
1435 class UsersGroupRepoToPerm(Base, BaseModel):
1435 class UsersGroupRepoToPerm(Base, BaseModel):
1436 __tablename__ = 'users_group_repo_to_perm'
1436 __tablename__ = 'users_group_repo_to_perm'
1437 __table_args__ = (
1437 __table_args__ = (
1438 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1438 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1439 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1439 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1440 'mysql_charset': 'utf8'}
1440 'mysql_charset': 'utf8'}
1441 )
1441 )
1442 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1442 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1443 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1443 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1444 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1444 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1445 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1445 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1446
1446
1447 users_group = relationship('UsersGroup')
1447 users_group = relationship('UsersGroup')
1448 permission = relationship('Permission')
1448 permission = relationship('Permission')
1449 repository = relationship('Repository')
1449 repository = relationship('Repository')
1450
1450
1451 @classmethod
1451 @classmethod
1452 def create(cls, users_group, repository, permission):
1452 def create(cls, users_group, repository, permission):
1453 n = cls()
1453 n = cls()
1454 n.users_group = users_group
1454 n.users_group = users_group
1455 n.repository = repository
1455 n.repository = repository
1456 n.permission = permission
1456 n.permission = permission
1457 Session().add(n)
1457 Session().add(n)
1458 return n
1458 return n
1459
1459
1460 def __unicode__(self):
1460 def __unicode__(self):
1461 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1461 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1462
1462
1463
1463
1464 class UsersGroupToPerm(Base, BaseModel):
1464 class UsersGroupToPerm(Base, BaseModel):
1465 __tablename__ = 'users_group_to_perm'
1465 __tablename__ = 'users_group_to_perm'
1466 __table_args__ = (
1466 __table_args__ = (
1467 UniqueConstraint('users_group_id', 'permission_id',),
1467 UniqueConstraint('users_group_id', 'permission_id',),
1468 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1468 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1469 'mysql_charset': 'utf8'}
1469 'mysql_charset': 'utf8'}
1470 )
1470 )
1471 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1471 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1472 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1472 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1473 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1473 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1474
1474
1475 users_group = relationship('UsersGroup')
1475 users_group = relationship('UsersGroup')
1476 permission = relationship('Permission')
1476 permission = relationship('Permission')
1477
1477
1478
1478
1479 class UserRepoGroupToPerm(Base, BaseModel):
1479 class UserRepoGroupToPerm(Base, BaseModel):
1480 __tablename__ = 'user_repo_group_to_perm'
1480 __tablename__ = 'user_repo_group_to_perm'
1481 __table_args__ = (
1481 __table_args__ = (
1482 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1482 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1483 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1483 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1484 'mysql_charset': 'utf8'}
1484 'mysql_charset': 'utf8'}
1485 )
1485 )
1486
1486
1487 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1487 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1488 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1488 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1489 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1489 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1490 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1490 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1491
1491
1492 user = relationship('User')
1492 user = relationship('User')
1493 group = relationship('RepoGroup')
1493 group = relationship('RepoGroup')
1494 permission = relationship('Permission')
1494 permission = relationship('Permission')
1495
1495
1496
1496
1497 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1497 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1498 __tablename__ = 'users_group_repo_group_to_perm'
1498 __tablename__ = 'users_group_repo_group_to_perm'
1499 __table_args__ = (
1499 __table_args__ = (
1500 UniqueConstraint('users_group_id', 'group_id'),
1500 UniqueConstraint('users_group_id', 'group_id'),
1501 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1501 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1502 'mysql_charset': 'utf8'}
1502 'mysql_charset': 'utf8'}
1503 )
1503 )
1504
1504
1505 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1505 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1506 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1506 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1507 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1507 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1508 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1508 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1509
1509
1510 users_group = relationship('UsersGroup')
1510 users_group = relationship('UsersGroup')
1511 permission = relationship('Permission')
1511 permission = relationship('Permission')
1512 group = relationship('RepoGroup')
1512 group = relationship('RepoGroup')
1513
1513
1514
1514
1515 class Statistics(Base, BaseModel):
1515 class Statistics(Base, BaseModel):
1516 __tablename__ = 'statistics'
1516 __tablename__ = 'statistics'
1517 __table_args__ = (
1517 __table_args__ = (
1518 UniqueConstraint('repository_id'),
1518 UniqueConstraint('repository_id'),
1519 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1519 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1520 'mysql_charset': 'utf8'}
1520 'mysql_charset': 'utf8'}
1521 )
1521 )
1522 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1522 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1523 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1523 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1524 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1524 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1525 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1525 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1526 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1526 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1527 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1527 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1528
1528
1529 repository = relationship('Repository', single_parent=True)
1529 repository = relationship('Repository', single_parent=True)
1530
1530
1531
1531
1532 class UserFollowing(Base, BaseModel):
1532 class UserFollowing(Base, BaseModel):
1533 __tablename__ = 'user_followings'
1533 __tablename__ = 'user_followings'
1534 __table_args__ = (
1534 __table_args__ = (
1535 UniqueConstraint('user_id', 'follows_repository_id'),
1535 UniqueConstraint('user_id', 'follows_repository_id'),
1536 UniqueConstraint('user_id', 'follows_user_id'),
1536 UniqueConstraint('user_id', 'follows_user_id'),
1537 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1537 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1538 'mysql_charset': 'utf8'}
1538 'mysql_charset': 'utf8'}
1539 )
1539 )
1540
1540
1541 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1541 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1542 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1542 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1543 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1543 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1544 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1544 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1545 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1545 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1546
1546
1547 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1547 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1548
1548
1549 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1549 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1550 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1550 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1551
1551
1552 @classmethod
1552 @classmethod
1553 def get_repo_followers(cls, repo_id):
1553 def get_repo_followers(cls, repo_id):
1554 return cls.query().filter(cls.follows_repo_id == repo_id)
1554 return cls.query().filter(cls.follows_repo_id == repo_id)
1555
1555
1556
1556
1557 class CacheInvalidation(Base, BaseModel):
1557 class CacheInvalidation(Base, BaseModel):
1558 __tablename__ = 'cache_invalidation'
1558 __tablename__ = 'cache_invalidation'
1559 __table_args__ = (
1559 __table_args__ = (
1560 UniqueConstraint('cache_key'),
1560 UniqueConstraint('cache_key'),
1561 Index('key_idx', 'cache_key'),
1561 Index('key_idx', 'cache_key'),
1562 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1562 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1563 'mysql_charset': 'utf8'},
1563 'mysql_charset': 'utf8'},
1564 )
1564 )
1565 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1565 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1566 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1566 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1567 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1567 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1568 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1568 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1569
1569
1570 def __init__(self, cache_key, cache_args=''):
1570 def __init__(self, cache_key, cache_args=''):
1571 self.cache_key = cache_key
1571 self.cache_key = cache_key
1572 self.cache_args = cache_args
1572 self.cache_args = cache_args
1573 self.cache_active = False
1573 self.cache_active = False
1574
1574
1575 def __unicode__(self):
1575 def __unicode__(self):
1576 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1576 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1577 self.cache_id, self.cache_key)
1577 self.cache_id, self.cache_key)
1578
1578
1579 @property
1579 @property
1580 def prefix(self):
1580 def prefix(self):
1581 _split = self.cache_key.split(self.cache_args, 1)
1581 _split = self.cache_key.split(self.cache_args, 1)
1582 if _split and len(_split) == 2:
1582 if _split and len(_split) == 2:
1583 return _split[0]
1583 return _split[0]
1584 return ''
1584 return ''
1585
1585
1586 @classmethod
1586 @classmethod
1587 def clear_cache(cls):
1587 def clear_cache(cls):
1588 cls.query().delete()
1588 cls.query().delete()
1589
1589
1590 @classmethod
1590 @classmethod
1591 def _get_key(cls, key):
1591 def _get_key(cls, key):
1592 """
1592 """
1593 Wrapper for generating a key, together with a prefix
1593 Wrapper for generating a key, together with a prefix
1594
1594
1595 :param key:
1595 :param key:
1596 """
1596 """
1597 import rhodecode
1597 import rhodecode
1598 prefix = ''
1598 prefix = ''
1599 org_key = key
1599 org_key = key
1600 iid = rhodecode.CONFIG.get('instance_id')
1600 iid = rhodecode.CONFIG.get('instance_id')
1601 if iid:
1601 if iid:
1602 prefix = iid
1602 prefix = iid
1603
1603
1604 return "%s%s" % (prefix, key), prefix, org_key
1604 return "%s%s" % (prefix, key), prefix, org_key
1605
1605
1606 @classmethod
1606 @classmethod
1607 def get_by_key(cls, key):
1607 def get_by_key(cls, key):
1608 return cls.query().filter(cls.cache_key == key).scalar()
1608 return cls.query().filter(cls.cache_key == key).scalar()
1609
1609
1610 @classmethod
1610 @classmethod
1611 def get_by_repo_name(cls, repo_name):
1611 def get_by_repo_name(cls, repo_name):
1612 return cls.query().filter(cls.cache_args == repo_name).all()
1612 return cls.query().filter(cls.cache_args == repo_name).all()
1613
1613
1614 @classmethod
1614 @classmethod
1615 def _get_or_create_key(cls, key, repo_name, commit=True):
1615 def _get_or_create_key(cls, key, repo_name, commit=True):
1616 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1616 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1617 if not inv_obj:
1617 if not inv_obj:
1618 try:
1618 try:
1619 inv_obj = CacheInvalidation(key, repo_name)
1619 inv_obj = CacheInvalidation(key, repo_name)
1620 Session().add(inv_obj)
1620 Session().add(inv_obj)
1621 if commit:
1621 if commit:
1622 Session().commit()
1622 Session().commit()
1623 except Exception:
1623 except Exception:
1624 log.error(traceback.format_exc())
1624 log.error(traceback.format_exc())
1625 Session().rollback()
1625 Session().rollback()
1626 return inv_obj
1626 return inv_obj
1627
1627
1628 @classmethod
1628 @classmethod
1629 def invalidate(cls, key):
1629 def invalidate(cls, key):
1630 """
1630 """
1631 Returns Invalidation object if this given key should be invalidated
1631 Returns Invalidation object if this given key should be invalidated
1632 None otherwise. `cache_active = False` means that this cache
1632 None otherwise. `cache_active = False` means that this cache
1633 state is not valid and needs to be invalidated
1633 state is not valid and needs to be invalidated
1634
1634
1635 :param key:
1635 :param key:
1636 """
1636 """
1637 repo_name = key
1637 repo_name = key
1638 repo_name = remove_suffix(repo_name, '_README')
1638 repo_name = remove_suffix(repo_name, '_README')
1639 repo_name = remove_suffix(repo_name, '_RSS')
1639 repo_name = remove_suffix(repo_name, '_RSS')
1640 repo_name = remove_suffix(repo_name, '_ATOM')
1640 repo_name = remove_suffix(repo_name, '_ATOM')
1641
1641
1642 # adds instance prefix
1642 # adds instance prefix
1643 key, _prefix, _org_key = cls._get_key(key)
1643 key, _prefix, _org_key = cls._get_key(key)
1644 inv = cls._get_or_create_key(key, repo_name)
1644 inv = cls._get_or_create_key(key, repo_name)
1645
1645
1646 if inv and inv.cache_active is False:
1646 if inv and inv.cache_active is False:
1647 return inv
1647 return inv
1648
1648
1649 @classmethod
1649 @classmethod
1650 def set_invalidate(cls, key=None, repo_name=None):
1650 def set_invalidate(cls, key=None, repo_name=None):
1651 """
1651 """
1652 Mark this Cache key for invalidation, either by key or whole
1652 Mark this Cache key for invalidation, either by key or whole
1653 cache sets based on repo_name
1653 cache sets based on repo_name
1654
1654
1655 :param key:
1655 :param key:
1656 """
1656 """
1657 invalidated_keys = []
1657 invalidated_keys = []
1658 if key:
1658 if key:
1659 key, _prefix, _org_key = cls._get_key(key)
1659 key, _prefix, _org_key = cls._get_key(key)
1660 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1660 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1661 elif repo_name:
1661 elif repo_name:
1662 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1662 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1663
1663
1664 try:
1664 try:
1665 for inv_obj in inv_objs:
1665 for inv_obj in inv_objs:
1666 inv_obj.cache_active = False
1666 inv_obj.cache_active = False
1667 log.debug('marking %s key for invalidation based on key=%s,repo_name=%s'
1667 log.debug('marking %s key for invalidation based on key=%s,repo_name=%s'
1668 % (inv_obj, key, repo_name))
1668 % (inv_obj, key, repo_name))
1669 invalidated_keys.append(inv_obj.cache_key)
1669 invalidated_keys.append(inv_obj.cache_key)
1670 Session().add(inv_obj)
1670 Session().add(inv_obj)
1671 Session().commit()
1671 Session().commit()
1672 except Exception:
1672 except Exception:
1673 log.error(traceback.format_exc())
1673 log.error(traceback.format_exc())
1674 Session().rollback()
1674 Session().rollback()
1675 return invalidated_keys
1675 return invalidated_keys
1676
1676
1677 @classmethod
1677 @classmethod
1678 def set_valid(cls, key):
1678 def set_valid(cls, key):
1679 """
1679 """
1680 Mark this cache key as active and currently cached
1680 Mark this cache key as active and currently cached
1681
1681
1682 :param key:
1682 :param key:
1683 """
1683 """
1684 inv_obj = cls.get_by_key(key)
1684 inv_obj = cls.get_by_key(key)
1685 inv_obj.cache_active = True
1685 inv_obj.cache_active = True
1686 Session().add(inv_obj)
1686 Session().add(inv_obj)
1687 Session().commit()
1687 Session().commit()
1688
1688
1689 @classmethod
1689 @classmethod
1690 def get_cache_map(cls):
1690 def get_cache_map(cls):
1691
1691
1692 class cachemapdict(dict):
1692 class cachemapdict(dict):
1693
1693
1694 def __init__(self, *args, **kwargs):
1694 def __init__(self, *args, **kwargs):
1695 fixkey = kwargs.get('fixkey')
1695 fixkey = kwargs.get('fixkey')
1696 if fixkey:
1696 if fixkey:
1697 del kwargs['fixkey']
1697 del kwargs['fixkey']
1698 self.fixkey = fixkey
1698 self.fixkey = fixkey
1699 super(cachemapdict, self).__init__(*args, **kwargs)
1699 super(cachemapdict, self).__init__(*args, **kwargs)
1700
1700
1701 def __getattr__(self, name):
1701 def __getattr__(self, name):
1702 key = name
1702 key = name
1703 if self.fixkey:
1703 if self.fixkey:
1704 key, _prefix, _org_key = cls._get_key(key)
1704 key, _prefix, _org_key = cls._get_key(key)
1705 if key in self.__dict__:
1705 if key in self.__dict__:
1706 return self.__dict__[key]
1706 return self.__dict__[key]
1707 else:
1707 else:
1708 return self[key]
1708 return self[key]
1709
1709
1710 def __getitem__(self, key):
1710 def __getitem__(self, key):
1711 if self.fixkey:
1711 if self.fixkey:
1712 key, _prefix, _org_key = cls._get_key(key)
1712 key, _prefix, _org_key = cls._get_key(key)
1713 try:
1713 try:
1714 return super(cachemapdict, self).__getitem__(key)
1714 return super(cachemapdict, self).__getitem__(key)
1715 except KeyError:
1715 except KeyError:
1716 return
1716 return
1717
1717
1718 cache_map = cachemapdict(fixkey=True)
1718 cache_map = cachemapdict(fixkey=True)
1719 for obj in cls.query().all():
1719 for obj in cls.query().all():
1720 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1720 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1721 return cache_map
1721 return cache_map
1722
1722
1723
1723
1724 class ChangesetComment(Base, BaseModel):
1724 class ChangesetComment(Base, BaseModel):
1725 __tablename__ = 'changeset_comments'
1725 __tablename__ = 'changeset_comments'
1726 __table_args__ = (
1726 __table_args__ = (
1727 Index('cc_revision_idx', 'revision'),
1727 Index('cc_revision_idx', 'revision'),
1728 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1728 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1729 'mysql_charset': 'utf8'},
1729 'mysql_charset': 'utf8'},
1730 )
1730 )
1731 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1731 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1732 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1732 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1733 revision = Column('revision', String(40), nullable=True)
1733 revision = Column('revision', String(40), nullable=True)
1734 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1734 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1735 line_no = Column('line_no', Unicode(10), nullable=True)
1735 line_no = Column('line_no', Unicode(10), nullable=True)
1736 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1736 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1737 f_path = Column('f_path', Unicode(1000), nullable=True)
1737 f_path = Column('f_path', Unicode(1000), nullable=True)
1738 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1738 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1739 text = Column('text', UnicodeText(25000), nullable=False)
1739 text = Column('text', UnicodeText(25000), nullable=False)
1740 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1740 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1741 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1741 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1742
1742
1743 author = relationship('User', lazy='joined')
1743 author = relationship('User', lazy='joined')
1744 repo = relationship('Repository')
1744 repo = relationship('Repository')
1745 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1745 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1746 pull_request = relationship('PullRequest', lazy='joined')
1746 pull_request = relationship('PullRequest', lazy='joined')
1747
1747
1748 @classmethod
1748 @classmethod
1749 def get_users(cls, revision=None, pull_request_id=None):
1749 def get_users(cls, revision=None, pull_request_id=None):
1750 """
1750 """
1751 Returns user associated with this ChangesetComment. ie those
1751 Returns user associated with this ChangesetComment. ie those
1752 who actually commented
1752 who actually commented
1753
1753
1754 :param cls:
1754 :param cls:
1755 :param revision:
1755 :param revision:
1756 """
1756 """
1757 q = Session().query(User)\
1757 q = Session().query(User)\
1758 .join(ChangesetComment.author)
1758 .join(ChangesetComment.author)
1759 if revision:
1759 if revision:
1760 q = q.filter(cls.revision == revision)
1760 q = q.filter(cls.revision == revision)
1761 elif pull_request_id:
1761 elif pull_request_id:
1762 q = q.filter(cls.pull_request_id == pull_request_id)
1762 q = q.filter(cls.pull_request_id == pull_request_id)
1763 return q.all()
1763 return q.all()
1764
1764
1765
1765
1766 class ChangesetStatus(Base, BaseModel):
1766 class ChangesetStatus(Base, BaseModel):
1767 __tablename__ = 'changeset_statuses'
1767 __tablename__ = 'changeset_statuses'
1768 __table_args__ = (
1768 __table_args__ = (
1769 Index('cs_revision_idx', 'revision'),
1769 Index('cs_revision_idx', 'revision'),
1770 Index('cs_version_idx', 'version'),
1770 Index('cs_version_idx', 'version'),
1771 UniqueConstraint('repo_id', 'revision', 'version'),
1771 UniqueConstraint('repo_id', 'revision', 'version'),
1772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1773 'mysql_charset': 'utf8'}
1773 'mysql_charset': 'utf8'}
1774 )
1774 )
1775 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1775 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1776 STATUS_APPROVED = 'approved'
1776 STATUS_APPROVED = 'approved'
1777 STATUS_REJECTED = 'rejected'
1777 STATUS_REJECTED = 'rejected'
1778 STATUS_UNDER_REVIEW = 'under_review'
1778 STATUS_UNDER_REVIEW = 'under_review'
1779
1779
1780 STATUSES = [
1780 STATUSES = [
1781 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1781 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1782 (STATUS_APPROVED, _("Approved")),
1782 (STATUS_APPROVED, _("Approved")),
1783 (STATUS_REJECTED, _("Rejected")),
1783 (STATUS_REJECTED, _("Rejected")),
1784 (STATUS_UNDER_REVIEW, _("Under Review")),
1784 (STATUS_UNDER_REVIEW, _("Under Review")),
1785 ]
1785 ]
1786
1786
1787 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1787 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1788 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1788 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1789 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1789 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1790 revision = Column('revision', String(40), nullable=False)
1790 revision = Column('revision', String(40), nullable=False)
1791 status = Column('status', String(128), nullable=False, default=DEFAULT)
1791 status = Column('status', String(128), nullable=False, default=DEFAULT)
1792 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1792 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1793 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1793 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1794 version = Column('version', Integer(), nullable=False, default=0)
1794 version = Column('version', Integer(), nullable=False, default=0)
1795 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1795 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1796
1796
1797 author = relationship('User', lazy='joined')
1797 author = relationship('User', lazy='joined')
1798 repo = relationship('Repository')
1798 repo = relationship('Repository')
1799 comment = relationship('ChangesetComment', lazy='joined')
1799 comment = relationship('ChangesetComment', lazy='joined')
1800 pull_request = relationship('PullRequest', lazy='joined')
1800 pull_request = relationship('PullRequest', lazy='joined')
1801
1801
1802 def __unicode__(self):
1802 def __unicode__(self):
1803 return u"<%s('%s:%s')>" % (
1803 return u"<%s('%s:%s')>" % (
1804 self.__class__.__name__,
1804 self.__class__.__name__,
1805 self.status, self.author
1805 self.status, self.author
1806 )
1806 )
1807
1807
1808 @classmethod
1808 @classmethod
1809 def get_status_lbl(cls, value):
1809 def get_status_lbl(cls, value):
1810 return dict(cls.STATUSES).get(value)
1810 return dict(cls.STATUSES).get(value)
1811
1811
1812 @property
1812 @property
1813 def status_lbl(self):
1813 def status_lbl(self):
1814 return ChangesetStatus.get_status_lbl(self.status)
1814 return ChangesetStatus.get_status_lbl(self.status)
1815
1815
1816
1816
1817 class PullRequest(Base, BaseModel):
1817 class PullRequest(Base, BaseModel):
1818 __tablename__ = 'pull_requests'
1818 __tablename__ = 'pull_requests'
1819 __table_args__ = (
1819 __table_args__ = (
1820 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1820 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1821 'mysql_charset': 'utf8'},
1821 'mysql_charset': 'utf8'},
1822 )
1822 )
1823
1823
1824 STATUS_NEW = u'new'
1824 STATUS_NEW = u'new'
1825 STATUS_OPEN = u'open'
1825 STATUS_OPEN = u'open'
1826 STATUS_CLOSED = u'closed'
1826 STATUS_CLOSED = u'closed'
1827
1827
1828 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1828 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1829 title = Column('title', Unicode(256), nullable=True)
1829 title = Column('title', Unicode(256), nullable=True)
1830 description = Column('description', UnicodeText(10240), nullable=True)
1830 description = Column('description', UnicodeText(10240), nullable=True)
1831 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1831 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1832 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1832 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1833 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1833 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1834 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1834 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1835 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1835 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1836 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1836 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1837 org_ref = Column('org_ref', Unicode(256), nullable=False)
1837 org_ref = Column('org_ref', Unicode(256), nullable=False)
1838 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1838 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1839 other_ref = Column('other_ref', Unicode(256), nullable=False)
1839 other_ref = Column('other_ref', Unicode(256), nullable=False)
1840
1840
1841 @hybrid_property
1841 @hybrid_property
1842 def revisions(self):
1842 def revisions(self):
1843 return self._revisions.split(':')
1843 return self._revisions.split(':')
1844
1844
1845 @revisions.setter
1845 @revisions.setter
1846 def revisions(self, val):
1846 def revisions(self, val):
1847 self._revisions = ':'.join(val)
1847 self._revisions = ':'.join(val)
1848
1848
1849 @property
1849 @property
1850 def org_ref_parts(self):
1850 def org_ref_parts(self):
1851 return self.org_ref.split(':')
1851 return self.org_ref.split(':')
1852
1852
1853 @property
1853 @property
1854 def other_ref_parts(self):
1854 def other_ref_parts(self):
1855 return self.other_ref.split(':')
1855 return self.other_ref.split(':')
1856
1856
1857 author = relationship('User', lazy='joined')
1857 author = relationship('User', lazy='joined')
1858 reviewers = relationship('PullRequestReviewers',
1858 reviewers = relationship('PullRequestReviewers',
1859 cascade="all, delete, delete-orphan")
1859 cascade="all, delete, delete-orphan")
1860 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1860 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1861 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1861 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1862 statuses = relationship('ChangesetStatus')
1862 statuses = relationship('ChangesetStatus')
1863 comments = relationship('ChangesetComment',
1863 comments = relationship('ChangesetComment',
1864 cascade="all, delete, delete-orphan")
1864 cascade="all, delete, delete-orphan")
1865
1865
1866 def is_closed(self):
1866 def is_closed(self):
1867 return self.status == self.STATUS_CLOSED
1867 return self.status == self.STATUS_CLOSED
1868
1868
1869 @property
1869 @property
1870 def last_review_status(self):
1870 def last_review_status(self):
1871 return self.statuses[-1].status
1871 return self.statuses[-1].status
1872
1872
1873 def __json__(self):
1873 def __json__(self):
1874 return dict(
1874 return dict(
1875 revisions=self.revisions
1875 revisions=self.revisions
1876 )
1876 )
1877
1877
1878
1878
1879 class PullRequestReviewers(Base, BaseModel):
1879 class PullRequestReviewers(Base, BaseModel):
1880 __tablename__ = 'pull_request_reviewers'
1880 __tablename__ = 'pull_request_reviewers'
1881 __table_args__ = (
1881 __table_args__ = (
1882 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1882 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1883 'mysql_charset': 'utf8'},
1883 'mysql_charset': 'utf8'},
1884 )
1884 )
1885
1885
1886 def __init__(self, user=None, pull_request=None):
1886 def __init__(self, user=None, pull_request=None):
1887 self.user = user
1887 self.user = user
1888 self.pull_request = pull_request
1888 self.pull_request = pull_request
1889
1889
1890 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1890 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1891 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1891 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1892 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1892 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1893
1893
1894 user = relationship('User')
1894 user = relationship('User')
1895 pull_request = relationship('PullRequest')
1895 pull_request = relationship('PullRequest')
1896
1896
1897
1897
1898 class Notification(Base, BaseModel):
1898 class Notification(Base, BaseModel):
1899 __tablename__ = 'notifications'
1899 __tablename__ = 'notifications'
1900 __table_args__ = (
1900 __table_args__ = (
1901 Index('notification_type_idx', 'type'),
1901 Index('notification_type_idx', 'type'),
1902 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1902 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1903 'mysql_charset': 'utf8'},
1903 'mysql_charset': 'utf8'},
1904 )
1904 )
1905
1905
1906 TYPE_CHANGESET_COMMENT = u'cs_comment'
1906 TYPE_CHANGESET_COMMENT = u'cs_comment'
1907 TYPE_MESSAGE = u'message'
1907 TYPE_MESSAGE = u'message'
1908 TYPE_MENTION = u'mention'
1908 TYPE_MENTION = u'mention'
1909 TYPE_REGISTRATION = u'registration'
1909 TYPE_REGISTRATION = u'registration'
1910 TYPE_PULL_REQUEST = u'pull_request'
1910 TYPE_PULL_REQUEST = u'pull_request'
1911 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1911 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1912
1912
1913 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1913 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1914 subject = Column('subject', Unicode(512), nullable=True)
1914 subject = Column('subject', Unicode(512), nullable=True)
1915 body = Column('body', UnicodeText(50000), nullable=True)
1915 body = Column('body', UnicodeText(50000), nullable=True)
1916 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1916 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1917 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1917 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1918 type_ = Column('type', Unicode(256))
1918 type_ = Column('type', Unicode(256))
1919
1919
1920 created_by_user = relationship('User')
1920 created_by_user = relationship('User')
1921 notifications_to_users = relationship('UserNotification', lazy='joined',
1921 notifications_to_users = relationship('UserNotification', lazy='joined',
1922 cascade="all, delete, delete-orphan")
1922 cascade="all, delete, delete-orphan")
1923
1923
1924 @property
1924 @property
1925 def recipients(self):
1925 def recipients(self):
1926 return [x.user for x in UserNotification.query()\
1926 return [x.user for x in UserNotification.query()\
1927 .filter(UserNotification.notification == self)\
1927 .filter(UserNotification.notification == self)\
1928 .order_by(UserNotification.user_id.asc()).all()]
1928 .order_by(UserNotification.user_id.asc()).all()]
1929
1929
1930 @classmethod
1930 @classmethod
1931 def create(cls, created_by, subject, body, recipients, type_=None):
1931 def create(cls, created_by, subject, body, recipients, type_=None):
1932 if type_ is None:
1932 if type_ is None:
1933 type_ = Notification.TYPE_MESSAGE
1933 type_ = Notification.TYPE_MESSAGE
1934
1934
1935 notification = cls()
1935 notification = cls()
1936 notification.created_by_user = created_by
1936 notification.created_by_user = created_by
1937 notification.subject = subject
1937 notification.subject = subject
1938 notification.body = body
1938 notification.body = body
1939 notification.type_ = type_
1939 notification.type_ = type_
1940 notification.created_on = datetime.datetime.now()
1940 notification.created_on = datetime.datetime.now()
1941
1941
1942 for u in recipients:
1942 for u in recipients:
1943 assoc = UserNotification()
1943 assoc = UserNotification()
1944 assoc.notification = notification
1944 assoc.notification = notification
1945 u.notifications.append(assoc)
1945 u.notifications.append(assoc)
1946 Session().add(notification)
1946 Session().add(notification)
1947 return notification
1947 return notification
1948
1948
1949 @property
1949 @property
1950 def description(self):
1950 def description(self):
1951 from rhodecode.model.notification import NotificationModel
1951 from rhodecode.model.notification import NotificationModel
1952 return NotificationModel().make_description(self)
1952 return NotificationModel().make_description(self)
1953
1953
1954
1954
1955 class UserNotification(Base, BaseModel):
1955 class UserNotification(Base, BaseModel):
1956 __tablename__ = 'user_to_notification'
1956 __tablename__ = 'user_to_notification'
1957 __table_args__ = (
1957 __table_args__ = (
1958 UniqueConstraint('user_id', 'notification_id'),
1958 UniqueConstraint('user_id', 'notification_id'),
1959 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1959 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1960 'mysql_charset': 'utf8'}
1960 'mysql_charset': 'utf8'}
1961 )
1961 )
1962 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1962 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1963 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1963 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1964 read = Column('read', Boolean, default=False)
1964 read = Column('read', Boolean, default=False)
1965 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1965 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1966
1966
1967 user = relationship('User', lazy="joined")
1967 user = relationship('User', lazy="joined")
1968 notification = relationship('Notification', lazy="joined",
1968 notification = relationship('Notification', lazy="joined",
1969 order_by=lambda: Notification.created_on.desc(),)
1969 order_by=lambda: Notification.created_on.desc(),)
1970
1970
1971 def mark_as_read(self):
1971 def mark_as_read(self):
1972 self.read = True
1972 self.read = True
1973 Session().add(self)
1973 Session().add(self)
1974
1974
1975
1975
1976 class DbMigrateVersion(Base, BaseModel):
1976 class DbMigrateVersion(Base, BaseModel):
1977 __tablename__ = 'db_migrate_version'
1977 __tablename__ = 'db_migrate_version'
1978 __table_args__ = (
1978 __table_args__ = (
1979 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1979 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1980 'mysql_charset': 'utf8'},
1980 'mysql_charset': 'utf8'},
1981 )
1981 )
1982 repository_id = Column('repository_id', String(250), primary_key=True)
1982 repository_id = Column('repository_id', String(250), primary_key=True)
1983 repository_path = Column('repository_path', Text)
1983 repository_path = Column('repository_path', Text)
1984 version = Column('version', Integer)
1984 version = Column('version', Integer)
@@ -1,175 +1,173 b''
1 div.codeblock {
1 div.codeblock {
2 overflow: auto;
2 overflow: auto;
3 padding: 0px;
3 padding: 0px;
4 border: 1px solid #ccc;
4 border: 1px solid #ccc;
5 background: #f8f8f8;
5 background: #f8f8f8;
6 font-size: 100%;
6 font-size: 100%;
7 line-height: 100%;
7 line-height: 100%;
8 /* new */
8 /* new */
9 line-height: 125%;
9 line-height: 125%;
10 -webkit-border-radius: 4px;
10 -webkit-border-radius: 4px;
11 -moz-border-radius: 4px;
11 -moz-border-radius: 4px;
12 border-radius: 4px;
12 border-radius: 4px;
13 }
13 }
14 div.codeblock .code-header{
14 div.codeblock .code-header{
15 border-bottom: 1px solid #CCCCCC;
15 border-bottom: 1px solid #CCCCCC;
16 background: #EEEEEE;
16 background: #EEEEEE;
17 padding:10px 0 10px 0;
17 padding:10px 0 10px 0;
18 }
18 }
19
19
20 div.codeblock .code-header .stats{
20 div.codeblock .code-header .stats{
21 clear: both;
21 clear: both;
22 padding: 6px 8px 6px 10px;
22 padding: 6px 8px 6px 10px;
23 border-bottom: 1px solid rgb(204, 204, 204);
23 border-bottom: 1px solid rgb(204, 204, 204);
24 height: 23px;
24 height: 23px;
25 margin-bottom: 6px;
25 margin-bottom: 6px;
26 }
26 }
27
27
28 div.codeblock .code-header .stats .left{
28 div.codeblock .code-header .stats .left{
29 float:left;
29 float:left;
30 }
30 }
31 div.codeblock .code-header .stats .left.img{
31 div.codeblock .code-header .stats .left.img{
32 margin-top:-2px;
32 margin-top:-2px;
33 }
33 }
34 div.codeblock .code-header .stats .left.item{
34 div.codeblock .code-header .stats .left.item{
35 float:left;
35 float:left;
36 padding: 0 9px 0 9px;
36 padding: 0 9px 0 9px;
37 border-right:1px solid #ccc;
37 border-right:1px solid #ccc;
38 }
38 }
39 div.codeblock .code-header .stats .left.item pre{
39 div.codeblock .code-header .stats .left.item pre{
40
41 }
40 }
42 div.codeblock .code-header .stats .left.item.last{
41 div.codeblock .code-header .stats .left.item.last{
43 border-right:none;
42 border-right:none;
44 }
43 }
45 div.codeblock .code-header .stats .buttons{
44 div.codeblock .code-header .stats .buttons{
46 float:right;
45 float:right;
47 padding-right:4px;
46 padding-right:4px;
48 }
47 }
49
48
50 div.codeblock .code-header .author{
49 div.codeblock .code-header .author{
51 margin-left:25px;
50 margin-left:25px;
52 font-weight: bold;
51 font-weight: bold;
53 height: 25px;
52 height: 25px;
54 }
53 }
55 div.codeblock .code-header .author .user{
54 div.codeblock .code-header .author .user{
56 padding-top:3px;
55 padding-top:3px;
57 }
56 }
58 div.codeblock .code-header .commit{
57 div.codeblock .code-header .commit{
59 margin-left:25px;
58 margin-left:25px;
60 font-weight: normal;
59 font-weight: normal;
61 white-space:pre;
60 white-space:pre;
62 }
61 }
63
62
64 div.codeblock .code-body table{
63 div.codeblock .code-body table{
65 width: 0 !important;
64 width: 0 !important;
66 border: 0px !important;
65 border: 0px !important;
67 }
66 }
68 div.codeblock .code-body table td {
67 div.codeblock .code-body table td {
69 border: 0px !important;
68 border: 0px !important;
70 }
69 }
71 div.code-body {
70 div.code-body {
72 background-color: #FFFFFF;
71 background-color: #FFFFFF;
73 }
72 }
74
73
75 div.codeblock .code-header .search-path {
74 div.codeblock .code-header .search-path {
76 padding: 0px 0px 0px 10px;
75 padding: 0px 0px 0px 10px;
77 }
76 }
78
77
79 div.search-code-body {
78 div.search-code-body {
80 background-color: #FFFFFF;
79 background-color: #FFFFFF;
81 padding: 5px 0px 5px 10px;
80 padding: 5px 0px 5px 10px;
82 }
81 }
83
82
84 div.search-code-body pre .match{
83 div.search-code-body pre .match{
85 background-color: #FAFFA6;
84 background-color: #FAFFA6;
86 }
85 }
87 div.search-code-body pre .break{
86 div.search-code-body pre .break{
88 background-color: #DDE7EF;
87 background-color: #DDE7EF;
89 width: 100%;
88 width: 100%;
90 color: #747474;
89 color: #747474;
91 display: block;
90 display: block;
92
93 }
91 }
94 div.annotatediv{
92 div.annotatediv{
95 margin-left:2px;
93 margin-left:2px;
96 margin-right:4px;
94 margin-right:4px;
97 }
95 }
98 .code-highlight {
96 .code-highlight {
99 padding: 0px;
97 padding: 0px;
100 margin-top: 5px;
98 margin-top: 5px;
101 margin-bottom: 5px;
99 margin-bottom: 5px;
102 border-left: 2px solid #ccc;
100 border-left: 2px solid #ccc;
103 }
101 }
104 .code-highlight pre, .linenodiv pre {
102 .code-highlight pre, .linenodiv pre {
105 padding: 5px;
103 padding: 5px;
106 margin: 0;
104 margin: 0;
107 }
105 }
108 .code-highlight pre div:target {
106 .code-highlight pre div:target {
109 background-color: #FFFFBE !important;
107 background-color: #FFFFBE !important;
110 }
108 }
111
109
112 .linenos a { text-decoration: none; }
110 .linenos a { text-decoration: none; }
113
111
114 .code { display: block; }
112 .code { display: block; }
115 .code-highlight .hll, .codehilite .hll { background-color: #ffffcc }
113 .code-highlight .hll, .codehilite .hll { background-color: #ffffcc }
116 .code-highlight .c, .codehilite .c { color: #408080; font-style: italic } /* Comment */
114 .code-highlight .c, .codehilite .c { color: #408080; font-style: italic } /* Comment */
117 .code-highlight .err, .codehilite .err { border: 1px solid #FF0000 } /* Error */
115 .code-highlight .err, .codehilite .err { border: 1px solid #FF0000 } /* Error */
118 .code-highlight .k, .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
116 .code-highlight .k, .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
119 .code-highlight .o, .codehilite .o { color: #666666 } /* Operator */
117 .code-highlight .o, .codehilite .o { color: #666666 } /* Operator */
120 .code-highlight .cm, .codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
118 .code-highlight .cm, .codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
121 .code-highlight .cp, .codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
119 .code-highlight .cp, .codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
122 .code-highlight .c1, .codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
120 .code-highlight .c1, .codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
123 .code-highlight .cs, .codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
121 .code-highlight .cs, .codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
124 .code-highlight .gd, .codehilite .gd { color: #A00000 } /* Generic.Deleted */
122 .code-highlight .gd, .codehilite .gd { color: #A00000 } /* Generic.Deleted */
125 .code-highlight .ge, .codehilite .ge { font-style: italic } /* Generic.Emph */
123 .code-highlight .ge, .codehilite .ge { font-style: italic } /* Generic.Emph */
126 .code-highlight .gr, .codehilite .gr { color: #FF0000 } /* Generic.Error */
124 .code-highlight .gr, .codehilite .gr { color: #FF0000 } /* Generic.Error */
127 .code-highlight .gh, .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
125 .code-highlight .gh, .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
128 .code-highlight .gi, .codehilite .gi { color: #00A000 } /* Generic.Inserted */
126 .code-highlight .gi, .codehilite .gi { color: #00A000 } /* Generic.Inserted */
129 .code-highlight .go, .codehilite .go { color: #808080 } /* Generic.Output */
127 .code-highlight .go, .codehilite .go { color: #808080 } /* Generic.Output */
130 .code-highlight .gp, .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
128 .code-highlight .gp, .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
131 .code-highlight .gs, .codehilite .gs { font-weight: bold } /* Generic.Strong */
129 .code-highlight .gs, .codehilite .gs { font-weight: bold } /* Generic.Strong */
132 .code-highlight .gu, .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
130 .code-highlight .gu, .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
133 .code-highlight .gt, .codehilite .gt { color: #0040D0 } /* Generic.Traceback */
131 .code-highlight .gt, .codehilite .gt { color: #0040D0 } /* Generic.Traceback */
134 .code-highlight .kc, .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
132 .code-highlight .kc, .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
135 .code-highlight .kd, .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
133 .code-highlight .kd, .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
136 .code-highlight .kn, .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
134 .code-highlight .kn, .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
137 .code-highlight .kp, .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
135 .code-highlight .kp, .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
138 .code-highlight .kr, .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
136 .code-highlight .kr, .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
139 .code-highlight .kt, .codehilite .kt { color: #B00040 } /* Keyword.Type */
137 .code-highlight .kt, .codehilite .kt { color: #B00040 } /* Keyword.Type */
140 .code-highlight .m, .codehilite .m { color: #666666 } /* Literal.Number */
138 .code-highlight .m, .codehilite .m { color: #666666 } /* Literal.Number */
141 .code-highlight .s, .codehilite .s { color: #BA2121 } /* Literal.String */
139 .code-highlight .s, .codehilite .s { color: #BA2121 } /* Literal.String */
142 .code-highlight .na, .codehilite .na { color: #7D9029 } /* Name.Attribute */
140 .code-highlight .na, .codehilite .na { color: #7D9029 } /* Name.Attribute */
143 .code-highlight .nb, .codehilite .nb { color: #008000 } /* Name.Builtin */
141 .code-highlight .nb, .codehilite .nb { color: #008000 } /* Name.Builtin */
144 .code-highlight .nc, .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
142 .code-highlight .nc, .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
145 .code-highlight .no, .codehilite .no { color: #880000 } /* Name.Constant */
143 .code-highlight .no, .codehilite .no { color: #880000 } /* Name.Constant */
146 .code-highlight .nd, .codehilite .nd { color: #AA22FF } /* Name.Decorator */
144 .code-highlight .nd, .codehilite .nd { color: #AA22FF } /* Name.Decorator */
147 .code-highlight .ni, .codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
145 .code-highlight .ni, .codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
148 .code-highlight .ne, .codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
146 .code-highlight .ne, .codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
149 .code-highlight .nf, .codehilite .nf { color: #0000FF } /* Name.Function */
147 .code-highlight .nf, .codehilite .nf { color: #0000FF } /* Name.Function */
150 .code-highlight .nl, .codehilite .nl { color: #A0A000 } /* Name.Label */
148 .code-highlight .nl, .codehilite .nl { color: #A0A000 } /* Name.Label */
151 .code-highlight .nn, .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
149 .code-highlight .nn, .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
152 .code-highlight .nt, .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
150 .code-highlight .nt, .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
153 .code-highlight .nv, .codehilite .nv { color: #19177C } /* Name.Variable */
151 .code-highlight .nv, .codehilite .nv { color: #19177C } /* Name.Variable */
154 .code-highlight .ow, .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
152 .code-highlight .ow, .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
155 .code-highlight .w, .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
153 .code-highlight .w, .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
156 .code-highlight .mf, .codehilite .mf { color: #666666 } /* Literal.Number.Float */
154 .code-highlight .mf, .codehilite .mf { color: #666666 } /* Literal.Number.Float */
157 .code-highlight .mh, .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
155 .code-highlight .mh, .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
158 .code-highlight .mi, .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
156 .code-highlight .mi, .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
159 .code-highlight .mo, .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
157 .code-highlight .mo, .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
160 .code-highlight .sb, .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
158 .code-highlight .sb, .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
161 .code-highlight .sc, .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
159 .code-highlight .sc, .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
162 .code-highlight .sd, .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
160 .code-highlight .sd, .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
163 .code-highlight .s2, .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
161 .code-highlight .s2, .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
164 .code-highlight .se, .codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
162 .code-highlight .se, .codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
165 .code-highlight .sh, .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
163 .code-highlight .sh, .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
166 .code-highlight .si, .codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
164 .code-highlight .si, .codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
167 .code-highlight .sx, .codehilite .sx { color: #008000 } /* Literal.String.Other */
165 .code-highlight .sx, .codehilite .sx { color: #008000 } /* Literal.String.Other */
168 .code-highlight .sr, .codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
166 .code-highlight .sr, .codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
169 .code-highlight .s1, .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
167 .code-highlight .s1, .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
170 .code-highlight .ss, .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
168 .code-highlight .ss, .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
171 .code-highlight .bp, .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
169 .code-highlight .bp, .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
172 .code-highlight .vc, .codehilite .vc { color: #19177C } /* Name.Variable.Class */
170 .code-highlight .vc, .codehilite .vc { color: #19177C } /* Name.Variable.Class */
173 .code-highlight .vg, .codehilite .vg { color: #19177C } /* Name.Variable.Global */
171 .code-highlight .vg, .codehilite .vg { color: #19177C } /* Name.Variable.Global */
174 .code-highlight .vi, .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
172 .code-highlight .vi, .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
175 .code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
173 .code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
This diff has been collapsed as it changes many lines, (3590 lines changed) Show them Hide them
@@ -1,4881 +1,4873 b''
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td
2 {
2 {
3 border: 0;
3 border: 0;
4 outline: 0;
4 outline: 0;
5 font-size: 100%;
5 font-size: 100%;
6 vertical-align: baseline;
6 vertical-align: baseline;
7 background: transparent;
7 background: transparent;
8 margin: 0;
8 margin: 0;
9 padding: 0;
9 padding: 0;
10 }
10 }
11
11
12 body {
12 body {
13 line-height: 1;
13 line-height: 1;
14 height: 100%;
14 height: 100%;
15 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
16 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
16 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
17 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
17 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
18 color: #000;
18 color: #000;
19 margin: 0;
19 margin: 0;
20 padding: 0;
20 padding: 0;
21 font-size: 12px;
21 font-size: 12px;
22 }
22 }
23
23
24 ol,ul {
24 ol,ul {
25 list-style: none;
25 list-style: none;
26 }
26 }
27
27
28 blockquote,q {
28 blockquote,q {
29 quotes: none;
29 quotes: none;
30 }
30 }
31
31
32 blockquote:before,blockquote:after,q:before,q:after {
32 blockquote:before,blockquote:after,q:before,q:after {
33 content: none;
33 content: none;
34 }
34 }
35
35
36 :focus {
36 :focus {
37 outline: 0;
37 outline: 0;
38 }
38 }
39
39
40 del {
40 del {
41 text-decoration: line-through;
41 text-decoration: line-through;
42 }
42 }
43
43
44 table {
44 table {
45 border-collapse: collapse;
45 border-collapse: collapse;
46 border-spacing: 0;
46 border-spacing: 0;
47 }
47 }
48
48
49 html {
49 html {
50 height: 100%;
50 height: 100%;
51 }
51 }
52
52
53 a {
53 a {
54 color: #003367;
54 color: #003367;
55 text-decoration: none;
55 text-decoration: none;
56 cursor: pointer;
56 cursor: pointer;
57 }
57 }
58
58
59 a:hover {
59 a:hover {
60 color: #316293;
60 color: #316293;
61 text-decoration: underline;
61 text-decoration: underline;
62 }
62 }
63
63
64 h1,h2,h3,h4,h5,h6,
64 h1,h2,h3,h4,h5,h6,
65 div.h1,div.h2,div.h3,div.h4,div.h5,div.h6 {
65 div.h1,div.h2,div.h3,div.h4,div.h5,div.h6 {
66 color: #292929;
66 color: #292929;
67 font-weight: 700;
67 font-weight: 700;
68 }
68 }
69
69
70 h1,div.h1 {
70 h1,div.h1 {
71 font-size: 22px;
71 font-size: 22px;
72 }
72 }
73
73
74 h2,div.h2 {
74 h2,div.h2 {
75 font-size: 20px;
75 font-size: 20px;
76 }
76 }
77
77
78 h3,div.h3 {
78 h3,div.h3 {
79 font-size: 18px;
79 font-size: 18px;
80 }
80 }
81
81
82 h4,div.h4 {
82 h4,div.h4 {
83 font-size: 16px;
83 font-size: 16px;
84 }
84 }
85
85
86 h5,div.h5 {
86 h5,div.h5 {
87 font-size: 14px;
87 font-size: 14px;
88 }
88 }
89
89
90 h6,div.h6 {
90 h6,div.h6 {
91 font-size: 11px;
91 font-size: 11px;
92 }
92 }
93
93
94 ul.circle {
94 ul.circle {
95 list-style-type: circle;
95 list-style-type: circle;
96 }
96 }
97
97
98 ul.disc {
98 ul.disc {
99 list-style-type: disc;
99 list-style-type: disc;
100 }
100 }
101
101
102 ul.square {
102 ul.square {
103 list-style-type: square;
103 list-style-type: square;
104 }
104 }
105
105
106 ol.lower-roman {
106 ol.lower-roman {
107 list-style-type: lower-roman;
107 list-style-type: lower-roman;
108 }
108 }
109
109
110 ol.upper-roman {
110 ol.upper-roman {
111 list-style-type: upper-roman;
111 list-style-type: upper-roman;
112 }
112 }
113
113
114 ol.lower-alpha {
114 ol.lower-alpha {
115 list-style-type: lower-alpha;
115 list-style-type: lower-alpha;
116 }
116 }
117
117
118 ol.upper-alpha {
118 ol.upper-alpha {
119 list-style-type: upper-alpha;
119 list-style-type: upper-alpha;
120 }
120 }
121
121
122 ol.decimal {
122 ol.decimal {
123 list-style-type: decimal;
123 list-style-type: decimal;
124 }
124 }
125
125
126 div.color {
126 div.color {
127 clear: both;
127 clear: both;
128 overflow: hidden;
128 overflow: hidden;
129 position: absolute;
129 position: absolute;
130 background: #FFF;
130 background: #FFF;
131 margin: 7px 0 0 60px;
131 margin: 7px 0 0 60px;
132 padding: 1px 1px 1px 0;
132 padding: 1px 1px 1px 0;
133 }
133 }
134
134
135 div.color a {
135 div.color a {
136 width: 15px;
136 width: 15px;
137 height: 15px;
137 height: 15px;
138 display: block;
138 display: block;
139 float: left;
139 float: left;
140 margin: 0 0 0 1px;
140 margin: 0 0 0 1px;
141 padding: 0;
141 padding: 0;
142 }
142 }
143
143
144 div.options {
144 div.options {
145 clear: both;
145 clear: both;
146 overflow: hidden;
146 overflow: hidden;
147 position: absolute;
147 position: absolute;
148 background: #FFF;
148 background: #FFF;
149 margin: 7px 0 0 162px;
149 margin: 7px 0 0 162px;
150 padding: 0;
150 padding: 0;
151 }
151 }
152
152
153 div.options a {
153 div.options a {
154 height: 1%;
154 height: 1%;
155 display: block;
155 display: block;
156 text-decoration: none;
156 text-decoration: none;
157 margin: 0;
157 margin: 0;
158 padding: 3px 8px;
158 padding: 3px 8px;
159 }
159 }
160
160
161 .top-left-rounded-corner {
161 .top-left-rounded-corner {
162 -webkit-border-top-left-radius: 8px;
162 -webkit-border-top-left-radius: 8px;
163 -khtml-border-radius-topleft: 8px;
163 -khtml-border-radius-topleft: 8px;
164 -moz-border-radius-topleft: 8px;
164 -moz-border-radius-topleft: 8px;
165 border-top-left-radius: 8px;
165 border-top-left-radius: 8px;
166 }
166 }
167
167
168 .top-right-rounded-corner {
168 .top-right-rounded-corner {
169 -webkit-border-top-right-radius: 8px;
169 -webkit-border-top-right-radius: 8px;
170 -khtml-border-radius-topright: 8px;
170 -khtml-border-radius-topright: 8px;
171 -moz-border-radius-topright: 8px;
171 -moz-border-radius-topright: 8px;
172 border-top-right-radius: 8px;
172 border-top-right-radius: 8px;
173 }
173 }
174
174
175 .bottom-left-rounded-corner {
175 .bottom-left-rounded-corner {
176 -webkit-border-bottom-left-radius: 8px;
176 -webkit-border-bottom-left-radius: 8px;
177 -khtml-border-radius-bottomleft: 8px;
177 -khtml-border-radius-bottomleft: 8px;
178 -moz-border-radius-bottomleft: 8px;
178 -moz-border-radius-bottomleft: 8px;
179 border-bottom-left-radius: 8px;
179 border-bottom-left-radius: 8px;
180 }
180 }
181
181
182 .bottom-right-rounded-corner {
182 .bottom-right-rounded-corner {
183 -webkit-border-bottom-right-radius: 8px;
183 -webkit-border-bottom-right-radius: 8px;
184 -khtml-border-radius-bottomright: 8px;
184 -khtml-border-radius-bottomright: 8px;
185 -moz-border-radius-bottomright: 8px;
185 -moz-border-radius-bottomright: 8px;
186 border-bottom-right-radius: 8px;
186 border-bottom-right-radius: 8px;
187 }
187 }
188
188
189 .top-left-rounded-corner-mid {
189 .top-left-rounded-corner-mid {
190 -webkit-border-top-left-radius: 4px;
190 -webkit-border-top-left-radius: 4px;
191 -khtml-border-radius-topleft: 4px;
191 -khtml-border-radius-topleft: 4px;
192 -moz-border-radius-topleft: 4px;
192 -moz-border-radius-topleft: 4px;
193 border-top-left-radius: 4px;
193 border-top-left-radius: 4px;
194 }
194 }
195
195
196 .top-right-rounded-corner-mid {
196 .top-right-rounded-corner-mid {
197 -webkit-border-top-right-radius: 4px;
197 -webkit-border-top-right-radius: 4px;
198 -khtml-border-radius-topright: 4px;
198 -khtml-border-radius-topright: 4px;
199 -moz-border-radius-topright: 4px;
199 -moz-border-radius-topright: 4px;
200 border-top-right-radius: 4px;
200 border-top-right-radius: 4px;
201 }
201 }
202
202
203 .bottom-left-rounded-corner-mid {
203 .bottom-left-rounded-corner-mid {
204 -webkit-border-bottom-left-radius: 4px;
204 -webkit-border-bottom-left-radius: 4px;
205 -khtml-border-radius-bottomleft: 4px;
205 -khtml-border-radius-bottomleft: 4px;
206 -moz-border-radius-bottomleft: 4px;
206 -moz-border-radius-bottomleft: 4px;
207 border-bottom-left-radius: 4px;
207 border-bottom-left-radius: 4px;
208 }
208 }
209
209
210 .bottom-right-rounded-corner-mid {
210 .bottom-right-rounded-corner-mid {
211 -webkit-border-bottom-right-radius: 4px;
211 -webkit-border-bottom-right-radius: 4px;
212 -khtml-border-radius-bottomright: 4px;
212 -khtml-border-radius-bottomright: 4px;
213 -moz-border-radius-bottomright: 4px;
213 -moz-border-radius-bottomright: 4px;
214 border-bottom-right-radius: 4px;
214 border-bottom-right-radius: 4px;
215 }
215 }
216
216
217 .help-block {
217 .help-block {
218 color: #999999;
218 color: #999999;
219 display: block;
219 display: block;
220 margin-bottom: 0;
220 margin-bottom: 0;
221 margin-top: 5px;
221 margin-top: 5px;
222 }
222 }
223
223
224 .empty_data{
224 .empty_data{
225 color:#B9B9B9;
225 color:#B9B9B9;
226 }
226 }
227
227
228 a.permalink{
228 a.permalink{
229 visibility: hidden;
229 visibility: hidden;
230 }
230 }
231
231
232 a.permalink:hover{
232 a.permalink:hover{
233 text-decoration: none;
233 text-decoration: none;
234 }
234 }
235
235
236 h1:hover > a.permalink,
236 h1:hover > a.permalink,
237 h2:hover > a.permalink,
237 h2:hover > a.permalink,
238 h3:hover > a.permalink,
238 h3:hover > a.permalink,
239 h4:hover > a.permalink,
239 h4:hover > a.permalink,
240 h5:hover > a.permalink,
240 h5:hover > a.permalink,
241 h6:hover > a.permalink,
241 h6:hover > a.permalink,
242 div:hover > a.permalink {
242 div:hover > a.permalink {
243 visibility: visible;
243 visibility: visible;
244 }
244 }
245
245
246 #header {
246 #header {
247 margin: 0;
247 margin: 0;
248 padding: 0 10px;
248 padding: 0 10px;
249 }
249 }
250
250
251 #header ul#logged-user {
251 #header ul#logged-user {
252 margin-bottom: 5px !important;
252 margin-bottom: 5px !important;
253 -webkit-border-radius: 0px 0px 8px 8px;
253 -webkit-border-radius: 0px 0px 8px 8px;
254 -khtml-border-radius: 0px 0px 8px 8px;
254 -khtml-border-radius: 0px 0px 8px 8px;
255 -moz-border-radius: 0px 0px 8px 8px;
255 -moz-border-radius: 0px 0px 8px 8px;
256 border-radius: 0px 0px 8px 8px;
256 border-radius: 0px 0px 8px 8px;
257 height: 37px;
257 height: 37px;
258 background-color: #003B76;
258 background-color: #003B76;
259 background-repeat: repeat-x;
259 background-repeat: repeat-x;
260 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
260 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
261 background-image: -moz-linear-gradient(top, #003b76, #00376e);
261 background-image: -moz-linear-gradient(top, #003b76, #00376e);
262 background-image: -ms-linear-gradient(top, #003b76, #00376e);
262 background-image: -ms-linear-gradient(top, #003b76, #00376e);
263 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
263 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
264 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
264 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
265 background-image: -o-linear-gradient(top, #003b76, #00376e);
265 background-image: -o-linear-gradient(top, #003b76, #00376e);
266 background-image: linear-gradient(top, #003b76, #00376e);
266 background-image: linear-gradient(top, #003b76, #00376e);
267 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
267 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
268 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
268 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
269 }
269 }
270
270
271 #header ul#logged-user li {
271 #header ul#logged-user li {
272 list-style: none;
272 list-style: none;
273 float: left;
273 float: left;
274 margin: 8px 0 0;
274 margin: 8px 0 0;
275 padding: 4px 12px;
275 padding: 4px 12px;
276 border-left: 1px solid #316293;
276 border-left: 1px solid #316293;
277 }
277 }
278
278
279 #header ul#logged-user li.first {
279 #header ul#logged-user li.first {
280 border-left: none;
280 border-left: none;
281 margin: 4px;
281 margin: 4px;
282 }
282 }
283
283
284 #header ul#logged-user li.first div.gravatar {
284 #header ul#logged-user li.first div.gravatar {
285 margin-top: -2px;
285 margin-top: -2px;
286 }
286 }
287
287
288 #header ul#logged-user li.first div.account {
288 #header ul#logged-user li.first div.account {
289 padding-top: 4px;
289 padding-top: 4px;
290 float: left;
290 float: left;
291 }
291 }
292
292
293 #header ul#logged-user li.last {
293 #header ul#logged-user li.last {
294 border-right: none;
294 border-right: none;
295 }
295 }
296
296
297 #header ul#logged-user li a {
297 #header ul#logged-user li a {
298 color: #fff;
298 color: #fff;
299 font-weight: 700;
299 font-weight: 700;
300 text-decoration: none;
300 text-decoration: none;
301 }
301 }
302
302
303 #header ul#logged-user li a:hover {
303 #header ul#logged-user li a:hover {
304 text-decoration: underline;
304 text-decoration: underline;
305 }
305 }
306
306
307 #header ul#logged-user li.highlight a {
307 #header ul#logged-user li.highlight a {
308 color: #fff;
308 color: #fff;
309 }
309 }
310
310
311 #header ul#logged-user li.highlight a:hover {
311 #header ul#logged-user li.highlight a:hover {
312 color: #FFF;
312 color: #FFF;
313 }
313 }
314
314
315 #header #header-inner {
315 #header #header-inner {
316 min-height: 44px;
316 min-height: 44px;
317 clear: both;
317 clear: both;
318 position: relative;
318 position: relative;
319 background-color: #003B76;
319 background-color: #003B76;
320 background-repeat: repeat-x;
320 background-repeat: repeat-x;
321 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
321 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
322 background-image: -moz-linear-gradient(top, #003b76, #00376e);
322 background-image: -moz-linear-gradient(top, #003b76, #00376e);
323 background-image: -ms-linear-gradient(top, #003b76, #00376e);
323 background-image: -ms-linear-gradient(top, #003b76, #00376e);
324 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
324 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
325 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
325 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
326 background-image: -o-linear-gradient(top, #003b76, #00376e);
326 background-image: -o-linear-gradient(top, #003b76, #00376e);
327 background-image: linear-gradient(top, #003b76, #00376e);
327 background-image: linear-gradient(top, #003b76, #00376e);
328 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
328 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
329 margin: 0;
329 margin: 0;
330 padding: 0;
330 padding: 0;
331 display: block;
331 display: block;
332 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
332 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
333 -webkit-border-radius: 4px 4px 4px 4px;
333 -webkit-border-radius: 4px 4px 4px 4px;
334 -khtml-border-radius: 4px 4px 4px 4px;
334 -khtml-border-radius: 4px 4px 4px 4px;
335 -moz-border-radius: 4px 4px 4px 4px;
335 -moz-border-radius: 4px 4px 4px 4px;
336 border-radius: 4px 4px 4px 4px;
336 border-radius: 4px 4px 4px 4px;
337 }
337 }
338 #header #header-inner.hover{
338 #header #header-inner.hover{
339 position: fixed !important;
339 position: fixed !important;
340 width: 100% !important;
340 width: 100% !important;
341 margin-left: -10px !important;
341 margin-left: -10px !important;
342 z-index: 10000;
342 z-index: 10000;
343 -webkit-border-radius: 0px 0px 0px 0px;
343 -webkit-border-radius: 0px 0px 0px 0px;
344 -khtml-border-radius: 0px 0px 0px 0px;
344 -khtml-border-radius: 0px 0px 0px 0px;
345 -moz-border-radius: 0px 0px 0px 0px;
345 -moz-border-radius: 0px 0px 0px 0px;
346 border-radius: 0px 0px 0px 0px;
346 border-radius: 0px 0px 0px 0px;
347 }
347 }
348
348
349 .ie7 #header #header-inner.hover,
349 .ie7 #header #header-inner.hover,
350 .ie8 #header #header-inner.hover,
350 .ie8 #header #header-inner.hover,
351 .ie9 #header #header-inner.hover
351 .ie9 #header #header-inner.hover
352 {
352 {
353 z-index: auto !important;
353 z-index: auto !important;
354 }
354 }
355
355
356 .header-pos-fix, .anchor{
356 .header-pos-fix, .anchor{
357 margin-top: -46px;
357 margin-top: -46px;
358 padding-top: 46px;
358 padding-top: 46px;
359 }
359 }
360
360
361 #header #header-inner #home a {
361 #header #header-inner #home a {
362 height: 40px;
362 height: 40px;
363 width: 46px;
363 width: 46px;
364 display: block;
364 display: block;
365 background: url("../images/button_home.png");
365 background: url("../images/button_home.png");
366 background-position: 0 0;
366 background-position: 0 0;
367 margin: 0;
367 margin: 0;
368 padding: 0;
368 padding: 0;
369 }
369 }
370
370
371 #header #header-inner #home a:hover {
371 #header #header-inner #home a:hover {
372 background-position: 0 -40px;
372 background-position: 0 -40px;
373 }
373 }
374
374
375 #header #header-inner #logo {
375 #header #header-inner #logo {
376 float: left;
376 float: left;
377 position: absolute;
377 position: absolute;
378 }
378 }
379
379
380 #header #header-inner #logo h1 {
380 #header #header-inner #logo h1 {
381 color: #FFF;
381 color: #FFF;
382 font-size: 20px;
382 font-size: 20px;
383 margin: 12px 0 0 13px;
383 margin: 12px 0 0 13px;
384 padding: 0;
384 padding: 0;
385 }
385 }
386
386
387 #header #header-inner #logo a {
387 #header #header-inner #logo a {
388 color: #fff;
388 color: #fff;
389 text-decoration: none;
389 text-decoration: none;
390 }
390 }
391
391
392 #header #header-inner #logo a:hover {
392 #header #header-inner #logo a:hover {
393 color: #bfe3ff;
393 color: #bfe3ff;
394 }
394 }
395
395
396 #header #header-inner #quick,#header #header-inner #quick ul {
396 #header #header-inner #quick,#header #header-inner #quick ul {
397 position: relative;
397 position: relative;
398 float: right;
398 float: right;
399 list-style-type: none;
399 list-style-type: none;
400 list-style-position: outside;
400 list-style-position: outside;
401 margin: 8px 8px 0 0;
401 margin: 8px 8px 0 0;
402 padding: 0;
402 padding: 0;
403 }
403 }
404
404
405 #header #header-inner #quick li {
405 #header #header-inner #quick li {
406 position: relative;
406 position: relative;
407 float: left;
407 float: left;
408 margin: 0 5px 0 0;
408 margin: 0 5px 0 0;
409 padding: 0;
409 padding: 0;
410 }
410 }
411
411
412 #header #header-inner #quick li a.menu_link {
412 #header #header-inner #quick li a.menu_link {
413 top: 0;
413 top: 0;
414 left: 0;
414 left: 0;
415 height: 1%;
415 height: 1%;
416 display: block;
416 display: block;
417 clear: both;
417 clear: both;
418 overflow: hidden;
418 overflow: hidden;
419 color: #FFF;
419 color: #FFF;
420 font-weight: 700;
420 font-weight: 700;
421 text-decoration: none;
421 text-decoration: none;
422 background: #369;
422 background: #369;
423 padding: 0;
423 padding: 0;
424 -webkit-border-radius: 4px 4px 4px 4px;
424 -webkit-border-radius: 4px 4px 4px 4px;
425 -khtml-border-radius: 4px 4px 4px 4px;
425 -khtml-border-radius: 4px 4px 4px 4px;
426 -moz-border-radius: 4px 4px 4px 4px;
426 -moz-border-radius: 4px 4px 4px 4px;
427 border-radius: 4px 4px 4px 4px;
427 border-radius: 4px 4px 4px 4px;
428 }
428 }
429
429
430 #header #header-inner #quick li span.short {
430 #header #header-inner #quick li span.short {
431 padding: 9px 6px 8px 6px;
431 padding: 9px 6px 8px 6px;
432 }
432 }
433
433
434 #header #header-inner #quick li span {
434 #header #header-inner #quick li span {
435 top: 0;
435 top: 0;
436 right: 0;
436 right: 0;
437 height: 1%;
437 height: 1%;
438 display: block;
438 display: block;
439 float: left;
439 float: left;
440 border-left: 1px solid #3f6f9f;
440 border-left: 1px solid #3f6f9f;
441 margin: 0;
441 margin: 0;
442 padding: 10px 12px 8px 10px;
442 padding: 10px 12px 8px 10px;
443 }
443 }
444
444
445 #header #header-inner #quick li span.normal {
445 #header #header-inner #quick li span.normal {
446 border: none;
446 border: none;
447 padding: 10px 12px 8px;
447 padding: 10px 12px 8px;
448 }
448 }
449
449
450 #header #header-inner #quick li span.icon {
450 #header #header-inner #quick li span.icon {
451 top: 0;
451 top: 0;
452 left: 0;
452 left: 0;
453 border-left: none;
453 border-left: none;
454 border-right: 1px solid #2e5c89;
454 border-right: 1px solid #2e5c89;
455 padding: 8px 6px 4px;
455 padding: 8px 6px 4px;
456 min-width: 16px;
456 min-width: 16px;
457 min-height: 16px;
457 min-height: 16px;
458 }
458 }
459
459
460 #header #header-inner #quick li span.icon_short {
460 #header #header-inner #quick li span.icon_short {
461 top: 0;
461 top: 0;
462 left: 0;
462 left: 0;
463 border-left: none;
463 border-left: none;
464 border-right: 1px solid #2e5c89;
464 border-right: 1px solid #2e5c89;
465 padding: 8px 6px 4px;
465 padding: 8px 6px 4px;
466 }
466 }
467
467
468 #header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
468 #header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
469 {
469 {
470 margin: 0px -2px 0px 0px;
470 margin: 0px -2px 0px 0px;
471 }
471 }
472
472
473 #header #header-inner #quick li.current a,
473 #header #header-inner #quick li.current a,
474 #header #header-inner #quick li a:hover {
474 #header #header-inner #quick li a:hover {
475 background: #4e4e4e no-repeat top left;
475 background: #4e4e4e no-repeat top left;
476 }
476 }
477
477
478 #header #header-inner #quick li.current a span,
478 #header #header-inner #quick li.current a span,
479 #header #header-inner #quick li a:hover span {
479 #header #header-inner #quick li a:hover span {
480 border-left: 1px solid #545454;
480 border-left: 1px solid #545454;
481 }
481 }
482
482
483 #header #header-inner #quick li.current a span.icon,
483 #header #header-inner #quick li.current a span.icon,
484 #header #header-inner #quick li.current a span.icon_short,
484 #header #header-inner #quick li.current a span.icon_short,
485 #header #header-inner #quick li a:hover span.icon,
485 #header #header-inner #quick li a:hover span.icon,
486 #header #header-inner #quick li a:hover span.icon_short
486 #header #header-inner #quick li a:hover span.icon_short
487 {
487 {
488 border-left: none;
488 border-left: none;
489 border-right: 1px solid #464646;
489 border-right: 1px solid #464646;
490 }
490 }
491
491
492 #header #header-inner #quick ul {
492 #header #header-inner #quick ul {
493 top: 29px;
493 top: 29px;
494 right: 0;
494 right: 0;
495 min-width: 200px;
495 min-width: 200px;
496 display: none;
496 display: none;
497 position: absolute;
497 position: absolute;
498 background: #FFF;
498 background: #FFF;
499 border: 1px solid #666;
499 border: 1px solid #666;
500 border-top: 1px solid #003367;
500 border-top: 1px solid #003367;
501 z-index: 100;
501 z-index: 100;
502 margin: 0px 0px 0px 0px;
502 margin: 0px 0px 0px 0px;
503 padding: 0;
503 padding: 0;
504 }
504 }
505
505
506 #header #header-inner #quick ul.repo_switcher {
506 #header #header-inner #quick ul.repo_switcher {
507 max-height: 275px;
507 max-height: 275px;
508 overflow-x: hidden;
508 overflow-x: hidden;
509 overflow-y: auto;
509 overflow-y: auto;
510 }
510 }
511
511
512 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
512 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
513 float: none;
513 float: none;
514 margin: 0;
514 margin: 0;
515 border-bottom: 2px solid #003367;
515 border-bottom: 2px solid #003367;
516 }
516 }
517
517
518 #header #header-inner #quick .repo_switcher_type {
518 #header #header-inner #quick .repo_switcher_type {
519 position: absolute;
519 position: absolute;
520 left: 0;
520 left: 0;
521 top: 9px;
521 top: 9px;
522 }
522 }
523
523
524 #header #header-inner #quick li ul li {
524 #header #header-inner #quick li ul li {
525 border-bottom: 1px solid #ddd;
525 border-bottom: 1px solid #ddd;
526 }
526 }
527
527
528 #header #header-inner #quick li ul li a {
528 #header #header-inner #quick li ul li a {
529 width: 182px;
529 width: 182px;
530 height: auto;
530 height: auto;
531 display: block;
531 display: block;
532 float: left;
532 float: left;
533 background: #FFF;
533 background: #FFF;
534 color: #003367;
534 color: #003367;
535 font-weight: 400;
535 font-weight: 400;
536 margin: 0;
536 margin: 0;
537 padding: 7px 9px;
537 padding: 7px 9px;
538 }
538 }
539
539
540 #header #header-inner #quick li ul li a:hover {
540 #header #header-inner #quick li ul li a:hover {
541 color: #000;
541 color: #000;
542 background: #FFF;
542 background: #FFF;
543 }
543 }
544
544
545 #header #header-inner #quick ul ul {
545 #header #header-inner #quick ul ul {
546 top: auto;
546 top: auto;
547 }
547 }
548
548
549 #header #header-inner #quick li ul ul {
549 #header #header-inner #quick li ul ul {
550 right: 200px;
550 right: 200px;
551 max-height: 290px;
551 max-height: 290px;
552 overflow: auto;
552 overflow: auto;
553 overflow-x: hidden;
553 overflow-x: hidden;
554 white-space: normal;
554 white-space: normal;
555 }
555 }
556
556
557 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
557 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
558 {
558 {
559 background: url("../images/icons/book.png") no-repeat scroll 4px 9px
559 background: url("../images/icons/book.png") no-repeat scroll 4px 9px
560 #FFF;
560 #FFF;
561 width: 167px;
561 width: 167px;
562 margin: 0;
562 margin: 0;
563 padding: 12px 9px 7px 24px;
563 padding: 12px 9px 7px 24px;
564 }
564 }
565
565
566 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
566 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
567 {
567 {
568 background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
568 background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
569 #FFF;
569 #FFF;
570 min-width: 167px;
570 min-width: 167px;
571 margin: 0;
571 margin: 0;
572 padding: 12px 9px 7px 24px;
572 padding: 12px 9px 7px 24px;
573 }
573 }
574
574
575 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
575 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
576 {
576 {
577 background: url("../images/icons/lock_open.png") no-repeat scroll 4px
577 background: url("../images/icons/lock_open.png") no-repeat scroll 4px
578 9px #FFF;
578 9px #FFF;
579 min-width: 167px;
579 min-width: 167px;
580 margin: 0;
580 margin: 0;
581 padding: 12px 9px 7px 24px;
581 padding: 12px 9px 7px 24px;
582 }
582 }
583
583
584 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
584 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
585 {
585 {
586 background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
586 background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
587 #FFF;
587 #FFF;
588 min-width: 167px;
588 min-width: 167px;
589 margin: 0 0 0 14px;
589 margin: 0 0 0 14px;
590 padding: 12px 9px 7px 24px;
590 padding: 12px 9px 7px 24px;
591 }
591 }
592
592
593 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
593 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
594 {
594 {
595 background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
595 background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
596 #FFF;
596 #FFF;
597 min-width: 167px;
597 min-width: 167px;
598 margin: 0 0 0 14px;
598 margin: 0 0 0 14px;
599 padding: 12px 9px 7px 24px;
599 padding: 12px 9px 7px 24px;
600 }
600 }
601
601
602 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
602 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
603 {
603 {
604 background: url("../images/icons/database_edit.png") no-repeat scroll
604 background: url("../images/icons/database_edit.png") no-repeat scroll
605 4px 9px #FFF;
605 4px 9px #FFF;
606 width: 167px;
606 width: 167px;
607 margin: 0;
607 margin: 0;
608 padding: 12px 9px 7px 24px;
608 padding: 12px 9px 7px 24px;
609 }
609 }
610
610
611 #header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
611 #header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
612 {
612 {
613 background: url("../images/icons/database_link.png") no-repeat scroll
613 background: url("../images/icons/database_link.png") no-repeat scroll
614 4px 9px #FFF;
614 4px 9px #FFF;
615 width: 167px;
615 width: 167px;
616 margin: 0;
616 margin: 0;
617 padding: 12px 9px 7px 24px;
617 padding: 12px 9px 7px 24px;
618 }
618 }
619
619
620 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
620 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
621 {
621 {
622 background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
622 background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
623 width: 167px;
623 width: 167px;
624 margin: 0;
624 margin: 0;
625 padding: 12px 9px 7px 24px;
625 padding: 12px 9px 7px 24px;
626 }
626 }
627
627
628 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
628 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
629 {
629 {
630 background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
630 background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
631 width: 167px;
631 width: 167px;
632 margin: 0;
632 margin: 0;
633 padding: 12px 9px 7px 24px;
633 padding: 12px 9px 7px 24px;
634 }
634 }
635
635
636 #header #header-inner #quick li ul li a.defaults,#header #header-inner #quick li ul li a.defaults:hover
636 #header #header-inner #quick li ul li a.defaults,#header #header-inner #quick li ul li a.defaults:hover
637 {
637 {
638 background: #FFF url("../images/icons/wrench.png") no-repeat 4px 9px;
638 background: #FFF url("../images/icons/wrench.png") no-repeat 4px 9px;
639 width: 167px;
639 width: 167px;
640 margin: 0;
640 margin: 0;
641 padding: 12px 9px 7px 24px;
641 padding: 12px 9px 7px 24px;
642 }
642 }
643
643
644 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
644 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
645 {
645 {
646 background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
646 background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
647 width: 167px;
647 width: 167px;
648 margin: 0;
648 margin: 0;
649 padding: 12px 9px 7px 24px;
649 padding: 12px 9px 7px 24px;
650 }
650 }
651
651
652 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover
652 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover
653 {
653 {
654 background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
654 background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
655 width: 167px;
655 width: 167px;
656 margin: 0;
656 margin: 0;
657 padding: 12px 9px 7px 24px;
657 padding: 12px 9px 7px 24px;
658 }
658 }
659
659
660 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover
660 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover
661 {
661 {
662 background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
662 background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
663 width: 167px;
663 width: 167px;
664 margin: 0;
664 margin: 0;
665 padding: 12px 9px 7px 24px;
665 padding: 12px 9px 7px 24px;
666 }
666 }
667
667
668 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover
668 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover
669 {
669 {
670 background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
670 background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
671 9px;
671 9px;
672 width: 167px;
672 width: 167px;
673 margin: 0;
673 margin: 0;
674 padding: 12px 9px 7px 24px;
674 padding: 12px 9px 7px 24px;
675 }
675 }
676
676
677 #header #header-inner #quick li ul li a.locking_add,#header #header-inner #quick li ul li a.locking_add:hover
677 #header #header-inner #quick li ul li a.locking_add,#header #header-inner #quick li ul li a.locking_add:hover
678 {
678 {
679 background: #FFF url("../images/icons/lock_add.png") no-repeat 4px
679 background: #FFF url("../images/icons/lock_add.png") no-repeat 4px
680 9px;
680 9px;
681 width: 167px;
681 width: 167px;
682 margin: 0;
682 margin: 0;
683 padding: 12px 9px 7px 24px;
683 padding: 12px 9px 7px 24px;
684 }
684 }
685
685
686 #header #header-inner #quick li ul li a.locking_del,#header #header-inner #quick li ul li a.locking_del:hover
686 #header #header-inner #quick li ul li a.locking_del,#header #header-inner #quick li ul li a.locking_del:hover
687 {
687 {
688 background: #FFF url("../images/icons/lock_delete.png") no-repeat 4px
688 background: #FFF url("../images/icons/lock_delete.png") no-repeat 4px
689 9px;
689 9px;
690 width: 167px;
690 width: 167px;
691 margin: 0;
691 margin: 0;
692 padding: 12px 9px 7px 24px;
692 padding: 12px 9px 7px 24px;
693 }
693 }
694
694
695 #header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
695 #header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
696 {
696 {
697 background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
697 background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
698 9px;
698 9px;
699 width: 167px;
699 width: 167px;
700 margin: 0;
700 margin: 0;
701 padding: 12px 9px 7px 24px;
701 padding: 12px 9px 7px 24px;
702 }
702 }
703
703
704 #header #header-inner #quick li ul li a.compare_request,#header #header-inner #quick li ul li a.compare_request:hover
704 #header #header-inner #quick li ul li a.compare_request,#header #header-inner #quick li ul li a.compare_request:hover
705 {
705 {
706 background: #FFF url("../images/icons/arrow_inout.png") no-repeat 4px
706 background: #FFF url("../images/icons/arrow_inout.png") no-repeat 4px
707 9px;
707 9px;
708 width: 167px;
708 width: 167px;
709 margin: 0;
709 margin: 0;
710 padding: 12px 9px 7px 24px;
710 padding: 12px 9px 7px 24px;
711 }
711 }
712
712
713 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
713 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
714 {
714 {
715 background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
715 background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
716 width: 167px;
716 width: 167px;
717 margin: 0;
717 margin: 0;
718 padding: 12px 9px 7px 24px;
718 padding: 12px 9px 7px 24px;
719 }
719 }
720
720
721 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover
721 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover
722 {
722 {
723 background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
723 background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
724 width: 167px;
724 width: 167px;
725 margin: 0;
725 margin: 0;
726 padding: 12px 9px 7px 24px;
726 padding: 12px 9px 7px 24px;
727 }
727 }
728
728
729 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover
729 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover
730 {
730 {
731 background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
731 background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
732 9px;
732 9px;
733 width: 167px;
733 width: 167px;
734 margin: 0;
734 margin: 0;
735 padding: 12px 9px 7px 24px;
735 padding: 12px 9px 7px 24px;
736 }
736 }
737
737
738 #header #header-inner #quick li ul li a.tags,
738 #header #header-inner #quick li ul li a.tags,
739 #header #header-inner #quick li ul li a.tags:hover{
739 #header #header-inner #quick li ul li a.tags:hover{
740 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
740 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
741 width: 167px;
741 width: 167px;
742 margin: 0;
742 margin: 0;
743 padding: 12px 9px 7px 24px;
743 padding: 12px 9px 7px 24px;
744 }
744 }
745
745
746 #header #header-inner #quick li ul li a.bookmarks,
746 #header #header-inner #quick li ul li a.bookmarks,
747 #header #header-inner #quick li ul li a.bookmarks:hover{
747 #header #header-inner #quick li ul li a.bookmarks:hover{
748 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
748 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
749 width: 167px;
749 width: 167px;
750 margin: 0;
750 margin: 0;
751 padding: 12px 9px 7px 24px;
751 padding: 12px 9px 7px 24px;
752 }
752 }
753
753
754 #header #header-inner #quick li ul li a.admin,
754 #header #header-inner #quick li ul li a.admin,
755 #header #header-inner #quick li ul li a.admin:hover{
755 #header #header-inner #quick li ul li a.admin:hover{
756 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
756 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
757 width: 167px;
757 width: 167px;
758 margin: 0;
758 margin: 0;
759 padding: 12px 9px 7px 24px;
759 padding: 12px 9px 7px 24px;
760 }
760 }
761
761
762 .groups_breadcrumbs a {
762 .groups_breadcrumbs a {
763 color: #fff;
763 color: #fff;
764 }
764 }
765
765
766 .groups_breadcrumbs a:hover {
766 .groups_breadcrumbs a:hover {
767 color: #bfe3ff;
767 color: #bfe3ff;
768 text-decoration: none;
768 text-decoration: none;
769 }
769 }
770
770
771 td.quick_repo_menu {
771 td.quick_repo_menu {
772 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
772 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
773 cursor: pointer;
773 cursor: pointer;
774 width: 8px;
774 width: 8px;
775 border: 1px solid transparent;
775 border: 1px solid transparent;
776 }
776 }
777
777
778 td.quick_repo_menu.active {
778 td.quick_repo_menu.active {
779 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
779 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
780 border: 1px solid #003367;
780 border: 1px solid #003367;
781 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
781 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
782 cursor: pointer;
782 cursor: pointer;
783 }
783 }
784
784
785 td.quick_repo_menu .menu_items {
785 td.quick_repo_menu .menu_items {
786 margin-top: 10px;
786 margin-top: 10px;
787 margin-left:-6px;
787 margin-left:-6px;
788 width: 150px;
788 width: 150px;
789 position: absolute;
789 position: absolute;
790 background-color: #FFF;
790 background-color: #FFF;
791 background: none repeat scroll 0 0 #FFFFFF;
791 background: none repeat scroll 0 0 #FFFFFF;
792 border-color: #003367 #666666 #666666;
792 border-color: #003367 #666666 #666666;
793 border-right: 1px solid #666666;
793 border-right: 1px solid #666666;
794 border-style: solid;
794 border-style: solid;
795 border-width: 1px;
795 border-width: 1px;
796 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
796 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
797 border-top-style: none;
797 border-top-style: none;
798 }
798 }
799
799
800 td.quick_repo_menu .menu_items li {
800 td.quick_repo_menu .menu_items li {
801 padding: 0 !important;
801 padding: 0 !important;
802 }
802 }
803
803
804 td.quick_repo_menu .menu_items a {
804 td.quick_repo_menu .menu_items a {
805 display: block;
805 display: block;
806 padding: 4px 12px 4px 8px;
806 padding: 4px 12px 4px 8px;
807 }
807 }
808
808
809 td.quick_repo_menu .menu_items a:hover {
809 td.quick_repo_menu .menu_items a:hover {
810 background-color: #EEE;
810 background-color: #EEE;
811 text-decoration: none;
811 text-decoration: none;
812 }
812 }
813
813
814 td.quick_repo_menu .menu_items .icon img {
814 td.quick_repo_menu .menu_items .icon img {
815 margin-bottom: -2px;
815 margin-bottom: -2px;
816 }
816 }
817
817
818 td.quick_repo_menu .menu_items.hidden {
818 td.quick_repo_menu .menu_items.hidden {
819 display: none;
819 display: none;
820 }
820 }
821
821
822 .yui-dt-first th {
822 .yui-dt-first th {
823 text-align: left;
823 text-align: left;
824 }
824 }
825
825
826 /*
826 /*
827 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
827 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
828 Code licensed under the BSD License:
828 Code licensed under the BSD License:
829 http://developer.yahoo.com/yui/license.html
829 http://developer.yahoo.com/yui/license.html
830 version: 2.9.0
830 version: 2.9.0
831 */
831 */
832 .yui-skin-sam .yui-dt-mask {
832 .yui-skin-sam .yui-dt-mask {
833 position: absolute;
833 position: absolute;
834 z-index: 9500;
834 z-index: 9500;
835 }
835 }
836 .yui-dt-tmp {
836 .yui-dt-tmp {
837 position: absolute;
837 position: absolute;
838 left: -9000px;
838 left: -9000px;
839 }
839 }
840 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
840 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
841 .yui-dt-scrollable .yui-dt-hd {
841 .yui-dt-scrollable .yui-dt-hd {
842 overflow: hidden;
842 overflow: hidden;
843 position: relative;
843 position: relative;
844 }
844 }
845 .yui-dt-scrollable .yui-dt-bd thead tr,
845 .yui-dt-scrollable .yui-dt-bd thead tr,
846 .yui-dt-scrollable .yui-dt-bd thead th {
846 .yui-dt-scrollable .yui-dt-bd thead th {
847 position: absolute;
847 position: absolute;
848 left: -1500px;
848 left: -1500px;
849 }
849 }
850 .yui-dt-scrollable tbody { -moz-outline: 0 }
850 .yui-dt-scrollable tbody { -moz-outline: 0 }
851 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
851 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
852 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
852 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
853 .yui-dt-coltarget {
853 .yui-dt-coltarget {
854 position: absolute;
854 position: absolute;
855 z-index: 999;
855 z-index: 999;
856 }
856 }
857 .yui-dt-hd { zoom: 1 }
857 .yui-dt-hd { zoom: 1 }
858 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
858 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
859 .yui-dt-resizer {
859 .yui-dt-resizer {
860 position: absolute;
860 position: absolute;
861 right: 0;
861 right: 0;
862 bottom: 0;
862 bottom: 0;
863 height: 100%;
863 height: 100%;
864 cursor: e-resize;
864 cursor: e-resize;
865 cursor: col-resize;
865 cursor: col-resize;
866 background-color: #CCC;
866 background-color: #CCC;
867 opacity: 0;
867 opacity: 0;
868 filter: alpha(opacity=0);
868 filter: alpha(opacity=0);
869 }
869 }
870 .yui-dt-resizerproxy {
870 .yui-dt-resizerproxy {
871 visibility: hidden;
871 visibility: hidden;
872 position: absolute;
872 position: absolute;
873 z-index: 9000;
873 z-index: 9000;
874 background-color: #CCC;
874 background-color: #CCC;
875 opacity: 0;
875 opacity: 0;
876 filter: alpha(opacity=0);
876 filter: alpha(opacity=0);
877 }
877 }
878 th.yui-dt-hidden .yui-dt-liner,
878 th.yui-dt-hidden .yui-dt-liner,
879 td.yui-dt-hidden .yui-dt-liner,
879 td.yui-dt-hidden .yui-dt-liner,
880 th.yui-dt-hidden .yui-dt-resizer { display: none }
880 th.yui-dt-hidden .yui-dt-resizer { display: none }
881 .yui-dt-editor,
881 .yui-dt-editor,
882 .yui-dt-editor-shim {
882 .yui-dt-editor-shim {
883 position: absolute;
883 position: absolute;
884 z-index: 9000;
884 z-index: 9000;
885 }
885 }
886 .yui-skin-sam .yui-dt table {
886 .yui-skin-sam .yui-dt table {
887 margin: 0;
887 margin: 0;
888 padding: 0;
888 padding: 0;
889 font-family: arial;
889 font-family: arial;
890 font-size: inherit;
890 font-size: inherit;
891 border-collapse: separate;
891 border-collapse: separate;
892 *border-collapse: collapse;
892 *border-collapse: collapse;
893 border-spacing: 0;
893 border-spacing: 0;
894 border: 1px solid #7f7f7f;
894 border: 1px solid #7f7f7f;
895 }
895 }
896 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
896 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
897 .yui-skin-sam .yui-dt caption {
897 .yui-skin-sam .yui-dt caption {
898 color: #000;
898 color: #000;
899 font-size: 85%;
899 font-size: 85%;
900 font-weight: normal;
900 font-weight: normal;
901 font-style: italic;
901 font-style: italic;
902 line-height: 1;
902 line-height: 1;
903 padding: 1em 0;
903 padding: 1em 0;
904 text-align: center;
904 text-align: center;
905 }
905 }
906 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
906 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
907 .yui-skin-sam .yui-dt th,
907 .yui-skin-sam .yui-dt th,
908 .yui-skin-sam .yui-dt th a {
908 .yui-skin-sam .yui-dt th a {
909 font-weight: normal;
909 font-weight: normal;
910 text-decoration: none;
910 text-decoration: none;
911 color: #000;
911 color: #000;
912 vertical-align: bottom;
912 vertical-align: bottom;
913 }
913 }
914 .yui-skin-sam .yui-dt th {
914 .yui-skin-sam .yui-dt th {
915 margin: 0;
915 margin: 0;
916 padding: 0;
916 padding: 0;
917 border: 0;
917 border: 0;
918 border-right: 1px solid #cbcbcb;
918 border-right: 1px solid #cbcbcb;
919 }
919 }
920 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
920 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
921 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
921 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
922 .yui-skin-sam .yui-dt-liner {
922 .yui-skin-sam .yui-dt-liner {
923 margin: 0;
923 margin: 0;
924 padding: 0;
924 padding: 0;
925 }
925 }
926 .yui-skin-sam .yui-dt-coltarget {
926 .yui-skin-sam .yui-dt-coltarget {
927 width: 5px;
927 width: 5px;
928 background-color: red;
928 background-color: red;
929 }
929 }
930 .yui-skin-sam .yui-dt td {
930 .yui-skin-sam .yui-dt td {
931 margin: 0;
931 margin: 0;
932 padding: 0;
932 padding: 0;
933 border: 0;
933 border: 0;
934 border-right: 1px solid #cbcbcb;
934 border-right: 1px solid #cbcbcb;
935 text-align: left;
935 text-align: left;
936 }
936 }
937 .yui-skin-sam .yui-dt-list td { border-right: 0 }
937 .yui-skin-sam .yui-dt-list td { border-right: 0 }
938 .yui-skin-sam .yui-dt-resizer { width: 6px }
938 .yui-skin-sam .yui-dt-resizer { width: 6px }
939 .yui-skin-sam .yui-dt-mask {
939 .yui-skin-sam .yui-dt-mask {
940 background-color: #000;
940 background-color: #000;
941 opacity: .25;
941 opacity: .25;
942 filter: alpha(opacity=25);
942 filter: alpha(opacity=25);
943 }
943 }
944 .yui-skin-sam .yui-dt-message { background-color: #FFF }
944 .yui-skin-sam .yui-dt-message { background-color: #FFF }
945 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
945 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
946 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
946 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
947 border-left: 1px solid #7f7f7f;
947 border-left: 1px solid #7f7f7f;
948 border-top: 1px solid #7f7f7f;
948 border-top: 1px solid #7f7f7f;
949 border-right: 1px solid #7f7f7f;
949 border-right: 1px solid #7f7f7f;
950 }
950 }
951 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
951 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
952 border-left: 1px solid #7f7f7f;
952 border-left: 1px solid #7f7f7f;
953 border-bottom: 1px solid #7f7f7f;
953 border-bottom: 1px solid #7f7f7f;
954 border-right: 1px solid #7f7f7f;
954 border-right: 1px solid #7f7f7f;
955 background-color: #FFF;
955 background-color: #FFF;
956 }
956 }
957 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
957 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
958 .yui-skin-sam th.yui-dt-asc,
958 .yui-skin-sam th.yui-dt-asc,
959 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
959 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
960 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
960 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
961 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
961 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
962 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
962 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
963 tbody .yui-dt-editable { cursor: pointer }
963 tbody .yui-dt-editable { cursor: pointer }
964 .yui-dt-editor {
964 .yui-dt-editor {
965 text-align: left;
965 text-align: left;
966 background-color: #f2f2f2;
966 background-color: #f2f2f2;
967 border: 1px solid #808080;
967 border: 1px solid #808080;
968 padding: 6px;
968 padding: 6px;
969 }
969 }
970 .yui-dt-editor label {
970 .yui-dt-editor label {
971 padding-left: 4px;
971 padding-left: 4px;
972 padding-right: 6px;
972 padding-right: 6px;
973 }
973 }
974 .yui-dt-editor .yui-dt-button {
974 .yui-dt-editor .yui-dt-button {
975 padding-top: 6px;
975 padding-top: 6px;
976 text-align: right;
976 text-align: right;
977 }
977 }
978 .yui-dt-editor .yui-dt-button button {
978 .yui-dt-editor .yui-dt-button button {
979 background: url(../images/sprite.png) repeat-x 0 0;
979 background: url(../images/sprite.png) repeat-x 0 0;
980 border: 1px solid #999;
980 border: 1px solid #999;
981 width: 4em;
981 width: 4em;
982 height: 1.8em;
982 height: 1.8em;
983 margin-left: 6px;
983 margin-left: 6px;
984 }
984 }
985 .yui-dt-editor .yui-dt-button button.yui-dt-default {
985 .yui-dt-editor .yui-dt-button button.yui-dt-default {
986 background: url(../images/sprite.png) repeat-x 0 -1400px;
986 background: url(../images/sprite.png) repeat-x 0 -1400px;
987 background-color: #5584e0;
987 background-color: #5584e0;
988 border: 1px solid #304369;
988 border: 1px solid #304369;
989 color: #FFF;
989 color: #FFF;
990 }
990 }
991 .yui-dt-editor .yui-dt-button button:hover {
991 .yui-dt-editor .yui-dt-button button:hover {
992 background: url(../images/sprite.png) repeat-x 0 -1300px;
992 background: url(../images/sprite.png) repeat-x 0 -1300px;
993 color: #000;
993 color: #000;
994 }
994 }
995 .yui-dt-editor .yui-dt-button button:active {
995 .yui-dt-editor .yui-dt-button button:active {
996 background: url(../images/sprite.png) repeat-x 0 -1700px;
996 background: url(../images/sprite.png) repeat-x 0 -1700px;
997 color: #000;
997 color: #000;
998 }
998 }
999 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
999 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
1000 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
1000 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
1001 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
1001 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
1002 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1002 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1003 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
1003 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
1004 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
1004 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
1005 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
1005 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
1006 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
1006 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
1007 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
1007 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
1008 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1008 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1009 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
1009 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
1010 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
1010 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
1011 .yui-skin-sam th.yui-dt-highlighted,
1011 .yui-skin-sam th.yui-dt-highlighted,
1012 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
1012 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
1013 .yui-skin-sam tr.yui-dt-highlighted,
1013 .yui-skin-sam tr.yui-dt-highlighted,
1014 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
1014 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
1015 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
1015 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
1016 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
1016 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
1017 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
1017 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
1018 cursor: pointer;
1018 cursor: pointer;
1019 background-color: #b2d2ff;
1019 background-color: #b2d2ff;
1020 }
1020 }
1021 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
1021 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
1022 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
1022 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
1023 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
1023 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
1024 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
1024 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
1025 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
1025 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
1026 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
1026 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
1027 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
1027 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
1028 cursor: pointer;
1028 cursor: pointer;
1029 background-color: #b2d2ff;
1029 background-color: #b2d2ff;
1030 }
1030 }
1031 .yui-skin-sam th.yui-dt-selected,
1031 .yui-skin-sam th.yui-dt-selected,
1032 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
1032 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
1033 .yui-skin-sam tr.yui-dt-selected td,
1033 .yui-skin-sam tr.yui-dt-selected td,
1034 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
1034 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
1035 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
1035 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
1036 background-color: #426fd9;
1036 background-color: #426fd9;
1037 color: #FFF;
1037 color: #FFF;
1038 }
1038 }
1039 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
1039 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
1040 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
1040 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
1041 background-color: #446cd7;
1041 background-color: #446cd7;
1042 color: #FFF;
1042 color: #FFF;
1043 }
1043 }
1044 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
1044 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
1045 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
1045 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
1046 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
1046 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
1047 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
1047 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
1048 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
1048 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
1049 background-color: #426fd9;
1049 background-color: #426fd9;
1050 color: #FFF;
1050 color: #FFF;
1051 }
1051 }
1052 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
1052 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
1053 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
1053 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
1054 background-color: #446cd7;
1054 background-color: #446cd7;
1055 color: #FFF;
1055 color: #FFF;
1056 }
1056 }
1057 .yui-skin-sam .yui-dt-paginator {
1057 .yui-skin-sam .yui-dt-paginator {
1058 display: block;
1058 display: block;
1059 margin: 6px 0;
1059 margin: 6px 0;
1060 white-space: nowrap;
1060 white-space: nowrap;
1061 }
1061 }
1062 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
1062 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
1063 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
1063 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
1064 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
1064 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
1065 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
1065 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
1066 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
1066 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
1067 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
1067 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
1068 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
1068 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
1069 .yui-skin-sam a.yui-dt-page {
1069 .yui-skin-sam a.yui-dt-page {
1070 border: 1px solid #cbcbcb;
1070 border: 1px solid #cbcbcb;
1071 padding: 2px 6px;
1071 padding: 2px 6px;
1072 text-decoration: none;
1072 text-decoration: none;
1073 background-color: #fff;
1073 background-color: #fff;
1074 }
1074 }
1075 .yui-skin-sam .yui-dt-selected {
1075 .yui-skin-sam .yui-dt-selected {
1076 border: 1px solid #fff;
1076 border: 1px solid #fff;
1077 background-color: #fff;
1077 background-color: #fff;
1078 }
1078 }
1079
1079
1080 #content #left {
1080 #content #left {
1081 left: 0;
1081 left: 0;
1082 width: 280px;
1082 width: 280px;
1083 position: absolute;
1083 position: absolute;
1084 }
1084 }
1085
1085
1086 #content #right {
1086 #content #right {
1087 margin: 0 60px 10px 290px;
1087 margin: 0 60px 10px 290px;
1088 }
1088 }
1089
1089
1090 #content div.box {
1090 #content div.box {
1091 clear: both;
1091 clear: both;
1092 overflow: hidden;
1092 overflow: hidden;
1093 background: #fff;
1093 background: #fff;
1094 margin: 0 0 10px;
1094 margin: 0 0 10px;
1095 padding: 0 0 10px;
1095 padding: 0 0 10px;
1096 -webkit-border-radius: 4px 4px 4px 4px;
1096 -webkit-border-radius: 4px 4px 4px 4px;
1097 -khtml-border-radius: 4px 4px 4px 4px;
1097 -khtml-border-radius: 4px 4px 4px 4px;
1098 -moz-border-radius: 4px 4px 4px 4px;
1098 -moz-border-radius: 4px 4px 4px 4px;
1099 border-radius: 4px 4px 4px 4px;
1099 border-radius: 4px 4px 4px 4px;
1100 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1100 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1101 }
1101 }
1102
1102
1103 #content div.box-left {
1103 #content div.box-left {
1104 width: 49%;
1104 width: 49%;
1105 clear: none;
1105 clear: none;
1106 float: left;
1106 float: left;
1107 margin: 0 0 10px;
1107 margin: 0 0 10px;
1108 }
1108 }
1109
1109
1110 #content div.box-right {
1110 #content div.box-right {
1111 width: 49%;
1111 width: 49%;
1112 clear: none;
1112 clear: none;
1113 float: right;
1113 float: right;
1114 margin: 0 0 10px;
1114 margin: 0 0 10px;
1115 }
1115 }
1116
1116
1117 #content div.box div.title {
1117 #content div.box div.title {
1118 clear: both;
1118 clear: both;
1119 overflow: hidden;
1119 overflow: hidden;
1120 background-color: #003B76;
1120 background-color: #003B76;
1121 background-repeat: repeat-x;
1121 background-repeat: repeat-x;
1122 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1122 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1123 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1123 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1124 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1124 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1125 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1125 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1126 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1126 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1127 background-image: -o-linear-gradient(top, #003b76, #00376e);
1127 background-image: -o-linear-gradient(top, #003b76, #00376e);
1128 background-image: linear-gradient(top, #003b76, #00376e);
1128 background-image: linear-gradient(top, #003b76, #00376e);
1129 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1129 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1130 margin: 0 0 20px;
1130 margin: 0 0 20px;
1131 padding: 0;
1131 padding: 0;
1132 }
1132 }
1133
1133
1134 #content div.box div.title h5 {
1134 #content div.box div.title h5 {
1135 float: left;
1135 float: left;
1136 border: none;
1136 border: none;
1137 color: #fff;
1137 color: #fff;
1138 text-transform: uppercase;
1138 text-transform: uppercase;
1139 margin: 0;
1139 margin: 0;
1140 padding: 11px 0 11px 10px;
1140 padding: 11px 0 11px 10px;
1141 }
1141 }
1142
1142
1143 #content div.box div.title .link-white{
1143 #content div.box div.title .link-white{
1144 color: #FFFFFF;
1144 color: #FFFFFF;
1145 }
1145 }
1146
1146
1147 #content div.box div.title .link-white.current{
1147 #content div.box div.title .link-white.current{
1148 color: #BFE3FF;
1148 color: #BFE3FF;
1149 }
1149 }
1150
1150
1151 #content div.box div.title ul.links li {
1151 #content div.box div.title ul.links li {
1152 list-style: none;
1152 list-style: none;
1153 float: left;
1153 float: left;
1154 margin: 0;
1154 margin: 0;
1155 padding: 0;
1155 padding: 0;
1156 }
1156 }
1157
1157
1158 #content div.box div.title ul.links li a {
1158 #content div.box div.title ul.links li a {
1159 border-left: 1px solid #316293;
1159 border-left: 1px solid #316293;
1160 color: #FFFFFF;
1160 color: #FFFFFF;
1161 display: block;
1161 display: block;
1162 float: left;
1162 float: left;
1163 font-size: 13px;
1163 font-size: 13px;
1164 font-weight: 700;
1164 font-weight: 700;
1165 height: 1%;
1165 height: 1%;
1166 margin: 0;
1166 margin: 0;
1167 padding: 11px 22px 12px;
1167 padding: 11px 22px 12px;
1168 text-decoration: none;
1168 text-decoration: none;
1169 }
1169 }
1170
1170
1171 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6,
1171 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6,
1172 #content div.box div.h1,#content div.box div.h2,#content div.box div.h3,#content div.box div.h4,#content div.box div.h5,#content div.box div.h6
1172 #content div.box div.h1,#content div.box div.h2,#content div.box div.h3,#content div.box div.h4,#content div.box div.h5,#content div.box div.h6
1173
1173
1174 {
1174 {
1175 clear: both;
1175 clear: both;
1176 overflow: hidden;
1176 overflow: hidden;
1177 border-bottom: 1px solid #DDD;
1177 border-bottom: 1px solid #DDD;
1178 margin: 10px 20px;
1178 margin: 10px 20px;
1179 padding: 0 0 15px;
1179 padding: 0 0 15px;
1180 }
1180 }
1181
1181
1182 #content div.box p {
1182 #content div.box p {
1183 color: #5f5f5f;
1183 color: #5f5f5f;
1184 font-size: 12px;
1184 font-size: 12px;
1185 line-height: 150%;
1185 line-height: 150%;
1186 margin: 0 24px 10px;
1186 margin: 0 24px 10px;
1187 padding: 0;
1187 padding: 0;
1188 }
1188 }
1189
1189
1190 #content div.box blockquote {
1190 #content div.box blockquote {
1191 border-left: 4px solid #DDD;
1191 border-left: 4px solid #DDD;
1192 color: #5f5f5f;
1192 color: #5f5f5f;
1193 font-size: 11px;
1193 font-size: 11px;
1194 line-height: 150%;
1194 line-height: 150%;
1195 margin: 0 34px;
1195 margin: 0 34px;
1196 padding: 0 0 0 14px;
1196 padding: 0 0 0 14px;
1197 }
1197 }
1198
1198
1199 #content div.box blockquote p {
1199 #content div.box blockquote p {
1200 margin: 10px 0;
1200 margin: 10px 0;
1201 padding: 0;
1201 padding: 0;
1202 }
1202 }
1203
1203
1204 #content div.box dl {
1204 #content div.box dl {
1205 margin: 10px 0px;
1205 margin: 10px 0px;
1206 }
1206 }
1207
1207
1208 #content div.box dt {
1208 #content div.box dt {
1209 font-size: 12px;
1209 font-size: 12px;
1210 margin: 0;
1210 margin: 0;
1211 }
1211 }
1212
1212
1213 #content div.box dd {
1213 #content div.box dd {
1214 font-size: 12px;
1214 font-size: 12px;
1215 margin: 0;
1215 margin: 0;
1216 padding: 8px 0 8px 15px;
1216 padding: 8px 0 8px 15px;
1217 }
1217 }
1218
1218
1219 #content div.box li {
1219 #content div.box li {
1220 font-size: 12px;
1220 font-size: 12px;
1221 padding: 4px 0;
1221 padding: 4px 0;
1222 }
1222 }
1223
1223
1224 #content div.box ul.disc,#content div.box ul.circle {
1224 #content div.box ul.disc,#content div.box ul.circle {
1225 margin: 10px 24px 10px 38px;
1225 margin: 10px 24px 10px 38px;
1226 }
1226 }
1227
1227
1228 #content div.box ul.square {
1228 #content div.box ul.square {
1229 margin: 10px 24px 10px 40px;
1229 margin: 10px 24px 10px 40px;
1230 }
1230 }
1231
1231
1232 #content div.box img.left {
1232 #content div.box img.left {
1233 border: none;
1233 border: none;
1234 float: left;
1234 float: left;
1235 margin: 10px 10px 10px 0;
1235 margin: 10px 10px 10px 0;
1236 }
1236 }
1237
1237
1238 #content div.box img.right {
1238 #content div.box img.right {
1239 border: none;
1239 border: none;
1240 float: right;
1240 float: right;
1241 margin: 10px 0 10px 10px;
1241 margin: 10px 0 10px 10px;
1242 }
1242 }
1243
1243
1244 #content div.box div.messages {
1244 #content div.box div.messages {
1245 clear: both;
1245 clear: both;
1246 overflow: hidden;
1246 overflow: hidden;
1247 margin: 0 20px;
1247 margin: 0 20px;
1248 padding: 0;
1248 padding: 0;
1249 }
1249 }
1250
1250
1251 #content div.box div.message {
1251 #content div.box div.message {
1252 clear: both;
1252 clear: both;
1253 overflow: hidden;
1253 overflow: hidden;
1254 margin: 0;
1254 margin: 0;
1255 padding: 5px 0;
1255 padding: 5px 0;
1256 white-space: pre-wrap;
1256 white-space: pre-wrap;
1257 }
1257 }
1258 #content div.box div.expand {
1258 #content div.box div.expand {
1259 width: 110%;
1259 width: 110%;
1260 height:14px;
1260 height:14px;
1261 font-size:10px;
1261 font-size:10px;
1262 text-align:center;
1262 text-align:center;
1263 cursor: pointer;
1263 cursor: pointer;
1264 color:#666;
1264 color:#666;
1265
1265
1266 background:-webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1266 background:-webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1267 background:-webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1267 background:-webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1268 background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1268 background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1269 background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1269 background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1270 background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1270 background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1271 background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1271 background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1272
1272
1273 display: none;
1273 display: none;
1274 }
1274 }
1275 #content div.box div.expand .expandtext {
1275 #content div.box div.expand .expandtext {
1276 background-color: #ffffff;
1276 background-color: #ffffff;
1277 padding: 2px;
1277 padding: 2px;
1278 border-radius: 2px;
1278 border-radius: 2px;
1279 }
1279 }
1280
1280
1281 #content div.box div.message a {
1281 #content div.box div.message a {
1282 font-weight: 400 !important;
1282 font-weight: 400 !important;
1283 }
1283 }
1284
1284
1285 #content div.box div.message div.image {
1285 #content div.box div.message div.image {
1286 float: left;
1286 float: left;
1287 margin: 9px 0 0 5px;
1287 margin: 9px 0 0 5px;
1288 padding: 6px;
1288 padding: 6px;
1289 }
1289 }
1290
1290
1291 #content div.box div.message div.image img {
1291 #content div.box div.message div.image img {
1292 vertical-align: middle;
1292 vertical-align: middle;
1293 margin: 0;
1293 margin: 0;
1294 }
1294 }
1295
1295
1296 #content div.box div.message div.text {
1296 #content div.box div.message div.text {
1297 float: left;
1297 float: left;
1298 margin: 0;
1298 margin: 0;
1299 padding: 9px 6px;
1299 padding: 9px 6px;
1300 }
1300 }
1301
1301
1302 #content div.box div.message div.dismiss a {
1302 #content div.box div.message div.dismiss a {
1303 height: 16px;
1303 height: 16px;
1304 width: 16px;
1304 width: 16px;
1305 display: block;
1305 display: block;
1306 background: url("../images/icons/cross.png") no-repeat;
1306 background: url("../images/icons/cross.png") no-repeat;
1307 margin: 15px 14px 0 0;
1307 margin: 15px 14px 0 0;
1308 padding: 0;
1308 padding: 0;
1309 }
1309 }
1310
1310
1311 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6
1311 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6
1312 {
1312 {
1313 border: none;
1313 border: none;
1314 margin: 0;
1314 margin: 0;
1315 padding: 0;
1315 padding: 0;
1316 }
1316 }
1317
1317
1318 #content div.box div.message div.text span {
1318 #content div.box div.message div.text span {
1319 height: 1%;
1319 height: 1%;
1320 display: block;
1320 display: block;
1321 margin: 0;
1321 margin: 0;
1322 padding: 5px 0 0;
1322 padding: 5px 0 0;
1323 }
1323 }
1324
1324
1325 #content div.box div.message-error {
1325 #content div.box div.message-error {
1326 height: 1%;
1326 height: 1%;
1327 clear: both;
1327 clear: both;
1328 overflow: hidden;
1328 overflow: hidden;
1329 background: #FBE3E4;
1329 background: #FBE3E4;
1330 border: 1px solid #FBC2C4;
1330 border: 1px solid #FBC2C4;
1331 color: #860006;
1331 color: #860006;
1332 }
1332 }
1333
1333
1334 #content div.box div.message-error h6 {
1334 #content div.box div.message-error h6 {
1335 color: #860006;
1335 color: #860006;
1336 }
1336 }
1337
1337
1338 #content div.box div.message-warning {
1338 #content div.box div.message-warning {
1339 height: 1%;
1339 height: 1%;
1340 clear: both;
1340 clear: both;
1341 overflow: hidden;
1341 overflow: hidden;
1342 background: #FFF6BF;
1342 background: #FFF6BF;
1343 border: 1px solid #FFD324;
1343 border: 1px solid #FFD324;
1344 color: #5f5200;
1344 color: #5f5200;
1345 }
1345 }
1346
1346
1347 #content div.box div.message-warning h6 {
1347 #content div.box div.message-warning h6 {
1348 color: #5f5200;
1348 color: #5f5200;
1349 }
1349 }
1350
1350
1351 #content div.box div.message-notice {
1351 #content div.box div.message-notice {
1352 height: 1%;
1352 height: 1%;
1353 clear: both;
1353 clear: both;
1354 overflow: hidden;
1354 overflow: hidden;
1355 background: #8FBDE0;
1355 background: #8FBDE0;
1356 border: 1px solid #6BACDE;
1356 border: 1px solid #6BACDE;
1357 color: #003863;
1357 color: #003863;
1358 }
1358 }
1359
1359
1360 #content div.box div.message-notice h6 {
1360 #content div.box div.message-notice h6 {
1361 color: #003863;
1361 color: #003863;
1362 }
1362 }
1363
1363
1364 #content div.box div.message-success {
1364 #content div.box div.message-success {
1365 height: 1%;
1365 height: 1%;
1366 clear: both;
1366 clear: both;
1367 overflow: hidden;
1367 overflow: hidden;
1368 background: #E6EFC2;
1368 background: #E6EFC2;
1369 border: 1px solid #C6D880;
1369 border: 1px solid #C6D880;
1370 color: #4e6100;
1370 color: #4e6100;
1371 }
1371 }
1372
1372
1373 #content div.box div.message-success h6 {
1373 #content div.box div.message-success h6 {
1374 color: #4e6100;
1374 color: #4e6100;
1375 }
1375 }
1376
1376
1377 #content div.box div.form div.fields div.field {
1377 #content div.box div.form div.fields div.field {
1378 height: 1%;
1378 height: 1%;
1379 border-bottom: 1px solid #DDD;
1379 border-bottom: 1px solid #DDD;
1380 clear: both;
1380 clear: both;
1381 margin: 0;
1381 margin: 0;
1382 padding: 10px 0;
1382 padding: 10px 0;
1383 }
1383 }
1384
1384
1385 #content div.box div.form div.fields div.field-first {
1385 #content div.box div.form div.fields div.field-first {
1386 padding: 0 0 10px;
1386 padding: 0 0 10px;
1387 }
1387 }
1388
1388
1389 #content div.box div.form div.fields div.field-noborder {
1389 #content div.box div.form div.fields div.field-noborder {
1390 border-bottom: 0 !important;
1390 border-bottom: 0 !important;
1391 }
1391 }
1392
1392
1393 #content div.box div.form div.fields div.field span.error-message {
1393 #content div.box div.form div.fields div.field span.error-message {
1394 height: 1%;
1394 height: 1%;
1395 display: inline-block;
1395 display: inline-block;
1396 color: red;
1396 color: red;
1397 margin: 8px 0 0 4px;
1397 margin: 8px 0 0 4px;
1398 padding: 0;
1398 padding: 0;
1399 }
1399 }
1400
1400
1401 #content div.box div.form div.fields div.field span.success {
1401 #content div.box div.form div.fields div.field span.success {
1402 height: 1%;
1402 height: 1%;
1403 display: block;
1403 display: block;
1404 color: #316309;
1404 color: #316309;
1405 margin: 8px 0 0;
1405 margin: 8px 0 0;
1406 padding: 0;
1406 padding: 0;
1407 }
1407 }
1408
1408
1409 #content div.box div.form div.fields div.field div.label {
1409 #content div.box div.form div.fields div.field div.label {
1410 left: 70px;
1410 left: 70px;
1411 width: 155px;
1411 width: 155px;
1412 position: absolute;
1412 position: absolute;
1413 margin: 0;
1413 margin: 0;
1414 padding: 5px 0 0 0px;
1414 padding: 5px 0 0 0px;
1415 }
1415 }
1416
1416
1417 #content div.box div.form div.fields div.field div.label-summary {
1417 #content div.box div.form div.fields div.field div.label-summary {
1418 left: 30px;
1418 left: 30px;
1419 width: 155px;
1419 width: 155px;
1420 position: absolute;
1420 position: absolute;
1421 margin: 0;
1421 margin: 0;
1422 padding: 0px 0 0 0px;
1422 padding: 0px 0 0 0px;
1423 }
1423 }
1424
1424
1425 #content div.box-left div.form div.fields div.field div.label,
1425 #content div.box-left div.form div.fields div.field div.label,
1426 #content div.box-right div.form div.fields div.field div.label,
1426 #content div.box-right div.form div.fields div.field div.label,
1427 #content div.box-left div.form div.fields div.field div.label,
1427 #content div.box-left div.form div.fields div.field div.label,
1428 #content div.box-left div.form div.fields div.field div.label-summary,
1428 #content div.box-left div.form div.fields div.field div.label-summary,
1429 #content div.box-right div.form div.fields div.field div.label-summary,
1429 #content div.box-right div.form div.fields div.field div.label-summary,
1430 #content div.box-left div.form div.fields div.field div.label-summary
1430 #content div.box-left div.form div.fields div.field div.label-summary
1431 {
1431 {
1432 clear: both;
1432 clear: both;
1433 overflow: hidden;
1433 overflow: hidden;
1434 left: 0;
1434 left: 0;
1435 width: auto;
1435 width: auto;
1436 position: relative;
1436 position: relative;
1437 margin: 0;
1437 margin: 0;
1438 padding: 0 0 8px;
1438 padding: 0 0 8px;
1439 }
1439 }
1440
1440
1441 #content div.box div.form div.fields div.field div.label-select {
1441 #content div.box div.form div.fields div.field div.label-select {
1442 padding: 5px 0 0 5px;
1442 padding: 5px 0 0 5px;
1443 }
1443 }
1444
1444
1445 #content div.box-left div.form div.fields div.field div.label-select,
1445 #content div.box-left div.form div.fields div.field div.label-select,
1446 #content div.box-right div.form div.fields div.field div.label-select
1446 #content div.box-right div.form div.fields div.field div.label-select
1447 {
1447 {
1448 padding: 0 0 8px;
1448 padding: 0 0 8px;
1449 }
1449 }
1450
1450
1451 #content div.box-left div.form div.fields div.field div.label-textarea,
1451 #content div.box-left div.form div.fields div.field div.label-textarea,
1452 #content div.box-right div.form div.fields div.field div.label-textarea
1452 #content div.box-right div.form div.fields div.field div.label-textarea
1453 {
1453 {
1454 padding: 0 0 8px !important;
1454 padding: 0 0 8px !important;
1455 }
1455 }
1456
1456
1457 #content div.box div.form div.fields div.field div.label label,div.label label
1457 #content div.box div.form div.fields div.field div.label label,div.label label
1458 {
1458 {
1459 color: #393939;
1459 color: #393939;
1460 font-weight: 700;
1460 font-weight: 700;
1461 }
1461 }
1462 #content div.box div.form div.fields div.field div.label label,div.label-summary label
1462 #content div.box div.form div.fields div.field div.label label,div.label-summary label
1463 {
1463 {
1464 color: #393939;
1464 color: #393939;
1465 font-weight: 700;
1465 font-weight: 700;
1466 }
1466 }
1467 #content div.box div.form div.fields div.field div.input {
1467 #content div.box div.form div.fields div.field div.input {
1468 margin: 0 0 0 200px;
1468 margin: 0 0 0 200px;
1469 }
1469 }
1470
1470
1471 #content div.box div.form div.fields div.field div.input.summary {
1471 #content div.box div.form div.fields div.field div.input.summary {
1472 margin: 0 0 0 110px;
1472 margin: 0 0 0 110px;
1473 }
1473 }
1474 #content div.box div.form div.fields div.field div.input.summary-short {
1474 #content div.box div.form div.fields div.field div.input.summary-short {
1475 margin: 0 0 0 110px;
1475 margin: 0 0 0 110px;
1476 }
1476 }
1477 #content div.box div.form div.fields div.field div.file {
1477 #content div.box div.form div.fields div.field div.file {
1478 margin: 0 0 0 200px;
1478 margin: 0 0 0 200px;
1479 }
1479 }
1480
1480
1481 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input
1481 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input
1482 {
1482 {
1483 margin: 0 0 0 0px;
1483 margin: 0 0 0 0px;
1484 }
1484 }
1485
1485
1486 #content div.box div.form div.fields div.field div.input input,
1486 #content div.box div.form div.fields div.field div.input input,
1487 .reviewer_ac input {
1487 .reviewer_ac input {
1488 background: #FFF;
1488 background: #FFF;
1489 border-top: 1px solid #b3b3b3;
1489 border-top: 1px solid #b3b3b3;
1490 border-left: 1px solid #b3b3b3;
1490 border-left: 1px solid #b3b3b3;
1491 border-right: 1px solid #eaeaea;
1491 border-right: 1px solid #eaeaea;
1492 border-bottom: 1px solid #eaeaea;
1492 border-bottom: 1px solid #eaeaea;
1493 color: #000;
1493 color: #000;
1494 font-size: 11px;
1494 font-size: 11px;
1495 margin: 0;
1495 margin: 0;
1496 padding: 7px 7px 6px;
1496 padding: 7px 7px 6px;
1497 }
1497 }
1498
1498
1499 #content div.box div.form div.fields div.field div.input input#clone_url,
1499 #content div.box div.form div.fields div.field div.input input#clone_url,
1500 #content div.box div.form div.fields div.field div.input input#clone_url_id
1500 #content div.box div.form div.fields div.field div.input input#clone_url_id
1501 {
1501 {
1502 font-size: 16px;
1502 font-size: 16px;
1503 padding: 2px;
1503 padding: 2px;
1504 }
1504 }
1505
1505
1506 #content div.box div.form div.fields div.field div.file input {
1506 #content div.box div.form div.fields div.field div.file input {
1507 background: none repeat scroll 0 0 #FFFFFF;
1507 background: none repeat scroll 0 0 #FFFFFF;
1508 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1508 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1509 border-style: solid;
1509 border-style: solid;
1510 border-width: 1px;
1510 border-width: 1px;
1511 color: #000000;
1511 color: #000000;
1512 font-size: 11px;
1512 font-size: 11px;
1513 margin: 0;
1513 margin: 0;
1514 padding: 7px 7px 6px;
1514 padding: 7px 7px 6px;
1515 }
1515 }
1516
1516
1517 input.disabled {
1517 input.disabled {
1518 background-color: #F5F5F5 !important;
1518 background-color: #F5F5F5 !important;
1519 }
1519 }
1520 #content div.box div.form div.fields div.field div.input input.small {
1520 #content div.box div.form div.fields div.field div.input input.small {
1521 width: 30%;
1521 width: 30%;
1522 }
1522 }
1523
1523
1524 #content div.box div.form div.fields div.field div.input input.medium {
1524 #content div.box div.form div.fields div.field div.input input.medium {
1525 width: 55%;
1525 width: 55%;
1526 }
1526 }
1527
1527
1528 #content div.box div.form div.fields div.field div.input input.large {
1528 #content div.box div.form div.fields div.field div.input input.large {
1529 width: 85%;
1529 width: 85%;
1530 }
1530 }
1531
1531
1532 #content div.box div.form div.fields div.field div.input input.date {
1532 #content div.box div.form div.fields div.field div.input input.date {
1533 width: 177px;
1533 width: 177px;
1534 }
1534 }
1535
1535
1536 #content div.box div.form div.fields div.field div.input input.button {
1536 #content div.box div.form div.fields div.field div.input input.button {
1537 background: #D4D0C8;
1537 background: #D4D0C8;
1538 border-top: 1px solid #FFF;
1538 border-top: 1px solid #FFF;
1539 border-left: 1px solid #FFF;
1539 border-left: 1px solid #FFF;
1540 border-right: 1px solid #404040;
1540 border-right: 1px solid #404040;
1541 border-bottom: 1px solid #404040;
1541 border-bottom: 1px solid #404040;
1542 color: #000;
1542 color: #000;
1543 margin: 0;
1543 margin: 0;
1544 padding: 4px 8px;
1544 padding: 4px 8px;
1545 }
1545 }
1546
1546
1547 #content div.box div.form div.fields div.field div.textarea {
1547 #content div.box div.form div.fields div.field div.textarea {
1548 border-top: 1px solid #b3b3b3;
1548 border-top: 1px solid #b3b3b3;
1549 border-left: 1px solid #b3b3b3;
1549 border-left: 1px solid #b3b3b3;
1550 border-right: 1px solid #eaeaea;
1550 border-right: 1px solid #eaeaea;
1551 border-bottom: 1px solid #eaeaea;
1551 border-bottom: 1px solid #eaeaea;
1552 margin: 0 0 0 200px;
1552 margin: 0 0 0 200px;
1553 padding: 10px;
1553 padding: 10px;
1554 }
1554 }
1555
1555
1556 #content div.box div.form div.fields div.field div.textarea-editor {
1556 #content div.box div.form div.fields div.field div.textarea-editor {
1557 border: 1px solid #ddd;
1557 border: 1px solid #ddd;
1558 padding: 0;
1558 padding: 0;
1559 }
1559 }
1560
1560
1561 #content div.box div.form div.fields div.field div.textarea textarea {
1561 #content div.box div.form div.fields div.field div.textarea textarea {
1562 width: 100%;
1562 width: 100%;
1563 height: 220px;
1563 height: 220px;
1564 overflow: hidden;
1564 overflow: hidden;
1565 background: #FFF;
1565 background: #FFF;
1566 color: #000;
1566 color: #000;
1567 font-size: 11px;
1567 font-size: 11px;
1568 outline: none;
1568 outline: none;
1569 border-width: 0;
1569 border-width: 0;
1570 margin: 0;
1570 margin: 0;
1571 padding: 0;
1571 padding: 0;
1572 }
1572 }
1573
1573
1574 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea
1574 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea
1575 {
1575 {
1576 width: 100%;
1576 width: 100%;
1577 height: 100px;
1577 height: 100px;
1578 }
1578 }
1579
1579
1580 #content div.box div.form div.fields div.field div.textarea table {
1580 #content div.box div.form div.fields div.field div.textarea table {
1581 width: 100%;
1581 width: 100%;
1582 border: none;
1582 border: none;
1583 margin: 0;
1583 margin: 0;
1584 padding: 0;
1584 padding: 0;
1585 }
1585 }
1586
1586
1587 #content div.box div.form div.fields div.field div.textarea table td {
1587 #content div.box div.form div.fields div.field div.textarea table td {
1588 background: #DDD;
1588 background: #DDD;
1589 border: none;
1589 border: none;
1590 padding: 0;
1590 padding: 0;
1591 }
1591 }
1592
1592
1593 #content div.box div.form div.fields div.field div.textarea table td table
1593 #content div.box div.form div.fields div.field div.textarea table td table
1594 {
1594 {
1595 width: auto;
1595 width: auto;
1596 border: none;
1596 border: none;
1597 margin: 0;
1597 margin: 0;
1598 padding: 0;
1598 padding: 0;
1599 }
1599 }
1600
1600
1601 #content div.box div.form div.fields div.field div.textarea table td table td
1601 #content div.box div.form div.fields div.field div.textarea table td table td
1602 {
1602 {
1603 font-size: 11px;
1603 font-size: 11px;
1604 padding: 5px 5px 5px 0;
1604 padding: 5px 5px 5px 0;
1605 }
1605 }
1606
1606
1607 #content div.box div.form div.fields div.field input[type=text]:focus,
1607 #content div.box div.form div.fields div.field input[type=text]:focus,
1608 #content div.box div.form div.fields div.field input[type=password]:focus,
1608 #content div.box div.form div.fields div.field input[type=password]:focus,
1609 #content div.box div.form div.fields div.field input[type=file]:focus,
1609 #content div.box div.form div.fields div.field input[type=file]:focus,
1610 #content div.box div.form div.fields div.field textarea:focus,
1610 #content div.box div.form div.fields div.field textarea:focus,
1611 #content div.box div.form div.fields div.field select:focus,
1611 #content div.box div.form div.fields div.field select:focus,
1612 .reviewer_ac input:focus
1612 .reviewer_ac input:focus
1613 {
1613 {
1614 background: #f6f6f6;
1614 background: #f6f6f6;
1615 border-color: #666;
1615 border-color: #666;
1616 }
1616 }
1617
1617
1618 .reviewer_ac {
1618 .reviewer_ac {
1619 padding:10px
1619 padding:10px
1620 }
1620 }
1621
1621
1622 div.form div.fields div.field div.button {
1622 div.form div.fields div.field div.button {
1623 margin: 0;
1623 margin: 0;
1624 padding: 0 0 0 8px;
1624 padding: 0 0 0 8px;
1625 }
1625 }
1626 #content div.box table.noborder {
1626 #content div.box table.noborder {
1627 border: 1px solid transparent;
1627 border: 1px solid transparent;
1628 }
1628 }
1629
1629
1630 #content div.box table {
1630 #content div.box table {
1631 width: 100%;
1631 width: 100%;
1632 border-collapse: separate;
1632 border-collapse: separate;
1633 margin: 0;
1633 margin: 0;
1634 padding: 0;
1634 padding: 0;
1635 border: 1px solid #eee;
1635 border: 1px solid #eee;
1636 -webkit-border-radius: 4px;
1636 -webkit-border-radius: 4px;
1637 -moz-border-radius: 4px;
1637 -moz-border-radius: 4px;
1638 border-radius: 4px;
1638 border-radius: 4px;
1639 }
1639 }
1640
1640
1641 #content div.box table th {
1641 #content div.box table th {
1642 background: #eee;
1642 background: #eee;
1643 border-bottom: 1px solid #ddd;
1643 border-bottom: 1px solid #ddd;
1644 padding: 5px 0px 5px 5px;
1644 padding: 5px 0px 5px 5px;
1645 text-align: left;
1645 text-align: left;
1646 }
1646 }
1647
1647
1648 #content div.box table th.left {
1648 #content div.box table th.left {
1649 text-align: left;
1649 text-align: left;
1650 }
1650 }
1651
1651
1652 #content div.box table th.right {
1652 #content div.box table th.right {
1653 text-align: right;
1653 text-align: right;
1654 }
1654 }
1655
1655
1656 #content div.box table th.center {
1656 #content div.box table th.center {
1657 text-align: center;
1657 text-align: center;
1658 }
1658 }
1659
1659
1660 #content div.box table th.selected {
1660 #content div.box table th.selected {
1661 vertical-align: middle;
1661 vertical-align: middle;
1662 padding: 0;
1662 padding: 0;
1663 }
1663 }
1664
1664
1665 #content div.box table td {
1665 #content div.box table td {
1666 background: #fff;
1666 background: #fff;
1667 border-bottom: 1px solid #cdcdcd;
1667 border-bottom: 1px solid #cdcdcd;
1668 vertical-align: middle;
1668 vertical-align: middle;
1669 padding: 5px;
1669 padding: 5px;
1670 }
1670 }
1671
1671
1672 #content div.box table tr.selected td {
1672 #content div.box table tr.selected td {
1673 background: #FFC;
1673 background: #FFC;
1674 }
1674 }
1675
1675
1676 #content div.box table td.selected {
1676 #content div.box table td.selected {
1677 width: 3%;
1677 width: 3%;
1678 text-align: center;
1678 text-align: center;
1679 vertical-align: middle;
1679 vertical-align: middle;
1680 padding: 0;
1680 padding: 0;
1681 }
1681 }
1682
1682
1683 #content div.box table td.action {
1683 #content div.box table td.action {
1684 width: 45%;
1684 width: 45%;
1685 text-align: left;
1685 text-align: left;
1686 }
1686 }
1687
1687
1688 #content div.box table td.date {
1688 #content div.box table td.date {
1689 width: 33%;
1689 width: 33%;
1690 text-align: center;
1690 text-align: center;
1691 }
1691 }
1692
1692
1693 #content div.box div.action {
1693 #content div.box div.action {
1694 float: right;
1694 float: right;
1695 background: #FFF;
1695 background: #FFF;
1696 text-align: right;
1696 text-align: right;
1697 margin: 10px 0 0;
1697 margin: 10px 0 0;
1698 padding: 0;
1698 padding: 0;
1699 }
1699 }
1700
1700
1701 #content div.box div.action select {
1701 #content div.box div.action select {
1702 font-size: 11px;
1702 font-size: 11px;
1703 margin: 0;
1703 margin: 0;
1704 }
1704 }
1705
1705
1706 #content div.box div.action .ui-selectmenu {
1706 #content div.box div.action .ui-selectmenu {
1707 margin: 0;
1707 margin: 0;
1708 padding: 0;
1708 padding: 0;
1709 }
1709 }
1710
1710
1711 #content div.box div.pagination {
1711 #content div.box div.pagination {
1712 height: 1%;
1712 height: 1%;
1713 clear: both;
1713 clear: both;
1714 overflow: hidden;
1714 overflow: hidden;
1715 margin: 10px 0 0;
1715 margin: 10px 0 0;
1716 padding: 0;
1716 padding: 0;
1717 }
1717 }
1718
1718
1719 #content div.box div.pagination ul.pager {
1719 #content div.box div.pagination ul.pager {
1720 float: right;
1720 float: right;
1721 text-align: right;
1721 text-align: right;
1722 margin: 0;
1722 margin: 0;
1723 padding: 0;
1723 padding: 0;
1724 }
1724 }
1725
1725
1726 #content div.box div.pagination ul.pager li {
1726 #content div.box div.pagination ul.pager li {
1727 height: 1%;
1727 height: 1%;
1728 float: left;
1728 float: left;
1729 list-style: none;
1729 list-style: none;
1730 background: #ebebeb url("../images/pager.png") repeat-x;
1730 background: #ebebeb url("../images/pager.png") repeat-x;
1731 border-top: 1px solid #dedede;
1731 border-top: 1px solid #dedede;
1732 border-left: 1px solid #cfcfcf;
1732 border-left: 1px solid #cfcfcf;
1733 border-right: 1px solid #c4c4c4;
1733 border-right: 1px solid #c4c4c4;
1734 border-bottom: 1px solid #c4c4c4;
1734 border-bottom: 1px solid #c4c4c4;
1735 color: #4A4A4A;
1735 color: #4A4A4A;
1736 font-weight: 700;
1736 font-weight: 700;
1737 margin: 0 0 0 4px;
1737 margin: 0 0 0 4px;
1738 padding: 0;
1738 padding: 0;
1739 }
1739 }
1740
1740
1741 #content div.box div.pagination ul.pager li.separator {
1741 #content div.box div.pagination ul.pager li.separator {
1742 padding: 6px;
1742 padding: 6px;
1743 }
1743 }
1744
1744
1745 #content div.box div.pagination ul.pager li.current {
1745 #content div.box div.pagination ul.pager li.current {
1746 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1746 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1747 border-top: 1px solid #ccc;
1747 border-top: 1px solid #ccc;
1748 border-left: 1px solid #bebebe;
1748 border-left: 1px solid #bebebe;
1749 border-right: 1px solid #b1b1b1;
1749 border-right: 1px solid #b1b1b1;
1750 border-bottom: 1px solid #afafaf;
1750 border-bottom: 1px solid #afafaf;
1751 color: #515151;
1751 color: #515151;
1752 padding: 6px;
1752 padding: 6px;
1753 }
1753 }
1754
1754
1755 #content div.box div.pagination ul.pager li a {
1755 #content div.box div.pagination ul.pager li a {
1756 height: 1%;
1756 height: 1%;
1757 display: block;
1757 display: block;
1758 float: left;
1758 float: left;
1759 color: #515151;
1759 color: #515151;
1760 text-decoration: none;
1760 text-decoration: none;
1761 margin: 0;
1761 margin: 0;
1762 padding: 6px;
1762 padding: 6px;
1763 }
1763 }
1764
1764
1765 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active
1765 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active
1766 {
1766 {
1767 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1767 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1768 border-top: 1px solid #ccc;
1768 border-top: 1px solid #ccc;
1769 border-left: 1px solid #bebebe;
1769 border-left: 1px solid #bebebe;
1770 border-right: 1px solid #b1b1b1;
1770 border-right: 1px solid #b1b1b1;
1771 border-bottom: 1px solid #afafaf;
1771 border-bottom: 1px solid #afafaf;
1772 margin: -1px;
1772 margin: -1px;
1773 }
1773 }
1774
1774
1775 #content div.box div.pagination-wh {
1775 #content div.box div.pagination-wh {
1776 height: 1%;
1776 height: 1%;
1777 clear: both;
1777 clear: both;
1778 overflow: hidden;
1778 overflow: hidden;
1779 text-align: right;
1779 text-align: right;
1780 margin: 10px 0 0;
1780 margin: 10px 0 0;
1781 padding: 0;
1781 padding: 0;
1782 }
1782 }
1783
1783
1784 #content div.box div.pagination-right {
1784 #content div.box div.pagination-right {
1785 float: right;
1785 float: right;
1786 }
1786 }
1787
1787
1788 #content div.box div.pagination-wh a,
1788 #content div.box div.pagination-wh a,
1789 #content div.box div.pagination-wh span.pager_dotdot,
1789 #content div.box div.pagination-wh span.pager_dotdot,
1790 #content div.box div.pagination-wh span.yui-pg-previous,
1790 #content div.box div.pagination-wh span.yui-pg-previous,
1791 #content div.box div.pagination-wh span.yui-pg-last,
1791 #content div.box div.pagination-wh span.yui-pg-last,
1792 #content div.box div.pagination-wh span.yui-pg-next,
1792 #content div.box div.pagination-wh span.yui-pg-next,
1793 #content div.box div.pagination-wh span.yui-pg-first
1793 #content div.box div.pagination-wh span.yui-pg-first
1794 {
1794 {
1795 height: 1%;
1795 height: 1%;
1796 float: left;
1796 float: left;
1797 background: #ebebeb url("../images/pager.png") repeat-x;
1797 background: #ebebeb url("../images/pager.png") repeat-x;
1798 border-top: 1px solid #dedede;
1798 border-top: 1px solid #dedede;
1799 border-left: 1px solid #cfcfcf;
1799 border-left: 1px solid #cfcfcf;
1800 border-right: 1px solid #c4c4c4;
1800 border-right: 1px solid #c4c4c4;
1801 border-bottom: 1px solid #c4c4c4;
1801 border-bottom: 1px solid #c4c4c4;
1802 color: #4A4A4A;
1802 color: #4A4A4A;
1803 font-weight: 700;
1803 font-weight: 700;
1804 margin: 0 0 0 4px;
1804 margin: 0 0 0 4px;
1805 padding: 6px;
1805 padding: 6px;
1806 }
1806 }
1807
1807
1808 #content div.box div.pagination-wh span.pager_curpage {
1808 #content div.box div.pagination-wh span.pager_curpage {
1809 height: 1%;
1809 height: 1%;
1810 float: left;
1810 float: left;
1811 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1811 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1812 border-top: 1px solid #ccc;
1812 border-top: 1px solid #ccc;
1813 border-left: 1px solid #bebebe;
1813 border-left: 1px solid #bebebe;
1814 border-right: 1px solid #b1b1b1;
1814 border-right: 1px solid #b1b1b1;
1815 border-bottom: 1px solid #afafaf;
1815 border-bottom: 1px solid #afafaf;
1816 color: #515151;
1816 color: #515151;
1817 font-weight: 700;
1817 font-weight: 700;
1818 margin: 0 0 0 4px;
1818 margin: 0 0 0 4px;
1819 padding: 6px;
1819 padding: 6px;
1820 }
1820 }
1821
1821
1822 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active
1822 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active
1823 {
1823 {
1824 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1824 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1825 border-top: 1px solid #ccc;
1825 border-top: 1px solid #ccc;
1826 border-left: 1px solid #bebebe;
1826 border-left: 1px solid #bebebe;
1827 border-right: 1px solid #b1b1b1;
1827 border-right: 1px solid #b1b1b1;
1828 border-bottom: 1px solid #afafaf;
1828 border-bottom: 1px solid #afafaf;
1829 text-decoration: none;
1829 text-decoration: none;
1830 }
1830 }
1831
1831
1832 #content div.box div.traffic div.legend {
1832 #content div.box div.traffic div.legend {
1833 clear: both;
1833 clear: both;
1834 overflow: hidden;
1834 overflow: hidden;
1835 border-bottom: 1px solid #ddd;
1835 border-bottom: 1px solid #ddd;
1836 margin: 0 0 10px;
1836 margin: 0 0 10px;
1837 padding: 0 0 10px;
1837 padding: 0 0 10px;
1838 }
1838 }
1839
1839
1840 #content div.box div.traffic div.legend h6 {
1840 #content div.box div.traffic div.legend h6 {
1841 float: left;
1841 float: left;
1842 border: none;
1842 border: none;
1843 margin: 0;
1843 margin: 0;
1844 padding: 0;
1844 padding: 0;
1845 }
1845 }
1846
1846
1847 #content div.box div.traffic div.legend li {
1847 #content div.box div.traffic div.legend li {
1848 list-style: none;
1848 list-style: none;
1849 float: left;
1849 float: left;
1850 font-size: 11px;
1850 font-size: 11px;
1851 margin: 0;
1851 margin: 0;
1852 padding: 0 8px 0 4px;
1852 padding: 0 8px 0 4px;
1853 }
1853 }
1854
1854
1855 #content div.box div.traffic div.legend li.visits {
1855 #content div.box div.traffic div.legend li.visits {
1856 border-left: 12px solid #edc240;
1856 border-left: 12px solid #edc240;
1857 }
1857 }
1858
1858
1859 #content div.box div.traffic div.legend li.pageviews {
1859 #content div.box div.traffic div.legend li.pageviews {
1860 border-left: 12px solid #afd8f8;
1860 border-left: 12px solid #afd8f8;
1861 }
1861 }
1862
1862
1863 #content div.box div.traffic table {
1863 #content div.box div.traffic table {
1864 width: auto;
1864 width: auto;
1865 }
1865 }
1866
1866
1867 #content div.box div.traffic table td {
1867 #content div.box div.traffic table td {
1868 background: transparent;
1868 background: transparent;
1869 border: none;
1869 border: none;
1870 padding: 2px 3px 3px;
1870 padding: 2px 3px 3px;
1871 }
1871 }
1872
1872
1873 #content div.box div.traffic table td.legendLabel {
1873 #content div.box div.traffic table td.legendLabel {
1874 padding: 0 3px 2px;
1874 padding: 0 3px 2px;
1875 }
1875 }
1876
1876
1877 #summary {
1877 #summary {
1878
1879 }
1878 }
1880
1879
1881 #summary .metatag {
1880 #summary .metatag {
1882 display: inline-block;
1881 display: inline-block;
1883 padding: 3px 5px;
1882 padding: 3px 5px;
1884 margin-bottom: 3px;
1883 margin-bottom: 3px;
1885 margin-right: 1px;
1884 margin-right: 1px;
1886 border-radius: 5px;
1885 border-radius: 5px;
1887 }
1886 }
1888
1887
1889 #content div.box #summary p {
1888 #content div.box #summary p {
1890 margin-bottom: -5px;
1889 margin-bottom: -5px;
1891 width: 600px;
1890 width: 600px;
1892 white-space: pre-wrap;
1891 white-space: pre-wrap;
1893 }
1892 }
1894
1893
1895 #content div.box #summary p:last-child {
1894 #content div.box #summary p:last-child {
1896 margin-bottom: 9px;
1895 margin-bottom: 9px;
1897 }
1896 }
1898
1897
1899 #content div.box #summary p:first-of-type {
1898 #content div.box #summary p:first-of-type {
1900 margin-top: 9px;
1899 margin-top: 9px;
1901 }
1900 }
1902
1901
1903 .metatag {
1902 .metatag {
1904 display: inline-block;
1903 display: inline-block;
1905 margin-right: 1px;
1904 margin-right: 1px;
1906 -webkit-border-radius: 4px 4px 4px 4px;
1905 -webkit-border-radius: 4px 4px 4px 4px;
1907 -khtml-border-radius: 4px 4px 4px 4px;
1906 -khtml-border-radius: 4px 4px 4px 4px;
1908 -moz-border-radius: 4px 4px 4px 4px;
1907 -moz-border-radius: 4px 4px 4px 4px;
1909 border-radius: 4px 4px 4px 4px;
1908 border-radius: 4px 4px 4px 4px;
1910
1909
1911 border: solid 1px #9CF;
1910 border: solid 1px #9CF;
1912 padding: 2px 3px 2px 3px !important;
1911 padding: 2px 3px 2px 3px !important;
1913 background-color: #DEF;
1912 background-color: #DEF;
1914 }
1913 }
1915
1914
1916 .metatag[tag="dead"] {
1915 .metatag[tag="dead"] {
1917 background-color: #E44;
1916 background-color: #E44;
1918 }
1917 }
1919
1918
1920 .metatag[tag="stale"] {
1919 .metatag[tag="stale"] {
1921 background-color: #EA4;
1920 background-color: #EA4;
1922 }
1921 }
1923
1922
1924 .metatag[tag="featured"] {
1923 .metatag[tag="featured"] {
1925 background-color: #AEA;
1924 background-color: #AEA;
1926 }
1925 }
1927
1926
1928 .metatag[tag="requires"] {
1927 .metatag[tag="requires"] {
1929 background-color: #9CF;
1928 background-color: #9CF;
1930 }
1929 }
1931
1930
1932 .metatag[tag="recommends"] {
1931 .metatag[tag="recommends"] {
1933 background-color: #BDF;
1932 background-color: #BDF;
1934 }
1933 }
1935
1934
1936 .metatag[tag="lang"] {
1935 .metatag[tag="lang"] {
1937 background-color: #FAF474;
1936 background-color: #FAF474;
1938 }
1937 }
1939
1938
1940 .metatag[tag="license"] {
1939 .metatag[tag="license"] {
1941 border: solid 1px #9CF;
1940 border: solid 1px #9CF;
1942 background-color: #DEF;
1941 background-color: #DEF;
1943 target-new: tab !important;
1942 target-new: tab !important;
1944 }
1943 }
1945 .metatag[tag="see"] {
1944 .metatag[tag="see"] {
1946 border: solid 1px #CBD;
1945 border: solid 1px #CBD;
1947 background-color: #EDF;
1946 background-color: #EDF;
1948 }
1947 }
1949
1948
1950 a.metatag[tag="license"]:hover {
1949 a.metatag[tag="license"]:hover {
1951 background-color: #003367;
1950 background-color: #003367;
1952 color: #FFF;
1951 color: #FFF;
1953 text-decoration: none;
1952 text-decoration: none;
1954 }
1953 }
1955
1954
1956 #summary .desc {
1955 #summary .desc {
1957 white-space: pre;
1956 white-space: pre;
1958 width: 100%;
1957 width: 100%;
1959 }
1958 }
1960
1959
1961 #summary .repo_name {
1960 #summary .repo_name {
1962 font-size: 1.6em;
1961 font-size: 1.6em;
1963 font-weight: bold;
1962 font-weight: bold;
1964 vertical-align: baseline;
1963 vertical-align: baseline;
1965 clear: right
1964 clear: right
1966 }
1965 }
1967
1966
1968 #footer {
1967 #footer {
1969 clear: both;
1968 clear: both;
1970 overflow: hidden;
1969 overflow: hidden;
1971 text-align: right;
1970 text-align: right;
1972 margin: 0;
1971 margin: 0;
1973 padding: 0 10px 4px;
1972 padding: 0 10px 4px;
1974 margin: -10px 0 0;
1973 margin: -10px 0 0;
1975 }
1974 }
1976
1975
1977 #footer div#footer-inner {
1976 #footer div#footer-inner {
1978 background-color: #003B76;
1977 background-color: #003B76;
1979 background-repeat : repeat-x;
1978 background-repeat : repeat-x;
1980 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1979 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1981 background-image : -moz-linear-gradient(top, #003b76, #00376e);
1980 background-image : -moz-linear-gradient(top, #003b76, #00376e);
1982 background-image : -ms-linear-gradient( top, #003b76, #00376e);
1981 background-image : -ms-linear-gradient( top, #003b76, #00376e);
1983 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1982 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1984 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
1983 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
1985 background-image : -o-linear-gradient( top, #003b76, #00376e));
1984 background-image : -o-linear-gradient( top, #003b76, #00376e));
1986 background-image : linear-gradient( top, #003b76, #00376e);
1985 background-image : linear-gradient( top, #003b76, #00376e);
1987 filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1986 filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1988 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1987 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1989 -webkit-border-radius: 4px 4px 4px 4px;
1988 -webkit-border-radius: 4px 4px 4px 4px;
1990 -khtml-border-radius: 4px 4px 4px 4px;
1989 -khtml-border-radius: 4px 4px 4px 4px;
1991 -moz-border-radius: 4px 4px 4px 4px;
1990 -moz-border-radius: 4px 4px 4px 4px;
1992 border-radius: 4px 4px 4px 4px;
1991 border-radius: 4px 4px 4px 4px;
1993 }
1992 }
1994
1993
1995 #footer div#footer-inner p {
1994 #footer div#footer-inner p {
1996 padding: 15px 25px 15px 0;
1995 padding: 15px 25px 15px 0;
1997 color: #FFF;
1996 color: #FFF;
1998 font-weight: 700;
1997 font-weight: 700;
1999 }
1998 }
2000
1999
2001 #footer div#footer-inner .footer-link {
2000 #footer div#footer-inner .footer-link {
2002 float: left;
2001 float: left;
2003 padding-left: 10px;
2002 padding-left: 10px;
2004 }
2003 }
2005
2004
2006 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a
2005 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a
2007 {
2006 {
2008 color: #FFF;
2007 color: #FFF;
2009 }
2008 }
2010
2009
2011 #login div.title {
2010 #login div.title {
2012 clear: both;
2011 clear: both;
2013 overflow: hidden;
2012 overflow: hidden;
2014 position: relative;
2013 position: relative;
2015 background-color: #003B76;
2014 background-color: #003B76;
2016 background-repeat : repeat-x;
2015 background-repeat : repeat-x;
2017 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
2016 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
2018 background-image : -moz-linear-gradient( top, #003b76, #00376e);
2017 background-image : -moz-linear-gradient( top, #003b76, #00376e);
2019 background-image : -ms-linear-gradient( top, #003b76, #00376e);
2018 background-image : -ms-linear-gradient( top, #003b76, #00376e);
2020 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
2019 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
2021 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
2020 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
2022 background-image : -o-linear-gradient( top, #003b76, #00376e));
2021 background-image : -o-linear-gradient( top, #003b76, #00376e));
2023 background-image : linear-gradient( top, #003b76, #00376e);
2022 background-image : linear-gradient( top, #003b76, #00376e);
2024 filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
2023 filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
2025 margin: 0 auto;
2024 margin: 0 auto;
2026 padding: 0;
2025 padding: 0;
2027 }
2026 }
2028
2027
2029 #login div.inner {
2028 #login div.inner {
2030 background: #FFF url("../images/login.png") no-repeat top left;
2029 background: #FFF url("../images/login.png") no-repeat top left;
2031 border-top: none;
2030 border-top: none;
2032 border-bottom: none;
2031 border-bottom: none;
2033 margin: 0 auto;
2032 margin: 0 auto;
2034 padding: 20px;
2033 padding: 20px;
2035 }
2034 }
2036
2035
2037 #login div.form div.fields div.field div.label {
2036 #login div.form div.fields div.field div.label {
2038 width: 173px;
2037 width: 173px;
2039 float: left;
2038 float: left;
2040 text-align: right;
2039 text-align: right;
2041 margin: 2px 10px 0 0;
2040 margin: 2px 10px 0 0;
2042 padding: 5px 0 0 5px;
2041 padding: 5px 0 0 5px;
2043 }
2042 }
2044
2043
2045 #login div.form div.fields div.field div.input input {
2044 #login div.form div.fields div.field div.input input {
2046 background: #FFF;
2045 background: #FFF;
2047 border-top: 1px solid #b3b3b3;
2046 border-top: 1px solid #b3b3b3;
2048 border-left: 1px solid #b3b3b3;
2047 border-left: 1px solid #b3b3b3;
2049 border-right: 1px solid #eaeaea;
2048 border-right: 1px solid #eaeaea;
2050 border-bottom: 1px solid #eaeaea;
2049 border-bottom: 1px solid #eaeaea;
2051 color: #000;
2050 color: #000;
2052 font-size: 11px;
2051 font-size: 11px;
2053 margin: 0;
2052 margin: 0;
2054 padding: 7px 7px 6px;
2053 padding: 7px 7px 6px;
2055 }
2054 }
2056
2055
2057 #login div.form div.fields div.buttons {
2056 #login div.form div.fields div.buttons {
2058 clear: both;
2057 clear: both;
2059 overflow: hidden;
2058 overflow: hidden;
2060 border-top: 1px solid #DDD;
2059 border-top: 1px solid #DDD;
2061 text-align: right;
2060 text-align: right;
2062 margin: 0;
2061 margin: 0;
2063 padding: 10px 0 0;
2062 padding: 10px 0 0;
2064 }
2063 }
2065
2064
2066 #login div.form div.links {
2065 #login div.form div.links {
2067 clear: both;
2066 clear: both;
2068 overflow: hidden;
2067 overflow: hidden;
2069 margin: 10px 0 0;
2068 margin: 10px 0 0;
2070 padding: 0 0 2px;
2069 padding: 0 0 2px;
2071 }
2070 }
2072
2071
2073 .user-menu{
2072 .user-menu{
2074 margin: 0px !important;
2073 margin: 0px !important;
2075 float: left;
2074 float: left;
2076 }
2075 }
2077
2076
2078 .user-menu .container{
2077 .user-menu .container{
2079 padding:0px 4px 0px 4px;
2078 padding:0px 4px 0px 4px;
2080 margin: 0px 0px 0px 0px;
2079 margin: 0px 0px 0px 0px;
2081 }
2080 }
2082
2081
2083 .user-menu .gravatar{
2082 .user-menu .gravatar{
2084 margin: 0px 0px 0px 0px;
2083 margin: 0px 0px 0px 0px;
2085 cursor: pointer;
2084 cursor: pointer;
2086 }
2085 }
2087 .user-menu .gravatar.enabled{
2086 .user-menu .gravatar.enabled{
2088 background-color: #FDF784 !important;
2087 background-color: #FDF784 !important;
2089 }
2088 }
2090 .user-menu .gravatar:hover{
2089 .user-menu .gravatar:hover{
2091 background-color: #FDF784 !important;
2090 background-color: #FDF784 !important;
2092 }
2091 }
2093 #quick_login{
2092 #quick_login{
2094 min-height: 80px;
2093 min-height: 80px;
2095 padding: 4px;
2094 padding: 4px;
2096 position: absolute;
2095 position: absolute;
2097 right: 0;
2096 right: 0;
2098 width: 278px;
2097 width: 278px;
2099 background-color: #003B76;
2098 background-color: #003B76;
2100 background-repeat: repeat-x;
2099 background-repeat: repeat-x;
2101 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2100 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2102 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2101 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2103 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2102 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2104 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2103 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2105 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2104 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2106 background-image: -o-linear-gradient(top, #003b76, #00376e);
2105 background-image: -o-linear-gradient(top, #003b76, #00376e);
2107 background-image: linear-gradient(top, #003b76, #00376e);
2106 background-image: linear-gradient(top, #003b76, #00376e);
2108 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
2107 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
2109
2108
2110 z-index: 999;
2109 z-index: 999;
2111 -webkit-border-radius: 0px 0px 4px 4px;
2110 -webkit-border-radius: 0px 0px 4px 4px;
2112 -khtml-border-radius: 0px 0px 4px 4px;
2111 -khtml-border-radius: 0px 0px 4px 4px;
2113 -moz-border-radius: 0px 0px 4px 4px;
2112 -moz-border-radius: 0px 0px 4px 4px;
2114 border-radius: 0px 0px 4px 4px;
2113 border-radius: 0px 0px 4px 4px;
2115 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2114 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2116 }
2115 }
2117 #quick_login h4{
2116 #quick_login h4{
2118 color: #fff;
2117 color: #fff;
2119 padding: 5px 0px 5px 14px;
2118 padding: 5px 0px 5px 14px;
2120 }
2119 }
2121
2120
2122 #quick_login .password_forgoten {
2121 #quick_login .password_forgoten {
2123 padding-right: 10px;
2122 padding-right: 10px;
2124 padding-top: 0px;
2123 padding-top: 0px;
2125 text-align: left;
2124 text-align: left;
2126 }
2125 }
2127
2126
2128 #quick_login .password_forgoten a {
2127 #quick_login .password_forgoten a {
2129 font-size: 10px;
2128 font-size: 10px;
2130 color: #fff;
2129 color: #fff;
2131 }
2130 }
2132
2131
2133 #quick_login .register {
2132 #quick_login .register {
2134 padding-right: 10px;
2133 padding-right: 10px;
2135 padding-top: 5px;
2134 padding-top: 5px;
2136 text-align: left;
2135 text-align: left;
2137 }
2136 }
2138
2137
2139 #quick_login .register a {
2138 #quick_login .register a {
2140 font-size: 10px;
2139 font-size: 10px;
2141 color: #fff;
2140 color: #fff;
2142 }
2141 }
2143
2142
2144 #quick_login .submit {
2143 #quick_login .submit {
2145 margin: -20px 0 0 0px;
2144 margin: -20px 0 0 0px;
2146 position: absolute;
2145 position: absolute;
2147 right: 15px;
2146 right: 15px;
2148 }
2147 }
2149
2148
2150 #quick_login .links_left{
2149 #quick_login .links_left{
2151 float: left;
2150 float: left;
2152 }
2151 }
2153 #quick_login .links_right{
2152 #quick_login .links_right{
2154 float: right;
2153 float: right;
2155 }
2154 }
2156 #quick_login .full_name{
2155 #quick_login .full_name{
2157 color: #FFFFFF;
2156 color: #FFFFFF;
2158 font-weight: bold;
2157 font-weight: bold;
2159 padding: 3px;
2158 padding: 3px;
2160 }
2159 }
2161 #quick_login .big_gravatar{
2160 #quick_login .big_gravatar{
2162 padding:4px 0px 0px 6px;
2161 padding:4px 0px 0px 6px;
2163 }
2162 }
2164 #quick_login .inbox{
2163 #quick_login .inbox{
2165 padding:4px 0px 0px 6px;
2164 padding:4px 0px 0px 6px;
2166 color: #FFFFFF;
2165 color: #FFFFFF;
2167 font-weight: bold;
2166 font-weight: bold;
2168 }
2167 }
2169 #quick_login .inbox a{
2168 #quick_login .inbox a{
2170 color: #FFFFFF;
2169 color: #FFFFFF;
2171 }
2170 }
2172 #quick_login .email,#quick_login .email a{
2171 #quick_login .email,#quick_login .email a{
2173 color: #FFFFFF;
2172 color: #FFFFFF;
2174 padding: 3px;
2173 padding: 3px;
2175
2174
2176 }
2175 }
2177 #quick_login .links .logout{
2176 #quick_login .links .logout{
2178
2177
2179 }
2178 }
2180
2179
2181 #quick_login div.form div.fields {
2180 #quick_login div.form div.fields {
2182 padding-top: 2px;
2181 padding-top: 2px;
2183 padding-left: 10px;
2182 padding-left: 10px;
2184 }
2183 }
2185
2184
2186 #quick_login div.form div.fields div.field {
2185 #quick_login div.form div.fields div.field {
2187 padding: 5px;
2186 padding: 5px;
2188 }
2187 }
2189
2188
2190 #quick_login div.form div.fields div.field div.label label {
2189 #quick_login div.form div.fields div.field div.label label {
2191 color: #fff;
2190 color: #fff;
2192 padding-bottom: 3px;
2191 padding-bottom: 3px;
2193 }
2192 }
2194
2193
2195 #quick_login div.form div.fields div.field div.input input {
2194 #quick_login div.form div.fields div.field div.input input {
2196 width: 236px;
2195 width: 236px;
2197 background: #FFF;
2196 background: #FFF;
2198 border-top: 1px solid #b3b3b3;
2197 border-top: 1px solid #b3b3b3;
2199 border-left: 1px solid #b3b3b3;
2198 border-left: 1px solid #b3b3b3;
2200 border-right: 1px solid #eaeaea;
2199 border-right: 1px solid #eaeaea;
2201 border-bottom: 1px solid #eaeaea;
2200 border-bottom: 1px solid #eaeaea;
2202 color: #000;
2201 color: #000;
2203 font-size: 11px;
2202 font-size: 11px;
2204 margin: 0;
2203 margin: 0;
2205 padding: 5px 7px 4px;
2204 padding: 5px 7px 4px;
2206 }
2205 }
2207
2206
2208 #quick_login div.form div.fields div.buttons {
2207 #quick_login div.form div.fields div.buttons {
2209 clear: both;
2208 clear: both;
2210 overflow: hidden;
2209 overflow: hidden;
2211 text-align: right;
2210 text-align: right;
2212 margin: 0;
2211 margin: 0;
2213 padding: 5px 14px 0px 5px;
2212 padding: 5px 14px 0px 5px;
2214 }
2213 }
2215
2214
2216 #quick_login div.form div.links {
2215 #quick_login div.form div.links {
2217 clear: both;
2216 clear: both;
2218 overflow: hidden;
2217 overflow: hidden;
2219 margin: 10px 0 0;
2218 margin: 10px 0 0;
2220 padding: 0 0 2px;
2219 padding: 0 0 2px;
2221 }
2220 }
2222
2221
2223 #quick_login ol.links{
2222 #quick_login ol.links{
2224 display: block;
2223 display: block;
2225 font-weight: bold;
2224 font-weight: bold;
2226 list-style: none outside none;
2225 list-style: none outside none;
2227 text-align: right;
2226 text-align: right;
2228 }
2227 }
2229 #quick_login ol.links li{
2228 #quick_login ol.links li{
2230 line-height: 27px;
2229 line-height: 27px;
2231 margin: 0;
2230 margin: 0;
2232 padding: 0;
2231 padding: 0;
2233 color: #fff;
2232 color: #fff;
2234 display: block;
2233 display: block;
2235 float:none !important;
2234 float:none !important;
2236 }
2235 }
2237
2236
2238 #quick_login ol.links li a{
2237 #quick_login ol.links li a{
2239 color: #fff;
2238 color: #fff;
2240 display: block;
2239 display: block;
2241 padding: 2px;
2240 padding: 2px;
2242 }
2241 }
2243 #quick_login ol.links li a:HOVER{
2242 #quick_login ol.links li a:HOVER{
2244 background-color: inherit !important;
2243 background-color: inherit !important;
2245 }
2244 }
2246
2245
2247 #register div.title {
2246 #register div.title {
2248 clear: both;
2247 clear: both;
2249 overflow: hidden;
2248 overflow: hidden;
2250 position: relative;
2249 position: relative;
2251 background-color: #003B76;
2250 background-color: #003B76;
2252 background-repeat: repeat-x;
2251 background-repeat: repeat-x;
2253 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2252 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2254 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2253 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2255 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2254 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2256 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2255 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2257 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2256 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2258 background-image: -o-linear-gradient(top, #003b76, #00376e);
2257 background-image: -o-linear-gradient(top, #003b76, #00376e);
2259 background-image: linear-gradient(top, #003b76, #00376e);
2258 background-image: linear-gradient(top, #003b76, #00376e);
2260 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2259 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2261 endColorstr='#00376e', GradientType=0 );
2260 endColorstr='#00376e', GradientType=0 );
2262 margin: 0 auto;
2261 margin: 0 auto;
2263 padding: 0;
2262 padding: 0;
2264 }
2263 }
2265
2264
2266 #register div.inner {
2265 #register div.inner {
2267 background: #FFF;
2266 background: #FFF;
2268 border-top: none;
2267 border-top: none;
2269 border-bottom: none;
2268 border-bottom: none;
2270 margin: 0 auto;
2269 margin: 0 auto;
2271 padding: 20px;
2270 padding: 20px;
2272 }
2271 }
2273
2272
2274 #register div.form div.fields div.field div.label {
2273 #register div.form div.fields div.field div.label {
2275 width: 135px;
2274 width: 135px;
2276 float: left;
2275 float: left;
2277 text-align: right;
2276 text-align: right;
2278 margin: 2px 10px 0 0;
2277 margin: 2px 10px 0 0;
2279 padding: 5px 0 0 5px;
2278 padding: 5px 0 0 5px;
2280 }
2279 }
2281
2280
2282 #register div.form div.fields div.field div.input input {
2281 #register div.form div.fields div.field div.input input {
2283 width: 300px;
2282 width: 300px;
2284 background: #FFF;
2283 background: #FFF;
2285 border-top: 1px solid #b3b3b3;
2284 border-top: 1px solid #b3b3b3;
2286 border-left: 1px solid #b3b3b3;
2285 border-left: 1px solid #b3b3b3;
2287 border-right: 1px solid #eaeaea;
2286 border-right: 1px solid #eaeaea;
2288 border-bottom: 1px solid #eaeaea;
2287 border-bottom: 1px solid #eaeaea;
2289 color: #000;
2288 color: #000;
2290 font-size: 11px;
2289 font-size: 11px;
2291 margin: 0;
2290 margin: 0;
2292 padding: 7px 7px 6px;
2291 padding: 7px 7px 6px;
2293 }
2292 }
2294
2293
2295 #register div.form div.fields div.buttons {
2294 #register div.form div.fields div.buttons {
2296 clear: both;
2295 clear: both;
2297 overflow: hidden;
2296 overflow: hidden;
2298 border-top: 1px solid #DDD;
2297 border-top: 1px solid #DDD;
2299 text-align: left;
2298 text-align: left;
2300 margin: 0;
2299 margin: 0;
2301 padding: 10px 0 0 150px;
2300 padding: 10px 0 0 150px;
2302 }
2301 }
2303
2302
2304 #register div.form div.activation_msg {
2303 #register div.form div.activation_msg {
2305 padding-top: 4px;
2304 padding-top: 4px;
2306 padding-bottom: 4px;
2305 padding-bottom: 4px;
2307 }
2306 }
2308
2307
2309 #journal .journal_day {
2308 #journal .journal_day {
2310 font-size: 20px;
2309 font-size: 20px;
2311 padding: 10px 0px;
2310 padding: 10px 0px;
2312 border-bottom: 2px solid #DDD;
2311 border-bottom: 2px solid #DDD;
2313 margin-left: 10px;
2312 margin-left: 10px;
2314 margin-right: 10px;
2313 margin-right: 10px;
2315 }
2314 }
2316
2315
2317 #journal .journal_container {
2316 #journal .journal_container {
2318 padding: 5px;
2317 padding: 5px;
2319 clear: both;
2318 clear: both;
2320 margin: 0px 5px 0px 10px;
2319 margin: 0px 5px 0px 10px;
2321 }
2320 }
2322
2321
2323 #journal .journal_action_container {
2322 #journal .journal_action_container {
2324 padding-left: 38px;
2323 padding-left: 38px;
2325 }
2324 }
2326
2325
2327 #journal .journal_user {
2326 #journal .journal_user {
2328 color: #747474;
2327 color: #747474;
2329 font-size: 14px;
2328 font-size: 14px;
2330 font-weight: bold;
2329 font-weight: bold;
2331 height: 30px;
2330 height: 30px;
2332 }
2331 }
2333
2332
2334 #journal .journal_user.deleted {
2333 #journal .journal_user.deleted {
2335 color: #747474;
2334 color: #747474;
2336 font-size: 14px;
2335 font-size: 14px;
2337 font-weight: normal;
2336 font-weight: normal;
2338 height: 30px;
2337 height: 30px;
2339 font-style: italic;
2338 font-style: italic;
2340 }
2339 }
2341
2340
2342
2341
2343 #journal .journal_icon {
2342 #journal .journal_icon {
2344 clear: both;
2343 clear: both;
2345 float: left;
2344 float: left;
2346 padding-right: 4px;
2345 padding-right: 4px;
2347 padding-top: 3px;
2346 padding-top: 3px;
2348 }
2347 }
2349
2348
2350 #journal .journal_action {
2349 #journal .journal_action {
2351 padding-top: 4px;
2350 padding-top: 4px;
2352 min-height: 2px;
2351 min-height: 2px;
2353 float: left
2352 float: left
2354 }
2353 }
2355
2354
2356 #journal .journal_action_params {
2355 #journal .journal_action_params {
2357 clear: left;
2356 clear: left;
2358 padding-left: 22px;
2357 padding-left: 22px;
2359 }
2358 }
2360
2359
2361 #journal .journal_repo {
2360 #journal .journal_repo {
2362 float: left;
2361 float: left;
2363 margin-left: 6px;
2362 margin-left: 6px;
2364 padding-top: 3px;
2363 padding-top: 3px;
2365 }
2364 }
2366
2365
2367 #journal .date {
2366 #journal .date {
2368 clear: both;
2367 clear: both;
2369 color: #777777;
2368 color: #777777;
2370 font-size: 11px;
2369 font-size: 11px;
2371 padding-left: 22px;
2370 padding-left: 22px;
2372 }
2371 }
2373
2372
2374 #journal .journal_repo .journal_repo_name {
2373 #journal .journal_repo .journal_repo_name {
2375 font-weight: bold;
2374 font-weight: bold;
2376 font-size: 1.1em;
2375 font-size: 1.1em;
2377 }
2376 }
2378
2377
2379 #journal .compare_view {
2378 #journal .compare_view {
2380 padding: 5px 0px 5px 0px;
2379 padding: 5px 0px 5px 0px;
2381 width: 95px;
2380 width: 95px;
2382 }
2381 }
2383
2382
2384 .journal_highlight {
2383 .journal_highlight {
2385 font-weight: bold;
2384 font-weight: bold;
2386 padding: 0 2px;
2385 padding: 0 2px;
2387 vertical-align: bottom;
2386 vertical-align: bottom;
2388 }
2387 }
2389
2388
2390 .trending_language_tbl,.trending_language_tbl td {
2389 .trending_language_tbl,.trending_language_tbl td {
2391 border: 0 !important;
2390 border: 0 !important;
2392 margin: 0 !important;
2391 margin: 0 !important;
2393 padding: 0 !important;
2392 padding: 0 !important;
2394 }
2393 }
2395
2394
2396 .trending_language_tbl,.trending_language_tbl tr {
2395 .trending_language_tbl,.trending_language_tbl tr {
2397 border-spacing: 1px;
2396 border-spacing: 1px;
2398 }
2397 }
2399
2398
2400 .trending_language {
2399 .trending_language {
2401 background-color: #003367;
2400 background-color: #003367;
2402 color: #FFF;
2401 color: #FFF;
2403 display: block;
2402 display: block;
2404 min-width: 20px;
2403 min-width: 20px;
2405 text-decoration: none;
2404 text-decoration: none;
2406 height: 12px;
2405 height: 12px;
2407 margin-bottom: 0px;
2406 margin-bottom: 0px;
2408 margin-left: 5px;
2407 margin-left: 5px;
2409 white-space: pre;
2408 white-space: pre;
2410 padding: 3px;
2409 padding: 3px;
2411 }
2410 }
2412
2411
2413 h3.files_location {
2412 h3.files_location {
2414 font-size: 1.8em;
2413 font-size: 1.8em;
2415 font-weight: 700;
2414 font-weight: 700;
2416 border-bottom: none !important;
2415 border-bottom: none !important;
2417 margin: 10px 0 !important;
2416 margin: 10px 0 !important;
2418 }
2417 }
2419
2418
2420 #files_data dl dt {
2419 #files_data dl dt {
2421 float: left;
2420 float: left;
2422 width: 60px;
2421 width: 60px;
2423 margin: 0 !important;
2422 margin: 0 !important;
2424 padding: 5px;
2423 padding: 5px;
2425 }
2424 }
2426
2425
2427 #files_data dl dd {
2426 #files_data dl dd {
2428 margin: 0 !important;
2427 margin: 0 !important;
2429 padding: 5px !important;
2428 padding: 5px !important;
2430 }
2429 }
2431
2430
2432 .file_history{
2431 .file_history{
2433 padding-top:10px;
2432 padding-top:10px;
2434 font-size:16px;
2433 font-size:16px;
2435 }
2434 }
2436 .file_author{
2435 .file_author{
2437 float: left;
2436 float: left;
2438 }
2437 }
2439
2438
2440 .file_author .item{
2439 .file_author .item{
2441 float:left;
2440 float:left;
2442 padding:5px;
2441 padding:5px;
2443 color: #888;
2442 color: #888;
2444 }
2443 }
2445
2444
2446 .tablerow0 {
2445 .tablerow0 {
2447 background-color: #F8F8F8;
2446 background-color: #F8F8F8;
2448 }
2447 }
2449
2448
2450 .tablerow1 {
2449 .tablerow1 {
2451 background-color: #FFFFFF;
2450 background-color: #FFFFFF;
2452 }
2451 }
2453
2452
2454 .changeset_id {
2453 .changeset_id {
2455 font-family: monospace;
2454 font-family: monospace;
2456 color: #666666;
2455 color: #666666;
2457 }
2456 }
2458
2457
2459 .changeset_hash {
2458 .changeset_hash {
2460 color: #000000;
2459 color: #000000;
2461 }
2460 }
2462
2461
2463 #changeset_content {
2462 #changeset_content {
2464 border-left: 1px solid #CCC;
2463 border-left: 1px solid #CCC;
2465 border-right: 1px solid #CCC;
2464 border-right: 1px solid #CCC;
2466 border-bottom: 1px solid #CCC;
2465 border-bottom: 1px solid #CCC;
2467 padding: 5px;
2466 padding: 5px;
2468 }
2467 }
2469
2468
2470 #changeset_compare_view_content {
2469 #changeset_compare_view_content {
2471 border: 1px solid #CCC;
2470 border: 1px solid #CCC;
2472 padding: 5px;
2471 padding: 5px;
2473 }
2472 }
2474
2473
2475 #changeset_content .container {
2474 #changeset_content .container {
2476 min-height: 100px;
2475 min-height: 100px;
2477 font-size: 1.2em;
2476 font-size: 1.2em;
2478 overflow: hidden;
2477 overflow: hidden;
2479 }
2478 }
2480
2479
2481 #changeset_compare_view_content .compare_view_commits {
2480 #changeset_compare_view_content .compare_view_commits {
2482 width: auto !important;
2481 width: auto !important;
2483 }
2482 }
2484
2483
2485 #changeset_compare_view_content .compare_view_commits td {
2484 #changeset_compare_view_content .compare_view_commits td {
2486 padding: 0px 0px 0px 12px !important;
2485 padding: 0px 0px 0px 12px !important;
2487 }
2486 }
2488
2487
2489 #changeset_content .container .right {
2488 #changeset_content .container .right {
2490 float: right;
2489 float: right;
2491 width: 20%;
2490 width: 20%;
2492 text-align: right;
2491 text-align: right;
2493 }
2492 }
2494
2493
2495 #changeset_content .container .left .message {
2494 #changeset_content .container .left .message {
2496 white-space: pre-wrap;
2495 white-space: pre-wrap;
2497 }
2496 }
2498 #changeset_content .container .left .message a:hover {
2497 #changeset_content .container .left .message a:hover {
2499 text-decoration: none;
2498 text-decoration: none;
2500 }
2499 }
2501 .cs_files .cur_cs {
2500 .cs_files .cur_cs {
2502 margin: 10px 2px;
2501 margin: 10px 2px;
2503 font-weight: bold;
2502 font-weight: bold;
2504 }
2503 }
2505
2504
2506 .cs_files .node {
2505 .cs_files .node {
2507 float: left;
2506 float: left;
2508 }
2507 }
2509
2508
2510 .cs_files .changes {
2509 .cs_files .changes {
2511 float: right;
2510 float: right;
2512 color:#003367;
2511 color:#003367;
2513
2514 }
2512 }
2515
2513
2516 .cs_files .changes .added {
2514 .cs_files .changes .added {
2517 background-color: #BBFFBB;
2515 background-color: #BBFFBB;
2518 float: left;
2516 float: left;
2519 text-align: center;
2517 text-align: center;
2520 font-size: 9px;
2518 font-size: 9px;
2521 padding: 2px 0px 2px 0px;
2519 padding: 2px 0px 2px 0px;
2522 }
2520 }
2523
2521
2524 .cs_files .changes .deleted {
2522 .cs_files .changes .deleted {
2525 background-color: #FF8888;
2523 background-color: #FF8888;
2526 float: left;
2524 float: left;
2527 text-align: center;
2525 text-align: center;
2528 font-size: 9px;
2526 font-size: 9px;
2529 padding: 2px 0px 2px 0px;
2527 padding: 2px 0px 2px 0px;
2530 }
2528 }
2531 /*new binary*/
2529 /*new binary*/
2532 .cs_files .changes .bin1 {
2530 .cs_files .changes .bin1 {
2533 background-color: #BBFFBB;
2531 background-color: #BBFFBB;
2534 float: left;
2532 float: left;
2535 text-align: center;
2533 text-align: center;
2536 font-size: 9px;
2534 font-size: 9px;
2537 padding: 2px 0px 2px 0px;
2535 padding: 2px 0px 2px 0px;
2538 }
2536 }
2539
2537
2540 /*deleted binary*/
2538 /*deleted binary*/
2541 .cs_files .changes .bin2 {
2539 .cs_files .changes .bin2 {
2542 background-color: #FF8888;
2540 background-color: #FF8888;
2543 float: left;
2541 float: left;
2544 text-align: center;
2542 text-align: center;
2545 font-size: 9px;
2543 font-size: 9px;
2546 padding: 2px 0px 2px 0px;
2544 padding: 2px 0px 2px 0px;
2547 }
2545 }
2548
2546
2549 /*mod binary*/
2547 /*mod binary*/
2550 .cs_files .changes .bin3 {
2548 .cs_files .changes .bin3 {
2551 background-color: #DDDDDD;
2549 background-color: #DDDDDD;
2552 float: left;
2550 float: left;
2553 text-align: center;
2551 text-align: center;
2554 font-size: 9px;
2552 font-size: 9px;
2555 padding: 2px 0px 2px 0px;
2553 padding: 2px 0px 2px 0px;
2556 }
2554 }
2557
2555
2558 /*rename file*/
2556 /*rename file*/
2559 .cs_files .changes .bin4 {
2557 .cs_files .changes .bin4 {
2560 background-color: #6D99FF;
2558 background-color: #6D99FF;
2561 float: left;
2559 float: left;
2562 text-align: center;
2560 text-align: center;
2563 font-size: 9px;
2561 font-size: 9px;
2564 padding: 2px 0px 2px 0px;
2562 padding: 2px 0px 2px 0px;
2565 }
2563 }
2566
2564
2567
2565
2568 .cs_files .cs_added,.cs_files .cs_A {
2566 .cs_files .cs_added,.cs_files .cs_A {
2569 background: url("../images/icons/page_white_add.png") no-repeat scroll
2567 background: url("../images/icons/page_white_add.png") no-repeat scroll
2570 3px;
2568 3px;
2571 height: 16px;
2569 height: 16px;
2572 padding-left: 20px;
2570 padding-left: 20px;
2573 margin-top: 7px;
2571 margin-top: 7px;
2574 text-align: left;
2572 text-align: left;
2575 }
2573 }
2576
2574
2577 .cs_files .cs_changed,.cs_files .cs_M {
2575 .cs_files .cs_changed,.cs_files .cs_M {
2578 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2576 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2579 3px;
2577 3px;
2580 height: 16px;
2578 height: 16px;
2581 padding-left: 20px;
2579 padding-left: 20px;
2582 margin-top: 7px;
2580 margin-top: 7px;
2583 text-align: left;
2581 text-align: left;
2584 }
2582 }
2585
2583
2586 .cs_files .cs_removed,.cs_files .cs_D {
2584 .cs_files .cs_removed,.cs_files .cs_D {
2587 background: url("../images/icons/page_white_delete.png") no-repeat
2585 background: url("../images/icons/page_white_delete.png") no-repeat
2588 scroll 3px;
2586 scroll 3px;
2589 height: 16px;
2587 height: 16px;
2590 padding-left: 20px;
2588 padding-left: 20px;
2591 margin-top: 7px;
2589 margin-top: 7px;
2592 text-align: left;
2590 text-align: left;
2593 }
2591 }
2594
2592
2595 #graph {
2593 #graph {
2596 overflow: hidden;
2594 overflow: hidden;
2597 }
2595 }
2598
2596
2599 #graph_nodes {
2597 #graph_nodes {
2600 float: left;
2598 float: left;
2601 margin-right: 0px;
2599 margin-right: 0px;
2602 margin-top: 0px;
2600 margin-top: 0px;
2603 }
2601 }
2604
2602
2605 #graph_content {
2603 #graph_content {
2606 width: 80%;
2604 width: 80%;
2607 float: left;
2605 float: left;
2608 }
2606 }
2609
2607
2610 #graph_content .container_header {
2608 #graph_content .container_header {
2611 border-bottom: 1px solid #DDD;
2609 border-bottom: 1px solid #DDD;
2612 padding: 10px;
2610 padding: 10px;
2613 height: 25px;
2611 height: 25px;
2614 }
2612 }
2615
2613
2616 #graph_content #rev_range_container {
2614 #graph_content #rev_range_container {
2617 float: left;
2615 float: left;
2618 margin: 0px 0px 0px 3px;
2616 margin: 0px 0px 0px 3px;
2619 }
2617 }
2620
2618
2621 #graph_content #rev_range_clear {
2619 #graph_content #rev_range_clear {
2622 float: left;
2620 float: left;
2623 margin: 0px 0px 0px 3px;
2621 margin: 0px 0px 0px 3px;
2624 }
2622 }
2625
2623
2626 #graph_content .container {
2624 #graph_content .container {
2627 border-bottom: 1px solid #DDD;
2625 border-bottom: 1px solid #DDD;
2628 height: 56px;
2626 height: 56px;
2629 overflow: hidden;
2627 overflow: hidden;
2630 }
2628 }
2631
2629
2632 #graph_content .container .right {
2630 #graph_content .container .right {
2633 float: right;
2631 float: right;
2634 width: 23%;
2632 width: 23%;
2635 text-align: right;
2633 text-align: right;
2636 }
2634 }
2637
2635
2638 #graph_content .container .left {
2636 #graph_content .container .left {
2639 float: left;
2637 float: left;
2640 width: 25%;
2638 width: 25%;
2641 padding-left: 5px;
2639 padding-left: 5px;
2642 }
2640 }
2643
2641
2644 #graph_content .container .mid {
2642 #graph_content .container .mid {
2645 float: left;
2643 float: left;
2646 width: 49%;
2644 width: 49%;
2647 }
2645 }
2648
2646
2649
2647
2650 #graph_content .container .left .date {
2648 #graph_content .container .left .date {
2651 color: #666;
2649 color: #666;
2652 padding-left: 22px;
2650 padding-left: 22px;
2653 font-size: 10px;
2651 font-size: 10px;
2654 }
2652 }
2655
2653
2656 #graph_content .container .left .author {
2654 #graph_content .container .left .author {
2657 height: 22px;
2655 height: 22px;
2658 }
2656 }
2659
2657
2660 #graph_content .container .left .author .user {
2658 #graph_content .container .left .author .user {
2661 color: #444444;
2659 color: #444444;
2662 float: left;
2660 float: left;
2663 margin-left: -4px;
2661 margin-left: -4px;
2664 margin-top: 4px;
2662 margin-top: 4px;
2665 }
2663 }
2666
2664
2667 #graph_content .container .mid .message {
2665 #graph_content .container .mid .message {
2668 white-space: pre-wrap;
2666 white-space: pre-wrap;
2669 }
2667 }
2670
2668
2671 #graph_content .container .mid .message a:hover{
2669 #graph_content .container .mid .message a:hover{
2672 text-decoration: none;
2670 text-decoration: none;
2673 }
2671 }
2674
2672
2675 .revision-link
2673 .revision-link
2676 {
2674 {
2677 color:#3F6F9F;
2675 color:#3F6F9F;
2678 font-weight: bold !important;
2676 font-weight: bold !important;
2679 }
2677 }
2680
2678
2681 .issue-tracker-link{
2679 .issue-tracker-link{
2682 color:#3F6F9F;
2680 color:#3F6F9F;
2683 font-weight: bold !important;
2681 font-weight: bold !important;
2684 }
2682 }
2685
2683
2686 .changeset-status-container{
2684 .changeset-status-container{
2687 padding-right: 5px;
2685 padding-right: 5px;
2688 margin-top:1px;
2686 margin-top:1px;
2689 float:right;
2687 float:right;
2690 height:14px;
2688 height:14px;
2691 }
2689 }
2692 .code-header .changeset-status-container{
2690 .code-header .changeset-status-container{
2693 float:left;
2691 float:left;
2694 padding:2px 0px 0px 2px;
2692 padding:2px 0px 0px 2px;
2695 }
2693 }
2696 .changeset-status-container .changeset-status-lbl{
2694 .changeset-status-container .changeset-status-lbl{
2697 color: rgb(136, 136, 136);
2695 color: rgb(136, 136, 136);
2698 float: left;
2696 float: left;
2699 padding: 3px 4px 0px 0px
2697 padding: 3px 4px 0px 0px
2700 }
2698 }
2701 .code-header .changeset-status-container .changeset-status-lbl{
2699 .code-header .changeset-status-container .changeset-status-lbl{
2702 float: left;
2700 float: left;
2703 padding: 0px 4px 0px 0px;
2701 padding: 0px 4px 0px 0px;
2704 }
2702 }
2705 .changeset-status-container .changeset-status-ico{
2703 .changeset-status-container .changeset-status-ico{
2706 float: left;
2704 float: left;
2707 }
2705 }
2708 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico{
2706 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico{
2709 float: left;
2707 float: left;
2710 }
2708 }
2711 .right .comments-container{
2709 .right .comments-container{
2712 padding-right: 5px;
2710 padding-right: 5px;
2713 margin-top:1px;
2711 margin-top:1px;
2714 float:right;
2712 float:right;
2715 height:14px;
2713 height:14px;
2716 }
2714 }
2717
2715
2718 .right .comments-cnt{
2716 .right .comments-cnt{
2719 float: left;
2717 float: left;
2720 color: rgb(136, 136, 136);
2718 color: rgb(136, 136, 136);
2721 padding-right: 2px;
2719 padding-right: 2px;
2722 }
2720 }
2723
2721
2724 .right .changes{
2722 .right .changes{
2725 clear: both;
2723 clear: both;
2726 }
2724 }
2727
2725
2728 .right .changes .changed_total {
2726 .right .changes .changed_total {
2729 display: block;
2727 display: block;
2730 float: right;
2728 float: right;
2731 text-align: center;
2729 text-align: center;
2732 min-width: 45px;
2730 min-width: 45px;
2733 cursor: pointer;
2731 cursor: pointer;
2734 color: #444444;
2732 color: #444444;
2735 background: #FEA;
2733 background: #FEA;
2736 -webkit-border-radius: 0px 0px 0px 6px;
2734 -webkit-border-radius: 0px 0px 0px 6px;
2737 -moz-border-radius: 0px 0px 0px 6px;
2735 -moz-border-radius: 0px 0px 0px 6px;
2738 border-radius: 0px 0px 0px 6px;
2736 border-radius: 0px 0px 0px 6px;
2739 padding: 1px;
2737 padding: 1px;
2740 }
2738 }
2741
2739
2742 .right .changes .added,.changed,.removed {
2740 .right .changes .added,.changed,.removed {
2743 display: block;
2741 display: block;
2744 padding: 1px;
2742 padding: 1px;
2745 color: #444444;
2743 color: #444444;
2746 float: right;
2744 float: right;
2747 text-align: center;
2745 text-align: center;
2748 min-width: 15px;
2746 min-width: 15px;
2749 }
2747 }
2750
2748
2751 .right .changes .added {
2749 .right .changes .added {
2752 background: #CFC;
2750 background: #CFC;
2753 }
2751 }
2754
2752
2755 .right .changes .changed {
2753 .right .changes .changed {
2756 background: #FEA;
2754 background: #FEA;
2757 }
2755 }
2758
2756
2759 .right .changes .removed {
2757 .right .changes .removed {
2760 background: #FAA;
2758 background: #FAA;
2761 }
2759 }
2762
2760
2763 .right .merge {
2761 .right .merge {
2764 padding: 1px 3px 1px 3px;
2762 padding: 1px 3px 1px 3px;
2765 background-color: #fca062;
2763 background-color: #fca062;
2766 font-size: 10px;
2764 font-size: 10px;
2767 font-weight: bold;
2765 font-weight: bold;
2768 color: #ffffff;
2766 color: #ffffff;
2769 text-transform: uppercase;
2767 text-transform: uppercase;
2770 white-space: nowrap;
2768 white-space: nowrap;
2771 -webkit-border-radius: 3px;
2769 -webkit-border-radius: 3px;
2772 -moz-border-radius: 3px;
2770 -moz-border-radius: 3px;
2773 border-radius: 3px;
2771 border-radius: 3px;
2774 margin-right: 2px;
2772 margin-right: 2px;
2775 }
2773 }
2776
2774
2777 .right .parent {
2775 .right .parent {
2778 color: #666666;
2776 color: #666666;
2779 clear:both;
2777 clear:both;
2780 }
2778 }
2781 .right .logtags{
2779 .right .logtags{
2782 padding: 2px 2px 2px 2px;
2780 padding: 2px 2px 2px 2px;
2783 }
2781 }
2784 .right .logtags .branchtag,.right .logtags .tagtag,.right .logtags .booktag{
2782 .right .logtags .branchtag,.right .logtags .tagtag,.right .logtags .booktag{
2785 margin: 0px 2px;
2783 margin: 0px 2px;
2786 }
2784 }
2787
2785
2788 .right .logtags .branchtag,
2786 .right .logtags .branchtag,
2789 .logtags .branchtag,
2787 .logtags .branchtag,
2790 .spantag {
2788 .spantag {
2791 padding: 1px 3px 1px 3px;
2789 padding: 1px 3px 1px 3px;
2792 background-color: #bfbfbf;
2790 background-color: #bfbfbf;
2793 font-size: 10px;
2791 font-size: 10px;
2794 font-weight: bold;
2792 font-weight: bold;
2795 color: #ffffff;
2793 color: #ffffff;
2796 white-space: nowrap;
2794 white-space: nowrap;
2797 -webkit-border-radius: 3px;
2795 -webkit-border-radius: 3px;
2798 -moz-border-radius: 3px;
2796 -moz-border-radius: 3px;
2799 border-radius: 3px;
2797 border-radius: 3px;
2800 }
2798 }
2801 .right .logtags .branchtag a:hover,.logtags .branchtag a{
2799 .right .logtags .branchtag a:hover,.logtags .branchtag a{
2802 color: #ffffff;
2800 color: #ffffff;
2803 }
2801 }
2804 .right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
2802 .right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
2805 text-decoration: none;
2803 text-decoration: none;
2806 color: #ffffff;
2804 color: #ffffff;
2807 }
2805 }
2808 .right .logtags .tagtag,.logtags .tagtag {
2806 .right .logtags .tagtag,.logtags .tagtag {
2809 padding: 1px 3px 1px 3px;
2807 padding: 1px 3px 1px 3px;
2810 background-color: #62cffc;
2808 background-color: #62cffc;
2811 font-size: 10px;
2809 font-size: 10px;
2812 font-weight: bold;
2810 font-weight: bold;
2813 color: #ffffff;
2811 color: #ffffff;
2814 white-space: nowrap;
2812 white-space: nowrap;
2815 -webkit-border-radius: 3px;
2813 -webkit-border-radius: 3px;
2816 -moz-border-radius: 3px;
2814 -moz-border-radius: 3px;
2817 border-radius: 3px;
2815 border-radius: 3px;
2818 }
2816 }
2819 .right .logtags .tagtag a:hover,.logtags .tagtag a{
2817 .right .logtags .tagtag a:hover,.logtags .tagtag a{
2820 color: #ffffff;
2818 color: #ffffff;
2821 }
2819 }
2822 .right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
2820 .right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
2823 text-decoration: none;
2821 text-decoration: none;
2824 color: #ffffff;
2822 color: #ffffff;
2825 }
2823 }
2826 .right .logbooks .bookbook,.logbooks .bookbook,.right .logtags .bookbook,.logtags .bookbook {
2824 .right .logbooks .bookbook,.logbooks .bookbook,.right .logtags .bookbook,.logtags .bookbook {
2827 padding: 1px 3px 1px 3px;
2825 padding: 1px 3px 1px 3px;
2828 background-color: #46A546;
2826 background-color: #46A546;
2829 font-size: 10px;
2827 font-size: 10px;
2830 font-weight: bold;
2828 font-weight: bold;
2831 color: #ffffff;
2829 color: #ffffff;
2832 text-transform: uppercase;
2830 text-transform: uppercase;
2833 white-space: nowrap;
2831 white-space: nowrap;
2834 -webkit-border-radius: 3px;
2832 -webkit-border-radius: 3px;
2835 -moz-border-radius: 3px;
2833 -moz-border-radius: 3px;
2836 border-radius: 3px;
2834 border-radius: 3px;
2837 }
2835 }
2838 .right .logbooks .bookbook,.logbooks .bookbook a,.right .logtags .bookbook,.logtags .bookbook a{
2836 .right .logbooks .bookbook,.logbooks .bookbook a,.right .logtags .bookbook,.logtags .bookbook a{
2839 color: #ffffff;
2837 color: #ffffff;
2840 }
2838 }
2841 .right .logbooks .bookbook,.logbooks .bookbook a:hover,.right .logtags .bookbook,.logtags .bookbook a:hover{
2839 .right .logbooks .bookbook,.logbooks .bookbook a:hover,.right .logtags .bookbook,.logtags .bookbook a:hover{
2842 text-decoration: none;
2840 text-decoration: none;
2843 color: #ffffff;
2841 color: #ffffff;
2844 }
2842 }
2845 div.browserblock {
2843 div.browserblock {
2846 overflow: hidden;
2844 overflow: hidden;
2847 border: 1px solid #ccc;
2845 border: 1px solid #ccc;
2848 background: #f8f8f8;
2846 background: #f8f8f8;
2849 font-size: 100%;
2847 font-size: 100%;
2850 line-height: 125%;
2848 line-height: 125%;
2851 padding: 0;
2849 padding: 0;
2852 -webkit-border-radius: 6px 6px 0px 0px;
2850 -webkit-border-radius: 6px 6px 0px 0px;
2853 -moz-border-radius: 6px 6px 0px 0px;
2851 -moz-border-radius: 6px 6px 0px 0px;
2854 border-radius: 6px 6px 0px 0px;
2852 border-radius: 6px 6px 0px 0px;
2855 }
2853 }
2856
2854
2857 div.browserblock .browser-header {
2855 div.browserblock .browser-header {
2858 background: #FFF;
2856 background: #FFF;
2859 padding: 10px 0px 15px 0px;
2857 padding: 10px 0px 15px 0px;
2860 width: 100%;
2858 width: 100%;
2861 }
2859 }
2862
2860
2863 div.browserblock .browser-nav {
2861 div.browserblock .browser-nav {
2864 float: left
2862 float: left
2865 }
2863 }
2866
2864
2867 div.browserblock .browser-branch {
2865 div.browserblock .browser-branch {
2868 float: left;
2866 float: left;
2869 }
2867 }
2870
2868
2871 div.browserblock .browser-branch label {
2869 div.browserblock .browser-branch label {
2872 color: #4A4A4A;
2870 color: #4A4A4A;
2873 vertical-align: text-top;
2871 vertical-align: text-top;
2874 }
2872 }
2875
2873
2876 div.browserblock .browser-header span {
2874 div.browserblock .browser-header span {
2877 margin-left: 5px;
2875 margin-left: 5px;
2878 font-weight: 700;
2876 font-weight: 700;
2879 }
2877 }
2880
2878
2881 div.browserblock .browser-search {
2879 div.browserblock .browser-search {
2882 clear: both;
2880 clear: both;
2883 padding: 8px 8px 0px 5px;
2881 padding: 8px 8px 0px 5px;
2884 height: 20px;
2882 height: 20px;
2885 }
2883 }
2886
2884
2887 div.browserblock #node_filter_box {
2885 div.browserblock #node_filter_box {
2888
2889 }
2886 }
2890
2887
2891 div.browserblock .search_activate {
2888 div.browserblock .search_activate {
2892 float: left
2889 float: left
2893 }
2890 }
2894
2891
2895 div.browserblock .add_node {
2892 div.browserblock .add_node {
2896 float: left;
2893 float: left;
2897 padding-left: 5px;
2894 padding-left: 5px;
2898 }
2895 }
2899
2896
2900 div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover
2897 div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover
2901 {
2898 {
2902 text-decoration: none !important;
2899 text-decoration: none !important;
2903 }
2900 }
2904
2901
2905 div.browserblock .browser-body {
2902 div.browserblock .browser-body {
2906 background: #EEE;
2903 background: #EEE;
2907 border-top: 1px solid #CCC;
2904 border-top: 1px solid #CCC;
2908 }
2905 }
2909
2906
2910 table.code-browser {
2907 table.code-browser {
2911 border-collapse: collapse;
2908 border-collapse: collapse;
2912 width: 100%;
2909 width: 100%;
2913 }
2910 }
2914
2911
2915 table.code-browser tr {
2912 table.code-browser tr {
2916 margin: 3px;
2913 margin: 3px;
2917 }
2914 }
2918
2915
2919 table.code-browser thead th {
2916 table.code-browser thead th {
2920 background-color: #EEE;
2917 background-color: #EEE;
2921 height: 20px;
2918 height: 20px;
2922 font-size: 1.1em;
2919 font-size: 1.1em;
2923 font-weight: 700;
2920 font-weight: 700;
2924 text-align: left;
2921 text-align: left;
2925 padding-left: 10px;
2922 padding-left: 10px;
2926 }
2923 }
2927
2924
2928 table.code-browser tbody td {
2925 table.code-browser tbody td {
2929 padding-left: 10px;
2926 padding-left: 10px;
2930 height: 20px;
2927 height: 20px;
2931 }
2928 }
2932
2929
2933 table.code-browser .browser-file {
2930 table.code-browser .browser-file {
2934 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2931 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2935 height: 16px;
2932 height: 16px;
2936 padding-left: 20px;
2933 padding-left: 20px;
2937 text-align: left;
2934 text-align: left;
2938 }
2935 }
2939 .diffblock .changeset_header {
2936 .diffblock .changeset_header {
2940 height: 16px;
2937 height: 16px;
2941 }
2938 }
2942 .diffblock .changeset_file {
2939 .diffblock .changeset_file {
2943 background: url("../images/icons/file.png") no-repeat scroll 3px;
2940 background: url("../images/icons/file.png") no-repeat scroll 3px;
2944 text-align: left;
2941 text-align: left;
2945 float: left;
2942 float: left;
2946 padding: 2px 0px 2px 22px;
2943 padding: 2px 0px 2px 22px;
2947 }
2944 }
2948 .diffblock .diff-menu-wrapper{
2945 .diffblock .diff-menu-wrapper{
2949 float: left;
2946 float: left;
2950 }
2947 }
2951
2948
2952 .diffblock .diff-menu{
2949 .diffblock .diff-menu{
2953 position: absolute;
2950 position: absolute;
2954 background: none repeat scroll 0 0 #FFFFFF;
2951 background: none repeat scroll 0 0 #FFFFFF;
2955 border-color: #003367 #666666 #666666;
2952 border-color: #003367 #666666 #666666;
2956 border-right: 1px solid #666666;
2953 border-right: 1px solid #666666;
2957 border-style: solid solid solid;
2954 border-style: solid solid solid;
2958 border-width: 1px;
2955 border-width: 1px;
2959 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2956 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2960 margin-top:5px;
2957 margin-top:5px;
2961 margin-left:1px;
2958 margin-left:1px;
2962
2959
2963 }
2960 }
2964 .diffblock .diff-actions {
2961 .diffblock .diff-actions {
2965 padding: 2px 0px 0px 2px;
2962 padding: 2px 0px 0px 2px;
2966 float: left;
2963 float: left;
2967 }
2964 }
2968 .diffblock .diff-menu ul li {
2965 .diffblock .diff-menu ul li {
2969 padding: 0px 0px 0px 0px !important;
2966 padding: 0px 0px 0px 0px !important;
2970 }
2967 }
2971 .diffblock .diff-menu ul li a{
2968 .diffblock .diff-menu ul li a{
2972 display: block;
2969 display: block;
2973 padding: 3px 8px 3px 8px !important;
2970 padding: 3px 8px 3px 8px !important;
2974 }
2971 }
2975 .diffblock .diff-menu ul li a:hover{
2972 .diffblock .diff-menu ul li a:hover{
2976 text-decoration: none;
2973 text-decoration: none;
2977 background-color: #EEEEEE;
2974 background-color: #EEEEEE;
2978 }
2975 }
2979 table.code-browser .browser-dir {
2976 table.code-browser .browser-dir {
2980 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2977 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2981 height: 16px;
2978 height: 16px;
2982 padding-left: 20px;
2979 padding-left: 20px;
2983 text-align: left;
2980 text-align: left;
2984 }
2981 }
2985
2982
2986 table.code-browser .submodule-dir {
2983 table.code-browser .submodule-dir {
2987 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
2984 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
2988 height: 16px;
2985 height: 16px;
2989 padding-left: 20px;
2986 padding-left: 20px;
2990 text-align: left;
2987 text-align: left;
2991 }
2988 }
2992
2989
2993
2990
2994 .box .search {
2991 .box .search {
2995 clear: both;
2992 clear: both;
2996 overflow: hidden;
2993 overflow: hidden;
2997 margin: 0;
2994 margin: 0;
2998 padding: 0 20px 10px;
2995 padding: 0 20px 10px;
2999 }
2996 }
3000
2997
3001 .box .search div.search_path {
2998 .box .search div.search_path {
3002 background: none repeat scroll 0 0 #EEE;
2999 background: none repeat scroll 0 0 #EEE;
3003 border: 1px solid #CCC;
3000 border: 1px solid #CCC;
3004 color: blue;
3001 color: blue;
3005 margin-bottom: 10px;
3002 margin-bottom: 10px;
3006 padding: 10px 0;
3003 padding: 10px 0;
3007 }
3004 }
3008
3005
3009 .box .search div.search_path div.link {
3006 .box .search div.search_path div.link {
3010 font-weight: 700;
3007 font-weight: 700;
3011 margin-left: 25px;
3008 margin-left: 25px;
3012 }
3009 }
3013
3010
3014 .box .search div.search_path div.link a {
3011 .box .search div.search_path div.link a {
3015 color: #003367;
3012 color: #003367;
3016 cursor: pointer;
3013 cursor: pointer;
3017 text-decoration: none;
3014 text-decoration: none;
3018 }
3015 }
3019
3016
3020 #path_unlock {
3017 #path_unlock {
3021 color: red;
3018 color: red;
3022 font-size: 1.2em;
3019 font-size: 1.2em;
3023 padding-left: 4px;
3020 padding-left: 4px;
3024 }
3021 }
3025
3022
3026 .info_box span {
3023 .info_box span {
3027 margin-left: 3px;
3024 margin-left: 3px;
3028 margin-right: 3px;
3025 margin-right: 3px;
3029 }
3026 }
3030
3027
3031 .info_box .rev {
3028 .info_box .rev {
3032 color: #003367;
3029 color: #003367;
3033 font-size: 1.6em;
3030 font-size: 1.6em;
3034 font-weight: bold;
3031 font-weight: bold;
3035 vertical-align: sub;
3032 vertical-align: sub;
3036 }
3033 }
3037
3034
3038 .info_box input#at_rev,.info_box input#size {
3035 .info_box input#at_rev,.info_box input#size {
3039 background: #FFF;
3036 background: #FFF;
3040 border-top: 1px solid #b3b3b3;
3037 border-top: 1px solid #b3b3b3;
3041 border-left: 1px solid #b3b3b3;
3038 border-left: 1px solid #b3b3b3;
3042 border-right: 1px solid #eaeaea;
3039 border-right: 1px solid #eaeaea;
3043 border-bottom: 1px solid #eaeaea;
3040 border-bottom: 1px solid #eaeaea;
3044 color: #000;
3041 color: #000;
3045 font-size: 12px;
3042 font-size: 12px;
3046 margin: 0;
3043 margin: 0;
3047 padding: 1px 5px 1px;
3044 padding: 1px 5px 1px;
3048 }
3045 }
3049
3046
3050 .info_box input#view {
3047 .info_box input#view {
3051 text-align: center;
3048 text-align: center;
3052 padding: 4px 3px 2px 2px;
3049 padding: 4px 3px 2px 2px;
3053 }
3050 }
3054
3051
3055 .yui-overlay,.yui-panel-container {
3052 .yui-overlay,.yui-panel-container {
3056 visibility: hidden;
3053 visibility: hidden;
3057 position: absolute;
3054 position: absolute;
3058 z-index: 2;
3055 z-index: 2;
3059 }
3056 }
3060
3057
3061 #tip-box {
3058 #tip-box {
3062 position: absolute;
3059 position: absolute;
3063
3060
3064 background-color: #FFF;
3061 background-color: #FFF;
3065 border: 2px solid #003367;
3062 border: 2px solid #003367;
3066 font: 100% sans-serif;
3063 font: 100% sans-serif;
3067 width: auto;
3064 width: auto;
3068 opacity: 1px;
3065 opacity: 1px;
3069 padding: 8px;
3066 padding: 8px;
3070
3067
3071 white-space: pre-wrap;
3068 white-space: pre-wrap;
3072 -webkit-border-radius: 8px 8px 8px 8px;
3069 -webkit-border-radius: 8px 8px 8px 8px;
3073 -khtml-border-radius: 8px 8px 8px 8px;
3070 -khtml-border-radius: 8px 8px 8px 8px;
3074 -moz-border-radius: 8px 8px 8px 8px;
3071 -moz-border-radius: 8px 8px 8px 8px;
3075 border-radius: 8px 8px 8px 8px;
3072 border-radius: 8px 8px 8px 8px;
3076 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3073 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3077 -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3074 -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3078 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3075 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3079 }
3076 }
3080
3077
3081 .hl-tip-box {
3078 .hl-tip-box {
3082 visibility: hidden;
3079 visibility: hidden;
3083 position: absolute;
3080 position: absolute;
3084 color: #666;
3081 color: #666;
3085 background-color: #FFF;
3082 background-color: #FFF;
3086 border: 2px solid #003367;
3083 border: 2px solid #003367;
3087 font: 100% sans-serif;
3084 font: 100% sans-serif;
3088 width: auto;
3085 width: auto;
3089 opacity: 1px;
3086 opacity: 1px;
3090 padding: 8px;
3087 padding: 8px;
3091 white-space: pre-wrap;
3088 white-space: pre-wrap;
3092 -webkit-border-radius: 8px 8px 8px 8px;
3089 -webkit-border-radius: 8px 8px 8px 8px;
3093 -khtml-border-radius: 8px 8px 8px 8px;
3090 -khtml-border-radius: 8px 8px 8px 8px;
3094 -moz-border-radius: 8px 8px 8px 8px;
3091 -moz-border-radius: 8px 8px 8px 8px;
3095 border-radius: 8px 8px 8px 8px;
3092 border-radius: 8px 8px 8px 8px;
3096 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3093 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3097 }
3094 }
3098
3095
3099
3096
3100 .mentions-container{
3097 .mentions-container{
3101 width: 90% !important;
3098 width: 90% !important;
3102 }
3099 }
3103 .mentions-container .yui-ac-content{
3100 .mentions-container .yui-ac-content{
3104 width: 100% !important;
3101 width: 100% !important;
3105 }
3102 }
3106
3103
3107 .ac {
3104 .ac {
3108 vertical-align: top;
3105 vertical-align: top;
3109 }
3106 }
3110
3107
3111 .ac .yui-ac {
3108 .ac .yui-ac {
3112 position: inherit;
3109 position: inherit;
3113 font-size: 100%;
3110 font-size: 100%;
3114 }
3111 }
3115
3112
3116 .ac .perm_ac {
3113 .ac .perm_ac {
3117 width: 20em;
3114 width: 20em;
3118 }
3115 }
3119
3116
3120 .ac .yui-ac-input {
3117 .ac .yui-ac-input {
3121 width: 100%;
3118 width: 100%;
3122 }
3119 }
3123
3120
3124 .ac .yui-ac-container {
3121 .ac .yui-ac-container {
3125 position: absolute;
3122 position: absolute;
3126 top: 1.6em;
3123 top: 1.6em;
3127 width: auto;
3124 width: auto;
3128 }
3125 }
3129
3126
3130 .ac .yui-ac-content {
3127 .ac .yui-ac-content {
3131 position: absolute;
3128 position: absolute;
3132 border: 1px solid gray;
3129 border: 1px solid gray;
3133 background: #fff;
3130 background: #fff;
3134 z-index: 9050;
3131 z-index: 9050;
3135
3136 }
3132 }
3137
3133
3138 .ac .yui-ac-shadow {
3134 .ac .yui-ac-shadow {
3139 position: absolute;
3135 position: absolute;
3140 width: 100%;
3136 width: 100%;
3141 background: #000;
3137 background: #000;
3142 -moz-opacity: 0.1px;
3138 -moz-opacity: 0.1px;
3143 opacity: .10;
3139 opacity: .10;
3144 filter: alpha(opacity = 10);
3140 filter: alpha(opacity = 10);
3145 z-index: 9049;
3141 z-index: 9049;
3146 margin: .3em;
3142 margin: .3em;
3147 }
3143 }
3148
3144
3149 .ac .yui-ac-content ul {
3145 .ac .yui-ac-content ul {
3150 width: 100%;
3146 width: 100%;
3151 margin: 0;
3147 margin: 0;
3152 padding: 0;
3148 padding: 0;
3153 z-index: 9050;
3149 z-index: 9050;
3154 }
3150 }
3155
3151
3156 .ac .yui-ac-content li {
3152 .ac .yui-ac-content li {
3157 cursor: default;
3153 cursor: default;
3158 white-space: nowrap;
3154 white-space: nowrap;
3159 margin: 0;
3155 margin: 0;
3160 padding: 2px 5px;
3156 padding: 2px 5px;
3161 height: 18px;
3157 height: 18px;
3162 z-index: 9050;
3158 z-index: 9050;
3163 display: block;
3159 display: block;
3164 width: auto !important;
3160 width: auto !important;
3165 }
3161 }
3166
3162
3167 .ac .yui-ac-content li .ac-container-wrap{
3163 .ac .yui-ac-content li .ac-container-wrap{
3168 width: auto;
3164 width: auto;
3169 }
3165 }
3170
3166
3171 .ac .yui-ac-content li.yui-ac-prehighlight {
3167 .ac .yui-ac-content li.yui-ac-prehighlight {
3172 background: #B3D4FF;
3168 background: #B3D4FF;
3173 z-index: 9050;
3169 z-index: 9050;
3174 }
3170 }
3175
3171
3176 .ac .yui-ac-content li.yui-ac-highlight {
3172 .ac .yui-ac-content li.yui-ac-highlight {
3177 background: #556CB5;
3173 background: #556CB5;
3178 color: #FFF;
3174 color: #FFF;
3179 z-index: 9050;
3175 z-index: 9050;
3180 }
3176 }
3181 .ac .yui-ac-bd{
3177 .ac .yui-ac-bd{
3182 z-index: 9050;
3178 z-index: 9050;
3183 }
3179 }
3184
3180
3185 .follow {
3181 .follow {
3186 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3182 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3187 height: 16px;
3183 height: 16px;
3188 width: 20px;
3184 width: 20px;
3189 cursor: pointer;
3185 cursor: pointer;
3190 display: block;
3186 display: block;
3191 float: right;
3187 float: right;
3192 margin-top: 2px;
3188 margin-top: 2px;
3193 }
3189 }
3194
3190
3195 .following {
3191 .following {
3196 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3192 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3197 height: 16px;
3193 height: 16px;
3198 width: 20px;
3194 width: 20px;
3199 cursor: pointer;
3195 cursor: pointer;
3200 display: block;
3196 display: block;
3201 float: right;
3197 float: right;
3202 margin-top: 2px;
3198 margin-top: 2px;
3203 }
3199 }
3204
3200
3205 .reposize {
3201 .reposize {
3206 background: url("../images/icons/server.png") no-repeat scroll 3px;
3202 background: url("../images/icons/server.png") no-repeat scroll 3px;
3207 height: 16px;
3203 height: 16px;
3208 width: 20px;
3204 width: 20px;
3209 cursor: pointer;
3205 cursor: pointer;
3210 display: block;
3206 display: block;
3211 float: right;
3207 float: right;
3212 margin-top: 2px;
3208 margin-top: 2px;
3213 }
3209 }
3214
3210
3215 #repo_size{
3211 #repo_size{
3216 display: block;
3212 display: block;
3217 margin-top: 4px;
3213 margin-top: 4px;
3218 color: #666;
3214 color: #666;
3219 float:right;
3215 float:right;
3220 }
3216 }
3221
3217
3222 .locking_locked{
3218 .locking_locked{
3223 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3219 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3224 height: 16px;
3220 height: 16px;
3225 width: 20px;
3221 width: 20px;
3226 cursor: pointer;
3222 cursor: pointer;
3227 display: block;
3223 display: block;
3228 float: right;
3224 float: right;
3229 margin-top: 2px;
3225 margin-top: 2px;
3230 }
3226 }
3231
3227
3232 .locking_unlocked{
3228 .locking_unlocked{
3233 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3229 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3234 height: 16px;
3230 height: 16px;
3235 width: 20px;
3231 width: 20px;
3236 cursor: pointer;
3232 cursor: pointer;
3237 display: block;
3233 display: block;
3238 float: right;
3234 float: right;
3239 margin-top: 2px;
3235 margin-top: 2px;
3240 }
3236 }
3241
3237
3242 .currently_following {
3238 .currently_following {
3243 padding-left: 10px;
3239 padding-left: 10px;
3244 padding-bottom: 5px;
3240 padding-bottom: 5px;
3245 }
3241 }
3246
3242
3247 .add_icon {
3243 .add_icon {
3248 background: url("../images/icons/add.png") no-repeat scroll 3px;
3244 background: url("../images/icons/add.png") no-repeat scroll 3px;
3249 padding-left: 20px;
3245 padding-left: 20px;
3250 padding-top: 0px;
3246 padding-top: 0px;
3251 text-align: left;
3247 text-align: left;
3252 }
3248 }
3253
3249
3254 .accept_icon {
3250 .accept_icon {
3255 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3251 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3256 padding-left: 20px;
3252 padding-left: 20px;
3257 padding-top: 0px;
3253 padding-top: 0px;
3258 text-align: left;
3254 text-align: left;
3259 }
3255 }
3260
3256
3261 .edit_icon {
3257 .edit_icon {
3262 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3258 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3263 padding-left: 20px;
3259 padding-left: 20px;
3264 padding-top: 0px;
3260 padding-top: 0px;
3265 text-align: left;
3261 text-align: left;
3266 }
3262 }
3267
3263
3268 .delete_icon {
3264 .delete_icon {
3269 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3265 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3270 padding-left: 20px;
3266 padding-left: 20px;
3271 padding-top: 0px;
3267 padding-top: 0px;
3272 text-align: left;
3268 text-align: left;
3273 }
3269 }
3274
3270
3275 .refresh_icon {
3271 .refresh_icon {
3276 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3272 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3277 3px;
3273 3px;
3278 padding-left: 20px;
3274 padding-left: 20px;
3279 padding-top: 0px;
3275 padding-top: 0px;
3280 text-align: left;
3276 text-align: left;
3281 }
3277 }
3282
3278
3283 .pull_icon {
3279 .pull_icon {
3284 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3280 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3285 padding-left: 20px;
3281 padding-left: 20px;
3286 padding-top: 0px;
3282 padding-top: 0px;
3287 text-align: left;
3283 text-align: left;
3288 }
3284 }
3289
3285
3290 .rss_icon {
3286 .rss_icon {
3291 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3287 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3292 padding-left: 20px;
3288 padding-left: 20px;
3293 padding-top: 4px;
3289 padding-top: 4px;
3294 text-align: left;
3290 text-align: left;
3295 font-size: 8px
3291 font-size: 8px
3296 }
3292 }
3297
3293
3298 .atom_icon {
3294 .atom_icon {
3299 background: url("../images/icons/atom.png") no-repeat scroll 3px;
3295 background: url("../images/icons/atom.png") no-repeat scroll 3px;
3300 padding-left: 20px;
3296 padding-left: 20px;
3301 padding-top: 4px;
3297 padding-top: 4px;
3302 text-align: left;
3298 text-align: left;
3303 font-size: 8px
3299 font-size: 8px
3304 }
3300 }
3305
3301
3306 .archive_icon {
3302 .archive_icon {
3307 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3303 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3308 padding-left: 20px;
3304 padding-left: 20px;
3309 text-align: left;
3305 text-align: left;
3310 padding-top: 1px;
3306 padding-top: 1px;
3311 }
3307 }
3312
3308
3313 .start_following_icon {
3309 .start_following_icon {
3314 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3310 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3315 padding-left: 20px;
3311 padding-left: 20px;
3316 text-align: left;
3312 text-align: left;
3317 padding-top: 0px;
3313 padding-top: 0px;
3318 }
3314 }
3319
3315
3320 .stop_following_icon {
3316 .stop_following_icon {
3321 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3317 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3322 padding-left: 20px;
3318 padding-left: 20px;
3323 text-align: left;
3319 text-align: left;
3324 padding-top: 0px;
3320 padding-top: 0px;
3325 }
3321 }
3326
3322
3327 .action_button {
3323 .action_button {
3328 border: 0;
3324 border: 0;
3329 display: inline;
3325 display: inline;
3330 }
3326 }
3331
3327
3332 .action_button:hover {
3328 .action_button:hover {
3333 border: 0;
3329 border: 0;
3334 text-decoration: underline;
3330 text-decoration: underline;
3335 cursor: pointer;
3331 cursor: pointer;
3336 }
3332 }
3337
3333
3338 #switch_repos {
3334 #switch_repos {
3339 position: absolute;
3335 position: absolute;
3340 height: 25px;
3336 height: 25px;
3341 z-index: 1;
3337 z-index: 1;
3342 }
3338 }
3343
3339
3344 #switch_repos select {
3340 #switch_repos select {
3345 min-width: 150px;
3341 min-width: 150px;
3346 max-height: 250px;
3342 max-height: 250px;
3347 z-index: 1;
3343 z-index: 1;
3348 }
3344 }
3349
3345
3350 .breadcrumbs {
3346 .breadcrumbs {
3351 border: medium none;
3347 border: medium none;
3352 color: #FFF;
3348 color: #FFF;
3353 float: left;
3349 float: left;
3354 font-weight: 700;
3350 font-weight: 700;
3355 font-size: 14px;
3351 font-size: 14px;
3356 margin: 0;
3352 margin: 0;
3357 padding: 11px 0 11px 10px;
3353 padding: 11px 0 11px 10px;
3358 }
3354 }
3359
3355
3360 .breadcrumbs .hash {
3356 .breadcrumbs .hash {
3361 text-transform: none;
3357 text-transform: none;
3362 color: #fff;
3358 color: #fff;
3363 }
3359 }
3364
3360
3365 .breadcrumbs a {
3361 .breadcrumbs a {
3366 color: #FFF;
3362 color: #FFF;
3367 }
3363 }
3368
3364
3369 .flash_msg {
3365 .flash_msg {
3370
3371 }
3366 }
3372
3367
3373 .flash_msg ul {
3368 .flash_msg ul {
3374
3375 }
3369 }
3376
3370
3377 .error_red {
3371 .error_red {
3378 color:red;
3372 color:red;
3379 }
3373 }
3380
3374
3381 .error_msg {
3375 .error_msg {
3382 background-color: #c43c35;
3376 background-color: #c43c35;
3383 background-repeat: repeat-x;
3377 background-repeat: repeat-x;
3384 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3378 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3385 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3379 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3386 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3380 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3387 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3381 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3388 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3382 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3389 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3383 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3390 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3384 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3391 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3385 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3392 border-color: #c43c35 #c43c35 #882a25;
3386 border-color: #c43c35 #c43c35 #882a25;
3393 }
3387 }
3394
3388
3395 .warning_msg {
3389 .warning_msg {
3396 color: #404040 !important;
3390 color: #404040 !important;
3397 background-color: #eedc94;
3391 background-color: #eedc94;
3398 background-repeat: repeat-x;
3392 background-repeat: repeat-x;
3399 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3393 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3400 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3394 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3401 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3395 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3402 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3396 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3403 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3397 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3404 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3398 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3405 background-image: linear-gradient(top, #fceec1, #eedc94);
3399 background-image: linear-gradient(top, #fceec1, #eedc94);
3406 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3400 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3407 border-color: #eedc94 #eedc94 #e4c652;
3401 border-color: #eedc94 #eedc94 #e4c652;
3408 }
3402 }
3409
3403
3410 .success_msg {
3404 .success_msg {
3411 background-color: #57a957;
3405 background-color: #57a957;
3412 background-repeat: repeat-x !important;
3406 background-repeat: repeat-x !important;
3413 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3407 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3414 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3408 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3415 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3409 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3416 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3410 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3417 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3411 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3418 background-image: -o-linear-gradient(top, #62c462, #57a957);
3412 background-image: -o-linear-gradient(top, #62c462, #57a957);
3419 background-image: linear-gradient(top, #62c462, #57a957);
3413 background-image: linear-gradient(top, #62c462, #57a957);
3420 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3414 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3421 border-color: #57a957 #57a957 #3d773d;
3415 border-color: #57a957 #57a957 #3d773d;
3422 }
3416 }
3423
3417
3424 .notice_msg {
3418 .notice_msg {
3425 background-color: #339bb9;
3419 background-color: #339bb9;
3426 background-repeat: repeat-x;
3420 background-repeat: repeat-x;
3427 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3421 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3428 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3422 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3429 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3423 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3430 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3424 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3431 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3425 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3432 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3426 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3433 background-image: linear-gradient(top, #5bc0de, #339bb9);
3427 background-image: linear-gradient(top, #5bc0de, #339bb9);
3434 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3428 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3435 border-color: #339bb9 #339bb9 #22697d;
3429 border-color: #339bb9 #339bb9 #22697d;
3436 }
3430 }
3437
3431
3438 .success_msg,.error_msg,.notice_msg,.warning_msg {
3432 .success_msg,.error_msg,.notice_msg,.warning_msg {
3439 font-size: 12px;
3433 font-size: 12px;
3440 font-weight: 700;
3434 font-weight: 700;
3441 min-height: 14px;
3435 min-height: 14px;
3442 line-height: 14px;
3436 line-height: 14px;
3443 margin-bottom: 10px;
3437 margin-bottom: 10px;
3444 margin-top: 0;
3438 margin-top: 0;
3445 display: block;
3439 display: block;
3446 overflow: auto;
3440 overflow: auto;
3447 padding: 6px 10px 6px 10px;
3441 padding: 6px 10px 6px 10px;
3448 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3442 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3449 position: relative;
3443 position: relative;
3450 color: #FFF;
3444 color: #FFF;
3451 border-width: 1px;
3445 border-width: 1px;
3452 border-style: solid;
3446 border-style: solid;
3453 -webkit-border-radius: 4px;
3447 -webkit-border-radius: 4px;
3454 -moz-border-radius: 4px;
3448 -moz-border-radius: 4px;
3455 border-radius: 4px;
3449 border-radius: 4px;
3456 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3450 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3457 -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3451 -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3458 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3452 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3459 }
3453 }
3460
3454
3461 #msg_close {
3455 #msg_close {
3462 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3456 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3463 cursor: pointer;
3457 cursor: pointer;
3464 height: 16px;
3458 height: 16px;
3465 position: absolute;
3459 position: absolute;
3466 right: 5px;
3460 right: 5px;
3467 top: 5px;
3461 top: 5px;
3468 width: 16px;
3462 width: 16px;
3469 }
3463 }
3470 div#legend_data{
3464 div#legend_data{
3471 padding-left:10px;
3465 padding-left:10px;
3472 }
3466 }
3473 div#legend_container table{
3467 div#legend_container table{
3474 border: none !important;
3468 border: none !important;
3475 }
3469 }
3476 div#legend_container table,div#legend_choices table {
3470 div#legend_container table,div#legend_choices table {
3477 width: auto !important;
3471 width: auto !important;
3478 }
3472 }
3479
3473
3480 table#permissions_manage {
3474 table#permissions_manage {
3481 width: 0 !important;
3475 width: 0 !important;
3482 }
3476 }
3483
3477
3484 table#permissions_manage span.private_repo_msg {
3478 table#permissions_manage span.private_repo_msg {
3485 font-size: 0.8em;
3479 font-size: 0.8em;
3486 opacity: 0.6px;
3480 opacity: 0.6px;
3487 }
3481 }
3488
3482
3489 table#permissions_manage td.private_repo_msg {
3483 table#permissions_manage td.private_repo_msg {
3490 font-size: 0.8em;
3484 font-size: 0.8em;
3491 }
3485 }
3492
3486
3493 table#permissions_manage tr#add_perm_input td {
3487 table#permissions_manage tr#add_perm_input td {
3494 vertical-align: middle;
3488 vertical-align: middle;
3495 }
3489 }
3496
3490
3497 div.gravatar {
3491 div.gravatar {
3498 background-color: #FFF;
3492 background-color: #FFF;
3499 float: left;
3493 float: left;
3500 margin-right: 0.7em;
3494 margin-right: 0.7em;
3501 padding: 1px 1px 1px 1px;
3495 padding: 1px 1px 1px 1px;
3502 line-height:0;
3496 line-height:0;
3503 -webkit-border-radius: 3px;
3497 -webkit-border-radius: 3px;
3504 -khtml-border-radius: 3px;
3498 -khtml-border-radius: 3px;
3505 -moz-border-radius: 3px;
3499 -moz-border-radius: 3px;
3506 border-radius: 3px;
3500 border-radius: 3px;
3507 }
3501 }
3508
3502
3509 div.gravatar img {
3503 div.gravatar img {
3510 -webkit-border-radius: 2px;
3504 -webkit-border-radius: 2px;
3511 -khtml-border-radius: 2px;
3505 -khtml-border-radius: 2px;
3512 -moz-border-radius: 2px;
3506 -moz-border-radius: 2px;
3513 border-radius: 2px;
3507 border-radius: 2px;
3514 }
3508 }
3515
3509
3516 #header,#content,#footer {
3510 #header,#content,#footer {
3517 min-width: 978px;
3511 min-width: 978px;
3518 }
3512 }
3519
3513
3520 #content {
3514 #content {
3521 clear: both;
3515 clear: both;
3522 overflow: hidden;
3516 overflow: hidden;
3523 padding: 54px 10px 14px 10px;
3517 padding: 54px 10px 14px 10px;
3524 }
3518 }
3525
3519
3526 #content div.box div.title div.search {
3520 #content div.box div.title div.search {
3527
3521 border-left: 1px solid #316293;
3528 border-left: 1px solid #316293;
3529 }
3522 }
3530
3523
3531 #content div.box div.title div.search div.input input {
3524 #content div.box div.title div.search div.input input {
3532 border: 1px solid #316293;
3525 border: 1px solid #316293;
3533 }
3526 }
3534
3527
3535 .ui-btn{
3528 .ui-btn{
3536 color: #515151;
3529 color: #515151;
3537 background-color: #DADADA;
3530 background-color: #DADADA;
3538 background-repeat: repeat-x;
3531 background-repeat: repeat-x;
3539 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3532 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3540 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3533 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3541 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3534 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3542 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3535 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3543 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3536 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3544 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3537 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3545 background-image: linear-gradient(top, #F4F4F4, #DADADA);
3538 background-image: linear-gradient(top, #F4F4F4, #DADADA);
3546 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3539 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3547
3540
3548 border-top: 1px solid #DDD;
3541 border-top: 1px solid #DDD;
3549 border-left: 1px solid #c6c6c6;
3542 border-left: 1px solid #c6c6c6;
3550 border-right: 1px solid #DDD;
3543 border-right: 1px solid #DDD;
3551 border-bottom: 1px solid #c6c6c6;
3544 border-bottom: 1px solid #c6c6c6;
3552 color: #515151;
3545 color: #515151;
3553 outline: none;
3546 outline: none;
3554 margin: 0px 3px 3px 0px;
3547 margin: 0px 3px 3px 0px;
3555 -webkit-border-radius: 4px 4px 4px 4px !important;
3548 -webkit-border-radius: 4px 4px 4px 4px !important;
3556 -khtml-border-radius: 4px 4px 4px 4px !important;
3549 -khtml-border-radius: 4px 4px 4px 4px !important;
3557 -moz-border-radius: 4px 4px 4px 4px !important;
3550 -moz-border-radius: 4px 4px 4px 4px !important;
3558 border-radius: 4px 4px 4px 4px !important;
3551 border-radius: 4px 4px 4px 4px !important;
3559 cursor: pointer !important;
3552 cursor: pointer !important;
3560 padding: 3px 3px 3px 3px;
3553 padding: 3px 3px 3px 3px;
3561 background-position: 0 -15px;
3554 background-position: 0 -15px;
3562
3555
3563 }
3556 }
3564
3557
3565 .ui-btn.disabled{
3558 .ui-btn.disabled{
3566 color: #999;
3559 color: #999;
3567 }
3560 }
3568
3561
3569 .ui-btn.xsmall{
3562 .ui-btn.xsmall{
3570 padding: 1px 2px 1px 1px;
3563 padding: 1px 2px 1px 1px;
3571 }
3564 }
3572
3565
3573 .ui-btn.large{
3566 .ui-btn.large{
3574 padding: 6px 12px;
3567 padding: 6px 12px;
3575 }
3568 }
3576
3569
3577 .ui-btn.clone{
3570 .ui-btn.clone{
3578 padding: 5px 2px 6px 1px;
3571 padding: 5px 2px 6px 1px;
3579 margin: 0px -4px 3px 0px;
3572 margin: 0px -4px 3px 0px;
3580 -webkit-border-radius: 4px 0px 0px 4px !important;
3573 -webkit-border-radius: 4px 0px 0px 4px !important;
3581 -khtml-border-radius: 4px 0px 0px 4px !important;
3574 -khtml-border-radius: 4px 0px 0px 4px !important;
3582 -moz-border-radius: 4px 0px 0px 4px !important;
3575 -moz-border-radius: 4px 0px 0px 4px !important;
3583 border-radius: 4px 0px 0px 4px !important;
3576 border-radius: 4px 0px 0px 4px !important;
3584 width: 100px;
3577 width: 100px;
3585 text-align: center;
3578 text-align: center;
3586 float: left;
3579 float: left;
3587 position: absolute;
3580 position: absolute;
3588 }
3581 }
3589 .ui-btn:focus {
3582 .ui-btn:focus {
3590 outline: none;
3583 outline: none;
3591 }
3584 }
3592 .ui-btn:hover{
3585 .ui-btn:hover{
3593 background-position: 0 -15px;
3586 background-position: 0 -15px;
3594 text-decoration: none;
3587 text-decoration: none;
3595 color: #515151;
3588 color: #515151;
3596 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3589 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3597 }
3590 }
3598
3591
3599 .ui-btn.disabled:hover{
3592 .ui-btn.disabled:hover{
3600 background-position:none;
3593 background-position:none;
3601 color: #999;
3594 color: #999;
3602 text-decoration: none;
3595 text-decoration: none;
3603 box-shadow: none !important;
3596 box-shadow: none !important;
3604 }
3597 }
3605
3598
3606 .ui-btn.red{
3599 .ui-btn.red{
3607 color:#fff;
3600 color:#fff;
3608 background-color: #c43c35;
3601 background-color: #c43c35;
3609 background-repeat: repeat-x;
3602 background-repeat: repeat-x;
3610 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3603 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3611 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3604 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3612 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3605 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3613 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3606 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3614 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3607 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3615 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3608 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3616 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3609 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3617 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3610 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3618 border-color: #c43c35 #c43c35 #882a25;
3611 border-color: #c43c35 #c43c35 #882a25;
3619 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3612 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3620 }
3613 }
3621
3614
3622
3615
3623 .ui-btn.blue{
3616 .ui-btn.blue{
3624 color:#fff;
3617 color:#fff;
3625 background-color: #339bb9;
3618 background-color: #339bb9;
3626 background-repeat: repeat-x;
3619 background-repeat: repeat-x;
3627 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3620 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3628 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3621 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3629 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3622 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3630 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3623 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3631 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3624 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3632 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3625 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3633 background-image: linear-gradient(top, #5bc0de, #339bb9);
3626 background-image: linear-gradient(top, #5bc0de, #339bb9);
3634 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3627 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3635 border-color: #339bb9 #339bb9 #22697d;
3628 border-color: #339bb9 #339bb9 #22697d;
3636 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3629 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3637 }
3630 }
3638
3631
3639 .ui-btn.green{
3632 .ui-btn.green{
3640 background-color: #57a957;
3633 background-color: #57a957;
3641 background-repeat: repeat-x;
3634 background-repeat: repeat-x;
3642 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3635 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3643 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3636 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3644 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3637 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3645 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3638 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3646 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3639 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3647 background-image: -o-linear-gradient(top, #62c462, #57a957);
3640 background-image: -o-linear-gradient(top, #62c462, #57a957);
3648 background-image: linear-gradient(top, #62c462, #57a957);
3641 background-image: linear-gradient(top, #62c462, #57a957);
3649 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3642 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3650 border-color: #57a957 #57a957 #3d773d;
3643 border-color: #57a957 #57a957 #3d773d;
3651 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3644 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3652 }
3645 }
3653
3646
3654 .ui-btn.blue.hidden{
3647 .ui-btn.blue.hidden{
3655 display: none;
3648 display: none;
3656 }
3649 }
3657
3650
3658 .ui-btn.active{
3651 .ui-btn.active{
3659 font-weight: bold;
3652 font-weight: bold;
3660 }
3653 }
3661
3654
3662 ins,div.options a:hover {
3655 ins,div.options a:hover {
3663 text-decoration: none;
3656 text-decoration: none;
3664 }
3657 }
3665
3658
3666 img,
3659 img,
3667 #header #header-inner #quick li a:hover span.normal,
3660 #header #header-inner #quick li a:hover span.normal,
3668 #header #header-inner #quick li ul li.last,
3661 #header #header-inner #quick li ul li.last,
3669 #content div.box div.form div.fields div.field div.textarea table td table td a,
3662 #content div.box div.form div.fields div.field div.textarea table td table td a,
3670 #clone_url,
3663 #clone_url,
3671 #clone_url_id
3664 #clone_url_id
3672 {
3665 {
3673 border: none;
3666 border: none;
3674 }
3667 }
3675
3668
3676 img.icon,.right .merge img {
3669 img.icon,.right .merge img {
3677 vertical-align: bottom;
3670 vertical-align: bottom;
3678 }
3671 }
3679
3672
3680 #header ul#logged-user,#content div.box div.title ul.links,
3673 #header ul#logged-user,#content div.box div.title ul.links,
3681 #content div.box div.message div.dismiss,
3674 #content div.box div.message div.dismiss,
3682 #content div.box div.traffic div.legend ul
3675 #content div.box div.traffic div.legend ul
3683 {
3676 {
3684 float: right;
3677 float: right;
3685 margin: 0;
3678 margin: 0;
3686 padding: 0;
3679 padding: 0;
3687 }
3680 }
3688
3681
3689 #header #header-inner #home,#header #header-inner #logo,
3682 #header #header-inner #home,#header #header-inner #logo,
3690 #content div.box ul.left,#content div.box ol.left,
3683 #content div.box ul.left,#content div.box ol.left,
3691 #content div.box div.pagination-left,div#commit_history,
3684 #content div.box div.pagination-left,div#commit_history,
3692 div#legend_data,div#legend_container,div#legend_choices
3685 div#legend_data,div#legend_container,div#legend_choices
3693 {
3686 {
3694 float: left;
3687 float: left;
3695 }
3688 }
3696
3689
3697 #header #header-inner #quick li #quick_login,
3690 #header #header-inner #quick li #quick_login,
3698 #header #header-inner #quick li:hover ul ul,
3691 #header #header-inner #quick li:hover ul ul,
3699 #header #header-inner #quick li:hover ul ul ul,
3692 #header #header-inner #quick li:hover ul ul ul,
3700 #header #header-inner #quick li:hover ul ul ul ul,
3693 #header #header-inner #quick li:hover ul ul ul ul,
3701 #content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow
3694 #content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow
3702 {
3695 {
3703 display: none;
3696 display: none;
3704 }
3697 }
3705
3698
3706 #header #header-inner #quick li:hover #quick_login,
3699 #header #header-inner #quick li:hover #quick_login,
3707 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded
3700 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded
3708 {
3701 {
3709 display: block;
3702 display: block;
3710 }
3703 }
3711
3704
3712 #content div.graph {
3705 #content div.graph {
3713 padding: 0 10px 10px;
3706 padding: 0 10px 10px;
3714 }
3707 }
3715
3708
3716 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a
3709 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a
3717 {
3710 {
3718 color: #bfe3ff;
3711 color: #bfe3ff;
3719 }
3712 }
3720
3713
3721 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal
3714 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal
3722 {
3715 {
3723 margin: 10px 24px 10px 44px;
3716 margin: 10px 24px 10px 44px;
3724 }
3717 }
3725
3718
3726 #content div.box div.form,#content div.box div.table,#content div.box div.traffic
3719 #content div.box div.form,#content div.box div.table,#content div.box div.traffic
3727 {
3720 {
3728 clear: both;
3721 clear: both;
3729 overflow: hidden;
3722 overflow: hidden;
3730 margin: 0;
3723 margin: 0;
3731 padding: 0 20px 10px;
3724 padding: 0 20px 10px;
3732 }
3725 }
3733
3726
3734 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields
3727 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields
3735 {
3728 {
3736 clear: both;
3729 clear: both;
3737 overflow: hidden;
3730 overflow: hidden;
3738 margin: 0;
3731 margin: 0;
3739 padding: 0;
3732 padding: 0;
3740 }
3733 }
3741
3734
3742 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span
3735 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span
3743 {
3736 {
3744 height: 1%;
3737 height: 1%;
3745 display: block;
3738 display: block;
3746 color: #363636;
3739 color: #363636;
3747 margin: 0;
3740 margin: 0;
3748 padding: 2px 0 0;
3741 padding: 2px 0 0;
3749 }
3742 }
3750
3743
3751 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error
3744 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error
3752 {
3745 {
3753 background: #FBE3E4;
3746 background: #FBE3E4;
3754 border-top: 1px solid #e1b2b3;
3747 border-top: 1px solid #e1b2b3;
3755 border-left: 1px solid #e1b2b3;
3748 border-left: 1px solid #e1b2b3;
3756 border-right: 1px solid #FBC2C4;
3749 border-right: 1px solid #FBC2C4;
3757 border-bottom: 1px solid #FBC2C4;
3750 border-bottom: 1px solid #FBC2C4;
3758 }
3751 }
3759
3752
3760 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success
3753 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success
3761 {
3754 {
3762 background: #E6EFC2;
3755 background: #E6EFC2;
3763 border-top: 1px solid #cebb98;
3756 border-top: 1px solid #cebb98;
3764 border-left: 1px solid #cebb98;
3757 border-left: 1px solid #cebb98;
3765 border-right: 1px solid #c6d880;
3758 border-right: 1px solid #c6d880;
3766 border-bottom: 1px solid #c6d880;
3759 border-bottom: 1px solid #c6d880;
3767 }
3760 }
3768
3761
3769 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input
3762 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input
3770 {
3763 {
3771 margin: 0;
3764 margin: 0;
3772 }
3765 }
3773
3766
3774 #content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios
3767 #content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios
3775 {
3768 {
3776 margin: 0 0 0 0px !important;
3769 margin: 0 0 0 0px !important;
3777 padding: 0;
3770 padding: 0;
3778 }
3771 }
3779
3772
3780 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios
3773 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios
3781 {
3774 {
3782 margin: 0 0 0 200px;
3775 margin: 0 0 0 200px;
3783 padding: 0;
3776 padding: 0;
3784 }
3777 }
3785
3778
3786 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover
3779 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover
3787 {
3780 {
3788 color: #000;
3781 color: #000;
3789 text-decoration: none;
3782 text-decoration: none;
3790 }
3783 }
3791
3784
3792 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus
3785 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus
3793 {
3786 {
3794 border: 1px solid #666;
3787 border: 1px solid #666;
3795 }
3788 }
3796
3789
3797 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio
3790 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio
3798 {
3791 {
3799 clear: both;
3792 clear: both;
3800 overflow: hidden;
3793 overflow: hidden;
3801 margin: 0;
3794 margin: 0;
3802 padding: 8px 0 2px;
3795 padding: 8px 0 2px;
3803 }
3796 }
3804
3797
3805 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input
3798 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input
3806 {
3799 {
3807 float: left;
3800 float: left;
3808 margin: 0;
3801 margin: 0;
3809 }
3802 }
3810
3803
3811 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label
3804 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label
3812 {
3805 {
3813 height: 1%;
3806 height: 1%;
3814 display: block;
3807 display: block;
3815 float: left;
3808 float: left;
3816 margin: 2px 0 0 4px;
3809 margin: 2px 0 0 4px;
3817 }
3810 }
3818
3811
3819 div.form div.fields div.field div.button input,
3812 div.form div.fields div.field div.button input,
3820 #content div.box div.form div.fields div.buttons input
3813 #content div.box div.form div.fields div.buttons input
3821 div.form div.fields div.buttons input,
3814 div.form div.fields div.buttons input,
3822 #content div.box div.action div.button input {
3815 #content div.box div.action div.button input {
3823 /*color: #000;*/
3816 /*color: #000;*/
3824 font-size: 11px;
3817 font-size: 11px;
3825 font-weight: 700;
3818 font-weight: 700;
3826 margin: 0;
3819 margin: 0;
3827 }
3820 }
3828
3821
3829 input.ui-button {
3822 input.ui-button {
3830 background: #e5e3e3 url("../images/button.png") repeat-x;
3823 background: #e5e3e3 url("../images/button.png") repeat-x;
3831 border-top: 1px solid #DDD;
3824 border-top: 1px solid #DDD;
3832 border-left: 1px solid #c6c6c6;
3825 border-left: 1px solid #c6c6c6;
3833 border-right: 1px solid #DDD;
3826 border-right: 1px solid #DDD;
3834 border-bottom: 1px solid #c6c6c6;
3827 border-bottom: 1px solid #c6c6c6;
3835 color: #515151 !important;
3828 color: #515151 !important;
3836 outline: none;
3829 outline: none;
3837 margin: 0;
3830 margin: 0;
3838 padding: 6px 12px;
3831 padding: 6px 12px;
3839 -webkit-border-radius: 4px 4px 4px 4px;
3832 -webkit-border-radius: 4px 4px 4px 4px;
3840 -khtml-border-radius: 4px 4px 4px 4px;
3833 -khtml-border-radius: 4px 4px 4px 4px;
3841 -moz-border-radius: 4px 4px 4px 4px;
3834 -moz-border-radius: 4px 4px 4px 4px;
3842 border-radius: 4px 4px 4px 4px;
3835 border-radius: 4px 4px 4px 4px;
3843 box-shadow: 0 1px 0 #ececec;
3836 box-shadow: 0 1px 0 #ececec;
3844 cursor: pointer;
3837 cursor: pointer;
3845 }
3838 }
3846
3839
3847 input.ui-button:hover {
3840 input.ui-button:hover {
3848 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3841 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3849 border-top: 1px solid #ccc;
3842 border-top: 1px solid #ccc;
3850 border-left: 1px solid #bebebe;
3843 border-left: 1px solid #bebebe;
3851 border-right: 1px solid #b1b1b1;
3844 border-right: 1px solid #b1b1b1;
3852 border-bottom: 1px solid #afafaf;
3845 border-bottom: 1px solid #afafaf;
3853 }
3846 }
3854
3847
3855 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight
3848 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight
3856 {
3849 {
3857 display: inline;
3850 display: inline;
3858 }
3851 }
3859
3852
3860 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons
3853 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons
3861 {
3854 {
3862 margin: 10px 0 0 200px;
3855 margin: 10px 0 0 200px;
3863 padding: 0;
3856 padding: 0;
3864 }
3857 }
3865
3858
3866 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons
3859 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons
3867 {
3860 {
3868 margin: 10px 0 0;
3861 margin: 10px 0 0;
3869 }
3862 }
3870
3863
3871 #content div.box table td.user,#content div.box table td.address {
3864 #content div.box table td.user,#content div.box table td.address {
3872 width: 10%;
3865 width: 10%;
3873 text-align: center;
3866 text-align: center;
3874 }
3867 }
3875
3868
3876 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link
3869 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link
3877 {
3870 {
3878 text-align: right;
3871 text-align: right;
3879 margin: 6px 0 0;
3872 margin: 6px 0 0;
3880 padding: 0;
3873 padding: 0;
3881 }
3874 }
3882
3875
3883 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover
3876 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover
3884 {
3877 {
3885 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3878 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3886 border-top: 1px solid #ccc;
3879 border-top: 1px solid #ccc;
3887 border-left: 1px solid #bebebe;
3880 border-left: 1px solid #bebebe;
3888 border-right: 1px solid #b1b1b1;
3881 border-right: 1px solid #b1b1b1;
3889 border-bottom: 1px solid #afafaf;
3882 border-bottom: 1px solid #afafaf;
3890 color: #515151;
3883 color: #515151;
3891 margin: 0;
3884 margin: 0;
3892 padding: 6px 12px;
3885 padding: 6px 12px;
3893 }
3886 }
3894
3887
3895 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results
3888 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results
3896 {
3889 {
3897 text-align: left;
3890 text-align: left;
3898 float: left;
3891 float: left;
3899 margin: 0;
3892 margin: 0;
3900 padding: 0;
3893 padding: 0;
3901 }
3894 }
3902
3895
3903 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span
3896 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span
3904 {
3897 {
3905 height: 1%;
3898 height: 1%;
3906 display: block;
3899 display: block;
3907 float: left;
3900 float: left;
3908 background: #ebebeb url("../images/pager.png") repeat-x;
3901 background: #ebebeb url("../images/pager.png") repeat-x;
3909 border-top: 1px solid #dedede;
3902 border-top: 1px solid #dedede;
3910 border-left: 1px solid #cfcfcf;
3903 border-left: 1px solid #cfcfcf;
3911 border-right: 1px solid #c4c4c4;
3904 border-right: 1px solid #c4c4c4;
3912 border-bottom: 1px solid #c4c4c4;
3905 border-bottom: 1px solid #c4c4c4;
3913 color: #4A4A4A;
3906 color: #4A4A4A;
3914 font-weight: 700;
3907 font-weight: 700;
3915 margin: 0;
3908 margin: 0;
3916 padding: 6px 8px;
3909 padding: 6px 8px;
3917 }
3910 }
3918
3911
3919 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled
3912 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled
3920 {
3913 {
3921 color: #B4B4B4;
3914 color: #B4B4B4;
3922 padding: 6px;
3915 padding: 6px;
3923 }
3916 }
3924
3917
3925 #login,#register {
3918 #login,#register {
3926 width: 520px;
3919 width: 520px;
3927 margin: 10% auto 0;
3920 margin: 10% auto 0;
3928 padding: 0;
3921 padding: 0;
3929 }
3922 }
3930
3923
3931 #login div.color,#register div.color {
3924 #login div.color,#register div.color {
3932 clear: both;
3925 clear: both;
3933 overflow: hidden;
3926 overflow: hidden;
3934 background: #FFF;
3927 background: #FFF;
3935 margin: 10px auto 0;
3928 margin: 10px auto 0;
3936 padding: 3px 3px 3px 0;
3929 padding: 3px 3px 3px 0;
3937 }
3930 }
3938
3931
3939 #login div.color a,#register div.color a {
3932 #login div.color a,#register div.color a {
3940 width: 20px;
3933 width: 20px;
3941 height: 20px;
3934 height: 20px;
3942 display: block;
3935 display: block;
3943 float: left;
3936 float: left;
3944 margin: 0 0 0 3px;
3937 margin: 0 0 0 3px;
3945 padding: 0;
3938 padding: 0;
3946 }
3939 }
3947
3940
3948 #login div.title h5,#register div.title h5 {
3941 #login div.title h5,#register div.title h5 {
3949 color: #fff;
3942 color: #fff;
3950 margin: 10px;
3943 margin: 10px;
3951 padding: 0;
3944 padding: 0;
3952 }
3945 }
3953
3946
3954 #login div.form div.fields div.field,#register div.form div.fields div.field
3947 #login div.form div.fields div.field,#register div.form div.fields div.field
3955 {
3948 {
3956 clear: both;
3949 clear: both;
3957 overflow: hidden;
3950 overflow: hidden;
3958 margin: 0;
3951 margin: 0;
3959 padding: 0 0 10px;
3952 padding: 0 0 10px;
3960 }
3953 }
3961
3954
3962 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message
3955 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message
3963 {
3956 {
3964 height: 1%;
3957 height: 1%;
3965 display: block;
3958 display: block;
3966 color: red;
3959 color: red;
3967 margin: 8px 0 0;
3960 margin: 8px 0 0;
3968 padding: 0;
3961 padding: 0;
3969 max-width: 320px;
3962 max-width: 320px;
3970 }
3963 }
3971
3964
3972 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label
3965 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label
3973 {
3966 {
3974 color: #000;
3967 color: #000;
3975 font-weight: 700;
3968 font-weight: 700;
3976 }
3969 }
3977
3970
3978 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
3971 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
3979 {
3972 {
3980 float: left;
3973 float: left;
3981 margin: 0;
3974 margin: 0;
3982 padding: 0;
3975 padding: 0;
3983 }
3976 }
3984
3977
3985 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
3978 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
3986 {
3979 {
3987 margin: 0 0 0 184px;
3980 margin: 0 0 0 184px;
3988 padding: 0;
3981 padding: 0;
3989 }
3982 }
3990
3983
3991 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
3984 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
3992 {
3985 {
3993 color: #565656;
3986 color: #565656;
3994 font-weight: 700;
3987 font-weight: 700;
3995 }
3988 }
3996
3989
3997 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
3990 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
3998 {
3991 {
3999 color: #000;
3992 color: #000;
4000 font-size: 1em;
3993 font-size: 1em;
4001 font-weight: 700;
3994 font-weight: 700;
4002 margin: 0;
3995 margin: 0;
4003 }
3996 }
4004
3997
4005 #changeset_content .container .wrapper,#graph_content .container .wrapper
3998 #changeset_content .container .wrapper,#graph_content .container .wrapper
4006 {
3999 {
4007 width: 600px;
4000 width: 600px;
4008 }
4001 }
4009
4002
4010 #changeset_content .container .left {
4003 #changeset_content .container .left {
4011 float: left;
4004 float: left;
4012 width: 75%;
4005 width: 75%;
4013 padding-left: 5px;
4006 padding-left: 5px;
4014 }
4007 }
4015
4008
4016 #changeset_content .container .left .date,.ac .match {
4009 #changeset_content .container .left .date,.ac .match {
4017 font-weight: 700;
4010 font-weight: 700;
4018 padding-top: 5px;
4011 padding-top: 5px;
4019 padding-bottom: 5px;
4012 padding-bottom: 5px;
4020 }
4013 }
4021
4014
4022 div#legend_container table td,div#legend_choices table td {
4015 div#legend_container table td,div#legend_choices table td {
4023 border: none !important;
4016 border: none !important;
4024 height: 20px !important;
4017 height: 20px !important;
4025 padding: 0 !important;
4018 padding: 0 !important;
4026 }
4019 }
4027
4020
4028 .q_filter_box {
4021 .q_filter_box {
4029 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4022 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4030 -webkit-border-radius: 4px;
4023 -webkit-border-radius: 4px;
4031 -moz-border-radius: 4px;
4024 -moz-border-radius: 4px;
4032 border-radius: 4px;
4025 border-radius: 4px;
4033 border: 0 none;
4026 border: 0 none;
4034 color: #AAAAAA;
4027 color: #AAAAAA;
4035 margin-bottom: -4px;
4028 margin-bottom: -4px;
4036 margin-top: -4px;
4029 margin-top: -4px;
4037 padding-left: 3px;
4030 padding-left: 3px;
4038 }
4031 }
4039
4032
4040 #node_filter {
4033 #node_filter {
4041 border: 0px solid #545454;
4034 border: 0px solid #545454;
4042 color: #AAAAAA;
4035 color: #AAAAAA;
4043 padding-left: 3px;
4036 padding-left: 3px;
4044 }
4037 }
4045
4038
4046
4039
4047 .group_members_wrap{
4040 .group_members_wrap{
4048 min-height: 85px;
4041 min-height: 85px;
4049 padding-left: 20px;
4042 padding-left: 20px;
4050 }
4043 }
4051
4044
4052 .group_members .group_member{
4045 .group_members .group_member{
4053 height: 30px;
4046 height: 30px;
4054 padding:0px 0px 0px 0px;
4047 padding:0px 0px 0px 0px;
4055 }
4048 }
4056
4049
4057 .reviewers_member{
4050 .reviewers_member{
4058 height: 15px;
4051 height: 15px;
4059 padding:0px 0px 0px 10px;
4052 padding:0px 0px 0px 10px;
4060 }
4053 }
4061
4054
4062 .emails_wrap{
4055 .emails_wrap{
4063 padding: 0px 20px;
4056 padding: 0px 20px;
4064 }
4057 }
4065
4058
4066 .emails_wrap .email_entry{
4059 .emails_wrap .email_entry{
4067 height: 30px;
4060 height: 30px;
4068 padding:0px 0px 0px 10px;
4061 padding:0px 0px 0px 10px;
4069 }
4062 }
4070 .emails_wrap .email_entry .email{
4063 .emails_wrap .email_entry .email{
4071 float: left
4064 float: left
4072 }
4065 }
4073 .emails_wrap .email_entry .email_action{
4066 .emails_wrap .email_entry .email_action{
4074 float: left
4067 float: left
4075 }
4068 }
4076
4069
4077 .ips_wrap{
4070 .ips_wrap{
4078 padding: 0px 20px;
4071 padding: 0px 20px;
4079 }
4072 }
4080
4073
4081 .ips_wrap .ip_entry{
4074 .ips_wrap .ip_entry{
4082 height: 30px;
4075 height: 30px;
4083 padding:0px 0px 0px 10px;
4076 padding:0px 0px 0px 10px;
4084 }
4077 }
4085 .ips_wrap .ip_entry .ip{
4078 .ips_wrap .ip_entry .ip{
4086 float: left
4079 float: left
4087 }
4080 }
4088 .ips_wrap .ip_entry .ip_action{
4081 .ips_wrap .ip_entry .ip_action{
4089 float: left
4082 float: left
4090 }
4083 }
4091
4084
4092
4085
4093 /*README STYLE*/
4086 /*README STYLE*/
4094
4087
4095 div.readme {
4088 div.readme {
4096 padding:0px;
4089 padding:0px;
4097 }
4090 }
4098
4091
4099 div.readme h2 {
4092 div.readme h2 {
4100 font-weight: normal;
4093 font-weight: normal;
4101 }
4094 }
4102
4095
4103 div.readme .readme_box {
4096 div.readme .readme_box {
4104 background-color: #fafafa;
4097 background-color: #fafafa;
4105 }
4098 }
4106
4099
4107 div.readme .readme_box {
4100 div.readme .readme_box {
4108 clear:both;
4101 clear:both;
4109 overflow:hidden;
4102 overflow:hidden;
4110 margin:0;
4103 margin:0;
4111 padding:0 20px 10px;
4104 padding:0 20px 10px;
4112 }
4105 }
4113
4106
4114 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4107 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4115 border-bottom: 0 !important;
4108 border-bottom: 0 !important;
4116 margin: 0 !important;
4109 margin: 0 !important;
4117 padding: 0 !important;
4110 padding: 0 !important;
4118 line-height: 1.5em !important;
4111 line-height: 1.5em !important;
4119 }
4112 }
4120
4113
4121
4114
4122 div.readme .readme_box h1:first-child {
4115 div.readme .readme_box h1:first-child {
4123 padding-top: .25em !important;
4116 padding-top: .25em !important;
4124 }
4117 }
4125
4118
4126 div.readme .readme_box h2, div.readme .readme_box h3 {
4119 div.readme .readme_box h2, div.readme .readme_box h3 {
4127 margin: 1em 0 !important;
4120 margin: 1em 0 !important;
4128 }
4121 }
4129
4122
4130 div.readme .readme_box h2 {
4123 div.readme .readme_box h2 {
4131 margin-top: 1.5em !important;
4124 margin-top: 1.5em !important;
4132 border-top: 4px solid #e0e0e0 !important;
4125 border-top: 4px solid #e0e0e0 !important;
4133 padding-top: .5em !important;
4126 padding-top: .5em !important;
4134 }
4127 }
4135
4128
4136 div.readme .readme_box p {
4129 div.readme .readme_box p {
4137 color: black !important;
4130 color: black !important;
4138 margin: 1em 0 !important;
4131 margin: 1em 0 !important;
4139 line-height: 1.5em !important;
4132 line-height: 1.5em !important;
4140 }
4133 }
4141
4134
4142 div.readme .readme_box ul {
4135 div.readme .readme_box ul {
4143 list-style: disc !important;
4136 list-style: disc !important;
4144 margin: 1em 0 1em 2em !important;
4137 margin: 1em 0 1em 2em !important;
4145 }
4138 }
4146
4139
4147 div.readme .readme_box ol {
4140 div.readme .readme_box ol {
4148 list-style: decimal;
4141 list-style: decimal;
4149 margin: 1em 0 1em 2em !important;
4142 margin: 1em 0 1em 2em !important;
4150 }
4143 }
4151
4144
4152 div.readme .readme_box pre, code {
4145 div.readme .readme_box pre, code {
4153 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4146 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4154 }
4147 }
4155
4148
4156 div.readme .readme_box code {
4149 div.readme .readme_box code {
4157 font-size: 12px !important;
4150 font-size: 12px !important;
4158 background-color: ghostWhite !important;
4151 background-color: ghostWhite !important;
4159 color: #444 !important;
4152 color: #444 !important;
4160 padding: 0 .2em !important;
4153 padding: 0 .2em !important;
4161 border: 1px solid #dedede !important;
4154 border: 1px solid #dedede !important;
4162 }
4155 }
4163
4156
4164 div.readme .readme_box pre code {
4157 div.readme .readme_box pre code {
4165 padding: 0 !important;
4158 padding: 0 !important;
4166 font-size: 12px !important;
4159 font-size: 12px !important;
4167 background-color: #eee !important;
4160 background-color: #eee !important;
4168 border: none !important;
4161 border: none !important;
4169 }
4162 }
4170
4163
4171 div.readme .readme_box pre {
4164 div.readme .readme_box pre {
4172 margin: 1em 0;
4165 margin: 1em 0;
4173 font-size: 12px;
4166 font-size: 12px;
4174 background-color: #eee;
4167 background-color: #eee;
4175 border: 1px solid #ddd;
4168 border: 1px solid #ddd;
4176 padding: 5px;
4169 padding: 5px;
4177 color: #444;
4170 color: #444;
4178 overflow: auto;
4171 overflow: auto;
4179 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4172 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4180 -webkit-border-radius: 3px;
4173 -webkit-border-radius: 3px;
4181 -moz-border-radius: 3px;
4174 -moz-border-radius: 3px;
4182 border-radius: 3px;
4175 border-radius: 3px;
4183 }
4176 }
4184
4177
4185 div.readme .readme_box table {
4178 div.readme .readme_box table {
4186 display: table;
4179 display: table;
4187 border-collapse: separate;
4180 border-collapse: separate;
4188 border-spacing: 2px;
4181 border-spacing: 2px;
4189 border-color: gray;
4182 border-color: gray;
4190 width: auto !important;
4183 width: auto !important;
4191 }
4184 }
4192
4185
4193
4186
4194 /** RST STYLE **/
4187 /** RST STYLE **/
4195
4188
4196
4189
4197 div.rst-block {
4190 div.rst-block {
4198 padding:0px;
4191 padding:0px;
4199 }
4192 }
4200
4193
4201 div.rst-block h2 {
4194 div.rst-block h2 {
4202 font-weight: normal;
4195 font-weight: normal;
4203 }
4196 }
4204
4197
4205 div.rst-block {
4198 div.rst-block {
4206 background-color: #fafafa;
4199 background-color: #fafafa;
4207 }
4200 }
4208
4201
4209 div.rst-block {
4202 div.rst-block {
4210 clear:both;
4203 clear:both;
4211 overflow:hidden;
4204 overflow:hidden;
4212 margin:0;
4205 margin:0;
4213 padding:0 20px 10px;
4206 padding:0 20px 10px;
4214 }
4207 }
4215
4208
4216 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4209 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4217 border-bottom: 0 !important;
4210 border-bottom: 0 !important;
4218 margin: 0 !important;
4211 margin: 0 !important;
4219 padding: 0 !important;
4212 padding: 0 !important;
4220 line-height: 1.5em !important;
4213 line-height: 1.5em !important;
4221 }
4214 }
4222
4215
4223
4216
4224 div.rst-block h1:first-child {
4217 div.rst-block h1:first-child {
4225 padding-top: .25em !important;
4218 padding-top: .25em !important;
4226 }
4219 }
4227
4220
4228 div.rst-block h2, div.rst-block h3 {
4221 div.rst-block h2, div.rst-block h3 {
4229 margin: 1em 0 !important;
4222 margin: 1em 0 !important;
4230 }
4223 }
4231
4224
4232 div.rst-block h2 {
4225 div.rst-block h2 {
4233 margin-top: 1.5em !important;
4226 margin-top: 1.5em !important;
4234 border-top: 4px solid #e0e0e0 !important;
4227 border-top: 4px solid #e0e0e0 !important;
4235 padding-top: .5em !important;
4228 padding-top: .5em !important;
4236 }
4229 }
4237
4230
4238 div.rst-block p {
4231 div.rst-block p {
4239 color: black !important;
4232 color: black !important;
4240 margin: 1em 0 !important;
4233 margin: 1em 0 !important;
4241 line-height: 1.5em !important;
4234 line-height: 1.5em !important;
4242 }
4235 }
4243
4236
4244 div.rst-block ul {
4237 div.rst-block ul {
4245 list-style: disc !important;
4238 list-style: disc !important;
4246 margin: 1em 0 1em 2em !important;
4239 margin: 1em 0 1em 2em !important;
4247 }
4240 }
4248
4241
4249 div.rst-block ol {
4242 div.rst-block ol {
4250 list-style: decimal;
4243 list-style: decimal;
4251 margin: 1em 0 1em 2em !important;
4244 margin: 1em 0 1em 2em !important;
4252 }
4245 }
4253
4246
4254 div.rst-block pre, code {
4247 div.rst-block pre, code {
4255 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4248 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4256 }
4249 }
4257
4250
4258 div.rst-block code {
4251 div.rst-block code {
4259 font-size: 12px !important;
4252 font-size: 12px !important;
4260 background-color: ghostWhite !important;
4253 background-color: ghostWhite !important;
4261 color: #444 !important;
4254 color: #444 !important;
4262 padding: 0 .2em !important;
4255 padding: 0 .2em !important;
4263 border: 1px solid #dedede !important;
4256 border: 1px solid #dedede !important;
4264 }
4257 }
4265
4258
4266 div.rst-block pre code {
4259 div.rst-block pre code {
4267 padding: 0 !important;
4260 padding: 0 !important;
4268 font-size: 12px !important;
4261 font-size: 12px !important;
4269 background-color: #eee !important;
4262 background-color: #eee !important;
4270 border: none !important;
4263 border: none !important;
4271 }
4264 }
4272
4265
4273 div.rst-block pre {
4266 div.rst-block pre {
4274 margin: 1em 0;
4267 margin: 1em 0;
4275 font-size: 12px;
4268 font-size: 12px;
4276 background-color: #eee;
4269 background-color: #eee;
4277 border: 1px solid #ddd;
4270 border: 1px solid #ddd;
4278 padding: 5px;
4271 padding: 5px;
4279 color: #444;
4272 color: #444;
4280 overflow: auto;
4273 overflow: auto;
4281 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4274 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4282 -webkit-border-radius: 3px;
4275 -webkit-border-radius: 3px;
4283 -moz-border-radius: 3px;
4276 -moz-border-radius: 3px;
4284 border-radius: 3px;
4277 border-radius: 3px;
4285 }
4278 }
4286
4279
4287
4280
4288 /** comment main **/
4281 /** comment main **/
4289 .comments {
4282 .comments {
4290 padding:10px 20px;
4283 padding:10px 20px;
4291 }
4284 }
4292
4285
4293 .comments .comment {
4286 .comments .comment {
4294 border: 1px solid #ddd;
4287 border: 1px solid #ddd;
4295 margin-top: 10px;
4288 margin-top: 10px;
4296 -webkit-border-radius: 4px;
4289 -webkit-border-radius: 4px;
4297 -moz-border-radius: 4px;
4290 -moz-border-radius: 4px;
4298 border-radius: 4px;
4291 border-radius: 4px;
4299 }
4292 }
4300
4293
4301 .comments .comment .meta {
4294 .comments .comment .meta {
4302 background: #f8f8f8;
4295 background: #f8f8f8;
4303 padding: 4px;
4296 padding: 4px;
4304 border-bottom: 1px solid #ddd;
4297 border-bottom: 1px solid #ddd;
4305 height: 18px;
4298 height: 18px;
4306 }
4299 }
4307
4300
4308 .comments .comment .meta img {
4301 .comments .comment .meta img {
4309 vertical-align: middle;
4302 vertical-align: middle;
4310 }
4303 }
4311
4304
4312 .comments .comment .meta .user {
4305 .comments .comment .meta .user {
4313 font-weight: bold;
4306 font-weight: bold;
4314 float: left;
4307 float: left;
4315 padding: 4px 2px 2px 2px;
4308 padding: 4px 2px 2px 2px;
4316 }
4309 }
4317
4310
4318 .comments .comment .meta .date {
4311 .comments .comment .meta .date {
4319 float: left;
4312 float: left;
4320 padding:4px 4px 0px 4px;
4313 padding:4px 4px 0px 4px;
4321 }
4314 }
4322
4315
4323 .comments .comment .text {
4316 .comments .comment .text {
4324 background-color: #FAFAFA;
4317 background-color: #FAFAFA;
4325 }
4318 }
4326 .comment .text div.rst-block p {
4319 .comment .text div.rst-block p {
4327 margin: 0.5em 0px !important;
4320 margin: 0.5em 0px !important;
4328 }
4321 }
4329
4322
4330 .comments .comments-number{
4323 .comments .comments-number{
4331 padding:0px 0px 10px 0px;
4324 padding:0px 0px 10px 0px;
4332 font-weight: bold;
4325 font-weight: bold;
4333 color: #666;
4326 color: #666;
4334 font-size: 16px;
4327 font-size: 16px;
4335 }
4328 }
4336
4329
4337 /** comment form **/
4330 /** comment form **/
4338
4331
4339 .status-block{
4332 .status-block{
4340 height:80px;
4333 height:80px;
4341 clear:both
4334 clear:both
4342 }
4335 }
4343
4336
4344 .comment-form .clearfix{
4337 .comment-form .clearfix{
4345 background: #EEE;
4338 background: #EEE;
4346 -webkit-border-radius: 4px;
4339 -webkit-border-radius: 4px;
4347 -moz-border-radius: 4px;
4340 -moz-border-radius: 4px;
4348 border-radius: 4px;
4341 border-radius: 4px;
4349 padding: 10px;
4342 padding: 10px;
4350 }
4343 }
4351
4344
4352 div.comment-form {
4345 div.comment-form {
4353 margin-top: 20px;
4346 margin-top: 20px;
4354 }
4347 }
4355
4348
4356 .comment-form strong {
4349 .comment-form strong {
4357 display: block;
4350 display: block;
4358 margin-bottom: 15px;
4351 margin-bottom: 15px;
4359 }
4352 }
4360
4353
4361 .comment-form textarea {
4354 .comment-form textarea {
4362 width: 100%;
4355 width: 100%;
4363 height: 100px;
4356 height: 100px;
4364 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4357 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4365 }
4358 }
4366
4359
4367 form.comment-form {
4360 form.comment-form {
4368 margin-top: 10px;
4361 margin-top: 10px;
4369 margin-left: 10px;
4362 margin-left: 10px;
4370 }
4363 }
4371
4364
4372 .comment-form-submit {
4365 .comment-form-submit {
4373 margin-top: 5px;
4366 margin-top: 5px;
4374 margin-left: 525px;
4367 margin-left: 525px;
4375 }
4368 }
4376
4369
4377 .file-comments {
4370 .file-comments {
4378 display: none;
4371 display: none;
4379 }
4372 }
4380
4373
4381 .comment-form .comment {
4374 .comment-form .comment {
4382 margin-left: 10px;
4375 margin-left: 10px;
4383 }
4376 }
4384
4377
4385 .comment-form .comment-help{
4378 .comment-form .comment-help{
4386 padding: 0px 0px 5px 0px;
4379 padding: 0px 0px 5px 0px;
4387 color: #666;
4380 color: #666;
4388 }
4381 }
4389
4382
4390 .comment-form .comment-button{
4383 .comment-form .comment-button{
4391 padding-top:5px;
4384 padding-top:5px;
4392 }
4385 }
4393
4386
4394 .add-another-button {
4387 .add-another-button {
4395 margin-left: 10px;
4388 margin-left: 10px;
4396 margin-top: 10px;
4389 margin-top: 10px;
4397 margin-bottom: 10px;
4390 margin-bottom: 10px;
4398 }
4391 }
4399
4392
4400 .comment .buttons {
4393 .comment .buttons {
4401 float: right;
4394 float: right;
4402 padding:2px 2px 0px 0px;
4395 padding:2px 2px 0px 0px;
4403 }
4396 }
4404
4397
4405
4398
4406 .show-inline-comments{
4399 .show-inline-comments{
4407 position: relative;
4400 position: relative;
4408 top:1px
4401 top:1px
4409 }
4402 }
4410
4403
4411 /** comment inline form **/
4404 /** comment inline form **/
4412 .comment-inline-form .overlay{
4405 .comment-inline-form .overlay{
4413 display: none;
4406 display: none;
4414 }
4407 }
4415 .comment-inline-form .overlay.submitting{
4408 .comment-inline-form .overlay.submitting{
4416 display:block;
4409 display:block;
4417 background: none repeat scroll 0 0 white;
4410 background: none repeat scroll 0 0 white;
4418 font-size: 16px;
4411 font-size: 16px;
4419 opacity: 0.5;
4412 opacity: 0.5;
4420 position: absolute;
4413 position: absolute;
4421 text-align: center;
4414 text-align: center;
4422 vertical-align: top;
4415 vertical-align: top;
4423
4416
4424 }
4417 }
4425 .comment-inline-form .overlay.submitting .overlay-text{
4418 .comment-inline-form .overlay.submitting .overlay-text{
4426 width:100%;
4419 width:100%;
4427 margin-top:5%;
4420 margin-top:5%;
4428 }
4421 }
4429
4422
4430 .comment-inline-form .clearfix{
4423 .comment-inline-form .clearfix{
4431 background: #EEE;
4424 background: #EEE;
4432 -webkit-border-radius: 4px;
4425 -webkit-border-radius: 4px;
4433 -moz-border-radius: 4px;
4426 -moz-border-radius: 4px;
4434 border-radius: 4px;
4427 border-radius: 4px;
4435 padding: 5px;
4428 padding: 5px;
4436 }
4429 }
4437
4430
4438 div.comment-inline-form {
4431 div.comment-inline-form {
4439 padding:4px 0px 6px 0px;
4432 padding:4px 0px 6px 0px;
4440 }
4433 }
4441
4434
4442
4435
4443 tr.hl-comment{
4436 tr.hl-comment{
4444 /*
4437 /*
4445 background-color: #FFFFCC !important;
4438 background-color: #FFFFCC !important;
4446 */
4439 */
4447 }
4440 }
4448
4441
4449 /*
4442 /*
4450 tr.hl-comment pre {
4443 tr.hl-comment pre {
4451 border-top: 2px solid #FFEE33;
4444 border-top: 2px solid #FFEE33;
4452 border-left: 2px solid #FFEE33;
4445 border-left: 2px solid #FFEE33;
4453 border-right: 2px solid #FFEE33;
4446 border-right: 2px solid #FFEE33;
4454 }
4447 }
4455 */
4448 */
4456
4449
4457 .comment-inline-form strong {
4450 .comment-inline-form strong {
4458 display: block;
4451 display: block;
4459 margin-bottom: 15px;
4452 margin-bottom: 15px;
4460 }
4453 }
4461
4454
4462 .comment-inline-form textarea {
4455 .comment-inline-form textarea {
4463 width: 100%;
4456 width: 100%;
4464 height: 100px;
4457 height: 100px;
4465 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4458 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4466 }
4459 }
4467
4460
4468 form.comment-inline-form {
4461 form.comment-inline-form {
4469 margin-top: 10px;
4462 margin-top: 10px;
4470 margin-left: 10px;
4463 margin-left: 10px;
4471 }
4464 }
4472
4465
4473 .comment-inline-form-submit {
4466 .comment-inline-form-submit {
4474 margin-top: 5px;
4467 margin-top: 5px;
4475 margin-left: 525px;
4468 margin-left: 525px;
4476 }
4469 }
4477
4470
4478 .file-comments {
4471 .file-comments {
4479 display: none;
4472 display: none;
4480 }
4473 }
4481
4474
4482 .comment-inline-form .comment {
4475 .comment-inline-form .comment {
4483 margin-left: 10px;
4476 margin-left: 10px;
4484 }
4477 }
4485
4478
4486 .comment-inline-form .comment-help{
4479 .comment-inline-form .comment-help{
4487 padding: 0px 0px 2px 0px;
4480 padding: 0px 0px 2px 0px;
4488 color: #666666;
4481 color: #666666;
4489 font-size: 10px;
4482 font-size: 10px;
4490 }
4483 }
4491
4484
4492 .comment-inline-form .comment-button{
4485 .comment-inline-form .comment-button{
4493 padding-top:5px;
4486 padding-top:5px;
4494 }
4487 }
4495
4488
4496 /** comment inline **/
4489 /** comment inline **/
4497 .inline-comments {
4490 .inline-comments {
4498 padding:10px 20px;
4491 padding:10px 20px;
4499 }
4492 }
4500
4493
4501 .inline-comments div.rst-block {
4494 .inline-comments div.rst-block {
4502 clear:both;
4495 clear:both;
4503 overflow:hidden;
4496 overflow:hidden;
4504 margin:0;
4497 margin:0;
4505 padding:0 20px 0px;
4498 padding:0 20px 0px;
4506 }
4499 }
4507 .inline-comments .comment {
4500 .inline-comments .comment {
4508 border: 1px solid #ddd;
4501 border: 1px solid #ddd;
4509 -webkit-border-radius: 4px;
4502 -webkit-border-radius: 4px;
4510 -moz-border-radius: 4px;
4503 -moz-border-radius: 4px;
4511 border-radius: 4px;
4504 border-radius: 4px;
4512 margin: 3px 3px 5px 5px;
4505 margin: 3px 3px 5px 5px;
4513 background-color: #FAFAFA;
4506 background-color: #FAFAFA;
4514 }
4507 }
4515 .inline-comments .add-comment {
4508 .inline-comments .add-comment {
4516 padding: 2px 4px 8px 5px;
4509 padding: 2px 4px 8px 5px;
4517 }
4510 }
4518
4511
4519 .inline-comments .comment-wrapp{
4512 .inline-comments .comment-wrapp{
4520 padding:1px;
4513 padding:1px;
4521 }
4514 }
4522 .inline-comments .comment .meta {
4515 .inline-comments .comment .meta {
4523 background: #f8f8f8;
4516 background: #f8f8f8;
4524 padding: 4px;
4517 padding: 4px;
4525 border-bottom: 1px solid #ddd;
4518 border-bottom: 1px solid #ddd;
4526 height: 20px;
4519 height: 20px;
4527 }
4520 }
4528
4521
4529 .inline-comments .comment .meta img {
4522 .inline-comments .comment .meta img {
4530 vertical-align: middle;
4523 vertical-align: middle;
4531 }
4524 }
4532
4525
4533 .inline-comments .comment .meta .user {
4526 .inline-comments .comment .meta .user {
4534 font-weight: bold;
4527 font-weight: bold;
4535 float:left;
4528 float:left;
4536 padding: 3px;
4529 padding: 3px;
4537 }
4530 }
4538
4531
4539 .inline-comments .comment .meta .date {
4532 .inline-comments .comment .meta .date {
4540 float:left;
4533 float:left;
4541 padding: 3px;
4534 padding: 3px;
4542 }
4535 }
4543
4536
4544 .inline-comments .comment .text {
4537 .inline-comments .comment .text {
4545 background-color: #FAFAFA;
4538 background-color: #FAFAFA;
4546 }
4539 }
4547
4540
4548 .inline-comments .comments-number{
4541 .inline-comments .comments-number{
4549 padding:0px 0px 10px 0px;
4542 padding:0px 0px 10px 0px;
4550 font-weight: bold;
4543 font-weight: bold;
4551 color: #666;
4544 color: #666;
4552 font-size: 16px;
4545 font-size: 16px;
4553 }
4546 }
4554 .inline-comments-button .add-comment{
4547 .inline-comments-button .add-comment{
4555 margin:2px 0px 8px 5px !important
4548 margin:2px 0px 8px 5px !important
4556 }
4549 }
4557
4550
4558
4551
4559 .notification-paginator{
4552 .notification-paginator{
4560 padding: 0px 0px 4px 16px;
4553 padding: 0px 0px 4px 16px;
4561 float: left;
4554 float: left;
4562 }
4555 }
4563
4556
4564 .menu_link_user{
4557 .menu_link_user{
4565 padding: 10px 8px 8px 8px !important;
4558 padding: 10px 8px 8px 8px !important;
4566 }
4559 }
4567
4560
4568 .menu_link_notifications {
4561 .menu_link_notifications {
4569 padding: 4px 4px !important;
4562 padding: 4px 4px !important;
4570 margin: 7px 4px 0px 0px !important;
4563 margin: 7px 4px 0px 0px !important;
4571 text-align: center;
4564 text-align: center;
4572 color:#888 !important;
4565 color:#888 !important;
4573 font-size: 10px;
4566 font-size: 10px;
4574 background-color: #DEDEDE !important;
4567 background-color: #DEDEDE !important;
4575 border-radius: 4px !important;
4568 border-radius: 4px !important;
4576 -webkit-border-radius: 4px !important;
4569 -webkit-border-radius: 4px !important;
4577 -moz-border-radius: 4px !important;
4570 -moz-border-radius: 4px !important;
4578 }
4571 }
4579
4572
4580 .notification-header{
4573 .notification-header{
4581 padding-top:6px;
4574 padding-top:6px;
4582 }
4575 }
4583 .notification-header .desc{
4576 .notification-header .desc{
4584 font-size: 16px;
4577 font-size: 16px;
4585 height: 24px;
4578 height: 24px;
4586 float: left
4579 float: left
4587 }
4580 }
4588 .notification-list .container.unread{
4581 .notification-list .container.unread{
4589 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4582 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4590 }
4583 }
4591 .notification-header .gravatar{
4584 .notification-header .gravatar{
4592 background: none repeat scroll 0 0 transparent;
4585 background: none repeat scroll 0 0 transparent;
4593 padding: 0px 0px 0px 8px;
4586 padding: 0px 0px 0px 8px;
4594 }
4587 }
4595 .notification-list .container .notification-header .desc{
4588 .notification-list .container .notification-header .desc{
4596 font-weight: bold;
4589 font-weight: bold;
4597 font-size: 17px;
4590 font-size: 17px;
4598 }
4591 }
4599 .notification-table{
4592 .notification-table{
4600 border: 1px solid #ccc;
4593 border: 1px solid #ccc;
4601 -webkit-border-radius: 6px 6px 6px 6px;
4594 -webkit-border-radius: 6px 6px 6px 6px;
4602 -moz-border-radius: 6px 6px 6px 6px;
4595 -moz-border-radius: 6px 6px 6px 6px;
4603 border-radius: 6px 6px 6px 6px;
4596 border-radius: 6px 6px 6px 6px;
4604 clear: both;
4597 clear: both;
4605 margin: 0px 20px 0px 20px;
4598 margin: 0px 20px 0px 20px;
4606 }
4599 }
4607 .notification-header .delete-notifications{
4600 .notification-header .delete-notifications{
4608 float: right;
4601 float: right;
4609 padding-top: 8px;
4602 padding-top: 8px;
4610 cursor: pointer;
4603 cursor: pointer;
4611 }
4604 }
4612 .notification-header .read-notifications{
4605 .notification-header .read-notifications{
4613 float: right;
4606 float: right;
4614 padding-top: 8px;
4607 padding-top: 8px;
4615 cursor: pointer;
4608 cursor: pointer;
4616 }
4609 }
4617 .notification-subject{
4610 .notification-subject{
4618 clear:both;
4611 clear:both;
4619 border-bottom: 1px solid #eee;
4612 border-bottom: 1px solid #eee;
4620 padding:5px 0px 5px 38px;
4613 padding:5px 0px 5px 38px;
4621 }
4614 }
4622
4615
4623 .notification-body{
4616 .notification-body{
4624 clear:both;
4617 clear:both;
4625 margin: 34px 2px 2px 8px
4618 margin: 34px 2px 2px 8px
4626 }
4619 }
4627
4620
4628 /****
4621 /****
4629 PULL REQUESTS
4622 PULL REQUESTS
4630 *****/
4623 *****/
4631 .pullrequests_section_head {
4624 .pullrequests_section_head {
4632 padding:10px 10px 10px 0px;
4625 padding:10px 10px 10px 0px;
4633 font-size:16px;
4626 font-size:16px;
4634 font-weight: bold;
4627 font-weight: bold;
4635 }
4628 }
4636
4629
4637 /****
4630 /****
4638 PERMS
4631 PERMS
4639 *****/
4632 *****/
4640 #perms .perms_section_head {
4633 #perms .perms_section_head {
4641 padding:10px 10px 10px 0px;
4634 padding:10px 10px 10px 0px;
4642 font-size:16px;
4635 font-size:16px;
4643 font-weight: bold;
4636 font-weight: bold;
4644 }
4637 }
4645
4638
4646 #perms .perm_tag{
4639 #perms .perm_tag{
4647 padding: 1px 3px 1px 3px;
4640 padding: 1px 3px 1px 3px;
4648 font-size: 10px;
4641 font-size: 10px;
4649 font-weight: bold;
4642 font-weight: bold;
4650 text-transform: uppercase;
4643 text-transform: uppercase;
4651 white-space: nowrap;
4644 white-space: nowrap;
4652 -webkit-border-radius: 3px;
4645 -webkit-border-radius: 3px;
4653 -moz-border-radius: 3px;
4646 -moz-border-radius: 3px;
4654 border-radius: 3px;
4647 border-radius: 3px;
4655 }
4648 }
4656
4649
4657 #perms .perm_tag.admin{
4650 #perms .perm_tag.admin{
4658 background-color: #B94A48;
4651 background-color: #B94A48;
4659 color: #ffffff;
4652 color: #ffffff;
4660 }
4653 }
4661
4654
4662 #perms .perm_tag.write{
4655 #perms .perm_tag.write{
4663 background-color: #DB7525;
4656 background-color: #DB7525;
4664 color: #ffffff;
4657 color: #ffffff;
4665 }
4658 }
4666
4659
4667 #perms .perm_tag.read{
4660 #perms .perm_tag.read{
4668 background-color: #468847;
4661 background-color: #468847;
4669 color: #ffffff;
4662 color: #ffffff;
4670 }
4663 }
4671
4664
4672 #perms .perm_tag.none{
4665 #perms .perm_tag.none{
4673 background-color: #bfbfbf;
4666 background-color: #bfbfbf;
4674 color: #ffffff;
4667 color: #ffffff;
4675 }
4668 }
4676
4669
4677 .perm-gravatar{
4670 .perm-gravatar{
4678 vertical-align:middle;
4671 vertical-align:middle;
4679 padding:2px;
4672 padding:2px;
4680 }
4673 }
4681 .perm-gravatar-ac{
4674 .perm-gravatar-ac{
4682 vertical-align:middle;
4675 vertical-align:middle;
4683 padding:2px;
4676 padding:2px;
4684 width: 14px;
4677 width: 14px;
4685 height: 14px;
4678 height: 14px;
4686 }
4679 }
4687
4680
4688 /*****************************************************************************
4681 /*****************************************************************************
4689 DIFFS CSS
4682 DIFFS CSS
4690 ******************************************************************************/
4683 ******************************************************************************/
4691
4684
4692 div.diffblock {
4685 div.diffblock {
4693 overflow: auto;
4686 overflow: auto;
4694 padding: 0px;
4687 padding: 0px;
4695 border: 1px solid #ccc;
4688 border: 1px solid #ccc;
4696 background: #f8f8f8;
4689 background: #f8f8f8;
4697 font-size: 100%;
4690 font-size: 100%;
4698 line-height: 100%;
4691 line-height: 100%;
4699 /* new */
4692 /* new */
4700 line-height: 125%;
4693 line-height: 125%;
4701 -webkit-border-radius: 6px 6px 0px 0px;
4694 -webkit-border-radius: 6px 6px 0px 0px;
4702 -moz-border-radius: 6px 6px 0px 0px;
4695 -moz-border-radius: 6px 6px 0px 0px;
4703 border-radius: 6px 6px 0px 0px;
4696 border-radius: 6px 6px 0px 0px;
4704 }
4697 }
4705 div.diffblock.margined{
4698 div.diffblock.margined{
4706 margin: 0px 20px 0px 20px;
4699 margin: 0px 20px 0px 20px;
4707 }
4700 }
4708 div.diffblock .code-header{
4701 div.diffblock .code-header{
4709 border-bottom: 1px solid #CCCCCC;
4702 border-bottom: 1px solid #CCCCCC;
4710 background: #EEEEEE;
4703 background: #EEEEEE;
4711 padding:10px 0 10px 0;
4704 padding:10px 0 10px 0;
4712 height: 14px;
4705 height: 14px;
4713 }
4706 }
4714
4707
4715 div.diffblock .code-header.banner{
4708 div.diffblock .code-header.banner{
4716 border-bottom: 1px solid #CCCCCC;
4709 border-bottom: 1px solid #CCCCCC;
4717 background: #EEEEEE;
4710 background: #EEEEEE;
4718 height: 14px;
4711 height: 14px;
4719 margin: 0px 95px 0px 95px;
4712 margin: 0px 95px 0px 95px;
4720 padding: 3px 3px 11px 3px;
4713 padding: 3px 3px 11px 3px;
4721 }
4714 }
4722
4715
4723 div.diffblock .code-header.cv{
4716 div.diffblock .code-header.cv{
4724 height: 34px;
4717 height: 34px;
4725 }
4718 }
4726 div.diffblock .code-header-title{
4719 div.diffblock .code-header-title{
4727 padding: 0px 0px 10px 5px !important;
4720 padding: 0px 0px 10px 5px !important;
4728 margin: 0 !important;
4721 margin: 0 !important;
4729 }
4722 }
4730 div.diffblock .code-header .hash{
4723 div.diffblock .code-header .hash{
4731 float: left;
4724 float: left;
4732 padding: 2px 0 0 2px;
4725 padding: 2px 0 0 2px;
4733 }
4726 }
4734 div.diffblock .code-header .date{
4727 div.diffblock .code-header .date{
4735 float:left;
4728 float:left;
4736 text-transform: uppercase;
4729 text-transform: uppercase;
4737 padding: 2px 0px 0px 2px;
4730 padding: 2px 0px 0px 2px;
4738 }
4731 }
4739 div.diffblock .code-header div{
4732 div.diffblock .code-header div{
4740 margin-left:4px;
4733 margin-left:4px;
4741 font-weight: bold;
4734 font-weight: bold;
4742 font-size: 14px;
4735 font-size: 14px;
4743 }
4736 }
4744
4737
4745 div.diffblock .parents {
4738 div.diffblock .parents {
4746 float: left;
4739 float: left;
4747 height: 26px;
4740 height: 26px;
4748 width:100px;
4741 width:100px;
4749 font-size: 10px;
4742 font-size: 10px;
4750 font-weight: 400;
4743 font-weight: 400;
4751 vertical-align: middle;
4744 vertical-align: middle;
4752 padding: 0px 2px 2px 2px;
4745 padding: 0px 2px 2px 2px;
4753 background-color:#eeeeee;
4746 background-color:#eeeeee;
4754 border-bottom: 1px solid #CCCCCC;
4747 border-bottom: 1px solid #CCCCCC;
4755 }
4748 }
4756
4749
4757 div.diffblock .children {
4750 div.diffblock .children {
4758 float: right;
4751 float: right;
4759 height: 26px;
4752 height: 26px;
4760 width:100px;
4753 width:100px;
4761 font-size: 10px;
4754 font-size: 10px;
4762 font-weight: 400;
4755 font-weight: 400;
4763 vertical-align: middle;
4756 vertical-align: middle;
4764 text-align: right;
4757 text-align: right;
4765 padding: 0px 2px 2px 2px;
4758 padding: 0px 2px 2px 2px;
4766 background-color:#eeeeee;
4759 background-color:#eeeeee;
4767 border-bottom: 1px solid #CCCCCC;
4760 border-bottom: 1px solid #CCCCCC;
4768 }
4761 }
4769
4762
4770 div.diffblock .code-body{
4763 div.diffblock .code-body{
4771 background: #FFFFFF;
4764 background: #FFFFFF;
4772 }
4765 }
4773 div.diffblock pre.raw{
4766 div.diffblock pre.raw{
4774 background: #FFFFFF;
4767 background: #FFFFFF;
4775 color:#000000;
4768 color:#000000;
4776 }
4769 }
4777 table.code-difftable{
4770 table.code-difftable{
4778 border-collapse: collapse;
4771 border-collapse: collapse;
4779 width: 99%;
4772 width: 99%;
4780 }
4773 }
4781 table.code-difftable td {
4774 table.code-difftable td {
4782 padding: 0 !important;
4775 padding: 0 !important;
4783 background: none !important;
4776 background: none !important;
4784 border:0 !important;
4777 border:0 !important;
4785 vertical-align: none !important;
4778 vertical-align: none !important;
4786 }
4779 }
4787 table.code-difftable .context{
4780 table.code-difftable .context{
4788 background:none repeat scroll 0 0 #DDE7EF;
4781 background:none repeat scroll 0 0 #DDE7EF;
4789 }
4782 }
4790 table.code-difftable .add{
4783 table.code-difftable .add{
4791 background:none repeat scroll 0 0 #DDFFDD;
4784 background:none repeat scroll 0 0 #DDFFDD;
4792 }
4785 }
4793 table.code-difftable .add ins{
4786 table.code-difftable .add ins{
4794 background:none repeat scroll 0 0 #AAFFAA;
4787 background:none repeat scroll 0 0 #AAFFAA;
4795 text-decoration:none;
4788 text-decoration:none;
4796 }
4789 }
4797 table.code-difftable .del{
4790 table.code-difftable .del{
4798 background:none repeat scroll 0 0 #FFDDDD;
4791 background:none repeat scroll 0 0 #FFDDDD;
4799 }
4792 }
4800 table.code-difftable .del del{
4793 table.code-difftable .del del{
4801 background:none repeat scroll 0 0 #FFAAAA;
4794 background:none repeat scroll 0 0 #FFAAAA;
4802 text-decoration:none;
4795 text-decoration:none;
4803 }
4796 }
4804
4797
4805 /** LINE NUMBERS **/
4798 /** LINE NUMBERS **/
4806 table.code-difftable .lineno{
4799 table.code-difftable .lineno{
4807
4800
4808 padding-left:2px;
4801 padding-left:2px;
4809 padding-right:2px;
4802 padding-right:2px;
4810 text-align:right;
4803 text-align:right;
4811 width:32px;
4804 width:32px;
4812 -moz-user-select:none;
4805 -moz-user-select:none;
4813 -webkit-user-select: none;
4806 -webkit-user-select: none;
4814 border-right: 1px solid #CCC !important;
4807 border-right: 1px solid #CCC !important;
4815 border-left: 0px solid #CCC !important;
4808 border-left: 0px solid #CCC !important;
4816 border-top: 0px solid #CCC !important;
4809 border-top: 0px solid #CCC !important;
4817 border-bottom: none !important;
4810 border-bottom: none !important;
4818 vertical-align: middle !important;
4811 vertical-align: middle !important;
4819
4812
4820 }
4813 }
4821 table.code-difftable .lineno.new {
4814 table.code-difftable .lineno.new {
4822 }
4815 }
4823 table.code-difftable .lineno.old {
4816 table.code-difftable .lineno.old {
4824 }
4817 }
4825 table.code-difftable .lineno a{
4818 table.code-difftable .lineno a{
4826 color:#747474 !important;
4819 color:#747474 !important;
4827 font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4820 font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4828 letter-spacing:-1px;
4821 letter-spacing:-1px;
4829 text-align:right;
4822 text-align:right;
4830 padding-right: 2px;
4823 padding-right: 2px;
4831 cursor: pointer;
4824 cursor: pointer;
4832 display: block;
4825 display: block;
4833 width: 32px;
4826 width: 32px;
4834 }
4827 }
4835
4828
4836 table.code-difftable .lineno-inline{
4829 table.code-difftable .lineno-inline{
4837 background:none repeat scroll 0 0 #FFF !important;
4830 background:none repeat scroll 0 0 #FFF !important;
4838 padding-left:2px;
4831 padding-left:2px;
4839 padding-right:2px;
4832 padding-right:2px;
4840 text-align:right;
4833 text-align:right;
4841 width:30px;
4834 width:30px;
4842 -moz-user-select:none;
4835 -moz-user-select:none;
4843 -webkit-user-select: none;
4836 -webkit-user-select: none;
4844 }
4837 }
4845
4838
4846 /** CODE **/
4839 /** CODE **/
4847 table.code-difftable .code {
4840 table.code-difftable .code {
4848 display: block;
4841 display: block;
4849 width: 100%;
4842 width: 100%;
4850 }
4843 }
4851 table.code-difftable .code td{
4844 table.code-difftable .code td{
4852 margin:0;
4845 margin:0;
4853 padding:0;
4846 padding:0;
4854 }
4847 }
4855 table.code-difftable .code pre{
4848 table.code-difftable .code pre{
4856 margin:0;
4849 margin:0;
4857 padding:0;
4850 padding:0;
4858 height: 17px;
4851 height: 17px;
4859 line-height: 17px;
4852 line-height: 17px;
4860 }
4853 }
4861
4854
4862
4855
4863 .diffblock.margined.comm .line .code:hover{
4856 .diffblock.margined.comm .line .code:hover{
4864 background-color:#FFFFCC !important;
4857 background-color:#FFFFCC !important;
4865 cursor: pointer !important;
4858 cursor: pointer !important;
4866 background-image:url("../images/icons/comment_add.png") !important;
4859 background-image:url("../images/icons/comment_add.png") !important;
4867 background-repeat:no-repeat !important;
4860 background-repeat:no-repeat !important;
4868 background-position: right !important;
4861 background-position: right !important;
4869 background-position: 0% 50% !important;
4862 background-position: 0% 50% !important;
4870 }
4863 }
4871 .diffblock.margined.comm .line .code.no-comment:hover{
4864 .diffblock.margined.comm .line .code.no-comment:hover{
4872 background-image: none !important;
4865 background-image: none !important;
4873 cursor: auto !important;
4866 cursor: auto !important;
4874 background-color: inherit !important;
4867 background-color: inherit !important;
4875
4876 }
4868 }
4877
4869
4878 div:target {
4870 div:target {
4879 border: solid 2px #ee0 !important;
4871 border: solid 2px #ee0 !important;
4880 margin: -2px;
4872 margin: -2px;
4881 }
4873 }
@@ -1,359 +1,359 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <!-- HEADER -->
4 <!-- HEADER -->
5 <div id="header">
5 <div id="header">
6 <div id="header-inner" class="title hover">
6 <div id="header-inner" class="title hover">
7 <div id="logo">
7 <div id="logo">
8 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
8 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
9 </div>
9 </div>
10 <!-- MENU -->
10 <!-- MENU -->
11 ${self.page_nav()}
11 ${self.page_nav()}
12 <!-- END MENU -->
12 <!-- END MENU -->
13 ${self.body()}
13 ${self.body()}
14 </div>
14 </div>
15 </div>
15 </div>
16 <!-- END HEADER -->
16 <!-- END HEADER -->
17
17
18 <!-- CONTENT -->
18 <!-- CONTENT -->
19 <div id="content">
19 <div id="content">
20 <div class="flash_msg">
20 <div class="flash_msg">
21 <% messages = h.flash.pop_messages() %>
21 <% messages = h.flash.pop_messages() %>
22 % if messages:
22 % if messages:
23 <ul id="flash-messages">
23 <ul id="flash-messages">
24 % for message in messages:
24 % for message in messages:
25 <li class="${message.category}_msg">${message}</li>
25 <li class="${message.category}_msg">${message}</li>
26 % endfor
26 % endfor
27 </ul>
27 </ul>
28 % endif
28 % endif
29 </div>
29 </div>
30 <div id="main">
30 <div id="main">
31 ${next.main()}
31 ${next.main()}
32 </div>
32 </div>
33 </div>
33 </div>
34 <!-- END CONTENT -->
34 <!-- END CONTENT -->
35
35
36 <!-- FOOTER -->
36 <!-- FOOTER -->
37 <div id="footer">
37 <div id="footer">
38 <div id="footer-inner" class="title">
38 <div id="footer-inner" class="title">
39 <div>
39 <div>
40 <p class="footer-link">
40 <p class="footer-link">
41 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
41 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
42 </p>
42 </p>
43 <p class="footer-link-right">
43 <p class="footer-link-right">
44 <a href="${h.url('rhodecode_official')}">RhodeCode${'-%s' % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}</a>
44 <a href="${h.url('rhodecode_official')}">RhodeCode${'-%s' % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}</a>
45 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
45 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
46 </p>
46 </p>
47 </div>
47 </div>
48 </div>
48 </div>
49 </div>
49 </div>
50 <!-- END FOOTER -->
50 <!-- END FOOTER -->
51
51
52 ### MAKO DEFS ###
52 ### MAKO DEFS ###
53 <%def name="page_nav()">
53 <%def name="page_nav()">
54 ${self.menu()}
54 ${self.menu()}
55 </%def>
55 </%def>
56
56
57 <%def name="breadcrumbs()">
57 <%def name="breadcrumbs()">
58 <div class="breadcrumbs">
58 <div class="breadcrumbs">
59 ${self.breadcrumbs_links()}
59 ${self.breadcrumbs_links()}
60 </div>
60 </div>
61 </%def>
61 </%def>
62
62
63 <%def name="usermenu()">
63 <%def name="usermenu()">
64 ## USER MENU
64 ## USER MENU
65 <li>
65 <li>
66 <a class="menu_link" id="quick_login_link">
66 <a class="menu_link" id="quick_login_link">
67 <span class="icon" style="padding:5px 5px 0px 5px">
67 <span class="icon" style="padding:5px 5px 0px 5px">
68 <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
68 <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
69 </span>
69 </span>
70 %if c.rhodecode_user.username != 'default':
70 %if c.rhodecode_user.username != 'default':
71 <span class="menu_link_user">${c.rhodecode_user.username}</span>
71 <span class="menu_link_user">${c.rhodecode_user.username}</span>
72 %if c.unread_notifications != 0:
72 %if c.unread_notifications != 0:
73 <span class="menu_link_notifications">${c.unread_notifications}</span>
73 <span class="menu_link_notifications">${c.unread_notifications}</span>
74 %endif
74 %endif
75 %else:
75 %else:
76 <span>${_('Not logged in')}</span>
76 <span>${_('Not logged in')}</span>
77 %endif
77 %endif
78 </a>
78 </a>
79
79
80 <div class="user-menu">
80 <div class="user-menu">
81 <div id="quick_login">
81 <div id="quick_login">
82 %if c.rhodecode_user.username == 'default':
82 %if c.rhodecode_user.username == 'default':
83 <h4>${_('Login to your account')}</h4>
83 <h4>${_('Login to your account')}</h4>
84 ${h.form(h.url('login_home',came_from=h.url.current()))}
84 ${h.form(h.url('login_home',came_from=h.url.current()))}
85 <div class="form">
85 <div class="form">
86 <div class="fields">
86 <div class="fields">
87 <div class="field">
87 <div class="field">
88 <div class="label">
88 <div class="label">
89 <label for="username">${_('Username')}:</label>
89 <label for="username">${_('Username')}:</label>
90 </div>
90 </div>
91 <div class="input">
91 <div class="input">
92 ${h.text('username',class_='focus',size=40)}
92 ${h.text('username',class_='focus',size=40)}
93 </div>
93 </div>
94
94
95 </div>
95 </div>
96 <div class="field">
96 <div class="field">
97 <div class="label">
97 <div class="label">
98 <label for="password">${_('Password')}:</label>
98 <label for="password">${_('Password')}:</label>
99 </div>
99 </div>
100 <div class="input">
100 <div class="input">
101 ${h.password('password',class_='focus',size=40)}
101 ${h.password('password',class_='focus',size=40)}
102 </div>
102 </div>
103
103
104 </div>
104 </div>
105 <div class="buttons">
105 <div class="buttons">
106 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
106 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
107 <div class="register">
107 <div class="register">
108 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
108 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
109 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
109 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
110 %endif
110 %endif
111 </div>
111 </div>
112 <div class="submit">
112 <div class="submit">
113 ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
113 ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
114 </div>
114 </div>
115 </div>
115 </div>
116 </div>
116 </div>
117 </div>
117 </div>
118 ${h.end_form()}
118 ${h.end_form()}
119 %else:
119 %else:
120 <div class="links_left">
120 <div class="links_left">
121 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
121 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
122 <div class="email">${c.rhodecode_user.email}</div>
122 <div class="email">${c.rhodecode_user.email}</div>
123 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
123 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
124 <div class="inbox"><a href="${h.url('notifications')}">${_('Inbox')}: ${c.unread_notifications}</a></div>
124 <div class="inbox"><a href="${h.url('notifications')}">${_('Inbox')}: ${c.unread_notifications}</a></div>
125 </div>
125 </div>
126 <div class="links_right">
126 <div class="links_right">
127 <ol class="links">
127 <ol class="links">
128 <li>${h.link_to(_(u'Home'),h.url('home'))}</li>
128 <li>${h.link_to(_(u'Home'),h.url('home'))}</li>
129 <li>${h.link_to(_(u'Journal'),h.url('journal'))}</li>
129 <li>${h.link_to(_(u'Journal'),h.url('journal'))}</li>
130 <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
130 <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
131 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
131 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
132 </ol>
132 </ol>
133 </div>
133 </div>
134 %endif
134 %endif
135 </div>
135 </div>
136 </div>
136 </div>
137
137
138 </li>
138 </li>
139 </%def>
139 </%def>
140
140
141 <%def name="menu(current=None)">
141 <%def name="menu(current=None)">
142 <%
142 <%
143 def is_current(selected):
143 def is_current(selected):
144 if selected == current:
144 if selected == current:
145 return h.literal('class="current"')
145 return h.literal('class="current"')
146 %>
146 %>
147 <ul id="quick">
147 <ul id="quick">
148 <!-- repo switcher -->
148 <!-- repo switcher -->
149 <li>
149 <li>
150 <a class="menu_link" id="repo_switcher" title="${_('Switch repository')}" href="#">
150 <a class="menu_link" id="repo_switcher" title="${_('Switch repository')}" href="#">
151 <span class="icon">
151 <span class="icon">
152 <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
152 <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
153 </span>
153 </span>
154 <span>${_('Repositories')}</span>
154 <span>${_('Repositories')}</span>
155 </a>
155 </a>
156 <ul id="repo_switcher_list" class="repo_switcher">
156 <ul id="repo_switcher_list" class="repo_switcher">
157 <li>
157 <li>
158 <a href="#">${_('loading...')}</a>
158 <a href="#">${_('loading...')}</a>
159 </li>
159 </li>
160 </ul>
160 </ul>
161 </li>
161 </li>
162 ## we render this menu only not for those pages
162 ## we render this menu only not for those pages
163 %if current not in ['home','admin', 'search', 'journal']:
163 %if current not in ['home','admin', 'search', 'journal']:
164 ##REGULAR MENU
164 ##REGULAR MENU
165 <li ${is_current('summary')}>
165 <li ${is_current('summary')}>
166 <a class="menu_link" title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
166 <a class="menu_link" title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
167 <span class="icon">
167 <span class="icon">
168 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
168 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
169 </span>
169 </span>
170 <span>${_('Summary')}</span>
170 <span>${_('Summary')}</span>
171 </a>
171 </a>
172 </li>
172 </li>
173 <li ${is_current('changelog')}>
173 <li ${is_current('changelog')}>
174 <a class="menu_link" title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
174 <a class="menu_link" title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
175 <span class="icon">
175 <span class="icon">
176 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
176 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
177 </span>
177 </span>
178 <span>${_('Changelog')}</span>
178 <span>${_('Changelog')}</span>
179 </a>
179 </a>
180 </li>
180 </li>
181 <li ${is_current('switch_to')}>
181 <li ${is_current('switch_to')}>
182 <a class="menu_link" id="branch_tag_switcher" title="${_('Switch to')}" href="#">
182 <a class="menu_link" id="branch_tag_switcher" title="${_('Switch to')}" href="#">
183 <span class="icon">
183 <span class="icon">
184 <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
184 <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
185 </span>
185 </span>
186 <span>${_('Switch to')}</span>
186 <span>${_('Switch to')}</span>
187 </a>
187 </a>
188 <ul id="switch_to_list" class="switch_to">
188 <ul id="switch_to_list" class="switch_to">
189 <li><a href="#">${_('loading...')}</a></li>
189 <li><a href="#">${_('loading...')}</a></li>
190 </ul>
190 </ul>
191 </li>
191 </li>
192 <li ${is_current('files')}>
192 <li ${is_current('files')}>
193 <a class="menu_link" title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
193 <a class="menu_link" title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
194 <span class="icon">
194 <span class="icon">
195 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
195 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
196 </span>
196 </span>
197 <span>${_('Files')}</span>
197 <span>${_('Files')}</span>
198 </a>
198 </a>
199 </li>
199 </li>
200 <li ${is_current('options')}>
200 <li ${is_current('options')}>
201 <a class="menu_link" title="${_('Options')}" href="#">
201 <a class="menu_link" title="${_('Options')}" href="#">
202 <span class="icon">
202 <span class="icon">
203 <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
203 <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
204 </span>
204 </span>
205 <span>${_('Options')}</span>
205 <span>${_('Options')}</span>
206 </a>
206 </a>
207 <ul>
207 <ul>
208 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
208 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
209 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
209 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
210 <li>${h.link_to(_('repository settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
210 <li>${h.link_to(_('repository settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
211 %else:
211 %else:
212 <li>${h.link_to(_('repository settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
212 <li>${h.link_to(_('repository settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
213 %endif
213 %endif
214 %endif
214 %endif
215
215
216 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
216 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
217 %if h.is_hg(c.rhodecode_repo):
217 %if h.is_hg(c.rhodecode_repo):
218 <li>${h.link_to(_('open new pull request'),h.url('pullrequest_home',repo_name=c.repo_name),class_='pull_request')}</li>
218 <li>${h.link_to(_('open new pull request'),h.url('pullrequest_home',repo_name=c.repo_name),class_='pull_request')}</li>
219 %endif
219 %endif
220 %if c.rhodecode_db_repo.fork:
220 %if c.rhodecode_db_repo.fork:
221 <li>${h.link_to(_('compare fork'),h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name),class_='compare_request')}</li>
221 <li>${h.link_to(_('compare fork'),h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name),class_='compare_request')}</li>
222 %endif
222 %endif
223 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
223 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
224
224
225 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
225 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
226 %if c.rhodecode_db_repo.locked[0]:
226 %if c.rhodecode_db_repo.locked[0]:
227 <li>${h.link_to(_('unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
227 <li>${h.link_to(_('unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
228 %else:
228 %else:
229 <li>${h.link_to(_('lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
229 <li>${h.link_to(_('lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
230 %endif
230 %endif
231 %endif
231 %endif
232
232
233 % if h.HasPermissionAll('hg.admin')('access admin main page'):
233 % if h.HasPermissionAll('hg.admin')('access admin main page'):
234 <li>
234 <li>
235 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
235 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
236 <%def name="admin_menu()">
236 <%def name="admin_menu()">
237 <ul>
237 <ul>
238 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
238 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
239 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
239 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
240 <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
240 <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
241 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
241 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
242 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
242 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
243 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
243 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
244 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
244 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
245 <li>${h.link_to(_('defaults'),h.url('defaults'),class_='defaults')}</li>
245 <li>${h.link_to(_('defaults'),h.url('defaults'),class_='defaults')}</li>
246 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
246 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
247 </ul>
247 </ul>
248 </%def>
248 </%def>
249 ## ADMIN MENU
249 ## ADMIN MENU
250 ${admin_menu()}
250 ${admin_menu()}
251 </li>
251 </li>
252 % endif
252 % endif
253 </ul>
253 </ul>
254 </li>
254 </li>
255 <li>
255 <li>
256 <a class="menu_link" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
256 <a class="menu_link" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
257 <span class="icon_short">
257 <span class="icon_short">
258 <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
258 <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
259 </span>
259 </span>
260 <span id="current_followers_count" class="short">${c.repository_followers}</span>
260 <span id="current_followers_count" class="short">${c.repository_followers}</span>
261 </a>
261 </a>
262 </li>
262 </li>
263 <li>
263 <li>
264 <a class="menu_link" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
264 <a class="menu_link" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
265 <span class="icon_short">
265 <span class="icon_short">
266 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
266 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
267 </span>
267 </span>
268 <span class="short">${c.repository_forks}</span>
268 <span class="short">${c.repository_forks}</span>
269 </a>
269 </a>
270 </li>
270 </li>
271 <li>
271 <li>
272 <a class="menu_link" title="${_('Pull requests')}" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}">
272 <a class="menu_link" title="${_('Pull requests')}" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}">
273 <span class="icon_short">
273 <span class="icon_short">
274 <img src="${h.url('/images/icons/arrow_join.png')}" alt="${_('Pull requests')}" />
274 <img src="${h.url('/images/icons/arrow_join.png')}" alt="${_('Pull requests')}" />
275 </span>
275 </span>
276 <span class="short">${c.repository_pull_requests}</span>
276 <span class="short">${c.repository_pull_requests}</span>
277 </a>
277 </a>
278 </li>
278 </li>
279 ${usermenu()}
279 ${usermenu()}
280 <script type="text/javascript">
280 <script type="text/javascript">
281 YUE.on('branch_tag_switcher','mouseover',function(){
281 YUE.on('branch_tag_switcher','mouseover',function(){
282 var loaded = YUD.hasClass('branch_tag_switcher','loaded');
282 var loaded = YUD.hasClass('branch_tag_switcher','loaded');
283 if(!loaded){
283 if(!loaded){
284 YUD.addClass('branch_tag_switcher','loaded');
284 YUD.addClass('branch_tag_switcher','loaded');
285 ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list',
285 ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list',
286 function(o){},
286 function(o){},
287 function(o){YUD.removeClass('branch_tag_switcher','loaded');}
287 function(o){YUD.removeClass('branch_tag_switcher','loaded');}
288 ,null);
288 ,null);
289 }
289 }
290 return false;
290 return false;
291 });
291 });
292 </script>
292 </script>
293 %else:
293 %else:
294 ##ROOT MENU
294 ##ROOT MENU
295 %if c.rhodecode_user.username != 'default':
295 %if c.rhodecode_user.username != 'default':
296 <li ${is_current('journal')}>
296 <li ${is_current('journal')}>
297 <a class="menu_link" title="${_('Journal')}" href="${h.url('journal')}">
297 <a class="menu_link" title="${_('Journal')}" href="${h.url('journal')}">
298 <span class="icon">
298 <span class="icon">
299 <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
299 <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
300 </span>
300 </span>
301 <span>${_('Journal')}</span>
301 <span>${_('Journal')}</span>
302 </a>
302 </a>
303 </li>
303 </li>
304 %else:
304 %else:
305 <li ${is_current('journal')}>
305 <li ${is_current('journal')}>
306 <a class="menu_link" title="${_('Public journal')}" href="${h.url('public_journal')}">
306 <a class="menu_link" title="${_('Public journal')}" href="${h.url('public_journal')}">
307 <span class="icon">
307 <span class="icon">
308 <img src="${h.url('/images/icons/book.png')}" alt="${_('Public journal')}" />
308 <img src="${h.url('/images/icons/book.png')}" alt="${_('Public journal')}" />
309 </span>
309 </span>
310 <span>${_('Public journal')}</span>
310 <span>${_('Public journal')}</span>
311 </a>
311 </a>
312 </li>
312 </li>
313 %endif
313 %endif
314 <li ${is_current('search')}>
314 <li ${is_current('search')}>
315 <a class="menu_link" title="${_('Search')}" href="${h.url('search')}">
315 <a class="menu_link" title="${_('Search')}" href="${h.url('search')}">
316 <span class="icon">
316 <span class="icon">
317 <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
317 <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
318 </span>
318 </span>
319 <span>${_('Search')}</span>
319 <span>${_('Search')}</span>
320 </a>
320 </a>
321 </li>
321 </li>
322 %if h.HasPermissionAll('hg.admin')('access admin main page'):
322 %if h.HasPermissionAll('hg.admin')('access admin main page'):
323 <li ${is_current('admin')}>
323 <li ${is_current('admin')}>
324 <a class="menu_link" title="${_('Admin')}" href="${h.url('admin_home')}">
324 <a class="menu_link" title="${_('Admin')}" href="${h.url('admin_home')}">
325 <span class="icon">
325 <span class="icon">
326 <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
326 <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
327 </span>
327 </span>
328 <span>${_('Admin')}</span>
328 <span>${_('Admin')}</span>
329 </a>
329 </a>
330 ${admin_menu()}
330 ${admin_menu()}
331 </li>
331 </li>
332 %endif
332 %endif
333 ${usermenu()}
333 ${usermenu()}
334 %endif
334 %endif
335 <script type="text/javascript">
335 <script type="text/javascript">
336 YUE.on('repo_switcher','mouseover',function(){
336 YUE.on('repo_switcher','mouseover',function(){
337 var target = 'q_filter_rs';
337 var target = 'q_filter_rs';
338 var qfilter_activate = function(){
338 var qfilter_activate = function(){
339 var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
339 var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
340 var func = function(node){
340 var func = function(node){
341 return node.parentNode;
341 return node.parentNode;
342 }
342 }
343 q_filter(target,nodes,func);
343 q_filter(target,nodes,func);
344 }
344 }
345
345
346 var loaded = YUD.hasClass('repo_switcher','loaded');
346 var loaded = YUD.hasClass('repo_switcher','loaded');
347 if(!loaded){
347 if(!loaded){
348 YUD.addClass('repo_switcher','loaded');
348 YUD.addClass('repo_switcher','loaded');
349 ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
349 ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
350 function(o){qfilter_activate();YUD.get(target).focus()},
350 function(o){qfilter_activate();YUD.get(target).focus()},
351 function(o){YUD.removeClass('repo_switcher','loaded');}
351 function(o){YUD.removeClass('repo_switcher','loaded');}
352 ,null);
352 ,null);
353 }else{
353 }else{
354 YUD.get(target).focus();
354 YUD.get(target).focus();
355 }
355 }
356 return false;
356 return false;
357 });
357 });
358 </script>
358 </script>
359 </%def>
359 </%def>
@@ -1,155 +1,155 b''
1 ## DATA TABLE RE USABLE ELEMENTS
1 ## DATA TABLE RE USABLE ELEMENTS
2 ## usage:
2 ## usage:
3 ## <%namespace name="dt" file="/data_table/_dt_elements.html"/>
3 ## <%namespace name="dt" file="/data_table/_dt_elements.html"/>
4
4
5 <%def name="quick_menu(repo_name)">
5 <%def name="quick_menu(repo_name)">
6 <ul class="menu_items hidden">
6 <ul class="menu_items hidden">
7 <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
7 <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
8 <li>
8 <li>
9 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
9 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
10 <span class="icon">
10 <span class="icon">
11 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
11 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
12 </span>
12 </span>
13 <span>${_('Summary')}</span>
13 <span>${_('Summary')}</span>
14 </a>
14 </a>
15 </li>
15 </li>
16 <li>
16 <li>
17 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
17 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
18 <span class="icon">
18 <span class="icon">
19 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
19 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
20 </span>
20 </span>
21 <span>${_('Changelog')}</span>
21 <span>${_('Changelog')}</span>
22 </a>
22 </a>
23 </li>
23 </li>
24 <li>
24 <li>
25 <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
25 <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
26 <span class="icon">
26 <span class="icon">
27 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
27 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
28 </span>
28 </span>
29 <span>${_('Files')}</span>
29 <span>${_('Files')}</span>
30 </a>
30 </a>
31 </li>
31 </li>
32 <li>
32 <li>
33 <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
33 <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
34 <span class="icon">
34 <span class="icon">
35 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
35 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
36 </span>
36 </span>
37 <span>${_('Fork')}</span>
37 <span>${_('Fork')}</span>
38 </a>
38 </a>
39 </li>
39 </li>
40 </ul>
40 </ul>
41 </%def>
41 </%def>
42
42
43 <%def name="repo_name(name,rtype,private,fork_of,short_name=False,admin=False)">
43 <%def name="repo_name(name,rtype,private,fork_of,short_name=False,admin=False)">
44 <%
44 <%
45 def get_name(name,short_name=short_name):
45 def get_name(name,short_name=short_name):
46 if short_name:
46 if short_name:
47 return name.split('/')[-1]
47 return name.split('/')[-1]
48 else:
48 else:
49 return name
49 return name
50 %>
50 %>
51 <div style="white-space: nowrap">
51 <div style="white-space: nowrap">
52 ##TYPE OF REPO
52 ##TYPE OF REPO
53 %if h.is_hg(rtype):
53 %if h.is_hg(rtype):
54 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
54 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
55 %elif h.is_git(rtype):
55 %elif h.is_git(rtype):
56 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
56 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
57 %endif
57 %endif
58
58
59 ##PRIVATE/PUBLIC
59 ##PRIVATE/PUBLIC
60 %if private and c.visual.show_private_icon:
60 %if private and c.visual.show_private_icon:
61 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
61 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
62 %elif not private and c.visual.show_public_icon:
62 %elif not private and c.visual.show_public_icon:
63 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
63 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
64 %endif
64 %endif
65
65
66 ##NAME
66 ##NAME
67 %if admin:
67 %if admin:
68 ${h.link_to(get_name(name),h.url('edit_repo',repo_name=name),class_="repo_name")}
68 ${h.link_to(get_name(name),h.url('edit_repo',repo_name=name),class_="repo_name")}
69 %else:
69 %else:
70 ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
70 ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
71 %endif
71 %endif
72 %if fork_of:
72 %if fork_of:
73 <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}">
73 <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}">
74 <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
74 <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
75 %endif
75 %endif
76 </div>
76 </div>
77 </%def>
77 </%def>
78
78
79 <%def name="last_change(last_change)">
79 <%def name="last_change(last_change)">
80 <span class="tooltip" date="${last_change}" title="${h.tooltip(h.fmt_date(last_change))}">${h.age(last_change)}</span>
80 <span class="tooltip" date="${last_change}" title="${h.tooltip(h.fmt_date(last_change))}">${h.age(last_change)}</span>
81 </%def>
81 </%def>
82
82
83 <%def name="revision(name,rev,tip,author,last_msg)">
83 <%def name="revision(name,rev,tip,author,last_msg)">
84 <div>
84 <div>
85 %if rev >= 0:
85 %if rev >= 0:
86 <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
86 <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
87 %else:
87 %else:
88 ${_('No changesets yet')}
88 ${_('No changesets yet')}
89 %endif
89 %endif
90 </div>
90 </div>
91 </%def>
91 </%def>
92
92
93 <%def name="rss(name)">
93 <%def name="rss(name)">
94 %if c.rhodecode_user.username != 'default':
94 %if c.rhodecode_user.username != 'default':
95 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
95 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
96 %else:
96 %else:
97 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name)}"></a>
97 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name)}"></a>
98 %endif
98 %endif
99 </%def>
99 </%def>
100
100
101 <%def name="atom(name)">
101 <%def name="atom(name)">
102 %if c.rhodecode_user.username != 'default':
102 %if c.rhodecode_user.username != 'default':
103 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
103 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
104 %else:
104 %else:
105 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name)}"></a>
105 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name)}"></a>
106 %endif
106 %endif
107 </%def>
107 </%def>
108
108
109 <%def name="user_gravatar(email, size=24)">
109 <%def name="user_gravatar(email, size=24)">
110 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
110 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
111 </%def>
111 </%def>
112
112
113 <%def name="repo_actions(repo_name, super_user=True)">
113 <%def name="repo_actions(repo_name, super_user=True)">
114 <div>
114 <div>
115 <div style="float:left">
115 <div style="float:left">
116 %if super_user:
116 %if super_user:
117 <a href="${h.url('edit_repo',repo_name=repo_name)}" title="${_('edit')}">
117 <a href="${h.url('edit_repo',repo_name=repo_name)}" title="${_('edit')}">
118 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
118 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
119 </a>
119 </a>
120 %else:
120 %else:
121 <a href="${h.url('repo_settings_home',repo_name=repo_name)}" title="${_('edit')}">
121 <a href="${h.url('repo_settings_home',repo_name=repo_name)}" title="${_('edit')}">
122 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
122 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
123 </a>
123 </a>
124 %endif
124 %endif
125 </div>
125 </div>
126 <div style="float:left">
126 <div style="float:left">
127 %if super_user:
127 %if super_user:
128 ${h.form(h.url('repo', repo_name=repo_name),method='delete')}
128 ${h.form(h.url('repo', repo_name=repo_name),method='delete')}
129 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
129 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
130 ${h.end_form()}
130 ${h.end_form()}
131 %else:
131 %else:
132 ${h.form(h.url('repo_settings_delete', repo_name=repo_name),method='delete')}
132 ${h.form(h.url('repo_settings_delete', repo_name=repo_name),method='delete')}
133 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
133 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
134 ${h.end_form()}
134 ${h.end_form()}
135 %endif
135 %endif
136 </div>
136 </div>
137 </div>
137 </div>
138 </%def>
138 </%def>
139
139
140 <%def name="user_actions(user_id, username)">
140 <%def name="user_actions(user_id, username)">
141 ${h.form(h.url('delete_user', id=user_id),method='delete')}
141 ${h.form(h.url('delete_user', id=user_id),method='delete')}
142 ${h.submit('remove_',_('delete'),id="remove_user_%s" % user_id,
142 ${h.submit('remove_',_('delete'),id="remove_user_%s" % user_id,
143 class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")}
143 class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")}
144 ${h.end_form()}
144 ${h.end_form()}
145 </%def>
145 </%def>
146
146
147 <%def name="user_name(user_id, username)">
147 <%def name="user_name(user_id, username)">
148 ${h.link_to(username,h.url('edit_user', id=user_id))}
148 ${h.link_to(username,h.url('edit_user', id=user_id))}
149 </%def>
149 </%def>
150
150
151 <%def name="toggle_follow(repo_id)">
151 <%def name="toggle_follow(repo_id)">
152 <span id="follow_toggle_${repo_id}" class="following" title="${_('Stop following this repository')}"
152 <span id="follow_toggle_${repo_id}" class="following" title="${_('Stop following this repository')}"
153 onclick="javascript:toggleFollowingRepo(this, ${repo_id},'${str(h.get_token())}')">
153 onclick="javascript:toggleFollowingRepo(this, ${repo_id},'${str(h.get_token())}')">
154 </span>
154 </span>
155 </%def>
155 </%def>
@@ -1,727 +1,727 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('%s Summary') % c.repo_name} - ${c.rhodecode_name}
4 ${_('%s Summary') % c.repo_name} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(_(u'Home'),h.url('/'))}
8 ${h.link_to(_(u'Home'),h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.repo_link(c.dbrepo.groups_and_repo)}
10 ${h.repo_link(c.dbrepo.groups_and_repo)}
11 &raquo;
11 &raquo;
12 ${_('summary')}
12 ${_('summary')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('summary')}
16 ${self.menu('summary')}
17 </%def>
17 </%def>
18
18
19 <%def name="head_extra()">
19 <%def name="head_extra()">
20 <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" />
20 <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" />
21 <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" />
21 <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" />
22 </%def>
22 </%def>
23
23
24 <%def name="main()">
24 <%def name="main()">
25 <%
25 <%
26 summary = lambda n:{False:'summary-short'}.get(n)
26 summary = lambda n:{False:'summary-short'}.get(n)
27 %>
27 %>
28 %if c.show_stats:
28 %if c.show_stats:
29 <div class="box box-left">
29 <div class="box box-left">
30 %else:
30 %else:
31 <div class="box">
31 <div class="box">
32 %endif
32 %endif
33 <!-- box / title -->
33 <!-- box / title -->
34 <div class="title">
34 <div class="title">
35 ${self.breadcrumbs()}
35 ${self.breadcrumbs()}
36 </div>
36 </div>
37 <!-- end box / title -->
37 <!-- end box / title -->
38 <div class="form">
38 <div class="form">
39 <div id="summary" class="fields">
39 <div id="summary" class="fields">
40
40
41 <div class="field">
41 <div class="field">
42 <div class="label-summary">
42 <div class="label-summary">
43 <label>${_('Name')}:</label>
43 <label>${_('Name')}:</label>
44 </div>
44 </div>
45 <div class="input ${summary(c.show_stats)}">
45 <div class="input ${summary(c.show_stats)}">
46 <div style="float:right;padding:5px 0px 0px 5px">
46 <div style="float:right;padding:5px 0px 0px 5px">
47 %if c.rhodecode_user.username != 'default':
47 %if c.rhodecode_user.username != 'default':
48 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
48 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
49 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
49 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
50 %else:
50 %else:
51 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
51 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
52 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
52 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
53 %endif
53 %endif
54 </div>
54 </div>
55 %if c.rhodecode_user.username != 'default':
55 %if c.rhodecode_user.username != 'default':
56 %if c.following:
56 %if c.following:
57 <span id="follow_toggle" class="following tooltip" title="${_('Stop following this repository')}"
57 <span id="follow_toggle" class="following tooltip" title="${_('Stop following this repository')}"
58 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
58 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
59 </span>
59 </span>
60 %else:
60 %else:
61 <span id="follow_toggle" class="follow tooltip" title="${_('Start following this repository')}"
61 <span id="follow_toggle" class="follow tooltip" title="${_('Start following this repository')}"
62 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
62 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
63 </span>
63 </span>
64 %endif
64 %endif
65 <div style="float:right;padding:0px 0px 0px 0px">
65 <div style="float:right;padding:0px 0px 0px 0px">
66 <span class="reposize tooltip" title="${_('Click to show size of repository')}"
66 <span class="reposize tooltip" title="${_('Click to show size of repository')}"
67 onclick="javascript:showRepoSize('repo_size','${c.dbrepo.repo_name}','${str(h.get_token())}')">
67 onclick="javascript:showRepoSize('repo_size','${c.dbrepo.repo_name}','${str(h.get_token())}')">
68 </span>
68 </span>
69 <span id="repo_size"></span>
69 <span id="repo_size"></span>
70 </div>
70 </div>
71 %endif:
71 %endif:
72
72
73 ## locking icon
73 ## locking icon
74 %if c.rhodecode_db_repo.enable_locking:
74 %if c.rhodecode_db_repo.enable_locking:
75 %if c.rhodecode_db_repo.locked[0]:
75 %if c.rhodecode_db_repo.locked[0]:
76 <span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span>
76 <span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span>
77 %else:
77 %else:
78 <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span>
78 <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span>
79 %endif
79 %endif
80 %endif
80 %endif
81 ##REPO TYPE
81 ##REPO TYPE
82 %if h.is_hg(c.dbrepo):
82 %if h.is_hg(c.dbrepo):
83 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
83 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
84 %endif
84 %endif
85 %if h.is_git(c.dbrepo):
85 %if h.is_git(c.dbrepo):
86 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
86 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
87 %endif
87 %endif
88
88
89 ##PUBLIC/PRIVATE
89 ##PUBLIC/PRIVATE
90 %if c.dbrepo.private:
90 %if c.dbrepo.private:
91 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
91 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
92 %else:
92 %else:
93 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
93 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
94 %endif
94 %endif
95
95
96 ##REPO NAME
96 ##REPO NAME
97 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
97 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
98
98
99 ##FORK
99 ##FORK
100 %if c.dbrepo.fork:
100 %if c.dbrepo.fork:
101 <div style="margin-top:5px;clear:both"">
101 <div style="margin-top:5px;clear:both"">
102 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
102 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
103 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
103 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
104 </a>
104 </a>
105 </div>
105 </div>
106 %endif
106 %endif
107 ##REMOTE
107 ##REMOTE
108 %if c.dbrepo.clone_uri:
108 %if c.dbrepo.clone_uri:
109 <div style="margin-top:5px;clear:both">
109 <div style="margin-top:5px;clear:both">
110 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
110 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
111 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
111 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
112 </a>
112 </a>
113 </div>
113 </div>
114 %endif
114 %endif
115 </div>
115 </div>
116 </div>
116 </div>
117
117
118 <div class="field">
118 <div class="field">
119 <div class="label-summary">
119 <div class="label-summary">
120 <label>${_('Description')}:</label>
120 <label>${_('Description')}:</label>
121 </div>
121 </div>
122 %if c.visual.stylify_metatags:
122 %if c.visual.stylify_metatags:
123 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
123 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
124 %else:
124 %else:
125 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
125 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
126 %endif
126 %endif
127 </div>
127 </div>
128
128
129 <div class="field">
129 <div class="field">
130 <div class="label-summary">
130 <div class="label-summary">
131 <label>${_('Contact')}:</label>
131 <label>${_('Contact')}:</label>
132 </div>
132 </div>
133 <div class="input ${summary(c.show_stats)}">
133 <div class="input ${summary(c.show_stats)}">
134 <div class="gravatar">
134 <div class="gravatar">
135 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
135 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
136 </div>
136 </div>
137 ${_('Username')}: ${c.dbrepo.user.username}<br/>
137 ${_('Username')}: ${c.dbrepo.user.username}<br/>
138 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
138 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
139 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
139 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
140 </div>
140 </div>
141 </div>
141 </div>
142
142
143 <div class="field">
143 <div class="field">
144 <div class="label-summary">
144 <div class="label-summary">
145 <label>${_('Clone url')}:</label>
145 <label>${_('Clone url')}:</label>
146 </div>
146 </div>
147 <div class="input ${summary(c.show_stats)}">
147 <div class="input ${summary(c.show_stats)}">
148 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
148 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
149 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
149 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
150 <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
150 <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
151 <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
151 <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
152 </div>
152 </div>
153 </div>
153 </div>
154
154
155 <div class="field">
155 <div class="field">
156 <div class="label-summary">
156 <div class="label-summary">
157 <label>${_('Trending files')}:</label>
157 <label>${_('Trending files')}:</label>
158 </div>
158 </div>
159 <div class="input ${summary(c.show_stats)}">
159 <div class="input ${summary(c.show_stats)}">
160 %if c.show_stats:
160 %if c.show_stats:
161 <div id="lang_stats"></div>
161 <div id="lang_stats"></div>
162 %else:
162 %else:
163 ${_('Statistics are disabled for this repository')}
163 ${_('Statistics are disabled for this repository')}
164 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
164 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
165 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
165 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
166 %endif
166 %endif
167 %endif
167 %endif
168 </div>
168 </div>
169 </div>
169 </div>
170
170
171 <div class="field">
171 <div class="field">
172 <div class="label-summary">
172 <div class="label-summary">
173 <label>${_('Download')}:</label>
173 <label>${_('Download')}:</label>
174 </div>
174 </div>
175 <div class="input ${summary(c.show_stats)}">
175 <div class="input ${summary(c.show_stats)}">
176 %if len(c.rhodecode_repo.revisions) == 0:
176 %if len(c.rhodecode_repo.revisions) == 0:
177 ${_('There are no downloads yet')}
177 ${_('There are no downloads yet')}
178 %elif c.enable_downloads is False:
178 %elif c.enable_downloads is False:
179 ${_('Downloads are disabled for this repository')}
179 ${_('Downloads are disabled for this repository')}
180 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
180 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
181 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
181 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
182 %endif
182 %endif
183 %else:
183 %else:
184 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
184 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
185 <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
185 <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
186 <span style="vertical-align: bottom">
186 <span style="vertical-align: bottom">
187 <input id="archive_subrepos" type="checkbox" name="subrepos" />
187 <input id="archive_subrepos" type="checkbox" name="subrepos" />
188 <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label>
188 <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label>
189 </span>
189 </span>
190 %endif
190 %endif
191 </div>
191 </div>
192 </div>
192 </div>
193 </div>
193 </div>
194 </div>
194 </div>
195 </div>
195 </div>
196
196
197 %if c.show_stats:
197 %if c.show_stats:
198 <div class="box box-right" style="min-height:455px">
198 <div class="box box-right" style="min-height:455px">
199 <!-- box / title -->
199 <!-- box / title -->
200 <div class="title">
200 <div class="title">
201 <h5>${_('Commit activity by day / author')}</h5>
201 <h5>${_('Commit activity by day / author')}</h5>
202 </div>
202 </div>
203
203
204 <div class="graph">
204 <div class="graph">
205 <div style="padding:0 10px 10px 17px;">
205 <div style="padding:0 10px 10px 17px;">
206 %if c.no_data:
206 %if c.no_data:
207 ${c.no_data_msg}
207 ${c.no_data_msg}
208 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
208 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
209 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
209 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
210 %endif
210 %endif
211 %else:
211 %else:
212 ${_('Stats gathered: ')} ${c.stats_percentage}%
212 ${_('Stats gathered: ')} ${c.stats_percentage}%
213 %endif
213 %endif
214 </div>
214 </div>
215 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
215 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
216 <div style="clear: both;height: 10px"></div>
216 <div style="clear: both;height: 10px"></div>
217 <div id="overview" style="width:450px;height:100px;float:left"></div>
217 <div id="overview" style="width:450px;height:100px;float:left"></div>
218
218
219 <div id="legend_data" style="clear:both;margin-top:10px;">
219 <div id="legend_data" style="clear:both;margin-top:10px;">
220 <div id="legend_container"></div>
220 <div id="legend_container"></div>
221 <div id="legend_choices">
221 <div id="legend_choices">
222 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
222 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
223 </div>
223 </div>
224 </div>
224 </div>
225 </div>
225 </div>
226 </div>
226 </div>
227 %endif
227 %endif
228
228
229 <div class="box">
229 <div class="box">
230 <div class="title">
230 <div class="title">
231 <div class="breadcrumbs">
231 <div class="breadcrumbs">
232 %if c.repo_changesets:
232 %if c.repo_changesets:
233 ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}
233 ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}
234 %else:
234 %else:
235 ${_('Quick start')}
235 ${_('Quick start')}
236 %endif
236 %endif
237 </div>
237 </div>
238 </div>
238 </div>
239 <div class="table">
239 <div class="table">
240 <div id="shortlog_data">
240 <div id="shortlog_data">
241 <%include file='../shortlog/shortlog_data.html'/>
241 <%include file='../shortlog/shortlog_data.html'/>
242 </div>
242 </div>
243 </div>
243 </div>
244 </div>
244 </div>
245
245
246 %if c.readme_data:
246 %if c.readme_data:
247 <div id="readme" class="anchor">
247 <div id="readme" class="anchor">
248 <div class="box" style="background-color: #FAFAFA">
248 <div class="box" style="background-color: #FAFAFA">
249 <div class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}">
249 <div class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}">
250 <div class="breadcrumbs">
250 <div class="breadcrumbs">
251 <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a>
251 <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a>
252 <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">&para;</a>
252 <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">&para;</a>
253 </div>
253 </div>
254 </div>
254 </div>
255 <div class="readme">
255 <div class="readme">
256 <div class="readme_box">
256 <div class="readme_box">
257 ${c.readme_data|n}
257 ${c.readme_data|n}
258 </div>
258 </div>
259 </div>
259 </div>
260 </div>
260 </div>
261 </div>
261 </div>
262 %endif
262 %endif
263
263
264 <script type="text/javascript">
264 <script type="text/javascript">
265 var clone_url = 'clone_url';
265 var clone_url = 'clone_url';
266 YUE.on(clone_url,'click',function(e){
266 YUE.on(clone_url,'click',function(e){
267 if(YUD.hasClass(clone_url,'selected')){
267 if(YUD.hasClass(clone_url,'selected')){
268 return
268 return
269 }
269 }
270 else{
270 else{
271 YUD.addClass(clone_url,'selected');
271 YUD.addClass(clone_url,'selected');
272 YUD.get(clone_url).select();
272 YUD.get(clone_url).select();
273 }
273 }
274 })
274 })
275
275
276 YUE.on('clone_by_name','click',function(e){
276 YUE.on('clone_by_name','click',function(e){
277 // show url by name and hide name button
277 // show url by name and hide name button
278 YUD.setStyle('clone_url','display','');
278 YUD.setStyle('clone_url','display','');
279 YUD.setStyle('clone_by_name','display','none');
279 YUD.setStyle('clone_by_name','display','none');
280
280
281 // hide url by id and show name button
281 // hide url by id and show name button
282 YUD.setStyle('clone_by_id','display','');
282 YUD.setStyle('clone_by_id','display','');
283 YUD.setStyle('clone_url_id','display','none');
283 YUD.setStyle('clone_url_id','display','none');
284
284
285 })
285 })
286 YUE.on('clone_by_id','click',function(e){
286 YUE.on('clone_by_id','click',function(e){
287
287
288 // show url by id and hide id button
288 // show url by id and hide id button
289 YUD.setStyle('clone_by_id','display','none');
289 YUD.setStyle('clone_by_id','display','none');
290 YUD.setStyle('clone_url_id','display','');
290 YUD.setStyle('clone_url_id','display','');
291
291
292 // hide url by name and show id button
292 // hide url by name and show id button
293 YUD.setStyle('clone_by_name','display','');
293 YUD.setStyle('clone_by_name','display','');
294 YUD.setStyle('clone_url','display','none');
294 YUD.setStyle('clone_url','display','none');
295 })
295 })
296
296
297
297
298 var tmpl_links = {};
298 var tmpl_links = {};
299 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
299 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
300 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
300 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
301 %endfor
301 %endfor
302
302
303 YUE.on(['download_options','archive_subrepos'],'change',function(e){
303 YUE.on(['download_options','archive_subrepos'],'change',function(e){
304 var sm = YUD.get('download_options');
304 var sm = YUD.get('download_options');
305 var new_cs = sm.options[sm.selectedIndex];
305 var new_cs = sm.options[sm.selectedIndex];
306
306
307 for(k in tmpl_links){
307 for(k in tmpl_links){
308 var s = YUD.get(k+'_link');
308 var s = YUD.get(k+'_link');
309 if(s){
309 if(s){
310 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
310 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
311 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
311 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
312 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
312 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
313
313
314 var url = tmpl_links[k].replace('__CS__',new_cs.value);
314 var url = tmpl_links[k].replace('__CS__',new_cs.value);
315 var subrepos = YUD.get('archive_subrepos').checked;
315 var subrepos = YUD.get('archive_subrepos').checked;
316 url = url.replace('__SUB__',subrepos);
316 url = url.replace('__SUB__',subrepos);
317 url = url.replace('__NAME__',title_tmpl);
317 url = url.replace('__NAME__',title_tmpl);
318 s.innerHTML = url
318 s.innerHTML = url
319 }
319 }
320 }
320 }
321 });
321 });
322 </script>
322 </script>
323 %if c.show_stats:
323 %if c.show_stats:
324 <script type="text/javascript">
324 <script type="text/javascript">
325 var data = ${c.trending_languages|n};
325 var data = ${c.trending_languages|n};
326 var total = 0;
326 var total = 0;
327 var no_data = true;
327 var no_data = true;
328 var tbl = document.createElement('table');
328 var tbl = document.createElement('table');
329 tbl.setAttribute('class','trending_language_tbl');
329 tbl.setAttribute('class','trending_language_tbl');
330 var cnt = 0;
330 var cnt = 0;
331 for (var i=0;i<data.length;i++){
331 for (var i=0;i<data.length;i++){
332 total+= data[i][1].count;
332 total+= data[i][1].count;
333 }
333 }
334 for (var i=0;i<data.length;i++){
334 for (var i=0;i<data.length;i++){
335 cnt += 1;
335 cnt += 1;
336 no_data = false;
336 no_data = false;
337
337
338 var hide = cnt>2;
338 var hide = cnt>2;
339 var tr = document.createElement('tr');
339 var tr = document.createElement('tr');
340 if (hide){
340 if (hide){
341 tr.setAttribute('style','display:none');
341 tr.setAttribute('style','display:none');
342 tr.setAttribute('class','stats_hidden');
342 tr.setAttribute('class','stats_hidden');
343 }
343 }
344 var k = data[i][0];
344 var k = data[i][0];
345 var obj = data[i][1];
345 var obj = data[i][1];
346 var percentage = Math.round((obj.count/total*100),2);
346 var percentage = Math.round((obj.count/total*100),2);
347
347
348 var td1 = document.createElement('td');
348 var td1 = document.createElement('td');
349 td1.width = 150;
349 td1.width = 150;
350 var trending_language_label = document.createElement('div');
350 var trending_language_label = document.createElement('div');
351 trending_language_label.innerHTML = obj.desc+" ("+k+")";
351 trending_language_label.innerHTML = obj.desc+" ("+k+")";
352 td1.appendChild(trending_language_label);
352 td1.appendChild(trending_language_label);
353
353
354 var td2 = document.createElement('td');
354 var td2 = document.createElement('td');
355 td2.setAttribute('style','padding-right:14px !important');
355 td2.setAttribute('style','padding-right:14px !important');
356 var trending_language = document.createElement('div');
356 var trending_language = document.createElement('div');
357 var nr_files = obj.count+" ${_('files')}";
357 var nr_files = obj.count+" ${_('files')}";
358
358
359 trending_language.title = k+" "+nr_files;
359 trending_language.title = k+" "+nr_files;
360
360
361 if (percentage>22){
361 if (percentage>22){
362 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
362 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
363 }
363 }
364 else{
364 else{
365 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
365 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
366 }
366 }
367
367
368 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
368 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
369 trending_language.style.width=percentage+"%";
369 trending_language.style.width=percentage+"%";
370 td2.appendChild(trending_language);
370 td2.appendChild(trending_language);
371
371
372 tr.appendChild(td1);
372 tr.appendChild(td1);
373 tr.appendChild(td2);
373 tr.appendChild(td2);
374 tbl.appendChild(tr);
374 tbl.appendChild(tr);
375 if(cnt == 3){
375 if(cnt == 3){
376 var show_more = document.createElement('tr');
376 var show_more = document.createElement('tr');
377 var td = document.createElement('td');
377 var td = document.createElement('td');
378 lnk = document.createElement('a');
378 lnk = document.createElement('a');
379
379
380 lnk.href='#';
380 lnk.href='#';
381 lnk.innerHTML = "${_('show more')}";
381 lnk.innerHTML = "${_('show more')}";
382 lnk.id='code_stats_show_more';
382 lnk.id='code_stats_show_more';
383 td.appendChild(lnk);
383 td.appendChild(lnk);
384
384
385 show_more.appendChild(td);
385 show_more.appendChild(td);
386 show_more.appendChild(document.createElement('td'));
386 show_more.appendChild(document.createElement('td'));
387 tbl.appendChild(show_more);
387 tbl.appendChild(show_more);
388 }
388 }
389
389
390 }
390 }
391
391
392 YUD.get('lang_stats').appendChild(tbl);
392 YUD.get('lang_stats').appendChild(tbl);
393 YUE.on('code_stats_show_more','click',function(){
393 YUE.on('code_stats_show_more','click',function(){
394 l = YUD.getElementsByClassName('stats_hidden')
394 l = YUD.getElementsByClassName('stats_hidden')
395 for (e in l){
395 for (e in l){
396 YUD.setStyle(l[e],'display','');
396 YUD.setStyle(l[e],'display','');
397 };
397 };
398 YUD.setStyle(YUD.get('code_stats_show_more'),
398 YUD.setStyle(YUD.get('code_stats_show_more'),
399 'display','none');
399 'display','none');
400 });
400 });
401 </script>
401 </script>
402 <script type="text/javascript">
402 <script type="text/javascript">
403 /**
403 /**
404 * Plots summary graph
404 * Plots summary graph
405 *
405 *
406 * @class SummaryPlot
406 * @class SummaryPlot
407 * @param {from} initial from for detailed graph
407 * @param {from} initial from for detailed graph
408 * @param {to} initial to for detailed graph
408 * @param {to} initial to for detailed graph
409 * @param {dataset}
409 * @param {dataset}
410 * @param {overview_dataset}
410 * @param {overview_dataset}
411 */
411 */
412 function SummaryPlot(from,to,dataset,overview_dataset) {
412 function SummaryPlot(from,to,dataset,overview_dataset) {
413 var initial_ranges = {
413 var initial_ranges = {
414 "xaxis":{
414 "xaxis":{
415 "from":from,
415 "from":from,
416 "to":to,
416 "to":to,
417 },
417 },
418 };
418 };
419 var dataset = dataset;
419 var dataset = dataset;
420 var overview_dataset = [overview_dataset];
420 var overview_dataset = [overview_dataset];
421 var choiceContainer = YUD.get("legend_choices");
421 var choiceContainer = YUD.get("legend_choices");
422 var choiceContainerTable = YUD.get("legend_choices_tables");
422 var choiceContainerTable = YUD.get("legend_choices_tables");
423 var plotContainer = YUD.get('commit_history');
423 var plotContainer = YUD.get('commit_history');
424 var overviewContainer = YUD.get('overview');
424 var overviewContainer = YUD.get('overview');
425
425
426 var plot_options = {
426 var plot_options = {
427 bars: {show:true,align:'center',lineWidth:4},
427 bars: {show:true,align:'center',lineWidth:4},
428 legend: {show:true, container:"legend_container"},
428 legend: {show:true, container:"legend_container"},
429 points: {show:true,radius:0,fill:false},
429 points: {show:true,radius:0,fill:false},
430 yaxis: {tickDecimals:0,},
430 yaxis: {tickDecimals:0,},
431 xaxis: {
431 xaxis: {
432 mode: "time",
432 mode: "time",
433 timeformat: "%d/%m",
433 timeformat: "%d/%m",
434 min:from,
434 min:from,
435 max:to,
435 max:to,
436 },
436 },
437 grid: {
437 grid: {
438 hoverable: true,
438 hoverable: true,
439 clickable: true,
439 clickable: true,
440 autoHighlight:true,
440 autoHighlight:true,
441 color: "#999"
441 color: "#999"
442 },
442 },
443 //selection: {mode: "x"}
443 //selection: {mode: "x"}
444 };
444 };
445 var overview_options = {
445 var overview_options = {
446 legend:{show:false},
446 legend:{show:false},
447 bars: {show:true,barWidth: 2,},
447 bars: {show:true,barWidth: 2,},
448 shadowSize: 0,
448 shadowSize: 0,
449 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
449 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
450 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
450 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
451 grid: {color: "#999",},
451 grid: {color: "#999",},
452 selection: {mode: "x"}
452 selection: {mode: "x"}
453 };
453 };
454
454
455 /**
455 /**
456 *get dummy data needed in few places
456 *get dummy data needed in few places
457 */
457 */
458 function getDummyData(label){
458 function getDummyData(label){
459 return {"label":label,
459 return {"label":label,
460 "data":[{"time":0,
460 "data":[{"time":0,
461 "commits":0,
461 "commits":0,
462 "added":0,
462 "added":0,
463 "changed":0,
463 "changed":0,
464 "removed":0,
464 "removed":0,
465 }],
465 }],
466 "schema":["commits"],
466 "schema":["commits"],
467 "color":'#ffffff',
467 "color":'#ffffff',
468 }
468 }
469 }
469 }
470
470
471 /**
471 /**
472 * generate checkboxes accordindly to data
472 * generate checkboxes accordindly to data
473 * @param keys
473 * @param keys
474 * @returns
474 * @returns
475 */
475 */
476 function generateCheckboxes(data) {
476 function generateCheckboxes(data) {
477 //append checkboxes
477 //append checkboxes
478 var i = 0;
478 var i = 0;
479 choiceContainerTable.innerHTML = '';
479 choiceContainerTable.innerHTML = '';
480 for(var pos in data) {
480 for(var pos in data) {
481
481
482 data[pos].color = i;
482 data[pos].color = i;
483 i++;
483 i++;
484 if(data[pos].label != ''){
484 if(data[pos].label != ''){
485 choiceContainerTable.innerHTML +=
485 choiceContainerTable.innerHTML +=
486 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
486 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
487 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
487 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
488 }
488 }
489 }
489 }
490 }
490 }
491
491
492 /**
492 /**
493 * ToolTip show
493 * ToolTip show
494 */
494 */
495 function showTooltip(x, y, contents) {
495 function showTooltip(x, y, contents) {
496 var div=document.getElementById('tooltip');
496 var div=document.getElementById('tooltip');
497 if(!div) {
497 if(!div) {
498 div = document.createElement('div');
498 div = document.createElement('div');
499 div.id="tooltip";
499 div.id="tooltip";
500 div.style.position="absolute";
500 div.style.position="absolute";
501 div.style.border='1px solid #fdd';
501 div.style.border='1px solid #fdd';
502 div.style.padding='2px';
502 div.style.padding='2px';
503 div.style.backgroundColor='#fee';
503 div.style.backgroundColor='#fee';
504 document.body.appendChild(div);
504 document.body.appendChild(div);
505 }
505 }
506 YUD.setStyle(div, 'opacity', 0);
506 YUD.setStyle(div, 'opacity', 0);
507 div.innerHTML = contents;
507 div.innerHTML = contents;
508 div.style.top=(y + 5) + "px";
508 div.style.top=(y + 5) + "px";
509 div.style.left=(x + 5) + "px";
509 div.style.left=(x + 5) + "px";
510
510
511 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
511 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
512 anim.animate();
512 anim.animate();
513 }
513 }
514
514
515 /**
515 /**
516 * This function will detect if selected period has some changesets
516 * This function will detect if selected period has some changesets
517 for this user if it does this data is then pushed for displaying
517 for this user if it does this data is then pushed for displaying
518 Additionally it will only display users that are selected by the checkbox
518 Additionally it will only display users that are selected by the checkbox
519 */
519 */
520 function getDataAccordingToRanges(ranges) {
520 function getDataAccordingToRanges(ranges) {
521
521
522 var data = [];
522 var data = [];
523 var new_dataset = {};
523 var new_dataset = {};
524 var keys = [];
524 var keys = [];
525 var max_commits = 0;
525 var max_commits = 0;
526 for(var key in dataset){
526 for(var key in dataset){
527
527
528 for(var ds in dataset[key].data){
528 for(var ds in dataset[key].data){
529 commit_data = dataset[key].data[ds];
529 commit_data = dataset[key].data[ds];
530 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
530 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
531
531
532 if(new_dataset[key] === undefined){
532 if(new_dataset[key] === undefined){
533 new_dataset[key] = {data:[],schema:["commits"],label:key};
533 new_dataset[key] = {data:[],schema:["commits"],label:key};
534 }
534 }
535 new_dataset[key].data.push(commit_data);
535 new_dataset[key].data.push(commit_data);
536 }
536 }
537 }
537 }
538 if (new_dataset[key] !== undefined){
538 if (new_dataset[key] !== undefined){
539 data.push(new_dataset[key]);
539 data.push(new_dataset[key]);
540 }
540 }
541 }
541 }
542
542
543 if (data.length > 0){
543 if (data.length > 0){
544 return data;
544 return data;
545 }
545 }
546 else{
546 else{
547 //just return dummy data for graph to plot itself
547 //just return dummy data for graph to plot itself
548 return [getDummyData('')];
548 return [getDummyData('')];
549 }
549 }
550 }
550 }
551
551
552 /**
552 /**
553 * redraw using new checkbox data
553 * redraw using new checkbox data
554 */
554 */
555 function plotchoiced(e,args){
555 function plotchoiced(e,args){
556 var cur_data = args[0];
556 var cur_data = args[0];
557 var cur_ranges = args[1];
557 var cur_ranges = args[1];
558
558
559 var new_data = [];
559 var new_data = [];
560 var inputs = choiceContainer.getElementsByTagName("input");
560 var inputs = choiceContainer.getElementsByTagName("input");
561
561
562 //show only checked labels
562 //show only checked labels
563 for(var i=0; i<inputs.length; i++) {
563 for(var i=0; i<inputs.length; i++) {
564 var checkbox_key = inputs[i].name;
564 var checkbox_key = inputs[i].name;
565
565
566 if(inputs[i].checked){
566 if(inputs[i].checked){
567 for(var d in cur_data){
567 for(var d in cur_data){
568 if(cur_data[d].label == checkbox_key){
568 if(cur_data[d].label == checkbox_key){
569 new_data.push(cur_data[d]);
569 new_data.push(cur_data[d]);
570 }
570 }
571 }
571 }
572 }
572 }
573 else{
573 else{
574 //push dummy data to not hide the label
574 //push dummy data to not hide the label
575 new_data.push(getDummyData(checkbox_key));
575 new_data.push(getDummyData(checkbox_key));
576 }
576 }
577 }
577 }
578
578
579 var new_options = YAHOO.lang.merge(plot_options, {
579 var new_options = YAHOO.lang.merge(plot_options, {
580 xaxis: {
580 xaxis: {
581 min: cur_ranges.xaxis.from,
581 min: cur_ranges.xaxis.from,
582 max: cur_ranges.xaxis.to,
582 max: cur_ranges.xaxis.to,
583 mode:"time",
583 mode:"time",
584 timeformat: "%d/%m",
584 timeformat: "%d/%m",
585 },
585 },
586 });
586 });
587 if (!new_data){
587 if (!new_data){
588 new_data = [[0,1]];
588 new_data = [[0,1]];
589 }
589 }
590 // do the zooming
590 // do the zooming
591 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
591 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
592
592
593 plot.subscribe("plotselected", plotselected);
593 plot.subscribe("plotselected", plotselected);
594
594
595 //resubscribe plothover
595 //resubscribe plothover
596 plot.subscribe("plothover", plothover);
596 plot.subscribe("plothover", plothover);
597
597
598 // don't fire event on the overview to prevent eternal loop
598 // don't fire event on the overview to prevent eternal loop
599 overview.setSelection(cur_ranges, true);
599 overview.setSelection(cur_ranges, true);
600
600
601 }
601 }
602
602
603 /**
603 /**
604 * plot only selected items from overview
604 * plot only selected items from overview
605 * @param ranges
605 * @param ranges
606 * @returns
606 * @returns
607 */
607 */
608 function plotselected(ranges,cur_data) {
608 function plotselected(ranges,cur_data) {
609 //updates the data for new plot
609 //updates the data for new plot
610 var data = getDataAccordingToRanges(ranges);
610 var data = getDataAccordingToRanges(ranges);
611 generateCheckboxes(data);
611 generateCheckboxes(data);
612
612
613 var new_options = YAHOO.lang.merge(plot_options, {
613 var new_options = YAHOO.lang.merge(plot_options, {
614 xaxis: {
614 xaxis: {
615 min: ranges.xaxis.from,
615 min: ranges.xaxis.from,
616 max: ranges.xaxis.to,
616 max: ranges.xaxis.to,
617 mode:"time",
617 mode:"time",
618 timeformat: "%d/%m",
618 timeformat: "%d/%m",
619 },
619 },
620 });
620 });
621 // do the zooming
621 // do the zooming
622 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
622 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
623
623
624 plot.subscribe("plotselected", plotselected);
624 plot.subscribe("plotselected", plotselected);
625
625
626 //resubscribe plothover
626 //resubscribe plothover
627 plot.subscribe("plothover", plothover);
627 plot.subscribe("plothover", plothover);
628
628
629 // don't fire event on the overview to prevent eternal loop
629 // don't fire event on the overview to prevent eternal loop
630 overview.setSelection(ranges, true);
630 overview.setSelection(ranges, true);
631
631
632 //resubscribe choiced
632 //resubscribe choiced
633 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
633 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
634 }
634 }
635
635
636 var previousPoint = null;
636 var previousPoint = null;
637
637
638 function plothover(o) {
638 function plothover(o) {
639 var pos = o.pos;
639 var pos = o.pos;
640 var item = o.item;
640 var item = o.item;
641
641
642 //YUD.get("x").innerHTML = pos.x.toFixed(2);
642 //YUD.get("x").innerHTML = pos.x.toFixed(2);
643 //YUD.get("y").innerHTML = pos.y.toFixed(2);
643 //YUD.get("y").innerHTML = pos.y.toFixed(2);
644 if (item) {
644 if (item) {
645 if (previousPoint != item.datapoint) {
645 if (previousPoint != item.datapoint) {
646 previousPoint = item.datapoint;
646 previousPoint = item.datapoint;
647
647
648 var tooltip = YUD.get("tooltip");
648 var tooltip = YUD.get("tooltip");
649 if(tooltip) {
649 if(tooltip) {
650 tooltip.parentNode.removeChild(tooltip);
650 tooltip.parentNode.removeChild(tooltip);
651 }
651 }
652 var x = item.datapoint.x.toFixed(2);
652 var x = item.datapoint.x.toFixed(2);
653 var y = item.datapoint.y.toFixed(2);
653 var y = item.datapoint.y.toFixed(2);
654
654
655 if (!item.series.label){
655 if (!item.series.label){
656 item.series.label = 'commits';
656 item.series.label = 'commits';
657 }
657 }
658 var d = new Date(x*1000);
658 var d = new Date(x*1000);
659 var fd = d.toDateString()
659 var fd = d.toDateString()
660 var nr_commits = parseInt(y);
660 var nr_commits = parseInt(y);
661
661
662 var cur_data = dataset[item.series.label].data[item.dataIndex];
662 var cur_data = dataset[item.series.label].data[item.dataIndex];
663 var added = cur_data.added;
663 var added = cur_data.added;
664 var changed = cur_data.changed;
664 var changed = cur_data.changed;
665 var removed = cur_data.removed;
665 var removed = cur_data.removed;
666
666
667 var nr_commits_suffix = " ${_('commits')} ";
667 var nr_commits_suffix = " ${_('commits')} ";
668 var added_suffix = " ${_('files added')} ";
668 var added_suffix = " ${_('files added')} ";
669 var changed_suffix = " ${_('files changed')} ";
669 var changed_suffix = " ${_('files changed')} ";
670 var removed_suffix = " ${_('files removed')} ";
670 var removed_suffix = " ${_('files removed')} ";
671
671
672
672
673 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
673 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
674 if(added==1){added_suffix=" ${_('file added')} ";}
674 if(added==1){added_suffix=" ${_('file added')} ";}
675 if(changed==1){changed_suffix=" ${_('file changed')} ";}
675 if(changed==1){changed_suffix=" ${_('file changed')} ";}
676 if(removed==1){removed_suffix=" ${_('file removed')} ";}
676 if(removed==1){removed_suffix=" ${_('file removed')} ";}
677
677
678 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
678 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
679 +'<br/>'+
679 +'<br/>'+
680 nr_commits + nr_commits_suffix+'<br/>'+
680 nr_commits + nr_commits_suffix+'<br/>'+
681 added + added_suffix +'<br/>'+
681 added + added_suffix +'<br/>'+
682 changed + changed_suffix + '<br/>'+
682 changed + changed_suffix + '<br/>'+
683 removed + removed_suffix + '<br/>');
683 removed + removed_suffix + '<br/>');
684 }
684 }
685 }
685 }
686 else {
686 else {
687 var tooltip = YUD.get("tooltip");
687 var tooltip = YUD.get("tooltip");
688
688
689 if(tooltip) {
689 if(tooltip) {
690 tooltip.parentNode.removeChild(tooltip);
690 tooltip.parentNode.removeChild(tooltip);
691 }
691 }
692 previousPoint = null;
692 previousPoint = null;
693 }
693 }
694 }
694 }
695
695
696 /**
696 /**
697 * MAIN EXECUTION
697 * MAIN EXECUTION
698 */
698 */
699
699
700 var data = getDataAccordingToRanges(initial_ranges);
700 var data = getDataAccordingToRanges(initial_ranges);
701 generateCheckboxes(data);
701 generateCheckboxes(data);
702
702
703 //main plot
703 //main plot
704 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
704 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
705
705
706 //overview
706 //overview
707 var overview = YAHOO.widget.Flot(overviewContainer,
707 var overview = YAHOO.widget.Flot(overviewContainer,
708 overview_dataset, overview_options);
708 overview_dataset, overview_options);
709
709
710 //show initial selection on overview
710 //show initial selection on overview
711 overview.setSelection(initial_ranges);
711 overview.setSelection(initial_ranges);
712
712
713 plot.subscribe("plotselected", plotselected);
713 plot.subscribe("plotselected", plotselected);
714 plot.subscribe("plothover", plothover)
714 plot.subscribe("plothover", plothover)
715
715
716 overview.subscribe("plotselected", function (ranges) {
716 overview.subscribe("plotselected", function (ranges) {
717 plot.setSelection(ranges);
717 plot.setSelection(ranges);
718 });
718 });
719
719
720 // user choices on overview
720 // user choices on overview
721 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
721 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
722 }
722 }
723 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
723 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
724 </script>
724 </script>
725 %endif
725 %endif
726
726
727 </%def>
727 </%def>
General Comments 0
You need to be logged in to leave comments. Login now