##// END OF EJS Templates
Added api_key into user, api key get's generated again after password change...
marcink -
r1116:716911af beta
parent child Browse files
Show More
@@ -1,221 +1,221 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # RhodeCode - Pylons environment configuration #
4 4 # #
5 5 # The %(here)s variable will be replaced with the parent directory of this file#
6 6 ################################################################################
7 7
8 8 [DEFAULT]
9 9 debug = true
10 10 ################################################################################
11 11 ## Uncomment and replace with the address which should receive ##
12 12 ## any error reports after application crash ##
13 13 ## Additionally those settings will be used by RhodeCode mailing system ##
14 14 ################################################################################
15 15 #email_to = admin@localhost
16 16 #error_email_from = paste_error@localhost
17 17 #app_email_from = rhodecode-noreply@localhost
18 18 #error_message =
19 19
20 20 #smtp_server = mail.server.com
21 21 #smtp_username =
22 22 #smtp_password =
23 23 #smtp_port =
24 24 #smtp_use_tls = false
25 25 #smtp_use_ssl = true
26 26
27 27 [server:main]
28 28 ##nr of threads to spawn
29 29 threadpool_workers = 5
30 30
31 31 ##max request before thread respawn
32 32 threadpool_max_requests = 6
33 33
34 34 ##option to use threads of process
35 use_threadpool = false
35 use_threadpool = true
36 36
37 37 use = egg:Paste#http
38 38 host = 0.0.0.0
39 39 port = 5000
40 40
41 41 [app:main]
42 42 use = egg:rhodecode
43 43 full_stack = true
44 44 static_files = true
45 45 lang=en
46 46 cache_dir = %(here)s/data
47 47 index_dir = %(here)s/data/index
48 48 app_instance_uuid = develop
49 49 cut_off_limit = 256000
50 50 force_https = false
51 51 commit_parse_limit = 25
52 52 use_gravatar = true
53 53
54 54 ####################################
55 55 ### CELERY CONFIG ####
56 56 ####################################
57 57 use_celery = false
58 58 broker.host = localhost
59 59 broker.vhost = rabbitmqhost
60 60 broker.port = 5672
61 61 broker.user = rabbitmq
62 62 broker.password = qweqwe
63 63
64 64 celery.imports = rhodecode.lib.celerylib.tasks
65 65
66 66 celery.result.backend = amqp
67 67 celery.result.dburi = amqp://
68 68 celery.result.serialier = json
69 69
70 70 #celery.send.task.error.emails = true
71 71 #celery.amqp.task.result.expires = 18000
72 72
73 73 celeryd.concurrency = 2
74 74 #celeryd.log.file = celeryd.log
75 75 celeryd.log.level = debug
76 76 celeryd.max.tasks.per.child = 1
77 77
78 78 #tasks will never be sent to the queue, but executed locally instead.
79 79 celery.always.eager = false
80 80
81 81 ####################################
82 82 ### BEAKER CACHE ####
83 83 ####################################
84 84 beaker.cache.data_dir=%(here)s/data/cache/data
85 85 beaker.cache.lock_dir=%(here)s/data/cache/lock
86 86
87 87 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
88 88
89 89 beaker.cache.super_short_term.type=memory
90 90 beaker.cache.super_short_term.expire=10
91 91
92 92 beaker.cache.short_term.type=memory
93 93 beaker.cache.short_term.expire=60
94 94
95 95 beaker.cache.long_term.type=memory
96 96 beaker.cache.long_term.expire=36000
97 97
98 98 beaker.cache.sql_cache_short.type=memory
99 99 beaker.cache.sql_cache_short.expire=10
100 100
101 101 beaker.cache.sql_cache_med.type=memory
102 102 beaker.cache.sql_cache_med.expire=360
103 103
104 104 beaker.cache.sql_cache_long.type=file
105 105 beaker.cache.sql_cache_long.expire=3600
106 106
107 107 ####################################
108 108 ### BEAKER SESSION ####
109 109 ####################################
110 110 ## Type of storage used for the session, current types are
111 111 ## dbm, file, memcached, database, and memory.
112 112 ## The storage uses the Container API
113 113 ##that is also used by the cache system.
114 114 beaker.session.type = file
115 115
116 116 beaker.session.key = rhodecode
117 117 beaker.session.secret = g654dcno0-9873jhgfreyu
118 118 beaker.session.timeout = 36000
119 119
120 120 ##auto save the session to not to use .save()
121 121 beaker.session.auto = False
122 122
123 123 ##true exire at browser close
124 124 #beaker.session.cookie_expires = 3600
125 125
126 126
127 127 ################################################################################
128 128 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
129 129 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
130 130 ## execute malicious code after an exception is raised. ##
131 131 ################################################################################
132 132 #set debug = false
133 133
134 134 ##################################
135 135 ### LOGVIEW CONFIG ###
136 136 ##################################
137 137 logview.sqlalchemy = #faa
138 138 logview.pylons.templating = #bfb
139 139 logview.pylons.util = #eee
140 140
141 141 #########################################################
142 142 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
143 143 #########################################################
144 144 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
145 145 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
146 146 #sqlalchemy.db1.echo = False
147 147 #sqlalchemy.db1.pool_recycle = 3600
148 148 sqlalchemy.convert_unicode = true
149 149
150 150 ################################
151 151 ### LOGGING CONFIGURATION ####
152 152 ################################
153 153 [loggers]
154 154 keys = root, routes, rhodecode, sqlalchemy,beaker,templates
155 155
156 156 [handlers]
157 157 keys = console
158 158
159 159 [formatters]
160 160 keys = generic,color_formatter
161 161
162 162 #############
163 163 ## LOGGERS ##
164 164 #############
165 165 [logger_root]
166 166 level = NOTSET
167 167 handlers = console
168 168
169 169 [logger_routes]
170 170 level = DEBUG
171 171 handlers = console
172 172 qualname = routes.middleware
173 173 # "level = DEBUG" logs the route matched and routing variables.
174 174 propagate = 0
175 175
176 176 [logger_beaker]
177 177 level = ERROR
178 178 handlers = console
179 179 qualname = beaker.container
180 180 propagate = 0
181 181
182 182 [logger_templates]
183 183 level = INFO
184 184 handlers = console
185 185 qualname = pylons.templating
186 186 propagate = 0
187 187
188 188 [logger_rhodecode]
189 189 level = DEBUG
190 190 handlers = console
191 191 qualname = rhodecode
192 192 propagate = 0
193 193
194 194 [logger_sqlalchemy]
195 195 level = ERROR
196 196 handlers = console
197 197 qualname = sqlalchemy.engine
198 198 propagate = 0
199 199
200 200 ##############
201 201 ## HANDLERS ##
202 202 ##############
203 203
204 204 [handler_console]
205 205 class = StreamHandler
206 206 args = (sys.stderr,)
207 207 level = NOTSET
208 208 formatter = color_formatter
209 209
210 210 ################
211 211 ## FORMATTERS ##
212 212 ################
213 213
214 214 [formatter_generic]
215 215 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
216 216 datefmt = %Y-%m-%d %H:%M:%S
217 217
218 218 [formatter_color_formatter]
219 219 class=rhodecode.lib.colored_formatter.ColorFormatter
220 220 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
221 221 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
@@ -1,220 +1,220 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # RhodeCode - Pylons environment configuration #
4 4 # #
5 5 # The %(here)s variable will be replaced with the parent directory of this file#
6 6 ################################################################################
7 7
8 8 [DEFAULT]
9 9 debug = true
10 10 ################################################################################
11 11 ## Uncomment and replace with the address which should receive ##
12 12 ## any error reports after application crash ##
13 13 ## Additionally those settings will be used by RhodeCode mailing system ##
14 14 ################################################################################
15 15 #email_to = admin@localhost
16 16 #error_email_from = paste_error@localhost
17 17 #app_email_from = rhodecode-noreply@localhost
18 18 #error_message =
19 19
20 20 #smtp_server = mail.server.com
21 21 #smtp_username =
22 22 #smtp_password =
23 23 #smtp_port =
24 24 #smtp_use_tls = false
25 25 #smtp_use_ssl = true
26 26
27 27 [server:main]
28 28 ##nr of threads to spawn
29 29 threadpool_workers = 5
30 30
31 31 ##max request before thread respawn
32 threadpool_max_requests = 2
32 threadpool_max_requests = 6
33 33
34 34 ##option to use threads of process
35 35 use_threadpool = true
36 36
37 37 use = egg:Paste#http
38 38 host = 127.0.0.1
39 39 port = 8001
40 40
41 41 [app:main]
42 42 use = egg:rhodecode
43 43 full_stack = true
44 44 static_files = false
45 45 lang=en
46 46 cache_dir = %(here)s/data
47 47 index_dir = %(here)s/data/index
48 48 cut_off_limit = 256000
49 49 force_https = false
50 commit_parse_limit = 250
50 commit_parse_limit = 25
51 51 use_gravatar = true
52 52
53 53 ####################################
54 54 ### CELERY CONFIG ####
55 55 ####################################
56 56 use_celery = false
57 57 broker.host = localhost
58 58 broker.vhost = rabbitmqhost
59 59 broker.port = 5672
60 60 broker.user = rabbitmq
61 61 broker.password = qweqwe
62 62
63 63 celery.imports = rhodecode.lib.celerylib.tasks
64 64
65 65 celery.result.backend = amqp
66 66 celery.result.dburi = amqp://
67 67 celery.result.serialier = json
68 68
69 69 #celery.send.task.error.emails = true
70 70 #celery.amqp.task.result.expires = 18000
71 71
72 72 celeryd.concurrency = 2
73 73 #celeryd.log.file = celeryd.log
74 74 celeryd.log.level = debug
75 75 celeryd.max.tasks.per.child = 1
76 76
77 77 #tasks will never be sent to the queue, but executed locally instead.
78 78 celery.always.eager = false
79 79
80 80 ####################################
81 81 ### BEAKER CACHE ####
82 82 ####################################
83 83 beaker.cache.data_dir=%(here)s/data/cache/data
84 84 beaker.cache.lock_dir=%(here)s/data/cache/lock
85 85
86 86 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
87 87
88 88 beaker.cache.super_short_term.type=memory
89 89 beaker.cache.super_short_term.expire=10
90 90
91 91 beaker.cache.short_term.type=memory
92 92 beaker.cache.short_term.expire=60
93 93
94 94 beaker.cache.long_term.type=memory
95 95 beaker.cache.long_term.expire=36000
96 96
97
98 97 beaker.cache.sql_cache_short.type=memory
99 98 beaker.cache.sql_cache_short.expire=10
100 99
101 100 beaker.cache.sql_cache_med.type=memory
102 101 beaker.cache.sql_cache_med.expire=360
103 102
104 103 beaker.cache.sql_cache_long.type=file
105 104 beaker.cache.sql_cache_long.expire=3600
106 105
107 106 ####################################
108 107 ### BEAKER SESSION ####
109 108 ####################################
110 109 ## Type of storage used for the session, current types are
111 110 ## dbm, file, memcached, database, and memory.
112 111 ## The storage uses the Container API
113 112 ##that is also used by the cache system.
114 113 beaker.session.type = file
115 114
116 115 beaker.session.key = rhodecode
117 116 beaker.session.secret = g654dcno0-9873jhgfreyu
118 117 beaker.session.timeout = 36000
119 118
120 119 ##auto save the session to not to use .save()
121 120 beaker.session.auto = False
122 121
123 122 ##true exire at browser close
124 123 #beaker.session.cookie_expires = 3600
125 124
126 125
127 126 ################################################################################
128 127 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
129 128 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
130 129 ## execute malicious code after an exception is raised. ##
131 130 ################################################################################
132 131 set debug = false
133 132
134 133 ##################################
135 134 ### LOGVIEW CONFIG ###
136 135 ##################################
137 136 logview.sqlalchemy = #faa
138 137 logview.pylons.templating = #bfb
139 138 logview.pylons.util = #eee
140 139
141 140 #########################################################
142 141 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
143 142 #########################################################
144 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
143 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
144 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
145 145 #sqlalchemy.db1.echo = False
146 146 #sqlalchemy.db1.pool_recycle = 3600
147 147 sqlalchemy.convert_unicode = true
148 148
149 149 ################################
150 150 ### LOGGING CONFIGURATION ####
151 151 ################################
152 152 [loggers]
153 153 keys = root, routes, rhodecode, sqlalchemy,beaker,templates
154 154
155 155 [handlers]
156 156 keys = console
157 157
158 158 [formatters]
159 159 keys = generic,color_formatter
160 160
161 161 #############
162 162 ## LOGGERS ##
163 163 #############
164 164 [logger_root]
165 165 level = INFO
166 166 handlers = console
167 167
168 168 [logger_routes]
169 169 level = INFO
170 170 handlers = console
171 171 qualname = routes.middleware
172 172 # "level = DEBUG" logs the route matched and routing variables.
173 173 propagate = 0
174 174
175 175 [logger_beaker]
176 176 level = ERROR
177 177 handlers = console
178 178 qualname = beaker.container
179 179 propagate = 0
180 180
181 181 [logger_templates]
182 182 level = INFO
183 183 handlers = console
184 184 qualname = pylons.templating
185 185 propagate = 0
186 186
187 187 [logger_rhodecode]
188 188 level = DEBUG
189 189 handlers = console
190 190 qualname = rhodecode
191 191 propagate = 0
192 192
193 193 [logger_sqlalchemy]
194 194 level = ERROR
195 195 handlers = console
196 196 qualname = sqlalchemy.engine
197 197 propagate = 0
198 198
199 199 ##############
200 200 ## HANDLERS ##
201 201 ##############
202 202
203 203 [handler_console]
204 204 class = StreamHandler
205 205 args = (sys.stderr,)
206 206 level = NOTSET
207 207 formatter = color_formatter
208 208
209 209 ################
210 210 ## FORMATTERS ##
211 211 ################
212 212
213 213 [formatter_generic]
214 214 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
215 215 datefmt = %Y-%m-%d %H:%M:%S
216 216
217 217 [formatter_color_formatter]
218 218 class=rhodecode.lib.colored_formatter.ColorFormatter
219 219 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
220 220 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
@@ -1,29 +1,38 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.__init__
4 4 ~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Some simple helper functions
7 7
8 8 :created_on: Jan 5, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 def str2bool(v):
29 29 return v.lower() in ["yes", "true", "t", "1"] if v else None
30
31 def generate_api_key(username, salt=None):
32 from tempfile import _RandomNameSequence
33 import hashlib
34
35 if salt is None:
36 salt = _RandomNameSequence().next()
37
38 return hashlib.sha1(username + salt).hexdigest()
@@ -1,614 +1,621 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.auth
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 authentication and permission libraries
7 7
8 8 :created_on: Apr 4, 2010
9 9 :copyright: (c) 2010 by marcink.
10 10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 11 """
12 12 # This program is free software; you can redistribute it and/or
13 13 # modify it under the terms of the GNU General Public License
14 14 # as published by the Free Software Foundation; version 2
15 15 # of the License or (at your opinion) any later version of the license.
16 16 #
17 17 # This program is distributed in the hope that it will be useful,
18 18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 20 # GNU General Public License for more details.
21 21 #
22 22 # You should have received a copy of the GNU General Public License
23 23 # along with this program; if not, write to the Free Software
24 24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 25 # MA 02110-1301, USA.
26 26
27 27 import bcrypt
28 28 import random
29 29 import logging
30 30 import traceback
31
31 import hashlib
32 from tempfile import _RandomNameSequence
32 33 from decorator import decorator
33 34
34 35 from pylons import config, session, url, request
35 36 from pylons.controllers.util import abort, redirect
36 37 from pylons.i18n.translation import _
37 38
38 39 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
39 40 from rhodecode.lib.utils import get_repo_slug
40 41 from rhodecode.lib.auth_ldap import AuthLdap
41 42
42 43 from rhodecode.model import meta
43 44 from rhodecode.model.user import UserModel
44 45 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
45 46 UserToPerm, UsersGroupToPerm, UsersGroupMember
46 47
47 48
48 49 log = logging.getLogger(__name__)
49 50
50 51
51 52 PERM_WEIGHTS = {'repository.none':0,
52 53 'repository.read':1,
53 54 'repository.write':3,
54 55 'repository.admin':3}
55 56
56 57
57 58 class PasswordGenerator(object):
58 59 """This is a simple class for generating password from
59 60 different sets of characters
60 61 usage:
61 62 passwd_gen = PasswordGenerator()
62 63 #print 8-letter password containing only big and small letters of alphabet
63 64 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
64 65 """
65 66 ALPHABETS_NUM = r'''1234567890'''#[0]
66 67 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
67 68 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
68 69 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
69 70 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
70 71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
71 72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
72 73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
73 74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
74 75
75 76 def __init__(self, passwd=''):
76 77 self.passwd = passwd
77 78
78 79 def gen_password(self, len, type):
79 80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
80 81 return self.passwd
81 82
82 83
83 84 def get_crypt_password(password):
84 85 """Cryptographic function used for password hashing based on pybcrypt
85 86
86 87 :param password: password to hash
87 88 """
88 89 return bcrypt.hashpw(password, bcrypt.gensalt(10))
89 90
91 def generate_api_key(username, salt=None):
92 if salt is None:
93 salt = _RandomNameSequence().next()
94
95 return hashlib.sha1(username + salt).hexdigest()
96
90 97 def check_password(password, hashed):
91 98 return bcrypt.hashpw(password, hashed) == hashed
92 99
93 100 def authfunc(environ, username, password):
94 101 """Dummy authentication function used in Mercurial/Git/ and access control,
95 102
96 103 :param environ: needed only for using in Basic auth
97 104 """
98 105 return authenticate(username, password)
99 106
100 107
101 108 def authenticate(username, password):
102 109 """Authentication function used for access control,
103 110 firstly checks for db authentication then if ldap is enabled for ldap
104 111 authentication, also creates ldap user if not in database
105 112
106 113 :param username: username
107 114 :param password: password
108 115 """
109 116 user_model = UserModel()
110 117 user = user_model.get_by_username(username, cache=False)
111 118
112 119 log.debug('Authenticating user using RhodeCode account')
113 120 if user is not None and not user.ldap_dn:
114 121 if user.active:
115 122
116 123 if user.username == 'default' and user.active:
117 124 log.info('user %s authenticated correctly as anonymous user',
118 125 username)
119 126 return True
120 127
121 128 elif user.username == username and check_password(password, user.password):
122 129 log.info('user %s authenticated correctly', username)
123 130 return True
124 131 else:
125 132 log.warning('user %s is disabled', username)
126 133
127 134 else:
128 135 log.debug('Regular authentication failed')
129 136 user_obj = user_model.get_by_username(username, cache=False,
130 137 case_insensitive=True)
131 138
132 139 if user_obj is not None and not user_obj.ldap_dn:
133 140 log.debug('this user already exists as non ldap')
134 141 return False
135 142
136 143 from rhodecode.model.settings import SettingsModel
137 144 ldap_settings = SettingsModel().get_ldap_settings()
138 145
139 146 #======================================================================
140 147 # FALLBACK TO LDAP AUTH IF ENABLE
141 148 #======================================================================
142 149 if ldap_settings.get('ldap_active', False):
143 150 log.debug("Authenticating user using ldap")
144 151 kwargs = {
145 152 'server':ldap_settings.get('ldap_host', ''),
146 153 'base_dn':ldap_settings.get('ldap_base_dn', ''),
147 154 'port':ldap_settings.get('ldap_port'),
148 155 'bind_dn':ldap_settings.get('ldap_dn_user'),
149 156 'bind_pass':ldap_settings.get('ldap_dn_pass'),
150 157 'use_ldaps':ldap_settings.get('ldap_ldaps'),
151 158 'tls_reqcert':ldap_settings.get('ldap_tls_reqcert'),
152 159 'ldap_filter':ldap_settings.get('ldap_filter'),
153 160 'search_scope':ldap_settings.get('ldap_search_scope'),
154 161 'attr_login':ldap_settings.get('ldap_attr_login'),
155 162 'ldap_version':3,
156 163 }
157 164 log.debug('Checking for ldap authentication')
158 165 try:
159 166 aldap = AuthLdap(**kwargs)
160 167 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username, password)
161 168 log.debug('Got ldap DN response %s', user_dn)
162 169
163 170 user_attrs = {
164 171 'name' : ldap_attrs[ldap_settings.get('ldap_attr_firstname')][0],
165 172 'lastname' : ldap_attrs[ldap_settings.get('ldap_attr_lastname')][0],
166 173 'email' : ldap_attrs[ldap_settings.get('ldap_attr_email')][0],
167 174 }
168 175
169 176 if user_model.create_ldap(username, password, user_dn, user_attrs):
170 177 log.info('created new ldap user %s', username)
171 178
172 179 return True
173 180 except (LdapUsernameError, LdapPasswordError,):
174 181 pass
175 182 except (Exception,):
176 183 log.error(traceback.format_exc())
177 184 pass
178 185 return False
179 186
180 187 class AuthUser(object):
181 188 """A simple object that handles a mercurial username for authentication
182 189 """
183 190
184 191 def __init__(self):
185 192 self.username = 'None'
186 193 self.name = ''
187 194 self.lastname = ''
188 195 self.email = ''
189 196 self.user_id = None
190 197 self.is_authenticated = False
191 198 self.is_admin = False
192 199 self.permissions = {}
193 200
194 201 def __repr__(self):
195 202 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
196 203
197 204 def set_available_permissions(config):
198 205 """This function will propagate pylons globals with all available defined
199 206 permission given in db. We don't want to check each time from db for new
200 207 permissions since adding a new permission also requires application restart
201 208 ie. to decorate new views with the newly created permission
202 209
203 210 :param config: current pylons config instance
204 211
205 212 """
206 213 log.info('getting information about all available permissions')
207 214 try:
208 215 sa = meta.Session()
209 216 all_perms = sa.query(Permission).all()
210 217 except:
211 218 pass
212 219 finally:
213 220 meta.Session.remove()
214 221
215 222 config['available_permissions'] = [x.permission_name for x in all_perms]
216 223
217 224 def fill_perms(user):
218 225 """Fills user permission attribute with permissions taken from database
219 226 works for permissions given for repositories, and for permissions that
220 227 as part of beeing group member
221 228
222 229 :param user: user instance to fill his perms
223 230 """
224 231
225 232 sa = meta.Session()
226 233 user.permissions['repositories'] = {}
227 234 user.permissions['global'] = set()
228 235
229 236 #===========================================================================
230 237 # fetch default permissions
231 238 #===========================================================================
232 239 default_user = UserModel().get_by_username('default', cache=True)
233 240
234 241 default_perms = sa.query(RepoToPerm, Repository, Permission)\
235 242 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
236 243 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
237 244 .filter(RepoToPerm.user == default_user).all()
238 245
239 246 if user.is_admin:
240 247 #=======================================================================
241 248 # #admin have all default rights set to admin
242 249 #=======================================================================
243 250 user.permissions['global'].add('hg.admin')
244 251
245 252 for perm in default_perms:
246 253 p = 'repository.admin'
247 254 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
248 255
249 256 else:
250 257 #=======================================================================
251 258 # set default permissions
252 259 #=======================================================================
253 260
254 261 #default global
255 262 default_global_perms = sa.query(UserToPerm)\
256 263 .filter(UserToPerm.user == sa.query(User)\
257 264 .filter(User.username == 'default').one())
258 265
259 266 for perm in default_global_perms:
260 267 user.permissions['global'].add(perm.permission.permission_name)
261 268
262 269 #default for repositories
263 270 for perm in default_perms:
264 271 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
265 272 #disable defaults for private repos,
266 273 p = 'repository.none'
267 274 elif perm.Repository.user_id == user.user_id:
268 275 #set admin if owner
269 276 p = 'repository.admin'
270 277 else:
271 278 p = perm.Permission.permission_name
272 279
273 280 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
274 281
275 282 #=======================================================================
276 283 # overwrite default with user permissions if any
277 284 #=======================================================================
278 285 user_perms = sa.query(RepoToPerm, Permission, Repository)\
279 286 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
280 287 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
281 288 .filter(RepoToPerm.user_id == user.user_id).all()
282 289
283 290 for perm in user_perms:
284 291 if perm.Repository.user_id == user.user_id:#set admin if owner
285 292 p = 'repository.admin'
286 293 else:
287 294 p = perm.Permission.permission_name
288 295 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
289 296
290 297
291 298 #=======================================================================
292 299 # check if user is part of groups for this repository and fill in
293 300 # (or replace with higher) permissions
294 301 #=======================================================================
295 302 user_perms_from_users_groups = sa.query(UsersGroupToPerm, Permission, Repository,)\
296 303 .join((Repository, UsersGroupToPerm.repository_id == Repository.repo_id))\
297 304 .join((Permission, UsersGroupToPerm.permission_id == Permission.permission_id))\
298 305 .join((UsersGroupMember, UsersGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
299 306 .filter(UsersGroupMember.user_id == user.user_id).all()
300 307
301 308 for perm in user_perms_from_users_groups:
302 309 p = perm.Permission.permission_name
303 310 cur_perm = user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name]
304 311 #overwrite permission only if it's greater than permission given from other sources
305 312 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
306 313 user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name] = p
307 314
308 315 meta.Session.remove()
309 316 return user
310 317
311 318 def get_user(session):
312 319 """Gets user from session, and wraps permissions into user
313 320
314 321 :param session:
315 322 """
316 323 user = session.get('rhodecode_user', AuthUser())
317 324 #if the user is not logged in we check for anonymous access
318 325 #if user is logged and it's a default user check if we still have anonymous
319 326 #access enabled
320 327 if user.user_id is None or user.username == 'default':
321 328 anonymous_user = UserModel().get_by_username('default', cache=True)
322 329 if anonymous_user.active is True:
323 330 #then we set this user is logged in
324 331 user.is_authenticated = True
325 332 user.user_id = anonymous_user.user_id
326 333 else:
327 334 user.is_authenticated = False
328 335
329 336 if user.is_authenticated:
330 337 user = UserModel().fill_data(user)
331 338
332 339 user = fill_perms(user)
333 340 session['rhodecode_user'] = user
334 341 session.save()
335 342 return user
336 343
337 344 #===============================================================================
338 345 # CHECK DECORATORS
339 346 #===============================================================================
340 347 class LoginRequired(object):
341 348 """Must be logged in to execute this function else
342 349 redirect to login page"""
343 350
344 351 def __call__(self, func):
345 352 return decorator(self.__wrapper, func)
346 353
347 354 def __wrapper(self, func, *fargs, **fkwargs):
348 355 user = session.get('rhodecode_user', AuthUser())
349 356 log.debug('Checking login required for user:%s', user.username)
350 357 if user.is_authenticated:
351 358 log.debug('user %s is authenticated', user.username)
352 359 return func(*fargs, **fkwargs)
353 360 else:
354 361 log.warn('user %s not authenticated', user.username)
355 362
356 363 p = ''
357 364 if request.environ.get('SCRIPT_NAME') != '/':
358 365 p += request.environ.get('SCRIPT_NAME')
359 366
360 367 p += request.environ.get('PATH_INFO')
361 368 if request.environ.get('QUERY_STRING'):
362 369 p += '?' + request.environ.get('QUERY_STRING')
363 370
364 371 log.debug('redirecting to login page with %s', p)
365 372 return redirect(url('login_home', came_from=p))
366 373
367 374 class NotAnonymous(object):
368 375 """Must be logged in to execute this function else
369 376 redirect to login page"""
370 377
371 378 def __call__(self, func):
372 379 return decorator(self.__wrapper, func)
373 380
374 381 def __wrapper(self, func, *fargs, **fkwargs):
375 382 user = session.get('rhodecode_user', AuthUser())
376 383 log.debug('Checking if user is not anonymous')
377 384
378 385 anonymous = user.username == 'default'
379 386
380 387 if anonymous:
381 388 p = ''
382 389 if request.environ.get('SCRIPT_NAME') != '/':
383 390 p += request.environ.get('SCRIPT_NAME')
384 391
385 392 p += request.environ.get('PATH_INFO')
386 393 if request.environ.get('QUERY_STRING'):
387 394 p += '?' + request.environ.get('QUERY_STRING')
388 395
389 396 import rhodecode.lib.helpers as h
390 397 h.flash(_('You need to be a registered user to perform this action'),
391 398 category='warning')
392 399 return redirect(url('login_home', came_from=p))
393 400 else:
394 401 return func(*fargs, **fkwargs)
395 402
396 403 class PermsDecorator(object):
397 404 """Base class for decorators"""
398 405
399 406 def __init__(self, *required_perms):
400 407 available_perms = config['available_permissions']
401 408 for perm in required_perms:
402 409 if perm not in available_perms:
403 410 raise Exception("'%s' permission is not defined" % perm)
404 411 self.required_perms = set(required_perms)
405 412 self.user_perms = None
406 413
407 414 def __call__(self, func):
408 415 return decorator(self.__wrapper, func)
409 416
410 417
411 418 def __wrapper(self, func, *fargs, **fkwargs):
412 419 # _wrapper.__name__ = func.__name__
413 420 # _wrapper.__dict__.update(func.__dict__)
414 421 # _wrapper.__doc__ = func.__doc__
415 422 self.user = session.get('rhodecode_user', AuthUser())
416 423 self.user_perms = self.user.permissions
417 424 log.debug('checking %s permissions %s for %s %s',
418 425 self.__class__.__name__, self.required_perms, func.__name__,
419 426 self.user)
420 427
421 428 if self.check_permissions():
422 429 log.debug('Permission granted for %s %s', func.__name__, self.user)
423 430
424 431 return func(*fargs, **fkwargs)
425 432
426 433 else:
427 434 log.warning('Permission denied for %s %s', func.__name__, self.user)
428 435 #redirect with forbidden ret code
429 436 return abort(403)
430 437
431 438
432 439
433 440 def check_permissions(self):
434 441 """Dummy function for overriding"""
435 442 raise Exception('You have to write this function in child class')
436 443
437 444 class HasPermissionAllDecorator(PermsDecorator):
438 445 """Checks for access permission for all given predicates. All of them
439 446 have to be meet in order to fulfill the request
440 447 """
441 448
442 449 def check_permissions(self):
443 450 if self.required_perms.issubset(self.user_perms.get('global')):
444 451 return True
445 452 return False
446 453
447 454
448 455 class HasPermissionAnyDecorator(PermsDecorator):
449 456 """Checks for access permission for any of given predicates. In order to
450 457 fulfill the request any of predicates must be meet
451 458 """
452 459
453 460 def check_permissions(self):
454 461 if self.required_perms.intersection(self.user_perms.get('global')):
455 462 return True
456 463 return False
457 464
458 465 class HasRepoPermissionAllDecorator(PermsDecorator):
459 466 """Checks for access permission for all given predicates for specific
460 467 repository. All of them have to be meet in order to fulfill the request
461 468 """
462 469
463 470 def check_permissions(self):
464 471 repo_name = get_repo_slug(request)
465 472 try:
466 473 user_perms = set([self.user_perms['repositories'][repo_name]])
467 474 except KeyError:
468 475 return False
469 476 if self.required_perms.issubset(user_perms):
470 477 return True
471 478 return False
472 479
473 480
474 481 class HasRepoPermissionAnyDecorator(PermsDecorator):
475 482 """Checks for access permission for any of given predicates for specific
476 483 repository. In order to fulfill the request any of predicates must be meet
477 484 """
478 485
479 486 def check_permissions(self):
480 487 repo_name = get_repo_slug(request)
481 488
482 489 try:
483 490 user_perms = set([self.user_perms['repositories'][repo_name]])
484 491 except KeyError:
485 492 return False
486 493 if self.required_perms.intersection(user_perms):
487 494 return True
488 495 return False
489 496 #===============================================================================
490 497 # CHECK FUNCTIONS
491 498 #===============================================================================
492 499
493 500 class PermsFunction(object):
494 501 """Base function for other check functions"""
495 502
496 503 def __init__(self, *perms):
497 504 available_perms = config['available_permissions']
498 505
499 506 for perm in perms:
500 507 if perm not in available_perms:
501 508 raise Exception("'%s' permission in not defined" % perm)
502 509 self.required_perms = set(perms)
503 510 self.user_perms = None
504 511 self.granted_for = ''
505 512 self.repo_name = None
506 513
507 514 def __call__(self, check_Location=''):
508 515 user = session.get('rhodecode_user', False)
509 516 if not user:
510 517 return False
511 518 self.user_perms = user.permissions
512 519 self.granted_for = user.username
513 520 log.debug('checking %s %s %s', self.__class__.__name__,
514 521 self.required_perms, user)
515 522
516 523 if self.check_permissions():
517 524 log.debug('Permission granted for %s @ %s %s', self.granted_for,
518 525 check_Location, user)
519 526 return True
520 527
521 528 else:
522 529 log.warning('Permission denied for %s @ %s %s', self.granted_for,
523 530 check_Location, user)
524 531 return False
525 532
526 533 def check_permissions(self):
527 534 """Dummy function for overriding"""
528 535 raise Exception('You have to write this function in child class')
529 536
530 537 class HasPermissionAll(PermsFunction):
531 538 def check_permissions(self):
532 539 if self.required_perms.issubset(self.user_perms.get('global')):
533 540 return True
534 541 return False
535 542
536 543 class HasPermissionAny(PermsFunction):
537 544 def check_permissions(self):
538 545 if self.required_perms.intersection(self.user_perms.get('global')):
539 546 return True
540 547 return False
541 548
542 549 class HasRepoPermissionAll(PermsFunction):
543 550
544 551 def __call__(self, repo_name=None, check_Location=''):
545 552 self.repo_name = repo_name
546 553 return super(HasRepoPermissionAll, self).__call__(check_Location)
547 554
548 555 def check_permissions(self):
549 556 if not self.repo_name:
550 557 self.repo_name = get_repo_slug(request)
551 558
552 559 try:
553 560 self.user_perms = set([self.user_perms['repositories']\
554 561 [self.repo_name]])
555 562 except KeyError:
556 563 return False
557 564 self.granted_for = self.repo_name
558 565 if self.required_perms.issubset(self.user_perms):
559 566 return True
560 567 return False
561 568
562 569 class HasRepoPermissionAny(PermsFunction):
563 570
564 571 def __call__(self, repo_name=None, check_Location=''):
565 572 self.repo_name = repo_name
566 573 return super(HasRepoPermissionAny, self).__call__(check_Location)
567 574
568 575 def check_permissions(self):
569 576 if not self.repo_name:
570 577 self.repo_name = get_repo_slug(request)
571 578
572 579 try:
573 580 self.user_perms = set([self.user_perms['repositories']\
574 581 [self.repo_name]])
575 582 except KeyError:
576 583 return False
577 584 self.granted_for = self.repo_name
578 585 if self.required_perms.intersection(self.user_perms):
579 586 return True
580 587 return False
581 588
582 589 #===============================================================================
583 590 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
584 591 #===============================================================================
585 592
586 593 class HasPermissionAnyMiddleware(object):
587 594 def __init__(self, *perms):
588 595 self.required_perms = set(perms)
589 596
590 597 def __call__(self, user, repo_name):
591 598 usr = AuthUser()
592 599 usr.user_id = user.user_id
593 600 usr.username = user.username
594 601 usr.is_admin = user.admin
595 602
596 603 try:
597 604 self.user_perms = set([fill_perms(usr)\
598 605 .permissions['repositories'][repo_name]])
599 606 except:
600 607 self.user_perms = set()
601 608 self.granted_for = ''
602 609 self.username = user.username
603 610 self.repo_name = repo_name
604 611 return self.check_permissions()
605 612
606 613 def check_permissions(self):
607 614 log.debug('checking mercurial protocol '
608 615 'permissions %s for user:%s repository:%s', self.user_perms,
609 616 self.username, self.repo_name)
610 617 if self.required_perms.intersection(self.user_perms):
611 618 log.debug('permission granted')
612 619 return True
613 620 log.debug('permission denied')
614 621 return False
@@ -1,408 +1,409 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.celerylib.tasks
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 RhodeCode task modules, containing all task that suppose to be run
7 7 by celery daemon
8 8
9 9 :created_on: Oct 6, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software; you can redistribute it and/or
15 15 # modify it under the terms of the GNU General Public License
16 16 # as published by the Free Software Foundation; version 2
17 17 # of the License or (at your opinion) any later version of the license.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program; if not, write to the Free Software
26 26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 27 # MA 02110-1301, USA.
28 28 from celery.decorators import task
29 29
30 30 import os
31 31 import traceback
32 32 import logging
33 33
34 34 from time import mktime
35 35 from operator import itemgetter
36 36
37 37 from pylons import config
38 38 from pylons.i18n.translation import _
39 39
40 40 from rhodecode.lib.celerylib import run_task, locked_task, str2bool
41 41 from rhodecode.lib.helpers import person
42 42 from rhodecode.lib.smtp_mailer import SmtpMailer
43 43 from rhodecode.lib.utils import OrderedDict, add_cache
44 44 from rhodecode.model import init_model
45 45 from rhodecode.model import meta
46 46 from rhodecode.model.db import RhodeCodeUi
47 47
48 48 from vcs.backends import get_repo
49 49
50 50 from sqlalchemy import engine_from_config
51 51
52 52 add_cache(config)
53 53
54 54 try:
55 55 import json
56 56 except ImportError:
57 57 #python 2.5 compatibility
58 58 import simplejson as json
59 59
60 60 __all__ = ['whoosh_index', 'get_commits_stats',
61 61 'reset_user_password', 'send_email']
62 62
63 63 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
64 64
65 65 def get_session():
66 66 if CELERY_ON:
67 67 engine = engine_from_config(config, 'sqlalchemy.db1.')
68 68 init_model(engine)
69 69 sa = meta.Session()
70 70 return sa
71 71
72 72 def get_repos_path():
73 73 sa = get_session()
74 74 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
75 75 return q.ui_value
76 76
77 77 @task(ignore_result=True)
78 78 @locked_task
79 79 def whoosh_index(repo_location, full_index):
80 80 #log = whoosh_index.get_logger()
81 81 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
82 82 index_location = config['index_dir']
83 83 WhooshIndexingDaemon(index_location=index_location,
84 84 repo_location=repo_location, sa=get_session())\
85 85 .run(full_index=full_index)
86 86
87 87 @task(ignore_result=True)
88 88 @locked_task
89 89 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
90 90 try:
91 91 log = get_commits_stats.get_logger()
92 92 except:
93 93 log = logging.getLogger(__name__)
94 94
95 95 from rhodecode.model.db import Statistics, Repository
96 96
97 97 #for js data compatibilty
98 98 author_key_cleaner = lambda k: person(k).replace('"', "")
99 99
100 100 commits_by_day_author_aggregate = {}
101 101 commits_by_day_aggregate = {}
102 102 repos_path = get_repos_path()
103 103 p = os.path.join(repos_path, repo_name)
104 104 repo = get_repo(p)
105 105
106 106 skip_date_limit = True
107 107 parse_limit = int(config['app_conf'].get('commit_parse_limit'))
108 108 last_rev = 0
109 109 last_cs = None
110 110 timegetter = itemgetter('time')
111 111
112 112 sa = get_session()
113 113
114 114 dbrepo = sa.query(Repository)\
115 115 .filter(Repository.repo_name == repo_name).scalar()
116 116 cur_stats = sa.query(Statistics)\
117 117 .filter(Statistics.repository == dbrepo).scalar()
118 118
119 119 if cur_stats is not None:
120 120 last_rev = cur_stats.stat_on_revision
121 121
122 122 #return if repo is empty
123 123 if not repo.revisions:
124 124 return True
125 125
126 126 if last_rev == repo.get_changeset().revision and len(repo.revisions) > 1:
127 127 #pass silently without any work if we're not on first revision or
128 128 #current state of parsing revision(from db marker) is the last revision
129 129 return True
130 130
131 131 if cur_stats:
132 132 commits_by_day_aggregate = OrderedDict(
133 133 json.loads(
134 134 cur_stats.commit_activity_combined))
135 135 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
136 136
137 137 log.debug('starting parsing %s', parse_limit)
138 138 lmktime = mktime
139 139
140 140 last_rev = last_rev + 1 if last_rev > 0 else last_rev
141 141
142 142 for cs in repo[last_rev:last_rev + parse_limit]:
143 143 last_cs = cs #remember last parsed changeset
144 144 k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
145 145 cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
146 146
147 147 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
148 148 try:
149 149 l = [timegetter(x) for x in commits_by_day_author_aggregate\
150 150 [author_key_cleaner(cs.author)]['data']]
151 151 time_pos = l.index(k)
152 152 except ValueError:
153 153 time_pos = False
154 154
155 155 if time_pos >= 0 and time_pos is not False:
156 156
157 157 datadict = commits_by_day_author_aggregate\
158 158 [author_key_cleaner(cs.author)]['data'][time_pos]
159 159
160 160 datadict["commits"] += 1
161 161 datadict["added"] += len(cs.added)
162 162 datadict["changed"] += len(cs.changed)
163 163 datadict["removed"] += len(cs.removed)
164 164
165 165 else:
166 166 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
167 167
168 168 datadict = {"time":k,
169 169 "commits":1,
170 170 "added":len(cs.added),
171 171 "changed":len(cs.changed),
172 172 "removed":len(cs.removed),
173 173 }
174 174 commits_by_day_author_aggregate\
175 175 [author_key_cleaner(cs.author)]['data'].append(datadict)
176 176
177 177 else:
178 178 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
179 179 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
180 180 "label":author_key_cleaner(cs.author),
181 181 "data":[{"time":k,
182 182 "commits":1,
183 183 "added":len(cs.added),
184 184 "changed":len(cs.changed),
185 185 "removed":len(cs.removed),
186 186 }],
187 187 "schema":["commits"],
188 188 }
189 189
190 190 #gather all data by day
191 191 if commits_by_day_aggregate.has_key(k):
192 192 commits_by_day_aggregate[k] += 1
193 193 else:
194 194 commits_by_day_aggregate[k] = 1
195 195
196 196 overview_data = sorted(commits_by_day_aggregate.items(), key=itemgetter(0))
197 197 if not commits_by_day_author_aggregate:
198 198 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
199 199 "label":author_key_cleaner(repo.contact),
200 200 "data":[0, 1],
201 201 "schema":["commits"],
202 202 }
203 203
204 204 stats = cur_stats if cur_stats else Statistics()
205 205 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
206 206 stats.commit_activity_combined = json.dumps(overview_data)
207 207
208 208 log.debug('last revison %s', last_rev)
209 209 leftovers = len(repo.revisions[last_rev:])
210 210 log.debug('revisions to parse %s', leftovers)
211 211
212 212 if last_rev == 0 or leftovers < parse_limit:
213 213 log.debug('getting code trending stats')
214 214 stats.languages = json.dumps(__get_codes_stats(repo_name))
215 215
216 216 try:
217 217 stats.repository = dbrepo
218 218 stats.stat_on_revision = last_cs.revision if last_cs else 0
219 219 sa.add(stats)
220 220 sa.commit()
221 221 except:
222 222 log.error(traceback.format_exc())
223 223 sa.rollback()
224 224 return False
225 225 if len(repo.revisions) > 1:
226 226 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
227 227
228 228 return True
229 229
230 230 @task(ignore_result=True)
231 231 def reset_user_password(user_email):
232 232 try:
233 233 log = reset_user_password.get_logger()
234 234 except:
235 235 log = logging.getLogger(__name__)
236 236
237 237 from rhodecode.lib import auth
238 238 from rhodecode.model.db import User
239 239
240 240 try:
241 241 try:
242 242 sa = get_session()
243 243 user = sa.query(User).filter(User.email == user_email).scalar()
244 244 new_passwd = auth.PasswordGenerator().gen_password(8,
245 245 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
246 246 if user:
247 247 user.password = auth.get_crypt_password(new_passwd)
248 user.api_key = auth.generate_api_key(user.username)
248 249 sa.add(user)
249 250 sa.commit()
250 251 log.info('change password for %s', user_email)
251 252 if new_passwd is None:
252 253 raise Exception('unable to generate new password')
253 254
254 255 except:
255 256 log.error(traceback.format_exc())
256 257 sa.rollback()
257 258
258 259 run_task(send_email, user_email,
259 260 "Your new rhodecode password",
260 261 'Your new rhodecode password:%s' % (new_passwd))
261 262 log.info('send new password mail to %s', user_email)
262 263
263 264
264 265 except:
265 266 log.error('Failed to update user password')
266 267 log.error(traceback.format_exc())
267 268
268 269 return True
269 270
270 271 @task(ignore_result=True)
271 272 def send_email(recipients, subject, body):
272 273 """
273 274 Sends an email with defined parameters from the .ini files.
274 275
275 276
276 277 :param recipients: list of recipients, it this is empty the defined email
277 278 address from field 'email_to' is used instead
278 279 :param subject: subject of the mail
279 280 :param body: body of the mail
280 281 """
281 282 try:
282 283 log = send_email.get_logger()
283 284 except:
284 285 log = logging.getLogger(__name__)
285 286
286 287 email_config = config
287 288
288 289 if not recipients:
289 290 recipients = [email_config.get('email_to')]
290 291
291 292 mail_from = email_config.get('app_email_from')
292 293 user = email_config.get('smtp_username')
293 294 passwd = email_config.get('smtp_password')
294 295 mail_server = email_config.get('smtp_server')
295 296 mail_port = email_config.get('smtp_port')
296 297 tls = str2bool(email_config.get('smtp_use_tls'))
297 298 ssl = str2bool(email_config.get('smtp_use_ssl'))
298 299
299 300 try:
300 301 m = SmtpMailer(mail_from, user, passwd, mail_server,
301 302 mail_port, ssl, tls)
302 303 m.send(recipients, subject, body)
303 304 except:
304 305 log.error('Mail sending failed')
305 306 log.error(traceback.format_exc())
306 307 return False
307 308 return True
308 309
309 310 @task(ignore_result=True)
310 311 def create_repo_fork(form_data, cur_user):
311 312 try:
312 313 log = create_repo_fork.get_logger()
313 314 except:
314 315 log = logging.getLogger(__name__)
315 316
316 317 from rhodecode.model.repo import RepoModel
317 318 from vcs import get_backend
318 319
319 320 repo_model = RepoModel(get_session())
320 321 repo_model.create(form_data, cur_user, just_db=True, fork=True)
321 322 repo_name = form_data['repo_name']
322 323 repos_path = get_repos_path()
323 324 repo_path = os.path.join(repos_path, repo_name)
324 325 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
325 326 alias = form_data['repo_type']
326 327
327 328 log.info('creating repo fork %s as %s', repo_name, repo_path)
328 329 backend = get_backend(alias)
329 330 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
330 331
331 332 def __get_codes_stats(repo_name):
332 333 LANGUAGES_EXTENSIONS_MAP = {'scm': 'Scheme', 'asmx': 'VbNetAspx', 'Rout':
333 334 'RConsole', 'rest': 'Rst', 'abap': 'ABAP', 'go': 'Go', 'phtml': 'HtmlPhp',
334 335 'ns2': 'Newspeak', 'xml': 'EvoqueXml', 'sh-session': 'BashSession', 'ads':
335 336 'Ada', 'clj': 'Clojure', 'll': 'Llvm', 'ebuild': 'Bash', 'adb': 'Ada',
336 337 'ada': 'Ada', 'c++-objdump': 'CppObjdump', 'aspx':
337 338 'VbNetAspx', 'ksh': 'Bash', 'coffee': 'CoffeeScript', 'vert': 'GLShader',
338 339 'Makefile.*': 'Makefile', 'di': 'D', 'dpatch': 'DarcsPatch', 'rake':
339 340 'Ruby', 'moo': 'MOOCode', 'erl-sh': 'ErlangShell', 'geo': 'GLShader',
340 341 'pov': 'Povray', 'bas': 'VbNet', 'bat': 'Batch', 'd': 'D', 'lisp':
341 342 'CommonLisp', 'h': 'C', 'rbx': 'Ruby', 'tcl': 'Tcl', 'c++': 'Cpp', 'md':
342 343 'MiniD', '.vimrc': 'Vim', 'xsd': 'Xml', 'ml': 'Ocaml', 'el': 'CommonLisp',
343 344 'befunge': 'Befunge', 'xsl': 'Xslt', 'pyx': 'Cython', 'cfm':
344 345 'ColdfusionHtml', 'evoque': 'Evoque', 'cfg': 'Ini', 'htm': 'Html',
345 346 'Makefile': 'Makefile', 'cfc': 'ColdfusionHtml', 'tex': 'Tex', 'cs':
346 347 'CSharp', 'mxml': 'Mxml', 'patch': 'Diff', 'apache.conf': 'ApacheConf',
347 348 'scala': 'Scala', 'applescript': 'AppleScript', 'GNUmakefile': 'Makefile',
348 349 'c-objdump': 'CObjdump', 'lua': 'Lua', 'apache2.conf': 'ApacheConf', 'rb':
349 350 'Ruby', 'gemspec': 'Ruby', 'rl': 'RagelObjectiveC', 'vala': 'Vala', 'tmpl':
350 351 'Cheetah', 'bf': 'Brainfuck', 'plt': 'Gnuplot', 'G': 'AntlrRuby', 'xslt':
351 352 'Xslt', 'flxh': 'Felix', 'asax': 'VbNetAspx', 'Rakefile': 'Ruby', 'S': 'S',
352 353 'wsdl': 'Xml', 'js': 'Javascript', 'autodelegate': 'Myghty', 'properties':
353 354 'Ini', 'bash': 'Bash', 'c': 'C', 'g': 'AntlrRuby', 'r3': 'Rebol', 's':
354 355 'Gas', 'ashx': 'VbNetAspx', 'cxx': 'Cpp', 'boo': 'Boo', 'prolog': 'Prolog',
355 356 'sqlite3-console': 'SqliteConsole', 'cl': 'CommonLisp', 'cc': 'Cpp', 'pot':
356 357 'Gettext', 'vim': 'Vim', 'pxi': 'Cython', 'yaml': 'Yaml', 'SConstruct':
357 358 'Python', 'diff': 'Diff', 'txt': 'Text', 'cw': 'Redcode', 'pxd': 'Cython',
358 359 'plot': 'Gnuplot', 'java': 'Java', 'hrl': 'Erlang', 'py': 'Python',
359 360 'makefile': 'Makefile', 'squid.conf': 'SquidConf', 'asm': 'Nasm', 'toc':
360 361 'Tex', 'kid': 'Genshi', 'rhtml': 'Rhtml', 'po': 'Gettext', 'pl': 'Prolog',
361 362 'pm': 'Perl', 'hx': 'Haxe', 'ascx': 'VbNetAspx', 'ooc': 'Ooc', 'asy':
362 363 'Asymptote', 'hs': 'Haskell', 'SConscript': 'Python', 'pytb':
363 364 'PythonTraceback', 'myt': 'Myghty', 'hh': 'Cpp', 'R': 'S', 'aux': 'Tex',
364 365 'rst': 'Rst', 'cpp-objdump': 'CppObjdump', 'lgt': 'Logtalk', 'rss': 'Xml',
365 366 'flx': 'Felix', 'b': 'Brainfuck', 'f': 'Fortran', 'rbw': 'Ruby',
366 367 '.htaccess': 'ApacheConf', 'cxx-objdump': 'CppObjdump', 'j': 'ObjectiveJ',
367 368 'mll': 'Ocaml', 'yml': 'Yaml', 'mu': 'MuPAD', 'r': 'Rebol', 'ASM': 'Nasm',
368 369 'erl': 'Erlang', 'mly': 'Ocaml', 'mo': 'Modelica', 'def': 'Modula2', 'ini':
369 370 'Ini', 'control': 'DebianControl', 'vb': 'VbNet', 'vapi': 'Vala', 'pro':
370 371 'Prolog', 'spt': 'Cheetah', 'mli': 'Ocaml', 'as': 'ActionScript3', 'cmd':
371 372 'Batch', 'cpp': 'Cpp', 'io': 'Io', 'tac': 'Python', 'haml': 'Haml', 'rkt':
372 373 'Racket', 'st':'Smalltalk', 'inc': 'Povray', 'pas': 'Delphi', 'cmake':
373 374 'CMake', 'csh':'Tcsh', 'hpp': 'Cpp', 'feature': 'Gherkin', 'html': 'Html',
374 375 'php':'Php', 'php3':'Php', 'php4':'Php', 'php5':'Php', 'xhtml': 'Html',
375 376 'hxx': 'Cpp', 'eclass': 'Bash', 'css': 'Css',
376 377 'frag': 'GLShader', 'd-objdump': 'DObjdump', 'weechatlog': 'IrcLogs',
377 378 'tcsh': 'Tcsh', 'objdump': 'Objdump', 'pyw': 'Python', 'h++': 'Cpp',
378 379 'py3tb': 'Python3Traceback', 'jsp': 'Jsp', 'sql': 'Sql', 'mak': 'Makefile',
379 380 'php': 'Php', 'mao': 'Mako', 'man': 'Groff', 'dylan': 'Dylan', 'sass':
380 381 'Sass', 'cfml': 'ColdfusionHtml', 'darcspatch': 'DarcsPatch', 'tpl':
381 382 'Smarty', 'm': 'ObjectiveC', 'f90': 'Fortran', 'mod': 'Modula2', 'sh':
382 383 'Bash', 'lhs': 'LiterateHaskell', 'sources.list': 'SourcesList', 'axd':
383 384 'VbNetAspx', 'sc': 'Python'}
384 385
385 386 repos_path = get_repos_path()
386 387 p = os.path.join(repos_path, repo_name)
387 388 repo = get_repo(p)
388 389 tip = repo.get_changeset()
389 390 code_stats = {}
390 391
391 392 def aggregate(cs):
392 393 for f in cs[2]:
393 394 ext = f.extension
394 395 key = LANGUAGES_EXTENSIONS_MAP.get(ext, ext)
395 396 key = key or ext
396 397 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
397 398 if code_stats.has_key(key):
398 399 code_stats[key] += 1
399 400 else:
400 401 code_stats[key] = 1
401 402
402 403 map(aggregate, tip.walk('/'))
403 404
404 405 return code_stats or {}
405 406
406 407
407 408
408 409
@@ -1,534 +1,536 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.db_manage
4 4 ~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Database creation, and setup module for RhodeCode. Used for creation
7 7 of database as well as for migration operations
8 8
9 9 :created_on: Apr 10, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software; you can redistribute it and/or
15 15 # modify it under the terms of the GNU General Public License
16 16 # as published by the Free Software Foundation; version 2
17 17 # of the License or (at your opinion) any later version of the license.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program; if not, write to the Free Software
26 26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 27 # MA 02110-1301, USA.
28 28
29 29 import os
30 30 import sys
31 31 import uuid
32 32 import logging
33 33 from os.path import dirname as dn, join as jn
34 34
35 35 from rhodecode import __dbversion__
36 36 from rhodecode.model import meta
37 37
38 from rhodecode.lib.auth import get_crypt_password
38 from rhodecode.lib.auth import get_crypt_password, generate_api_key
39 39 from rhodecode.lib.utils import ask_ok
40 40 from rhodecode.model import init_model
41 41 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
42 42 UserToPerm, DbMigrateVersion
43 43
44 44 from sqlalchemy.engine import create_engine
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48 class DbManage(object):
49 49 def __init__(self, log_sql, dbconf, root, tests=False):
50 50 self.dbname = dbconf.split('/')[-1]
51 51 self.tests = tests
52 52 self.root = root
53 53 self.dburi = dbconf
54 54 self.log_sql = log_sql
55 55 self.db_exists = False
56 56 self.init_db()
57 57
58 58 def init_db(self):
59 59 engine = create_engine(self.dburi, echo=self.log_sql)
60 60 init_model(engine)
61 61 self.sa = meta.Session()
62 62
63 63 def check_for_db(self, override):
64 64 db_path = jn(self.root, self.dbname)
65 65 if self.dburi.startswith('sqlite'):
66 66 log.info('checking for existing db in %s', db_path)
67 67 if os.path.isfile(db_path):
68 68
69 69 self.db_exists = True
70 70 if not override:
71 71 raise Exception('database already exists')
72 72 return 'sqlite'
73 73 if self.dburi.startswith('postgresql'):
74 74 self.db_exists = True
75 75 return 'postgresql'
76 76
77 77
78 78 def create_tables(self, override=False):
79 79 """Create a auth database
80 80 """
81 81
82 82 db_type = self.check_for_db(override)
83 83 if self.db_exists:
84 84 log.info("database exist and it's going to be destroyed")
85 85 if self.tests:
86 86 destroy = True
87 87 else:
88 88 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
89 89 if not destroy:
90 90 sys.exit()
91 91 if self.db_exists and destroy:
92 92 if db_type == 'sqlite':
93 93 os.remove(jn(self.root, self.dbname))
94 94 if db_type == 'postgresql':
95 95 meta.Base.metadata.drop_all()
96 96
97 97 checkfirst = not override
98 98 meta.Base.metadata.create_all(checkfirst=checkfirst)
99 99 log.info('Created tables for %s', self.dbname)
100 100
101 101
102 102
103 103 def set_db_version(self):
104 104 try:
105 105 ver = DbMigrateVersion()
106 106 ver.version = __dbversion__
107 107 ver.repository_id = 'rhodecode_db_migrations'
108 108 ver.repository_path = 'versions'
109 109 self.sa.add(ver)
110 110 self.sa.commit()
111 111 except:
112 112 self.sa.rollback()
113 113 raise
114 114 log.info('db version set to: %s', __dbversion__)
115 115
116 116
117 117 def upgrade(self):
118 118 """Upgrades given database schema to given revision following
119 119 all needed steps, to perform the upgrade
120 120
121 121 """
122 122
123 123 from rhodecode.lib.dbmigrate.migrate.versioning import api
124 124 from rhodecode.lib.dbmigrate.migrate.exceptions import \
125 125 DatabaseNotControlledError
126 126
127 127 upgrade = ask_ok('You are about to perform database upgrade, make '
128 128 'sure You backed up your database before. '
129 129 'Continue ? [y/n]')
130 130 if not upgrade:
131 131 sys.exit('Nothing done')
132 132
133 133 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
134 134 'rhodecode/lib/dbmigrate')
135 135 db_uri = self.dburi
136 136
137 137 try:
138 138 curr_version = api.db_version(db_uri, repository_path)
139 139 msg = ('Found current database under version'
140 140 ' control with version %s' % curr_version)
141 141
142 142 except (RuntimeError, DatabaseNotControlledError), e:
143 143 curr_version = 1
144 144 msg = ('Current database is not under version control. Setting'
145 145 ' as version %s' % curr_version)
146 146 api.version_control(db_uri, repository_path, curr_version)
147 147
148 148 print (msg)
149 149
150 150 if curr_version == __dbversion__:
151 151 sys.exit('This database is already at the newest version')
152 152
153 153 #======================================================================
154 154 # UPGRADE STEPS
155 155 #======================================================================
156 156 class UpgradeSteps(object):
157 157 """Those steps follow schema versions so for example schema
158 158 for example schema with seq 002 == step_2 and so on.
159 159 """
160 160
161 161 def __init__(self, klass):
162 162 self.klass = klass
163 163
164 164 def step_0(self):
165 165 #step 0 is the schema upgrade, and than follow proper upgrades
166 166 print ('attempting to do database upgrade to version %s' \
167 167 % __dbversion__)
168 168 api.upgrade(db_uri, repository_path, __dbversion__)
169 169 print ('Schema upgrade completed')
170 170
171 171 def step_1(self):
172 172 pass
173 173
174 174 def step_2(self):
175 175 print ('Patching repo paths for newer version of RhodeCode')
176 176 self.klass.fix_repo_paths()
177 177
178 178 print ('Patching default user of RhodeCode')
179 179 self.klass.fix_default_user()
180 180
181 181 log.info('Changing ui settings')
182 182 self.klass.create_ui_settings()
183 183
184 184 def step_3(self):
185 185 print ('Adding additional settings into RhodeCode db')
186 186 self.klass.fix_settings()
187 187
188 188 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
189 189
190 190 #CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
191 191 for step in upgrade_steps:
192 192 print ('performing upgrade step %s' % step)
193 193 callable = getattr(UpgradeSteps(self), 'step_%s' % step)()
194 194
195 195
196 196
197 197 def fix_repo_paths(self):
198 198 """Fixes a old rhodecode version path into new one without a '*'
199 199 """
200 200
201 201 paths = self.sa.query(RhodeCodeUi)\
202 202 .filter(RhodeCodeUi.ui_key == '/')\
203 203 .scalar()
204 204
205 205 paths.ui_value = paths.ui_value.replace('*', '')
206 206
207 207 try:
208 208 self.sa.add(paths)
209 209 self.sa.commit()
210 210 except:
211 211 self.sa.rollback()
212 212 raise
213 213
214 214 def fix_default_user(self):
215 215 """Fixes a old default user with some 'nicer' default values,
216 216 used mostly for anonymous access
217 217 """
218 218 def_user = self.sa.query(User)\
219 219 .filter(User.username == 'default')\
220 220 .one()
221 221
222 222 def_user.name = 'Anonymous'
223 223 def_user.lastname = 'User'
224 224 def_user.email = 'anonymous@rhodecode.org'
225 225
226 226 try:
227 227 self.sa.add(def_user)
228 228 self.sa.commit()
229 229 except:
230 230 self.sa.rollback()
231 231 raise
232 232
233 233 def fix_settings(self):
234 234 """Fixes rhodecode settings adds ga_code key for google analytics
235 235 """
236 236
237 237 hgsettings3 = RhodeCodeSettings('ga_code', '')
238 238
239 239 try:
240 240 self.sa.add(hgsettings3)
241 241 self.sa.commit()
242 242 except:
243 243 self.sa.rollback()
244 244 raise
245 245
246 246 def admin_prompt(self, second=False):
247 247 if not self.tests:
248 248 import getpass
249 249
250 250
251 251 def get_password():
252 252 password = getpass.getpass('Specify admin password (min 6 chars):')
253 253 confirm = getpass.getpass('Confirm password:')
254 254
255 255 if password != confirm:
256 256 log.error('passwords mismatch')
257 257 return False
258 258 if len(password) < 6:
259 259 log.error('password is to short use at least 6 characters')
260 260 return False
261 261
262 262 return password
263 263
264 264 username = raw_input('Specify admin username:')
265 265
266 266 password = get_password()
267 267 if not password:
268 268 #second try
269 269 password = get_password()
270 270 if not password:
271 271 sys.exit()
272 272
273 273 email = raw_input('Specify admin email:')
274 274 self.create_user(username, password, email, True)
275 275 else:
276 276 log.info('creating admin and regular test users')
277 277 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
278 278 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
279 279 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
280 280
281 281 def create_ui_settings(self):
282 282 """Creates ui settings, fills out hooks
283 283 and disables dotencode
284 284
285 285 """
286 286 #HOOKS
287 287 hooks1_key = 'changegroup.update'
288 288 hooks1_ = self.sa.query(RhodeCodeUi)\
289 289 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
290 290
291 291 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
292 292 hooks1.ui_section = 'hooks'
293 293 hooks1.ui_key = hooks1_key
294 294 hooks1.ui_value = 'hg update >&2'
295 295 hooks1.ui_active = False
296 296
297 297 hooks2_key = 'changegroup.repo_size'
298 298 hooks2_ = self.sa.query(RhodeCodeUi)\
299 299 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
300 300
301 301 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
302 302 hooks2.ui_section = 'hooks'
303 303 hooks2.ui_key = hooks2_key
304 304 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
305 305
306 306 hooks3 = RhodeCodeUi()
307 307 hooks3.ui_section = 'hooks'
308 308 hooks3.ui_key = 'pretxnchangegroup.push_logger'
309 309 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
310 310
311 311 hooks4 = RhodeCodeUi()
312 312 hooks4.ui_section = 'hooks'
313 313 hooks4.ui_key = 'preoutgoing.pull_logger'
314 314 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
315 315
316 316 #For mercurial 1.7 set backward comapatibility with format
317 317 dotencode_disable = RhodeCodeUi()
318 318 dotencode_disable.ui_section = 'format'
319 319 dotencode_disable.ui_key = 'dotencode'
320 320 dotencode_disable.ui_value = 'false'
321 321
322 322 try:
323 323 self.sa.add(hooks1)
324 324 self.sa.add(hooks2)
325 325 self.sa.add(hooks3)
326 326 self.sa.add(hooks4)
327 327 self.sa.add(dotencode_disable)
328 328 self.sa.commit()
329 329 except:
330 330 self.sa.rollback()
331 331 raise
332 332
333 333
334 334 def create_ldap_options(self):
335 335 """Creates ldap settings"""
336 336
337 337 try:
338 338 for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
339 339 'ldap_tls_reqcert', 'ldap_dn_user', 'ldap_dn_pass',
340 340 'ldap_base_dn', 'ldap_filter', 'ldap_search_scope',
341 341 'ldap_attr_login', 'ldap_attr_firstname', 'ldap_attr_lastname',
342 342 'ldap_attr_email']:
343 343
344 344 setting = RhodeCodeSettings(k, '')
345 345 self.sa.add(setting)
346 346 self.sa.commit()
347 347 except:
348 348 self.sa.rollback()
349 349 raise
350 350
351 351 def config_prompt(self, test_repo_path='', retries=3):
352 352 if retries == 3:
353 353 log.info('Setting up repositories config')
354 354
355 355 if not self.tests and not test_repo_path:
356 356 path = raw_input('Specify valid full path to your repositories'
357 357 ' you can change this later in application settings:')
358 358 else:
359 359 path = test_repo_path
360 360 path_ok = True
361 361
362 362 #check proper dir
363 363 if not os.path.isdir(path):
364 364 path_ok = False
365 365 log.error('Entered path is not a valid directory: %s [%s/3]',
366 366 path, retries)
367 367
368 368 #check write access
369 369 if not os.access(path, os.W_OK):
370 370 path_ok = False
371 371
372 372 log.error('No write permission to given path: %s [%s/3]',
373 373 path, retries)
374 374
375 375
376 376 if retries == 0:
377 377 sys.exit()
378 378 if path_ok is False:
379 379 retries -= 1
380 380 return self.config_prompt(test_repo_path, retries)
381 381
382 382
383 383 return path
384 384
385 385 def create_settings(self, path):
386 386
387 387 self.create_ui_settings()
388 388
389 389 #HG UI OPTIONS
390 390 web1 = RhodeCodeUi()
391 391 web1.ui_section = 'web'
392 392 web1.ui_key = 'push_ssl'
393 393 web1.ui_value = 'false'
394 394
395 395 web2 = RhodeCodeUi()
396 396 web2.ui_section = 'web'
397 397 web2.ui_key = 'allow_archive'
398 398 web2.ui_value = 'gz zip bz2'
399 399
400 400 web3 = RhodeCodeUi()
401 401 web3.ui_section = 'web'
402 402 web3.ui_key = 'allow_push'
403 403 web3.ui_value = '*'
404 404
405 405 web4 = RhodeCodeUi()
406 406 web4.ui_section = 'web'
407 407 web4.ui_key = 'baseurl'
408 408 web4.ui_value = '/'
409 409
410 410 paths = RhodeCodeUi()
411 411 paths.ui_section = 'paths'
412 412 paths.ui_key = '/'
413 413 paths.ui_value = path
414 414
415 415
416 416 hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
417 417 hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
418 418 hgsettings3 = RhodeCodeSettings('ga_code', '')
419 419
420 420
421 421 try:
422 422 self.sa.add(web1)
423 423 self.sa.add(web2)
424 424 self.sa.add(web3)
425 425 self.sa.add(web4)
426 426 self.sa.add(paths)
427 427 self.sa.add(hgsettings1)
428 428 self.sa.add(hgsettings2)
429 429 self.sa.add(hgsettings3)
430 430
431 431 self.sa.commit()
432 432 except:
433 433 self.sa.rollback()
434 434 raise
435 435
436 436 self.create_ldap_options()
437 437
438 438 log.info('created ui config')
439 439
440 440 def create_user(self, username, password, email='', admin=False):
441 441 log.info('creating administrator user %s', username)
442 442 new_user = User()
443 443 new_user.username = username
444 444 new_user.password = get_crypt_password(password)
445 new_user.api_key = generate_api_key(username)
445 446 new_user.name = 'RhodeCode'
446 447 new_user.lastname = 'Admin'
447 448 new_user.email = email
448 449 new_user.admin = admin
449 450 new_user.active = True
450 451
451 452 try:
452 453 self.sa.add(new_user)
453 454 self.sa.commit()
454 455 except:
455 456 self.sa.rollback()
456 457 raise
457 458
458 459 def create_default_user(self):
459 460 log.info('creating default user')
460 461 #create default user for handling default permissions.
461 462 def_user = User()
462 463 def_user.username = 'default'
463 464 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
465 def_user.api_key = generate_api_key('default')
464 466 def_user.name = 'Anonymous'
465 467 def_user.lastname = 'User'
466 468 def_user.email = 'anonymous@rhodecode.org'
467 469 def_user.admin = False
468 470 def_user.active = False
469 471 try:
470 472 self.sa.add(def_user)
471 473 self.sa.commit()
472 474 except:
473 475 self.sa.rollback()
474 476 raise
475 477
476 478 def create_permissions(self):
477 479 #module.(access|create|change|delete)_[name]
478 480 #module.(read|write|owner)
479 481 perms = [('repository.none', 'Repository no access'),
480 482 ('repository.read', 'Repository read access'),
481 483 ('repository.write', 'Repository write access'),
482 484 ('repository.admin', 'Repository admin access'),
483 485 ('hg.admin', 'Hg Administrator'),
484 486 ('hg.create.repository', 'Repository create'),
485 487 ('hg.create.none', 'Repository creation disabled'),
486 488 ('hg.register.none', 'Register disabled'),
487 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
488 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
489 ('hg.register.manual_activate', 'Register new user with RhodeCode without manual activation'),
490 ('hg.register.auto_activate', 'Register new user with RhodeCode without auto activation'),
489 491 ]
490 492
491 493 for p in perms:
492 494 new_perm = Permission()
493 495 new_perm.permission_name = p[0]
494 496 new_perm.permission_longname = p[1]
495 497 try:
496 498 self.sa.add(new_perm)
497 499 self.sa.commit()
498 500 except:
499 501 self.sa.rollback()
500 502 raise
501 503
502 504 def populate_default_permissions(self):
503 505 log.info('creating default user permissions')
504 506
505 507 default_user = self.sa.query(User)\
506 508 .filter(User.username == 'default').scalar()
507 509
508 510 reg_perm = UserToPerm()
509 511 reg_perm.user = default_user
510 512 reg_perm.permission = self.sa.query(Permission)\
511 513 .filter(Permission.permission_name == 'hg.register.manual_activate')\
512 514 .scalar()
513 515
514 516 create_repo_perm = UserToPerm()
515 517 create_repo_perm.user = default_user
516 518 create_repo_perm.permission = self.sa.query(Permission)\
517 519 .filter(Permission.permission_name == 'hg.create.repository')\
518 520 .scalar()
519 521
520 522 default_repo_perm = UserToPerm()
521 523 default_repo_perm.user = default_user
522 524 default_repo_perm.permission = self.sa.query(Permission)\
523 525 .filter(Permission.permission_name == 'repository.read')\
524 526 .scalar()
525 527
526 528 try:
527 529 self.sa.add(reg_perm)
528 530 self.sa.add(create_repo_perm)
529 531 self.sa.add(default_repo_perm)
530 532 self.sa.commit()
531 533 except:
532 534 self.sa.rollback()
533 535 raise
534 536
@@ -1,225 +1,230 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users model for RhodeCode
7 7
8 8 :created_on: Apr 9, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import logging
29 29 import traceback
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 from rhodecode.model import BaseModel
34 34 from rhodecode.model.caching_query import FromCache
35 35 from rhodecode.model.db import User
36 36
37 37 from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
38 38
39 39 from sqlalchemy.exc import DatabaseError
40 from rhodecode.lib import generate_api_key
40 41
41 42 log = logging.getLogger(__name__)
42 43
43 44 class UserModel(BaseModel):
44 45
45 46 def get(self, user_id, cache=False):
46 47 user = self.sa.query(User)
47 48 if cache:
48 49 user = user.options(FromCache("sql_cache_short",
49 50 "get_user_%s" % user_id))
50 51 return user.get(user_id)
51 52
52 53
53 54 def get_by_username(self, username, cache=False, case_insensitive=False):
54 55
55 56 if case_insensitive:
56 57 user = self.sa.query(User).filter(User.username.ilike(username))
57 58 else:
58 59 user = self.sa.query(User)\
59 60 .filter(User.username == username)
60 61 if cache:
61 62 user = user.options(FromCache("sql_cache_short",
62 63 "get_user_%s" % username))
63 64 return user.scalar()
64 65
65 66 def create(self, form_data):
66 67 try:
67 68 new_user = User()
68 69 for k, v in form_data.items():
69 70 setattr(new_user, k, v)
70 71
72 new_user.api_key = generate_api_key(form_data['username'])
71 73 self.sa.add(new_user)
72 74 self.sa.commit()
73 75 except:
74 76 log.error(traceback.format_exc())
75 77 self.sa.rollback()
76 78 raise
77 79
78 80 def create_ldap(self, username, password, user_dn, attrs):
79 81 """
80 82 Checks if user is in database, if not creates this user marked
81 83 as ldap user
82 84 :param username:
83 85 :param password:
84 86 :param user_dn:
85 87 :param attrs:
86 88 """
87 89 from rhodecode.lib.auth import get_crypt_password
88 90 log.debug('Checking for such ldap account in RhodeCode database')
89 91 if self.get_by_username(username, case_insensitive=True) is None:
90 92 try:
91 93 new_user = User()
92 94 new_user.username = username.lower() # add ldap account always lowercase
93 95 new_user.password = get_crypt_password(password)
96 new_user.api_key = generate_api_key(username)
94 97 new_user.email = attrs['email']
95 98 new_user.active = True
96 99 new_user.ldap_dn = user_dn
97 100 new_user.name = attrs['name']
98 101 new_user.lastname = attrs['lastname']
99 102
100 103
101 104 self.sa.add(new_user)
102 105 self.sa.commit()
103 106 return True
104 107 except (DatabaseError,):
105 108 log.error(traceback.format_exc())
106 109 self.sa.rollback()
107 110 raise
108 111 log.debug('this %s user exists skipping creation of ldap account',
109 112 username)
110 113 return False
111 114
112 115 def create_registration(self, form_data):
113 116 from rhodecode.lib.celerylib import tasks, run_task
114 117 try:
115 118 new_user = User()
116 119 for k, v in form_data.items():
117 120 if k != 'admin':
118 121 setattr(new_user, k, v)
119 122
120 123 self.sa.add(new_user)
121 124 self.sa.commit()
122 125 body = ('New user registration\n'
123 126 'username: %s\n'
124 127 'email: %s\n')
125 128 body = body % (form_data['username'], form_data['email'])
126 129
127 130 run_task(tasks.send_email, None,
128 131 _('[RhodeCode] New User registration'),
129 132 body)
130 133 except:
131 134 log.error(traceback.format_exc())
132 135 self.sa.rollback()
133 136 raise
134 137
135 138 def update(self, user_id, form_data):
136 139 try:
137 new_user = self.get(user_id, cache=False)
138 if new_user.username == 'default':
140 user = self.get(user_id, cache=False)
141 if user.username == 'default':
139 142 raise DefaultUserException(
140 143 _("You can't Edit this user since it's"
141 144 " crucial for entire application"))
142 145
143 146 for k, v in form_data.items():
144 147 if k == 'new_password' and v != '':
145 new_user.password = v
148 user.password = v
149 user.api_key = generate_api_key(user.username)
146 150 else:
147 setattr(new_user, k, v)
151 setattr(user, k, v)
148 152
149 self.sa.add(new_user)
153 self.sa.add(user)
150 154 self.sa.commit()
151 155 except:
152 156 log.error(traceback.format_exc())
153 157 self.sa.rollback()
154 158 raise
155 159
156 160 def update_my_account(self, user_id, form_data):
157 161 try:
158 new_user = self.get(user_id, cache=False)
159 if new_user.username == 'default':
162 user = self.get(user_id, cache=False)
163 if user.username == 'default':
160 164 raise DefaultUserException(
161 165 _("You can't Edit this user since it's"
162 166 " crucial for entire application"))
163 167 for k, v in form_data.items():
164 168 if k == 'new_password' and v != '':
165 new_user.password = v
169 user.password = v
170 user.api_key = generate_api_key(user.username)
166 171 else:
167 172 if k not in ['admin', 'active']:
168 setattr(new_user, k, v)
173 setattr(user, k, v)
169 174
170 self.sa.add(new_user)
175 self.sa.add(user)
171 176 self.sa.commit()
172 177 except:
173 178 log.error(traceback.format_exc())
174 179 self.sa.rollback()
175 180 raise
176 181
177 182 def delete(self, user_id):
178 183 try:
179 184 user = self.get(user_id, cache=False)
180 185 if user.username == 'default':
181 186 raise DefaultUserException(
182 187 _("You can't remove this user since it's"
183 188 " crucial for entire application"))
184 189 if user.repositories:
185 190 raise UserOwnsReposException(_('This user still owns %s '
186 191 'repositories and cannot be '
187 192 'removed. Switch owners or '
188 193 'remove those repositories') \
189 194 % user.repositories)
190 195 self.sa.delete(user)
191 196 self.sa.commit()
192 197 except:
193 198 log.error(traceback.format_exc())
194 199 self.sa.rollback()
195 200 raise
196 201
197 202 def reset_password(self, data):
198 203 from rhodecode.lib.celerylib import tasks, run_task
199 204 run_task(tasks.reset_user_password, data['email'])
200 205
201 206
202 207 def fill_data(self, user):
203 208 """
204 209 Fills user data with those from database and log out user if not
205 210 present in database
206 211 :param user:
207 212 """
208 213
209 214 if not hasattr(user, 'user_id') or user.user_id is None:
210 215 raise Exception('passed in user has to have the user_id attribute')
211 216
212 217
213 218 log.debug('filling auth user data')
214 219 try:
215 220 dbuser = self.get(user.user_id)
216 221 user.username = dbuser.username
217 222 user.is_admin = dbuser.admin
218 223 user.name = dbuser.name
219 224 user.lastname = dbuser.lastname
220 225 user.email = dbuser.email
221 226 except:
222 227 log.error(traceback.format_exc())
223 228 user.is_authenticated = False
224 229
225 230 return user
@@ -1,2516 +1,2516 b''
1 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 border:0;
3 3 outline:0;
4 4 font-size:100%;
5 5 vertical-align:baseline;
6 6 background:transparent;
7 7 margin:0;
8 8 padding:0;
9 9 }
10 10
11 11 body {
12 12 line-height:1;
13 13 height:100%;
14 14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 16 font-size:12px;
17 17 color:#000;
18 18 margin:0;
19 19 padding:0;
20 20 }
21 21
22 22 ol,ul {
23 23 list-style:none;
24 24 }
25 25
26 26 blockquote,q {
27 27 quotes:none;
28 28 }
29 29
30 30 blockquote:before,blockquote:after,q:before,q:after {
31 31 content:none;
32 32 }
33 33
34 34 :focus {
35 35 outline:0;
36 36 }
37 37
38 38 del {
39 39 text-decoration:line-through;
40 40 }
41 41
42 42 table {
43 43 border-collapse:collapse;
44 44 border-spacing:0;
45 45 }
46 46
47 47 html {
48 48 height:100%;
49 49 }
50 50
51 51 a {
52 52 color:#003367;
53 53 text-decoration:none;
54 54 cursor:pointer;
55 55 font-weight:700;
56 56 }
57 57
58 58 a:hover {
59 59 color:#316293;
60 60 text-decoration:underline;
61 61 }
62 62
63 63 h1,h2,h3,h4,h5,h6 {
64 64 color:#292929;
65 65 font-weight:700;
66 66 }
67 67
68 68 h1 {
69 69 font-size:22px;
70 70 }
71 71
72 72 h2 {
73 73 font-size:20px;
74 74 }
75 75
76 76 h3 {
77 77 font-size:18px;
78 78 }
79 79
80 80 h4 {
81 81 font-size:16px;
82 82 }
83 83
84 84 h5 {
85 85 font-size:14px;
86 86 }
87 87
88 88 h6 {
89 89 font-size:11px;
90 90 }
91 91
92 92 ul.circle {
93 93 list-style-type:circle;
94 94 }
95 95
96 96 ul.disc {
97 97 list-style-type:disc;
98 98 }
99 99
100 100 ul.square {
101 101 list-style-type:square;
102 102 }
103 103
104 104 ol.lower-roman {
105 105 list-style-type:lower-roman;
106 106 }
107 107
108 108 ol.upper-roman {
109 109 list-style-type:upper-roman;
110 110 }
111 111
112 112 ol.lower-alpha {
113 113 list-style-type:lower-alpha;
114 114 }
115 115
116 116 ol.upper-alpha {
117 117 list-style-type:upper-alpha;
118 118 }
119 119
120 120 ol.decimal {
121 121 list-style-type:decimal;
122 122 }
123 123
124 124 div.color {
125 125 clear:both;
126 126 overflow:hidden;
127 127 position:absolute;
128 128 background:#FFF;
129 129 margin:7px 0 0 60px;
130 130 padding:1px 1px 1px 0;
131 131 }
132 132
133 133 div.color a {
134 134 width:15px;
135 135 height:15px;
136 136 display:block;
137 137 float:left;
138 138 margin:0 0 0 1px;
139 139 padding:0;
140 140 }
141 141
142 142 div.options {
143 143 clear:both;
144 144 overflow:hidden;
145 145 position:absolute;
146 146 background:#FFF;
147 147 margin:7px 0 0 162px;
148 148 padding:0;
149 149 }
150 150
151 151 div.options a {
152 152 height:1%;
153 153 display:block;
154 154 text-decoration:none;
155 155 margin:0;
156 156 padding:3px 8px;
157 157 }
158 158
159 159 .top-left-rounded-corner {
160 160 -webkit-border-top-left-radius: 8px;
161 161 -khtml-border-radius-topleft: 8px;
162 162 -moz-border-radius-topleft: 8px;
163 163 border-top-left-radius: 8px;
164 164 }
165 165
166 166 .top-right-rounded-corner {
167 167 -webkit-border-top-right-radius: 8px;
168 168 -khtml-border-radius-topright: 8px;
169 169 -moz-border-radius-topright: 8px;
170 170 border-top-right-radius: 8px;
171 171 }
172 172
173 173 .bottom-left-rounded-corner {
174 174 -webkit-border-bottom-left-radius: 8px;
175 175 -khtml-border-radius-bottomleft: 8px;
176 176 -moz-border-radius-bottomleft: 8px;
177 177 border-bottom-left-radius: 8px;
178 178 }
179 179
180 180 .bottom-right-rounded-corner {
181 181 -webkit-border-bottom-right-radius: 8px;
182 182 -khtml-border-radius-bottomright: 8px;
183 183 -moz-border-radius-bottomright: 8px;
184 184 border-bottom-right-radius: 8px;
185 185 }
186 186
187 187
188 188 #header {
189 189 margin:0;
190 190 padding:0 30px;
191 191 }
192 192
193 193
194 194 #header ul#logged-user{
195 195 margin-bottom:5px !important;
196 196 -webkit-border-radius: 0px 0px 8px 8px;
197 197 -khtml-border-radius: 0px 0px 8px 8px;
198 198 -moz-border-radius: 0px 0px 8px 8px;
199 199 border-radius: 0px 0px 8px 8px;
200 200 height:37px;
201 201 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
202 202 }
203 203
204 204 #header ul#logged-user li {
205 205 list-style:none;
206 206 float:left;
207 207 margin:8px 0 0;
208 208 padding:4px 12px;
209 209 border-left: 1px solid #316293;
210 210 }
211 211
212 212 #header ul#logged-user li.first {
213 213 border-left:none;
214 214 margin:4px;
215 215 }
216 216
217 217 #header ul#logged-user li.first div.gravatar {
218 218 margin-top:-2px;
219 219 }
220 220
221 221 #header ul#logged-user li.first div.account {
222 222 padding-top:4px;
223 223 float:left;
224 224 }
225 225
226 226 #header ul#logged-user li.last {
227 227 border-right:none;
228 228 }
229 229
230 230 #header ul#logged-user li a {
231 231 color:#fff;
232 232 font-weight:700;
233 233 text-decoration:none;
234 234 }
235 235
236 236 #header ul#logged-user li a:hover {
237 237 text-decoration:underline;
238 238 }
239 239
240 240 #header ul#logged-user li.highlight a {
241 241 color:#fff;
242 242 }
243 243
244 244 #header ul#logged-user li.highlight a:hover {
245 245 color:#FFF;
246 246 }
247 247
248 248 #header #header-inner {
249 249 height:40px;
250 250 clear:both;
251 251 position:relative;
252 252 background:#003367 url("../images/header_inner.png") repeat-x;
253 253 border-bottom:2px solid #fff;
254 254 margin:0;
255 255 padding:0;
256 256 }
257 257
258 258 #header #header-inner #home a {
259 259 height:40px;
260 260 width:46px;
261 261 display:block;
262 262 background:url("../images/button_home.png");
263 263 background-position:0 0;
264 264 margin:0;
265 265 padding:0;
266 266 }
267 267
268 268 #header #header-inner #home a:hover {
269 269 background-position:0 -40px;
270 270 }
271 271
272 272 #header #header-inner #logo h1 {
273 273 color:#FFF;
274 274 font-size:18px;
275 275 margin:10px 0 0 13px;
276 276 padding:0;
277 277 }
278 278
279 279 #header #header-inner #logo a {
280 280 color:#fff;
281 281 text-decoration:none;
282 282 }
283 283
284 284 #header #header-inner #logo a:hover {
285 285 color:#bfe3ff;
286 286 }
287 287
288 288 #header #header-inner #quick,#header #header-inner #quick ul {
289 289 position:relative;
290 290 float:right;
291 291 list-style-type:none;
292 292 list-style-position:outside;
293 293 margin:10px 5px 0 0;
294 294 padding:0;
295 295 }
296 296
297 297 #header #header-inner #quick li {
298 298 position:relative;
299 299 float:left;
300 300 margin:0 5px 0 0;
301 301 padding:0;
302 302 }
303 303
304 304 #header #header-inner #quick li a {
305 305 top:0;
306 306 left:0;
307 307 height:1%;
308 308 display:block;
309 309 clear:both;
310 310 overflow:hidden;
311 311 color:#FFF;
312 312 font-weight:700;
313 313 text-decoration:none;
314 314 background:#369 url("../images/quick_l.png") no-repeat top left;
315 315 padding:0;
316 316 }
317 317
318 318 #header #header-inner #quick li span.short {
319 319 padding:9px 6px 8px 6px;
320 320 }
321 321
322 322 #header #header-inner #quick li span {
323 323 top:0;
324 324 right:0;
325 325 height:1%;
326 326 display:block;
327 327 float:left;
328 328 background:url("../images/quick_r.png") no-repeat top right;
329 329 border-left:1px solid #3f6f9f;
330 330 margin:0;
331 331 padding:10px 12px 8px 10px;
332 332 }
333 333
334 334 #header #header-inner #quick li span.normal {
335 335 border:none;
336 336 padding:10px 12px 8px;
337 337 }
338 338
339 339 #header #header-inner #quick li span.icon {
340 340 top:0;
341 341 left:0;
342 342 border-left:none;
343 343 background:url("../images/quick_l.png") no-repeat top left;
344 344 border-right:1px solid #2e5c89;
345 345 padding:8px 8px 4px;
346 346 }
347 347
348 348 #header #header-inner #quick li span.icon_short {
349 349 top:0;
350 350 left:0;
351 351 border-left:none;
352 352 background:url("../images/quick_l.png") no-repeat top left;
353 353 border-right:1px solid #2e5c89;
354 354 padding:9px 4px 4px;
355 355 }
356 356
357 357 #header #header-inner #quick li a:hover {
358 358 background:#4e4e4e url("../images/quick_l_selected.png") no-repeat top left;
359 359 }
360 360
361 361 #header #header-inner #quick li a:hover span {
362 362 border-left:1px solid #545454;
363 363 background:url("../images/quick_r_selected.png") no-repeat top right;
364 364 }
365 365
366 366 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
367 367 border-left:none;
368 368 border-right:1px solid #464646;
369 369 background:url("../images/quick_l_selected.png") no-repeat top left;
370 370 }
371 371
372 372
373 373 #header #header-inner #quick ul {
374 374 top:29px;
375 375 right:0;
376 376 min-width:200px;
377 377 display:none;
378 378 position:absolute;
379 379 background:#FFF;
380 380 border:1px solid #666;
381 381 border-top:1px solid #003367;
382 382 z-index:100;
383 383 margin:0;
384 384 padding:0;
385 385 }
386 386
387 387 #header #header-inner #quick ul.repo_switcher {
388 388 max-height:275px;
389 389 overflow-x:hidden;
390 390 overflow-y:auto;
391 391 }
392 392
393 393 #header #header-inner #quick .repo_switcher_type{
394 394 position:absolute;
395 395 left:0;
396 396 top:9px;
397 397
398 398 }
399 399 #header #header-inner #quick li ul li {
400 400 border-bottom:1px solid #ddd;
401 401 }
402 402
403 403 #header #header-inner #quick li ul li a {
404 404 width:182px;
405 405 height:auto;
406 406 display:block;
407 407 float:left;
408 408 background:#FFF;
409 409 color:#003367;
410 410 font-weight:400;
411 411 margin:0;
412 412 padding:7px 9px;
413 413 }
414 414
415 415 #header #header-inner #quick li ul li a:hover {
416 416 color:#000;
417 417 background:#FFF;
418 418 }
419 419
420 420 #header #header-inner #quick ul ul {
421 421 top:auto;
422 422 }
423 423
424 424 #header #header-inner #quick li ul ul {
425 425 right:200px;
426 426 max-height:275px;
427 427 overflow:auto;
428 428 overflow-x:hidden;
429 429 white-space:normal;
430 430 }
431 431
432 432 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
433 433 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
434 434 width:167px;
435 435 margin:0;
436 436 padding:12px 9px 7px 24px;
437 437 }
438 438
439 439 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
440 440 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
441 441 min-width:167px;
442 442 margin:0;
443 443 padding:12px 9px 7px 24px;
444 444 }
445 445
446 446 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
447 447 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
448 448 min-width:167px;
449 449 margin:0;
450 450 padding:12px 9px 7px 24px;
451 451 }
452 452
453 453 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
454 454 background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
455 455 min-width:167px;
456 456 margin:0 0 0 14px;
457 457 padding:12px 9px 7px 24px;
458 458 }
459 459
460 460 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
461 461 background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
462 462 min-width:167px;
463 463 margin:0 0 0 14px;
464 464 padding:12px 9px 7px 24px;
465 465 }
466 466
467 467 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
468 468 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
469 469 width:167px;
470 470 margin:0;
471 471 padding:12px 9px 7px 24px;
472 472 }
473 473
474 474 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
475 475 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
476 476 width:167px;
477 477 margin:0;
478 478 padding:12px 9px 7px 24px;
479 479 }
480 480
481 481 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover {
482 482 background:#FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
483 483 width:167px;
484 484 margin:0;
485 485 padding:12px 9px 7px 24px;
486 486 }
487 487
488 488 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
489 489 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
490 490 width:167px;
491 491 margin:0;
492 492 padding:12px 9px 7px 24px;
493 493 }
494 494
495 495 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
496 496 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
497 497 width:167px;
498 498 margin:0;
499 499 padding:12px 9px 7px 24px;
500 500 }
501 501
502 502 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
503 503 background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
504 504 width:167px;
505 505 margin:0;
506 506 padding:12px 9px 7px 24px;
507 507 }
508 508
509 509 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
510 510 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
511 511 width:167px;
512 512 margin:0;
513 513 padding:12px 9px 7px 24px;
514 514 }
515 515
516 516 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
517 517 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
518 518 width:167px;
519 519 margin:0;
520 520 padding:12px 9px 7px 24px;
521 521 }
522 522
523 523 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
524 524 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
525 525 width:167px;
526 526 margin:0;
527 527 padding:12px 9px 7px 24px;
528 528 }
529 529
530 530 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
531 531 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
532 532 width:167px;
533 533 margin:0;
534 534 padding:12px 9px 7px 24px;
535 535 }
536 536
537 537 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
538 538 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
539 539 width:167px;
540 540 margin:0;
541 541 padding:12px 9px 7px 24px;
542 542 }
543 543
544 544 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
545 545 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
546 546 width:167px;
547 547 margin:0;
548 548 padding:12px 9px 7px 24px;
549 549 }
550 550
551 551 #content #left {
552 552 left:0;
553 553 width:280px;
554 554 position:absolute;
555 555 }
556 556
557 557 #content #right {
558 558 margin:0 60px 10px 290px;
559 559 }
560 560
561 561 #content div.box {
562 562 clear:both;
563 563 overflow:hidden;
564 564 background:#fff;
565 565 margin:0 0 10px;
566 566 padding:0 0 10px;
567 567 }
568 568
569 569 #content div.box-left {
570 570 width:49%;
571 571 clear:none;
572 572 float:left;
573 573 margin:0 0 10px;
574 574 }
575 575
576 576 #content div.box-right {
577 577 width:49%;
578 578 clear:none;
579 579 float:right;
580 580 margin:0 0 10px;
581 581 }
582 582
583 583 #content div.box div.title {
584 584 clear:both;
585 585 overflow:hidden;
586 586 background:#369 url("../images/header_inner.png") repeat-x;
587 587 margin:0 0 20px;
588 588 padding:0;
589 589 }
590 590
591 591 #content div.box div.title h5 {
592 592 float:left;
593 593 border:none;
594 594 color:#fff;
595 595 text-transform:uppercase;
596 596 margin:0;
597 597 padding:11px 0 11px 10px;
598 598 }
599 599
600 600 #content div.box div.title ul.links li {
601 601 list-style:none;
602 602 float:left;
603 603 margin:0;
604 604 padding:0;
605 605 }
606 606
607 607 #content div.box div.title ul.links li a {
608 608 border-left: 1px solid #316293;
609 609 color: #FFFFFF;
610 610 display: block;
611 611 float: left;
612 612 font-size: 13px;
613 613 font-weight: 700;
614 614 height: 1%;
615 615 margin: 0;
616 616 padding: 11px 22px 12px;
617 617 text-decoration: none;
618 618 }
619 619
620 620 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
621 621 clear:both;
622 622 overflow:hidden;
623 623 border-bottom:1px solid #DDD;
624 624 margin:10px 20px;
625 625 padding:0 0 15px;
626 626 }
627 627
628 628 #content div.box p {
629 629 color:#5f5f5f;
630 630 font-size:12px;
631 631 line-height:150%;
632 632 margin:0 24px 10px;
633 633 padding:0;
634 634 }
635 635
636 636 #content div.box blockquote {
637 637 border-left:4px solid #DDD;
638 638 color:#5f5f5f;
639 639 font-size:11px;
640 640 line-height:150%;
641 641 margin:0 34px;
642 642 padding:0 0 0 14px;
643 643 }
644 644
645 645 #content div.box blockquote p {
646 646 margin:10px 0;
647 647 padding:0;
648 648 }
649 649
650 650 #content div.box dl {
651 651 margin:10px 24px;
652 652 }
653 653
654 654 #content div.box dt {
655 655 font-size:12px;
656 656 margin:0;
657 657 }
658 658
659 659 #content div.box dd {
660 660 font-size:12px;
661 661 margin:0;
662 662 padding:8px 0 8px 15px;
663 663 }
664 664
665 665 #content div.box li {
666 666 font-size:12px;
667 667 padding:4px 0;
668 668 }
669 669
670 670 #content div.box ul.disc,#content div.box ul.circle {
671 671 margin:10px 24px 10px 38px;
672 672 }
673 673
674 674 #content div.box ul.square {
675 675 margin:10px 24px 10px 40px;
676 676 }
677 677
678 678 #content div.box img.left {
679 679 border:none;
680 680 float:left;
681 681 margin:10px 10px 10px 0;
682 682 }
683 683
684 684 #content div.box img.right {
685 685 border:none;
686 686 float:right;
687 687 margin:10px 0 10px 10px;
688 688 }
689 689
690 690 #content div.box div.messages {
691 691 clear:both;
692 692 overflow:hidden;
693 693 margin:0 20px;
694 694 padding:0;
695 695 }
696 696
697 697 #content div.box div.message {
698 698 clear:both;
699 699 overflow:hidden;
700 700 margin:0;
701 701 padding:10px 0;
702 702 }
703 703
704 704 #content div.box div.message a {
705 705 font-weight:400 !important;
706 706 }
707 707
708 708 #content div.box div.message div.image {
709 709 float:left;
710 710 margin:9px 0 0 5px;
711 711 padding:6px;
712 712 }
713 713
714 714 #content div.box div.message div.image img {
715 715 vertical-align:middle;
716 716 margin:0;
717 717 }
718 718
719 719 #content div.box div.message div.text {
720 720 float:left;
721 721 margin:0;
722 722 padding:9px 6px;
723 723 }
724 724
725 725 #content div.box div.message div.dismiss a {
726 726 height:16px;
727 727 width:16px;
728 728 display:block;
729 729 background:url("../images/icons/cross.png") no-repeat;
730 730 margin:15px 14px 0 0;
731 731 padding:0;
732 732 }
733 733
734 734 #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 {
735 735 border:none;
736 736 margin:0;
737 737 padding:0;
738 738 }
739 739
740 740 #content div.box div.message div.text span {
741 741 height:1%;
742 742 display:block;
743 743 margin:0;
744 744 padding:5px 0 0;
745 745 }
746 746
747 747 #content div.box div.message-error {
748 748 height:1%;
749 749 clear:both;
750 750 overflow:hidden;
751 751 background:#FBE3E4;
752 752 border:1px solid #FBC2C4;
753 753 color:#860006;
754 754 }
755 755
756 756 #content div.box div.message-error h6 {
757 757 color:#860006;
758 758 }
759 759
760 760 #content div.box div.message-warning {
761 761 height:1%;
762 762 clear:both;
763 763 overflow:hidden;
764 764 background:#FFF6BF;
765 765 border:1px solid #FFD324;
766 766 color:#5f5200;
767 767 }
768 768
769 769 #content div.box div.message-warning h6 {
770 770 color:#5f5200;
771 771 }
772 772
773 773 #content div.box div.message-notice {
774 774 height:1%;
775 775 clear:both;
776 776 overflow:hidden;
777 777 background:#8FBDE0;
778 778 border:1px solid #6BACDE;
779 779 color:#003863;
780 780 }
781 781
782 782 #content div.box div.message-notice h6 {
783 783 color:#003863;
784 784 }
785 785
786 786 #content div.box div.message-success {
787 787 height:1%;
788 788 clear:both;
789 789 overflow:hidden;
790 790 background:#E6EFC2;
791 791 border:1px solid #C6D880;
792 792 color:#4e6100;
793 793 }
794 794
795 795 #content div.box div.message-success h6 {
796 796 color:#4e6100;
797 797 }
798 798
799 799 #content div.box div.form div.fields div.field {
800 800 height:1%;
801 801 border-bottom:1px solid #DDD;
802 802 clear:both;
803 803 margin:0;
804 804 padding:10px 0;
805 805 }
806 806
807 807 #content div.box div.form div.fields div.field-first {
808 808 padding:0 0 10px;
809 809 }
810 810
811 811 #content div.box div.form div.fields div.field-noborder {
812 812 border-bottom:0 !important;
813 813 }
814 814
815 815 #content div.box div.form div.fields div.field span.error-message {
816 816 height:1%;
817 817 display:inline-block;
818 818 color:red;
819 819 margin:8px 0 0 4px;
820 820 padding:0;
821 821 }
822 822
823 823 #content div.box div.form div.fields div.field span.success {
824 824 height:1%;
825 825 display:block;
826 826 color:#316309;
827 827 margin:8px 0 0;
828 828 padding:0;
829 829 }
830 830
831 831 #content div.box div.form div.fields div.field div.label {
832 832 left:80px;
833 833 width:auto;
834 834 position:absolute;
835 835 margin:0;
836 836 padding:8px 0 0 5px;
837 837 }
838 838
839 839 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
840 840 clear:both;
841 841 overflow:hidden;
842 842 left:0;
843 843 width:auto;
844 844 position:relative;
845 845 margin:0;
846 846 padding:0 0 8px;
847 847 }
848 848
849 849 #content div.box div.form div.fields div.field div.label-select {
850 850 padding:5px 0 0 5px;
851 851 }
852 852
853 853 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
854 854 padding:0 0 8px;
855 855 }
856 856
857 857 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
858 858 padding:0 0 8px !important;
859 859 }
860 860
861 #content div.box div.form div.fields div.field div.label label {
861 #content div.box div.form div.fields div.field div.label label, div.label label{
862 862 color:#393939;
863 863 font-weight:700;
864 864 }
865 865
866 866 #content div.box div.form div.fields div.field div.input {
867 867 margin:0 0 0 200px;
868 868 }
869 869 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
870 870 margin:0 0 0 0px;
871 871 }
872 872
873 873 #content div.box div.form div.fields div.field div.input input {
874 874 background:#FFF;
875 875 border-top:1px solid #b3b3b3;
876 876 border-left:1px solid #b3b3b3;
877 877 border-right:1px solid #eaeaea;
878 878 border-bottom:1px solid #eaeaea;
879 879 color:#000;
880 880 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
881 881 font-size:11px;
882 882 margin:0;
883 883 padding:7px 7px 6px;
884 884 }
885 885
886 886
887 887
888 888 #content div.box div.form div.fields div.field div.input input.small {
889 889 width:30%;
890 890 }
891 891
892 892 #content div.box div.form div.fields div.field div.input input.medium {
893 893 width:55%;
894 894 }
895 895
896 896 #content div.box div.form div.fields div.field div.input input.large {
897 897 width:85%;
898 898 }
899 899
900 900 #content div.box div.form div.fields div.field div.input input.date {
901 901 width:177px;
902 902 }
903 903
904 904 #content div.box div.form div.fields div.field div.input input.button {
905 905 background:#D4D0C8;
906 906 border-top:1px solid #FFF;
907 907 border-left:1px solid #FFF;
908 908 border-right:1px solid #404040;
909 909 border-bottom:1px solid #404040;
910 910 color:#000;
911 911 margin:0;
912 912 padding:4px 8px;
913 913 }
914 914
915 915 #content div.box div.form div.fields div.field div.textarea {
916 916 border-top:1px solid #b3b3b3;
917 917 border-left:1px solid #b3b3b3;
918 918 border-right:1px solid #eaeaea;
919 919 border-bottom:1px solid #eaeaea;
920 920 margin:0 0 0 200px;
921 921 padding:10px;
922 922 }
923 923
924 924 #content div.box div.form div.fields div.field div.textarea-editor {
925 925 border:1px solid #ddd;
926 926 padding:0;
927 927 }
928 928
929 929 #content div.box div.form div.fields div.field div.textarea textarea {
930 930 width:100%;
931 931 height:220px;
932 932 overflow:hidden;
933 933 background:#FFF;
934 934 color:#000;
935 935 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
936 936 font-size:11px;
937 937 outline:none;
938 938 border-width:0;
939 939 margin:0;
940 940 padding:0;
941 941 }
942 942
943 943 #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 {
944 944 width:100%;
945 945 height:100px;
946 946 }
947 947
948 948 #content div.box div.form div.fields div.field div.textarea table {
949 949 width:100%;
950 950 border:none;
951 951 margin:0;
952 952 padding:0;
953 953 }
954 954
955 955 #content div.box div.form div.fields div.field div.textarea table td {
956 956 background:#DDD;
957 957 border:none;
958 958 padding:0;
959 959 }
960 960
961 961 #content div.box div.form div.fields div.field div.textarea table td table {
962 962 width:auto;
963 963 border:none;
964 964 margin:0;
965 965 padding:0;
966 966 }
967 967
968 968 #content div.box div.form div.fields div.field div.textarea table td table td {
969 969 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
970 970 font-size:11px;
971 971 padding:5px 5px 5px 0;
972 972 }
973 973
974 974 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
975 975 background:#f6f6f6;
976 976 border-color:#666;
977 977 }
978 978
979 979 div.form div.fields div.field div.button {
980 980 margin:0;
981 981 padding:0 0 0 8px;
982 982 }
983 983
984 984 div.form div.fields div.field div.highlight .ui-button {
985 985 background:#4e85bb url("../images/button_highlight.png") repeat-x;
986 986 border-top:1px solid #5c91a4;
987 987 border-left:1px solid #2a6f89;
988 988 border-right:1px solid #2b7089;
989 989 border-bottom:1px solid #1a6480;
990 990 color:#FFF;
991 991 margin:0;
992 992 padding:6px 12px;
993 993 }
994 994
995 995 div.form div.fields div.field div.highlight .ui-state-hover {
996 996 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
997 997 border-top:1px solid #78acbf;
998 998 border-left:1px solid #34819e;
999 999 border-right:1px solid #35829f;
1000 1000 border-bottom:1px solid #257897;
1001 1001 color:#FFF;
1002 1002 margin:0;
1003 1003 padding:6px 12px;
1004 1004 }
1005 1005
1006 1006 #content div.box div.form div.fields div.buttons div.highlight input.ui-button {
1007 1007 background:#4e85bb url("../images/button_highlight.png") repeat-x;
1008 1008 border-top:1px solid #5c91a4;
1009 1009 border-left:1px solid #2a6f89;
1010 1010 border-right:1px solid #2b7089;
1011 1011 border-bottom:1px solid #1a6480;
1012 1012 color:#fff;
1013 1013 margin:0;
1014 1014 padding:6px 12px;
1015 1015 }
1016 1016
1017 1017 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
1018 1018 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1019 1019 border-top:1px solid #78acbf;
1020 1020 border-left:1px solid #34819e;
1021 1021 border-right:1px solid #35829f;
1022 1022 border-bottom:1px solid #257897;
1023 1023 color:#fff;
1024 1024 margin:0;
1025 1025 padding:6px 12px;
1026 1026 }
1027 1027
1028 1028 #content div.box table {
1029 1029 width:100%;
1030 1030 border-collapse:collapse;
1031 1031 margin:0;
1032 1032 padding:0;
1033 1033 }
1034 1034
1035 1035 #content div.box table th {
1036 1036 background:#eee;
1037 1037 border-bottom:1px solid #ddd;
1038 1038 padding:5px 0px 5px 5px;
1039 1039 }
1040 1040
1041 1041 #content div.box table th.left {
1042 1042 text-align:left;
1043 1043 }
1044 1044
1045 1045 #content div.box table th.right {
1046 1046 text-align:right;
1047 1047 }
1048 1048
1049 1049 #content div.box table th.center {
1050 1050 text-align:center;
1051 1051 }
1052 1052
1053 1053 #content div.box table th.selected {
1054 1054 vertical-align:middle;
1055 1055 padding:0;
1056 1056 }
1057 1057
1058 1058 #content div.box table td {
1059 1059 background:#fff;
1060 1060 border-bottom:1px solid #cdcdcd;
1061 1061 vertical-align:middle;
1062 1062 padding:5px;
1063 1063 }
1064 1064
1065 1065 #content div.box table tr.selected td {
1066 1066 background:#FFC;
1067 1067 }
1068 1068
1069 1069 #content div.box table td.selected {
1070 1070 width:3%;
1071 1071 text-align:center;
1072 1072 vertical-align:middle;
1073 1073 padding:0;
1074 1074 }
1075 1075
1076 1076 #content div.box table td.action {
1077 1077 width:45%;
1078 1078 text-align:left;
1079 1079 }
1080 1080
1081 1081 #content div.box table td.date {
1082 1082 width:33%;
1083 1083 text-align:center;
1084 1084 }
1085 1085
1086 1086 #content div.box div.action {
1087 1087 float:right;
1088 1088 background:#FFF;
1089 1089 text-align:right;
1090 1090 margin:10px 0 0;
1091 1091 padding:0;
1092 1092 }
1093 1093
1094 1094 #content div.box div.action select {
1095 1095 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1096 1096 font-size:11px;
1097 1097 margin:0;
1098 1098 }
1099 1099
1100 1100 #content div.box div.action .ui-selectmenu {
1101 1101 margin:0;
1102 1102 padding:0;
1103 1103 }
1104 1104
1105 1105 #content div.box div.pagination {
1106 1106 height:1%;
1107 1107 clear:both;
1108 1108 overflow:hidden;
1109 1109 margin:10px 0 0;
1110 1110 padding:0;
1111 1111 }
1112 1112
1113 1113 #content div.box div.pagination ul.pager {
1114 1114 float:right;
1115 1115 text-align:right;
1116 1116 margin:0;
1117 1117 padding:0;
1118 1118 }
1119 1119
1120 1120 #content div.box div.pagination ul.pager li {
1121 1121 height:1%;
1122 1122 float:left;
1123 1123 list-style:none;
1124 1124 background:#ebebeb url("../images/pager.png") repeat-x;
1125 1125 border-top:1px solid #dedede;
1126 1126 border-left:1px solid #cfcfcf;
1127 1127 border-right:1px solid #c4c4c4;
1128 1128 border-bottom:1px solid #c4c4c4;
1129 1129 color:#4A4A4A;
1130 1130 font-weight:700;
1131 1131 margin:0 0 0 4px;
1132 1132 padding:0;
1133 1133 }
1134 1134
1135 1135 #content div.box div.pagination ul.pager li.separator {
1136 1136 padding:6px;
1137 1137 }
1138 1138
1139 1139 #content div.box div.pagination ul.pager li.current {
1140 1140 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1141 1141 border-top:1px solid #ccc;
1142 1142 border-left:1px solid #bebebe;
1143 1143 border-right:1px solid #b1b1b1;
1144 1144 border-bottom:1px solid #afafaf;
1145 1145 color:#515151;
1146 1146 padding:6px;
1147 1147 }
1148 1148
1149 1149 #content div.box div.pagination ul.pager li a {
1150 1150 height:1%;
1151 1151 display:block;
1152 1152 float:left;
1153 1153 color:#515151;
1154 1154 text-decoration:none;
1155 1155 margin:0;
1156 1156 padding:6px;
1157 1157 }
1158 1158
1159 1159 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1160 1160 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1161 1161 border-top:1px solid #ccc;
1162 1162 border-left:1px solid #bebebe;
1163 1163 border-right:1px solid #b1b1b1;
1164 1164 border-bottom:1px solid #afafaf;
1165 1165 margin:-1px;
1166 1166 }
1167 1167
1168 1168 #content div.box div.pagination-wh {
1169 1169 height:1%;
1170 1170 clear:both;
1171 1171 overflow:hidden;
1172 1172 text-align:right;
1173 1173 margin:10px 0 0;
1174 1174 padding:0;
1175 1175 }
1176 1176
1177 1177 #content div.box div.pagination-right {
1178 1178 float:right;
1179 1179 }
1180 1180
1181 1181 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1182 1182 height:1%;
1183 1183 float:left;
1184 1184 background:#ebebeb url("../images/pager.png") repeat-x;
1185 1185 border-top:1px solid #dedede;
1186 1186 border-left:1px solid #cfcfcf;
1187 1187 border-right:1px solid #c4c4c4;
1188 1188 border-bottom:1px solid #c4c4c4;
1189 1189 color:#4A4A4A;
1190 1190 font-weight:700;
1191 1191 margin:0 0 0 4px;
1192 1192 padding:6px;
1193 1193 }
1194 1194
1195 1195 #content div.box div.pagination-wh span.pager_curpage {
1196 1196 height:1%;
1197 1197 float:left;
1198 1198 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1199 1199 border-top:1px solid #ccc;
1200 1200 border-left:1px solid #bebebe;
1201 1201 border-right:1px solid #b1b1b1;
1202 1202 border-bottom:1px solid #afafaf;
1203 1203 color:#515151;
1204 1204 font-weight:700;
1205 1205 margin:0 0 0 4px;
1206 1206 padding:6px;
1207 1207 }
1208 1208
1209 1209 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1210 1210 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1211 1211 border-top:1px solid #ccc;
1212 1212 border-left:1px solid #bebebe;
1213 1213 border-right:1px solid #b1b1b1;
1214 1214 border-bottom:1px solid #afafaf;
1215 1215 text-decoration:none;
1216 1216 }
1217 1217
1218 1218 #content div.box div.traffic div.legend {
1219 1219 clear:both;
1220 1220 overflow:hidden;
1221 1221 border-bottom:1px solid #ddd;
1222 1222 margin:0 0 10px;
1223 1223 padding:0 0 10px;
1224 1224 }
1225 1225
1226 1226 #content div.box div.traffic div.legend h6 {
1227 1227 float:left;
1228 1228 border:none;
1229 1229 margin:0;
1230 1230 padding:0;
1231 1231 }
1232 1232
1233 1233 #content div.box div.traffic div.legend li {
1234 1234 list-style:none;
1235 1235 float:left;
1236 1236 font-size:11px;
1237 1237 margin:0;
1238 1238 padding:0 8px 0 4px;
1239 1239 }
1240 1240
1241 1241 #content div.box div.traffic div.legend li.visits {
1242 1242 border-left:12px solid #edc240;
1243 1243 }
1244 1244
1245 1245 #content div.box div.traffic div.legend li.pageviews {
1246 1246 border-left:12px solid #afd8f8;
1247 1247 }
1248 1248
1249 1249 #content div.box div.traffic table {
1250 1250 width:auto;
1251 1251 }
1252 1252
1253 1253 #content div.box div.traffic table td {
1254 1254 background:transparent;
1255 1255 border:none;
1256 1256 padding:2px 3px 3px;
1257 1257 }
1258 1258
1259 1259 #content div.box div.traffic table td.legendLabel {
1260 1260 padding:0 3px 2px;
1261 1261 }
1262 1262
1263 1263 #footer {
1264 1264 clear:both;
1265 1265 overflow:hidden;
1266 1266 text-align:right;
1267 1267 margin:0;
1268 1268 padding:0 30px 4px;
1269 1269 margin:-10px 0 0;
1270 1270 }
1271 1271
1272 1272 #footer div#footer-inner {
1273 1273 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1274 1274 border-top:2px solid #FFFFFF;
1275 1275 }
1276 1276
1277 1277 #footer div#footer-inner p {
1278 1278 padding:15px 25px 15px 0;
1279 1279 color:#FFF;
1280 1280 font-weight:700;
1281 1281 }
1282 1282 #footer div#footer-inner .footer-link {
1283 1283 float:left;
1284 1284 padding-left:10px;
1285 1285 }
1286 1286 #footer div#footer-inner .footer-link a {
1287 1287 color:#FFF;
1288 1288 }
1289 1289
1290 1290 #login div.title {
1291 1291 width:420px;
1292 1292 clear:both;
1293 1293 overflow:hidden;
1294 1294 position:relative;
1295 1295 background:#003367 url("../images/header_inner.png") repeat-x;
1296 1296 margin:0 auto;
1297 1297 padding:0;
1298 1298 }
1299 1299
1300 1300 #login div.inner {
1301 1301 width:380px;
1302 1302 background:#FFF url("../images/login.png") no-repeat top left;
1303 1303 border-top:none;
1304 1304 border-bottom:none;
1305 1305 margin:0 auto;
1306 1306 padding:20px;
1307 1307 }
1308 1308
1309 1309 #login div.form div.fields div.field div.label {
1310 1310 width:173px;
1311 1311 float:left;
1312 1312 text-align:right;
1313 1313 margin:2px 10px 0 0;
1314 1314 padding:5px 0 0 5px;
1315 1315 }
1316 1316
1317 1317 #login div.form div.fields div.field div.input input {
1318 1318 width:176px;
1319 1319 background:#FFF;
1320 1320 border-top:1px solid #b3b3b3;
1321 1321 border-left:1px solid #b3b3b3;
1322 1322 border-right:1px solid #eaeaea;
1323 1323 border-bottom:1px solid #eaeaea;
1324 1324 color:#000;
1325 1325 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1326 1326 font-size:11px;
1327 1327 margin:0;
1328 1328 padding:7px 7px 6px;
1329 1329 }
1330 1330
1331 1331 #login div.form div.fields div.buttons {
1332 1332 clear:both;
1333 1333 overflow:hidden;
1334 1334 border-top:1px solid #DDD;
1335 1335 text-align:right;
1336 1336 margin:0;
1337 1337 padding:10px 0 0;
1338 1338 }
1339 1339
1340 1340 #login div.form div.links {
1341 1341 clear:both;
1342 1342 overflow:hidden;
1343 1343 margin:10px 0 0;
1344 1344 padding:0 0 2px;
1345 1345 }
1346 1346
1347 1347 #register div.title {
1348 1348 clear:both;
1349 1349 overflow:hidden;
1350 1350 position:relative;
1351 1351 background:#003367 url("../images/header_inner.png") repeat-x;
1352 1352 margin:0 auto;
1353 1353 padding:0;
1354 1354 }
1355 1355
1356 1356 #register div.inner {
1357 1357 background:#FFF;
1358 1358 border-top:none;
1359 1359 border-bottom:none;
1360 1360 margin:0 auto;
1361 1361 padding:20px;
1362 1362 }
1363 1363
1364 1364 #register div.form div.fields div.field div.label {
1365 1365 width:135px;
1366 1366 float:left;
1367 1367 text-align:right;
1368 1368 margin:2px 10px 0 0;
1369 1369 padding:5px 0 0 5px;
1370 1370 }
1371 1371
1372 1372 #register div.form div.fields div.field div.input input {
1373 1373 width:300px;
1374 1374 background:#FFF;
1375 1375 border-top:1px solid #b3b3b3;
1376 1376 border-left:1px solid #b3b3b3;
1377 1377 border-right:1px solid #eaeaea;
1378 1378 border-bottom:1px solid #eaeaea;
1379 1379 color:#000;
1380 1380 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1381 1381 font-size:11px;
1382 1382 margin:0;
1383 1383 padding:7px 7px 6px;
1384 1384 }
1385 1385
1386 1386 #register div.form div.fields div.buttons {
1387 1387 clear:both;
1388 1388 overflow:hidden;
1389 1389 border-top:1px solid #DDD;
1390 1390 text-align:left;
1391 1391 margin:0;
1392 1392 padding:10px 0 0 150px;
1393 1393 }
1394 1394
1395 1395 #register div.form div.fields div.buttons div.highlight input.ui-button {
1396 1396 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1397 1397 color:#FFF;
1398 1398 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1399 1399 border-style:solid;
1400 1400 border-width:1px;
1401 1401 }
1402 1402
1403 1403 #register div.form div.activation_msg {
1404 1404 padding-top:4px;
1405 1405 padding-bottom:4px;
1406 1406 }
1407 1407
1408 1408 #journal .journal_day{
1409 1409 font-size:20px;
1410 1410 padding:10px 0px;
1411 1411 border-bottom:2px solid #DDD;
1412 1412 margin-left:10px;
1413 1413 margin-right:10px;
1414 1414 }
1415 1415
1416 1416 #journal .journal_container{
1417 1417 padding:5px;
1418 1418 clear:both;
1419 1419 margin:0px 5px 0px 10px;
1420 1420 }
1421 1421
1422 1422 #journal .journal_action_container{
1423 1423 padding-left:38px;
1424 1424 }
1425 1425
1426 1426 #journal .journal_user{
1427 1427 color: #747474;
1428 1428 font-size: 14px;
1429 1429 font-weight: bold;
1430 1430 height: 30px;
1431 1431 }
1432 1432 #journal .journal_icon{
1433 1433 clear: both;
1434 1434 float: left;
1435 1435 padding-right: 4px;
1436 1436 padding-top: 3px;
1437 1437 }
1438 1438 #journal .journal_action{
1439 1439 padding-top:4px;
1440 1440 min-height:2px;
1441 1441 float:left
1442 1442 }
1443 1443 #journal .journal_action_params{
1444 1444 clear: left;
1445 1445 padding-left: 22px;
1446 1446 }
1447 1447 #journal .journal_repo{
1448 1448 float: left;
1449 1449 margin-left: 6px;
1450 1450 padding-top: 3px;
1451 1451 }
1452 1452 #journal .date{
1453 1453 clear: both;
1454 1454 color: #777777;
1455 1455 font-size: 11px;
1456 1456 padding-left: 22px;
1457 1457 }
1458 1458 #journal .journal_repo .journal_repo_name{
1459 1459 font-weight: bold;
1460 1460 font-size: 1.1em;
1461 1461 }
1462 1462 #journal .compare_view{
1463 1463 padding: 5px 0px 5px 0px;
1464 1464 width: 95px;
1465 1465 }
1466 1466 .journal_highlight{
1467 1467 font-weight: bold;
1468 1468 padding: 0 2px;
1469 1469 vertical-align: bottom;
1470 1470 }
1471 1471 .trending_language_tbl,.trending_language_tbl td {
1472 1472 border:0 !important;
1473 1473 margin:0 !important;
1474 1474 padding:0 !important;
1475 1475 }
1476 1476
1477 1477 .trending_language {
1478 1478 background-color:#003367;
1479 1479 color:#FFF;
1480 1480 display:block;
1481 1481 min-width:20px;
1482 1482 text-decoration:none;
1483 1483 height:12px;
1484 1484 margin-bottom:4px;
1485 1485 margin-left:5px;
1486 1486 white-space:pre;
1487 1487 padding:3px;
1488 1488 }
1489 1489
1490 1490 h3.files_location {
1491 1491 font-size:1.8em;
1492 1492 font-weight:700;
1493 1493 border-bottom:none !important;
1494 1494 margin:10px 0 !important;
1495 1495 }
1496 1496
1497 1497 #files_data dl dt {
1498 1498 float:left;
1499 1499 width:115px;
1500 1500 margin:0 !important;
1501 1501 padding:5px;
1502 1502 }
1503 1503
1504 1504 #files_data dl dd {
1505 1505 margin:0 !important;
1506 1506 padding:5px !important;
1507 1507 }
1508 1508
1509 1509 #changeset_content {
1510 1510 border:1px solid #CCC;
1511 1511 padding:5px;
1512 1512 }
1513 1513 #changeset_compare_view_content{
1514 1514 border:1px solid #CCC;
1515 1515 padding:5px;
1516 1516 }
1517 1517
1518 1518 #changeset_content .container {
1519 1519 min-height:120px;
1520 1520 font-size:1.2em;
1521 1521 overflow:hidden;
1522 1522 }
1523 1523
1524 1524 #changeset_compare_view_content .compare_view_commits{
1525 1525 width: auto !important;
1526 1526 }
1527 1527
1528 1528 #changeset_compare_view_content .compare_view_commits td{
1529 1529 padding:0px 0px 0px 12px !important;
1530 1530 }
1531 1531
1532 1532 #changeset_content .container .right {
1533 1533 float:right;
1534 1534 width:25%;
1535 1535 text-align:right;
1536 1536 }
1537 1537
1538 1538 #changeset_content .container .left .message {
1539 1539 font-style:italic;
1540 1540 color:#556CB5;
1541 1541 white-space:pre-wrap;
1542 1542 }
1543 1543
1544 1544 .cs_files .cur_cs{
1545 1545 margin:10px 2px;
1546 1546 font-weight: bold;
1547 1547 }
1548 1548
1549 1549 .cs_files .cs_added {
1550 1550 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1551 1551 height:16px;
1552 1552 padding-left:20px;
1553 1553 margin-top:7px;
1554 1554 text-align:left;
1555 1555 }
1556 1556
1557 1557 .cs_files .cs_changed {
1558 1558 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1559 1559 height:16px;
1560 1560 padding-left:20px;
1561 1561 margin-top:7px;
1562 1562 text-align:left;
1563 1563 }
1564 1564
1565 1565 .cs_files .cs_removed {
1566 1566 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1567 1567 height:16px;
1568 1568 padding-left:20px;
1569 1569 margin-top:7px;
1570 1570 text-align:left;
1571 1571 }
1572 1572
1573 1573 #graph {
1574 1574 overflow:hidden;
1575 1575 }
1576 1576
1577 1577 #graph_nodes {
1578 1578 width:160px;
1579 1579 float:left;
1580 1580 margin-left:-50px;
1581 1581 margin-top:5px;
1582 1582 }
1583 1583
1584 1584 #graph_content {
1585 1585 width:800px;
1586 1586 float:left;
1587 1587 }
1588 1588
1589 1589 #graph_content .container_header {
1590 1590 border:1px solid #CCC;
1591 1591 padding:10px;
1592 1592 }
1593 1593 #graph_content #rev_range_container{
1594 1594 padding:10px 0px;
1595 1595 }
1596 1596 #graph_content .container {
1597 1597 border-bottom:1px solid #CCC;
1598 1598 border-left:1px solid #CCC;
1599 1599 border-right:1px solid #CCC;
1600 1600 min-height:80px;
1601 1601 overflow:hidden;
1602 1602 font-size:1.2em;
1603 1603 }
1604 1604
1605 1605 #graph_content .container .right {
1606 1606 float:right;
1607 1607 width:28%;
1608 1608 text-align:right;
1609 1609 padding-bottom:5px;
1610 1610 }
1611 1611
1612 1612 #graph_content .container .left .date {
1613 1613 font-weight:700;
1614 1614 padding-bottom:5px;
1615 1615 }
1616 1616 #graph_content .container .left .date span{
1617 1617 vertical-align: text-top;
1618 1618 }
1619 1619
1620 1620 #graph_content .container .left .message {
1621 1621 font-size:100%;
1622 1622 padding-top:3px;
1623 1623 white-space:pre-wrap;
1624 1624 }
1625 1625
1626 1626 .right div {
1627 1627 clear:both;
1628 1628 }
1629 1629
1630 1630 .right .changes .added,.changed,.removed {
1631 1631 border:1px solid #DDD;
1632 1632 display:block;
1633 1633 float:right;
1634 1634 text-align:center;
1635 1635 min-width:15px;
1636 1636 cursor: help;
1637 1637 }
1638 1638
1639 1639 .right .changes .added {
1640 1640 background:#BFB;
1641 1641 }
1642 1642
1643 1643 .right .changes .changed {
1644 1644 background:#FD8;
1645 1645 }
1646 1646
1647 1647 .right .changes .removed {
1648 1648 background:#F88;
1649 1649 }
1650 1650
1651 1651 .right .merge {
1652 1652 vertical-align:top;
1653 1653 font-size:0.75em;
1654 1654 font-weight:700;
1655 1655 }
1656 1656
1657 1657 .right .parent {
1658 1658 font-size:90%;
1659 1659 font-family:monospace;
1660 1660 }
1661 1661
1662 1662 .right .logtags .branchtag {
1663 1663 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1664 1664 display:block;
1665 1665 font-size:0.8em;
1666 1666 padding:11px 16px 0 0;
1667 1667 }
1668 1668
1669 1669 .right .logtags .tagtag {
1670 1670 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1671 1671 display:block;
1672 1672 font-size:0.8em;
1673 1673 padding:11px 16px 0 0;
1674 1674 }
1675 1675
1676 1676 div.browserblock {
1677 1677 overflow:hidden;
1678 1678 border:1px solid #ccc;
1679 1679 background:#f8f8f8;
1680 1680 font-size:100%;
1681 1681 line-height:125%;
1682 1682 padding:0;
1683 1683 }
1684 1684
1685 1685 div.browserblock .browser-header {
1686 1686 background:#FFF;
1687 1687 padding:10px 0px 35px 0px;
1688 1688 width: 100%;
1689 1689 }
1690 1690 div.browserblock .browser-nav {
1691 1691 float:left
1692 1692 }
1693 1693
1694 1694 div.browserblock .browser-branch {
1695 1695 padding:10px 0 0 0;
1696 1696 float:left;
1697 1697 }
1698 1698 div.browserblock .browser-branch label {
1699 1699 color:#4A4A4A;
1700 1700 vertical-align:text-top;
1701 1701 }
1702 1702
1703 1703 div.browserblock .browser-header span {
1704 1704 margin-left:25px;
1705 1705 font-weight:700;
1706 1706 }
1707 1707
1708 1708 div.browserblock .browser-body {
1709 1709 background:#EEE;
1710 1710 border-top:1px solid #CCC;
1711 1711 }
1712 1712
1713 1713 table.code-browser {
1714 1714 border-collapse:collapse;
1715 1715 width:100%;
1716 1716 }
1717 1717
1718 1718 table.code-browser tr {
1719 1719 margin:3px;
1720 1720 }
1721 1721
1722 1722 table.code-browser thead th {
1723 1723 background-color:#EEE;
1724 1724 height:20px;
1725 1725 font-size:1.1em;
1726 1726 font-weight:700;
1727 1727 text-align:left;
1728 1728 padding-left:10px;
1729 1729 }
1730 1730
1731 1731 table.code-browser tbody td {
1732 1732 padding-left:10px;
1733 1733 height:20px;
1734 1734 }
1735 1735
1736 1736 table.code-browser .browser-file {
1737 1737 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1738 1738 height:16px;
1739 1739 padding-left:20px;
1740 1740 text-align:left;
1741 1741 }
1742 1742 .diffblock .changeset_file{
1743 1743 background:url("../images/icons/file.png") no-repeat scroll 3px;
1744 1744 height:16px;
1745 1745 padding-left:22px;
1746 1746 text-align:left;
1747 1747 font-size: 14px;
1748 1748 }
1749 1749
1750 1750 .diffblock .changeset_header{
1751 1751 margin-left: 6px !important;
1752 1752 }
1753 1753
1754 1754 table.code-browser .browser-dir {
1755 1755 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1756 1756 height:16px;
1757 1757 padding-left:20px;
1758 1758 text-align:left;
1759 1759 }
1760 1760
1761 1761 .box .search {
1762 1762 clear:both;
1763 1763 overflow:hidden;
1764 1764 margin:0;
1765 1765 padding:0 20px 10px;
1766 1766 }
1767 1767
1768 1768 .box .search div.search_path {
1769 1769 background:none repeat scroll 0 0 #EEE;
1770 1770 border:1px solid #CCC;
1771 1771 color:blue;
1772 1772 margin-bottom:10px;
1773 1773 padding:10px 0;
1774 1774 }
1775 1775
1776 1776 .box .search div.search_path div.link {
1777 1777 font-weight:700;
1778 1778 margin-left:25px;
1779 1779 }
1780 1780
1781 1781 .box .search div.search_path div.link a {
1782 1782 color:#003367;
1783 1783 cursor:pointer;
1784 1784 text-decoration:none;
1785 1785 }
1786 1786
1787 1787 #path_unlock {
1788 1788 color:red;
1789 1789 font-size:1.2em;
1790 1790 padding-left:4px;
1791 1791 }
1792 1792
1793 1793 .info_box * {
1794 1794 background:url("../images/pager.png") repeat-x scroll 0 0 #EBEBEB;
1795 1795 color:#4A4A4A;
1796 1796 font-weight:700;
1797 1797 height:1%;
1798 1798 display:inline;
1799 1799 border-color:#DEDEDE #C4C4C4 #C4C4C4 #CFCFCF;
1800 1800 border-style:solid;
1801 1801 border-width:1px;
1802 1802 padding:4px 6px;
1803 1803 }
1804 1804
1805 1805 .info_box span {
1806 1806 margin-left:3px;
1807 1807 margin-right:3px;
1808 1808 }
1809 1809
1810 1810 .info_box input#at_rev {
1811 1811 text-align:center;
1812 1812 padding:5px 3px 3px 2px;
1813 1813 }
1814 1814
1815 1815 .info_box input#view {
1816 1816 text-align:center;
1817 1817 padding:4px 3px 2px 2px;
1818 1818 }
1819 1819
1820 1820 .yui-overlay,.yui-panel-container {
1821 1821 visibility:hidden;
1822 1822 position:absolute;
1823 1823 z-index:2;
1824 1824 }
1825 1825
1826 1826 .yui-tt {
1827 1827 visibility:hidden;
1828 1828 position:absolute;
1829 1829 color:#666;
1830 1830 background-color:#FFF;
1831 1831 font-family:arial, helvetica, verdana, sans-serif;
1832 1832 border:2px solid #003367;
1833 1833 font:100% sans-serif;
1834 1834 width:auto;
1835 1835 opacity:1px;
1836 1836 padding:8px;
1837 1837 white-space: pre;
1838 1838 -webkit-border-radius: 8px 8px 8px 8px;
1839 1839 -khtml-border-radius: 8px 8px 8px 8px;
1840 1840 -moz-border-radius: 8px 8px 8px 8px;
1841 1841 border-radius: 8px 8px 8px 8px;
1842 1842 }
1843 1843
1844 1844 .ac {
1845 1845 vertical-align:top;
1846 1846 }
1847 1847
1848 1848 .ac .yui-ac {
1849 1849 position:relative;
1850 1850 font-family:arial;
1851 1851 font-size:100%;
1852 1852 }
1853 1853
1854 1854 .ac .perm_ac {
1855 1855 width:15em;
1856 1856 }
1857 1857
1858 1858 .ac .yui-ac-input {
1859 1859 width:100%;
1860 1860 }
1861 1861
1862 1862 .ac .yui-ac-container {
1863 1863 position:absolute;
1864 1864 top:1.6em;
1865 1865 width:100%;
1866 1866 }
1867 1867
1868 1868 .ac .yui-ac-content {
1869 1869 position:absolute;
1870 1870 width:100%;
1871 1871 border:1px solid gray;
1872 1872 background:#fff;
1873 1873 overflow:hidden;
1874 1874 z-index:9050;
1875 1875 }
1876 1876
1877 1877 .ac .yui-ac-shadow {
1878 1878 position:absolute;
1879 1879 width:100%;
1880 1880 background:#000;
1881 1881 -moz-opacity:0.1px;
1882 1882 opacity:.10;
1883 1883 filter:alpha(opacity = 10);
1884 1884 z-index:9049;
1885 1885 margin:.3em;
1886 1886 }
1887 1887
1888 1888 .ac .yui-ac-content ul {
1889 1889 width:100%;
1890 1890 margin:0;
1891 1891 padding:0;
1892 1892 }
1893 1893
1894 1894 .ac .yui-ac-content li {
1895 1895 cursor:default;
1896 1896 white-space:nowrap;
1897 1897 margin:0;
1898 1898 padding:2px 5px;
1899 1899 }
1900 1900
1901 1901 .ac .yui-ac-content li.yui-ac-prehighlight {
1902 1902 background:#B3D4FF;
1903 1903 }
1904 1904
1905 1905 .ac .yui-ac-content li.yui-ac-highlight {
1906 1906 background:#556CB5;
1907 1907 color:#FFF;
1908 1908 }
1909 1909
1910 1910 .follow{
1911 1911 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
1912 1912 height: 16px;
1913 1913 width: 20px;
1914 1914 cursor: pointer;
1915 1915 display: block;
1916 1916 float: right;
1917 1917 margin-top: 2px;
1918 1918 }
1919 1919
1920 1920 .following{
1921 1921 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
1922 1922 height: 16px;
1923 1923 width: 20px;
1924 1924 cursor: pointer;
1925 1925 display: block;
1926 1926 float: right;
1927 1927 margin-top: 2px;
1928 1928 }
1929 1929
1930 1930 .currently_following{
1931 1931 padding-left: 10px;
1932 1932 padding-bottom:5px;
1933 1933 }
1934 1934
1935 1935 .add_icon {
1936 1936 background:url("../images/icons/add.png") no-repeat scroll 3px;
1937 1937 height:16px;
1938 1938 padding-left:20px;
1939 1939 padding-top:1px;
1940 1940 text-align:left;
1941 1941 }
1942 1942
1943 1943 .edit_icon {
1944 1944 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1945 1945 height:16px;
1946 1946 padding-left:20px;
1947 1947 padding-top:1px;
1948 1948 text-align:left;
1949 1949 }
1950 1950
1951 1951 .delete_icon {
1952 1952 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1953 1953 height:16px;
1954 1954 padding-left:20px;
1955 1955 padding-top:1px;
1956 1956 text-align:left;
1957 1957 }
1958 1958
1959 1959 .refresh_icon {
1960 1960 background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
1961 1961 height:16px;
1962 1962 padding-left:20px;
1963 1963 padding-top:1px;
1964 1964 text-align:left;
1965 1965 }
1966 1966
1967 1967 .pull_icon {
1968 1968 background:url("../images/icons/connect.png") no-repeat scroll 3px;
1969 1969 height:16px;
1970 1970 padding-left:20px;
1971 1971 padding-top:1px;
1972 1972 text-align:left;
1973 1973 }
1974 1974
1975 1975 .rss_icon {
1976 1976 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
1977 1977 height:16px;
1978 1978 padding-left:20px;
1979 1979 padding-top:1px;
1980 1980 text-align:left;
1981 1981 }
1982 1982
1983 1983 .atom_icon {
1984 1984 background:url("../images/icons/atom.png") no-repeat scroll 3px;
1985 1985 height:16px;
1986 1986 padding-left:20px;
1987 1987 padding-top:1px;
1988 1988 text-align:left;
1989 1989 }
1990 1990
1991 1991 .archive_icon {
1992 1992 background:url("../images/icons/compress.png") no-repeat scroll 3px;
1993 1993 height:16px;
1994 1994 padding-left:20px;
1995 1995 text-align:left;
1996 1996 padding-top:1px;
1997 1997 }
1998 1998 .start_following_icon {
1999 1999 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2000 2000 height:16px;
2001 2001 padding-left:20px;
2002 2002 text-align:left;
2003 2003 padding-top:1px;
2004 2004 }
2005 2005 .stop_following_icon {
2006 2006 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2007 2007 height:16px;
2008 2008 padding-left:20px;
2009 2009 text-align:left;
2010 2010 padding-top:1px;
2011 2011 }
2012 2012
2013 2013 .action_button {
2014 2014 border:0;
2015 2015 display:block;
2016 2016 }
2017 2017
2018 2018 .action_button:hover {
2019 2019 border:0;
2020 2020 text-decoration:underline;
2021 2021 cursor:pointer;
2022 2022 }
2023 2023
2024 2024 #switch_repos {
2025 2025 position:absolute;
2026 2026 height:25px;
2027 2027 z-index:1;
2028 2028 }
2029 2029
2030 2030 #switch_repos select {
2031 2031 min-width:150px;
2032 2032 max-height:250px;
2033 2033 z-index:1;
2034 2034 }
2035 2035
2036 2036 .breadcrumbs {
2037 2037 border:medium none;
2038 2038 color:#FFF;
2039 2039 float:left;
2040 2040 text-transform:uppercase;
2041 2041 font-weight:700;
2042 2042 font-size:14px;
2043 2043 margin:0;
2044 2044 padding:11px 0 11px 10px;
2045 2045 }
2046 2046
2047 2047 .breadcrumbs a {
2048 2048 color:#FFF;
2049 2049 }
2050 2050
2051 2051 .flash_msg ul {
2052 2052 margin:0;
2053 2053 padding:0 0 10px;
2054 2054 }
2055 2055
2056 2056 .error_msg {
2057 2057 background-color:#FFCFCF;
2058 2058 background-image:url("../images/icons/error_msg.png");
2059 2059 border:1px solid #FF9595;
2060 2060 color:#C30;
2061 2061 }
2062 2062
2063 2063 .warning_msg {
2064 2064 background-color:#FFFBCC;
2065 2065 background-image:url("../images/icons/warning_msg.png");
2066 2066 border:1px solid #FFF35E;
2067 2067 color:#C69E00;
2068 2068 }
2069 2069
2070 2070 .success_msg {
2071 2071 background-color:#D5FFCF;
2072 2072 background-image:url("../images/icons/success_msg.png");
2073 2073 border:1px solid #97FF88;
2074 2074 color:#090;
2075 2075 }
2076 2076
2077 2077 .notice_msg {
2078 2078 background-color:#DCE3FF;
2079 2079 background-image:url("../images/icons/notice_msg.png");
2080 2080 border:1px solid #93A8FF;
2081 2081 color:#556CB5;
2082 2082 }
2083 2083
2084 2084 .success_msg,.error_msg,.notice_msg,.warning_msg {
2085 2085 background-position:10px center;
2086 2086 background-repeat:no-repeat;
2087 2087 font-size:12px;
2088 2088 font-weight:700;
2089 2089 min-height:14px;
2090 2090 line-height:14px;
2091 2091 margin-bottom:0;
2092 2092 margin-top:0;
2093 2093 display:block;
2094 2094 overflow:auto;
2095 2095 padding:6px 10px 6px 40px;
2096 2096 }
2097 2097
2098 2098 #msg_close {
2099 2099 background:transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
2100 2100 cursor:pointer;
2101 2101 height:16px;
2102 2102 position:absolute;
2103 2103 right:5px;
2104 2104 top:5px;
2105 2105 width:16px;
2106 2106 }
2107 2107
2108 2108 div#legend_container table,div#legend_choices table {
2109 2109 width:auto !important;
2110 2110 }
2111 2111
2112 2112 table#permissions_manage {
2113 2113 width:0 !important;
2114 2114 }
2115 2115
2116 2116 table#permissions_manage span.private_repo_msg {
2117 2117 font-size:0.8em;
2118 2118 opacity:0.6px;
2119 2119 }
2120 2120
2121 2121 table#permissions_manage td.private_repo_msg {
2122 2122 font-size:0.8em;
2123 2123 }
2124 2124
2125 2125 table#permissions_manage tr#add_perm_input td {
2126 2126 vertical-align:middle;
2127 2127 }
2128 2128
2129 2129 div.gravatar {
2130 2130 background-color:#FFF;
2131 2131 border:1px solid #D0D0D0;
2132 2132 float:left;
2133 2133 margin-right:0.7em;
2134 2134 padding:2px 2px 0;
2135 2135 }
2136 2136
2137 2137 #header,#content,#footer {
2138 2138 min-width:1024px;
2139 2139 }
2140 2140
2141 2141 #content {
2142 2142 min-height:100%;
2143 2143 clear:both;
2144 2144 overflow:hidden;
2145 2145 padding:14px 30px;
2146 2146 }
2147 2147
2148 2148 #content div.box div.title div.search {
2149 2149 background:url("../images/title_link.png") no-repeat top left;
2150 2150 border-left:1px solid #316293;
2151 2151 }
2152 2152
2153 2153 #content div.box div.title div.search div.input input {
2154 2154 border:1px solid #316293;
2155 2155 }
2156 2156
2157 2157 #content div.box div.title div.search div.button input.ui-button {
2158 2158 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2159 2159 border:1px solid #316293;
2160 2160 border-left:none;
2161 2161 color:#FFF;
2162 2162 }
2163 2163
2164 2164 #content div.box div.title div.search div.button input.ui-state-hover {
2165 2165 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2166 2166 border:1px solid #316293;
2167 2167 border-left:none;
2168 2168 color:#FFF;
2169 2169 }
2170 2170
2171 2171 #content div.box div.form div.fields div.field div.highlight .ui-button {
2172 2172 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2173 2173 border-top:1px solid #5c91a4;
2174 2174 border-left:1px solid #2a6f89;
2175 2175 border-right:1px solid #2b7089;
2176 2176 border-bottom:1px solid #1a6480;
2177 2177 color:#fff;
2178 2178 }
2179 2179
2180 2180 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
2181 2181 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2182 2182 border-top:1px solid #78acbf;
2183 2183 border-left:1px solid #34819e;
2184 2184 border-right:1px solid #35829f;
2185 2185 border-bottom:1px solid #257897;
2186 2186 color:#fff;
2187 2187 }
2188 2188
2189 2189 ins,div.options a:hover {
2190 2190 text-decoration:none;
2191 2191 }
2192 2192
2193 2193 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2194 2194 border:none;
2195 2195 }
2196 2196
2197 2197 img.icon,.right .merge img {
2198 2198 vertical-align:bottom;
2199 2199 }
2200 2200
2201 2201 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2202 2202 float:right;
2203 2203 margin:0;
2204 2204 padding:0;
2205 2205 }
2206 2206
2207 2207 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2208 2208 float:left;
2209 2209 }
2210 2210
2211 2211 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2212 2212 display:none;
2213 2213 }
2214 2214
2215 2215 #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 {
2216 2216 display:block;
2217 2217 }
2218 2218
2219 2219 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2220 2220 color:#bfe3ff;
2221 2221 }
2222 2222
2223 2223 #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 {
2224 2224 margin:10px 24px 10px 44px;
2225 2225 }
2226 2226
2227 2227 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2228 2228 clear:both;
2229 2229 overflow:hidden;
2230 2230 margin:0;
2231 2231 padding:0 20px 10px;
2232 2232 }
2233 2233
2234 2234 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2235 2235 clear:both;
2236 2236 overflow:hidden;
2237 2237 margin:0;
2238 2238 padding:0;
2239 2239 }
2240 2240
2241 2241 #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 {
2242 2242 height:1%;
2243 2243 display:block;
2244 2244 color:#363636;
2245 2245 margin:0;
2246 2246 padding:2px 0 0;
2247 2247 }
2248 2248
2249 2249 #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 {
2250 2250 background:#FBE3E4;
2251 2251 border-top:1px solid #e1b2b3;
2252 2252 border-left:1px solid #e1b2b3;
2253 2253 border-right:1px solid #FBC2C4;
2254 2254 border-bottom:1px solid #FBC2C4;
2255 2255 }
2256 2256
2257 2257 #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 {
2258 2258 background:#E6EFC2;
2259 2259 border-top:1px solid #cebb98;
2260 2260 border-left:1px solid #cebb98;
2261 2261 border-right:1px solid #c6d880;
2262 2262 border-bottom:1px solid #c6d880;
2263 2263 }
2264 2264
2265 2265 #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 {
2266 2266 margin:0;
2267 2267 }
2268 2268
2269 2269 #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{
2270 2270 margin:0 0 0 0px !important;
2271 2271 padding:0;
2272 2272 }
2273 2273
2274 2274 #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 {
2275 2275 margin:0 0 0 200px;
2276 2276 padding:0;
2277 2277 }
2278 2278
2279 2279
2280 2280 #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 {
2281 2281 color:#000;
2282 2282 text-decoration:none;
2283 2283 }
2284 2284
2285 2285 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2286 2286 border:1px solid #666;
2287 2287 }
2288 2288
2289 2289 #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 {
2290 2290 clear:both;
2291 2291 overflow:hidden;
2292 2292 margin:0;
2293 2293 padding:8px 0 2px;
2294 2294 }
2295 2295
2296 2296 #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 {
2297 2297 float:left;
2298 2298 margin:0;
2299 2299 }
2300 2300
2301 2301 #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 {
2302 2302 height:1%;
2303 2303 display:block;
2304 2304 float:left;
2305 2305 margin:2px 0 0 4px;
2306 2306 }
2307 2307
2308 2308 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2309 2309 color:#000;
2310 2310 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2311 2311 font-size:11px;
2312 2312 font-weight:700;
2313 2313 margin:0;
2314 2314 }
2315 2315
2316 2316 div.form div.fields div.field div.button .ui-button,#content div.box div.form div.fields div.buttons input.ui-button {
2317 2317 background:#e5e3e3 url("../images/button.png") repeat-x;
2318 2318 border-top:1px solid #DDD;
2319 2319 border-left:1px solid #c6c6c6;
2320 2320 border-right:1px solid #DDD;
2321 2321 border-bottom:1px solid #c6c6c6;
2322 2322 color:#515151;
2323 2323 outline:none;
2324 2324 margin:0;
2325 2325 padding:6px 12px;
2326 2326 }
2327 2327
2328 2328 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2329 2329 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2330 2330 border-top:1px solid #ccc;
2331 2331 border-left:1px solid #bebebe;
2332 2332 border-right:1px solid #b1b1b1;
2333 2333 border-bottom:1px solid #afafaf;
2334 2334 color:#515151;
2335 2335 outline:none;
2336 2336 margin:0;
2337 2337 padding:6px 12px;
2338 2338 }
2339 2339
2340 2340 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2341 2341 display:inline;
2342 2342 }
2343 2343
2344 2344 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2345 2345 margin:10px 0 0 200px;
2346 2346 padding:0;
2347 2347 }
2348 2348
2349 2349 #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 {
2350 2350 margin:10px 0 0;
2351 2351 }
2352 2352
2353 2353 #content div.box table td.user,#content div.box table td.address {
2354 2354 width:10%;
2355 2355 text-align:center;
2356 2356 }
2357 2357
2358 2358 #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 {
2359 2359 text-align:right;
2360 2360 margin:6px 0 0;
2361 2361 padding:0;
2362 2362 }
2363 2363
2364 2364 #content div.box div.action div.button input.ui-button,#login div.form div.fields div.buttons input.ui-button,#register div.form div.fields div.buttons input.ui-button {
2365 2365 background:#e5e3e3 url("../images/button.png") repeat-x;
2366 2366 border-top:1px solid #DDD;
2367 2367 border-left:1px solid #c6c6c6;
2368 2368 border-right:1px solid #DDD;
2369 2369 border-bottom:1px solid #c6c6c6;
2370 2370 color:#515151;
2371 2371 margin:0;
2372 2372 padding:6px 12px;
2373 2373 }
2374 2374
2375 2375 #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 {
2376 2376 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2377 2377 border-top:1px solid #ccc;
2378 2378 border-left:1px solid #bebebe;
2379 2379 border-right:1px solid #b1b1b1;
2380 2380 border-bottom:1px solid #afafaf;
2381 2381 color:#515151;
2382 2382 margin:0;
2383 2383 padding:6px 12px;
2384 2384 }
2385 2385
2386 2386 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2387 2387 text-align:left;
2388 2388 float:left;
2389 2389 margin:0;
2390 2390 padding:0;
2391 2391 }
2392 2392
2393 2393 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2394 2394 height:1%;
2395 2395 display:block;
2396 2396 float:left;
2397 2397 background:#ebebeb url("../images/pager.png") repeat-x;
2398 2398 border-top:1px solid #dedede;
2399 2399 border-left:1px solid #cfcfcf;
2400 2400 border-right:1px solid #c4c4c4;
2401 2401 border-bottom:1px solid #c4c4c4;
2402 2402 color:#4A4A4A;
2403 2403 font-weight:700;
2404 2404 margin:0;
2405 2405 padding:6px 8px;
2406 2406 }
2407 2407
2408 2408 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2409 2409 color:#B4B4B4;
2410 2410 padding:6px;
2411 2411 }
2412 2412
2413 2413 #login,#register {
2414 2414 width:520px;
2415 2415 margin:10% auto 0;
2416 2416 padding:0;
2417 2417 }
2418 2418
2419 2419 #login div.color,#register div.color {
2420 2420 clear:both;
2421 2421 overflow:hidden;
2422 2422 background:#FFF;
2423 2423 margin:10px auto 0;
2424 2424 padding:3px 3px 3px 0;
2425 2425 }
2426 2426
2427 2427 #login div.color a,#register div.color a {
2428 2428 width:20px;
2429 2429 height:20px;
2430 2430 display:block;
2431 2431 float:left;
2432 2432 margin:0 0 0 3px;
2433 2433 padding:0;
2434 2434 }
2435 2435
2436 2436 #login div.title h5,#register div.title h5 {
2437 2437 color:#fff;
2438 2438 margin:10px;
2439 2439 padding:0;
2440 2440 }
2441 2441
2442 2442 #login div.form div.fields div.field,#register div.form div.fields div.field {
2443 2443 clear:both;
2444 2444 overflow:hidden;
2445 2445 margin:0;
2446 2446 padding:0 0 10px;
2447 2447 }
2448 2448
2449 2449 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2450 2450 height:1%;
2451 2451 display:block;
2452 2452 color:red;
2453 2453 margin:8px 0 0;
2454 2454 padding:0;
2455 2455 max-width: 320px;
2456 2456 }
2457 2457
2458 2458 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2459 2459 color:#000;
2460 2460 font-weight:700;
2461 2461 }
2462 2462
2463 2463 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2464 2464 float:left;
2465 2465 margin:0;
2466 2466 padding:0;
2467 2467 }
2468 2468
2469 2469 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2470 2470 margin:0 0 0 184px;
2471 2471 padding:0;
2472 2472 }
2473 2473
2474 2474 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2475 2475 color:#565656;
2476 2476 font-weight:700;
2477 2477 }
2478 2478
2479 2479 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2480 2480 color:#000;
2481 2481 font-size:1em;
2482 2482 font-weight:700;
2483 2483 font-family:Verdana, Helvetica, Sans-Serif;
2484 2484 margin:0;
2485 2485 }
2486 2486
2487 2487 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2488 2488 width:600px;
2489 2489 }
2490 2490
2491 2491 #changeset_content .container .left,#graph_content .container .left {
2492 2492 float:left;
2493 2493 width:70%;
2494 2494 padding-left:5px;
2495 2495 }
2496 2496
2497 2497 #changeset_content .container .left .date,.ac .match {
2498 2498 font-weight:700;
2499 2499 padding-top: 5px;
2500 2500 padding-bottom:5px;
2501 2501 }
2502 2502
2503 2503 div#legend_container table td,div#legend_choices table td {
2504 2504 border:none !important;
2505 2505 height:20px !important;
2506 2506 padding:0 !important;
2507 2507 }
2508 2508
2509 2509 #q_filter{
2510 2510 border:0 none;
2511 2511 color:#AAAAAA;
2512 2512 margin-bottom:-4px;
2513 2513 margin-top:-4px;
2514 2514 padding-left:3px;
2515 2515 }
2516 2516
@@ -1,243 +1,149 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${h.link_to(_('Users'),h.url('users'))}
12 12 &raquo;
13 13 ${_('edit')} "${c.user.username}"
14 14 </%def>
15 15
16 16 <%def name="page_nav()">
17 17 ${self.menu('admin')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21 <div class="box box-left">
22 22 <!-- box / title -->
23 23 <div class="title">
24 24 ${self.breadcrumbs()}
25 25 </div>
26 26 <!-- end box / title -->
27 27 ${h.form(url('user', id=c.user.user_id),method='put')}
28 28 <div class="form">
29 <!-- fields -->
30 <div class="fields">
31 29 <div class="field">
32 30 <div class="gravatar_box">
33 31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
34 32 <p>
35 33 <strong>Change your avatar at <a href="http://gravatar.com">gravatar.com</a></strong><br/>
36 34 ${_('Using')} ${c.user.email}
37 35 </p>
38 36 </div>
39 37 </div>
38 <div class="field">
39 <div class="label">
40 <label>${_('API key')}</label> ${c.user.api_key}
41 </div>
42 </div>
40 43
44 <div class="fields">
41 45 <div class="field">
42 46 <div class="label">
43 47 <label for="username">${_('Username')}:</label>
44 48 </div>
45 49 <div class="input">
46 50 ${h.text('username',class_='medium')}
47 51 </div>
48 52 </div>
49 53
50 54 <div class="field">
51 55 <div class="label">
52 56 <label for="ldap_dn">${_('LDAP DN')}:</label>
53 57 </div>
54 58 <div class="input">
55 ${h.text('ldap_dn',class_='small')}
59 ${h.text('ldap_dn',class_='medium')}
56 60 </div>
57 61 </div>
58 62
59 63 <div class="field">
60 64 <div class="label">
61 65 <label for="new_password">${_('New password')}:</label>
62 66 </div>
63 67 <div class="input">
64 68 ${h.password('new_password',class_='medium')}
65 69 </div>
66 70 </div>
67 71
68 72 <div class="field">
69 73 <div class="label">
70 74 <label for="name">${_('First Name')}:</label>
71 75 </div>
72 76 <div class="input">
73 77 ${h.text('name',class_='medium')}
74 78 </div>
75 79 </div>
76 80
77 81 <div class="field">
78 82 <div class="label">
79 83 <label for="lastname">${_('Last Name')}:</label>
80 84 </div>
81 85 <div class="input">
82 86 ${h.text('lastname',class_='medium')}
83 87 </div>
84 88 </div>
85 89
86 90 <div class="field">
87 91 <div class="label">
88 92 <label for="email">${_('Email')}:</label>
89 93 </div>
90 94 <div class="input">
91 95 ${h.text('email',class_='medium')}
92 96 </div>
93 97 </div>
94 98
95 99 <div class="field">
96 100 <div class="label label-checkbox">
97 101 <label for="active">${_('Active')}:</label>
98 102 </div>
99 103 <div class="checkboxes">
100 104 ${h.checkbox('active',value=True)}
101 105 </div>
102 106 </div>
103 107
104 108 <div class="field">
105 109 <div class="label label-checkbox">
106 110 <label for="admin">${_('Admin')}:</label>
107 111 </div>
108 112 <div class="checkboxes">
109 113 ${h.checkbox('admin',value=True)}
110 114 </div>
111 115 </div>
112 116 <div class="buttons">
113 117 ${h.submit('save','Save',class_="ui-button")}
114 118 ${h.reset('reset','Reset',class_="ui-button")}
115 119 </div>
116 120 </div>
117 121 </div>
118 122 ${h.end_form()}
119 123 </div>
120 124 <div class="box box-right">
121 125 <!-- box / title -->
122 126 <div class="title">
123 127 <h5>${_('Permissions')}</h5>
124 128 </div>
125 <form id="map_form" method="post" action="{%url update_permissions %}">
129 ${h.form(url('user', id=c.user.user_id),method='put')}
126 130 <div class="form">
131 <!-- fields -->
127 132 <div class="fields">
128
129
130
131 <table>
132 <tr>
133 <td class="label">${_('Permissions')}:</td>
134 <td>
135 <div>
136 <div style="float:left">
137 <div class="text">${_('Granted permissions')}</div>
138 ${h.select('granted_permissions',[],c.granted_permissions,multiple=True,size=8,style="min-width:210px")}
133 <div class="field">
134 <div class="label label-checkbox">
135 <label for="">${_('Create repositories')}:</label>
139 136 </div>
140 <div style="float:left;width:20px;padding-top:50px">
141 <img alt="add" id="add_element"
142 style="padding:2px;cursor:pointer"
143 src="${h.url("/images/icons/arrow_left.png")}">
144 <br />
145 <img alt="remove" id="remove_element"
146 style="padding:2px;cursor:pointer"
147 src="${h.url("/images/icons/arrow_right.png")}">
148 </div>
149 <div style="float:left">
150 <div class="text">${_('Available permissions')}</div>
151 ${h.select('available_permissions',[],c.available_permissions,multiple=True,size=8,style="min-width:210px")}
137 <div class="checkboxes">
138 ${h.checkbox('create',value=True)}
152 139 </div>
153 140 </div>
154 </td>
155 </tr>
156
157 </table>
158 141 <div class="buttons">
159 ${h.submit('Save','Save',class_="ui-button")}
142 ${h.submit('save','Save',class_="ui-button")}
143 ${h.reset('reset','Reset',class_="ui-button")}
160 144 </div>
161 145 </div>
162 146 </div>
163 </form>
164
165
166 <script type="text/javascript">
167 YAHOO.util.Event.onDOMReady(function(){
168
169 var D = YAHOO.util.Dom;
170 var E = YAHOO.util.Event;
171
172 //temp container for storage.
173 var cache = new Array();
174 var c = D.get('id_granted_permissions');
175
176 //get only selected options for further fullfilment
177 for(var i = 0;node =c.options[i];i++){
178 if(node.selected){
179 //push selected to my temp storage left overs :)
180 cache.push(node);
181 }
182 }
183
184 //clear select
185 c.options.length = 0;
186
187 //fill it with remembered options
188 for(var i = 0;node = cache[i];i++){
189 c.options[i]=new Option(node.text, node.value, false, false);
190 }
191
192 function target_callback(e){
193 window.location='/admin/t4?g='+e.target.value;
194 }
195
196 function prompts_action_callback(e){
197
198 var choosen = D.get('id_granted_permissions');
199 var availible = D.get('id_available_permissions');
200
201 if (this.id=='add_element'){
202 for(var i=0; node = availible.options[i];i++){
203 if(node.selected){
204 choosen.appendChild(new Option(node.text, node.value, false, false));
205 }
206 }
207 }
208 else if (this.id=='remove_element'){
209
210 //temp container for storage.
211 cache = new Array();
212
213 for(var i = 0;node = choosen.options[i];i++){
214 if(!node.selected){
215 //push left overs :)
216 cache.push(node);
217 }
218 }
219 //clear select
220 choosen.options.length = 0;
221 for(var i = 0;node = cache[i];i++){
222 choosen.options[i]=new Option(node.text, node.value, false, false);
223 }
224 }
225 else{
226
227 }
228 }
229
230 E.addListener('id_groups','change',target_callback);
231
232 E.addListener(['add_element','remove_element'],'click',prompts_action_callback)
233
234 E.addListener('map_form','submit',function(){
235 var choosen = D.get('id_granted_permissions');
236 for (var i = 0; i < choosen.options.length; i++) {
237 choosen.options[i].selected = 'selected';
238 }
239 })
240 });
241 </script>
147 ${h.end_form()}
242 148 </div>
243 149 </%def>
@@ -1,207 +1,211 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${_('My Account')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17
18 18 <div class="box box-left">
19 19 <!-- box / title -->
20 20 <div class="title">
21 21 ${self.breadcrumbs()}
22 22 </div>
23 23 <!-- end box / title -->
24 24 <div>
25 25 ${h.form(url('admin_settings_my_account_update'),method='put')}
26 26 <div class="form">
27 27
28 28 <div class="field">
29 29 <div class="gravatar_box">
30 30 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
31 31 <p>
32 32 <strong>Change your avatar at <a href="http://gravatar.com">gravatar.com</a></strong><br/>
33 33 ${_('Using')} ${c.user.email}
34 34 </p>
35 35 </div>
36 36 </div>
37
37 <div class="field">
38 <div class="label">
39 <label>${_('API key')}</label> ${c.user.api_key}
40 </div>
41 </div>
38 42 <div class="fields">
39 43 <div class="field">
40 44 <div class="label">
41 45 <label for="username">${_('Username')}:</label>
42 46 </div>
43 47 <div class="input">
44 48 ${h.text('username',class_="medium")}
45 49 </div>
46 50 </div>
47 51
48 52 <div class="field">
49 53 <div class="label">
50 54 <label for="new_password">${_('New password')}:</label>
51 55 </div>
52 56 <div class="input">
53 57 ${h.password('new_password',class_="medium")}
54 58 </div>
55 59 </div>
56 60
57 61 <div class="field">
58 62 <div class="label">
59 63 <label for="name">${_('First Name')}:</label>
60 64 </div>
61 65 <div class="input">
62 66 ${h.text('name',class_="medium")}
63 67 </div>
64 68 </div>
65 69
66 70 <div class="field">
67 71 <div class="label">
68 72 <label for="lastname">${_('Last Name')}:</label>
69 73 </div>
70 74 <div class="input">
71 75 ${h.text('lastname',class_="medium")}
72 76 </div>
73 77 </div>
74 78
75 79 <div class="field">
76 80 <div class="label">
77 81 <label for="email">${_('Email')}:</label>
78 82 </div>
79 83 <div class="input">
80 84 ${h.text('email',class_="medium")}
81 85 </div>
82 86 </div>
83 87
84 88 <div class="buttons">
85 89 ${h.submit('save','Save',class_="ui-button")}
86 90 ${h.reset('reset','Reset',class_="ui-button")}
87 91 </div>
88 92 </div>
89 93 </div>
90 94 ${h.end_form()}
91 95 </div>
92 96 </div>
93 97
94 98 <div class="box box-right">
95 99 <!-- box / title -->
96 100 <div class="title">
97 101 <h5>${_('My repositories')}
98 102 <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
99 103 </h5>
100 104 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
101 105 <ul class="links">
102 106 <li>
103 107 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
104 108 </li>
105 109 </ul>
106 110 %endif
107 111 </div>
108 112 <!-- end box / title -->
109 113 <div class="table">
110 114 <table>
111 115 <thead>
112 116 <tr>
113 117 <th class="left">${_('Name')}</th>
114 118 <th class="left">${_('revision')}</th>
115 119 <th colspan="2" class="left">${_('action')}</th>
116 120 </thead>
117 121 <tbody>
118 122 %if c.user_repos:
119 123 %for repo in c.user_repos:
120 124 <tr>
121 125 <td>
122 126 %if repo['dbrepo']['repo_type'] =='hg':
123 127 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
124 128 %elif repo['dbrepo']['repo_type'] =='git':
125 129 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
126 130 %else:
127 131
128 132 %endif
129 133 %if repo['dbrepo']['private']:
130 134 <img class="icon" alt="${_('private')}" src="${h.url("/images/icons/lock.png")}"/>
131 135 %else:
132 136 <img class="icon" alt="${_('public')}" src="${h.url("/images/icons/lock_open.png")}"/>
133 137 %endif
134 138
135 139 ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
136 140 %if repo['dbrepo_fork']:
137 141 <a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
138 142 <img class="icon" alt="${_('public')}"
139 143 title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}"
140 144 src="${h.url("/images/icons/arrow_divide.png")}"/></a>
141 145 %endif
142 146 </td>
143 147 <td><span class="tooltip" title="${repo['repo'].last_change}">${("r%s:%s") % (h.get_changeset_safe(repo['repo'],'tip').revision,h.short_id(h.get_changeset_safe(repo['repo'],'tip').raw_id))}</span></td>
144 148 <td><a href="${h.url('repo_settings_home',repo_name=repo['repo'].name)}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url("/images/icons/application_form_edit.png")}"/></a></td>
145 149 <td>
146 150 ${h.form(url('repo_settings_delete', repo_name=repo['repo'].name),method='delete')}
147 151 ${h.submit('remove_%s' % repo['repo'].name,'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
148 152 ${h.end_form()}
149 153 </td>
150 154 </tr>
151 155 %endfor
152 156 %else:
153 157 ${_('No repositories yet')}
154 158 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
155 159 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
156 160 %endif
157 161 %endif
158 162 </tbody>
159 163 </table>
160 164 </div>
161 165
162 166 </div>
163 167 <script type="text/javascript">
164 168 var D = YAHOO.util.Dom;
165 169 var E = YAHOO.util.Event;
166 170 var S = YAHOO.util.Selector;
167 171
168 172 var q_filter = D.get('q_filter');
169 173 var F = YAHOO.namespace('q_filter');
170 174
171 175 E.on(q_filter,'click',function(){
172 176 q_filter.value = '';
173 177 });
174 178
175 179 F.filterTimeout = null;
176 180
177 181 F.updateFilter = function() {
178 182 // Reset timeout
179 183 F.filterTimeout = null;
180 184
181 185 var obsolete = [];
182 186 var nodes = S.query('div.table tr td a.repo_name');
183 187 var req = D.get('q_filter').value;
184 188 for (n in nodes){
185 189 D.setStyle(nodes[n].parentNode.parentNode,'display','')
186 190 }
187 191 if (req){
188 192 for (n in nodes){
189 193 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
190 194 obsolete.push(nodes[n]);
191 195 }
192 196 }
193 197 if(obsolete){
194 198 for (n in obsolete){
195 199 D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
196 200 }
197 201 }
198 202 }
199 203 }
200 204
201 205 E.on(q_filter,'keyup',function(e){
202 206 clearTimeout(F.filterTimeout);
203 207 setTimeout(F.updateFilter,600);
204 208 });
205 209
206 210 </script>
207 211 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now