##// END OF EJS Templates
Cleaned the way cache keys are invalidated...
marcink -
r3020:00498b3e beta
parent child Browse files
Show More
@@ -1,714 +1,716 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.utils
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Utilities library for RhodeCode
7 7
8 8 :created_on: Apr 18, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import re
28 28 import logging
29 29 import datetime
30 30 import traceback
31 31 import paste
32 32 import beaker
33 33 import tarfile
34 34 import shutil
35 35 from os.path import abspath
36 36 from os.path import dirname as dn, join as jn
37 37
38 38 from paste.script.command import Command, BadCommand
39 39
40 40 from mercurial import ui, config
41 41
42 42 from webhelpers.text import collapse, remove_formatting, strip_tags
43 43
44 44 from rhodecode.lib.vcs import get_backend
45 45 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 47 from rhodecode.lib.vcs.utils.helpers import get_scm
48 48 from rhodecode.lib.vcs.exceptions import VCSError
49 49
50 50 from rhodecode.lib.caching_query import FromCache
51 51
52 52 from rhodecode.model import meta
53 53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
54 54 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
55 55 from rhodecode.model.meta import Session
56 56 from rhodecode.model.repos_group import ReposGroupModel
57 57 from rhodecode.lib.utils2 import safe_str, safe_unicode
58 58 from rhodecode.lib.vcs.utils.fakemod import create_module
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
63 63
64 64
65 65 def recursive_replace(str_, replace=' '):
66 66 """
67 67 Recursive replace of given sign to just one instance
68 68
69 69 :param str_: given string
70 70 :param replace: char to find and replace multiple instances
71 71
72 72 Examples::
73 73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
74 74 'Mighty-Mighty-Bo-sstones'
75 75 """
76 76
77 77 if str_.find(replace * 2) == -1:
78 78 return str_
79 79 else:
80 80 str_ = str_.replace(replace * 2, replace)
81 81 return recursive_replace(str_, replace)
82 82
83 83
84 84 def repo_name_slug(value):
85 85 """
86 86 Return slug of name of repository
87 87 This function is called on each creation/modification
88 88 of repository to prevent bad names in repo
89 89 """
90 90
91 91 slug = remove_formatting(value)
92 92 slug = strip_tags(slug)
93 93
94 94 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
95 95 slug = slug.replace(c, '-')
96 96 slug = recursive_replace(slug, '-')
97 97 slug = collapse(slug, '-')
98 98 return slug
99 99
100 100
101 101 def get_repo_slug(request):
102 102 _repo = request.environ['pylons.routes_dict'].get('repo_name')
103 103 if _repo:
104 104 _repo = _repo.rstrip('/')
105 105 return _repo
106 106
107 107
108 108 def get_repos_group_slug(request):
109 109 _group = request.environ['pylons.routes_dict'].get('group_name')
110 110 if _group:
111 111 _group = _group.rstrip('/')
112 112 return _group
113 113
114 114
115 115 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
116 116 """
117 117 Action logger for various actions made by users
118 118
119 119 :param user: user that made this action, can be a unique username string or
120 120 object containing user_id attribute
121 121 :param action: action to log, should be on of predefined unique actions for
122 122 easy translations
123 123 :param repo: string name of repository or object containing repo_id,
124 124 that action was made on
125 125 :param ipaddr: optional ip address from what the action was made
126 126 :param sa: optional sqlalchemy session
127 127
128 128 """
129 129
130 130 if not sa:
131 131 sa = meta.Session()
132 132
133 133 try:
134 134 if hasattr(user, 'user_id'):
135 135 user_obj = user
136 136 elif isinstance(user, basestring):
137 137 user_obj = User.get_by_username(user)
138 138 else:
139 139 raise Exception('You have to provide a user object or a username')
140 140
141 141 if hasattr(repo, 'repo_id'):
142 142 repo_obj = Repository.get(repo.repo_id)
143 143 repo_name = repo_obj.repo_name
144 144 elif isinstance(repo, basestring):
145 145 repo_name = repo.lstrip('/')
146 146 repo_obj = Repository.get_by_repo_name(repo_name)
147 147 else:
148 148 repo_obj = None
149 149 repo_name = ''
150 150
151 151 user_log = UserLog()
152 152 user_log.user_id = user_obj.user_id
153 153 user_log.action = safe_unicode(action)
154 154
155 155 user_log.repository = repo_obj
156 156 user_log.repository_name = repo_name
157 157
158 158 user_log.action_date = datetime.datetime.now()
159 159 user_log.user_ip = ipaddr
160 160 sa.add(user_log)
161 161
162 162 log.info(
163 163 'Adding user %s, action %s on %s' % (user_obj, action,
164 164 safe_unicode(repo))
165 165 )
166 166 if commit:
167 167 sa.commit()
168 168 except:
169 169 log.error(traceback.format_exc())
170 170 raise
171 171
172 172
173 173 def get_repos(path, recursive=False):
174 174 """
175 175 Scans given path for repos and return (name,(type,path)) tuple
176 176
177 177 :param path: path to scan for repositories
178 178 :param recursive: recursive search and return names with subdirs in front
179 179 """
180 180
181 181 # remove ending slash for better results
182 182 path = path.rstrip(os.sep)
183 183
184 184 def _get_repos(p):
185 185 if not os.access(p, os.W_OK):
186 186 return
187 187 for dirpath in os.listdir(p):
188 188 if os.path.isfile(os.path.join(p, dirpath)):
189 189 continue
190 190 cur_path = os.path.join(p, dirpath)
191 191 try:
192 192 scm_info = get_scm(cur_path)
193 193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
194 194 except VCSError:
195 195 if not recursive:
196 196 continue
197 197 #check if this dir containts other repos for recursive scan
198 198 rec_path = os.path.join(p, dirpath)
199 199 if os.path.isdir(rec_path):
200 200 for inner_scm in _get_repos(rec_path):
201 201 yield inner_scm
202 202
203 203 return _get_repos(path)
204 204
205 205
206 206 def is_valid_repo(repo_name, base_path, scm=None):
207 207 """
208 208 Returns True if given path is a valid repository False otherwise.
209 209 If scm param is given also compare if given scm is the same as expected
210 210 from scm parameter
211 211
212 212 :param repo_name:
213 213 :param base_path:
214 214 :param scm:
215 215
216 216 :return True: if given path is a valid repository
217 217 """
218 218 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
219 219
220 220 try:
221 221 scm_ = get_scm(full_path)
222 222 if scm:
223 223 return scm_[0] == scm
224 224 return True
225 225 except VCSError:
226 226 return False
227 227
228 228
229 229 def is_valid_repos_group(repos_group_name, base_path):
230 230 """
231 231 Returns True if given path is a repos group False otherwise
232 232
233 233 :param repo_name:
234 234 :param base_path:
235 235 """
236 236 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
237 237
238 238 # check if it's not a repo
239 239 if is_valid_repo(repos_group_name, base_path):
240 240 return False
241 241
242 242 try:
243 243 # we need to check bare git repos at higher level
244 244 # since we might match branches/hooks/info/objects or possible
245 245 # other things inside bare git repo
246 246 get_scm(os.path.dirname(full_path))
247 247 return False
248 248 except VCSError:
249 249 pass
250 250
251 251 # check if it's a valid path
252 252 if os.path.isdir(full_path):
253 253 return True
254 254
255 255 return False
256 256
257 257
258 258 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
259 259 while True:
260 260 ok = raw_input(prompt)
261 261 if ok in ('y', 'ye', 'yes'):
262 262 return True
263 263 if ok in ('n', 'no', 'nop', 'nope'):
264 264 return False
265 265 retries = retries - 1
266 266 if retries < 0:
267 267 raise IOError
268 268 print complaint
269 269
270 270 #propagated from mercurial documentation
271 271 ui_sections = ['alias', 'auth',
272 272 'decode/encode', 'defaults',
273 273 'diff', 'email',
274 274 'extensions', 'format',
275 275 'merge-patterns', 'merge-tools',
276 276 'hooks', 'http_proxy',
277 277 'smtp', 'patch',
278 278 'paths', 'profiling',
279 279 'server', 'trusted',
280 280 'ui', 'web', ]
281 281
282 282
283 283 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
284 284 """
285 285 A function that will read python rc files or database
286 286 and make an mercurial ui object from read options
287 287
288 288 :param path: path to mercurial config file
289 289 :param checkpaths: check the path
290 290 :param read_from: read from 'file' or 'db'
291 291 """
292 292
293 293 baseui = ui.ui()
294 294
295 295 # clean the baseui object
296 296 baseui._ocfg = config.config()
297 297 baseui._ucfg = config.config()
298 298 baseui._tcfg = config.config()
299 299
300 300 if read_from == 'file':
301 301 if not os.path.isfile(path):
302 302 log.debug('hgrc file is not present at %s, skipping...' % path)
303 303 return False
304 304 log.debug('reading hgrc from %s' % path)
305 305 cfg = config.config()
306 306 cfg.read(path)
307 307 for section in ui_sections:
308 308 for k, v in cfg.items(section):
309 309 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
310 310 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
311 311
312 312 elif read_from == 'db':
313 313 sa = meta.Session()
314 314 ret = sa.query(RhodeCodeUi)\
315 315 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
316 316 .all()
317 317
318 318 hg_ui = ret
319 319 for ui_ in hg_ui:
320 320 if ui_.ui_active:
321 321 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
322 322 ui_.ui_key, ui_.ui_value)
323 323 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
324 324 safe_str(ui_.ui_value))
325 325 if ui_.ui_key == 'push_ssl':
326 326 # force set push_ssl requirement to False, rhodecode
327 327 # handles that
328 328 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
329 329 False)
330 330 if clear_session:
331 331 meta.Session.remove()
332 332 return baseui
333 333
334 334
335 335 def set_rhodecode_config(config):
336 336 """
337 337 Updates pylons config with new settings from database
338 338
339 339 :param config:
340 340 """
341 341 hgsettings = RhodeCodeSetting.get_app_settings()
342 342
343 343 for k, v in hgsettings.items():
344 344 config[k] = v
345 345
346 346
347 347 def invalidate_cache(cache_key, *args):
348 348 """
349 349 Puts cache invalidation task into db for
350 350 further global cache invalidation
351 351 """
352 352
353 353 from rhodecode.model.scm import ScmModel
354 354
355 355 if cache_key.startswith('get_repo_cached_'):
356 356 name = cache_key.split('get_repo_cached_')[-1]
357 357 ScmModel().mark_for_invalidation(name)
358 358
359 359
360 360 def map_groups(path):
361 361 """
362 362 Given a full path to a repository, create all nested groups that this
363 363 repo is inside. This function creates parent-child relationships between
364 364 groups and creates default perms for all new groups.
365 365
366 366 :param paths: full path to repository
367 367 """
368 368 sa = meta.Session()
369 369 groups = path.split(Repository.url_sep())
370 370 parent = None
371 371 group = None
372 372
373 373 # last element is repo in nested groups structure
374 374 groups = groups[:-1]
375 375 rgm = ReposGroupModel(sa)
376 376 for lvl, group_name in enumerate(groups):
377 377 group_name = '/'.join(groups[:lvl] + [group_name])
378 378 group = RepoGroup.get_by_group_name(group_name)
379 379 desc = '%s group' % group_name
380 380
381 381 # skip folders that are now removed repos
382 382 if REMOVED_REPO_PAT.match(group_name):
383 383 break
384 384
385 385 if group is None:
386 386 log.debug('creating group level: %s group_name: %s' % (lvl,
387 387 group_name))
388 388 group = RepoGroup(group_name, parent)
389 389 group.group_description = desc
390 390 sa.add(group)
391 391 rgm._create_default_perms(group)
392 392 sa.flush()
393 393 parent = group
394 394 return group
395 395
396 396
397 397 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
398 398 install_git_hook=False):
399 399 """
400 400 maps all repos given in initial_repo_list, non existing repositories
401 401 are created, if remove_obsolete is True it also check for db entries
402 402 that are not in initial_repo_list and removes them.
403 403
404 404 :param initial_repo_list: list of repositories found by scanning methods
405 405 :param remove_obsolete: check for obsolete entries in database
406 406 :param install_git_hook: if this is True, also check and install githook
407 407 for a repo if missing
408 408 """
409 409 from rhodecode.model.repo import RepoModel
410 410 from rhodecode.model.scm import ScmModel
411 411 sa = meta.Session()
412 412 rm = RepoModel()
413 413 user = sa.query(User).filter(User.admin == True).first()
414 414 if user is None:
415 415 raise Exception('Missing administrative account!')
416 416 added = []
417 417
418 418 # # clear cache keys
419 419 # log.debug("Clearing cache keys now...")
420 420 # CacheInvalidation.clear_cache()
421 421 # sa.commit()
422 422
423 423 for name, repo in initial_repo_list.items():
424 424 group = map_groups(name)
425 425 db_repo = rm.get_by_repo_name(name)
426 426 # found repo that is on filesystem not in RhodeCode database
427 427 if not db_repo:
428 428 log.info('repository %s not found, creating now' % name)
429 429 added.append(name)
430 430 desc = (repo.description
431 431 if repo.description != 'unknown'
432 432 else '%s repository' % name)
433 433 new_repo = rm.create_repo(
434 434 repo_name=name,
435 435 repo_type=repo.alias,
436 436 description=desc,
437 437 repos_group=getattr(group, 'group_id', None),
438 438 owner=user,
439 439 just_db=True
440 440 )
441 441 # we added that repo just now, and make sure it has githook
442 442 # installed
443 443 if new_repo.repo_type == 'git':
444 444 ScmModel().install_git_hook(new_repo.scm_instance)
445 445 elif install_git_hook:
446 446 if db_repo.repo_type == 'git':
447 447 ScmModel().install_git_hook(db_repo.scm_instance)
448 448 # during starting install all cache keys for all repositories in the
449 449 # system, this will register all repos and multiple instances
450 450 key, _prefix, _org_key = CacheInvalidation._get_key(name)
451 log.debug("Creating a cache key for %s instance_id:`%s`" % (name, _prefix))
452 CacheInvalidation._get_or_create_key(key, _prefix, _org_key, commit=False)
451 CacheInvalidation.invalidate(name)
452 log.debug("Creating a cache key for %s instance_id=>`%s`"
453 % (name, _prefix or '-'))
454
453 455 sa.commit()
454 456 removed = []
455 457 if remove_obsolete:
456 458 # remove from database those repositories that are not in the filesystem
457 459 for repo in sa.query(Repository).all():
458 460 if repo.repo_name not in initial_repo_list.keys():
459 461 log.debug("Removing non-existing repository found in db `%s`" %
460 462 repo.repo_name)
461 463 try:
462 464 sa.delete(repo)
463 465 sa.commit()
464 466 removed.append(repo.repo_name)
465 467 except:
466 468 #don't hold further removals on error
467 469 log.error(traceback.format_exc())
468 470 sa.rollback()
469 471
470 472 return added, removed
471 473
472 474
473 475 # set cache regions for beaker so celery can utilise it
474 476 def add_cache(settings):
475 477 cache_settings = {'regions': None}
476 478 for key in settings.keys():
477 479 for prefix in ['beaker.cache.', 'cache.']:
478 480 if key.startswith(prefix):
479 481 name = key.split(prefix)[1].strip()
480 482 cache_settings[name] = settings[key].strip()
481 483 if cache_settings['regions']:
482 484 for region in cache_settings['regions'].split(','):
483 485 region = region.strip()
484 486 region_settings = {}
485 487 for key, value in cache_settings.items():
486 488 if key.startswith(region):
487 489 region_settings[key.split('.')[1]] = value
488 490 region_settings['expire'] = int(region_settings.get('expire',
489 491 60))
490 492 region_settings.setdefault('lock_dir',
491 493 cache_settings.get('lock_dir'))
492 494 region_settings.setdefault('data_dir',
493 495 cache_settings.get('data_dir'))
494 496
495 497 if 'type' not in region_settings:
496 498 region_settings['type'] = cache_settings.get('type',
497 499 'memory')
498 500 beaker.cache.cache_regions[region] = region_settings
499 501
500 502
501 503 def load_rcextensions(root_path):
502 504 import rhodecode
503 505 from rhodecode.config import conf
504 506
505 507 path = os.path.join(root_path, 'rcextensions', '__init__.py')
506 508 if os.path.isfile(path):
507 509 rcext = create_module('rc', path)
508 510 EXT = rhodecode.EXTENSIONS = rcext
509 511 log.debug('Found rcextensions now loading %s...' % rcext)
510 512
511 513 # Additional mappings that are not present in the pygments lexers
512 514 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
513 515
514 516 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
515 517
516 518 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
517 519 log.debug('settings custom INDEX_EXTENSIONS')
518 520 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
519 521
520 522 #ADDITIONAL MAPPINGS
521 523 log.debug('adding extra into INDEX_EXTENSIONS')
522 524 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
523 525
524 526
525 527 #==============================================================================
526 528 # TEST FUNCTIONS AND CREATORS
527 529 #==============================================================================
528 530 def create_test_index(repo_location, config, full_index):
529 531 """
530 532 Makes default test index
531 533
532 534 :param config: test config
533 535 :param full_index:
534 536 """
535 537
536 538 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
537 539 from rhodecode.lib.pidlock import DaemonLock, LockHeld
538 540
539 541 repo_location = repo_location
540 542
541 543 index_location = os.path.join(config['app_conf']['index_dir'])
542 544 if not os.path.exists(index_location):
543 545 os.makedirs(index_location)
544 546
545 547 try:
546 548 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
547 549 WhooshIndexingDaemon(index_location=index_location,
548 550 repo_location=repo_location)\
549 551 .run(full_index=full_index)
550 552 l.release()
551 553 except LockHeld:
552 554 pass
553 555
554 556
555 557 def create_test_env(repos_test_path, config):
556 558 """
557 559 Makes a fresh database and
558 560 install test repository into tmp dir
559 561 """
560 562 from rhodecode.lib.db_manage import DbManage
561 563 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
562 564
563 565 # PART ONE create db
564 566 dbconf = config['sqlalchemy.db1.url']
565 567 log.debug('making test db %s' % dbconf)
566 568
567 569 # create test dir if it doesn't exist
568 570 if not os.path.isdir(repos_test_path):
569 571 log.debug('Creating testdir %s' % repos_test_path)
570 572 os.makedirs(repos_test_path)
571 573
572 574 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
573 575 tests=True)
574 576 dbmanage.create_tables(override=True)
575 577 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
576 578 dbmanage.create_default_user()
577 579 dbmanage.admin_prompt()
578 580 dbmanage.create_permissions()
579 581 dbmanage.populate_default_permissions()
580 582 Session().commit()
581 583 # PART TWO make test repo
582 584 log.debug('making test vcs repositories')
583 585
584 586 idx_path = config['app_conf']['index_dir']
585 587 data_path = config['app_conf']['cache_dir']
586 588
587 589 #clean index and data
588 590 if idx_path and os.path.exists(idx_path):
589 591 log.debug('remove %s' % idx_path)
590 592 shutil.rmtree(idx_path)
591 593
592 594 if data_path and os.path.exists(data_path):
593 595 log.debug('remove %s' % data_path)
594 596 shutil.rmtree(data_path)
595 597
596 598 #CREATE DEFAULT TEST REPOS
597 599 cur_dir = dn(dn(abspath(__file__)))
598 600 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
599 601 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
600 602 tar.close()
601 603
602 604 cur_dir = dn(dn(abspath(__file__)))
603 605 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
604 606 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
605 607 tar.close()
606 608
607 609 #LOAD VCS test stuff
608 610 from rhodecode.tests.vcs import setup_package
609 611 setup_package()
610 612
611 613
612 614 #==============================================================================
613 615 # PASTER COMMANDS
614 616 #==============================================================================
615 617 class BasePasterCommand(Command):
616 618 """
617 619 Abstract Base Class for paster commands.
618 620
619 621 The celery commands are somewhat aggressive about loading
620 622 celery.conf, and since our module sets the `CELERY_LOADER`
621 623 environment variable to our loader, we have to bootstrap a bit and
622 624 make sure we've had a chance to load the pylons config off of the
623 625 command line, otherwise everything fails.
624 626 """
625 627 min_args = 1
626 628 min_args_error = "Please provide a paster config file as an argument."
627 629 takes_config_file = 1
628 630 requires_config_file = True
629 631
630 632 def notify_msg(self, msg, log=False):
631 633 """Make a notification to user, additionally if logger is passed
632 634 it logs this action using given logger
633 635
634 636 :param msg: message that will be printed to user
635 637 :param log: logging instance, to use to additionally log this message
636 638
637 639 """
638 640 if log and isinstance(log, logging):
639 641 log(msg)
640 642
641 643 def run(self, args):
642 644 """
643 645 Overrides Command.run
644 646
645 647 Checks for a config file argument and loads it.
646 648 """
647 649 if len(args) < self.min_args:
648 650 raise BadCommand(
649 651 self.min_args_error % {'min_args': self.min_args,
650 652 'actual_args': len(args)})
651 653
652 654 # Decrement because we're going to lob off the first argument.
653 655 # @@ This is hacky
654 656 self.min_args -= 1
655 657 self.bootstrap_config(args[0])
656 658 self.update_parser()
657 659 return super(BasePasterCommand, self).run(args[1:])
658 660
659 661 def update_parser(self):
660 662 """
661 663 Abstract method. Allows for the class's parser to be updated
662 664 before the superclass's `run` method is called. Necessary to
663 665 allow options/arguments to be passed through to the underlying
664 666 celery command.
665 667 """
666 668 raise NotImplementedError("Abstract Method.")
667 669
668 670 def bootstrap_config(self, conf):
669 671 """
670 672 Loads the pylons configuration.
671 673 """
672 674 from pylons import config as pylonsconfig
673 675
674 676 self.path_to_ini_file = os.path.realpath(conf)
675 677 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
676 678 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
677 679
678 680
679 681 def check_git_version():
680 682 """
681 683 Checks what version of git is installed in system, and issues a warning
682 684 if it's too old for RhodeCode to properly work.
683 685 """
684 686 import subprocess
685 687 from distutils.version import StrictVersion
686 688 from rhodecode import BACKENDS
687 689
688 690 p = subprocess.Popen('git --version', shell=True,
689 691 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
690 692 stdout, stderr = p.communicate()
691 693 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
692 694 if len(ver.split('.')) > 3:
693 695 #StrictVersion needs to be only 3 element type
694 696 ver = '.'.join(ver.split('.')[:3])
695 697 try:
696 698 _ver = StrictVersion(ver)
697 699 except:
698 700 _ver = StrictVersion('0.0.0')
699 701 stderr = traceback.format_exc()
700 702
701 703 req_ver = '1.7.4'
702 704 to_old_git = False
703 705 if _ver < StrictVersion(req_ver):
704 706 to_old_git = True
705 707
706 708 if 'git' in BACKENDS:
707 709 log.debug('GIT version detected: %s' % stdout)
708 710 if stderr:
709 711 log.warning('Unable to detect git version org error was:%r' % stderr)
710 712 elif to_old_git:
711 713 log.warning('RhodeCode detected git version %s, which is too old '
712 714 'for the system to function properly. Make sure '
713 715 'its version is at least %s' % (ver, req_ver))
714 716 return _ver
@@ -1,1802 +1,1812 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.db
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 Database Models for RhodeCode
7 7
8 8 :created_on: Apr 08, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import datetime
29 29 import traceback
30 30 import hashlib
31 31 import time
32 32 from collections import defaultdict
33 33
34 34 from sqlalchemy import *
35 35 from sqlalchemy.ext.hybrid import hybrid_property
36 36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 37 from sqlalchemy.exc import DatabaseError
38 38 from beaker.cache import cache_region, region_invalidate
39 39 from webob.exc import HTTPNotFound
40 40
41 41 from pylons.i18n.translation import lazy_ugettext as _
42 42
43 43 from rhodecode.lib.vcs import get_backend
44 44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 45 from rhodecode.lib.vcs.exceptions import VCSError
46 46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 47
48 48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 49 safe_unicode, remove_suffix
50 50 from rhodecode.lib.compat import json
51 51 from rhodecode.lib.caching_query import FromCache
52 52
53 53 from rhodecode.model.meta import Base, Session
54 54
55 55 URL_SEP = '/'
56 56 log = logging.getLogger(__name__)
57 57
58 58 #==============================================================================
59 59 # BASE CLASSES
60 60 #==============================================================================
61 61
62 62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63 63
64 64
65 65 class BaseModel(object):
66 66 """
67 67 Base Model for all classess
68 68 """
69 69
70 70 @classmethod
71 71 def _get_keys(cls):
72 72 """return column names for this model """
73 73 return class_mapper(cls).c.keys()
74 74
75 75 def get_dict(self):
76 76 """
77 77 return dict with keys and values corresponding
78 78 to this model data """
79 79
80 80 d = {}
81 81 for k in self._get_keys():
82 82 d[k] = getattr(self, k)
83 83
84 84 # also use __json__() if present to get additional fields
85 85 _json_attr = getattr(self, '__json__', None)
86 86 if _json_attr:
87 87 # update with attributes from __json__
88 88 if callable(_json_attr):
89 89 _json_attr = _json_attr()
90 90 for k, val in _json_attr.iteritems():
91 91 d[k] = val
92 92 return d
93 93
94 94 def get_appstruct(self):
95 95 """return list with keys and values tupples corresponding
96 96 to this model data """
97 97
98 98 l = []
99 99 for k in self._get_keys():
100 100 l.append((k, getattr(self, k),))
101 101 return l
102 102
103 103 def populate_obj(self, populate_dict):
104 104 """populate model with data from given populate_dict"""
105 105
106 106 for k in self._get_keys():
107 107 if k in populate_dict:
108 108 setattr(self, k, populate_dict[k])
109 109
110 110 @classmethod
111 111 def query(cls):
112 112 return Session().query(cls)
113 113
114 114 @classmethod
115 115 def get(cls, id_):
116 116 if id_:
117 117 return cls.query().get(id_)
118 118
119 119 @classmethod
120 120 def get_or_404(cls, id_):
121 121 try:
122 122 id_ = int(id_)
123 123 except (TypeError, ValueError):
124 124 raise HTTPNotFound
125 125
126 126 res = cls.query().get(id_)
127 127 if not res:
128 128 raise HTTPNotFound
129 129 return res
130 130
131 131 @classmethod
132 132 def getAll(cls):
133 133 return cls.query().all()
134 134
135 135 @classmethod
136 136 def delete(cls, id_):
137 137 obj = cls.query().get(id_)
138 138 Session().delete(obj)
139 139
140 140 def __repr__(self):
141 141 if hasattr(self, '__unicode__'):
142 142 # python repr needs to return str
143 143 return safe_str(self.__unicode__())
144 144 return '<DB:%s>' % (self.__class__.__name__)
145 145
146 146
147 147 class RhodeCodeSetting(Base, BaseModel):
148 148 __tablename__ = 'rhodecode_settings'
149 149 __table_args__ = (
150 150 UniqueConstraint('app_settings_name'),
151 151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 152 'mysql_charset': 'utf8'}
153 153 )
154 154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
157 157
158 158 def __init__(self, k='', v=''):
159 159 self.app_settings_name = k
160 160 self.app_settings_value = v
161 161
162 162 @validates('_app_settings_value')
163 163 def validate_settings_value(self, key, val):
164 164 assert type(val) == unicode
165 165 return val
166 166
167 167 @hybrid_property
168 168 def app_settings_value(self):
169 169 v = self._app_settings_value
170 170 if self.app_settings_name == 'ldap_active':
171 171 v = str2bool(v)
172 172 return v
173 173
174 174 @app_settings_value.setter
175 175 def app_settings_value(self, val):
176 176 """
177 177 Setter that will always make sure we use unicode in app_settings_value
178 178
179 179 :param val:
180 180 """
181 181 self._app_settings_value = safe_unicode(val)
182 182
183 183 def __unicode__(self):
184 184 return u"<%s('%s:%s')>" % (
185 185 self.__class__.__name__,
186 186 self.app_settings_name, self.app_settings_value
187 187 )
188 188
189 189 @classmethod
190 190 def get_by_name(cls, key):
191 191 return cls.query()\
192 192 .filter(cls.app_settings_name == key).scalar()
193 193
194 194 @classmethod
195 195 def get_by_name_or_create(cls, key):
196 196 res = cls.get_by_name(key)
197 197 if not res:
198 198 res = cls(key)
199 199 return res
200 200
201 201 @classmethod
202 202 def get_app_settings(cls, cache=False):
203 203
204 204 ret = cls.query()
205 205
206 206 if cache:
207 207 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
208 208
209 209 if not ret:
210 210 raise Exception('Could not get application settings !')
211 211 settings = {}
212 212 for each in ret:
213 213 settings['rhodecode_' + each.app_settings_name] = \
214 214 each.app_settings_value
215 215
216 216 return settings
217 217
218 218 @classmethod
219 219 def get_ldap_settings(cls, cache=False):
220 220 ret = cls.query()\
221 221 .filter(cls.app_settings_name.startswith('ldap_')).all()
222 222 fd = {}
223 223 for row in ret:
224 224 fd.update({row.app_settings_name: row.app_settings_value})
225 225
226 226 return fd
227 227
228 228
229 229 class RhodeCodeUi(Base, BaseModel):
230 230 __tablename__ = 'rhodecode_ui'
231 231 __table_args__ = (
232 232 UniqueConstraint('ui_key'),
233 233 {'extend_existing': True, 'mysql_engine': 'InnoDB',
234 234 'mysql_charset': 'utf8'}
235 235 )
236 236
237 237 HOOK_UPDATE = 'changegroup.update'
238 238 HOOK_REPO_SIZE = 'changegroup.repo_size'
239 239 HOOK_PUSH = 'changegroup.push_logger'
240 240 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
241 241 HOOK_PULL = 'outgoing.pull_logger'
242 242 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
243 243
244 244 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
245 245 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
246 246 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
247 247 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
248 248 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
249 249
250 250 @classmethod
251 251 def get_by_key(cls, key):
252 252 return cls.query().filter(cls.ui_key == key).scalar()
253 253
254 254 @classmethod
255 255 def get_builtin_hooks(cls):
256 256 q = cls.query()
257 257 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
258 258 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
259 259 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
260 260 return q.all()
261 261
262 262 @classmethod
263 263 def get_custom_hooks(cls):
264 264 q = cls.query()
265 265 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
266 266 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
267 267 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
268 268 q = q.filter(cls.ui_section == 'hooks')
269 269 return q.all()
270 270
271 271 @classmethod
272 272 def get_repos_location(cls):
273 273 return cls.get_by_key('/').ui_value
274 274
275 275 @classmethod
276 276 def create_or_update_hook(cls, key, val):
277 277 new_ui = cls.get_by_key(key) or cls()
278 278 new_ui.ui_section = 'hooks'
279 279 new_ui.ui_active = True
280 280 new_ui.ui_key = key
281 281 new_ui.ui_value = val
282 282
283 283 Session().add(new_ui)
284 284
285 285 def __repr__(self):
286 286 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
287 287 self.ui_value)
288 288
289 289
290 290 class User(Base, BaseModel):
291 291 __tablename__ = 'users'
292 292 __table_args__ = (
293 293 UniqueConstraint('username'), UniqueConstraint('email'),
294 294 Index('u_username_idx', 'username'),
295 295 Index('u_email_idx', 'email'),
296 296 {'extend_existing': True, 'mysql_engine': 'InnoDB',
297 297 'mysql_charset': 'utf8'}
298 298 )
299 299 DEFAULT_USER = 'default'
300 300 DEFAULT_PERMISSIONS = [
301 301 'hg.register.manual_activate', 'hg.create.repository',
302 302 'hg.fork.repository', 'repository.read'
303 303 ]
304 304 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
305 305 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
306 306 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
307 307 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
308 308 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
309 309 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
310 310 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
311 311 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
312 312 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
313 313 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
314 314 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
315 315 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
316 316
317 317 user_log = relationship('UserLog', cascade='all')
318 318 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
319 319
320 320 repositories = relationship('Repository')
321 321 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
322 322 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
323 323 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
324 324
325 325 group_member = relationship('UsersGroupMember', cascade='all')
326 326
327 327 notifications = relationship('UserNotification', cascade='all')
328 328 # notifications assigned to this user
329 329 user_created_notifications = relationship('Notification', cascade='all')
330 330 # comments created by this user
331 331 user_comments = relationship('ChangesetComment', cascade='all')
332 332 #extra emails for this user
333 333 user_emails = relationship('UserEmailMap', cascade='all')
334 334
335 335 @hybrid_property
336 336 def email(self):
337 337 return self._email
338 338
339 339 @email.setter
340 340 def email(self, val):
341 341 self._email = val.lower() if val else None
342 342
343 343 @property
344 344 def firstname(self):
345 345 # alias for future
346 346 return self.name
347 347
348 348 @property
349 349 def emails(self):
350 350 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
351 351 return [self.email] + [x.email for x in other]
352 352
353 353 @property
354 354 def username_and_name(self):
355 355 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
356 356
357 357 @property
358 358 def full_name(self):
359 359 return '%s %s' % (self.firstname, self.lastname)
360 360
361 361 @property
362 362 def full_name_or_username(self):
363 363 return ('%s %s' % (self.firstname, self.lastname)
364 364 if (self.firstname and self.lastname) else self.username)
365 365
366 366 @property
367 367 def full_contact(self):
368 368 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
369 369
370 370 @property
371 371 def short_contact(self):
372 372 return '%s %s' % (self.firstname, self.lastname)
373 373
374 374 @property
375 375 def is_admin(self):
376 376 return self.admin
377 377
378 378 def __unicode__(self):
379 379 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
380 380 self.user_id, self.username)
381 381
382 382 @classmethod
383 383 def get_by_username(cls, username, case_insensitive=False, cache=False):
384 384 if case_insensitive:
385 385 q = cls.query().filter(cls.username.ilike(username))
386 386 else:
387 387 q = cls.query().filter(cls.username == username)
388 388
389 389 if cache:
390 390 q = q.options(FromCache(
391 391 "sql_cache_short",
392 392 "get_user_%s" % _hash_key(username)
393 393 )
394 394 )
395 395 return q.scalar()
396 396
397 397 @classmethod
398 398 def get_by_api_key(cls, api_key, cache=False):
399 399 q = cls.query().filter(cls.api_key == api_key)
400 400
401 401 if cache:
402 402 q = q.options(FromCache("sql_cache_short",
403 403 "get_api_key_%s" % api_key))
404 404 return q.scalar()
405 405
406 406 @classmethod
407 407 def get_by_email(cls, email, case_insensitive=False, cache=False):
408 408 if case_insensitive:
409 409 q = cls.query().filter(cls.email.ilike(email))
410 410 else:
411 411 q = cls.query().filter(cls.email == email)
412 412
413 413 if cache:
414 414 q = q.options(FromCache("sql_cache_short",
415 415 "get_email_key_%s" % email))
416 416
417 417 ret = q.scalar()
418 418 if ret is None:
419 419 q = UserEmailMap.query()
420 420 # try fetching in alternate email map
421 421 if case_insensitive:
422 422 q = q.filter(UserEmailMap.email.ilike(email))
423 423 else:
424 424 q = q.filter(UserEmailMap.email == email)
425 425 q = q.options(joinedload(UserEmailMap.user))
426 426 if cache:
427 427 q = q.options(FromCache("sql_cache_short",
428 428 "get_email_map_key_%s" % email))
429 429 ret = getattr(q.scalar(), 'user', None)
430 430
431 431 return ret
432 432
433 433 def update_lastlogin(self):
434 434 """Update user lastlogin"""
435 435 self.last_login = datetime.datetime.now()
436 436 Session().add(self)
437 437 log.debug('updated user %s lastlogin' % self.username)
438 438
439 439 def get_api_data(self):
440 440 """
441 441 Common function for generating user related data for API
442 442 """
443 443 user = self
444 444 data = dict(
445 445 user_id=user.user_id,
446 446 username=user.username,
447 447 firstname=user.name,
448 448 lastname=user.lastname,
449 449 email=user.email,
450 450 emails=user.emails,
451 451 api_key=user.api_key,
452 452 active=user.active,
453 453 admin=user.admin,
454 454 ldap_dn=user.ldap_dn,
455 455 last_login=user.last_login,
456 456 )
457 457 return data
458 458
459 459 def __json__(self):
460 460 data = dict(
461 461 full_name=self.full_name,
462 462 full_name_or_username=self.full_name_or_username,
463 463 short_contact=self.short_contact,
464 464 full_contact=self.full_contact
465 465 )
466 466 data.update(self.get_api_data())
467 467 return data
468 468
469 469
470 470 class UserEmailMap(Base, BaseModel):
471 471 __tablename__ = 'user_email_map'
472 472 __table_args__ = (
473 473 Index('uem_email_idx', 'email'),
474 474 UniqueConstraint('email'),
475 475 {'extend_existing': True, 'mysql_engine': 'InnoDB',
476 476 'mysql_charset': 'utf8'}
477 477 )
478 478 __mapper_args__ = {}
479 479
480 480 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
481 481 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
482 482 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
483 483 user = relationship('User', lazy='joined')
484 484
485 485 @validates('_email')
486 486 def validate_email(self, key, email):
487 487 # check if this email is not main one
488 488 main_email = Session().query(User).filter(User.email == email).scalar()
489 489 if main_email is not None:
490 490 raise AttributeError('email %s is present is user table' % email)
491 491 return email
492 492
493 493 @hybrid_property
494 494 def email(self):
495 495 return self._email
496 496
497 497 @email.setter
498 498 def email(self, val):
499 499 self._email = val.lower() if val else None
500 500
501 501
502 502 class UserLog(Base, BaseModel):
503 503 __tablename__ = 'user_logs'
504 504 __table_args__ = (
505 505 {'extend_existing': True, 'mysql_engine': 'InnoDB',
506 506 'mysql_charset': 'utf8'},
507 507 )
508 508 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
509 509 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
510 510 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
511 511 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
512 512 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
513 513 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
514 514 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
515 515
516 516 @property
517 517 def action_as_day(self):
518 518 return datetime.date(*self.action_date.timetuple()[:3])
519 519
520 520 user = relationship('User')
521 521 repository = relationship('Repository', cascade='')
522 522
523 523
524 524 class UsersGroup(Base, BaseModel):
525 525 __tablename__ = 'users_groups'
526 526 __table_args__ = (
527 527 {'extend_existing': True, 'mysql_engine': 'InnoDB',
528 528 'mysql_charset': 'utf8'},
529 529 )
530 530
531 531 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
532 532 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
533 533 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
534 534 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
535 535
536 536 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
537 537 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
538 538 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
539 539
540 540 def __unicode__(self):
541 541 return u'<userGroup(%s)>' % (self.users_group_name)
542 542
543 543 @classmethod
544 544 def get_by_group_name(cls, group_name, cache=False,
545 545 case_insensitive=False):
546 546 if case_insensitive:
547 547 q = cls.query().filter(cls.users_group_name.ilike(group_name))
548 548 else:
549 549 q = cls.query().filter(cls.users_group_name == group_name)
550 550 if cache:
551 551 q = q.options(FromCache(
552 552 "sql_cache_short",
553 553 "get_user_%s" % _hash_key(group_name)
554 554 )
555 555 )
556 556 return q.scalar()
557 557
558 558 @classmethod
559 559 def get(cls, users_group_id, cache=False):
560 560 users_group = cls.query()
561 561 if cache:
562 562 users_group = users_group.options(FromCache("sql_cache_short",
563 563 "get_users_group_%s" % users_group_id))
564 564 return users_group.get(users_group_id)
565 565
566 566 def get_api_data(self):
567 567 users_group = self
568 568
569 569 data = dict(
570 570 users_group_id=users_group.users_group_id,
571 571 group_name=users_group.users_group_name,
572 572 active=users_group.users_group_active,
573 573 )
574 574
575 575 return data
576 576
577 577
578 578 class UsersGroupMember(Base, BaseModel):
579 579 __tablename__ = 'users_groups_members'
580 580 __table_args__ = (
581 581 {'extend_existing': True, 'mysql_engine': 'InnoDB',
582 582 'mysql_charset': 'utf8'},
583 583 )
584 584
585 585 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
586 586 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
587 587 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
588 588
589 589 user = relationship('User', lazy='joined')
590 590 users_group = relationship('UsersGroup')
591 591
592 592 def __init__(self, gr_id='', u_id=''):
593 593 self.users_group_id = gr_id
594 594 self.user_id = u_id
595 595
596 596
597 597 class Repository(Base, BaseModel):
598 598 __tablename__ = 'repositories'
599 599 __table_args__ = (
600 600 UniqueConstraint('repo_name'),
601 601 Index('r_repo_name_idx', 'repo_name'),
602 602 {'extend_existing': True, 'mysql_engine': 'InnoDB',
603 603 'mysql_charset': 'utf8'},
604 604 )
605 605
606 606 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
607 607 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
608 608 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
609 609 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
610 610 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
611 611 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
612 612 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
613 613 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
614 614 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
615 615 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
616 616 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
617 617 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
618 618 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
619 619 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
620 620
621 621 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
622 622 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
623 623
624 624 user = relationship('User')
625 625 fork = relationship('Repository', remote_side=repo_id)
626 626 group = relationship('RepoGroup')
627 627 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
628 628 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
629 629 stats = relationship('Statistics', cascade='all', uselist=False)
630 630
631 631 followers = relationship('UserFollowing',
632 632 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
633 633 cascade='all')
634 634
635 635 logs = relationship('UserLog')
636 636 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
637 637
638 638 pull_requests_org = relationship('PullRequest',
639 639 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
640 640 cascade="all, delete, delete-orphan")
641 641
642 642 pull_requests_other = relationship('PullRequest',
643 643 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
644 644 cascade="all, delete, delete-orphan")
645 645
646 646 def __unicode__(self):
647 647 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
648 648 self.repo_name)
649 649
650 650 @hybrid_property
651 651 def locked(self):
652 652 # always should return [user_id, timelocked]
653 653 if self._locked:
654 654 _lock_info = self._locked.split(':')
655 655 return int(_lock_info[0]), _lock_info[1]
656 656 return [None, None]
657 657
658 658 @locked.setter
659 659 def locked(self, val):
660 660 if val and isinstance(val, (list, tuple)):
661 661 self._locked = ':'.join(map(str, val))
662 662 else:
663 663 self._locked = None
664 664
665 665 @classmethod
666 666 def url_sep(cls):
667 667 return URL_SEP
668 668
669 669 @classmethod
670 670 def get_by_repo_name(cls, repo_name):
671 671 q = Session().query(cls).filter(cls.repo_name == repo_name)
672 672 q = q.options(joinedload(Repository.fork))\
673 673 .options(joinedload(Repository.user))\
674 674 .options(joinedload(Repository.group))
675 675 return q.scalar()
676 676
677 677 @classmethod
678 678 def get_by_full_path(cls, repo_full_path):
679 679 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
680 680 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
681 681
682 682 @classmethod
683 683 def get_repo_forks(cls, repo_id):
684 684 return cls.query().filter(Repository.fork_id == repo_id)
685 685
686 686 @classmethod
687 687 def base_path(cls):
688 688 """
689 689 Returns base path when all repos are stored
690 690
691 691 :param cls:
692 692 """
693 693 q = Session().query(RhodeCodeUi)\
694 694 .filter(RhodeCodeUi.ui_key == cls.url_sep())
695 695 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
696 696 return q.one().ui_value
697 697
698 698 @property
699 699 def forks(self):
700 700 """
701 701 Return forks of this repo
702 702 """
703 703 return Repository.get_repo_forks(self.repo_id)
704 704
705 705 @property
706 706 def parent(self):
707 707 """
708 708 Returns fork parent
709 709 """
710 710 return self.fork
711 711
712 712 @property
713 713 def just_name(self):
714 714 return self.repo_name.split(Repository.url_sep())[-1]
715 715
716 716 @property
717 717 def groups_with_parents(self):
718 718 groups = []
719 719 if self.group is None:
720 720 return groups
721 721
722 722 cur_gr = self.group
723 723 groups.insert(0, cur_gr)
724 724 while 1:
725 725 gr = getattr(cur_gr, 'parent_group', None)
726 726 cur_gr = cur_gr.parent_group
727 727 if gr is None:
728 728 break
729 729 groups.insert(0, gr)
730 730
731 731 return groups
732 732
733 733 @property
734 734 def groups_and_repo(self):
735 735 return self.groups_with_parents, self.just_name
736 736
737 737 @LazyProperty
738 738 def repo_path(self):
739 739 """
740 740 Returns base full path for that repository means where it actually
741 741 exists on a filesystem
742 742 """
743 743 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
744 744 Repository.url_sep())
745 745 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
746 746 return q.one().ui_value
747 747
748 748 @property
749 749 def repo_full_path(self):
750 750 p = [self.repo_path]
751 751 # we need to split the name by / since this is how we store the
752 752 # names in the database, but that eventually needs to be converted
753 753 # into a valid system path
754 754 p += self.repo_name.split(Repository.url_sep())
755 755 return os.path.join(*p)
756 756
757 757 @property
758 758 def cache_keys(self):
759 759 """
760 760 Returns associated cache keys for that repo
761 761 """
762 762 return CacheInvalidation.query()\
763 763 .filter(CacheInvalidation.cache_args == self.repo_name)\
764 764 .order_by(CacheInvalidation.cache_key)\
765 765 .all()
766 766
767 767 def get_new_name(self, repo_name):
768 768 """
769 769 returns new full repository name based on assigned group and new new
770 770
771 771 :param group_name:
772 772 """
773 773 path_prefix = self.group.full_path_splitted if self.group else []
774 774 return Repository.url_sep().join(path_prefix + [repo_name])
775 775
776 776 @property
777 777 def _ui(self):
778 778 """
779 779 Creates an db based ui object for this repository
780 780 """
781 781 from rhodecode.lib.utils import make_ui
782 782 return make_ui('db', clear_session=False)
783 783
784 784 @classmethod
785 785 def inject_ui(cls, repo, extras={}):
786 786 from rhodecode.lib.vcs.backends.hg import MercurialRepository
787 787 from rhodecode.lib.vcs.backends.git import GitRepository
788 788 required = (MercurialRepository, GitRepository)
789 789 if not isinstance(repo, required):
790 790 raise Exception('repo must be instance of %s' % required)
791 791
792 792 # inject ui extra param to log this action via push logger
793 793 for k, v in extras.items():
794 794 repo._repo.ui.setconfig('rhodecode_extras', k, v)
795 795
796 796 @classmethod
797 797 def is_valid(cls, repo_name):
798 798 """
799 799 returns True if given repo name is a valid filesystem repository
800 800
801 801 :param cls:
802 802 :param repo_name:
803 803 """
804 804 from rhodecode.lib.utils import is_valid_repo
805 805
806 806 return is_valid_repo(repo_name, cls.base_path())
807 807
808 808 def get_api_data(self):
809 809 """
810 810 Common function for generating repo api data
811 811
812 812 """
813 813 repo = self
814 814 data = dict(
815 815 repo_id=repo.repo_id,
816 816 repo_name=repo.repo_name,
817 817 repo_type=repo.repo_type,
818 818 clone_uri=repo.clone_uri,
819 819 private=repo.private,
820 820 created_on=repo.created_on,
821 821 description=repo.description,
822 822 landing_rev=repo.landing_rev,
823 823 owner=repo.user.username,
824 824 fork_of=repo.fork.repo_name if repo.fork else None
825 825 )
826 826
827 827 return data
828 828
829 829 @classmethod
830 830 def lock(cls, repo, user_id):
831 831 repo.locked = [user_id, time.time()]
832 832 Session().add(repo)
833 833 Session().commit()
834 834
835 835 @classmethod
836 836 def unlock(cls, repo):
837 837 repo.locked = None
838 838 Session().add(repo)
839 839 Session().commit()
840 840
841 841 @property
842 842 def last_db_change(self):
843 843 return self.updated_on
844 844
845 845 #==========================================================================
846 846 # SCM PROPERTIES
847 847 #==========================================================================
848 848
849 849 def get_changeset(self, rev=None):
850 850 return get_changeset_safe(self.scm_instance, rev)
851 851
852 852 def get_landing_changeset(self):
853 853 """
854 854 Returns landing changeset, or if that doesn't exist returns the tip
855 855 """
856 856 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
857 857 return cs
858 858
859 859 def update_last_change(self, last_change=None):
860 860 if last_change is None:
861 861 last_change = datetime.datetime.now()
862 862 if self.updated_on is None or self.updated_on != last_change:
863 863 log.debug('updated repo %s with new date %s' % (self, last_change))
864 864 self.updated_on = last_change
865 865 Session().add(self)
866 866 Session().commit()
867 867
868 868 @property
869 869 def tip(self):
870 870 return self.get_changeset('tip')
871 871
872 872 @property
873 873 def author(self):
874 874 return self.tip.author
875 875
876 876 @property
877 877 def last_change(self):
878 878 return self.scm_instance.last_change
879 879
880 880 def get_comments(self, revisions=None):
881 881 """
882 882 Returns comments for this repository grouped by revisions
883 883
884 884 :param revisions: filter query by revisions only
885 885 """
886 886 cmts = ChangesetComment.query()\
887 887 .filter(ChangesetComment.repo == self)
888 888 if revisions:
889 889 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
890 890 grouped = defaultdict(list)
891 891 for cmt in cmts.all():
892 892 grouped[cmt.revision].append(cmt)
893 893 return grouped
894 894
895 895 def statuses(self, revisions=None):
896 896 """
897 897 Returns statuses for this repository
898 898
899 899 :param revisions: list of revisions to get statuses for
900 900 :type revisions: list
901 901 """
902 902
903 903 statuses = ChangesetStatus.query()\
904 904 .filter(ChangesetStatus.repo == self)\
905 905 .filter(ChangesetStatus.version == 0)
906 906 if revisions:
907 907 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
908 908 grouped = {}
909 909
910 910 #maybe we have open new pullrequest without a status ?
911 911 stat = ChangesetStatus.STATUS_UNDER_REVIEW
912 912 status_lbl = ChangesetStatus.get_status_lbl(stat)
913 913 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
914 914 for rev in pr.revisions:
915 915 pr_id = pr.pull_request_id
916 916 pr_repo = pr.other_repo.repo_name
917 917 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
918 918
919 919 for stat in statuses.all():
920 920 pr_id = pr_repo = None
921 921 if stat.pull_request:
922 922 pr_id = stat.pull_request.pull_request_id
923 923 pr_repo = stat.pull_request.other_repo.repo_name
924 924 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
925 925 pr_id, pr_repo]
926 926 return grouped
927 927
928 928 #==========================================================================
929 929 # SCM CACHE INSTANCE
930 930 #==========================================================================
931 931
932 932 @property
933 933 def invalidate(self):
934 934 return CacheInvalidation.invalidate(self.repo_name)
935 935
936 936 def set_invalidate(self):
937 937 """
938 938 set a cache for invalidation for this instance
939 939 """
940 CacheInvalidation.set_invalidate(self.repo_name)
940 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
941 941
942 942 @LazyProperty
943 943 def scm_instance(self):
944 944 return self.scm_instance_cached()
945 945 return self.__get_instance()
946 946
947 947 def scm_instance_cached(self, cache_map=None):
948 948 @cache_region('long_term')
949 949 def _c(repo_name):
950 950 return self.__get_instance()
951 951 rn = self.repo_name
952 952 log.debug('Getting cached instance of repo')
953 953
954 954 if cache_map:
955 955 # get using prefilled cache_map
956 956 invalidate_repo = cache_map[self.repo_name]
957 957 if invalidate_repo:
958 958 invalidate_repo = (None if invalidate_repo.cache_active
959 959 else invalidate_repo)
960 960 else:
961 961 # get from invalidate
962 962 invalidate_repo = self.invalidate
963 963
964 964 if invalidate_repo is not None:
965 965 region_invalidate(_c, None, rn)
966 966 # update our cache
967 967 CacheInvalidation.set_valid(invalidate_repo.cache_key)
968 968 return _c(rn)
969 969
970 970 def __get_instance(self):
971 971 repo_full_path = self.repo_full_path
972 972 try:
973 973 alias = get_scm(repo_full_path)[0]
974 974 log.debug('Creating instance of %s repository' % alias)
975 975 backend = get_backend(alias)
976 976 except VCSError:
977 977 log.error(traceback.format_exc())
978 978 log.error('Perhaps this repository is in db and not in '
979 979 'filesystem run rescan repositories with '
980 980 '"destroy old data " option from admin panel')
981 981 return
982 982
983 983 if alias == 'hg':
984 984
985 985 repo = backend(safe_str(repo_full_path), create=False,
986 986 baseui=self._ui)
987 987 # skip hidden web repository
988 988 if repo._get_hidden():
989 989 return
990 990 else:
991 991 repo = backend(repo_full_path, create=False)
992 992
993 993 return repo
994 994
995 995
996 996 class RepoGroup(Base, BaseModel):
997 997 __tablename__ = 'groups'
998 998 __table_args__ = (
999 999 UniqueConstraint('group_name', 'group_parent_id'),
1000 1000 CheckConstraint('group_id != group_parent_id'),
1001 1001 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1002 1002 'mysql_charset': 'utf8'},
1003 1003 )
1004 1004 __mapper_args__ = {'order_by': 'group_name'}
1005 1005
1006 1006 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1007 1007 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1008 1008 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1009 1009 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1010 1010 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1011 1011
1012 1012 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1013 1013 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1014 1014
1015 1015 parent_group = relationship('RepoGroup', remote_side=group_id)
1016 1016
1017 1017 def __init__(self, group_name='', parent_group=None):
1018 1018 self.group_name = group_name
1019 1019 self.parent_group = parent_group
1020 1020
1021 1021 def __unicode__(self):
1022 1022 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1023 1023 self.group_name)
1024 1024
1025 1025 @classmethod
1026 1026 def groups_choices(cls, check_perms=False):
1027 1027 from webhelpers.html import literal as _literal
1028 1028 from rhodecode.model.scm import ScmModel
1029 1029 groups = cls.query().all()
1030 1030 if check_perms:
1031 1031 #filter group user have access to, it's done
1032 1032 #magically inside ScmModel based on current user
1033 1033 groups = ScmModel().get_repos_groups(groups)
1034 1034 repo_groups = [('', '')]
1035 1035 sep = ' &raquo; '
1036 1036 _name = lambda k: _literal(sep.join(k))
1037 1037
1038 1038 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1039 1039 for x in groups])
1040 1040
1041 1041 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1042 1042 return repo_groups
1043 1043
1044 1044 @classmethod
1045 1045 def url_sep(cls):
1046 1046 return URL_SEP
1047 1047
1048 1048 @classmethod
1049 1049 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1050 1050 if case_insensitive:
1051 1051 gr = cls.query()\
1052 1052 .filter(cls.group_name.ilike(group_name))
1053 1053 else:
1054 1054 gr = cls.query()\
1055 1055 .filter(cls.group_name == group_name)
1056 1056 if cache:
1057 1057 gr = gr.options(FromCache(
1058 1058 "sql_cache_short",
1059 1059 "get_group_%s" % _hash_key(group_name)
1060 1060 )
1061 1061 )
1062 1062 return gr.scalar()
1063 1063
1064 1064 @property
1065 1065 def parents(self):
1066 1066 parents_recursion_limit = 5
1067 1067 groups = []
1068 1068 if self.parent_group is None:
1069 1069 return groups
1070 1070 cur_gr = self.parent_group
1071 1071 groups.insert(0, cur_gr)
1072 1072 cnt = 0
1073 1073 while 1:
1074 1074 cnt += 1
1075 1075 gr = getattr(cur_gr, 'parent_group', None)
1076 1076 cur_gr = cur_gr.parent_group
1077 1077 if gr is None:
1078 1078 break
1079 1079 if cnt == parents_recursion_limit:
1080 1080 # this will prevent accidental infinit loops
1081 1081 log.error('group nested more than %s' %
1082 1082 parents_recursion_limit)
1083 1083 break
1084 1084
1085 1085 groups.insert(0, gr)
1086 1086 return groups
1087 1087
1088 1088 @property
1089 1089 def children(self):
1090 1090 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1091 1091
1092 1092 @property
1093 1093 def name(self):
1094 1094 return self.group_name.split(RepoGroup.url_sep())[-1]
1095 1095
1096 1096 @property
1097 1097 def full_path(self):
1098 1098 return self.group_name
1099 1099
1100 1100 @property
1101 1101 def full_path_splitted(self):
1102 1102 return self.group_name.split(RepoGroup.url_sep())
1103 1103
1104 1104 @property
1105 1105 def repositories(self):
1106 1106 return Repository.query()\
1107 1107 .filter(Repository.group == self)\
1108 1108 .order_by(Repository.repo_name)
1109 1109
1110 1110 @property
1111 1111 def repositories_recursive_count(self):
1112 1112 cnt = self.repositories.count()
1113 1113
1114 1114 def children_count(group):
1115 1115 cnt = 0
1116 1116 for child in group.children:
1117 1117 cnt += child.repositories.count()
1118 1118 cnt += children_count(child)
1119 1119 return cnt
1120 1120
1121 1121 return cnt + children_count(self)
1122 1122
1123 1123 def recursive_groups_and_repos(self):
1124 1124 """
1125 1125 Recursive return all groups, with repositories in those groups
1126 1126 """
1127 1127 all_ = []
1128 1128
1129 1129 def _get_members(root_gr):
1130 1130 for r in root_gr.repositories:
1131 1131 all_.append(r)
1132 1132 childs = root_gr.children.all()
1133 1133 if childs:
1134 1134 for gr in childs:
1135 1135 all_.append(gr)
1136 1136 _get_members(gr)
1137 1137
1138 1138 _get_members(self)
1139 1139 return [self] + all_
1140 1140
1141 1141 def get_new_name(self, group_name):
1142 1142 """
1143 1143 returns new full group name based on parent and new name
1144 1144
1145 1145 :param group_name:
1146 1146 """
1147 1147 path_prefix = (self.parent_group.full_path_splitted if
1148 1148 self.parent_group else [])
1149 1149 return RepoGroup.url_sep().join(path_prefix + [group_name])
1150 1150
1151 1151
1152 1152 class Permission(Base, BaseModel):
1153 1153 __tablename__ = 'permissions'
1154 1154 __table_args__ = (
1155 1155 Index('p_perm_name_idx', 'permission_name'),
1156 1156 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1157 1157 'mysql_charset': 'utf8'},
1158 1158 )
1159 1159 PERMS = [
1160 1160 ('repository.none', _('Repository no access')),
1161 1161 ('repository.read', _('Repository read access')),
1162 1162 ('repository.write', _('Repository write access')),
1163 1163 ('repository.admin', _('Repository admin access')),
1164 1164
1165 1165 ('group.none', _('Repositories Group no access')),
1166 1166 ('group.read', _('Repositories Group read access')),
1167 1167 ('group.write', _('Repositories Group write access')),
1168 1168 ('group.admin', _('Repositories Group admin access')),
1169 1169
1170 1170 ('hg.admin', _('RhodeCode Administrator')),
1171 1171 ('hg.create.none', _('Repository creation disabled')),
1172 1172 ('hg.create.repository', _('Repository creation enabled')),
1173 1173 ('hg.fork.none', _('Repository forking disabled')),
1174 1174 ('hg.fork.repository', _('Repository forking enabled')),
1175 1175 ('hg.register.none', _('Register disabled')),
1176 1176 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1177 1177 'with manual activation')),
1178 1178
1179 1179 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1180 1180 'with auto activation')),
1181 1181 ]
1182 1182
1183 1183 # defines which permissions are more important higher the more important
1184 1184 PERM_WEIGHTS = {
1185 1185 'repository.none': 0,
1186 1186 'repository.read': 1,
1187 1187 'repository.write': 3,
1188 1188 'repository.admin': 4,
1189 1189
1190 1190 'group.none': 0,
1191 1191 'group.read': 1,
1192 1192 'group.write': 3,
1193 1193 'group.admin': 4,
1194 1194
1195 1195 'hg.fork.none': 0,
1196 1196 'hg.fork.repository': 1,
1197 1197 'hg.create.none': 0,
1198 1198 'hg.create.repository':1
1199 1199 }
1200 1200
1201 1201 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1202 1202 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1203 1203 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1204 1204
1205 1205 def __unicode__(self):
1206 1206 return u"<%s('%s:%s')>" % (
1207 1207 self.__class__.__name__, self.permission_id, self.permission_name
1208 1208 )
1209 1209
1210 1210 @classmethod
1211 1211 def get_by_key(cls, key):
1212 1212 return cls.query().filter(cls.permission_name == key).scalar()
1213 1213
1214 1214 @classmethod
1215 1215 def get_default_perms(cls, default_user_id):
1216 1216 q = Session().query(UserRepoToPerm, Repository, cls)\
1217 1217 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1218 1218 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1219 1219 .filter(UserRepoToPerm.user_id == default_user_id)
1220 1220
1221 1221 return q.all()
1222 1222
1223 1223 @classmethod
1224 1224 def get_default_group_perms(cls, default_user_id):
1225 1225 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1226 1226 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1227 1227 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1228 1228 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1229 1229
1230 1230 return q.all()
1231 1231
1232 1232
1233 1233 class UserRepoToPerm(Base, BaseModel):
1234 1234 __tablename__ = 'repo_to_perm'
1235 1235 __table_args__ = (
1236 1236 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1237 1237 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1238 1238 'mysql_charset': 'utf8'}
1239 1239 )
1240 1240 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1241 1241 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1242 1242 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1243 1243 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1244 1244
1245 1245 user = relationship('User')
1246 1246 repository = relationship('Repository')
1247 1247 permission = relationship('Permission')
1248 1248
1249 1249 @classmethod
1250 1250 def create(cls, user, repository, permission):
1251 1251 n = cls()
1252 1252 n.user = user
1253 1253 n.repository = repository
1254 1254 n.permission = permission
1255 1255 Session().add(n)
1256 1256 return n
1257 1257
1258 1258 def __unicode__(self):
1259 1259 return u'<user:%s => %s >' % (self.user, self.repository)
1260 1260
1261 1261
1262 1262 class UserToPerm(Base, BaseModel):
1263 1263 __tablename__ = 'user_to_perm'
1264 1264 __table_args__ = (
1265 1265 UniqueConstraint('user_id', 'permission_id'),
1266 1266 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1267 1267 'mysql_charset': 'utf8'}
1268 1268 )
1269 1269 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1270 1270 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1271 1271 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1272 1272
1273 1273 user = relationship('User')
1274 1274 permission = relationship('Permission', lazy='joined')
1275 1275
1276 1276
1277 1277 class UsersGroupRepoToPerm(Base, BaseModel):
1278 1278 __tablename__ = 'users_group_repo_to_perm'
1279 1279 __table_args__ = (
1280 1280 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1281 1281 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1282 1282 'mysql_charset': 'utf8'}
1283 1283 )
1284 1284 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1285 1285 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1286 1286 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1287 1287 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1288 1288
1289 1289 users_group = relationship('UsersGroup')
1290 1290 permission = relationship('Permission')
1291 1291 repository = relationship('Repository')
1292 1292
1293 1293 @classmethod
1294 1294 def create(cls, users_group, repository, permission):
1295 1295 n = cls()
1296 1296 n.users_group = users_group
1297 1297 n.repository = repository
1298 1298 n.permission = permission
1299 1299 Session().add(n)
1300 1300 return n
1301 1301
1302 1302 def __unicode__(self):
1303 1303 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1304 1304
1305 1305
1306 1306 class UsersGroupToPerm(Base, BaseModel):
1307 1307 __tablename__ = 'users_group_to_perm'
1308 1308 __table_args__ = (
1309 1309 UniqueConstraint('users_group_id', 'permission_id',),
1310 1310 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1311 1311 'mysql_charset': 'utf8'}
1312 1312 )
1313 1313 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1314 1314 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1315 1315 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1316 1316
1317 1317 users_group = relationship('UsersGroup')
1318 1318 permission = relationship('Permission')
1319 1319
1320 1320
1321 1321 class UserRepoGroupToPerm(Base, BaseModel):
1322 1322 __tablename__ = 'user_repo_group_to_perm'
1323 1323 __table_args__ = (
1324 1324 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1325 1325 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1326 1326 'mysql_charset': 'utf8'}
1327 1327 )
1328 1328
1329 1329 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1330 1330 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1331 1331 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1332 1332 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1333 1333
1334 1334 user = relationship('User')
1335 1335 group = relationship('RepoGroup')
1336 1336 permission = relationship('Permission')
1337 1337
1338 1338
1339 1339 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1340 1340 __tablename__ = 'users_group_repo_group_to_perm'
1341 1341 __table_args__ = (
1342 1342 UniqueConstraint('users_group_id', 'group_id'),
1343 1343 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1344 1344 'mysql_charset': 'utf8'}
1345 1345 )
1346 1346
1347 1347 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1348 1348 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1349 1349 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1350 1350 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1351 1351
1352 1352 users_group = relationship('UsersGroup')
1353 1353 permission = relationship('Permission')
1354 1354 group = relationship('RepoGroup')
1355 1355
1356 1356
1357 1357 class Statistics(Base, BaseModel):
1358 1358 __tablename__ = 'statistics'
1359 1359 __table_args__ = (
1360 1360 UniqueConstraint('repository_id'),
1361 1361 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1362 1362 'mysql_charset': 'utf8'}
1363 1363 )
1364 1364 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1365 1365 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1366 1366 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1367 1367 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1368 1368 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1369 1369 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1370 1370
1371 1371 repository = relationship('Repository', single_parent=True)
1372 1372
1373 1373
1374 1374 class UserFollowing(Base, BaseModel):
1375 1375 __tablename__ = 'user_followings'
1376 1376 __table_args__ = (
1377 1377 UniqueConstraint('user_id', 'follows_repository_id'),
1378 1378 UniqueConstraint('user_id', 'follows_user_id'),
1379 1379 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1380 1380 'mysql_charset': 'utf8'}
1381 1381 )
1382 1382
1383 1383 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1384 1384 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1385 1385 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1386 1386 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1387 1387 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1388 1388
1389 1389 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1390 1390
1391 1391 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1392 1392 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1393 1393
1394 1394 @classmethod
1395 1395 def get_repo_followers(cls, repo_id):
1396 1396 return cls.query().filter(cls.follows_repo_id == repo_id)
1397 1397
1398 1398
1399 1399 class CacheInvalidation(Base, BaseModel):
1400 1400 __tablename__ = 'cache_invalidation'
1401 1401 __table_args__ = (
1402 1402 UniqueConstraint('cache_key'),
1403 1403 Index('key_idx', 'cache_key'),
1404 1404 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1405 1405 'mysql_charset': 'utf8'},
1406 1406 )
1407 1407 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1408 1408 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1409 1409 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1410 1410 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1411 1411
1412 1412 def __init__(self, cache_key, cache_args=''):
1413 1413 self.cache_key = cache_key
1414 1414 self.cache_args = cache_args
1415 1415 self.cache_active = False
1416 1416
1417 1417 def __unicode__(self):
1418 1418 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1419 1419 self.cache_id, self.cache_key)
1420 1420
1421 1421 @property
1422 1422 def prefix(self):
1423 1423 _split = self.cache_key.split(self.cache_args, 1)
1424 1424 if _split and len(_split) == 2:
1425 1425 return _split[0]
1426 1426 return ''
1427 1427
1428 1428 @classmethod
1429 1429 def clear_cache(cls):
1430 1430 cls.query().delete()
1431 1431
1432 1432 @classmethod
1433 1433 def _get_key(cls, key):
1434 1434 """
1435 1435 Wrapper for generating a key, together with a prefix
1436 1436
1437 1437 :param key:
1438 1438 """
1439 1439 import rhodecode
1440 1440 prefix = ''
1441 org_key = key
1441 1442 iid = rhodecode.CONFIG.get('instance_id')
1442 1443 if iid:
1443 1444 prefix = iid
1444 #remove specific suffixes like _README or _RSS
1445 key = remove_suffix(key, '_README')
1446 key = remove_suffix(key, '_RSS')
1447 key = remove_suffix(key, '_ATOM')
1448 return "%s%s" % (prefix, key), prefix, key
1445
1446 return "%s%s" % (prefix, key), prefix, org_key
1449 1447
1450 1448 @classmethod
1451 1449 def get_by_key(cls, key):
1452 1450 return cls.query().filter(cls.cache_key == key).scalar()
1453 1451
1454 1452 @classmethod
1455 def _get_or_create_key(cls, key, prefix, org_key, commit=True):
1453 def get_by_repo_name(cls, repo_name):
1454 return cls.query().filter(cls.cache_args == repo_name).all()
1455
1456 @classmethod
1457 def _get_or_create_key(cls, key, repo_name, commit=True):
1456 1458 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1457 1459 if not inv_obj:
1458 1460 try:
1459 inv_obj = CacheInvalidation(key, org_key)
1461 inv_obj = CacheInvalidation(key, repo_name)
1460 1462 Session().add(inv_obj)
1461 1463 if commit:
1462 1464 Session().commit()
1463 1465 except Exception:
1464 1466 log.error(traceback.format_exc())
1465 1467 Session().rollback()
1466 1468 return inv_obj
1467 1469
1468 1470 @classmethod
1469 1471 def invalidate(cls, key):
1470 1472 """
1471 1473 Returns Invalidation object if this given key should be invalidated
1472 1474 None otherwise. `cache_active = False` means that this cache
1473 1475 state is not valid and needs to be invalidated
1474 1476
1475 1477 :param key:
1476 1478 """
1479 repo_name = key
1480 repo_name = remove_suffix(repo_name, '_README')
1481 repo_name = remove_suffix(repo_name, '_RSS')
1482 repo_name = remove_suffix(repo_name, '_ATOM')
1477 1483
1484 # adds instance prefix
1478 1485 key, _prefix, _org_key = cls._get_key(key)
1479 inv = cls._get_or_create_key(key, _prefix, _org_key)
1486 inv = cls._get_or_create_key(key, repo_name)
1480 1487
1481 1488 if inv and inv.cache_active is False:
1482 1489 return inv
1483 1490
1484 1491 @classmethod
1485 def set_invalidate(cls, key):
1492 def set_invalidate(cls, key=None, repo_name=None):
1486 1493 """
1487 Mark this Cache key for invalidation
1494 Mark this Cache key for invalidation, either by key or whole
1495 cache sets based on repo_name
1488 1496
1489 1497 :param key:
1490 1498 """
1499 if key:
1500 key, _prefix, _org_key = cls._get_key(key)
1501 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1502 elif repo_name:
1503 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1491 1504
1492 key, _prefix, _org_key = cls._get_key(key)
1493 inv_objs = Session().query(cls).filter(cls.cache_args == _org_key).all()
1494 log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
1495 _org_key))
1505 log.debug('marking %s key[s] for invalidation based on key=%s,repo_name=%s'
1506 % (len(inv_objs), key, repo_name))
1496 1507 try:
1497 1508 for inv_obj in inv_objs:
1498 if inv_obj:
1499 inv_obj.cache_active = False
1500
1509 print inv_obj
1510 inv_obj.cache_active = False
1501 1511 Session().add(inv_obj)
1502 1512 Session().commit()
1503 1513 except Exception:
1504 1514 log.error(traceback.format_exc())
1505 1515 Session().rollback()
1506 1516
1507 1517 @classmethod
1508 1518 def set_valid(cls, key):
1509 1519 """
1510 1520 Mark this cache key as active and currently cached
1511 1521
1512 1522 :param key:
1513 1523 """
1514 1524 inv_obj = cls.get_by_key(key)
1515 1525 inv_obj.cache_active = True
1516 1526 Session().add(inv_obj)
1517 1527 Session().commit()
1518 1528
1519 1529 @classmethod
1520 1530 def get_cache_map(cls):
1521 1531
1522 1532 class cachemapdict(dict):
1523 1533
1524 1534 def __init__(self, *args, **kwargs):
1525 1535 fixkey = kwargs.get('fixkey')
1526 1536 if fixkey:
1527 1537 del kwargs['fixkey']
1528 1538 self.fixkey = fixkey
1529 1539 super(cachemapdict, self).__init__(*args, **kwargs)
1530 1540
1531 1541 def __getattr__(self, name):
1532 1542 key = name
1533 1543 if self.fixkey:
1534 1544 key, _prefix, _org_key = cls._get_key(key)
1535 1545 if key in self.__dict__:
1536 1546 return self.__dict__[key]
1537 1547 else:
1538 1548 return self[key]
1539 1549
1540 1550 def __getitem__(self, key):
1541 1551 if self.fixkey:
1542 1552 key, _prefix, _org_key = cls._get_key(key)
1543 1553 try:
1544 1554 return super(cachemapdict, self).__getitem__(key)
1545 1555 except KeyError:
1546 1556 return
1547 1557
1548 1558 cache_map = cachemapdict(fixkey=True)
1549 1559 for obj in cls.query().all():
1550 1560 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1551 1561 return cache_map
1552 1562
1553 1563
1554 1564 class ChangesetComment(Base, BaseModel):
1555 1565 __tablename__ = 'changeset_comments'
1556 1566 __table_args__ = (
1557 1567 Index('cc_revision_idx', 'revision'),
1558 1568 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1559 1569 'mysql_charset': 'utf8'},
1560 1570 )
1561 1571 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1562 1572 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1563 1573 revision = Column('revision', String(40), nullable=True)
1564 1574 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1565 1575 line_no = Column('line_no', Unicode(10), nullable=True)
1566 1576 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1567 1577 f_path = Column('f_path', Unicode(1000), nullable=True)
1568 1578 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1569 1579 text = Column('text', UnicodeText(25000), nullable=False)
1570 1580 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1571 1581 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1572 1582
1573 1583 author = relationship('User', lazy='joined')
1574 1584 repo = relationship('Repository')
1575 1585 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1576 1586 pull_request = relationship('PullRequest', lazy='joined')
1577 1587
1578 1588 @classmethod
1579 1589 def get_users(cls, revision=None, pull_request_id=None):
1580 1590 """
1581 1591 Returns user associated with this ChangesetComment. ie those
1582 1592 who actually commented
1583 1593
1584 1594 :param cls:
1585 1595 :param revision:
1586 1596 """
1587 1597 q = Session().query(User)\
1588 1598 .join(ChangesetComment.author)
1589 1599 if revision:
1590 1600 q = q.filter(cls.revision == revision)
1591 1601 elif pull_request_id:
1592 1602 q = q.filter(cls.pull_request_id == pull_request_id)
1593 1603 return q.all()
1594 1604
1595 1605
1596 1606 class ChangesetStatus(Base, BaseModel):
1597 1607 __tablename__ = 'changeset_statuses'
1598 1608 __table_args__ = (
1599 1609 Index('cs_revision_idx', 'revision'),
1600 1610 Index('cs_version_idx', 'version'),
1601 1611 UniqueConstraint('repo_id', 'revision', 'version'),
1602 1612 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1603 1613 'mysql_charset': 'utf8'}
1604 1614 )
1605 1615 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1606 1616 STATUS_APPROVED = 'approved'
1607 1617 STATUS_REJECTED = 'rejected'
1608 1618 STATUS_UNDER_REVIEW = 'under_review'
1609 1619
1610 1620 STATUSES = [
1611 1621 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1612 1622 (STATUS_APPROVED, _("Approved")),
1613 1623 (STATUS_REJECTED, _("Rejected")),
1614 1624 (STATUS_UNDER_REVIEW, _("Under Review")),
1615 1625 ]
1616 1626
1617 1627 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1618 1628 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1619 1629 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1620 1630 revision = Column('revision', String(40), nullable=False)
1621 1631 status = Column('status', String(128), nullable=False, default=DEFAULT)
1622 1632 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1623 1633 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1624 1634 version = Column('version', Integer(), nullable=False, default=0)
1625 1635 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1626 1636
1627 1637 author = relationship('User', lazy='joined')
1628 1638 repo = relationship('Repository')
1629 1639 comment = relationship('ChangesetComment', lazy='joined')
1630 1640 pull_request = relationship('PullRequest', lazy='joined')
1631 1641
1632 1642 def __unicode__(self):
1633 1643 return u"<%s('%s:%s')>" % (
1634 1644 self.__class__.__name__,
1635 1645 self.status, self.author
1636 1646 )
1637 1647
1638 1648 @classmethod
1639 1649 def get_status_lbl(cls, value):
1640 1650 return dict(cls.STATUSES).get(value)
1641 1651
1642 1652 @property
1643 1653 def status_lbl(self):
1644 1654 return ChangesetStatus.get_status_lbl(self.status)
1645 1655
1646 1656
1647 1657 class PullRequest(Base, BaseModel):
1648 1658 __tablename__ = 'pull_requests'
1649 1659 __table_args__ = (
1650 1660 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1651 1661 'mysql_charset': 'utf8'},
1652 1662 )
1653 1663
1654 1664 STATUS_NEW = u'new'
1655 1665 STATUS_OPEN = u'open'
1656 1666 STATUS_CLOSED = u'closed'
1657 1667
1658 1668 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1659 1669 title = Column('title', Unicode(256), nullable=True)
1660 1670 description = Column('description', UnicodeText(10240), nullable=True)
1661 1671 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1662 1672 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1663 1673 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1664 1674 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1665 1675 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1666 1676 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1667 1677 org_ref = Column('org_ref', Unicode(256), nullable=False)
1668 1678 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1669 1679 other_ref = Column('other_ref', Unicode(256), nullable=False)
1670 1680
1671 1681 @hybrid_property
1672 1682 def revisions(self):
1673 1683 return self._revisions.split(':')
1674 1684
1675 1685 @revisions.setter
1676 1686 def revisions(self, val):
1677 1687 self._revisions = ':'.join(val)
1678 1688
1679 1689 author = relationship('User', lazy='joined')
1680 1690 reviewers = relationship('PullRequestReviewers',
1681 1691 cascade="all, delete, delete-orphan")
1682 1692 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1683 1693 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1684 1694 statuses = relationship('ChangesetStatus')
1685 1695 comments = relationship('ChangesetComment',
1686 1696 cascade="all, delete, delete-orphan")
1687 1697
1688 1698 def is_closed(self):
1689 1699 return self.status == self.STATUS_CLOSED
1690 1700
1691 1701 def __json__(self):
1692 1702 return dict(
1693 1703 revisions=self.revisions
1694 1704 )
1695 1705
1696 1706
1697 1707 class PullRequestReviewers(Base, BaseModel):
1698 1708 __tablename__ = 'pull_request_reviewers'
1699 1709 __table_args__ = (
1700 1710 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1701 1711 'mysql_charset': 'utf8'},
1702 1712 )
1703 1713
1704 1714 def __init__(self, user=None, pull_request=None):
1705 1715 self.user = user
1706 1716 self.pull_request = pull_request
1707 1717
1708 1718 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1709 1719 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1710 1720 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1711 1721
1712 1722 user = relationship('User')
1713 1723 pull_request = relationship('PullRequest')
1714 1724
1715 1725
1716 1726 class Notification(Base, BaseModel):
1717 1727 __tablename__ = 'notifications'
1718 1728 __table_args__ = (
1719 1729 Index('notification_type_idx', 'type'),
1720 1730 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1721 1731 'mysql_charset': 'utf8'},
1722 1732 )
1723 1733
1724 1734 TYPE_CHANGESET_COMMENT = u'cs_comment'
1725 1735 TYPE_MESSAGE = u'message'
1726 1736 TYPE_MENTION = u'mention'
1727 1737 TYPE_REGISTRATION = u'registration'
1728 1738 TYPE_PULL_REQUEST = u'pull_request'
1729 1739 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1730 1740
1731 1741 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1732 1742 subject = Column('subject', Unicode(512), nullable=True)
1733 1743 body = Column('body', UnicodeText(50000), nullable=True)
1734 1744 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1735 1745 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1736 1746 type_ = Column('type', Unicode(256))
1737 1747
1738 1748 created_by_user = relationship('User')
1739 1749 notifications_to_users = relationship('UserNotification', lazy='joined',
1740 1750 cascade="all, delete, delete-orphan")
1741 1751
1742 1752 @property
1743 1753 def recipients(self):
1744 1754 return [x.user for x in UserNotification.query()\
1745 1755 .filter(UserNotification.notification == self)\
1746 1756 .order_by(UserNotification.user_id.asc()).all()]
1747 1757
1748 1758 @classmethod
1749 1759 def create(cls, created_by, subject, body, recipients, type_=None):
1750 1760 if type_ is None:
1751 1761 type_ = Notification.TYPE_MESSAGE
1752 1762
1753 1763 notification = cls()
1754 1764 notification.created_by_user = created_by
1755 1765 notification.subject = subject
1756 1766 notification.body = body
1757 1767 notification.type_ = type_
1758 1768 notification.created_on = datetime.datetime.now()
1759 1769
1760 1770 for u in recipients:
1761 1771 assoc = UserNotification()
1762 1772 assoc.notification = notification
1763 1773 u.notifications.append(assoc)
1764 1774 Session().add(notification)
1765 1775 return notification
1766 1776
1767 1777 @property
1768 1778 def description(self):
1769 1779 from rhodecode.model.notification import NotificationModel
1770 1780 return NotificationModel().make_description(self)
1771 1781
1772 1782
1773 1783 class UserNotification(Base, BaseModel):
1774 1784 __tablename__ = 'user_to_notification'
1775 1785 __table_args__ = (
1776 1786 UniqueConstraint('user_id', 'notification_id'),
1777 1787 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1778 1788 'mysql_charset': 'utf8'}
1779 1789 )
1780 1790 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1781 1791 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1782 1792 read = Column('read', Boolean, default=False)
1783 1793 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1784 1794
1785 1795 user = relationship('User', lazy="joined")
1786 1796 notification = relationship('Notification', lazy="joined",
1787 1797 order_by=lambda: Notification.created_on.desc(),)
1788 1798
1789 1799 def mark_as_read(self):
1790 1800 self.read = True
1791 1801 Session().add(self)
1792 1802
1793 1803
1794 1804 class DbMigrateVersion(Base, BaseModel):
1795 1805 __tablename__ = 'db_migrate_version'
1796 1806 __table_args__ = (
1797 1807 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1798 1808 'mysql_charset': 'utf8'},
1799 1809 )
1800 1810 repository_id = Column('repository_id', String(250), primary_key=True)
1801 1811 repository_path = Column('repository_path', Text)
1802 1812 version = Column('version', Integer)
@@ -1,618 +1,618 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.scm
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Scm model for RhodeCode
7 7
8 8 :created_on: Apr 9, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25 from __future__ import with_statement
26 26 import os
27 27 import re
28 28 import time
29 29 import traceback
30 30 import logging
31 31 import cStringIO
32 32 import pkg_resources
33 33 from os.path import dirname as dn, join as jn
34 34
35 35 from sqlalchemy import func
36 36 from pylons.i18n.translation import _
37 37
38 38 import rhodecode
39 39 from rhodecode.lib.vcs import get_backend
40 40 from rhodecode.lib.vcs.exceptions import RepositoryError
41 41 from rhodecode.lib.vcs.utils.lazy import LazyProperty
42 42 from rhodecode.lib.vcs.nodes import FileNode
43 43 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44 44
45 45 from rhodecode import BACKENDS
46 46 from rhodecode.lib import helpers as h
47 47 from rhodecode.lib.utils2 import safe_str, safe_unicode
48 48 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
49 49 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
50 50 action_logger, REMOVED_REPO_PAT
51 51 from rhodecode.model import BaseModel
52 52 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
53 53 UserFollowing, UserLog, User, RepoGroup, PullRequest
54 54
55 55 log = logging.getLogger(__name__)
56 56
57 57
58 58 class UserTemp(object):
59 59 def __init__(self, user_id):
60 60 self.user_id = user_id
61 61
62 62 def __repr__(self):
63 63 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
64 64
65 65
66 66 class RepoTemp(object):
67 67 def __init__(self, repo_id):
68 68 self.repo_id = repo_id
69 69
70 70 def __repr__(self):
71 71 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
72 72
73 73
74 74 class CachedRepoList(object):
75 75 """
76 76 Cached repo list, uses in-memory cache after initialization, that is
77 77 super fast
78 78 """
79 79
80 80 def __init__(self, db_repo_list, repos_path, order_by=None):
81 81 self.db_repo_list = db_repo_list
82 82 self.repos_path = repos_path
83 83 self.order_by = order_by
84 84 self.reversed = (order_by or '').startswith('-')
85 85
86 86 def __len__(self):
87 87 return len(self.db_repo_list)
88 88
89 89 def __repr__(self):
90 90 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
91 91
92 92 def __iter__(self):
93 93 # pre-propagated cache_map to save executing select statements
94 94 # for each repo
95 95 cache_map = CacheInvalidation.get_cache_map()
96 96
97 97 for dbr in self.db_repo_list:
98 98 scmr = dbr.scm_instance_cached(cache_map)
99 99 # check permission at this level
100 100 if not HasRepoPermissionAny(
101 101 'repository.read', 'repository.write', 'repository.admin'
102 102 )(dbr.repo_name, 'get repo check'):
103 103 continue
104 104
105 105 if scmr is None:
106 106 log.error(
107 107 '%s this repository is present in database but it '
108 108 'cannot be created as an scm instance' % dbr.repo_name
109 109 )
110 110 continue
111 111
112 112 last_change = scmr.last_change
113 113 tip = h.get_changeset_safe(scmr, 'tip')
114 114
115 115 tmp_d = {}
116 116 tmp_d['name'] = dbr.repo_name
117 117 tmp_d['name_sort'] = tmp_d['name'].lower()
118 118 tmp_d['raw_name'] = tmp_d['name'].lower()
119 119 tmp_d['description'] = dbr.description
120 120 tmp_d['description_sort'] = tmp_d['description'].lower()
121 121 tmp_d['last_change'] = last_change
122 122 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
123 123 tmp_d['tip'] = tip.raw_id
124 124 tmp_d['tip_sort'] = tip.revision
125 125 tmp_d['rev'] = tip.revision
126 126 tmp_d['contact'] = dbr.user.full_contact
127 127 tmp_d['contact_sort'] = tmp_d['contact']
128 128 tmp_d['owner_sort'] = tmp_d['contact']
129 129 tmp_d['repo_archives'] = list(scmr._get_archives())
130 130 tmp_d['last_msg'] = tip.message
131 131 tmp_d['author'] = tip.author
132 132 tmp_d['dbrepo'] = dbr.get_dict()
133 133 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
134 134 yield tmp_d
135 135
136 136
137 137 class SimpleCachedRepoList(CachedRepoList):
138 138 """
139 139 Lighter version of CachedRepoList without the scm initialisation
140 140 """
141 141
142 142 def __iter__(self):
143 143 for dbr in self.db_repo_list:
144 144 # check permission at this level
145 145 if not HasRepoPermissionAny(
146 146 'repository.read', 'repository.write', 'repository.admin'
147 147 )(dbr.repo_name, 'get repo check'):
148 148 continue
149 149
150 150 tmp_d = {}
151 151 tmp_d['name'] = dbr.repo_name
152 152 tmp_d['name_sort'] = tmp_d['name'].lower()
153 153 tmp_d['raw_name'] = tmp_d['name'].lower()
154 154 tmp_d['description'] = dbr.description
155 155 tmp_d['description_sort'] = tmp_d['description'].lower()
156 156 tmp_d['dbrepo'] = dbr.get_dict()
157 157 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
158 158 yield tmp_d
159 159
160 160
161 161 class GroupList(object):
162 162
163 163 def __init__(self, db_repo_group_list):
164 164 self.db_repo_group_list = db_repo_group_list
165 165
166 166 def __len__(self):
167 167 return len(self.db_repo_group_list)
168 168
169 169 def __repr__(self):
170 170 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
171 171
172 172 def __iter__(self):
173 173 for dbgr in self.db_repo_group_list:
174 174 # check permission at this level
175 175 if not HasReposGroupPermissionAny(
176 176 'group.read', 'group.write', 'group.admin'
177 177 )(dbgr.group_name, 'get group repo check'):
178 178 continue
179 179
180 180 yield dbgr
181 181
182 182
183 183 class ScmModel(BaseModel):
184 184 """
185 185 Generic Scm Model
186 186 """
187 187
188 188 def __get_repo(self, instance):
189 189 cls = Repository
190 190 if isinstance(instance, cls):
191 191 return instance
192 192 elif isinstance(instance, int) or safe_str(instance).isdigit():
193 193 return cls.get(instance)
194 194 elif isinstance(instance, basestring):
195 195 return cls.get_by_repo_name(instance)
196 196 elif instance:
197 197 raise Exception('given object must be int, basestr or Instance'
198 198 ' of %s got %s' % (type(cls), type(instance)))
199 199
200 200 @LazyProperty
201 201 def repos_path(self):
202 202 """
203 203 Get's the repositories root path from database
204 204 """
205 205
206 206 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
207 207
208 208 return q.ui_value
209 209
210 210 def repo_scan(self, repos_path=None):
211 211 """
212 212 Listing of repositories in given path. This path should not be a
213 213 repository itself. Return a dictionary of repository objects
214 214
215 215 :param repos_path: path to directory containing repositories
216 216 """
217 217
218 218 if repos_path is None:
219 219 repos_path = self.repos_path
220 220
221 221 log.info('scanning for repositories in %s' % repos_path)
222 222
223 223 baseui = make_ui('db')
224 224 repos = {}
225 225
226 226 for name, path in get_filesystem_repos(repos_path, recursive=True):
227 227 # skip removed repos
228 228 if REMOVED_REPO_PAT.match(name):
229 229 continue
230 230
231 231 # name need to be decomposed and put back together using the /
232 232 # since this is internal storage separator for rhodecode
233 233 name = Repository.url_sep().join(name.split(os.sep))
234 234
235 235 try:
236 236 if name in repos:
237 237 raise RepositoryError('Duplicate repository name %s '
238 238 'found in %s' % (name, path))
239 239 else:
240 240
241 241 klass = get_backend(path[0])
242 242
243 243 if path[0] == 'hg' and path[0] in BACKENDS.keys():
244 244 repos[name] = klass(safe_str(path[1]), baseui=baseui)
245 245
246 246 if path[0] == 'git' and path[0] in BACKENDS.keys():
247 247 repos[name] = klass(path[1])
248 248 except OSError:
249 249 continue
250 250
251 251 return repos
252 252
253 253 def get_repos(self, all_repos=None, sort_key=None, simple=False):
254 254 """
255 255 Get all repos from db and for each repo create it's
256 256 backend instance and fill that backed with information from database
257 257
258 258 :param all_repos: list of repository names as strings
259 259 give specific repositories list, good for filtering
260 260
261 261 :param sort_key: initial sorting of repos
262 262 :param simple: use SimpleCachedList - one without the SCM info
263 263 """
264 264 if all_repos is None:
265 265 all_repos = self.sa.query(Repository)\
266 266 .filter(Repository.group_id == None)\
267 267 .order_by(func.lower(Repository.repo_name)).all()
268 268 if simple:
269 269 repo_iter = SimpleCachedRepoList(all_repos,
270 270 repos_path=self.repos_path,
271 271 order_by=sort_key)
272 272 else:
273 273 repo_iter = CachedRepoList(all_repos,
274 274 repos_path=self.repos_path,
275 275 order_by=sort_key)
276 276
277 277 return repo_iter
278 278
279 279 def get_repos_groups(self, all_groups=None):
280 280 if all_groups is None:
281 281 all_groups = RepoGroup.query()\
282 282 .filter(RepoGroup.group_parent_id == None).all()
283 283 group_iter = GroupList(all_groups)
284 284
285 285 return group_iter
286 286
287 287 def mark_for_invalidation(self, repo_name):
288 288 """
289 289 Puts cache invalidation task into db for
290 290 further global cache invalidation
291 291
292 292 :param repo_name: this repo that should invalidation take place
293 293 """
294 CacheInvalidation.set_invalidate(repo_name)
294 CacheInvalidation.set_invalidate(repo_name=repo_name)
295 295
296 296 def toggle_following_repo(self, follow_repo_id, user_id):
297 297
298 298 f = self.sa.query(UserFollowing)\
299 299 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
300 300 .filter(UserFollowing.user_id == user_id).scalar()
301 301
302 302 if f is not None:
303 303 try:
304 304 self.sa.delete(f)
305 305 action_logger(UserTemp(user_id),
306 306 'stopped_following_repo',
307 307 RepoTemp(follow_repo_id))
308 308 return
309 309 except:
310 310 log.error(traceback.format_exc())
311 311 raise
312 312
313 313 try:
314 314 f = UserFollowing()
315 315 f.user_id = user_id
316 316 f.follows_repo_id = follow_repo_id
317 317 self.sa.add(f)
318 318
319 319 action_logger(UserTemp(user_id),
320 320 'started_following_repo',
321 321 RepoTemp(follow_repo_id))
322 322 except:
323 323 log.error(traceback.format_exc())
324 324 raise
325 325
326 326 def toggle_following_user(self, follow_user_id, user_id):
327 327 f = self.sa.query(UserFollowing)\
328 328 .filter(UserFollowing.follows_user_id == follow_user_id)\
329 329 .filter(UserFollowing.user_id == user_id).scalar()
330 330
331 331 if f is not None:
332 332 try:
333 333 self.sa.delete(f)
334 334 return
335 335 except:
336 336 log.error(traceback.format_exc())
337 337 raise
338 338
339 339 try:
340 340 f = UserFollowing()
341 341 f.user_id = user_id
342 342 f.follows_user_id = follow_user_id
343 343 self.sa.add(f)
344 344 except:
345 345 log.error(traceback.format_exc())
346 346 raise
347 347
348 348 def is_following_repo(self, repo_name, user_id, cache=False):
349 349 r = self.sa.query(Repository)\
350 350 .filter(Repository.repo_name == repo_name).scalar()
351 351
352 352 f = self.sa.query(UserFollowing)\
353 353 .filter(UserFollowing.follows_repository == r)\
354 354 .filter(UserFollowing.user_id == user_id).scalar()
355 355
356 356 return f is not None
357 357
358 358 def is_following_user(self, username, user_id, cache=False):
359 359 u = User.get_by_username(username)
360 360
361 361 f = self.sa.query(UserFollowing)\
362 362 .filter(UserFollowing.follows_user == u)\
363 363 .filter(UserFollowing.user_id == user_id).scalar()
364 364
365 365 return f is not None
366 366
367 367 def get_followers(self, repo):
368 368 repo = self._get_repo(repo)
369 369
370 370 return self.sa.query(UserFollowing)\
371 371 .filter(UserFollowing.follows_repository == repo).count()
372 372
373 373 def get_forks(self, repo):
374 374 repo = self._get_repo(repo)
375 375 return self.sa.query(Repository)\
376 376 .filter(Repository.fork == repo).count()
377 377
378 378 def get_pull_requests(self, repo):
379 379 repo = self._get_repo(repo)
380 380 return self.sa.query(PullRequest)\
381 381 .filter(PullRequest.other_repo == repo).count()
382 382
383 383 def mark_as_fork(self, repo, fork, user):
384 384 repo = self.__get_repo(repo)
385 385 fork = self.__get_repo(fork)
386 386 if fork and repo.repo_id == fork.repo_id:
387 387 raise Exception("Cannot set repository as fork of itself")
388 388 repo.fork = fork
389 389 self.sa.add(repo)
390 390 return repo
391 391
392 392 def pull_changes(self, repo, username):
393 393 dbrepo = self.__get_repo(repo)
394 394 clone_uri = dbrepo.clone_uri
395 395 if not clone_uri:
396 396 raise Exception("This repository doesn't have a clone uri")
397 397
398 398 repo = dbrepo.scm_instance
399 399 from rhodecode import CONFIG
400 400 try:
401 401 extras = {
402 402 'ip': '',
403 403 'username': username,
404 404 'action': 'push_remote',
405 405 'repository': dbrepo.repo_name,
406 406 'scm': repo.alias,
407 407 'config': CONFIG['__file__'],
408 408 'make_lock': None,
409 409 'locked_by': [None, None]
410 410 }
411 411
412 412 Repository.inject_ui(repo, extras=extras)
413 413
414 414 if repo.alias == 'git':
415 415 repo.fetch(clone_uri)
416 416 else:
417 417 repo.pull(clone_uri)
418 418 self.mark_for_invalidation(dbrepo.repo_name)
419 419 except:
420 420 log.error(traceback.format_exc())
421 421 raise
422 422
423 423 def commit_change(self, repo, repo_name, cs, user, author, message,
424 424 content, f_path):
425 425 """
426 426 Commits changes
427 427
428 428 :param repo: SCM instance
429 429
430 430 """
431 431
432 432 if repo.alias == 'hg':
433 433 from rhodecode.lib.vcs.backends.hg import \
434 434 MercurialInMemoryChangeset as IMC
435 435 elif repo.alias == 'git':
436 436 from rhodecode.lib.vcs.backends.git import \
437 437 GitInMemoryChangeset as IMC
438 438
439 439 # decoding here will force that we have proper encoded values
440 440 # in any other case this will throw exceptions and deny commit
441 441 content = safe_str(content)
442 442 path = safe_str(f_path)
443 443 # message and author needs to be unicode
444 444 # proper backend should then translate that into required type
445 445 message = safe_unicode(message)
446 446 author = safe_unicode(author)
447 447 m = IMC(repo)
448 448 m.change(FileNode(path, content))
449 449 tip = m.commit(message=message,
450 450 author=author,
451 451 parents=[cs], branch=cs.branch)
452 452
453 453 action = 'push_local:%s' % tip.raw_id
454 454 action_logger(user, action, repo_name)
455 455 self.mark_for_invalidation(repo_name)
456 456 return tip
457 457
458 458 def create_node(self, repo, repo_name, cs, user, author, message, content,
459 459 f_path):
460 460 if repo.alias == 'hg':
461 461 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
462 462 elif repo.alias == 'git':
463 463 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
464 464 # decoding here will force that we have proper encoded values
465 465 # in any other case this will throw exceptions and deny commit
466 466
467 467 if isinstance(content, (basestring,)):
468 468 content = safe_str(content)
469 469 elif isinstance(content, (file, cStringIO.OutputType,)):
470 470 content = content.read()
471 471 else:
472 472 raise Exception('Content is of unrecognized type %s' % (
473 473 type(content)
474 474 ))
475 475
476 476 message = safe_unicode(message)
477 477 author = safe_unicode(author)
478 478 path = safe_str(f_path)
479 479 m = IMC(repo)
480 480
481 481 if isinstance(cs, EmptyChangeset):
482 482 # EmptyChangeset means we we're editing empty repository
483 483 parents = None
484 484 else:
485 485 parents = [cs]
486 486
487 487 m.add(FileNode(path, content=content))
488 488 tip = m.commit(message=message,
489 489 author=author,
490 490 parents=parents, branch=cs.branch)
491 491
492 492 action = 'push_local:%s' % tip.raw_id
493 493 action_logger(user, action, repo_name)
494 494 self.mark_for_invalidation(repo_name)
495 495 return tip
496 496
497 497 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
498 498 """
499 499 recursive walk in root dir and return a set of all path in that dir
500 500 based on repository walk function
501 501
502 502 :param repo_name: name of repository
503 503 :param revision: revision for which to list nodes
504 504 :param root_path: root path to list
505 505 :param flat: return as a list, if False returns a dict with decription
506 506
507 507 """
508 508 _files = list()
509 509 _dirs = list()
510 510 try:
511 511 _repo = self.__get_repo(repo_name)
512 512 changeset = _repo.scm_instance.get_changeset(revision)
513 513 root_path = root_path.lstrip('/')
514 514 for topnode, dirs, files in changeset.walk(root_path):
515 515 for f in files:
516 516 _files.append(f.path if flat else {"name": f.path,
517 517 "type": "file"})
518 518 for d in dirs:
519 519 _dirs.append(d.path if flat else {"name": d.path,
520 520 "type": "dir"})
521 521 except RepositoryError:
522 522 log.debug(traceback.format_exc())
523 523 raise
524 524
525 525 return _dirs, _files
526 526
527 527 def get_unread_journal(self):
528 528 return self.sa.query(UserLog).count()
529 529
530 530 def get_repo_landing_revs(self, repo=None):
531 531 """
532 532 Generates select option with tags branches and bookmarks (for hg only)
533 533 grouped by type
534 534
535 535 :param repo:
536 536 :type repo:
537 537 """
538 538
539 539 hist_l = []
540 540 choices = []
541 541 repo = self.__get_repo(repo)
542 542 hist_l.append(['tip', _('latest tip')])
543 543 choices.append('tip')
544 544 if not repo:
545 545 return choices, hist_l
546 546
547 547 repo = repo.scm_instance
548 548
549 549 branches_group = ([(k, k) for k, v in
550 550 repo.branches.iteritems()], _("Branches"))
551 551 hist_l.append(branches_group)
552 552 choices.extend([x[0] for x in branches_group[0]])
553 553
554 554 if repo.alias == 'hg':
555 555 bookmarks_group = ([(k, k) for k, v in
556 556 repo.bookmarks.iteritems()], _("Bookmarks"))
557 557 hist_l.append(bookmarks_group)
558 558 choices.extend([x[0] for x in bookmarks_group[0]])
559 559
560 560 tags_group = ([(k, k) for k, v in
561 561 repo.tags.iteritems()], _("Tags"))
562 562 hist_l.append(tags_group)
563 563 choices.extend([x[0] for x in tags_group[0]])
564 564
565 565 return choices, hist_l
566 566
567 567 def install_git_hook(self, repo, force_create=False):
568 568 """
569 569 Creates a rhodecode hook inside a git repository
570 570
571 571 :param repo: Instance of VCS repo
572 572 :param force_create: Create even if same name hook exists
573 573 """
574 574
575 575 loc = jn(repo.path, 'hooks')
576 576 if not repo.bare:
577 577 loc = jn(repo.path, '.git', 'hooks')
578 578 if not os.path.isdir(loc):
579 579 os.makedirs(loc)
580 580
581 581 tmpl_post = pkg_resources.resource_string(
582 582 'rhodecode', jn('config', 'post_receive_tmpl.py')
583 583 )
584 584 tmpl_pre = pkg_resources.resource_string(
585 585 'rhodecode', jn('config', 'pre_receive_tmpl.py')
586 586 )
587 587
588 588 for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
589 589 _hook_file = jn(loc, '%s-receive' % h_type)
590 590 _rhodecode_hook = False
591 591 log.debug('Installing git hook in repo %s' % repo)
592 592 if os.path.exists(_hook_file):
593 593 # let's take a look at this hook, maybe it's rhodecode ?
594 594 log.debug('hook exists, checking if it is from rhodecode')
595 595 _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
596 596 with open(_hook_file, 'rb') as f:
597 597 data = f.read()
598 598 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
599 599 % 'RC_HOOK_VER').search(data)
600 600 if matches:
601 601 try:
602 602 ver = matches.groups()[0]
603 603 log.debug('got %s it is rhodecode' % (ver))
604 604 _rhodecode_hook = True
605 605 except:
606 606 log.error(traceback.format_exc())
607 607 else:
608 608 # there is no hook in this dir, so we want to create one
609 609 _rhodecode_hook = True
610 610
611 611 if _rhodecode_hook or force_create:
612 612 log.debug('writing %s hook file !' % h_type)
613 613 with open(_hook_file, 'wb') as f:
614 614 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
615 615 f.write(tmpl)
616 616 os.chmod(_hook_file, 0755)
617 617 else:
618 618 log.debug('skipping writing hook file')
@@ -1,4759 +1,4760 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 {
3 3 border: 0;
4 4 outline: 0;
5 5 font-size: 100%;
6 6 vertical-align: baseline;
7 7 background: transparent;
8 8 margin: 0;
9 9 padding: 0;
10 10 }
11 11
12 12 body {
13 13 line-height: 1;
14 14 height: 100%;
15 15 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
16 16 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
17 17 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
18 18 color: #000;
19 19 margin: 0;
20 20 padding: 0;
21 21 font-size: 12px;
22 22 }
23 23
24 24 ol,ul {
25 25 list-style: none;
26 26 }
27 27
28 28 blockquote,q {
29 29 quotes: none;
30 30 }
31 31
32 32 blockquote:before,blockquote:after,q:before,q:after {
33 33 content: none;
34 34 }
35 35
36 36 :focus {
37 37 outline: 0;
38 38 }
39 39
40 40 del {
41 41 text-decoration: line-through;
42 42 }
43 43
44 44 table {
45 45 border-collapse: collapse;
46 46 border-spacing: 0;
47 47 }
48 48
49 49 html {
50 50 height: 100%;
51 51 }
52 52
53 53 a {
54 54 color: #003367;
55 55 text-decoration: none;
56 56 cursor: pointer;
57 57 }
58 58
59 59 a:hover {
60 60 color: #316293;
61 61 text-decoration: underline;
62 62 }
63 63
64 64 h1,h2,h3,h4,h5,h6,
65 65 div.h1,div.h2,div.h3,div.h4,div.h5,div.h6 {
66 66 color: #292929;
67 67 font-weight: 700;
68 68 }
69 69
70 70 h1,div.h1 {
71 71 font-size: 22px;
72 72 }
73 73
74 74 h2,div.h2 {
75 75 font-size: 20px;
76 76 }
77 77
78 78 h3,div.h3 {
79 79 font-size: 18px;
80 80 }
81 81
82 82 h4,div.h4 {
83 83 font-size: 16px;
84 84 }
85 85
86 86 h5,div.h5 {
87 87 font-size: 14px;
88 88 }
89 89
90 90 h6,div.h6 {
91 91 font-size: 11px;
92 92 }
93 93
94 94 ul.circle {
95 95 list-style-type: circle;
96 96 }
97 97
98 98 ul.disc {
99 99 list-style-type: disc;
100 100 }
101 101
102 102 ul.square {
103 103 list-style-type: square;
104 104 }
105 105
106 106 ol.lower-roman {
107 107 list-style-type: lower-roman;
108 108 }
109 109
110 110 ol.upper-roman {
111 111 list-style-type: upper-roman;
112 112 }
113 113
114 114 ol.lower-alpha {
115 115 list-style-type: lower-alpha;
116 116 }
117 117
118 118 ol.upper-alpha {
119 119 list-style-type: upper-alpha;
120 120 }
121 121
122 122 ol.decimal {
123 123 list-style-type: decimal;
124 124 }
125 125
126 126 div.color {
127 127 clear: both;
128 128 overflow: hidden;
129 129 position: absolute;
130 130 background: #FFF;
131 131 margin: 7px 0 0 60px;
132 132 padding: 1px 1px 1px 0;
133 133 }
134 134
135 135 div.color a {
136 136 width: 15px;
137 137 height: 15px;
138 138 display: block;
139 139 float: left;
140 140 margin: 0 0 0 1px;
141 141 padding: 0;
142 142 }
143 143
144 144 div.options {
145 145 clear: both;
146 146 overflow: hidden;
147 147 position: absolute;
148 148 background: #FFF;
149 149 margin: 7px 0 0 162px;
150 150 padding: 0;
151 151 }
152 152
153 153 div.options a {
154 154 height: 1%;
155 155 display: block;
156 156 text-decoration: none;
157 157 margin: 0;
158 158 padding: 3px 8px;
159 159 }
160 160
161 161 .top-left-rounded-corner {
162 162 -webkit-border-top-left-radius: 8px;
163 163 -khtml-border-radius-topleft: 8px;
164 164 -moz-border-radius-topleft: 8px;
165 165 border-top-left-radius: 8px;
166 166 }
167 167
168 168 .top-right-rounded-corner {
169 169 -webkit-border-top-right-radius: 8px;
170 170 -khtml-border-radius-topright: 8px;
171 171 -moz-border-radius-topright: 8px;
172 172 border-top-right-radius: 8px;
173 173 }
174 174
175 175 .bottom-left-rounded-corner {
176 176 -webkit-border-bottom-left-radius: 8px;
177 177 -khtml-border-radius-bottomleft: 8px;
178 178 -moz-border-radius-bottomleft: 8px;
179 179 border-bottom-left-radius: 8px;
180 180 }
181 181
182 182 .bottom-right-rounded-corner {
183 183 -webkit-border-bottom-right-radius: 8px;
184 184 -khtml-border-radius-bottomright: 8px;
185 185 -moz-border-radius-bottomright: 8px;
186 186 border-bottom-right-radius: 8px;
187 187 }
188 188
189 189 .top-left-rounded-corner-mid {
190 190 -webkit-border-top-left-radius: 4px;
191 191 -khtml-border-radius-topleft: 4px;
192 192 -moz-border-radius-topleft: 4px;
193 193 border-top-left-radius: 4px;
194 194 }
195 195
196 196 .top-right-rounded-corner-mid {
197 197 -webkit-border-top-right-radius: 4px;
198 198 -khtml-border-radius-topright: 4px;
199 199 -moz-border-radius-topright: 4px;
200 200 border-top-right-radius: 4px;
201 201 }
202 202
203 203 .bottom-left-rounded-corner-mid {
204 204 -webkit-border-bottom-left-radius: 4px;
205 205 -khtml-border-radius-bottomleft: 4px;
206 206 -moz-border-radius-bottomleft: 4px;
207 207 border-bottom-left-radius: 4px;
208 208 }
209 209
210 210 .bottom-right-rounded-corner-mid {
211 211 -webkit-border-bottom-right-radius: 4px;
212 212 -khtml-border-radius-bottomright: 4px;
213 213 -moz-border-radius-bottomright: 4px;
214 214 border-bottom-right-radius: 4px;
215 215 }
216 216
217 217 .help-block {
218 218 color: #999999;
219 219 display: block;
220 220 margin-bottom: 0;
221 221 margin-top: 5px;
222 222 }
223 223
224 224 .empty_data{
225 225 color:#B9B9B9;
226 226 }
227 227
228 228 a.permalink{
229 229 visibility: hidden;
230 230 }
231 231
232 232 a.permalink:hover{
233 233 text-decoration: none;
234 234 }
235 235
236 236 h1:hover > a.permalink,
237 237 h2:hover > a.permalink,
238 238 h3:hover > a.permalink,
239 239 h4:hover > a.permalink,
240 240 h5:hover > a.permalink,
241 241 h6:hover > a.permalink,
242 242 div:hover > a.permalink {
243 243 visibility: visible;
244 244 }
245 245
246 246 #header {
247 247 margin: 0;
248 248 padding: 0 10px;
249 249 }
250 250
251 251 #header ul#logged-user {
252 252 margin-bottom: 5px !important;
253 253 -webkit-border-radius: 0px 0px 8px 8px;
254 254 -khtml-border-radius: 0px 0px 8px 8px;
255 255 -moz-border-radius: 0px 0px 8px 8px;
256 256 border-radius: 0px 0px 8px 8px;
257 257 height: 37px;
258 258 background-color: #003B76;
259 259 background-repeat: repeat-x;
260 260 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
261 261 background-image: -moz-linear-gradient(top, #003b76, #00376e);
262 262 background-image: -ms-linear-gradient(top, #003b76, #00376e);
263 263 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
264 264 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
265 265 background-image: -o-linear-gradient(top, #003b76, #00376e);
266 266 background-image: linear-gradient(top, #003b76, #00376e);
267 267 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
268 268 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
269 269 }
270 270
271 271 #header ul#logged-user li {
272 272 list-style: none;
273 273 float: left;
274 274 margin: 8px 0 0;
275 275 padding: 4px 12px;
276 276 border-left: 1px solid #316293;
277 277 }
278 278
279 279 #header ul#logged-user li.first {
280 280 border-left: none;
281 281 margin: 4px;
282 282 }
283 283
284 284 #header ul#logged-user li.first div.gravatar {
285 285 margin-top: -2px;
286 286 }
287 287
288 288 #header ul#logged-user li.first div.account {
289 289 padding-top: 4px;
290 290 float: left;
291 291 }
292 292
293 293 #header ul#logged-user li.last {
294 294 border-right: none;
295 295 }
296 296
297 297 #header ul#logged-user li a {
298 298 color: #fff;
299 299 font-weight: 700;
300 300 text-decoration: none;
301 301 }
302 302
303 303 #header ul#logged-user li a:hover {
304 304 text-decoration: underline;
305 305 }
306 306
307 307 #header ul#logged-user li.highlight a {
308 308 color: #fff;
309 309 }
310 310
311 311 #header ul#logged-user li.highlight a:hover {
312 312 color: #FFF;
313 313 }
314 314
315 315 #header #header-inner {
316 316 min-height: 44px;
317 317 clear: both;
318 318 position: relative;
319 319 background-color: #003B76;
320 320 background-repeat: repeat-x;
321 321 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
322 322 background-image: -moz-linear-gradient(top, #003b76, #00376e);
323 323 background-image: -ms-linear-gradient(top, #003b76, #00376e);
324 324 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
325 325 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
326 326 background-image: -o-linear-gradient(top, #003b76, #00376e);
327 327 background-image: linear-gradient(top, #003b76, #00376e);
328 328 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
329 329 margin: 0;
330 330 padding: 0;
331 331 display: block;
332 332 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
333 333 -webkit-border-radius: 4px 4px 4px 4px;
334 334 -khtml-border-radius: 4px 4px 4px 4px;
335 335 -moz-border-radius: 4px 4px 4px 4px;
336 336 border-radius: 4px 4px 4px 4px;
337 337 }
338 338 #header #header-inner.hover{
339 339 position: fixed !important;
340 340 width: 100% !important;
341 341 margin-left: -10px !important;
342 342 z-index: 10000;
343 343 -webkit-border-radius: 0px 0px 0px 0px;
344 344 -khtml-border-radius: 0px 0px 0px 0px;
345 345 -moz-border-radius: 0px 0px 0px 0px;
346 346 border-radius: 0px 0px 0px 0px;
347 347 }
348 348
349 349 .ie7 #header #header-inner.hover,
350 350 .ie8 #header #header-inner.hover,
351 351 .ie9 #header #header-inner.hover
352 352 {
353 353 z-index: auto !important;
354 354 }
355 355
356 356 .header-pos-fix, .anchor{
357 357 margin-top: -46px;
358 358 padding-top: 46px;
359 359 }
360 360
361 361 #header #header-inner #home a {
362 362 height: 40px;
363 363 width: 46px;
364 364 display: block;
365 365 background: url("../images/button_home.png");
366 366 background-position: 0 0;
367 367 margin: 0;
368 368 padding: 0;
369 369 }
370 370
371 371 #header #header-inner #home a:hover {
372 372 background-position: 0 -40px;
373 373 }
374 374
375 375 #header #header-inner #logo {
376 376 float: left;
377 377 position: absolute;
378 378 }
379 379
380 380 #header #header-inner #logo h1 {
381 381 color: #FFF;
382 382 font-size: 20px;
383 383 margin: 12px 0 0 13px;
384 384 padding: 0;
385 385 }
386 386
387 387 #header #header-inner #logo a {
388 388 color: #fff;
389 389 text-decoration: none;
390 390 }
391 391
392 392 #header #header-inner #logo a:hover {
393 393 color: #bfe3ff;
394 394 }
395 395
396 396 #header #header-inner #quick,#header #header-inner #quick ul {
397 397 position: relative;
398 398 float: right;
399 399 list-style-type: none;
400 400 list-style-position: outside;
401 401 margin: 8px 8px 0 0;
402 402 padding: 0;
403 403 }
404 404
405 405 #header #header-inner #quick li {
406 406 position: relative;
407 407 float: left;
408 408 margin: 0 5px 0 0;
409 409 padding: 0;
410 410 }
411 411
412 412 #header #header-inner #quick li a.menu_link {
413 413 top: 0;
414 414 left: 0;
415 415 height: 1%;
416 416 display: block;
417 417 clear: both;
418 418 overflow: hidden;
419 419 color: #FFF;
420 420 font-weight: 700;
421 421 text-decoration: none;
422 422 background: #369;
423 423 padding: 0;
424 424 -webkit-border-radius: 4px 4px 4px 4px;
425 425 -khtml-border-radius: 4px 4px 4px 4px;
426 426 -moz-border-radius: 4px 4px 4px 4px;
427 427 border-radius: 4px 4px 4px 4px;
428 428 }
429 429
430 430 #header #header-inner #quick li span.short {
431 431 padding: 9px 6px 8px 6px;
432 432 }
433 433
434 434 #header #header-inner #quick li span {
435 435 top: 0;
436 436 right: 0;
437 437 height: 1%;
438 438 display: block;
439 439 float: left;
440 440 border-left: 1px solid #3f6f9f;
441 441 margin: 0;
442 442 padding: 10px 12px 8px 10px;
443 443 }
444 444
445 445 #header #header-inner #quick li span.normal {
446 446 border: none;
447 447 padding: 10px 12px 8px;
448 448 }
449 449
450 450 #header #header-inner #quick li span.icon {
451 451 top: 0;
452 452 left: 0;
453 453 border-left: none;
454 454 border-right: 1px solid #2e5c89;
455 455 padding: 8px 6px 4px;
456 456 }
457 457
458 458 #header #header-inner #quick li span.icon_short {
459 459 top: 0;
460 460 left: 0;
461 461 border-left: none;
462 462 border-right: 1px solid #2e5c89;
463 463 padding: 8px 6px 4px;
464 464 }
465 465
466 466 #header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
467 467 {
468 468 margin: 0px -2px 0px 0px;
469 469 }
470 470
471 471 #header #header-inner #quick li a:hover {
472 472 background: #4e4e4e no-repeat top left;
473 473 }
474 474
475 475 #header #header-inner #quick li a:hover span {
476 476 border-left: 1px solid #545454;
477 477 }
478 478
479 479 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short
480 480 {
481 481 border-left: none;
482 482 border-right: 1px solid #464646;
483 483 }
484 484
485 485 #header #header-inner #quick ul {
486 486 top: 29px;
487 487 right: 0;
488 488 min-width: 200px;
489 489 display: none;
490 490 position: absolute;
491 491 background: #FFF;
492 492 border: 1px solid #666;
493 493 border-top: 1px solid #003367;
494 494 z-index: 100;
495 495 margin: 0px 0px 0px 0px;
496 496 padding: 0;
497 497 }
498 498
499 499 #header #header-inner #quick ul.repo_switcher {
500 500 max-height: 275px;
501 501 overflow-x: hidden;
502 502 overflow-y: auto;
503 503 }
504 504
505 505 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
506 506 float: none;
507 507 margin: 0;
508 508 border-bottom: 2px solid #003367;
509 509 }
510 510
511 511 #header #header-inner #quick .repo_switcher_type {
512 512 position: absolute;
513 513 left: 0;
514 514 top: 9px;
515 515 }
516 516
517 517 #header #header-inner #quick li ul li {
518 518 border-bottom: 1px solid #ddd;
519 519 }
520 520
521 521 #header #header-inner #quick li ul li a {
522 522 width: 182px;
523 523 height: auto;
524 524 display: block;
525 525 float: left;
526 526 background: #FFF;
527 527 color: #003367;
528 528 font-weight: 400;
529 529 margin: 0;
530 530 padding: 7px 9px;
531 531 }
532 532
533 533 #header #header-inner #quick li ul li a:hover {
534 534 color: #000;
535 535 background: #FFF;
536 536 }
537 537
538 538 #header #header-inner #quick ul ul {
539 539 top: auto;
540 540 }
541 541
542 542 #header #header-inner #quick li ul ul {
543 543 right: 200px;
544 544 max-height: 275px;
545 545 overflow: auto;
546 546 overflow-x: hidden;
547 547 white-space: normal;
548 548 }
549 549
550 550 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
551 551 {
552 552 background: url("../images/icons/book.png") no-repeat scroll 4px 9px
553 553 #FFF;
554 554 width: 167px;
555 555 margin: 0;
556 556 padding: 12px 9px 7px 24px;
557 557 }
558 558
559 559 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
560 560 {
561 561 background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
562 562 #FFF;
563 563 min-width: 167px;
564 564 margin: 0;
565 565 padding: 12px 9px 7px 24px;
566 566 }
567 567
568 568 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
569 569 {
570 570 background: url("../images/icons/lock_open.png") no-repeat scroll 4px
571 571 9px #FFF;
572 572 min-width: 167px;
573 573 margin: 0;
574 574 padding: 12px 9px 7px 24px;
575 575 }
576 576
577 577 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
578 578 {
579 579 background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
580 580 #FFF;
581 581 min-width: 167px;
582 582 margin: 0 0 0 14px;
583 583 padding: 12px 9px 7px 24px;
584 584 }
585 585
586 586 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
587 587 {
588 588 background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
589 589 #FFF;
590 590 min-width: 167px;
591 591 margin: 0 0 0 14px;
592 592 padding: 12px 9px 7px 24px;
593 593 }
594 594
595 595 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
596 596 {
597 597 background: url("../images/icons/database_edit.png") no-repeat scroll
598 598 4px 9px #FFF;
599 599 width: 167px;
600 600 margin: 0;
601 601 padding: 12px 9px 7px 24px;
602 602 }
603 603
604 604 #header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
605 605 {
606 606 background: url("../images/icons/database_link.png") no-repeat scroll
607 607 4px 9px #FFF;
608 608 width: 167px;
609 609 margin: 0;
610 610 padding: 12px 9px 7px 24px;
611 611 }
612 612
613 613 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
614 614 {
615 615 background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
616 616 width: 167px;
617 617 margin: 0;
618 618 padding: 12px 9px 7px 24px;
619 619 }
620 620
621 621 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
622 622 {
623 623 background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
624 624 width: 167px;
625 625 margin: 0;
626 626 padding: 12px 9px 7px 24px;
627 627 }
628 628
629 629 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
630 630 {
631 631 background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
632 632 width: 167px;
633 633 margin: 0;
634 634 padding: 12px 9px 7px 24px;
635 635 }
636 636
637 637 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover
638 638 {
639 639 background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
640 640 width: 167px;
641 641 margin: 0;
642 642 padding: 12px 9px 7px 24px;
643 643 }
644 644
645 645 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover
646 646 {
647 647 background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
648 648 width: 167px;
649 649 margin: 0;
650 650 padding: 12px 9px 7px 24px;
651 651 }
652 652
653 653 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover
654 654 {
655 655 background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
656 656 9px;
657 657 width: 167px;
658 658 margin: 0;
659 659 padding: 12px 9px 7px 24px;
660 660 }
661 661
662 662 #header #header-inner #quick li ul li a.locking_add,#header #header-inner #quick li ul li a.locking_add:hover
663 663 {
664 664 background: #FFF url("../images/icons/lock_add.png") no-repeat 4px
665 665 9px;
666 666 width: 167px;
667 667 margin: 0;
668 668 padding: 12px 9px 7px 24px;
669 669 }
670 670
671 671 #header #header-inner #quick li ul li a.locking_del,#header #header-inner #quick li ul li a.locking_del:hover
672 672 {
673 673 background: #FFF url("../images/icons/lock_delete.png") no-repeat 4px
674 674 9px;
675 675 width: 167px;
676 676 margin: 0;
677 677 padding: 12px 9px 7px 24px;
678 678 }
679 679
680 680 #header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
681 681 {
682 682 background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
683 683 9px;
684 684 width: 167px;
685 685 margin: 0;
686 686 padding: 12px 9px 7px 24px;
687 687 }
688 688
689 689 #header #header-inner #quick li ul li a.compare_request,#header #header-inner #quick li ul li a.compare_request:hover
690 690 {
691 691 background: #FFF url("../images/icons/arrow_inout.png") no-repeat 4px
692 692 9px;
693 693 width: 167px;
694 694 margin: 0;
695 695 padding: 12px 9px 7px 24px;
696 696 }
697 697
698 698 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
699 699 {
700 700 background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
701 701 width: 167px;
702 702 margin: 0;
703 703 padding: 12px 9px 7px 24px;
704 704 }
705 705
706 706 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover
707 707 {
708 708 background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
709 709 width: 167px;
710 710 margin: 0;
711 711 padding: 12px 9px 7px 24px;
712 712 }
713 713
714 714 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover
715 715 {
716 716 background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
717 717 9px;
718 718 width: 167px;
719 719 margin: 0;
720 720 padding: 12px 9px 7px 24px;
721 721 }
722 722
723 723 #header #header-inner #quick li ul li a.tags,
724 724 #header #header-inner #quick li ul li a.tags:hover{
725 725 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
726 726 width: 167px;
727 727 margin: 0;
728 728 padding: 12px 9px 7px 24px;
729 729 }
730 730
731 731 #header #header-inner #quick li ul li a.bookmarks,
732 732 #header #header-inner #quick li ul li a.bookmarks:hover{
733 733 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
734 734 width: 167px;
735 735 margin: 0;
736 736 padding: 12px 9px 7px 24px;
737 737 }
738 738
739 739 #header #header-inner #quick li ul li a.admin,
740 740 #header #header-inner #quick li ul li a.admin:hover{
741 741 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
742 742 width: 167px;
743 743 margin: 0;
744 744 padding: 12px 9px 7px 24px;
745 745 }
746 746
747 747 .groups_breadcrumbs a {
748 748 color: #fff;
749 749 }
750 750
751 751 .groups_breadcrumbs a:hover {
752 752 color: #bfe3ff;
753 753 text-decoration: none;
754 754 }
755 755
756 756 td.quick_repo_menu {
757 757 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
758 758 cursor: pointer;
759 759 width: 8px;
760 760 border: 1px solid transparent;
761 761 }
762 762
763 763 td.quick_repo_menu.active {
764 764 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
765 765 border: 1px solid #003367;
766 766 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
767 767 cursor: pointer;
768 768 }
769 769
770 770 td.quick_repo_menu .menu_items {
771 771 margin-top: 10px;
772 772 margin-left:-6px;
773 773 width: 150px;
774 774 position: absolute;
775 775 background-color: #FFF;
776 776 background: none repeat scroll 0 0 #FFFFFF;
777 777 border-color: #003367 #666666 #666666;
778 778 border-right: 1px solid #666666;
779 779 border-style: solid;
780 780 border-width: 1px;
781 781 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
782 782 border-top-style: none;
783 783 }
784 784
785 785 td.quick_repo_menu .menu_items li {
786 786 padding: 0 !important;
787 787 }
788 788
789 789 td.quick_repo_menu .menu_items a {
790 790 display: block;
791 791 padding: 4px 12px 4px 8px;
792 792 }
793 793
794 794 td.quick_repo_menu .menu_items a:hover {
795 795 background-color: #EEE;
796 796 text-decoration: none;
797 797 }
798 798
799 799 td.quick_repo_menu .menu_items .icon img {
800 800 margin-bottom: -2px;
801 801 }
802 802
803 803 td.quick_repo_menu .menu_items.hidden {
804 804 display: none;
805 805 }
806 806
807 807 .yui-dt-first th {
808 808 text-align: left;
809 809 }
810 810
811 811 /*
812 812 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
813 813 Code licensed under the BSD License:
814 814 http://developer.yahoo.com/yui/license.html
815 815 version: 2.9.0
816 816 */
817 817 .yui-skin-sam .yui-dt-mask {
818 818 position: absolute;
819 819 z-index: 9500;
820 820 }
821 821 .yui-dt-tmp {
822 822 position: absolute;
823 823 left: -9000px;
824 824 }
825 825 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
826 826 .yui-dt-scrollable .yui-dt-hd {
827 827 overflow: hidden;
828 828 position: relative;
829 829 }
830 830 .yui-dt-scrollable .yui-dt-bd thead tr,
831 831 .yui-dt-scrollable .yui-dt-bd thead th {
832 832 position: absolute;
833 833 left: -1500px;
834 834 }
835 835 .yui-dt-scrollable tbody { -moz-outline: 0 }
836 836 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
837 837 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
838 838 .yui-dt-coltarget {
839 839 position: absolute;
840 840 z-index: 999;
841 841 }
842 842 .yui-dt-hd { zoom: 1 }
843 843 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
844 844 .yui-dt-resizer {
845 845 position: absolute;
846 846 right: 0;
847 847 bottom: 0;
848 848 height: 100%;
849 849 cursor: e-resize;
850 850 cursor: col-resize;
851 851 background-color: #CCC;
852 852 opacity: 0;
853 853 filter: alpha(opacity=0);
854 854 }
855 855 .yui-dt-resizerproxy {
856 856 visibility: hidden;
857 857 position: absolute;
858 858 z-index: 9000;
859 859 background-color: #CCC;
860 860 opacity: 0;
861 861 filter: alpha(opacity=0);
862 862 }
863 863 th.yui-dt-hidden .yui-dt-liner,
864 864 td.yui-dt-hidden .yui-dt-liner,
865 865 th.yui-dt-hidden .yui-dt-resizer { display: none }
866 866 .yui-dt-editor,
867 867 .yui-dt-editor-shim {
868 868 position: absolute;
869 869 z-index: 9000;
870 870 }
871 871 .yui-skin-sam .yui-dt table {
872 872 margin: 0;
873 873 padding: 0;
874 874 font-family: arial;
875 875 font-size: inherit;
876 876 border-collapse: separate;
877 877 *border-collapse: collapse;
878 878 border-spacing: 0;
879 879 border: 1px solid #7f7f7f;
880 880 }
881 881 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
882 882 .yui-skin-sam .yui-dt caption {
883 883 color: #000;
884 884 font-size: 85%;
885 885 font-weight: normal;
886 886 font-style: italic;
887 887 line-height: 1;
888 888 padding: 1em 0;
889 889 text-align: center;
890 890 }
891 891 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
892 892 .yui-skin-sam .yui-dt th,
893 893 .yui-skin-sam .yui-dt th a {
894 894 font-weight: normal;
895 895 text-decoration: none;
896 896 color: #000;
897 897 vertical-align: bottom;
898 898 }
899 899 .yui-skin-sam .yui-dt th {
900 900 margin: 0;
901 901 padding: 0;
902 902 border: 0;
903 903 border-right: 1px solid #cbcbcb;
904 904 }
905 905 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
906 906 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
907 907 .yui-skin-sam .yui-dt-liner {
908 908 margin: 0;
909 909 padding: 0;
910 910 }
911 911 .yui-skin-sam .yui-dt-coltarget {
912 912 width: 5px;
913 913 background-color: red;
914 914 }
915 915 .yui-skin-sam .yui-dt td {
916 916 margin: 0;
917 917 padding: 0;
918 918 border: 0;
919 919 border-right: 1px solid #cbcbcb;
920 920 text-align: left;
921 921 }
922 922 .yui-skin-sam .yui-dt-list td { border-right: 0 }
923 923 .yui-skin-sam .yui-dt-resizer { width: 6px }
924 924 .yui-skin-sam .yui-dt-mask {
925 925 background-color: #000;
926 926 opacity: .25;
927 927 filter: alpha(opacity=25);
928 928 }
929 929 .yui-skin-sam .yui-dt-message { background-color: #FFF }
930 930 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
931 931 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
932 932 border-left: 1px solid #7f7f7f;
933 933 border-top: 1px solid #7f7f7f;
934 934 border-right: 1px solid #7f7f7f;
935 935 }
936 936 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
937 937 border-left: 1px solid #7f7f7f;
938 938 border-bottom: 1px solid #7f7f7f;
939 939 border-right: 1px solid #7f7f7f;
940 940 background-color: #FFF;
941 941 }
942 942 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
943 943 .yui-skin-sam th.yui-dt-asc,
944 944 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
945 945 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
946 946 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
947 947 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
948 948 tbody .yui-dt-editable { cursor: pointer }
949 949 .yui-dt-editor {
950 950 text-align: left;
951 951 background-color: #f2f2f2;
952 952 border: 1px solid #808080;
953 953 padding: 6px;
954 954 }
955 955 .yui-dt-editor label {
956 956 padding-left: 4px;
957 957 padding-right: 6px;
958 958 }
959 959 .yui-dt-editor .yui-dt-button {
960 960 padding-top: 6px;
961 961 text-align: right;
962 962 }
963 963 .yui-dt-editor .yui-dt-button button {
964 964 background: url(../images/sprite.png) repeat-x 0 0;
965 965 border: 1px solid #999;
966 966 width: 4em;
967 967 height: 1.8em;
968 968 margin-left: 6px;
969 969 }
970 970 .yui-dt-editor .yui-dt-button button.yui-dt-default {
971 971 background: url(../images/sprite.png) repeat-x 0 -1400px;
972 972 background-color: #5584e0;
973 973 border: 1px solid #304369;
974 974 color: #FFF;
975 975 }
976 976 .yui-dt-editor .yui-dt-button button:hover {
977 977 background: url(../images/sprite.png) repeat-x 0 -1300px;
978 978 color: #000;
979 979 }
980 980 .yui-dt-editor .yui-dt-button button:active {
981 981 background: url(../images/sprite.png) repeat-x 0 -1700px;
982 982 color: #000;
983 983 }
984 984 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
985 985 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
986 986 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
987 987 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
988 988 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
989 989 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
990 990 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
991 991 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
992 992 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
993 993 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
994 994 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
995 995 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
996 996 .yui-skin-sam th.yui-dt-highlighted,
997 997 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
998 998 .yui-skin-sam tr.yui-dt-highlighted,
999 999 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
1000 1000 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
1001 1001 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
1002 1002 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
1003 1003 cursor: pointer;
1004 1004 background-color: #b2d2ff;
1005 1005 }
1006 1006 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
1007 1007 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
1008 1008 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
1009 1009 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
1010 1010 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
1011 1011 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
1012 1012 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
1013 1013 cursor: pointer;
1014 1014 background-color: #b2d2ff;
1015 1015 }
1016 1016 .yui-skin-sam th.yui-dt-selected,
1017 1017 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
1018 1018 .yui-skin-sam tr.yui-dt-selected td,
1019 1019 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
1020 1020 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
1021 1021 background-color: #426fd9;
1022 1022 color: #FFF;
1023 1023 }
1024 1024 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
1025 1025 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
1026 1026 background-color: #446cd7;
1027 1027 color: #FFF;
1028 1028 }
1029 1029 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
1030 1030 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
1031 1031 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
1032 1032 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
1033 1033 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
1034 1034 background-color: #426fd9;
1035 1035 color: #FFF;
1036 1036 }
1037 1037 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
1038 1038 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
1039 1039 background-color: #446cd7;
1040 1040 color: #FFF;
1041 1041 }
1042 1042 .yui-skin-sam .yui-dt-paginator {
1043 1043 display: block;
1044 1044 margin: 6px 0;
1045 1045 white-space: nowrap;
1046 1046 }
1047 1047 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
1048 1048 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
1049 1049 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
1050 1050 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
1051 1051 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
1052 1052 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
1053 1053 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
1054 1054 .yui-skin-sam a.yui-dt-page {
1055 1055 border: 1px solid #cbcbcb;
1056 1056 padding: 2px 6px;
1057 1057 text-decoration: none;
1058 1058 background-color: #fff;
1059 1059 }
1060 1060 .yui-skin-sam .yui-dt-selected {
1061 1061 border: 1px solid #fff;
1062 1062 background-color: #fff;
1063 1063 }
1064 1064
1065 1065 #content #left {
1066 1066 left: 0;
1067 1067 width: 280px;
1068 1068 position: absolute;
1069 1069 }
1070 1070
1071 1071 #content #right {
1072 1072 margin: 0 60px 10px 290px;
1073 1073 }
1074 1074
1075 1075 #content div.box {
1076 1076 clear: both;
1077 1077 overflow: hidden;
1078 1078 background: #fff;
1079 1079 margin: 0 0 10px;
1080 1080 padding: 0 0 10px;
1081 1081 -webkit-border-radius: 4px 4px 4px 4px;
1082 1082 -khtml-border-radius: 4px 4px 4px 4px;
1083 1083 -moz-border-radius: 4px 4px 4px 4px;
1084 1084 border-radius: 4px 4px 4px 4px;
1085 1085 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1086 1086 }
1087 1087
1088 1088 #content div.box-left {
1089 1089 width: 49%;
1090 1090 clear: none;
1091 1091 float: left;
1092 1092 margin: 0 0 10px;
1093 1093 }
1094 1094
1095 1095 #content div.box-right {
1096 1096 width: 49%;
1097 1097 clear: none;
1098 1098 float: right;
1099 1099 margin: 0 0 10px;
1100 1100 }
1101 1101
1102 1102 #content div.box div.title {
1103 1103 clear: both;
1104 1104 overflow: hidden;
1105 1105 background-color: #003B76;
1106 1106 background-repeat: repeat-x;
1107 1107 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1108 1108 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1109 1109 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1110 1110 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1111 1111 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1112 1112 background-image: -o-linear-gradient(top, #003b76, #00376e);
1113 1113 background-image: linear-gradient(top, #003b76, #00376e);
1114 1114 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1115 1115 margin: 0 0 20px;
1116 1116 padding: 0;
1117 1117 }
1118 1118
1119 1119 #content div.box div.title h5 {
1120 1120 float: left;
1121 1121 border: none;
1122 1122 color: #fff;
1123 1123 text-transform: uppercase;
1124 1124 margin: 0;
1125 1125 padding: 11px 0 11px 10px;
1126 1126 }
1127 1127
1128 1128 #content div.box div.title .link-white{
1129 1129 color: #FFFFFF;
1130 1130 }
1131 1131
1132 1132 #content div.box div.title .link-white.current{
1133 1133 color: #BFE3FF;
1134 1134 }
1135 1135
1136 1136 #content div.box div.title ul.links li {
1137 1137 list-style: none;
1138 1138 float: left;
1139 1139 margin: 0;
1140 1140 padding: 0;
1141 1141 }
1142 1142
1143 1143 #content div.box div.title ul.links li a {
1144 1144 border-left: 1px solid #316293;
1145 1145 color: #FFFFFF;
1146 1146 display: block;
1147 1147 float: left;
1148 1148 font-size: 13px;
1149 1149 font-weight: 700;
1150 1150 height: 1%;
1151 1151 margin: 0;
1152 1152 padding: 11px 22px 12px;
1153 1153 text-decoration: none;
1154 1154 }
1155 1155
1156 1156 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6,
1157 1157 #content div.box div.h1,#content div.box div.h2,#content div.box div.h3,#content div.box div.h4,#content div.box div.h5,#content div.box div.h6
1158 1158
1159 1159 {
1160 1160 clear: both;
1161 1161 overflow: hidden;
1162 1162 border-bottom: 1px solid #DDD;
1163 1163 margin: 10px 20px;
1164 1164 padding: 0 0 15px;
1165 1165 }
1166 1166
1167 1167 #content div.box p {
1168 1168 color: #5f5f5f;
1169 1169 font-size: 12px;
1170 1170 line-height: 150%;
1171 1171 margin: 0 24px 10px;
1172 1172 padding: 0;
1173 1173 }
1174 1174
1175 1175 #content div.box blockquote {
1176 1176 border-left: 4px solid #DDD;
1177 1177 color: #5f5f5f;
1178 1178 font-size: 11px;
1179 1179 line-height: 150%;
1180 1180 margin: 0 34px;
1181 1181 padding: 0 0 0 14px;
1182 1182 }
1183 1183
1184 1184 #content div.box blockquote p {
1185 1185 margin: 10px 0;
1186 1186 padding: 0;
1187 1187 }
1188 1188
1189 1189 #content div.box dl {
1190 1190 margin: 10px 0px;
1191 1191 }
1192 1192
1193 1193 #content div.box dt {
1194 1194 font-size: 12px;
1195 1195 margin: 0;
1196 1196 }
1197 1197
1198 1198 #content div.box dd {
1199 1199 font-size: 12px;
1200 1200 margin: 0;
1201 1201 padding: 8px 0 8px 15px;
1202 1202 }
1203 1203
1204 1204 #content div.box li {
1205 1205 font-size: 12px;
1206 1206 padding: 4px 0;
1207 1207 }
1208 1208
1209 1209 #content div.box ul.disc,#content div.box ul.circle {
1210 1210 margin: 10px 24px 10px 38px;
1211 1211 }
1212 1212
1213 1213 #content div.box ul.square {
1214 1214 margin: 10px 24px 10px 40px;
1215 1215 }
1216 1216
1217 1217 #content div.box img.left {
1218 1218 border: none;
1219 1219 float: left;
1220 1220 margin: 10px 10px 10px 0;
1221 1221 }
1222 1222
1223 1223 #content div.box img.right {
1224 1224 border: none;
1225 1225 float: right;
1226 1226 margin: 10px 0 10px 10px;
1227 1227 }
1228 1228
1229 1229 #content div.box div.messages {
1230 1230 clear: both;
1231 1231 overflow: hidden;
1232 1232 margin: 0 20px;
1233 1233 padding: 0;
1234 1234 }
1235 1235
1236 1236 #content div.box div.message {
1237 1237 clear: both;
1238 1238 overflow: hidden;
1239 1239 margin: 0;
1240 1240 padding: 5px 0;
1241 1241 white-space: pre-wrap;
1242 1242 }
1243 1243 #content div.box div.expand {
1244 1244 width: 110%;
1245 1245 height:14px;
1246 1246 font-size:10px;
1247 1247 text-align:center;
1248 1248 cursor: pointer;
1249 1249 color:#666;
1250 1250
1251 1251 background:-webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1252 1252 background:-webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1253 1253 background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1254 1254 background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1255 1255 background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1256 1256 background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1257 1257
1258 1258 display: none;
1259 1259 }
1260 1260 #content div.box div.expand .expandtext {
1261 1261 background-color: #ffffff;
1262 1262 padding: 2px;
1263 1263 border-radius: 2px;
1264 1264 }
1265 1265
1266 1266 #content div.box div.message a {
1267 1267 font-weight: 400 !important;
1268 1268 }
1269 1269
1270 1270 #content div.box div.message div.image {
1271 1271 float: left;
1272 1272 margin: 9px 0 0 5px;
1273 1273 padding: 6px;
1274 1274 }
1275 1275
1276 1276 #content div.box div.message div.image img {
1277 1277 vertical-align: middle;
1278 1278 margin: 0;
1279 1279 }
1280 1280
1281 1281 #content div.box div.message div.text {
1282 1282 float: left;
1283 1283 margin: 0;
1284 1284 padding: 9px 6px;
1285 1285 }
1286 1286
1287 1287 #content div.box div.message div.dismiss a {
1288 1288 height: 16px;
1289 1289 width: 16px;
1290 1290 display: block;
1291 1291 background: url("../images/icons/cross.png") no-repeat;
1292 1292 margin: 15px 14px 0 0;
1293 1293 padding: 0;
1294 1294 }
1295 1295
1296 1296 #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
1297 1297 {
1298 1298 border: none;
1299 1299 margin: 0;
1300 1300 padding: 0;
1301 1301 }
1302 1302
1303 1303 #content div.box div.message div.text span {
1304 1304 height: 1%;
1305 1305 display: block;
1306 1306 margin: 0;
1307 1307 padding: 5px 0 0;
1308 1308 }
1309 1309
1310 1310 #content div.box div.message-error {
1311 1311 height: 1%;
1312 1312 clear: both;
1313 1313 overflow: hidden;
1314 1314 background: #FBE3E4;
1315 1315 border: 1px solid #FBC2C4;
1316 1316 color: #860006;
1317 1317 }
1318 1318
1319 1319 #content div.box div.message-error h6 {
1320 1320 color: #860006;
1321 1321 }
1322 1322
1323 1323 #content div.box div.message-warning {
1324 1324 height: 1%;
1325 1325 clear: both;
1326 1326 overflow: hidden;
1327 1327 background: #FFF6BF;
1328 1328 border: 1px solid #FFD324;
1329 1329 color: #5f5200;
1330 1330 }
1331 1331
1332 1332 #content div.box div.message-warning h6 {
1333 1333 color: #5f5200;
1334 1334 }
1335 1335
1336 1336 #content div.box div.message-notice {
1337 1337 height: 1%;
1338 1338 clear: both;
1339 1339 overflow: hidden;
1340 1340 background: #8FBDE0;
1341 1341 border: 1px solid #6BACDE;
1342 1342 color: #003863;
1343 1343 }
1344 1344
1345 1345 #content div.box div.message-notice h6 {
1346 1346 color: #003863;
1347 1347 }
1348 1348
1349 1349 #content div.box div.message-success {
1350 1350 height: 1%;
1351 1351 clear: both;
1352 1352 overflow: hidden;
1353 1353 background: #E6EFC2;
1354 1354 border: 1px solid #C6D880;
1355 1355 color: #4e6100;
1356 1356 }
1357 1357
1358 1358 #content div.box div.message-success h6 {
1359 1359 color: #4e6100;
1360 1360 }
1361 1361
1362 1362 #content div.box div.form div.fields div.field {
1363 1363 height: 1%;
1364 1364 border-bottom: 1px solid #DDD;
1365 1365 clear: both;
1366 1366 margin: 0;
1367 1367 padding: 10px 0;
1368 1368 }
1369 1369
1370 1370 #content div.box div.form div.fields div.field-first {
1371 1371 padding: 0 0 10px;
1372 1372 }
1373 1373
1374 1374 #content div.box div.form div.fields div.field-noborder {
1375 1375 border-bottom: 0 !important;
1376 1376 }
1377 1377
1378 1378 #content div.box div.form div.fields div.field span.error-message {
1379 1379 height: 1%;
1380 1380 display: inline-block;
1381 1381 color: red;
1382 1382 margin: 8px 0 0 4px;
1383 1383 padding: 0;
1384 1384 }
1385 1385
1386 1386 #content div.box div.form div.fields div.field span.success {
1387 1387 height: 1%;
1388 1388 display: block;
1389 1389 color: #316309;
1390 1390 margin: 8px 0 0;
1391 1391 padding: 0;
1392 1392 }
1393 1393
1394 1394 #content div.box div.form div.fields div.field div.label {
1395 1395 left: 70px;
1396 1396 width: 155px;
1397 1397 position: absolute;
1398 1398 margin: 0;
1399 1399 padding: 5px 0 0 0px;
1400 1400 }
1401 1401
1402 1402 #content div.box div.form div.fields div.field div.label-summary {
1403 1403 left: 30px;
1404 1404 width: 155px;
1405 1405 position: absolute;
1406 1406 margin: 0;
1407 1407 padding: 0px 0 0 0px;
1408 1408 }
1409 1409
1410 1410 #content div.box-left div.form div.fields div.field div.label,
1411 1411 #content div.box-right div.form div.fields div.field div.label,
1412 1412 #content div.box-left div.form div.fields div.field div.label,
1413 1413 #content div.box-left div.form div.fields div.field div.label-summary,
1414 1414 #content div.box-right div.form div.fields div.field div.label-summary,
1415 1415 #content div.box-left div.form div.fields div.field div.label-summary
1416 1416 {
1417 1417 clear: both;
1418 1418 overflow: hidden;
1419 1419 left: 0;
1420 1420 width: auto;
1421 1421 position: relative;
1422 1422 margin: 0;
1423 1423 padding: 0 0 8px;
1424 1424 }
1425 1425
1426 1426 #content div.box div.form div.fields div.field div.label-select {
1427 1427 padding: 5px 0 0 5px;
1428 1428 }
1429 1429
1430 1430 #content div.box-left div.form div.fields div.field div.label-select,
1431 1431 #content div.box-right div.form div.fields div.field div.label-select
1432 1432 {
1433 1433 padding: 0 0 8px;
1434 1434 }
1435 1435
1436 1436 #content div.box-left div.form div.fields div.field div.label-textarea,
1437 1437 #content div.box-right div.form div.fields div.field div.label-textarea
1438 1438 {
1439 1439 padding: 0 0 8px !important;
1440 1440 }
1441 1441
1442 1442 #content div.box div.form div.fields div.field div.label label,div.label label
1443 1443 {
1444 1444 color: #393939;
1445 1445 font-weight: 700;
1446 1446 }
1447 1447 #content div.box div.form div.fields div.field div.label label,div.label-summary label
1448 1448 {
1449 1449 color: #393939;
1450 1450 font-weight: 700;
1451 1451 }
1452 1452 #content div.box div.form div.fields div.field div.input {
1453 1453 margin: 0 0 0 200px;
1454 1454 }
1455 1455
1456 1456 #content div.box div.form div.fields div.field div.input.summary {
1457 1457 margin: 0 0 0 110px;
1458 1458 }
1459 1459 #content div.box div.form div.fields div.field div.input.summary-short {
1460 1460 margin: 0 0 0 110px;
1461 1461 }
1462 1462 #content div.box div.form div.fields div.field div.file {
1463 1463 margin: 0 0 0 200px;
1464 1464 }
1465 1465
1466 1466 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input
1467 1467 {
1468 1468 margin: 0 0 0 0px;
1469 1469 }
1470 1470
1471 1471 #content div.box div.form div.fields div.field div.input input,
1472 1472 .reviewer_ac input {
1473 1473 background: #FFF;
1474 1474 border-top: 1px solid #b3b3b3;
1475 1475 border-left: 1px solid #b3b3b3;
1476 1476 border-right: 1px solid #eaeaea;
1477 1477 border-bottom: 1px solid #eaeaea;
1478 1478 color: #000;
1479 1479 font-size: 11px;
1480 1480 margin: 0;
1481 1481 padding: 7px 7px 6px;
1482 1482 }
1483 1483
1484 1484 #content div.box div.form div.fields div.field div.input input#clone_url,
1485 1485 #content div.box div.form div.fields div.field div.input input#clone_url_id
1486 1486 {
1487 1487 font-size: 16px;
1488 1488 padding: 2px;
1489 1489 }
1490 1490
1491 1491 #content div.box div.form div.fields div.field div.file input {
1492 1492 background: none repeat scroll 0 0 #FFFFFF;
1493 1493 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1494 1494 border-style: solid;
1495 1495 border-width: 1px;
1496 1496 color: #000000;
1497 1497 font-size: 11px;
1498 1498 margin: 0;
1499 1499 padding: 7px 7px 6px;
1500 1500 }
1501 1501
1502 1502 input.disabled {
1503 1503 background-color: #F5F5F5 !important;
1504 1504 }
1505 1505 #content div.box div.form div.fields div.field div.input input.small {
1506 1506 width: 30%;
1507 1507 }
1508 1508
1509 1509 #content div.box div.form div.fields div.field div.input input.medium {
1510 1510 width: 55%;
1511 1511 }
1512 1512
1513 1513 #content div.box div.form div.fields div.field div.input input.large {
1514 1514 width: 85%;
1515 1515 }
1516 1516
1517 1517 #content div.box div.form div.fields div.field div.input input.date {
1518 1518 width: 177px;
1519 1519 }
1520 1520
1521 1521 #content div.box div.form div.fields div.field div.input input.button {
1522 1522 background: #D4D0C8;
1523 1523 border-top: 1px solid #FFF;
1524 1524 border-left: 1px solid #FFF;
1525 1525 border-right: 1px solid #404040;
1526 1526 border-bottom: 1px solid #404040;
1527 1527 color: #000;
1528 1528 margin: 0;
1529 1529 padding: 4px 8px;
1530 1530 }
1531 1531
1532 1532 #content div.box div.form div.fields div.field div.textarea {
1533 1533 border-top: 1px solid #b3b3b3;
1534 1534 border-left: 1px solid #b3b3b3;
1535 1535 border-right: 1px solid #eaeaea;
1536 1536 border-bottom: 1px solid #eaeaea;
1537 1537 margin: 0 0 0 200px;
1538 1538 padding: 10px;
1539 1539 }
1540 1540
1541 1541 #content div.box div.form div.fields div.field div.textarea-editor {
1542 1542 border: 1px solid #ddd;
1543 1543 padding: 0;
1544 1544 }
1545 1545
1546 1546 #content div.box div.form div.fields div.field div.textarea textarea {
1547 1547 width: 100%;
1548 1548 height: 220px;
1549 1549 overflow: hidden;
1550 1550 background: #FFF;
1551 1551 color: #000;
1552 1552 font-size: 11px;
1553 1553 outline: none;
1554 1554 border-width: 0;
1555 1555 margin: 0;
1556 1556 padding: 0;
1557 1557 }
1558 1558
1559 1559 #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
1560 1560 {
1561 1561 width: 100%;
1562 1562 height: 100px;
1563 1563 }
1564 1564
1565 1565 #content div.box div.form div.fields div.field div.textarea table {
1566 1566 width: 100%;
1567 1567 border: none;
1568 1568 margin: 0;
1569 1569 padding: 0;
1570 1570 }
1571 1571
1572 1572 #content div.box div.form div.fields div.field div.textarea table td {
1573 1573 background: #DDD;
1574 1574 border: none;
1575 1575 padding: 0;
1576 1576 }
1577 1577
1578 1578 #content div.box div.form div.fields div.field div.textarea table td table
1579 1579 {
1580 1580 width: auto;
1581 1581 border: none;
1582 1582 margin: 0;
1583 1583 padding: 0;
1584 1584 }
1585 1585
1586 1586 #content div.box div.form div.fields div.field div.textarea table td table td
1587 1587 {
1588 1588 font-size: 11px;
1589 1589 padding: 5px 5px 5px 0;
1590 1590 }
1591 1591
1592 1592 #content div.box div.form div.fields div.field input[type=text]:focus,
1593 1593 #content div.box div.form div.fields div.field input[type=password]:focus,
1594 1594 #content div.box div.form div.fields div.field input[type=file]:focus,
1595 1595 #content div.box div.form div.fields div.field textarea:focus,
1596 1596 #content div.box div.form div.fields div.field select:focus,
1597 1597 .reviewer_ac input:focus
1598 1598 {
1599 1599 background: #f6f6f6;
1600 1600 border-color: #666;
1601 1601 }
1602 1602
1603 1603 .reviewer_ac {
1604 1604 padding:10px
1605 1605 }
1606 1606
1607 1607 div.form div.fields div.field div.button {
1608 1608 margin: 0;
1609 1609 padding: 0 0 0 8px;
1610 1610 }
1611 1611 #content div.box table.noborder {
1612 1612 border: 1px solid transparent;
1613 1613 }
1614 1614
1615 1615 #content div.box table {
1616 1616 width: 100%;
1617 1617 border-collapse: separate;
1618 1618 margin: 0;
1619 1619 padding: 0;
1620 1620 border: 1px solid #eee;
1621 1621 -webkit-border-radius: 4px;
1622 1622 -moz-border-radius: 4px;
1623 1623 border-radius: 4px;
1624 1624 }
1625 1625
1626 1626 #content div.box table th {
1627 1627 background: #eee;
1628 1628 border-bottom: 1px solid #ddd;
1629 1629 padding: 5px 0px 5px 5px;
1630 text-align: left;
1630 1631 }
1631 1632
1632 1633 #content div.box table th.left {
1633 1634 text-align: left;
1634 1635 }
1635 1636
1636 1637 #content div.box table th.right {
1637 1638 text-align: right;
1638 1639 }
1639 1640
1640 1641 #content div.box table th.center {
1641 1642 text-align: center;
1642 1643 }
1643 1644
1644 1645 #content div.box table th.selected {
1645 1646 vertical-align: middle;
1646 1647 padding: 0;
1647 1648 }
1648 1649
1649 1650 #content div.box table td {
1650 1651 background: #fff;
1651 1652 border-bottom: 1px solid #cdcdcd;
1652 1653 vertical-align: middle;
1653 1654 padding: 5px;
1654 1655 }
1655 1656
1656 1657 #content div.box table tr.selected td {
1657 1658 background: #FFC;
1658 1659 }
1659 1660
1660 1661 #content div.box table td.selected {
1661 1662 width: 3%;
1662 1663 text-align: center;
1663 1664 vertical-align: middle;
1664 1665 padding: 0;
1665 1666 }
1666 1667
1667 1668 #content div.box table td.action {
1668 1669 width: 45%;
1669 1670 text-align: left;
1670 1671 }
1671 1672
1672 1673 #content div.box table td.date {
1673 1674 width: 33%;
1674 1675 text-align: center;
1675 1676 }
1676 1677
1677 1678 #content div.box div.action {
1678 1679 float: right;
1679 1680 background: #FFF;
1680 1681 text-align: right;
1681 1682 margin: 10px 0 0;
1682 1683 padding: 0;
1683 1684 }
1684 1685
1685 1686 #content div.box div.action select {
1686 1687 font-size: 11px;
1687 1688 margin: 0;
1688 1689 }
1689 1690
1690 1691 #content div.box div.action .ui-selectmenu {
1691 1692 margin: 0;
1692 1693 padding: 0;
1693 1694 }
1694 1695
1695 1696 #content div.box div.pagination {
1696 1697 height: 1%;
1697 1698 clear: both;
1698 1699 overflow: hidden;
1699 1700 margin: 10px 0 0;
1700 1701 padding: 0;
1701 1702 }
1702 1703
1703 1704 #content div.box div.pagination ul.pager {
1704 1705 float: right;
1705 1706 text-align: right;
1706 1707 margin: 0;
1707 1708 padding: 0;
1708 1709 }
1709 1710
1710 1711 #content div.box div.pagination ul.pager li {
1711 1712 height: 1%;
1712 1713 float: left;
1713 1714 list-style: none;
1714 1715 background: #ebebeb url("../images/pager.png") repeat-x;
1715 1716 border-top: 1px solid #dedede;
1716 1717 border-left: 1px solid #cfcfcf;
1717 1718 border-right: 1px solid #c4c4c4;
1718 1719 border-bottom: 1px solid #c4c4c4;
1719 1720 color: #4A4A4A;
1720 1721 font-weight: 700;
1721 1722 margin: 0 0 0 4px;
1722 1723 padding: 0;
1723 1724 }
1724 1725
1725 1726 #content div.box div.pagination ul.pager li.separator {
1726 1727 padding: 6px;
1727 1728 }
1728 1729
1729 1730 #content div.box div.pagination ul.pager li.current {
1730 1731 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1731 1732 border-top: 1px solid #ccc;
1732 1733 border-left: 1px solid #bebebe;
1733 1734 border-right: 1px solid #b1b1b1;
1734 1735 border-bottom: 1px solid #afafaf;
1735 1736 color: #515151;
1736 1737 padding: 6px;
1737 1738 }
1738 1739
1739 1740 #content div.box div.pagination ul.pager li a {
1740 1741 height: 1%;
1741 1742 display: block;
1742 1743 float: left;
1743 1744 color: #515151;
1744 1745 text-decoration: none;
1745 1746 margin: 0;
1746 1747 padding: 6px;
1747 1748 }
1748 1749
1749 1750 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active
1750 1751 {
1751 1752 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1752 1753 border-top: 1px solid #ccc;
1753 1754 border-left: 1px solid #bebebe;
1754 1755 border-right: 1px solid #b1b1b1;
1755 1756 border-bottom: 1px solid #afafaf;
1756 1757 margin: -1px;
1757 1758 }
1758 1759
1759 1760 #content div.box div.pagination-wh {
1760 1761 height: 1%;
1761 1762 clear: both;
1762 1763 overflow: hidden;
1763 1764 text-align: right;
1764 1765 margin: 10px 0 0;
1765 1766 padding: 0;
1766 1767 }
1767 1768
1768 1769 #content div.box div.pagination-right {
1769 1770 float: right;
1770 1771 }
1771 1772
1772 1773 #content div.box div.pagination-wh a,
1773 1774 #content div.box div.pagination-wh span.pager_dotdot,
1774 1775 #content div.box div.pagination-wh span.yui-pg-previous,
1775 1776 #content div.box div.pagination-wh span.yui-pg-last,
1776 1777 #content div.box div.pagination-wh span.yui-pg-next,
1777 1778 #content div.box div.pagination-wh span.yui-pg-first
1778 1779 {
1779 1780 height: 1%;
1780 1781 float: left;
1781 1782 background: #ebebeb url("../images/pager.png") repeat-x;
1782 1783 border-top: 1px solid #dedede;
1783 1784 border-left: 1px solid #cfcfcf;
1784 1785 border-right: 1px solid #c4c4c4;
1785 1786 border-bottom: 1px solid #c4c4c4;
1786 1787 color: #4A4A4A;
1787 1788 font-weight: 700;
1788 1789 margin: 0 0 0 4px;
1789 1790 padding: 6px;
1790 1791 }
1791 1792
1792 1793 #content div.box div.pagination-wh span.pager_curpage {
1793 1794 height: 1%;
1794 1795 float: left;
1795 1796 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1796 1797 border-top: 1px solid #ccc;
1797 1798 border-left: 1px solid #bebebe;
1798 1799 border-right: 1px solid #b1b1b1;
1799 1800 border-bottom: 1px solid #afafaf;
1800 1801 color: #515151;
1801 1802 font-weight: 700;
1802 1803 margin: 0 0 0 4px;
1803 1804 padding: 6px;
1804 1805 }
1805 1806
1806 1807 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active
1807 1808 {
1808 1809 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1809 1810 border-top: 1px solid #ccc;
1810 1811 border-left: 1px solid #bebebe;
1811 1812 border-right: 1px solid #b1b1b1;
1812 1813 border-bottom: 1px solid #afafaf;
1813 1814 text-decoration: none;
1814 1815 }
1815 1816
1816 1817 #content div.box div.traffic div.legend {
1817 1818 clear: both;
1818 1819 overflow: hidden;
1819 1820 border-bottom: 1px solid #ddd;
1820 1821 margin: 0 0 10px;
1821 1822 padding: 0 0 10px;
1822 1823 }
1823 1824
1824 1825 #content div.box div.traffic div.legend h6 {
1825 1826 float: left;
1826 1827 border: none;
1827 1828 margin: 0;
1828 1829 padding: 0;
1829 1830 }
1830 1831
1831 1832 #content div.box div.traffic div.legend li {
1832 1833 list-style: none;
1833 1834 float: left;
1834 1835 font-size: 11px;
1835 1836 margin: 0;
1836 1837 padding: 0 8px 0 4px;
1837 1838 }
1838 1839
1839 1840 #content div.box div.traffic div.legend li.visits {
1840 1841 border-left: 12px solid #edc240;
1841 1842 }
1842 1843
1843 1844 #content div.box div.traffic div.legend li.pageviews {
1844 1845 border-left: 12px solid #afd8f8;
1845 1846 }
1846 1847
1847 1848 #content div.box div.traffic table {
1848 1849 width: auto;
1849 1850 }
1850 1851
1851 1852 #content div.box div.traffic table td {
1852 1853 background: transparent;
1853 1854 border: none;
1854 1855 padding: 2px 3px 3px;
1855 1856 }
1856 1857
1857 1858 #content div.box div.traffic table td.legendLabel {
1858 1859 padding: 0 3px 2px;
1859 1860 }
1860 1861
1861 1862 #summary {
1862 1863
1863 1864 }
1864 1865
1865 1866 #summary .metatag {
1866 1867 display: inline-block;
1867 1868 padding: 3px 5px;
1868 1869 margin-bottom: 3px;
1869 1870 margin-right: 1px;
1870 1871 border-radius: 5px;
1871 1872 }
1872 1873
1873 1874 #content div.box #summary p {
1874 1875 margin-bottom: -5px;
1875 1876 width: 600px;
1876 1877 white-space: pre-wrap;
1877 1878 }
1878 1879
1879 1880 #content div.box #summary p:last-child {
1880 1881 margin-bottom: 9px;
1881 1882 }
1882 1883
1883 1884 #content div.box #summary p:first-of-type {
1884 1885 margin-top: 9px;
1885 1886 }
1886 1887
1887 1888 .metatag {
1888 1889 display: inline-block;
1889 1890 margin-right: 1px;
1890 1891 -webkit-border-radius: 4px 4px 4px 4px;
1891 1892 -khtml-border-radius: 4px 4px 4px 4px;
1892 1893 -moz-border-radius: 4px 4px 4px 4px;
1893 1894 border-radius: 4px 4px 4px 4px;
1894 1895
1895 1896 border: solid 1px #9CF;
1896 1897 padding: 2px 3px 2px 3px !important;
1897 1898 background-color: #DEF;
1898 1899 }
1899 1900
1900 1901 .metatag[tag="dead"] {
1901 1902 background-color: #E44;
1902 1903 }
1903 1904
1904 1905 .metatag[tag="stale"] {
1905 1906 background-color: #EA4;
1906 1907 }
1907 1908
1908 1909 .metatag[tag="featured"] {
1909 1910 background-color: #AEA;
1910 1911 }
1911 1912
1912 1913 .metatag[tag="requires"] {
1913 1914 background-color: #9CF;
1914 1915 }
1915 1916
1916 1917 .metatag[tag="recommends"] {
1917 1918 background-color: #BDF;
1918 1919 }
1919 1920
1920 1921 .metatag[tag="lang"] {
1921 1922 background-color: #FAF474;
1922 1923 }
1923 1924
1924 1925 .metatag[tag="license"] {
1925 1926 border: solid 1px #9CF;
1926 1927 background-color: #DEF;
1927 1928 target-new: tab !important;
1928 1929 }
1929 1930 .metatag[tag="see"] {
1930 1931 border: solid 1px #CBD;
1931 1932 background-color: #EDF;
1932 1933 }
1933 1934
1934 1935 a.metatag[tag="license"]:hover {
1935 1936 background-color: #003367;
1936 1937 color: #FFF;
1937 1938 text-decoration: none;
1938 1939 }
1939 1940
1940 1941 #summary .desc {
1941 1942 white-space: pre;
1942 1943 width: 100%;
1943 1944 }
1944 1945
1945 1946 #summary .repo_name {
1946 1947 font-size: 1.6em;
1947 1948 font-weight: bold;
1948 1949 vertical-align: baseline;
1949 1950 clear: right
1950 1951 }
1951 1952
1952 1953 #footer {
1953 1954 clear: both;
1954 1955 overflow: hidden;
1955 1956 text-align: right;
1956 1957 margin: 0;
1957 1958 padding: 0 10px 4px;
1958 1959 margin: -10px 0 0;
1959 1960 }
1960 1961
1961 1962 #footer div#footer-inner {
1962 1963 background-color: #003B76;
1963 1964 background-repeat : repeat-x;
1964 1965 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1965 1966 background-image : -moz-linear-gradient(top, #003b76, #00376e);
1966 1967 background-image : -ms-linear-gradient( top, #003b76, #00376e);
1967 1968 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1968 1969 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
1969 1970 background-image : -o-linear-gradient( top, #003b76, #00376e));
1970 1971 background-image : linear-gradient( top, #003b76, #00376e);
1971 1972 filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1972 1973 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1973 1974 -webkit-border-radius: 4px 4px 4px 4px;
1974 1975 -khtml-border-radius: 4px 4px 4px 4px;
1975 1976 -moz-border-radius: 4px 4px 4px 4px;
1976 1977 border-radius: 4px 4px 4px 4px;
1977 1978 }
1978 1979
1979 1980 #footer div#footer-inner p {
1980 1981 padding: 15px 25px 15px 0;
1981 1982 color: #FFF;
1982 1983 font-weight: 700;
1983 1984 }
1984 1985
1985 1986 #footer div#footer-inner .footer-link {
1986 1987 float: left;
1987 1988 padding-left: 10px;
1988 1989 }
1989 1990
1990 1991 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a
1991 1992 {
1992 1993 color: #FFF;
1993 1994 }
1994 1995
1995 1996 #login div.title {
1996 1997 width: 420px;
1997 1998 clear: both;
1998 1999 overflow: hidden;
1999 2000 position: relative;
2000 2001 background-color: #003B76;
2001 2002 background-repeat : repeat-x;
2002 2003 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
2003 2004 background-image : -moz-linear-gradient( top, #003b76, #00376e);
2004 2005 background-image : -ms-linear-gradient( top, #003b76, #00376e);
2005 2006 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
2006 2007 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
2007 2008 background-image : -o-linear-gradient( top, #003b76, #00376e));
2008 2009 background-image : linear-gradient( top, #003b76, #00376e);
2009 2010 filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
2010 2011 margin: 0 auto;
2011 2012 padding: 0;
2012 2013 }
2013 2014
2014 2015 #login div.inner {
2015 2016 width: 380px;
2016 2017 background: #FFF url("../images/login.png") no-repeat top left;
2017 2018 border-top: none;
2018 2019 border-bottom: none;
2019 2020 margin: 0 auto;
2020 2021 padding: 20px;
2021 2022 }
2022 2023
2023 2024 #login div.form div.fields div.field div.label {
2024 2025 width: 173px;
2025 2026 float: left;
2026 2027 text-align: right;
2027 2028 margin: 2px 10px 0 0;
2028 2029 padding: 5px 0 0 5px;
2029 2030 }
2030 2031
2031 2032 #login div.form div.fields div.field div.input input {
2032 2033 width: 176px;
2033 2034 background: #FFF;
2034 2035 border-top: 1px solid #b3b3b3;
2035 2036 border-left: 1px solid #b3b3b3;
2036 2037 border-right: 1px solid #eaeaea;
2037 2038 border-bottom: 1px solid #eaeaea;
2038 2039 color: #000;
2039 2040 font-size: 11px;
2040 2041 margin: 0;
2041 2042 padding: 7px 7px 6px;
2042 2043 }
2043 2044
2044 2045 #login div.form div.fields div.buttons {
2045 2046 clear: both;
2046 2047 overflow: hidden;
2047 2048 border-top: 1px solid #DDD;
2048 2049 text-align: right;
2049 2050 margin: 0;
2050 2051 padding: 10px 0 0;
2051 2052 }
2052 2053
2053 2054 #login div.form div.links {
2054 2055 clear: both;
2055 2056 overflow: hidden;
2056 2057 margin: 10px 0 0;
2057 2058 padding: 0 0 2px;
2058 2059 }
2059 2060
2060 2061 .user-menu{
2061 2062 margin: 0px !important;
2062 2063 float: left;
2063 2064 }
2064 2065
2065 2066 .user-menu .container{
2066 2067 padding:0px 4px 0px 4px;
2067 2068 margin: 0px 0px 0px 0px;
2068 2069 }
2069 2070
2070 2071 .user-menu .gravatar{
2071 2072 margin: 0px 0px 0px 0px;
2072 2073 cursor: pointer;
2073 2074 }
2074 2075 .user-menu .gravatar.enabled{
2075 2076 background-color: #FDF784 !important;
2076 2077 }
2077 2078 .user-menu .gravatar:hover{
2078 2079 background-color: #FDF784 !important;
2079 2080 }
2080 2081 #quick_login{
2081 2082 min-height: 80px;
2082 2083 margin: 37px 0 0 -251px;
2083 2084 padding: 4px;
2084 2085 position: absolute;
2085 2086 width: 278px;
2086 2087 background-color: #003B76;
2087 2088 background-repeat: repeat-x;
2088 2089 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2089 2090 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2090 2091 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2091 2092 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2092 2093 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2093 2094 background-image: -o-linear-gradient(top, #003b76, #00376e);
2094 2095 background-image: linear-gradient(top, #003b76, #00376e);
2095 2096 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
2096 2097
2097 2098 z-index: 999;
2098 2099 -webkit-border-radius: 0px 0px 4px 4px;
2099 2100 -khtml-border-radius: 0px 0px 4px 4px;
2100 2101 -moz-border-radius: 0px 0px 4px 4px;
2101 2102 border-radius: 0px 0px 4px 4px;
2102 2103 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2103 2104 }
2104 2105 #quick_login h4{
2105 2106 color: #fff;
2106 2107 padding: 5px 0px 5px 14px;
2107 2108 }
2108 2109
2109 2110 #quick_login .password_forgoten {
2110 2111 padding-right: 10px;
2111 2112 padding-top: 0px;
2112 2113 text-align: left;
2113 2114 }
2114 2115
2115 2116 #quick_login .password_forgoten a {
2116 2117 font-size: 10px;
2117 2118 color: #fff;
2118 2119 }
2119 2120
2120 2121 #quick_login .register {
2121 2122 padding-right: 10px;
2122 2123 padding-top: 5px;
2123 2124 text-align: left;
2124 2125 }
2125 2126
2126 2127 #quick_login .register a {
2127 2128 font-size: 10px;
2128 2129 color: #fff;
2129 2130 }
2130 2131
2131 2132 #quick_login .submit {
2132 2133 margin: -20px 0 0 0px;
2133 2134 position: absolute;
2134 2135 right: 15px;
2135 2136 }
2136 2137
2137 2138 #quick_login .links_left{
2138 2139 float: left;
2139 2140 }
2140 2141 #quick_login .links_right{
2141 2142 float: right;
2142 2143 }
2143 2144 #quick_login .full_name{
2144 2145 color: #FFFFFF;
2145 2146 font-weight: bold;
2146 2147 padding: 3px;
2147 2148 }
2148 2149 #quick_login .big_gravatar{
2149 2150 padding:4px 0px 0px 6px;
2150 2151 }
2151 2152 #quick_login .inbox{
2152 2153 padding:4px 0px 0px 6px;
2153 2154 color: #FFFFFF;
2154 2155 font-weight: bold;
2155 2156 }
2156 2157 #quick_login .inbox a{
2157 2158 color: #FFFFFF;
2158 2159 }
2159 2160 #quick_login .email,#quick_login .email a{
2160 2161 color: #FFFFFF;
2161 2162 padding: 3px;
2162 2163
2163 2164 }
2164 2165 #quick_login .links .logout{
2165 2166
2166 2167 }
2167 2168
2168 2169 #quick_login div.form div.fields {
2169 2170 padding-top: 2px;
2170 2171 padding-left: 10px;
2171 2172 }
2172 2173
2173 2174 #quick_login div.form div.fields div.field {
2174 2175 padding: 5px;
2175 2176 }
2176 2177
2177 2178 #quick_login div.form div.fields div.field div.label label {
2178 2179 color: #fff;
2179 2180 padding-bottom: 3px;
2180 2181 }
2181 2182
2182 2183 #quick_login div.form div.fields div.field div.input input {
2183 2184 width: 236px;
2184 2185 background: #FFF;
2185 2186 border-top: 1px solid #b3b3b3;
2186 2187 border-left: 1px solid #b3b3b3;
2187 2188 border-right: 1px solid #eaeaea;
2188 2189 border-bottom: 1px solid #eaeaea;
2189 2190 color: #000;
2190 2191 font-size: 11px;
2191 2192 margin: 0;
2192 2193 padding: 5px 7px 4px;
2193 2194 }
2194 2195
2195 2196 #quick_login div.form div.fields div.buttons {
2196 2197 clear: both;
2197 2198 overflow: hidden;
2198 2199 text-align: right;
2199 2200 margin: 0;
2200 2201 padding: 5px 14px 0px 5px;
2201 2202 }
2202 2203
2203 2204 #quick_login div.form div.links {
2204 2205 clear: both;
2205 2206 overflow: hidden;
2206 2207 margin: 10px 0 0;
2207 2208 padding: 0 0 2px;
2208 2209 }
2209 2210
2210 2211 #quick_login ol.links{
2211 2212 display: block;
2212 2213 font-weight: bold;
2213 2214 list-style: none outside none;
2214 2215 text-align: right;
2215 2216 }
2216 2217 #quick_login ol.links li{
2217 2218 line-height: 27px;
2218 2219 margin: 0;
2219 2220 padding: 0;
2220 2221 color: #fff;
2221 2222 display: block;
2222 2223 float:none !important;
2223 2224 }
2224 2225
2225 2226 #quick_login ol.links li a{
2226 2227 color: #fff;
2227 2228 display: block;
2228 2229 padding: 2px;
2229 2230 }
2230 2231 #quick_login ol.links li a:HOVER{
2231 2232 background-color: inherit !important;
2232 2233 }
2233 2234
2234 2235 #register div.title {
2235 2236 clear: both;
2236 2237 overflow: hidden;
2237 2238 position: relative;
2238 2239 background-color: #003B76;
2239 2240 background-repeat: repeat-x;
2240 2241 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2241 2242 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2242 2243 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2243 2244 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2244 2245 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2245 2246 background-image: -o-linear-gradient(top, #003b76, #00376e);
2246 2247 background-image: linear-gradient(top, #003b76, #00376e);
2247 2248 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2248 2249 endColorstr='#00376e', GradientType=0 );
2249 2250 margin: 0 auto;
2250 2251 padding: 0;
2251 2252 }
2252 2253
2253 2254 #register div.inner {
2254 2255 background: #FFF;
2255 2256 border-top: none;
2256 2257 border-bottom: none;
2257 2258 margin: 0 auto;
2258 2259 padding: 20px;
2259 2260 }
2260 2261
2261 2262 #register div.form div.fields div.field div.label {
2262 2263 width: 135px;
2263 2264 float: left;
2264 2265 text-align: right;
2265 2266 margin: 2px 10px 0 0;
2266 2267 padding: 5px 0 0 5px;
2267 2268 }
2268 2269
2269 2270 #register div.form div.fields div.field div.input input {
2270 2271 width: 300px;
2271 2272 background: #FFF;
2272 2273 border-top: 1px solid #b3b3b3;
2273 2274 border-left: 1px solid #b3b3b3;
2274 2275 border-right: 1px solid #eaeaea;
2275 2276 border-bottom: 1px solid #eaeaea;
2276 2277 color: #000;
2277 2278 font-size: 11px;
2278 2279 margin: 0;
2279 2280 padding: 7px 7px 6px;
2280 2281 }
2281 2282
2282 2283 #register div.form div.fields div.buttons {
2283 2284 clear: both;
2284 2285 overflow: hidden;
2285 2286 border-top: 1px solid #DDD;
2286 2287 text-align: left;
2287 2288 margin: 0;
2288 2289 padding: 10px 0 0 150px;
2289 2290 }
2290 2291
2291 2292 #register div.form div.activation_msg {
2292 2293 padding-top: 4px;
2293 2294 padding-bottom: 4px;
2294 2295 }
2295 2296
2296 2297 #journal .journal_day {
2297 2298 font-size: 20px;
2298 2299 padding: 10px 0px;
2299 2300 border-bottom: 2px solid #DDD;
2300 2301 margin-left: 10px;
2301 2302 margin-right: 10px;
2302 2303 }
2303 2304
2304 2305 #journal .journal_container {
2305 2306 padding: 5px;
2306 2307 clear: both;
2307 2308 margin: 0px 5px 0px 10px;
2308 2309 }
2309 2310
2310 2311 #journal .journal_action_container {
2311 2312 padding-left: 38px;
2312 2313 }
2313 2314
2314 2315 #journal .journal_user {
2315 2316 color: #747474;
2316 2317 font-size: 14px;
2317 2318 font-weight: bold;
2318 2319 height: 30px;
2319 2320 }
2320 2321
2321 2322 #journal .journal_icon {
2322 2323 clear: both;
2323 2324 float: left;
2324 2325 padding-right: 4px;
2325 2326 padding-top: 3px;
2326 2327 }
2327 2328
2328 2329 #journal .journal_action {
2329 2330 padding-top: 4px;
2330 2331 min-height: 2px;
2331 2332 float: left
2332 2333 }
2333 2334
2334 2335 #journal .journal_action_params {
2335 2336 clear: left;
2336 2337 padding-left: 22px;
2337 2338 }
2338 2339
2339 2340 #journal .journal_repo {
2340 2341 float: left;
2341 2342 margin-left: 6px;
2342 2343 padding-top: 3px;
2343 2344 }
2344 2345
2345 2346 #journal .date {
2346 2347 clear: both;
2347 2348 color: #777777;
2348 2349 font-size: 11px;
2349 2350 padding-left: 22px;
2350 2351 }
2351 2352
2352 2353 #journal .journal_repo .journal_repo_name {
2353 2354 font-weight: bold;
2354 2355 font-size: 1.1em;
2355 2356 }
2356 2357
2357 2358 #journal .compare_view {
2358 2359 padding: 5px 0px 5px 0px;
2359 2360 width: 95px;
2360 2361 }
2361 2362
2362 2363 .journal_highlight {
2363 2364 font-weight: bold;
2364 2365 padding: 0 2px;
2365 2366 vertical-align: bottom;
2366 2367 }
2367 2368
2368 2369 .trending_language_tbl,.trending_language_tbl td {
2369 2370 border: 0 !important;
2370 2371 margin: 0 !important;
2371 2372 padding: 0 !important;
2372 2373 }
2373 2374
2374 2375 .trending_language_tbl,.trending_language_tbl tr {
2375 2376 border-spacing: 1px;
2376 2377 }
2377 2378
2378 2379 .trending_language {
2379 2380 background-color: #003367;
2380 2381 color: #FFF;
2381 2382 display: block;
2382 2383 min-width: 20px;
2383 2384 text-decoration: none;
2384 2385 height: 12px;
2385 2386 margin-bottom: 0px;
2386 2387 margin-left: 5px;
2387 2388 white-space: pre;
2388 2389 padding: 3px;
2389 2390 }
2390 2391
2391 2392 h3.files_location {
2392 2393 font-size: 1.8em;
2393 2394 font-weight: 700;
2394 2395 border-bottom: none !important;
2395 2396 margin: 10px 0 !important;
2396 2397 }
2397 2398
2398 2399 #files_data dl dt {
2399 2400 float: left;
2400 2401 width: 60px;
2401 2402 margin: 0 !important;
2402 2403 padding: 5px;
2403 2404 }
2404 2405
2405 2406 #files_data dl dd {
2406 2407 margin: 0 !important;
2407 2408 padding: 5px !important;
2408 2409 }
2409 2410
2410 2411 .file_history{
2411 2412 padding-top:10px;
2412 2413 font-size:16px;
2413 2414 }
2414 2415 .file_author{
2415 2416 float: left;
2416 2417 }
2417 2418
2418 2419 .file_author .item{
2419 2420 float:left;
2420 2421 padding:5px;
2421 2422 color: #888;
2422 2423 }
2423 2424
2424 2425 .tablerow0 {
2425 2426 background-color: #F8F8F8;
2426 2427 }
2427 2428
2428 2429 .tablerow1 {
2429 2430 background-color: #FFFFFF;
2430 2431 }
2431 2432
2432 2433 .changeset_id {
2433 2434 font-family: monospace;
2434 2435 color: #666666;
2435 2436 }
2436 2437
2437 2438 .changeset_hash {
2438 2439 color: #000000;
2439 2440 }
2440 2441
2441 2442 #changeset_content {
2442 2443 border-left: 1px solid #CCC;
2443 2444 border-right: 1px solid #CCC;
2444 2445 border-bottom: 1px solid #CCC;
2445 2446 padding: 5px;
2446 2447 }
2447 2448
2448 2449 #changeset_compare_view_content {
2449 2450 border: 1px solid #CCC;
2450 2451 padding: 5px;
2451 2452 }
2452 2453
2453 2454 #changeset_content .container {
2454 2455 min-height: 100px;
2455 2456 font-size: 1.2em;
2456 2457 overflow: hidden;
2457 2458 }
2458 2459
2459 2460 #changeset_compare_view_content .compare_view_commits {
2460 2461 width: auto !important;
2461 2462 }
2462 2463
2463 2464 #changeset_compare_view_content .compare_view_commits td {
2464 2465 padding: 0px 0px 0px 12px !important;
2465 2466 }
2466 2467
2467 2468 #changeset_content .container .right {
2468 2469 float: right;
2469 2470 width: 20%;
2470 2471 text-align: right;
2471 2472 }
2472 2473
2473 2474 #changeset_content .container .left .message {
2474 2475 white-space: pre-wrap;
2475 2476 }
2476 2477 #changeset_content .container .left .message a:hover {
2477 2478 text-decoration: none;
2478 2479 }
2479 2480 .cs_files .cur_cs {
2480 2481 margin: 10px 2px;
2481 2482 font-weight: bold;
2482 2483 }
2483 2484
2484 2485 .cs_files .node {
2485 2486 float: left;
2486 2487 }
2487 2488
2488 2489 .cs_files .changes {
2489 2490 float: right;
2490 2491 color:#003367;
2491 2492
2492 2493 }
2493 2494
2494 2495 .cs_files .changes .added {
2495 2496 background-color: #BBFFBB;
2496 2497 float: left;
2497 2498 text-align: center;
2498 2499 font-size: 9px;
2499 2500 padding: 2px 0px 2px 0px;
2500 2501 }
2501 2502
2502 2503 .cs_files .changes .deleted {
2503 2504 background-color: #FF8888;
2504 2505 float: left;
2505 2506 text-align: center;
2506 2507 font-size: 9px;
2507 2508 padding: 2px 0px 2px 0px;
2508 2509 }
2509 2510 /*new binary*/
2510 2511 .cs_files .changes .bin1 {
2511 2512 background-color: #BBFFBB;
2512 2513 float: left;
2513 2514 text-align: center;
2514 2515 font-size: 9px;
2515 2516 padding: 2px 0px 2px 0px;
2516 2517 }
2517 2518
2518 2519 /*deleted binary*/
2519 2520 .cs_files .changes .bin2 {
2520 2521 background-color: #FF8888;
2521 2522 float: left;
2522 2523 text-align: center;
2523 2524 font-size: 9px;
2524 2525 padding: 2px 0px 2px 0px;
2525 2526 }
2526 2527
2527 2528 /*mod binary*/
2528 2529 .cs_files .changes .bin3 {
2529 2530 background-color: #DDDDDD;
2530 2531 float: left;
2531 2532 text-align: center;
2532 2533 font-size: 9px;
2533 2534 padding: 2px 0px 2px 0px;
2534 2535 }
2535 2536
2536 2537 /*rename file*/
2537 2538 .cs_files .changes .bin4 {
2538 2539 background-color: #6D99FF;
2539 2540 float: left;
2540 2541 text-align: center;
2541 2542 font-size: 9px;
2542 2543 padding: 2px 0px 2px 0px;
2543 2544 }
2544 2545
2545 2546
2546 2547 .cs_files .cs_added,.cs_files .cs_A {
2547 2548 background: url("../images/icons/page_white_add.png") no-repeat scroll
2548 2549 3px;
2549 2550 height: 16px;
2550 2551 padding-left: 20px;
2551 2552 margin-top: 7px;
2552 2553 text-align: left;
2553 2554 }
2554 2555
2555 2556 .cs_files .cs_changed,.cs_files .cs_M {
2556 2557 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2557 2558 3px;
2558 2559 height: 16px;
2559 2560 padding-left: 20px;
2560 2561 margin-top: 7px;
2561 2562 text-align: left;
2562 2563 }
2563 2564
2564 2565 .cs_files .cs_removed,.cs_files .cs_D {
2565 2566 background: url("../images/icons/page_white_delete.png") no-repeat
2566 2567 scroll 3px;
2567 2568 height: 16px;
2568 2569 padding-left: 20px;
2569 2570 margin-top: 7px;
2570 2571 text-align: left;
2571 2572 }
2572 2573
2573 2574 #graph {
2574 2575 overflow: hidden;
2575 2576 }
2576 2577
2577 2578 #graph_nodes {
2578 2579 float: left;
2579 2580 margin-right: 0px;
2580 2581 margin-top: 0px;
2581 2582 }
2582 2583
2583 2584 #graph_content {
2584 2585 width: 80%;
2585 2586 float: left;
2586 2587 }
2587 2588
2588 2589 #graph_content .container_header {
2589 2590 border-bottom: 1px solid #DDD;
2590 2591 padding: 10px;
2591 2592 height: 25px;
2592 2593 }
2593 2594
2594 2595 #graph_content #rev_range_container {
2595 2596 float: left;
2596 2597 margin: 0px 0px 0px 3px;
2597 2598 }
2598 2599
2599 2600 #graph_content #rev_range_clear {
2600 2601 float: left;
2601 2602 margin: 0px 0px 0px 3px;
2602 2603 }
2603 2604
2604 2605 #graph_content .container {
2605 2606 border-bottom: 1px solid #DDD;
2606 2607 height: 56px;
2607 2608 overflow: hidden;
2608 2609 }
2609 2610
2610 2611 #graph_content .container .right {
2611 2612 float: right;
2612 2613 width: 23%;
2613 2614 text-align: right;
2614 2615 }
2615 2616
2616 2617 #graph_content .container .left {
2617 2618 float: left;
2618 2619 width: 25%;
2619 2620 padding-left: 5px;
2620 2621 }
2621 2622
2622 2623 #graph_content .container .mid {
2623 2624 float: left;
2624 2625 width: 49%;
2625 2626 }
2626 2627
2627 2628
2628 2629 #graph_content .container .left .date {
2629 2630 color: #666;
2630 2631 padding-left: 22px;
2631 2632 font-size: 10px;
2632 2633 }
2633 2634
2634 2635 #graph_content .container .left .author {
2635 2636 height: 22px;
2636 2637 }
2637 2638
2638 2639 #graph_content .container .left .author .user {
2639 2640 color: #444444;
2640 2641 float: left;
2641 2642 margin-left: -4px;
2642 2643 margin-top: 4px;
2643 2644 }
2644 2645
2645 2646 #graph_content .container .mid .message {
2646 2647 white-space: pre-wrap;
2647 2648 }
2648 2649
2649 2650 #graph_content .container .mid .message a:hover{
2650 2651 text-decoration: none;
2651 2652 }
2652 2653 #content #graph_content .message .revision-link,
2653 2654 #changeset_content .container .message .revision-link
2654 2655 {
2655 2656 color:#3F6F9F;
2656 2657 font-weight: bold !important;
2657 2658 }
2658 2659
2659 2660 #content #graph_content .message .issue-tracker-link,
2660 2661 #changeset_content .container .message .issue-tracker-link{
2661 2662 color:#3F6F9F;
2662 2663 font-weight: bold !important;
2663 2664 }
2664 2665
2665 2666 .changeset-status-container{
2666 2667 padding-right: 5px;
2667 2668 margin-top:1px;
2668 2669 float:right;
2669 2670 height:14px;
2670 2671 }
2671 2672 .code-header .changeset-status-container{
2672 2673 float:left;
2673 2674 padding:2px 0px 0px 2px;
2674 2675 }
2675 2676 .changeset-status-container .changeset-status-lbl{
2676 2677 color: rgb(136, 136, 136);
2677 2678 float: left;
2678 2679 padding: 3px 4px 0px 0px
2679 2680 }
2680 2681 .code-header .changeset-status-container .changeset-status-lbl{
2681 2682 float: left;
2682 2683 padding: 0px 4px 0px 0px;
2683 2684 }
2684 2685 .changeset-status-container .changeset-status-ico{
2685 2686 float: left;
2686 2687 }
2687 2688 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico{
2688 2689 float: left;
2689 2690 }
2690 2691 .right .comments-container{
2691 2692 padding-right: 5px;
2692 2693 margin-top:1px;
2693 2694 float:right;
2694 2695 height:14px;
2695 2696 }
2696 2697
2697 2698 .right .comments-cnt{
2698 2699 float: left;
2699 2700 color: rgb(136, 136, 136);
2700 2701 padding-right: 2px;
2701 2702 }
2702 2703
2703 2704 .right .changes{
2704 2705 clear: both;
2705 2706 }
2706 2707
2707 2708 .right .changes .changed_total {
2708 2709 display: block;
2709 2710 float: right;
2710 2711 text-align: center;
2711 2712 min-width: 45px;
2712 2713 cursor: pointer;
2713 2714 color: #444444;
2714 2715 background: #FEA;
2715 2716 -webkit-border-radius: 0px 0px 0px 6px;
2716 2717 -moz-border-radius: 0px 0px 0px 6px;
2717 2718 border-radius: 0px 0px 0px 6px;
2718 2719 padding: 1px;
2719 2720 }
2720 2721
2721 2722 .right .changes .added,.changed,.removed {
2722 2723 display: block;
2723 2724 padding: 1px;
2724 2725 color: #444444;
2725 2726 float: right;
2726 2727 text-align: center;
2727 2728 min-width: 15px;
2728 2729 }
2729 2730
2730 2731 .right .changes .added {
2731 2732 background: #CFC;
2732 2733 }
2733 2734
2734 2735 .right .changes .changed {
2735 2736 background: #FEA;
2736 2737 }
2737 2738
2738 2739 .right .changes .removed {
2739 2740 background: #FAA;
2740 2741 }
2741 2742
2742 2743 .right .merge {
2743 2744 padding: 1px 3px 1px 3px;
2744 2745 background-color: #fca062;
2745 2746 font-size: 10px;
2746 2747 font-weight: bold;
2747 2748 color: #ffffff;
2748 2749 text-transform: uppercase;
2749 2750 white-space: nowrap;
2750 2751 -webkit-border-radius: 3px;
2751 2752 -moz-border-radius: 3px;
2752 2753 border-radius: 3px;
2753 2754 margin-right: 2px;
2754 2755 }
2755 2756
2756 2757 .right .parent {
2757 2758 color: #666666;
2758 2759 clear:both;
2759 2760 }
2760 2761 .right .logtags{
2761 2762 padding: 2px 2px 2px 2px;
2762 2763 }
2763 2764 .right .logtags .branchtag,.right .logtags .tagtag,.right .logtags .booktag{
2764 2765 margin: 0px 2px;
2765 2766 }
2766 2767
2767 2768 .right .logtags .branchtag,.logtags .branchtag {
2768 2769 padding: 1px 3px 1px 3px;
2769 2770 background-color: #bfbfbf;
2770 2771 font-size: 10px;
2771 2772 font-weight: bold;
2772 2773 color: #ffffff;
2773 2774 text-transform: uppercase;
2774 2775 white-space: nowrap;
2775 2776 -webkit-border-radius: 3px;
2776 2777 -moz-border-radius: 3px;
2777 2778 border-radius: 3px;
2778 2779 }
2779 2780 .right .logtags .branchtag a:hover,.logtags .branchtag a{
2780 2781 color: #ffffff;
2781 2782 }
2782 2783 .right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
2783 2784 text-decoration: none;
2784 2785 color: #ffffff;
2785 2786 }
2786 2787 .right .logtags .tagtag,.logtags .tagtag {
2787 2788 padding: 1px 3px 1px 3px;
2788 2789 background-color: #62cffc;
2789 2790 font-size: 10px;
2790 2791 font-weight: bold;
2791 2792 color: #ffffff;
2792 2793 text-transform: uppercase;
2793 2794 white-space: nowrap;
2794 2795 -webkit-border-radius: 3px;
2795 2796 -moz-border-radius: 3px;
2796 2797 border-radius: 3px;
2797 2798 }
2798 2799 .right .logtags .tagtag a:hover,.logtags .tagtag a{
2799 2800 color: #ffffff;
2800 2801 }
2801 2802 .right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
2802 2803 text-decoration: none;
2803 2804 color: #ffffff;
2804 2805 }
2805 2806 .right .logbooks .bookbook,.logbooks .bookbook,.right .logtags .bookbook,.logtags .bookbook {
2806 2807 padding: 1px 3px 1px 3px;
2807 2808 background-color: #46A546;
2808 2809 font-size: 10px;
2809 2810 font-weight: bold;
2810 2811 color: #ffffff;
2811 2812 text-transform: uppercase;
2812 2813 white-space: nowrap;
2813 2814 -webkit-border-radius: 3px;
2814 2815 -moz-border-radius: 3px;
2815 2816 border-radius: 3px;
2816 2817 }
2817 2818 .right .logbooks .bookbook,.logbooks .bookbook a,.right .logtags .bookbook,.logtags .bookbook a{
2818 2819 color: #ffffff;
2819 2820 }
2820 2821 .right .logbooks .bookbook,.logbooks .bookbook a:hover,.right .logtags .bookbook,.logtags .bookbook a:hover{
2821 2822 text-decoration: none;
2822 2823 color: #ffffff;
2823 2824 }
2824 2825 div.browserblock {
2825 2826 overflow: hidden;
2826 2827 border: 1px solid #ccc;
2827 2828 background: #f8f8f8;
2828 2829 font-size: 100%;
2829 2830 line-height: 125%;
2830 2831 padding: 0;
2831 2832 -webkit-border-radius: 6px 6px 0px 0px;
2832 2833 -moz-border-radius: 6px 6px 0px 0px;
2833 2834 border-radius: 6px 6px 0px 0px;
2834 2835 }
2835 2836
2836 2837 div.browserblock .browser-header {
2837 2838 background: #FFF;
2838 2839 padding: 10px 0px 15px 0px;
2839 2840 width: 100%;
2840 2841 }
2841 2842
2842 2843 div.browserblock .browser-nav {
2843 2844 float: left
2844 2845 }
2845 2846
2846 2847 div.browserblock .browser-branch {
2847 2848 float: left;
2848 2849 }
2849 2850
2850 2851 div.browserblock .browser-branch label {
2851 2852 color: #4A4A4A;
2852 2853 vertical-align: text-top;
2853 2854 }
2854 2855
2855 2856 div.browserblock .browser-header span {
2856 2857 margin-left: 5px;
2857 2858 font-weight: 700;
2858 2859 }
2859 2860
2860 2861 div.browserblock .browser-search {
2861 2862 clear: both;
2862 2863 padding: 8px 8px 0px 5px;
2863 2864 height: 20px;
2864 2865 }
2865 2866
2866 2867 div.browserblock #node_filter_box {
2867 2868
2868 2869 }
2869 2870
2870 2871 div.browserblock .search_activate {
2871 2872 float: left
2872 2873 }
2873 2874
2874 2875 div.browserblock .add_node {
2875 2876 float: left;
2876 2877 padding-left: 5px;
2877 2878 }
2878 2879
2879 2880 div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover
2880 2881 {
2881 2882 text-decoration: none !important;
2882 2883 }
2883 2884
2884 2885 div.browserblock .browser-body {
2885 2886 background: #EEE;
2886 2887 border-top: 1px solid #CCC;
2887 2888 }
2888 2889
2889 2890 table.code-browser {
2890 2891 border-collapse: collapse;
2891 2892 width: 100%;
2892 2893 }
2893 2894
2894 2895 table.code-browser tr {
2895 2896 margin: 3px;
2896 2897 }
2897 2898
2898 2899 table.code-browser thead th {
2899 2900 background-color: #EEE;
2900 2901 height: 20px;
2901 2902 font-size: 1.1em;
2902 2903 font-weight: 700;
2903 2904 text-align: left;
2904 2905 padding-left: 10px;
2905 2906 }
2906 2907
2907 2908 table.code-browser tbody td {
2908 2909 padding-left: 10px;
2909 2910 height: 20px;
2910 2911 }
2911 2912
2912 2913 table.code-browser .browser-file {
2913 2914 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2914 2915 height: 16px;
2915 2916 padding-left: 20px;
2916 2917 text-align: left;
2917 2918 }
2918 2919 .diffblock .changeset_header {
2919 2920 height: 16px;
2920 2921 }
2921 2922 .diffblock .changeset_file {
2922 2923 background: url("../images/icons/file.png") no-repeat scroll 3px;
2923 2924 text-align: left;
2924 2925 float: left;
2925 2926 padding: 2px 0px 2px 22px;
2926 2927 }
2927 2928 .diffblock .diff-menu-wrapper{
2928 2929 float: left;
2929 2930 }
2930 2931
2931 2932 .diffblock .diff-menu{
2932 2933 position: absolute;
2933 2934 background: none repeat scroll 0 0 #FFFFFF;
2934 2935 border-color: #003367 #666666 #666666;
2935 2936 border-right: 1px solid #666666;
2936 2937 border-style: solid solid solid;
2937 2938 border-width: 1px;
2938 2939 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2939 2940 margin-top:5px;
2940 2941 margin-left:1px;
2941 2942
2942 2943 }
2943 2944 .diffblock .diff-actions {
2944 2945 padding: 2px 0px 0px 2px;
2945 2946 float: left;
2946 2947 }
2947 2948 .diffblock .diff-menu ul li {
2948 2949 padding: 0px 0px 0px 0px !important;
2949 2950 }
2950 2951 .diffblock .diff-menu ul li a{
2951 2952 display: block;
2952 2953 padding: 3px 8px 3px 8px !important;
2953 2954 }
2954 2955 .diffblock .diff-menu ul li a:hover{
2955 2956 text-decoration: none;
2956 2957 background-color: #EEEEEE;
2957 2958 }
2958 2959 table.code-browser .browser-dir {
2959 2960 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2960 2961 height: 16px;
2961 2962 padding-left: 20px;
2962 2963 text-align: left;
2963 2964 }
2964 2965
2965 2966 table.code-browser .submodule-dir {
2966 2967 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
2967 2968 height: 16px;
2968 2969 padding-left: 20px;
2969 2970 text-align: left;
2970 2971 }
2971 2972
2972 2973
2973 2974 .box .search {
2974 2975 clear: both;
2975 2976 overflow: hidden;
2976 2977 margin: 0;
2977 2978 padding: 0 20px 10px;
2978 2979 }
2979 2980
2980 2981 .box .search div.search_path {
2981 2982 background: none repeat scroll 0 0 #EEE;
2982 2983 border: 1px solid #CCC;
2983 2984 color: blue;
2984 2985 margin-bottom: 10px;
2985 2986 padding: 10px 0;
2986 2987 }
2987 2988
2988 2989 .box .search div.search_path div.link {
2989 2990 font-weight: 700;
2990 2991 margin-left: 25px;
2991 2992 }
2992 2993
2993 2994 .box .search div.search_path div.link a {
2994 2995 color: #003367;
2995 2996 cursor: pointer;
2996 2997 text-decoration: none;
2997 2998 }
2998 2999
2999 3000 #path_unlock {
3000 3001 color: red;
3001 3002 font-size: 1.2em;
3002 3003 padding-left: 4px;
3003 3004 }
3004 3005
3005 3006 .info_box span {
3006 3007 margin-left: 3px;
3007 3008 margin-right: 3px;
3008 3009 }
3009 3010
3010 3011 .info_box .rev {
3011 3012 color: #003367;
3012 3013 font-size: 1.6em;
3013 3014 font-weight: bold;
3014 3015 vertical-align: sub;
3015 3016 }
3016 3017
3017 3018 .info_box input#at_rev,.info_box input#size {
3018 3019 background: #FFF;
3019 3020 border-top: 1px solid #b3b3b3;
3020 3021 border-left: 1px solid #b3b3b3;
3021 3022 border-right: 1px solid #eaeaea;
3022 3023 border-bottom: 1px solid #eaeaea;
3023 3024 color: #000;
3024 3025 font-size: 12px;
3025 3026 margin: 0;
3026 3027 padding: 1px 5px 1px;
3027 3028 }
3028 3029
3029 3030 .info_box input#view {
3030 3031 text-align: center;
3031 3032 padding: 4px 3px 2px 2px;
3032 3033 }
3033 3034
3034 3035 .yui-overlay,.yui-panel-container {
3035 3036 visibility: hidden;
3036 3037 position: absolute;
3037 3038 z-index: 2;
3038 3039 }
3039 3040
3040 3041 #tip-box {
3041 3042 position: absolute;
3042 3043
3043 3044 background-color: #FFF;
3044 3045 border: 2px solid #003367;
3045 3046 font: 100% sans-serif;
3046 3047 width: auto;
3047 3048 opacity: 1px;
3048 3049 padding: 8px;
3049 3050
3050 3051 white-space: pre-wrap;
3051 3052 -webkit-border-radius: 8px 8px 8px 8px;
3052 3053 -khtml-border-radius: 8px 8px 8px 8px;
3053 3054 -moz-border-radius: 8px 8px 8px 8px;
3054 3055 border-radius: 8px 8px 8px 8px;
3055 3056 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3056 3057 -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3057 3058 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3058 3059 }
3059 3060
3060 3061 .mentions-container{
3061 3062 width: 90% !important;
3062 3063 }
3063 3064 .mentions-container .yui-ac-content{
3064 3065 width: 100% !important;
3065 3066 }
3066 3067
3067 3068 .ac {
3068 3069 vertical-align: top;
3069 3070 }
3070 3071
3071 3072 .ac .yui-ac {
3072 3073 position: inherit;
3073 3074 font-size: 100%;
3074 3075 }
3075 3076
3076 3077 .ac .perm_ac {
3077 3078 width: 20em;
3078 3079 }
3079 3080
3080 3081 .ac .yui-ac-input {
3081 3082 width: 100%;
3082 3083 }
3083 3084
3084 3085 .ac .yui-ac-container {
3085 3086 position: absolute;
3086 3087 top: 1.6em;
3087 3088 width: auto;
3088 3089 }
3089 3090
3090 3091 .ac .yui-ac-content {
3091 3092 position: absolute;
3092 3093 border: 1px solid gray;
3093 3094 background: #fff;
3094 3095 z-index: 9050;
3095 3096
3096 3097 }
3097 3098
3098 3099 .ac .yui-ac-shadow {
3099 3100 position: absolute;
3100 3101 width: 100%;
3101 3102 background: #000;
3102 3103 -moz-opacity: 0.1px;
3103 3104 opacity: .10;
3104 3105 filter: alpha(opacity = 10);
3105 3106 z-index: 9049;
3106 3107 margin: .3em;
3107 3108 }
3108 3109
3109 3110 .ac .yui-ac-content ul {
3110 3111 width: 100%;
3111 3112 margin: 0;
3112 3113 padding: 0;
3113 3114 z-index: 9050;
3114 3115 }
3115 3116
3116 3117 .ac .yui-ac-content li {
3117 3118 cursor: default;
3118 3119 white-space: nowrap;
3119 3120 margin: 0;
3120 3121 padding: 2px 5px;
3121 3122 height: 18px;
3122 3123 z-index: 9050;
3123 3124 display: block;
3124 3125 width: auto !important;
3125 3126 }
3126 3127
3127 3128 .ac .yui-ac-content li .ac-container-wrap{
3128 3129 width: auto;
3129 3130 }
3130 3131
3131 3132 .ac .yui-ac-content li.yui-ac-prehighlight {
3132 3133 background: #B3D4FF;
3133 3134 z-index: 9050;
3134 3135 }
3135 3136
3136 3137 .ac .yui-ac-content li.yui-ac-highlight {
3137 3138 background: #556CB5;
3138 3139 color: #FFF;
3139 3140 z-index: 9050;
3140 3141 }
3141 3142 .ac .yui-ac-bd{
3142 3143 z-index: 9050;
3143 3144 }
3144 3145
3145 3146 .follow {
3146 3147 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3147 3148 height: 16px;
3148 3149 width: 20px;
3149 3150 cursor: pointer;
3150 3151 display: block;
3151 3152 float: right;
3152 3153 margin-top: 2px;
3153 3154 }
3154 3155
3155 3156 .following {
3156 3157 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3157 3158 height: 16px;
3158 3159 width: 20px;
3159 3160 cursor: pointer;
3160 3161 display: block;
3161 3162 float: right;
3162 3163 margin-top: 2px;
3163 3164 }
3164 3165
3165 3166 .locking_locked{
3166 3167 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3167 3168 height: 16px;
3168 3169 width: 20px;
3169 3170 cursor: pointer;
3170 3171 display: block;
3171 3172 float: right;
3172 3173 margin-top: 2px;
3173 3174 }
3174 3175
3175 3176 .locking_unlocked{
3176 3177 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3177 3178 height: 16px;
3178 3179 width: 20px;
3179 3180 cursor: pointer;
3180 3181 display: block;
3181 3182 float: right;
3182 3183 margin-top: 2px;
3183 3184 }
3184 3185
3185 3186 .currently_following {
3186 3187 padding-left: 10px;
3187 3188 padding-bottom: 5px;
3188 3189 }
3189 3190
3190 3191 .add_icon {
3191 3192 background: url("../images/icons/add.png") no-repeat scroll 3px;
3192 3193 padding-left: 20px;
3193 3194 padding-top: 0px;
3194 3195 text-align: left;
3195 3196 }
3196 3197
3197 3198 .accept_icon {
3198 3199 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3199 3200 padding-left: 20px;
3200 3201 padding-top: 0px;
3201 3202 text-align: left;
3202 3203 }
3203 3204
3204 3205 .edit_icon {
3205 3206 background: url("../images/icons/folder_edit.png") no-repeat scroll 3px;
3206 3207 padding-left: 20px;
3207 3208 padding-top: 0px;
3208 3209 text-align: left;
3209 3210 }
3210 3211
3211 3212 .delete_icon {
3212 3213 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3213 3214 padding-left: 20px;
3214 3215 padding-top: 0px;
3215 3216 text-align: left;
3216 3217 }
3217 3218
3218 3219 .refresh_icon {
3219 3220 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3220 3221 3px;
3221 3222 padding-left: 20px;
3222 3223 padding-top: 0px;
3223 3224 text-align: left;
3224 3225 }
3225 3226
3226 3227 .pull_icon {
3227 3228 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3228 3229 padding-left: 20px;
3229 3230 padding-top: 0px;
3230 3231 text-align: left;
3231 3232 }
3232 3233
3233 3234 .rss_icon {
3234 3235 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3235 3236 padding-left: 20px;
3236 3237 padding-top: 4px;
3237 3238 text-align: left;
3238 3239 font-size: 8px
3239 3240 }
3240 3241
3241 3242 .atom_icon {
3242 3243 background: url("../images/icons/atom.png") no-repeat scroll 3px;
3243 3244 padding-left: 20px;
3244 3245 padding-top: 4px;
3245 3246 text-align: left;
3246 3247 font-size: 8px
3247 3248 }
3248 3249
3249 3250 .archive_icon {
3250 3251 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3251 3252 padding-left: 20px;
3252 3253 text-align: left;
3253 3254 padding-top: 1px;
3254 3255 }
3255 3256
3256 3257 .start_following_icon {
3257 3258 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3258 3259 padding-left: 20px;
3259 3260 text-align: left;
3260 3261 padding-top: 0px;
3261 3262 }
3262 3263
3263 3264 .stop_following_icon {
3264 3265 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3265 3266 padding-left: 20px;
3266 3267 text-align: left;
3267 3268 padding-top: 0px;
3268 3269 }
3269 3270
3270 3271 .action_button {
3271 3272 border: 0;
3272 3273 display: inline;
3273 3274 }
3274 3275
3275 3276 .action_button:hover {
3276 3277 border: 0;
3277 3278 text-decoration: underline;
3278 3279 cursor: pointer;
3279 3280 }
3280 3281
3281 3282 #switch_repos {
3282 3283 position: absolute;
3283 3284 height: 25px;
3284 3285 z-index: 1;
3285 3286 }
3286 3287
3287 3288 #switch_repos select {
3288 3289 min-width: 150px;
3289 3290 max-height: 250px;
3290 3291 z-index: 1;
3291 3292 }
3292 3293
3293 3294 .breadcrumbs {
3294 3295 border: medium none;
3295 3296 color: #FFF;
3296 3297 float: left;
3297 3298 text-transform: uppercase;
3298 3299 font-weight: 700;
3299 3300 font-size: 14px;
3300 3301 margin: 0;
3301 3302 padding: 11px 0 11px 10px;
3302 3303 }
3303 3304
3304 3305 .breadcrumbs .hash {
3305 3306 text-transform: none;
3306 3307 color: #fff;
3307 3308 }
3308 3309
3309 3310 .breadcrumbs a {
3310 3311 color: #FFF;
3311 3312 }
3312 3313
3313 3314 .flash_msg {
3314 3315
3315 3316 }
3316 3317
3317 3318 .flash_msg ul {
3318 3319
3319 3320 }
3320 3321
3321 3322 .error_red {
3322 3323 color:red;
3323 3324 }
3324 3325
3325 3326 .error_msg {
3326 3327 background-color: #c43c35;
3327 3328 background-repeat: repeat-x;
3328 3329 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3329 3330 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3330 3331 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3331 3332 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3332 3333 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3333 3334 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3334 3335 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3335 3336 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3336 3337 border-color: #c43c35 #c43c35 #882a25;
3337 3338 }
3338 3339
3339 3340 .warning_msg {
3340 3341 color: #404040 !important;
3341 3342 background-color: #eedc94;
3342 3343 background-repeat: repeat-x;
3343 3344 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3344 3345 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3345 3346 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3346 3347 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3347 3348 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3348 3349 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3349 3350 background-image: linear-gradient(top, #fceec1, #eedc94);
3350 3351 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3351 3352 border-color: #eedc94 #eedc94 #e4c652;
3352 3353 }
3353 3354
3354 3355 .success_msg {
3355 3356 background-color: #57a957;
3356 3357 background-repeat: repeat-x !important;
3357 3358 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3358 3359 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3359 3360 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3360 3361 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3361 3362 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3362 3363 background-image: -o-linear-gradient(top, #62c462, #57a957);
3363 3364 background-image: linear-gradient(top, #62c462, #57a957);
3364 3365 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3365 3366 border-color: #57a957 #57a957 #3d773d;
3366 3367 }
3367 3368
3368 3369 .notice_msg {
3369 3370 background-color: #339bb9;
3370 3371 background-repeat: repeat-x;
3371 3372 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3372 3373 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3373 3374 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3374 3375 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3375 3376 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3376 3377 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3377 3378 background-image: linear-gradient(top, #5bc0de, #339bb9);
3378 3379 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3379 3380 border-color: #339bb9 #339bb9 #22697d;
3380 3381 }
3381 3382
3382 3383 .success_msg,.error_msg,.notice_msg,.warning_msg {
3383 3384 font-size: 12px;
3384 3385 font-weight: 700;
3385 3386 min-height: 14px;
3386 3387 line-height: 14px;
3387 3388 margin-bottom: 10px;
3388 3389 margin-top: 0;
3389 3390 display: block;
3390 3391 overflow: auto;
3391 3392 padding: 6px 10px 6px 10px;
3392 3393 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3393 3394 position: relative;
3394 3395 color: #FFF;
3395 3396 border-width: 1px;
3396 3397 border-style: solid;
3397 3398 -webkit-border-radius: 4px;
3398 3399 -moz-border-radius: 4px;
3399 3400 border-radius: 4px;
3400 3401 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3401 3402 -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3402 3403 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3403 3404 }
3404 3405
3405 3406 #msg_close {
3406 3407 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3407 3408 cursor: pointer;
3408 3409 height: 16px;
3409 3410 position: absolute;
3410 3411 right: 5px;
3411 3412 top: 5px;
3412 3413 width: 16px;
3413 3414 }
3414 3415 div#legend_data{
3415 3416 padding-left:10px;
3416 3417 }
3417 3418 div#legend_container table{
3418 3419 border: none !important;
3419 3420 }
3420 3421 div#legend_container table,div#legend_choices table {
3421 3422 width: auto !important;
3422 3423 }
3423 3424
3424 3425 table#permissions_manage {
3425 3426 width: 0 !important;
3426 3427 }
3427 3428
3428 3429 table#permissions_manage span.private_repo_msg {
3429 3430 font-size: 0.8em;
3430 3431 opacity: 0.6px;
3431 3432 }
3432 3433
3433 3434 table#permissions_manage td.private_repo_msg {
3434 3435 font-size: 0.8em;
3435 3436 }
3436 3437
3437 3438 table#permissions_manage tr#add_perm_input td {
3438 3439 vertical-align: middle;
3439 3440 }
3440 3441
3441 3442 div.gravatar {
3442 3443 background-color: #FFF;
3443 3444 float: left;
3444 3445 margin-right: 0.7em;
3445 3446 padding: 1px 1px 1px 1px;
3446 3447 line-height:0;
3447 3448 -webkit-border-radius: 3px;
3448 3449 -khtml-border-radius: 3px;
3449 3450 -moz-border-radius: 3px;
3450 3451 border-radius: 3px;
3451 3452 }
3452 3453
3453 3454 div.gravatar img {
3454 3455 -webkit-border-radius: 2px;
3455 3456 -khtml-border-radius: 2px;
3456 3457 -moz-border-radius: 2px;
3457 3458 border-radius: 2px;
3458 3459 }
3459 3460
3460 3461 #header,#content,#footer {
3461 3462 min-width: 978px;
3462 3463 }
3463 3464
3464 3465 #content {
3465 3466 clear: both;
3466 3467 overflow: hidden;
3467 3468 padding: 54px 10px 14px 10px;
3468 3469 }
3469 3470
3470 3471 #content div.box div.title div.search {
3471 3472
3472 3473 border-left: 1px solid #316293;
3473 3474 }
3474 3475
3475 3476 #content div.box div.title div.search div.input input {
3476 3477 border: 1px solid #316293;
3477 3478 }
3478 3479
3479 3480 .ui-btn{
3480 3481 color: #515151;
3481 3482 background-color: #DADADA;
3482 3483 background-repeat: repeat-x;
3483 3484 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3484 3485 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3485 3486 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3486 3487 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3487 3488 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3488 3489 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3489 3490 background-image: linear-gradient(top, #F4F4F4, #DADADA);
3490 3491 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3491 3492
3492 3493 border-top: 1px solid #DDD;
3493 3494 border-left: 1px solid #c6c6c6;
3494 3495 border-right: 1px solid #DDD;
3495 3496 border-bottom: 1px solid #c6c6c6;
3496 3497 color: #515151;
3497 3498 outline: none;
3498 3499 margin: 0px 3px 3px 0px;
3499 3500 -webkit-border-radius: 4px 4px 4px 4px !important;
3500 3501 -khtml-border-radius: 4px 4px 4px 4px !important;
3501 3502 -moz-border-radius: 4px 4px 4px 4px !important;
3502 3503 border-radius: 4px 4px 4px 4px !important;
3503 3504 cursor: pointer !important;
3504 3505 padding: 3px 3px 3px 3px;
3505 3506 background-position: 0 -15px;
3506 3507
3507 3508 }
3508 3509 .ui-btn.xsmall{
3509 3510 padding: 1px 2px 1px 1px;
3510 3511 }
3511 3512
3512 3513 .ui-btn.large{
3513 3514 padding: 6px 12px;
3514 3515 }
3515 3516
3516 3517 .ui-btn.clone{
3517 3518 padding: 5px 2px 6px 1px;
3518 3519 margin: 0px -4px 3px 0px;
3519 3520 -webkit-border-radius: 4px 0px 0px 4px !important;
3520 3521 -khtml-border-radius: 4px 0px 0px 4px !important;
3521 3522 -moz-border-radius: 4px 0px 0px 4px !important;
3522 3523 border-radius: 4px 0px 0px 4px !important;
3523 3524 width: 100px;
3524 3525 text-align: center;
3525 3526 float: left;
3526 3527 position: absolute;
3527 3528 }
3528 3529 .ui-btn:focus {
3529 3530 outline: none;
3530 3531 }
3531 3532 .ui-btn:hover{
3532 3533 background-position: 0 0px;
3533 3534 text-decoration: none;
3534 3535 color: #515151;
3535 3536 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3536 3537 }
3537 3538
3538 3539 .ui-btn.red{
3539 3540 color:#fff;
3540 3541 background-color: #c43c35;
3541 3542 background-repeat: repeat-x;
3542 3543 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3543 3544 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3544 3545 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3545 3546 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3546 3547 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3547 3548 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3548 3549 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3549 3550 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3550 3551 border-color: #c43c35 #c43c35 #882a25;
3551 3552 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3552 3553 }
3553 3554
3554 3555
3555 3556 .ui-btn.blue{
3556 3557 color:#fff;
3557 3558 background-color: #339bb9;
3558 3559 background-repeat: repeat-x;
3559 3560 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3560 3561 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3561 3562 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3562 3563 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3563 3564 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3564 3565 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3565 3566 background-image: linear-gradient(top, #5bc0de, #339bb9);
3566 3567 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3567 3568 border-color: #339bb9 #339bb9 #22697d;
3568 3569 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3569 3570 }
3570 3571
3571 3572 .ui-btn.green{
3572 3573 background-color: #57a957;
3573 3574 background-repeat: repeat-x;
3574 3575 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3575 3576 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3576 3577 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3577 3578 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3578 3579 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3579 3580 background-image: -o-linear-gradient(top, #62c462, #57a957);
3580 3581 background-image: linear-gradient(top, #62c462, #57a957);
3581 3582 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3582 3583 border-color: #57a957 #57a957 #3d773d;
3583 3584 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3584 3585 }
3585 3586
3586 3587 .ui-btn.active{
3587 3588 font-weight: bold;
3588 3589 }
3589 3590
3590 3591 ins,div.options a:hover {
3591 3592 text-decoration: none;
3592 3593 }
3593 3594
3594 3595 img,
3595 3596 #header #header-inner #quick li a:hover span.normal,
3596 3597 #header #header-inner #quick li ul li.last,
3597 3598 #content div.box div.form div.fields div.field div.textarea table td table td a,
3598 3599 #clone_url,
3599 3600 #clone_url_id
3600 3601 {
3601 3602 border: none;
3602 3603 }
3603 3604
3604 3605 img.icon,.right .merge img {
3605 3606 vertical-align: bottom;
3606 3607 }
3607 3608
3608 3609 #header ul#logged-user,#content div.box div.title ul.links,
3609 3610 #content div.box div.message div.dismiss,
3610 3611 #content div.box div.traffic div.legend ul
3611 3612 {
3612 3613 float: right;
3613 3614 margin: 0;
3614 3615 padding: 0;
3615 3616 }
3616 3617
3617 3618 #header #header-inner #home,#header #header-inner #logo,
3618 3619 #content div.box ul.left,#content div.box ol.left,
3619 3620 #content div.box div.pagination-left,div#commit_history,
3620 3621 div#legend_data,div#legend_container,div#legend_choices
3621 3622 {
3622 3623 float: left;
3623 3624 }
3624 3625
3625 3626 #header #header-inner #quick li:hover ul ul,
3626 3627 #header #header-inner #quick li:hover ul ul ul,
3627 3628 #header #header-inner #quick li:hover ul ul ul ul,
3628 3629 #content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow
3629 3630 {
3630 3631 display: none;
3631 3632 }
3632 3633
3633 3634 #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
3634 3635 {
3635 3636 display: block;
3636 3637 }
3637 3638
3638 3639 #content div.graph {
3639 3640 padding: 0 10px 10px;
3640 3641 }
3641 3642
3642 3643 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a
3643 3644 {
3644 3645 color: #bfe3ff;
3645 3646 }
3646 3647
3647 3648 #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
3648 3649 {
3649 3650 margin: 10px 24px 10px 44px;
3650 3651 }
3651 3652
3652 3653 #content div.box div.form,#content div.box div.table,#content div.box div.traffic
3653 3654 {
3654 3655 clear: both;
3655 3656 overflow: hidden;
3656 3657 margin: 0;
3657 3658 padding: 0 20px 10px;
3658 3659 }
3659 3660
3660 3661 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields
3661 3662 {
3662 3663 clear: both;
3663 3664 overflow: hidden;
3664 3665 margin: 0;
3665 3666 padding: 0;
3666 3667 }
3667 3668
3668 3669 #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
3669 3670 {
3670 3671 height: 1%;
3671 3672 display: block;
3672 3673 color: #363636;
3673 3674 margin: 0;
3674 3675 padding: 2px 0 0;
3675 3676 }
3676 3677
3677 3678 #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
3678 3679 {
3679 3680 background: #FBE3E4;
3680 3681 border-top: 1px solid #e1b2b3;
3681 3682 border-left: 1px solid #e1b2b3;
3682 3683 border-right: 1px solid #FBC2C4;
3683 3684 border-bottom: 1px solid #FBC2C4;
3684 3685 }
3685 3686
3686 3687 #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
3687 3688 {
3688 3689 background: #E6EFC2;
3689 3690 border-top: 1px solid #cebb98;
3690 3691 border-left: 1px solid #cebb98;
3691 3692 border-right: 1px solid #c6d880;
3692 3693 border-bottom: 1px solid #c6d880;
3693 3694 }
3694 3695
3695 3696 #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
3696 3697 {
3697 3698 margin: 0;
3698 3699 }
3699 3700
3700 3701 #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
3701 3702 {
3702 3703 margin: 0 0 0 0px !important;
3703 3704 padding: 0;
3704 3705 }
3705 3706
3706 3707 #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
3707 3708 {
3708 3709 margin: 0 0 0 200px;
3709 3710 padding: 0;
3710 3711 }
3711 3712
3712 3713 #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
3713 3714 {
3714 3715 color: #000;
3715 3716 text-decoration: none;
3716 3717 }
3717 3718
3718 3719 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus
3719 3720 {
3720 3721 border: 1px solid #666;
3721 3722 }
3722 3723
3723 3724 #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
3724 3725 {
3725 3726 clear: both;
3726 3727 overflow: hidden;
3727 3728 margin: 0;
3728 3729 padding: 8px 0 2px;
3729 3730 }
3730 3731
3731 3732 #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
3732 3733 {
3733 3734 float: left;
3734 3735 margin: 0;
3735 3736 }
3736 3737
3737 3738 #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
3738 3739 {
3739 3740 height: 1%;
3740 3741 display: block;
3741 3742 float: left;
3742 3743 margin: 2px 0 0 4px;
3743 3744 }
3744 3745
3745 3746 div.form div.fields div.field div.button input,
3746 3747 #content div.box div.form div.fields div.buttons input
3747 3748 div.form div.fields div.buttons input,
3748 3749 #content div.box div.action div.button input {
3749 3750 /*color: #000;*/
3750 3751 font-size: 11px;
3751 3752 font-weight: 700;
3752 3753 margin: 0;
3753 3754 }
3754 3755
3755 3756 input.ui-button {
3756 3757 background: #e5e3e3 url("../images/button.png") repeat-x;
3757 3758 border-top: 1px solid #DDD;
3758 3759 border-left: 1px solid #c6c6c6;
3759 3760 border-right: 1px solid #DDD;
3760 3761 border-bottom: 1px solid #c6c6c6;
3761 3762 color: #515151 !important;
3762 3763 outline: none;
3763 3764 margin: 0;
3764 3765 padding: 6px 12px;
3765 3766 -webkit-border-radius: 4px 4px 4px 4px;
3766 3767 -khtml-border-radius: 4px 4px 4px 4px;
3767 3768 -moz-border-radius: 4px 4px 4px 4px;
3768 3769 border-radius: 4px 4px 4px 4px;
3769 3770 box-shadow: 0 1px 0 #ececec;
3770 3771 cursor: pointer;
3771 3772 }
3772 3773
3773 3774 input.ui-button:hover {
3774 3775 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3775 3776 border-top: 1px solid #ccc;
3776 3777 border-left: 1px solid #bebebe;
3777 3778 border-right: 1px solid #b1b1b1;
3778 3779 border-bottom: 1px solid #afafaf;
3779 3780 }
3780 3781
3781 3782 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight
3782 3783 {
3783 3784 display: inline;
3784 3785 }
3785 3786
3786 3787 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons
3787 3788 {
3788 3789 margin: 10px 0 0 200px;
3789 3790 padding: 0;
3790 3791 }
3791 3792
3792 3793 #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
3793 3794 {
3794 3795 margin: 10px 0 0;
3795 3796 }
3796 3797
3797 3798 #content div.box table td.user,#content div.box table td.address {
3798 3799 width: 10%;
3799 3800 text-align: center;
3800 3801 }
3801 3802
3802 3803 #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
3803 3804 {
3804 3805 text-align: right;
3805 3806 margin: 6px 0 0;
3806 3807 padding: 0;
3807 3808 }
3808 3809
3809 3810 #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
3810 3811 {
3811 3812 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3812 3813 border-top: 1px solid #ccc;
3813 3814 border-left: 1px solid #bebebe;
3814 3815 border-right: 1px solid #b1b1b1;
3815 3816 border-bottom: 1px solid #afafaf;
3816 3817 color: #515151;
3817 3818 margin: 0;
3818 3819 padding: 6px 12px;
3819 3820 }
3820 3821
3821 3822 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results
3822 3823 {
3823 3824 text-align: left;
3824 3825 float: left;
3825 3826 margin: 0;
3826 3827 padding: 0;
3827 3828 }
3828 3829
3829 3830 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span
3830 3831 {
3831 3832 height: 1%;
3832 3833 display: block;
3833 3834 float: left;
3834 3835 background: #ebebeb url("../images/pager.png") repeat-x;
3835 3836 border-top: 1px solid #dedede;
3836 3837 border-left: 1px solid #cfcfcf;
3837 3838 border-right: 1px solid #c4c4c4;
3838 3839 border-bottom: 1px solid #c4c4c4;
3839 3840 color: #4A4A4A;
3840 3841 font-weight: 700;
3841 3842 margin: 0;
3842 3843 padding: 6px 8px;
3843 3844 }
3844 3845
3845 3846 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled
3846 3847 {
3847 3848 color: #B4B4B4;
3848 3849 padding: 6px;
3849 3850 }
3850 3851
3851 3852 #login,#register {
3852 3853 width: 520px;
3853 3854 margin: 10% auto 0;
3854 3855 padding: 0;
3855 3856 }
3856 3857
3857 3858 #login div.color,#register div.color {
3858 3859 clear: both;
3859 3860 overflow: hidden;
3860 3861 background: #FFF;
3861 3862 margin: 10px auto 0;
3862 3863 padding: 3px 3px 3px 0;
3863 3864 }
3864 3865
3865 3866 #login div.color a,#register div.color a {
3866 3867 width: 20px;
3867 3868 height: 20px;
3868 3869 display: block;
3869 3870 float: left;
3870 3871 margin: 0 0 0 3px;
3871 3872 padding: 0;
3872 3873 }
3873 3874
3874 3875 #login div.title h5,#register div.title h5 {
3875 3876 color: #fff;
3876 3877 margin: 10px;
3877 3878 padding: 0;
3878 3879 }
3879 3880
3880 3881 #login div.form div.fields div.field,#register div.form div.fields div.field
3881 3882 {
3882 3883 clear: both;
3883 3884 overflow: hidden;
3884 3885 margin: 0;
3885 3886 padding: 0 0 10px;
3886 3887 }
3887 3888
3888 3889 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message
3889 3890 {
3890 3891 height: 1%;
3891 3892 display: block;
3892 3893 color: red;
3893 3894 margin: 8px 0 0;
3894 3895 padding: 0;
3895 3896 max-width: 320px;
3896 3897 }
3897 3898
3898 3899 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label
3899 3900 {
3900 3901 color: #000;
3901 3902 font-weight: 700;
3902 3903 }
3903 3904
3904 3905 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
3905 3906 {
3906 3907 float: left;
3907 3908 margin: 0;
3908 3909 padding: 0;
3909 3910 }
3910 3911
3911 3912 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
3912 3913 {
3913 3914 margin: 0 0 0 184px;
3914 3915 padding: 0;
3915 3916 }
3916 3917
3917 3918 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
3918 3919 {
3919 3920 color: #565656;
3920 3921 font-weight: 700;
3921 3922 }
3922 3923
3923 3924 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
3924 3925 {
3925 3926 color: #000;
3926 3927 font-size: 1em;
3927 3928 font-weight: 700;
3928 3929 margin: 0;
3929 3930 }
3930 3931
3931 3932 #changeset_content .container .wrapper,#graph_content .container .wrapper
3932 3933 {
3933 3934 width: 600px;
3934 3935 }
3935 3936
3936 3937 #changeset_content .container .left {
3937 3938 float: left;
3938 3939 width: 75%;
3939 3940 padding-left: 5px;
3940 3941 }
3941 3942
3942 3943 #changeset_content .container .left .date,.ac .match {
3943 3944 font-weight: 700;
3944 3945 padding-top: 5px;
3945 3946 padding-bottom: 5px;
3946 3947 }
3947 3948
3948 3949 div#legend_container table td,div#legend_choices table td {
3949 3950 border: none !important;
3950 3951 height: 20px !important;
3951 3952 padding: 0 !important;
3952 3953 }
3953 3954
3954 3955 .q_filter_box {
3955 3956 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
3956 3957 -webkit-border-radius: 4px;
3957 3958 -moz-border-radius: 4px;
3958 3959 border-radius: 4px;
3959 3960 border: 0 none;
3960 3961 color: #AAAAAA;
3961 3962 margin-bottom: -4px;
3962 3963 margin-top: -4px;
3963 3964 padding-left: 3px;
3964 3965 }
3965 3966
3966 3967 #node_filter {
3967 3968 border: 0px solid #545454;
3968 3969 color: #AAAAAA;
3969 3970 padding-left: 3px;
3970 3971 }
3971 3972
3972 3973
3973 3974 .group_members_wrap{
3974 3975 min-height: 85px;
3975 3976 padding-left: 20px;
3976 3977 }
3977 3978
3978 3979 .group_members .group_member{
3979 3980 height: 30px;
3980 3981 padding:0px 0px 0px 0px;
3981 3982 }
3982 3983
3983 3984 .reviewers_member{
3984 3985 height: 15px;
3985 3986 padding:0px 0px 0px 10px;
3986 3987 }
3987 3988
3988 3989 .emails_wrap{
3989 3990 padding: 0px 20px;
3990 3991 }
3991 3992
3992 3993 .emails_wrap .email_entry{
3993 3994 height: 30px;
3994 3995 padding:0px 0px 0px 10px;
3995 3996 }
3996 3997 .emails_wrap .email_entry .email{
3997 3998 float: left
3998 3999 }
3999 4000 .emails_wrap .email_entry .email_action{
4000 4001 float: left
4001 4002 }
4002 4003
4003 4004 /*README STYLE*/
4004 4005
4005 4006 div.readme {
4006 4007 padding:0px;
4007 4008 }
4008 4009
4009 4010 div.readme h2 {
4010 4011 font-weight: normal;
4011 4012 }
4012 4013
4013 4014 div.readme .readme_box {
4014 4015 background-color: #fafafa;
4015 4016 }
4016 4017
4017 4018 div.readme .readme_box {
4018 4019 clear:both;
4019 4020 overflow:hidden;
4020 4021 margin:0;
4021 4022 padding:0 20px 10px;
4022 4023 }
4023 4024
4024 4025 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4025 4026 border-bottom: 0 !important;
4026 4027 margin: 0 !important;
4027 4028 padding: 0 !important;
4028 4029 line-height: 1.5em !important;
4029 4030 }
4030 4031
4031 4032
4032 4033 div.readme .readme_box h1:first-child {
4033 4034 padding-top: .25em !important;
4034 4035 }
4035 4036
4036 4037 div.readme .readme_box h2, div.readme .readme_box h3 {
4037 4038 margin: 1em 0 !important;
4038 4039 }
4039 4040
4040 4041 div.readme .readme_box h2 {
4041 4042 margin-top: 1.5em !important;
4042 4043 border-top: 4px solid #e0e0e0 !important;
4043 4044 padding-top: .5em !important;
4044 4045 }
4045 4046
4046 4047 div.readme .readme_box p {
4047 4048 color: black !important;
4048 4049 margin: 1em 0 !important;
4049 4050 line-height: 1.5em !important;
4050 4051 }
4051 4052
4052 4053 div.readme .readme_box ul {
4053 4054 list-style: disc !important;
4054 4055 margin: 1em 0 1em 2em !important;
4055 4056 }
4056 4057
4057 4058 div.readme .readme_box ol {
4058 4059 list-style: decimal;
4059 4060 margin: 1em 0 1em 2em !important;
4060 4061 }
4061 4062
4062 4063 div.readme .readme_box pre, code {
4063 4064 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4064 4065 }
4065 4066
4066 4067 div.readme .readme_box code {
4067 4068 font-size: 12px !important;
4068 4069 background-color: ghostWhite !important;
4069 4070 color: #444 !important;
4070 4071 padding: 0 .2em !important;
4071 4072 border: 1px solid #dedede !important;
4072 4073 }
4073 4074
4074 4075 div.readme .readme_box pre code {
4075 4076 padding: 0 !important;
4076 4077 font-size: 12px !important;
4077 4078 background-color: #eee !important;
4078 4079 border: none !important;
4079 4080 }
4080 4081
4081 4082 div.readme .readme_box pre {
4082 4083 margin: 1em 0;
4083 4084 font-size: 12px;
4084 4085 background-color: #eee;
4085 4086 border: 1px solid #ddd;
4086 4087 padding: 5px;
4087 4088 color: #444;
4088 4089 overflow: auto;
4089 4090 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4090 4091 -webkit-border-radius: 3px;
4091 4092 -moz-border-radius: 3px;
4092 4093 border-radius: 3px;
4093 4094 }
4094 4095
4095 4096 div.readme .readme_box table {
4096 4097 display: table;
4097 4098 border-collapse: separate;
4098 4099 border-spacing: 2px;
4099 4100 border-color: gray;
4100 4101 width: auto !important;
4101 4102 }
4102 4103
4103 4104
4104 4105 /** RST STYLE **/
4105 4106
4106 4107
4107 4108 div.rst-block {
4108 4109 padding:0px;
4109 4110 }
4110 4111
4111 4112 div.rst-block h2 {
4112 4113 font-weight: normal;
4113 4114 }
4114 4115
4115 4116 div.rst-block {
4116 4117 background-color: #fafafa;
4117 4118 }
4118 4119
4119 4120 div.rst-block {
4120 4121 clear:both;
4121 4122 overflow:hidden;
4122 4123 margin:0;
4123 4124 padding:0 20px 10px;
4124 4125 }
4125 4126
4126 4127 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4127 4128 border-bottom: 0 !important;
4128 4129 margin: 0 !important;
4129 4130 padding: 0 !important;
4130 4131 line-height: 1.5em !important;
4131 4132 }
4132 4133
4133 4134
4134 4135 div.rst-block h1:first-child {
4135 4136 padding-top: .25em !important;
4136 4137 }
4137 4138
4138 4139 div.rst-block h2, div.rst-block h3 {
4139 4140 margin: 1em 0 !important;
4140 4141 }
4141 4142
4142 4143 div.rst-block h2 {
4143 4144 margin-top: 1.5em !important;
4144 4145 border-top: 4px solid #e0e0e0 !important;
4145 4146 padding-top: .5em !important;
4146 4147 }
4147 4148
4148 4149 div.rst-block p {
4149 4150 color: black !important;
4150 4151 margin: 1em 0 !important;
4151 4152 line-height: 1.5em !important;
4152 4153 }
4153 4154
4154 4155 div.rst-block ul {
4155 4156 list-style: disc !important;
4156 4157 margin: 1em 0 1em 2em !important;
4157 4158 }
4158 4159
4159 4160 div.rst-block ol {
4160 4161 list-style: decimal;
4161 4162 margin: 1em 0 1em 2em !important;
4162 4163 }
4163 4164
4164 4165 div.rst-block pre, code {
4165 4166 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4166 4167 }
4167 4168
4168 4169 div.rst-block code {
4169 4170 font-size: 12px !important;
4170 4171 background-color: ghostWhite !important;
4171 4172 color: #444 !important;
4172 4173 padding: 0 .2em !important;
4173 4174 border: 1px solid #dedede !important;
4174 4175 }
4175 4176
4176 4177 div.rst-block pre code {
4177 4178 padding: 0 !important;
4178 4179 font-size: 12px !important;
4179 4180 background-color: #eee !important;
4180 4181 border: none !important;
4181 4182 }
4182 4183
4183 4184 div.rst-block pre {
4184 4185 margin: 1em 0;
4185 4186 font-size: 12px;
4186 4187 background-color: #eee;
4187 4188 border: 1px solid #ddd;
4188 4189 padding: 5px;
4189 4190 color: #444;
4190 4191 overflow: auto;
4191 4192 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4192 4193 -webkit-border-radius: 3px;
4193 4194 -moz-border-radius: 3px;
4194 4195 border-radius: 3px;
4195 4196 }
4196 4197
4197 4198
4198 4199 /** comment main **/
4199 4200 .comments {
4200 4201 padding:10px 20px;
4201 4202 }
4202 4203
4203 4204 .comments .comment {
4204 4205 border: 1px solid #ddd;
4205 4206 margin-top: 10px;
4206 4207 -webkit-border-radius: 4px;
4207 4208 -moz-border-radius: 4px;
4208 4209 border-radius: 4px;
4209 4210 }
4210 4211
4211 4212 .comments .comment .meta {
4212 4213 background: #f8f8f8;
4213 4214 padding: 4px;
4214 4215 border-bottom: 1px solid #ddd;
4215 4216 height: 18px;
4216 4217 }
4217 4218
4218 4219 .comments .comment .meta img {
4219 4220 vertical-align: middle;
4220 4221 }
4221 4222
4222 4223 .comments .comment .meta .user {
4223 4224 font-weight: bold;
4224 4225 float: left;
4225 4226 padding: 4px 2px 2px 2px;
4226 4227 }
4227 4228
4228 4229 .comments .comment .meta .date {
4229 4230 float: left;
4230 4231 padding:4px 4px 0px 4px;
4231 4232 }
4232 4233
4233 4234 .comments .comment .text {
4234 4235 background-color: #FAFAFA;
4235 4236 }
4236 4237 .comment .text div.rst-block p {
4237 4238 margin: 0.5em 0px !important;
4238 4239 }
4239 4240
4240 4241 .comments .comments-number{
4241 4242 padding:0px 0px 10px 0px;
4242 4243 font-weight: bold;
4243 4244 color: #666;
4244 4245 font-size: 16px;
4245 4246 }
4246 4247
4247 4248 /** comment form **/
4248 4249
4249 4250 .status-block{
4250 4251 height:80px;
4251 4252 clear:both
4252 4253 }
4253 4254
4254 4255 .comment-form .clearfix{
4255 4256 background: #EEE;
4256 4257 -webkit-border-radius: 4px;
4257 4258 -moz-border-radius: 4px;
4258 4259 border-radius: 4px;
4259 4260 padding: 10px;
4260 4261 }
4261 4262
4262 4263 div.comment-form {
4263 4264 margin-top: 20px;
4264 4265 }
4265 4266
4266 4267 .comment-form strong {
4267 4268 display: block;
4268 4269 margin-bottom: 15px;
4269 4270 }
4270 4271
4271 4272 .comment-form textarea {
4272 4273 width: 100%;
4273 4274 height: 100px;
4274 4275 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4275 4276 }
4276 4277
4277 4278 form.comment-form {
4278 4279 margin-top: 10px;
4279 4280 margin-left: 10px;
4280 4281 }
4281 4282
4282 4283 .comment-form-submit {
4283 4284 margin-top: 5px;
4284 4285 margin-left: 525px;
4285 4286 }
4286 4287
4287 4288 .file-comments {
4288 4289 display: none;
4289 4290 }
4290 4291
4291 4292 .comment-form .comment {
4292 4293 margin-left: 10px;
4293 4294 }
4294 4295
4295 4296 .comment-form .comment-help{
4296 4297 padding: 0px 0px 5px 0px;
4297 4298 color: #666;
4298 4299 }
4299 4300
4300 4301 .comment-form .comment-button{
4301 4302 padding-top:5px;
4302 4303 }
4303 4304
4304 4305 .add-another-button {
4305 4306 margin-left: 10px;
4306 4307 margin-top: 10px;
4307 4308 margin-bottom: 10px;
4308 4309 }
4309 4310
4310 4311 .comment .buttons {
4311 4312 float: right;
4312 4313 padding:2px 2px 0px 0px;
4313 4314 }
4314 4315
4315 4316
4316 4317 .show-inline-comments{
4317 4318 position: relative;
4318 4319 top:1px
4319 4320 }
4320 4321
4321 4322 /** comment inline form **/
4322 4323 .comment-inline-form .overlay{
4323 4324 display: none;
4324 4325 }
4325 4326 .comment-inline-form .overlay.submitting{
4326 4327 display:block;
4327 4328 background: none repeat scroll 0 0 white;
4328 4329 font-size: 16px;
4329 4330 opacity: 0.5;
4330 4331 position: absolute;
4331 4332 text-align: center;
4332 4333 vertical-align: top;
4333 4334
4334 4335 }
4335 4336 .comment-inline-form .overlay.submitting .overlay-text{
4336 4337 width:100%;
4337 4338 margin-top:5%;
4338 4339 }
4339 4340
4340 4341 .comment-inline-form .clearfix{
4341 4342 background: #EEE;
4342 4343 -webkit-border-radius: 4px;
4343 4344 -moz-border-radius: 4px;
4344 4345 border-radius: 4px;
4345 4346 padding: 5px;
4346 4347 }
4347 4348
4348 4349 div.comment-inline-form {
4349 4350 padding:4px 0px 6px 0px;
4350 4351 }
4351 4352
4352 4353
4353 4354 tr.hl-comment{
4354 4355 /*
4355 4356 background-color: #FFFFCC !important;
4356 4357 */
4357 4358 }
4358 4359
4359 4360 /*
4360 4361 tr.hl-comment pre {
4361 4362 border-top: 2px solid #FFEE33;
4362 4363 border-left: 2px solid #FFEE33;
4363 4364 border-right: 2px solid #FFEE33;
4364 4365 }
4365 4366 */
4366 4367
4367 4368 .comment-inline-form strong {
4368 4369 display: block;
4369 4370 margin-bottom: 15px;
4370 4371 }
4371 4372
4372 4373 .comment-inline-form textarea {
4373 4374 width: 100%;
4374 4375 height: 100px;
4375 4376 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4376 4377 }
4377 4378
4378 4379 form.comment-inline-form {
4379 4380 margin-top: 10px;
4380 4381 margin-left: 10px;
4381 4382 }
4382 4383
4383 4384 .comment-inline-form-submit {
4384 4385 margin-top: 5px;
4385 4386 margin-left: 525px;
4386 4387 }
4387 4388
4388 4389 .file-comments {
4389 4390 display: none;
4390 4391 }
4391 4392
4392 4393 .comment-inline-form .comment {
4393 4394 margin-left: 10px;
4394 4395 }
4395 4396
4396 4397 .comment-inline-form .comment-help{
4397 4398 padding: 0px 0px 2px 0px;
4398 4399 color: #666666;
4399 4400 font-size: 10px;
4400 4401 }
4401 4402
4402 4403 .comment-inline-form .comment-button{
4403 4404 padding-top:5px;
4404 4405 }
4405 4406
4406 4407 /** comment inline **/
4407 4408 .inline-comments {
4408 4409 padding:10px 20px;
4409 4410 }
4410 4411
4411 4412 .inline-comments div.rst-block {
4412 4413 clear:both;
4413 4414 overflow:hidden;
4414 4415 margin:0;
4415 4416 padding:0 20px 0px;
4416 4417 }
4417 4418 .inline-comments .comment {
4418 4419 border: 1px solid #ddd;
4419 4420 -webkit-border-radius: 4px;
4420 4421 -moz-border-radius: 4px;
4421 4422 border-radius: 4px;
4422 4423 margin: 3px 3px 5px 5px;
4423 4424 background-color: #FAFAFA;
4424 4425 }
4425 4426 .inline-comments .add-comment {
4426 4427 padding: 2px 4px 8px 5px;
4427 4428 }
4428 4429
4429 4430 .inline-comments .comment-wrapp{
4430 4431 padding:1px;
4431 4432 }
4432 4433 .inline-comments .comment .meta {
4433 4434 background: #f8f8f8;
4434 4435 padding: 4px;
4435 4436 border-bottom: 1px solid #ddd;
4436 4437 height: 20px;
4437 4438 }
4438 4439
4439 4440 .inline-comments .comment .meta img {
4440 4441 vertical-align: middle;
4441 4442 }
4442 4443
4443 4444 .inline-comments .comment .meta .user {
4444 4445 font-weight: bold;
4445 4446 float:left;
4446 4447 padding: 3px;
4447 4448 }
4448 4449
4449 4450 .inline-comments .comment .meta .date {
4450 4451 float:left;
4451 4452 padding: 3px;
4452 4453 }
4453 4454
4454 4455 .inline-comments .comment .text {
4455 4456 background-color: #FAFAFA;
4456 4457 }
4457 4458
4458 4459 .inline-comments .comments-number{
4459 4460 padding:0px 0px 10px 0px;
4460 4461 font-weight: bold;
4461 4462 color: #666;
4462 4463 font-size: 16px;
4463 4464 }
4464 4465 .inline-comments-button .add-comment{
4465 4466 margin:2px 0px 8px 5px !important
4466 4467 }
4467 4468
4468 4469
4469 4470 .notification-paginator{
4470 4471 padding: 0px 0px 4px 16px;
4471 4472 float: left;
4472 4473 }
4473 4474
4474 4475 .notifications{
4475 4476 border-radius: 4px 4px 4px 4px;
4476 4477 -webkit-border-radius: 4px;
4477 4478 -moz-border-radius: 4px;
4478 4479 float: right;
4479 4480 margin: 20px 0px 0px 0px;
4480 4481 position: absolute;
4481 4482 text-align: center;
4482 4483 width: 26px;
4483 4484 z-index: 1000;
4484 4485 }
4485 4486 .notifications a{
4486 4487 color:#888 !important;
4487 4488 display: block;
4488 4489 font-size: 10px;
4489 4490 background-color: #DEDEDE !important;
4490 4491 border-radius: 2px !important;
4491 4492 -webkit-border-radius: 2px !important;
4492 4493 -moz-border-radius: 2px !important;
4493 4494 }
4494 4495 .notifications a:hover{
4495 4496 text-decoration: none !important;
4496 4497 background-color: #EEEFFF !important;
4497 4498 }
4498 4499 .notification-header{
4499 4500 padding-top:6px;
4500 4501 }
4501 4502 .notification-header .desc{
4502 4503 font-size: 16px;
4503 4504 height: 24px;
4504 4505 float: left
4505 4506 }
4506 4507 .notification-list .container.unread{
4507 4508 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4508 4509 }
4509 4510 .notification-header .gravatar{
4510 4511 background: none repeat scroll 0 0 transparent;
4511 4512 padding: 0px 0px 0px 8px;
4512 4513 }
4513 4514 .notification-list .container .notification-header .desc{
4514 4515 font-weight: bold;
4515 4516 font-size: 17px;
4516 4517 }
4517 4518 .notification-table{
4518 4519 border: 1px solid #ccc;
4519 4520 -webkit-border-radius: 6px 6px 6px 6px;
4520 4521 -moz-border-radius: 6px 6px 6px 6px;
4521 4522 border-radius: 6px 6px 6px 6px;
4522 4523 clear: both;
4523 4524 margin: 0px 20px 0px 20px;
4524 4525 }
4525 4526 .notification-header .delete-notifications{
4526 4527 float: right;
4527 4528 padding-top: 8px;
4528 4529 cursor: pointer;
4529 4530 }
4530 4531 .notification-header .read-notifications{
4531 4532 float: right;
4532 4533 padding-top: 8px;
4533 4534 cursor: pointer;
4534 4535 }
4535 4536 .notification-subject{
4536 4537 clear:both;
4537 4538 border-bottom: 1px solid #eee;
4538 4539 padding:5px 0px 5px 38px;
4539 4540 }
4540 4541
4541 4542 .notification-body{
4542 4543 clear:both;
4543 4544 margin: 34px 2px 2px 8px
4544 4545 }
4545 4546
4546 4547 /****
4547 4548 PULL REQUESTS
4548 4549 *****/
4549 4550 .pullrequests_section_head {
4550 4551 padding:10px 10px 10px 0px;
4551 4552 font-size:16px;
4552 4553 font-weight: bold;
4553 4554 }
4554 4555
4555 4556 /****
4556 4557 PERMS
4557 4558 *****/
4558 4559 #perms .perms_section_head {
4559 4560 padding:10px 10px 10px 0px;
4560 4561 font-size:16px;
4561 4562 font-weight: bold;
4562 4563 }
4563 4564
4564 4565 #perms .perm_tag{
4565 4566 padding: 1px 3px 1px 3px;
4566 4567 font-size: 10px;
4567 4568 font-weight: bold;
4568 4569 text-transform: uppercase;
4569 4570 white-space: nowrap;
4570 4571 -webkit-border-radius: 3px;
4571 4572 -moz-border-radius: 3px;
4572 4573 border-radius: 3px;
4573 4574 }
4574 4575
4575 4576 #perms .perm_tag.admin{
4576 4577 background-color: #B94A48;
4577 4578 color: #ffffff;
4578 4579 }
4579 4580
4580 4581 #perms .perm_tag.write{
4581 4582 background-color: #B94A48;
4582 4583 color: #ffffff;
4583 4584 }
4584 4585
4585 4586 #perms .perm_tag.read{
4586 4587 background-color: #468847;
4587 4588 color: #ffffff;
4588 4589 }
4589 4590
4590 4591 #perms .perm_tag.none{
4591 4592 background-color: #bfbfbf;
4592 4593 color: #ffffff;
4593 4594 }
4594 4595
4595 4596 .perm-gravatar{
4596 4597 vertical-align:middle;
4597 4598 padding:2px;
4598 4599 }
4599 4600 .perm-gravatar-ac{
4600 4601 vertical-align:middle;
4601 4602 padding:2px;
4602 4603 width: 14px;
4603 4604 height: 14px;
4604 4605 }
4605 4606
4606 4607 /*****************************************************************************
4607 4608 DIFFS CSS
4608 4609 ******************************************************************************/
4609 4610
4610 4611 div.diffblock {
4611 4612 overflow: auto;
4612 4613 padding: 0px;
4613 4614 border: 1px solid #ccc;
4614 4615 background: #f8f8f8;
4615 4616 font-size: 100%;
4616 4617 line-height: 100%;
4617 4618 /* new */
4618 4619 line-height: 125%;
4619 4620 -webkit-border-radius: 6px 6px 0px 0px;
4620 4621 -moz-border-radius: 6px 6px 0px 0px;
4621 4622 border-radius: 6px 6px 0px 0px;
4622 4623 }
4623 4624 div.diffblock.margined{
4624 4625 margin: 0px 20px 0px 20px;
4625 4626 }
4626 4627 div.diffblock .code-header{
4627 4628 border-bottom: 1px solid #CCCCCC;
4628 4629 background: #EEEEEE;
4629 4630 padding:10px 0 10px 0;
4630 4631 height: 14px;
4631 4632 }
4632 4633 div.diffblock .code-header.cv{
4633 4634 height: 34px;
4634 4635 }
4635 4636 div.diffblock .code-header-title{
4636 4637 padding: 0px 0px 10px 5px !important;
4637 4638 margin: 0 !important;
4638 4639 }
4639 4640 div.diffblock .code-header .hash{
4640 4641 float: left;
4641 4642 padding: 2px 0 0 2px;
4642 4643 }
4643 4644 div.diffblock .code-header .date{
4644 4645 float:left;
4645 4646 text-transform: uppercase;
4646 4647 padding: 2px 0px 0px 2px;
4647 4648 }
4648 4649 div.diffblock .code-header div{
4649 4650 margin-left:4px;
4650 4651 font-weight: bold;
4651 4652 font-size: 14px;
4652 4653 }
4653 4654 div.diffblock .code-body{
4654 4655 background: #FFFFFF;
4655 4656 }
4656 4657 div.diffblock pre.raw{
4657 4658 background: #FFFFFF;
4658 4659 color:#000000;
4659 4660 }
4660 4661 table.code-difftable{
4661 4662 border-collapse: collapse;
4662 4663 width: 99%;
4663 4664 }
4664 4665 table.code-difftable td {
4665 4666 padding: 0 !important;
4666 4667 background: none !important;
4667 4668 border:0 !important;
4668 4669 vertical-align: none !important;
4669 4670 }
4670 4671 table.code-difftable .context{
4671 4672 background:none repeat scroll 0 0 #DDE7EF;
4672 4673 }
4673 4674 table.code-difftable .add{
4674 4675 background:none repeat scroll 0 0 #DDFFDD;
4675 4676 }
4676 4677 table.code-difftable .add ins{
4677 4678 background:none repeat scroll 0 0 #AAFFAA;
4678 4679 text-decoration:none;
4679 4680 }
4680 4681 table.code-difftable .del{
4681 4682 background:none repeat scroll 0 0 #FFDDDD;
4682 4683 }
4683 4684 table.code-difftable .del del{
4684 4685 background:none repeat scroll 0 0 #FFAAAA;
4685 4686 text-decoration:none;
4686 4687 }
4687 4688
4688 4689 /** LINE NUMBERS **/
4689 4690 table.code-difftable .lineno{
4690 4691
4691 4692 padding-left:2px;
4692 4693 padding-right:2px;
4693 4694 text-align:right;
4694 4695 width:32px;
4695 4696 -moz-user-select:none;
4696 4697 -webkit-user-select: none;
4697 4698 border-right: 1px solid #CCC !important;
4698 4699 border-left: 0px solid #CCC !important;
4699 4700 border-top: 0px solid #CCC !important;
4700 4701 border-bottom: none !important;
4701 4702 vertical-align: middle !important;
4702 4703
4703 4704 }
4704 4705 table.code-difftable .lineno.new {
4705 4706 }
4706 4707 table.code-difftable .lineno.old {
4707 4708 }
4708 4709 table.code-difftable .lineno a{
4709 4710 color:#747474 !important;
4710 4711 font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4711 4712 letter-spacing:-1px;
4712 4713 text-align:right;
4713 4714 padding-right: 2px;
4714 4715 cursor: pointer;
4715 4716 display: block;
4716 4717 width: 32px;
4717 4718 }
4718 4719
4719 4720 table.code-difftable .lineno-inline{
4720 4721 background:none repeat scroll 0 0 #FFF !important;
4721 4722 padding-left:2px;
4722 4723 padding-right:2px;
4723 4724 text-align:right;
4724 4725 width:30px;
4725 4726 -moz-user-select:none;
4726 4727 -webkit-user-select: none;
4727 4728 }
4728 4729
4729 4730 /** CODE **/
4730 4731 table.code-difftable .code {
4731 4732 display: block;
4732 4733 width: 100%;
4733 4734 }
4734 4735 table.code-difftable .code td{
4735 4736 margin:0;
4736 4737 padding:0;
4737 4738 }
4738 4739 table.code-difftable .code pre{
4739 4740 margin:0;
4740 4741 padding:0;
4741 4742 height: 17px;
4742 4743 line-height: 17px;
4743 4744 }
4744 4745
4745 4746
4746 4747 .diffblock.margined.comm .line .code:hover{
4747 4748 background-color:#FFFFCC !important;
4748 4749 cursor: pointer !important;
4749 4750 background-image:url("../images/icons/comment_add.png") !important;
4750 4751 background-repeat:no-repeat !important;
4751 4752 background-position: right !important;
4752 4753 background-position: 0% 50% !important;
4753 4754 }
4754 4755 .diffblock.margined.comm .line .code.no-comment:hover{
4755 4756 background-image: none !important;
4756 4757 cursor: auto !important;
4757 4758 background-color: inherit !important;
4758 4759
4759 4760 }
@@ -1,282 +1,291 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${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(_('Repositories'),h.url('repos'))}
12 12 &raquo;
13 13 ${_('edit')} &raquo; ${h.link_to(c.repo_info.just_name,h.url('summary_home',repo_name=c.repo_name))}
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 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 27 <div class="form">
28 28 <!-- fields -->
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label">
32 32 <label for="repo_name">${_('Name')}:</label>
33 33 </div>
34 34 <div class="input">
35 35 ${h.text('repo_name',class_="medium")}
36 36 </div>
37 37 </div>
38 38 <div class="field">
39 39 <div class="label">
40 40 <label for="clone_uri">${_('Clone uri')}:</label>
41 41 </div>
42 42 <div class="input">
43 43 ${h.text('clone_uri',class_="medium")}
44 44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
45 45 </div>
46 46 </div>
47 47 <div class="field">
48 48 <div class="label">
49 49 <label for="repo_group">${_('Repository group')}:</label>
50 50 </div>
51 51 <div class="input">
52 52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
53 53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
54 54 </div>
55 55 </div>
56 56 <div class="field">
57 57 <div class="label">
58 58 <label for="repo_type">${_('Type')}:</label>
59 59 </div>
60 60 <div class="input">
61 61 ${h.select('repo_type','hg',c.backends,class_="medium")}
62 62 </div>
63 63 </div>
64 64 <div class="field">
65 65 <div class="label">
66 66 <label for="landing_rev">${_('Landing revision')}:</label>
67 67 </div>
68 68 <div class="input">
69 69 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
70 70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
71 71 </div>
72 72 </div>
73 73 <div class="field">
74 74 <div class="label label-textarea">
75 75 <label for="description">${_('Description')}:</label>
76 76 </div>
77 77 <div class="textarea text-area editor">
78 78 ${h.textarea('description')}
79 79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
80 80 </div>
81 81 </div>
82 82
83 83 <div class="field">
84 84 <div class="label label-checkbox">
85 85 <label for="private">${_('Private repository')}:</label>
86 86 </div>
87 87 <div class="checkboxes">
88 88 ${h.checkbox('private',value="True")}
89 89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
90 90 </div>
91 91 </div>
92 92 <div class="field">
93 93 <div class="label label-checkbox">
94 94 <label for="enable_statistics">${_('Enable statistics')}:</label>
95 95 </div>
96 96 <div class="checkboxes">
97 97 ${h.checkbox('enable_statistics',value="True")}
98 98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
99 99 </div>
100 100 </div>
101 101 <div class="field">
102 102 <div class="label label-checkbox">
103 103 <label for="enable_downloads">${_('Enable downloads')}:</label>
104 104 </div>
105 105 <div class="checkboxes">
106 106 ${h.checkbox('enable_downloads',value="True")}
107 107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
108 108 </div>
109 109 </div>
110 110 <div class="field">
111 111 <div class="label label-checkbox">
112 112 <label for="enable_locking">${_('Enable locking')}:</label>
113 113 </div>
114 114 <div class="checkboxes">
115 115 ${h.checkbox('enable_locking',value="True")}
116 116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
117 117 </div>
118 118 </div>
119 119 <div class="field">
120 120 <div class="label">
121 121 <label for="user">${_('Owner')}:</label>
122 122 </div>
123 123 <div class="input input-medium ac">
124 124 <div class="perm_ac">
125 125 ${h.text('user',class_='yui-ac-input')}
126 126 <span class="help-block">${_('Change owner of this repository.')}</span>
127 127 <div id="owner_container"></div>
128 128 </div>
129 129 </div>
130 130 </div>
131 131
132 132 <div class="field">
133 133 <div class="label">
134 134 <label for="input">${_('Permissions')}:</label>
135 135 </div>
136 136 <div class="input">
137 137 <%include file="repo_edit_perms.html"/>
138 138 </div>
139 139
140 140 <div class="buttons">
141 141 ${h.submit('save',_('Save'),class_="ui-btn large")}
142 142 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
143 143 </div>
144 144 </div>
145 145 </div>
146 146 </div>
147 147 ${h.end_form()}
148 148 </div>
149 149
150 150 <div class="box box-right">
151 151 <div class="title">
152 152 <h5>${_('Administration')}</h5>
153 153 </div>
154 154
155 155 <h3>${_('Statistics')}</h3>
156 156 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
157 157 <div class="form">
158 158 <div class="fields">
159 159 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
160 160 <div class="field" style="border:none;color:#888">
161 161 <ul>
162 162 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
163 163 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
164 164 </ul>
165 165 </div>
166 166 </div>
167 167 </div>
168 168 ${h.end_form()}
169 169
170 170 %if c.repo_info.clone_uri:
171 171 <h3>${_('Remote')}</h3>
172 172 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
173 173 <div class="form">
174 174 <div class="fields">
175 175 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
176 176 <div class="field" style="border:none">
177 177 <ul>
178 178 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
179 179 </ul>
180 180 </div>
181 181 </div>
182 182 </div>
183 183 ${h.end_form()}
184 184 %endif
185 185
186 186 <h3>${_('Cache')}</h3>
187 187 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
188 188 <div class="form">
189 189 <div class="fields">
190 190 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
191 191 <div class="field" style="border:none;color:#888">
192 192 <ul>
193 193 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
194 194 </li>
195 195 </ul>
196 196 </div>
197 197 <div class="field" style="border:none;">
198 198 ${_('List of cached values')}
199 <ul>
199 <table>
200 <tr>
201 <th>${_('Prefix')}</th>
202 <th>${_('Key')}</th>
203 <th>${_('Active')}</th>
204 </tr>
200 205 %for cache in c.repo_info.cache_keys:
201 <li>INSTANCE ID:${cache.prefix or '-'} ${cache.cache_args} CACHED: ${h.bool2icon(cache.cache_active)}</li>
206 <tr>
207 <td>${cache.prefix or '-'}</td>
208 <td>${cache.cache_key}</td>
209 <td>${h.bool2icon(cache.cache_active)}</td>
210 </tr>
202 211 %endfor
203 </ul>
212 </table>
204 213 </div>
205 214 </div>
206 215 </div>
207 216 ${h.end_form()}
208 217
209 218 <h3>${_('Public journal')}</h3>
210 219 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
211 220 <div class="form">
212 221 ${h.hidden('auth_token',str(h.get_token()))}
213 222 <div class="field">
214 223 %if c.in_public_journal:
215 224 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
216 225 %else:
217 226 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
218 227 %endif
219 228 </div>
220 229 <div class="field" style="border:none;color:#888">
221 230 <ul>
222 231 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
223 232 </li>
224 233 </ul>
225 234 </div>
226 235 </div>
227 236 ${h.end_form()}
228 237
229 238 <h3>${_('Locking')}</h3>
230 239 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
231 240 <div class="form">
232 241 <div class="fields">
233 242 %if c.repo_info.locked[0]:
234 243 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
235 244 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
236 245 %else:
237 246 ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
238 247 ${_('Repository is not locked')}
239 248 %endif
240 249 </div>
241 250 <div class="field" style="border:none;color:#888">
242 251 <ul>
243 252 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
244 253 </li>
245 254 </ul>
246 255 </div>
247 256 </div>
248 257 ${h.end_form()}
249 258
250 259 <h3>${_('Set as fork of')}</h3>
251 260 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
252 261 <div class="form">
253 262 <div class="fields">
254 263 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
255 264 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
256 265 </div>
257 266 <div class="field" style="border:none;color:#888">
258 267 <ul>
259 268 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
260 269 </ul>
261 270 </div>
262 271 </div>
263 272 ${h.end_form()}
264 273
265 274 <h3>${_('Delete')}</h3>
266 275 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
267 276 <div class="form">
268 277 <div class="fields">
269 278 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
270 279 </div>
271 280 <div class="field" style="border:none;color:#888">
272 281 <ul>
273 282 <li>${_('''This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems.
274 283 If you need fully delete it from filesystem please do it manually''')}
275 284 </li>
276 285 </ul>
277 286 </div>
278 287 </div>
279 288 ${h.end_form()}
280 289 </div>
281 290
282 291 </%def>
General Comments 0
You need to be logged in to leave comments. Login now