##// END OF EJS Templates
#47 implemented Adding of new repo_groups+forms+validators. Fixed sorting of repo groups by main names in multiple locations. Removed some unneeded calls to self.sa for exchange to .query() methods....
marcink -
r1345:3bce31f0 beta
parent child Browse files
Show More
@@ -0,0 +1,133 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.user_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 users groups model for RhodeCode
7
8 :created_on: Jan 25, 2011
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 import os
27 import logging
28 import traceback
29
30 from pylons.i18n.translation import _
31
32 from vcs.utils.lazy import LazyProperty
33
34 from rhodecode.model import BaseModel
35 from rhodecode.model.caching_query import FromCache
36 from rhodecode.model.db import Group, RhodeCodeUi
37
38 log = logging.getLogger(__name__)
39
40
41 class ReposGroupModel(BaseModel):
42
43 @LazyProperty
44 def repos_path(self):
45 """
46 Get's the repositories root path from database
47 """
48
49 q = RhodeCodeUi.get_by_key('/').one()
50 return q.ui_value
51
52 def __create_group(self, group_name, parent_id):
53 """
54 makes repositories group on filesystem
55
56 :param repo_name:
57 :param parent_id:
58 """
59
60 if parent_id:
61 parent_group_name = Group.get(parent_id).group_name
62 else:
63 parent_group_name = ''
64
65 create_path = os.path.join(self.repos_path, parent_group_name,
66 group_name)
67 log.debug('creating new group in %s', create_path)
68
69 if os.path.isdir(create_path):
70 raise Exception('That directory already exists !')
71
72
73 os.makedirs(create_path)
74
75
76 def __rename_group(self, group_name):
77 """
78 Renames a group on filesystem
79
80 :param group_name:
81 """
82 pass
83
84 def __delete_group(self, group_name):
85 """
86 Deletes a group from a filesystem
87
88 :param group_name:
89 """
90 pass
91
92 def create(self, form_data):
93 try:
94 new_repos_group = Group()
95 new_repos_group.group_name = form_data['repos_group_name']
96 new_repos_group.group_description = \
97 form_data['repos_group_description']
98 new_repos_group.group_parent_id = form_data['repos_group_parent']
99
100 self.sa.add(new_repos_group)
101
102 self.__create_group(form_data['repos_group_name'],
103 form_data['repos_group_parent'])
104
105 self.sa.commit()
106 except:
107 log.error(traceback.format_exc())
108 self.sa.rollback()
109 raise
110
111 def update(self, repos_group_id, form_data):
112
113 try:
114 repos_group = Group.get(repos_group_id)
115
116
117
118 self.sa.add(repos_group)
119 self.sa.commit()
120 except:
121 log.error(traceback.format_exc())
122 self.sa.rollback()
123 raise
124
125 def delete(self, users_group_id):
126 try:
127 users_group = self.get(users_group_id, cache=False)
128 self.sa.delete(users_group)
129 self.sa.commit()
130 except:
131 log.error(traceback.format_exc())
132 self.sa.rollback()
133 raise
@@ -0,0 +1,64 b''
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3
4 <%def name="title()">
5 ${_('Add repos group')} - ${c.rhodecode_name}
6 </%def>
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 &raquo;
10 ${h.link_to(_('Repos groups'),h.url('repos_groups'))}
11 &raquo;
12 ${_('add new repos group')}
13 </%def>
14
15 <%def name="page_nav()">
16 ${self.menu('admin')}
17 </%def>
18
19 <%def name="main()">
20 <div class="box">
21 <!-- box / title -->
22 <div class="title">
23 ${self.breadcrumbs()}
24 </div>
25 <!-- end box / title -->
26 ${h.form(url('repos_groups'))}
27 <div class="form">
28 <!-- fields -->
29 <div class="fields">
30 <div class="field">
31 <div class="label">
32 <label for="users_group_name">${_('Group name')}:</label>
33 </div>
34 <div class="input">
35 ${h.text('repos_group_name',class_='medium')}
36 </div>
37 </div>
38
39 <div class="field">
40 <div class="label label-textarea">
41 <label for="description">${_('Description')}:</label>
42 </div>
43 <div class="textarea text-area editor">
44 ${h.textarea('repos_group_description',cols=23,rows=5,class_="medium")}
45 </div>
46 </div>
47
48 <div class="field">
49 <div class="label">
50 <label for="repo_group">${_('Group parent')}:</label>
51 </div>
52 <div class="input">
53 ${h.select('repos_group_parent','',c.repo_groups,class_="medium")}
54 </div>
55 </div>
56
57 <div class="buttons">
58 ${h.submit('save','save',class_="ui-button")}
59 </div>
60 </div>
61 </div>
62 ${h.end_form()}
63 </div>
64 </%def> No newline at end of file
@@ -0,0 +1,68 b''
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3
4 <%def name="title()">
5 ${_('Repositories groups administration')} - ${c.rhodecode_name}
6 </%def>
7
8
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Repositories')}
11 </%def>
12 <%def name="page_nav()">
13 ${self.menu('admin')}
14 </%def>
15 <%def name="main()">
16 <div class="box">
17 <!-- box / title -->
18 <div class="title">
19 ${self.breadcrumbs()}
20 <ul class="links">
21 <li>
22 <span>${h.link_to(u'ADD NEW GROUP',h.url('new_repos_group'))}</span>
23 </li>
24 </ul>
25 </div>
26 <!-- end box / title -->
27 <div class="table">
28 % if c.groups:
29 <table class="table_disp">
30
31 <thead>
32 <tr>
33 <th class="left"><a href="#">${_('Group name')}</a></th>
34 <th class="left"><a href="#">${_('Description')}</a></th>
35 <th class="left"><a href="#">${_('Number of repositories')}</a></th>
36 <th class="left">${_('action')}</th>
37 </tr>
38 </thead>
39
40 ## REPO GROUPS
41
42 % for gr in c.groups:
43 <tr>
44 <td>
45 <div style="white-space: nowrap">
46 <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
47 ${h.link_to(h.literal(' &raquo; '.join([g.group_name for g in gr.parents+[gr]])),url('edit_repos_group',id=gr.group_id))}
48 </div>
49 </td>
50 <td>${gr.group_description}</td>
51 <td><b>${gr.repositories.count()}</b></td>
52 <td>
53 ${h.form(url('repos_group', id=gr.group_id),method='delete')}
54 ${h.submit('remove_%s' % gr.group_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this group');")}
55 ${h.end_form()}
56 </td>
57 </tr>
58 % endfor
59
60 </table>
61 % else:
62 {_('There are no repositories groups yet')}
63 % endif
64
65 </div>
66 </div>
67
68 </%def>
@@ -1,418 +1,420 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Admin controller for RhodeCode
6 Admin controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29 from operator import itemgetter
29 from operator import itemgetter
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from paste.httpexceptions import HTTPInternalServerError
32 from paste.httpexceptions import HTTPInternalServerError
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 HasPermissionAnyDecorator
39 HasPermissionAnyDecorator
40 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
41 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
42 from rhodecode.lib.helpers import get_token
42 from rhodecode.lib.helpers import get_token
43 from rhodecode.model.db import User, Repository, UserFollowing, Group
43 from rhodecode.model.db import User, Repository, UserFollowing, Group
44 from rhodecode.model.forms import RepoForm
44 from rhodecode.model.forms import RepoForm
45 from rhodecode.model.scm import ScmModel
45 from rhodecode.model.scm import ScmModel
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class ReposController(BaseController):
51 class ReposController(BaseController):
52 """
52 """
53 REST Controller styled on the Atom Publishing Protocol"""
53 REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
55 # file has a resource setup:
56 # map.resource('repo', 'repos')
56 # map.resource('repo', 'repos')
57
57
58 @LoginRequired()
58 @LoginRequired()
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 def __before__(self):
60 def __before__(self):
61 c.admin_user = session.get('admin_user')
61 c.admin_user = session.get('admin_user')
62 c.admin_username = session.get('admin_username')
62 c.admin_username = session.get('admin_username')
63 super(ReposController, self).__before__()
63 super(ReposController, self).__before__()
64
64
65 def __load_defaults(self):
65 def __load_defaults(self):
66 repo_model = RepoModel()
66 repo_model = RepoModel()
67
67
68 c.repo_groups = [('', '')]
68 c.repo_groups = [('', '')]
69 parents_link = lambda k: h.literal('&raquo;'.join(
69 parents_link = lambda k: h.literal('&raquo;'.join(
70 map(lambda k: k.group_name,
70 map(lambda k: k.group_name,
71 k.parents + [k])
71 k.parents + [k])
72 )
72 )
73 )
73 )
74
74
75 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
75 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
76 x in self.sa.query(Group).all()])
76 x in self.sa.query(Group).all()])
77 c.repo_groups = sorted(c.repo_groups,
78 key=lambda t: t[1].split('&raquo;')[0])
77 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
79 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
78 c.users_array = repo_model.get_users_js()
80 c.users_array = repo_model.get_users_js()
79 c.users_groups_array = repo_model.get_users_groups_js()
81 c.users_groups_array = repo_model.get_users_groups_js()
80
82
81 def __load_data(self, repo_name=None):
83 def __load_data(self, repo_name=None):
82 """
84 """
83 Load defaults settings for edit, and update
85 Load defaults settings for edit, and update
84
86
85 :param repo_name:
87 :param repo_name:
86 """
88 """
87 self.__load_defaults()
89 self.__load_defaults()
88
90
89 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
91 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
90
92
91 repo_model = RepoModel()
93 repo_model = RepoModel()
92 c.repo_info = repo_model.get_by_repo_name(repo_name)
94 c.repo_info = repo_model.get_by_repo_name(repo_name)
93
95
94 if c.repo_info is None:
96 if c.repo_info is None:
95 h.flash(_('%s repository is not mapped to db perhaps'
97 h.flash(_('%s repository is not mapped to db perhaps'
96 ' it was created or renamed from the filesystem'
98 ' it was created or renamed from the filesystem'
97 ' please run the application again'
99 ' please run the application again'
98 ' in order to rescan repositories') % repo_name,
100 ' in order to rescan repositories') % repo_name,
99 category='error')
101 category='error')
100
102
101 return redirect(url('repos'))
103 return redirect(url('repos'))
102
104
103 c.default_user_id = User.by_username('default').user_id
105 c.default_user_id = User.by_username('default').user_id
104 c.in_public_journal = self.sa.query(UserFollowing)\
106 c.in_public_journal = self.sa.query(UserFollowing)\
105 .filter(UserFollowing.user_id == c.default_user_id)\
107 .filter(UserFollowing.user_id == c.default_user_id)\
106 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
108 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
107
109
108 if c.repo_info.stats:
110 if c.repo_info.stats:
109 last_rev = c.repo_info.stats.stat_on_revision
111 last_rev = c.repo_info.stats.stat_on_revision
110 else:
112 else:
111 last_rev = 0
113 last_rev = 0
112 c.stats_revision = last_rev
114 c.stats_revision = last_rev
113
115
114 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
116 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
115
117
116 if last_rev == 0 or c.repo_last_rev == 0:
118 if last_rev == 0 or c.repo_last_rev == 0:
117 c.stats_percentage = 0
119 c.stats_percentage = 0
118 else:
120 else:
119 c.stats_percentage = '%.2f' % ((float((last_rev)) /
121 c.stats_percentage = '%.2f' % ((float((last_rev)) /
120 c.repo_last_rev) * 100)
122 c.repo_last_rev) * 100)
121
123
122 defaults = c.repo_info.get_dict()
124 defaults = c.repo_info.get_dict()
123 group, repo_name = c.repo_info.groups_and_repo
125 group, repo_name = c.repo_info.groups_and_repo
124 defaults['repo_name'] = repo_name
126 defaults['repo_name'] = repo_name
125 defaults['repo_group'] = getattr(group[-1] if group else None,
127 defaults['repo_group'] = getattr(group[-1] if group else None,
126 'group_id', None)
128 'group_id', None)
127
129
128 #fill owner
130 #fill owner
129 if c.repo_info.user:
131 if c.repo_info.user:
130 defaults.update({'user': c.repo_info.user.username})
132 defaults.update({'user': c.repo_info.user.username})
131 else:
133 else:
132 replacement_user = self.sa.query(User)\
134 replacement_user = self.sa.query(User)\
133 .filter(User.admin == True).first().username
135 .filter(User.admin == True).first().username
134 defaults.update({'user': replacement_user})
136 defaults.update({'user': replacement_user})
135
137
136 #fill repository users
138 #fill repository users
137 for p in c.repo_info.repo_to_perm:
139 for p in c.repo_info.repo_to_perm:
138 defaults.update({'u_perm_%s' % p.user.username:
140 defaults.update({'u_perm_%s' % p.user.username:
139 p.permission.permission_name})
141 p.permission.permission_name})
140
142
141 #fill repository groups
143 #fill repository groups
142 for p in c.repo_info.users_group_to_perm:
144 for p in c.repo_info.users_group_to_perm:
143 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
145 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
144 p.permission.permission_name})
146 p.permission.permission_name})
145
147
146 return defaults
148 return defaults
147
149
148 @HasPermissionAllDecorator('hg.admin')
150 @HasPermissionAllDecorator('hg.admin')
149 def index(self, format='html'):
151 def index(self, format='html'):
150 """GET /repos: All items in the collection"""
152 """GET /repos: All items in the collection"""
151 # url('repos')
153 # url('repos')
152
154
153 all_repos = [r.repo_name for r in Repository.query().all()]
155 all_repos = [r.repo_name for r in Repository.query().all()]
154
156
155 cached_repo_list = ScmModel().get_repos(all_repos)
157 cached_repo_list = ScmModel().get_repos(all_repos)
156 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
158 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
157 return render('admin/repos/repos.html')
159 return render('admin/repos/repos.html')
158
160
159 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
161 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
160 def create(self):
162 def create(self):
161 """
163 """
162 POST /repos: Create a new item"""
164 POST /repos: Create a new item"""
163 # url('repos')
165 # url('repos')
164 repo_model = RepoModel()
166 repo_model = RepoModel()
165 self.__load_defaults()
167 self.__load_defaults()
166 form_result = {}
168 form_result = {}
167 try:
169 try:
168 form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
170 form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
169 .to_python(dict(request.POST))
171 .to_python(dict(request.POST))
170 repo_model.create(form_result, self.rhodecode_user)
172 repo_model.create(form_result, self.rhodecode_user)
171 if form_result['clone_uri']:
173 if form_result['clone_uri']:
172 h.flash(_('created repository %s from %s') \
174 h.flash(_('created repository %s from %s') \
173 % (form_result['repo_name'], form_result['clone_uri']),
175 % (form_result['repo_name'], form_result['clone_uri']),
174 category='success')
176 category='success')
175 else:
177 else:
176 h.flash(_('created repository %s') % form_result['repo_name'],
178 h.flash(_('created repository %s') % form_result['repo_name'],
177 category='success')
179 category='success')
178
180
179 if request.POST.get('user_created'):
181 if request.POST.get('user_created'):
180 action_logger(self.rhodecode_user, 'user_created_repo',
182 action_logger(self.rhodecode_user, 'user_created_repo',
181 form_result['repo_name'], '', self.sa)
183 form_result['repo_name'], '', self.sa)
182 else:
184 else:
183 action_logger(self.rhodecode_user, 'admin_created_repo',
185 action_logger(self.rhodecode_user, 'admin_created_repo',
184 form_result['repo_name'], '', self.sa)
186 form_result['repo_name'], '', self.sa)
185
187
186 except formencode.Invalid, errors:
188 except formencode.Invalid, errors:
187
189
188 c.new_repo = errors.value['repo_name']
190 c.new_repo = errors.value['repo_name']
189
191
190 if request.POST.get('user_created'):
192 if request.POST.get('user_created'):
191 r = render('admin/repos/repo_add_create_repository.html')
193 r = render('admin/repos/repo_add_create_repository.html')
192 else:
194 else:
193 r = render('admin/repos/repo_add.html')
195 r = render('admin/repos/repo_add.html')
194
196
195 return htmlfill.render(
197 return htmlfill.render(
196 r,
198 r,
197 defaults=errors.value,
199 defaults=errors.value,
198 errors=errors.error_dict or {},
200 errors=errors.error_dict or {},
199 prefix_error=False,
201 prefix_error=False,
200 encoding="UTF-8")
202 encoding="UTF-8")
201
203
202 except Exception:
204 except Exception:
203 log.error(traceback.format_exc())
205 log.error(traceback.format_exc())
204 msg = _('error occurred during creation of repository %s') \
206 msg = _('error occurred during creation of repository %s') \
205 % form_result.get('repo_name')
207 % form_result.get('repo_name')
206 h.flash(msg, category='error')
208 h.flash(msg, category='error')
207 if request.POST.get('user_created'):
209 if request.POST.get('user_created'):
208 return redirect(url('home'))
210 return redirect(url('home'))
209 return redirect(url('repos'))
211 return redirect(url('repos'))
210
212
211 @HasPermissionAllDecorator('hg.admin')
213 @HasPermissionAllDecorator('hg.admin')
212 def new(self, format='html'):
214 def new(self, format='html'):
213 """GET /repos/new: Form to create a new item"""
215 """GET /repos/new: Form to create a new item"""
214 new_repo = request.GET.get('repo', '')
216 new_repo = request.GET.get('repo', '')
215 c.new_repo = repo_name_slug(new_repo)
217 c.new_repo = repo_name_slug(new_repo)
216 self.__load_defaults()
218 self.__load_defaults()
217 return render('admin/repos/repo_add.html')
219 return render('admin/repos/repo_add.html')
218
220
219 @HasPermissionAllDecorator('hg.admin')
221 @HasPermissionAllDecorator('hg.admin')
220 def update(self, repo_name):
222 def update(self, repo_name):
221 """
223 """
222 PUT /repos/repo_name: Update an existing item"""
224 PUT /repos/repo_name: Update an existing item"""
223 # Forms posted to this method should contain a hidden field:
225 # Forms posted to this method should contain a hidden field:
224 # <input type="hidden" name="_method" value="PUT" />
226 # <input type="hidden" name="_method" value="PUT" />
225 # Or using helpers:
227 # Or using helpers:
226 # h.form(url('repo', repo_name=ID),
228 # h.form(url('repo', repo_name=ID),
227 # method='put')
229 # method='put')
228 # url('repo', repo_name=ID)
230 # url('repo', repo_name=ID)
229 self.__load_defaults()
231 self.__load_defaults()
230 repo_model = RepoModel()
232 repo_model = RepoModel()
231 changed_name = repo_name
233 changed_name = repo_name
232 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
234 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
233 repo_groups=c.repo_groups_choices)()
235 repo_groups=c.repo_groups_choices)()
234 try:
236 try:
235 form_result = _form.to_python(dict(request.POST))
237 form_result = _form.to_python(dict(request.POST))
236 repo_model.update(repo_name, form_result)
238 repo_model.update(repo_name, form_result)
237 invalidate_cache('get_repo_cached_%s' % repo_name)
239 invalidate_cache('get_repo_cached_%s' % repo_name)
238 h.flash(_('Repository %s updated successfully' % repo_name),
240 h.flash(_('Repository %s updated successfully' % repo_name),
239 category='success')
241 category='success')
240 changed_name = form_result['repo_name_full']
242 changed_name = form_result['repo_name_full']
241 action_logger(self.rhodecode_user, 'admin_updated_repo',
243 action_logger(self.rhodecode_user, 'admin_updated_repo',
242 changed_name, '', self.sa)
244 changed_name, '', self.sa)
243
245
244 except formencode.Invalid, errors:
246 except formencode.Invalid, errors:
245 defaults = self.__load_data(repo_name)
247 defaults = self.__load_data(repo_name)
246 defaults.update(errors.value)
248 defaults.update(errors.value)
247 return htmlfill.render(
249 return htmlfill.render(
248 render('admin/repos/repo_edit.html'),
250 render('admin/repos/repo_edit.html'),
249 defaults=defaults,
251 defaults=defaults,
250 errors=errors.error_dict or {},
252 errors=errors.error_dict or {},
251 prefix_error=False,
253 prefix_error=False,
252 encoding="UTF-8")
254 encoding="UTF-8")
253
255
254 except Exception:
256 except Exception:
255 log.error(traceback.format_exc())
257 log.error(traceback.format_exc())
256 h.flash(_('error occurred during update of repository %s') \
258 h.flash(_('error occurred during update of repository %s') \
257 % repo_name, category='error')
259 % repo_name, category='error')
258 return redirect(url('edit_repo', repo_name=changed_name))
260 return redirect(url('edit_repo', repo_name=changed_name))
259
261
260 @HasPermissionAllDecorator('hg.admin')
262 @HasPermissionAllDecorator('hg.admin')
261 def delete(self, repo_name):
263 def delete(self, repo_name):
262 """
264 """
263 DELETE /repos/repo_name: Delete an existing item"""
265 DELETE /repos/repo_name: Delete an existing item"""
264 # Forms posted to this method should contain a hidden field:
266 # Forms posted to this method should contain a hidden field:
265 # <input type="hidden" name="_method" value="DELETE" />
267 # <input type="hidden" name="_method" value="DELETE" />
266 # Or using helpers:
268 # Or using helpers:
267 # h.form(url('repo', repo_name=ID),
269 # h.form(url('repo', repo_name=ID),
268 # method='delete')
270 # method='delete')
269 # url('repo', repo_name=ID)
271 # url('repo', repo_name=ID)
270
272
271 repo_model = RepoModel()
273 repo_model = RepoModel()
272 repo = repo_model.get_by_repo_name(repo_name)
274 repo = repo_model.get_by_repo_name(repo_name)
273 if not repo:
275 if not repo:
274 h.flash(_('%s repository is not mapped to db perhaps'
276 h.flash(_('%s repository is not mapped to db perhaps'
275 ' it was moved or renamed from the filesystem'
277 ' it was moved or renamed from the filesystem'
276 ' please run the application again'
278 ' please run the application again'
277 ' in order to rescan repositories') % repo_name,
279 ' in order to rescan repositories') % repo_name,
278 category='error')
280 category='error')
279
281
280 return redirect(url('repos'))
282 return redirect(url('repos'))
281 try:
283 try:
282 action_logger(self.rhodecode_user, 'admin_deleted_repo',
284 action_logger(self.rhodecode_user, 'admin_deleted_repo',
283 repo_name, '', self.sa)
285 repo_name, '', self.sa)
284 repo_model.delete(repo)
286 repo_model.delete(repo)
285 invalidate_cache('get_repo_cached_%s' % repo_name)
287 invalidate_cache('get_repo_cached_%s' % repo_name)
286 h.flash(_('deleted repository %s') % repo_name, category='success')
288 h.flash(_('deleted repository %s') % repo_name, category='success')
287
289
288 except Exception, e:
290 except Exception, e:
289 log.error(traceback.format_exc())
291 log.error(traceback.format_exc())
290 h.flash(_('An error occurred during deletion of %s') % repo_name,
292 h.flash(_('An error occurred during deletion of %s') % repo_name,
291 category='error')
293 category='error')
292
294
293 return redirect(url('repos'))
295 return redirect(url('repos'))
294
296
295 @HasPermissionAllDecorator('hg.admin')
297 @HasPermissionAllDecorator('hg.admin')
296 def delete_perm_user(self, repo_name):
298 def delete_perm_user(self, repo_name):
297 """
299 """
298 DELETE an existing repository permission user
300 DELETE an existing repository permission user
299
301
300 :param repo_name:
302 :param repo_name:
301 """
303 """
302
304
303 try:
305 try:
304 repo_model = RepoModel()
306 repo_model = RepoModel()
305 repo_model.delete_perm_user(request.POST, repo_name)
307 repo_model.delete_perm_user(request.POST, repo_name)
306 except Exception, e:
308 except Exception, e:
307 h.flash(_('An error occurred during deletion of repository user'),
309 h.flash(_('An error occurred during deletion of repository user'),
308 category='error')
310 category='error')
309 raise HTTPInternalServerError()
311 raise HTTPInternalServerError()
310
312
311 @HasPermissionAllDecorator('hg.admin')
313 @HasPermissionAllDecorator('hg.admin')
312 def delete_perm_users_group(self, repo_name):
314 def delete_perm_users_group(self, repo_name):
313 """
315 """
314 DELETE an existing repository permission users group
316 DELETE an existing repository permission users group
315
317
316 :param repo_name:
318 :param repo_name:
317 """
319 """
318 try:
320 try:
319 repo_model = RepoModel()
321 repo_model = RepoModel()
320 repo_model.delete_perm_users_group(request.POST, repo_name)
322 repo_model.delete_perm_users_group(request.POST, repo_name)
321 except Exception, e:
323 except Exception, e:
322 h.flash(_('An error occurred during deletion of repository'
324 h.flash(_('An error occurred during deletion of repository'
323 ' users groups'),
325 ' users groups'),
324 category='error')
326 category='error')
325 raise HTTPInternalServerError()
327 raise HTTPInternalServerError()
326
328
327 @HasPermissionAllDecorator('hg.admin')
329 @HasPermissionAllDecorator('hg.admin')
328 def repo_stats(self, repo_name):
330 def repo_stats(self, repo_name):
329 """
331 """
330 DELETE an existing repository statistics
332 DELETE an existing repository statistics
331
333
332 :param repo_name:
334 :param repo_name:
333 """
335 """
334
336
335 try:
337 try:
336 repo_model = RepoModel()
338 repo_model = RepoModel()
337 repo_model.delete_stats(repo_name)
339 repo_model.delete_stats(repo_name)
338 except Exception, e:
340 except Exception, e:
339 h.flash(_('An error occurred during deletion of repository stats'),
341 h.flash(_('An error occurred during deletion of repository stats'),
340 category='error')
342 category='error')
341 return redirect(url('edit_repo', repo_name=repo_name))
343 return redirect(url('edit_repo', repo_name=repo_name))
342
344
343 @HasPermissionAllDecorator('hg.admin')
345 @HasPermissionAllDecorator('hg.admin')
344 def repo_cache(self, repo_name):
346 def repo_cache(self, repo_name):
345 """
347 """
346 INVALIDATE existing repository cache
348 INVALIDATE existing repository cache
347
349
348 :param repo_name:
350 :param repo_name:
349 """
351 """
350
352
351 try:
353 try:
352 ScmModel().mark_for_invalidation(repo_name)
354 ScmModel().mark_for_invalidation(repo_name)
353 except Exception, e:
355 except Exception, e:
354 h.flash(_('An error occurred during cache invalidation'),
356 h.flash(_('An error occurred during cache invalidation'),
355 category='error')
357 category='error')
356 return redirect(url('edit_repo', repo_name=repo_name))
358 return redirect(url('edit_repo', repo_name=repo_name))
357
359
358 @HasPermissionAllDecorator('hg.admin')
360 @HasPermissionAllDecorator('hg.admin')
359 def repo_public_journal(self, repo_name):
361 def repo_public_journal(self, repo_name):
360 """
362 """
361 Set's this repository to be visible in public journal,
363 Set's this repository to be visible in public journal,
362 in other words assing default user to follow this repo
364 in other words assing default user to follow this repo
363
365
364 :param repo_name:
366 :param repo_name:
365 """
367 """
366
368
367 cur_token = request.POST.get('auth_token')
369 cur_token = request.POST.get('auth_token')
368 token = get_token()
370 token = get_token()
369 if cur_token == token:
371 if cur_token == token:
370 try:
372 try:
371 repo_id = Repository.by_repo_name(repo_name).repo_id
373 repo_id = Repository.by_repo_name(repo_name).repo_id
372 user_id = User.by_username('default').user_id
374 user_id = User.by_username('default').user_id
373 self.scm_model.toggle_following_repo(repo_id, user_id)
375 self.scm_model.toggle_following_repo(repo_id, user_id)
374 h.flash(_('Updated repository visibility in public journal'),
376 h.flash(_('Updated repository visibility in public journal'),
375 category='success')
377 category='success')
376 except:
378 except:
377 h.flash(_('An error occurred during setting this'
379 h.flash(_('An error occurred during setting this'
378 ' repository in public journal'),
380 ' repository in public journal'),
379 category='error')
381 category='error')
380
382
381 else:
383 else:
382 h.flash(_('Token mismatch'), category='error')
384 h.flash(_('Token mismatch'), category='error')
383 return redirect(url('edit_repo', repo_name=repo_name))
385 return redirect(url('edit_repo', repo_name=repo_name))
384
386
385 @HasPermissionAllDecorator('hg.admin')
387 @HasPermissionAllDecorator('hg.admin')
386 def repo_pull(self, repo_name):
388 def repo_pull(self, repo_name):
387 """
389 """
388 Runs task to update given repository with remote changes,
390 Runs task to update given repository with remote changes,
389 ie. make pull on remote location
391 ie. make pull on remote location
390
392
391 :param repo_name:
393 :param repo_name:
392 """
394 """
393 try:
395 try:
394 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
396 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
395 h.flash(_('Pulled from remote location'), category='success')
397 h.flash(_('Pulled from remote location'), category='success')
396 except Exception, e:
398 except Exception, e:
397 h.flash(_('An error occurred during pull from remote location'),
399 h.flash(_('An error occurred during pull from remote location'),
398 category='error')
400 category='error')
399
401
400 return redirect(url('edit_repo', repo_name=repo_name))
402 return redirect(url('edit_repo', repo_name=repo_name))
401
403
402 @HasPermissionAllDecorator('hg.admin')
404 @HasPermissionAllDecorator('hg.admin')
403 def show(self, repo_name, format='html'):
405 def show(self, repo_name, format='html'):
404 """GET /repos/repo_name: Show a specific item"""
406 """GET /repos/repo_name: Show a specific item"""
405 # url('repo', repo_name=ID)
407 # url('repo', repo_name=ID)
406
408
407 @HasPermissionAllDecorator('hg.admin')
409 @HasPermissionAllDecorator('hg.admin')
408 def edit(self, repo_name, format='html'):
410 def edit(self, repo_name, format='html'):
409 """GET /repos/repo_name/edit: Form to edit an existing item"""
411 """GET /repos/repo_name/edit: Form to edit an existing item"""
410 # url('edit_repo', repo_name=ID)
412 # url('edit_repo', repo_name=ID)
411 defaults = self.__load_data(repo_name)
413 defaults = self.__load_data(repo_name)
412
414
413 return htmlfill.render(
415 return htmlfill.render(
414 render('admin/repos/repo_edit.html'),
416 render('admin/repos/repo_edit.html'),
415 defaults=defaults,
417 defaults=defaults,
416 encoding="UTF-8",
418 encoding="UTF-8",
417 force_defaults=False
419 force_defaults=False
418 )
420 )
@@ -1,93 +1,160 b''
1 import logging
1 import logging
2 import traceback
3 import formencode
4
5 from formencode import htmlfill
2 from operator import itemgetter
6 from operator import itemgetter
3
7
4 from pylons import request, response, session, tmpl_context as c, url
8 from pylons import request, response, session, tmpl_context as c, url
5 from pylons.controllers.util import abort, redirect
9 from pylons.controllers.util import abort, redirect
10 from pylons.i18n.translation import _
6
11
12 from rhodecode.lib import helpers as h
13 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
14 HasPermissionAnyDecorator
7 from rhodecode.lib.base import BaseController, render
15 from rhodecode.lib.base import BaseController, render
8 from rhodecode.model.db import Group
16 from rhodecode.model.db import Group
17 from rhodecode.model.repos_group import ReposGroupModel
18 from rhodecode.model.forms import ReposGroupForm
9
19
10 log = logging.getLogger(__name__)
20 log = logging.getLogger(__name__)
11
21
12
22
13 class ReposGroupsController(BaseController):
23 class ReposGroupsController(BaseController):
14 """REST Controller styled on the Atom Publishing Protocol"""
24 """REST Controller styled on the Atom Publishing Protocol"""
15 # To properly map this controller, ensure your config/routing.py
25 # To properly map this controller, ensure your config/routing.py
16 # file has a resource setup:
26 # file has a resource setup:
17 # map.resource('repos_group', 'repos_groups')
27 # map.resource('repos_group', 'repos_groups')
18
28
29 def __load_defaults(self):
30
31 c.repo_groups = [('', '')]
32 parents_link = lambda k: h.literal('&raquo;'.join(
33 map(lambda k: k.group_name,
34 k.parents + [k])
35 )
36 )
37
38 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
39 x in self.sa.query(Group).all()])
40
41 c.repo_groups = sorted(c.repo_groups,
42 key=lambda t: t[1].split('&raquo;')[0])
43 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
44
45 @LoginRequired()
46 def __before__(self):
47 super(ReposGroupsController, self).__before__()
48
49 @HasPermissionAnyDecorator('hg.admin')
19 def index(self, format='html'):
50 def index(self, format='html'):
20 """GET /repos_groups: All items in the collection"""
51 """GET /repos_groups: All items in the collection"""
21 # url('repos_groups')
52 # url('repos_groups')
22
53
54 sk = lambda g:g.parents[0].group_name if g.parents else g.group_name
55 c.groups = sorted(Group.query().all(), key=sk)
56 return render('admin/repos_groups/repos_groups_show.html')
57
58 @HasPermissionAnyDecorator('hg.admin')
23 def create(self):
59 def create(self):
24 """POST /repos_groups: Create a new item"""
60 """POST /repos_groups: Create a new item"""
25 # url('repos_groups')
61 # url('repos_groups')
62 self.__load_defaults()
63 repos_group_model = ReposGroupModel()
64 repos_group_form = ReposGroupForm(available_groups=
65 c.repo_groups_choices)()
66 try:
67 form_result = repos_group_form.to_python(dict(request.POST))
68 repos_group_model.create(form_result)
69 h.flash(_('created repos group %s') \
70 % form_result['repos_group_name'], category='success')
71 #TODO: in futureaction_logger(, '', '', '', self.sa)
72 except formencode.Invalid, errors:
26
73
74 return htmlfill.render(
75 render('admin/repos_groups/repos_groups_add.html'),
76 defaults=errors.value,
77 errors=errors.error_dict or {},
78 prefix_error=False,
79 encoding="UTF-8")
80 except Exception:
81 log.error(traceback.format_exc())
82 h.flash(_('error occurred during creation of repos group %s') \
83 % request.POST.get('repos_group_name'), category='error')
84
85 return redirect(url('repos_groups'))
86
87
88 @HasPermissionAnyDecorator('hg.admin')
27 def new(self, format='html'):
89 def new(self, format='html'):
28 """GET /repos_groups/new: Form to create a new item"""
90 """GET /repos_groups/new: Form to create a new item"""
29 # url('new_repos_group')
91 # url('new_repos_group')
92 self.__load_defaults()
93 return render('admin/repos_groups/repos_groups_add.html')
30
94
95 @HasPermissionAnyDecorator('hg.admin')
31 def update(self, id):
96 def update(self, id):
32 """PUT /repos_groups/id: Update an existing item"""
97 """PUT /repos_groups/id: Update an existing item"""
33 # Forms posted to this method should contain a hidden field:
98 # Forms posted to this method should contain a hidden field:
34 # <input type="hidden" name="_method" value="PUT" />
99 # <input type="hidden" name="_method" value="PUT" />
35 # Or using helpers:
100 # Or using helpers:
36 # h.form(url('repos_group', id=ID),
101 # h.form(url('repos_group', id=ID),
37 # method='put')
102 # method='put')
38 # url('repos_group', id=ID)
103 # url('repos_group', id=ID)
39
104
105 @HasPermissionAnyDecorator('hg.admin')
40 def delete(self, id):
106 def delete(self, id):
41 """DELETE /repos_groups/id: Delete an existing item"""
107 """DELETE /repos_groups/id: Delete an existing item"""
42 # Forms posted to this method should contain a hidden field:
108 # Forms posted to this method should contain a hidden field:
43 # <input type="hidden" name="_method" value="DELETE" />
109 # <input type="hidden" name="_method" value="DELETE" />
44 # Or using helpers:
110 # Or using helpers:
45 # h.form(url('repos_group', id=ID),
111 # h.form(url('repos_group', id=ID),
46 # method='delete')
112 # method='delete')
47 # url('repos_group', id=ID)
113 # url('repos_group', id=ID)
48
114
49 def show(self, id, format='html'):
115 def show(self, id, format='html'):
50 """GET /repos_groups/id: Show a specific item"""
116 """GET /repos_groups/id: Show a specific item"""
51 # url('repos_group', id=ID)
117 # url('repos_group', id=ID)
52
118
53 c.group = Group.get(id)
119 c.group = Group.get(id)
54 if c.group:
120 if c.group:
55 c.group_repos = c.group.repositories.all()
121 c.group_repos = c.group.repositories.all()
56 else:
122 else:
57 return redirect(url('repos_group'))
123 return redirect(url('repos_group'))
58
124
59 sortables = ['name', 'description', 'last_change', 'tip', 'owner']
125 sortables = ['name', 'description', 'last_change', 'tip', 'owner']
60 current_sort = request.GET.get('sort', 'name')
126 current_sort = request.GET.get('sort', 'name')
61 current_sort_slug = current_sort.replace('-', '')
127 current_sort_slug = current_sort.replace('-', '')
62
128
63 if current_sort_slug not in sortables:
129 if current_sort_slug not in sortables:
64 c.sort_by = 'name'
130 c.sort_by = 'name'
65 current_sort_slug = c.sort_by
131 current_sort_slug = c.sort_by
66 else:
132 else:
67 c.sort_by = current_sort
133 c.sort_by = current_sort
68 c.sort_slug = current_sort_slug
134 c.sort_slug = current_sort_slug
69
135
70 sort_key = current_sort_slug + '_sort'
136 sort_key = current_sort_slug + '_sort'
71
137
72 #overwrite our cached list with current filter
138 #overwrite our cached list with current filter
73 gr_filter = [r.repo_name for r in c.group_repos]
139 gr_filter = [r.repo_name for r in c.group_repos]
74 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
140 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
75
141
76 if c.sort_by.startswith('-'):
142 if c.sort_by.startswith('-'):
77 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
143 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
78 reverse=True)
144 reverse=True)
79 else:
145 else:
80 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
146 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
81 reverse=False)
147 reverse=False)
82
148
83 c.repo_cnt = len(c.repos_list)
149 c.repo_cnt = len(c.repos_list)
84
150
85
151
86 c.groups = self.sa.query(Group).order_by(Group.group_name)\
152 c.groups = self.sa.query(Group).order_by(Group.group_name)\
87 .filter(Group.group_parent_id == id).all()
153 .filter(Group.group_parent_id == id).all()
88
154
89 return render('admin/repos_groups/repos_groups.html')
155 return render('admin/repos_groups/repos_groups.html')
90
156
157 @HasPermissionAnyDecorator('hg.admin')
91 def edit(self, id, format='html'):
158 def edit(self, id, format='html'):
92 """GET /repos_groups/id/edit: Form to edit an existing item"""
159 """GET /repos_groups/id/edit: Form to edit an existing item"""
93 # url('edit_repos_group', id=ID)
160 # url('edit_repos_group', id=ID)
@@ -1,362 +1,364 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.settings
3 rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 settings controller for rhodecode admin
6 settings controller for rhodecode admin
7
7
8 :created_on: Jul 14, 2010
8 :created_on: Jul 14, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from sqlalchemy import func
30 from sqlalchemy import func
31 from formencode import htmlfill
31 from formencode import htmlfill
32 from pylons import request, session, tmpl_context as c, url, config
32 from pylons import request, session, tmpl_context as c, url, config
33 from pylons.controllers.util import abort, redirect
33 from pylons.controllers.util import abort, redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
37 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
37 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
38 HasPermissionAnyDecorator, NotAnonymous
38 HasPermissionAnyDecorator, NotAnonymous
39 from rhodecode.lib.base import BaseController, render
39 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.celerylib import tasks, run_task
40 from rhodecode.lib.celerylib import tasks, run_task
41 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
41 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
42 set_rhodecode_config, repo_name_slug
42 set_rhodecode_config, repo_name_slug
43 from rhodecode.model.db import RhodeCodeUi, Repository, Group, \
43 from rhodecode.model.db import RhodeCodeUi, Repository, Group, \
44 RhodeCodeSettings
44 RhodeCodeSettings
45 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
45 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
46 ApplicationUiSettingsForm
46 ApplicationUiSettingsForm
47 from rhodecode.model.scm import ScmModel
47 from rhodecode.model.scm import ScmModel
48 from rhodecode.model.user import UserModel
48 from rhodecode.model.user import UserModel
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 class SettingsController(BaseController):
53 class SettingsController(BaseController):
54 """REST Controller styled on the Atom Publishing Protocol"""
54 """REST Controller styled on the Atom Publishing Protocol"""
55 # To properly map this controller, ensure your config/routing.py
55 # To properly map this controller, ensure your config/routing.py
56 # file has a resource setup:
56 # file has a resource setup:
57 # map.resource('setting', 'settings', controller='admin/settings',
57 # map.resource('setting', 'settings', controller='admin/settings',
58 # path_prefix='/admin', name_prefix='admin_')
58 # path_prefix='/admin', name_prefix='admin_')
59
59
60 @LoginRequired()
60 @LoginRequired()
61 def __before__(self):
61 def __before__(self):
62 c.admin_user = session.get('admin_user')
62 c.admin_user = session.get('admin_user')
63 c.admin_username = session.get('admin_username')
63 c.admin_username = session.get('admin_username')
64 super(SettingsController, self).__before__()
64 super(SettingsController, self).__before__()
65
65
66 @HasPermissionAllDecorator('hg.admin')
66 @HasPermissionAllDecorator('hg.admin')
67 def index(self, format='html'):
67 def index(self, format='html'):
68 """GET /admin/settings: All items in the collection"""
68 """GET /admin/settings: All items in the collection"""
69 # url('admin_settings')
69 # url('admin_settings')
70
70
71 defaults = RhodeCodeSettings.get_app_settings()
71 defaults = RhodeCodeSettings.get_app_settings()
72 defaults.update(self.get_hg_ui_settings())
72 defaults.update(self.get_hg_ui_settings())
73 return htmlfill.render(
73 return htmlfill.render(
74 render('admin/settings/settings.html'),
74 render('admin/settings/settings.html'),
75 defaults=defaults,
75 defaults=defaults,
76 encoding="UTF-8",
76 encoding="UTF-8",
77 force_defaults=False
77 force_defaults=False
78 )
78 )
79
79
80 @HasPermissionAllDecorator('hg.admin')
80 @HasPermissionAllDecorator('hg.admin')
81 def create(self):
81 def create(self):
82 """POST /admin/settings: Create a new item"""
82 """POST /admin/settings: Create a new item"""
83 # url('admin_settings')
83 # url('admin_settings')
84
84
85 @HasPermissionAllDecorator('hg.admin')
85 @HasPermissionAllDecorator('hg.admin')
86 def new(self, format='html'):
86 def new(self, format='html'):
87 """GET /admin/settings/new: Form to create a new item"""
87 """GET /admin/settings/new: Form to create a new item"""
88 # url('admin_new_setting')
88 # url('admin_new_setting')
89
89
90 @HasPermissionAllDecorator('hg.admin')
90 @HasPermissionAllDecorator('hg.admin')
91 def update(self, setting_id):
91 def update(self, setting_id):
92 """PUT /admin/settings/setting_id: Update an existing item"""
92 """PUT /admin/settings/setting_id: Update an existing item"""
93 # Forms posted to this method should contain a hidden field:
93 # Forms posted to this method should contain a hidden field:
94 # <input type="hidden" name="_method" value="PUT" />
94 # <input type="hidden" name="_method" value="PUT" />
95 # Or using helpers:
95 # Or using helpers:
96 # h.form(url('admin_setting', setting_id=ID),
96 # h.form(url('admin_setting', setting_id=ID),
97 # method='put')
97 # method='put')
98 # url('admin_setting', setting_id=ID)
98 # url('admin_setting', setting_id=ID)
99 if setting_id == 'mapping':
99 if setting_id == 'mapping':
100 rm_obsolete = request.POST.get('destroy', False)
100 rm_obsolete = request.POST.get('destroy', False)
101 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
101 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
102 initial = ScmModel().repo_scan()
102 initial = ScmModel().repo_scan()
103 log.debug('invalidating all repositories')
103 log.debug('invalidating all repositories')
104 for repo_name in initial.keys():
104 for repo_name in initial.keys():
105 invalidate_cache('get_repo_cached_%s' % repo_name)
105 invalidate_cache('get_repo_cached_%s' % repo_name)
106
106
107 added, removed = repo2db_mapper(initial, rm_obsolete)
107 added, removed = repo2db_mapper(initial, rm_obsolete)
108
108
109 h.flash(_('Repositories successfully'
109 h.flash(_('Repositories successfully'
110 ' rescanned added: %s,removed: %s') % (added, removed),
110 ' rescanned added: %s,removed: %s') % (added, removed),
111 category='success')
111 category='success')
112
112
113 if setting_id == 'whoosh':
113 if setting_id == 'whoosh':
114 repo_location = self.get_hg_ui_settings()['paths_root_path']
114 repo_location = self.get_hg_ui_settings()['paths_root_path']
115 full_index = request.POST.get('full_index', False)
115 full_index = request.POST.get('full_index', False)
116 run_task(tasks.whoosh_index, repo_location, full_index)
116 run_task(tasks.whoosh_index, repo_location, full_index)
117
117
118 h.flash(_('Whoosh reindex task scheduled'), category='success')
118 h.flash(_('Whoosh reindex task scheduled'), category='success')
119 if setting_id == 'global':
119 if setting_id == 'global':
120
120
121 application_form = ApplicationSettingsForm()()
121 application_form = ApplicationSettingsForm()()
122 try:
122 try:
123 form_result = application_form.to_python(dict(request.POST))
123 form_result = application_form.to_python(dict(request.POST))
124
124
125 try:
125 try:
126 hgsettings1 = RhodeCodeSettings.get_by_name('title')
126 hgsettings1 = RhodeCodeSettings.get_by_name('title')
127 hgsettings1.app_settings_value = \
127 hgsettings1.app_settings_value = \
128 form_result['rhodecode_title']
128 form_result['rhodecode_title']
129
129
130 hgsettings2 = RhodeCodeSettings.get_by_name('realm')
130 hgsettings2 = RhodeCodeSettings.get_by_name('realm')
131 hgsettings2.app_settings_value = \
131 hgsettings2.app_settings_value = \
132 form_result['rhodecode_realm']
132 form_result['rhodecode_realm']
133
133
134 hgsettings3 = RhodeCodeSettings.get_by_name('ga_code')
134 hgsettings3 = RhodeCodeSettings.get_by_name('ga_code')
135 hgsettings3.app_settings_value = \
135 hgsettings3.app_settings_value = \
136 form_result['rhodecode_ga_code']
136 form_result['rhodecode_ga_code']
137
137
138 self.sa.add(hgsettings1)
138 self.sa.add(hgsettings1)
139 self.sa.add(hgsettings2)
139 self.sa.add(hgsettings2)
140 self.sa.add(hgsettings3)
140 self.sa.add(hgsettings3)
141 self.sa.commit()
141 self.sa.commit()
142 set_rhodecode_config(config)
142 set_rhodecode_config(config)
143 h.flash(_('Updated application settings'),
143 h.flash(_('Updated application settings'),
144 category='success')
144 category='success')
145
145
146 except Exception:
146 except Exception:
147 log.error(traceback.format_exc())
147 log.error(traceback.format_exc())
148 h.flash(_('error occurred during updating '
148 h.flash(_('error occurred during updating '
149 'application settings'),
149 'application settings'),
150 category='error')
150 category='error')
151
151
152 self.sa.rollback()
152 self.sa.rollback()
153
153
154 except formencode.Invalid, errors:
154 except formencode.Invalid, errors:
155 return htmlfill.render(
155 return htmlfill.render(
156 render('admin/settings/settings.html'),
156 render('admin/settings/settings.html'),
157 defaults=errors.value,
157 defaults=errors.value,
158 errors=errors.error_dict or {},
158 errors=errors.error_dict or {},
159 prefix_error=False,
159 prefix_error=False,
160 encoding="UTF-8")
160 encoding="UTF-8")
161
161
162 if setting_id == 'mercurial':
162 if setting_id == 'mercurial':
163 application_form = ApplicationUiSettingsForm()()
163 application_form = ApplicationUiSettingsForm()()
164 try:
164 try:
165 form_result = application_form.to_python(dict(request.POST))
165 form_result = application_form.to_python(dict(request.POST))
166
166
167 try:
167 try:
168
168
169 hgsettings1 = self.sa.query(RhodeCodeUi)\
169 hgsettings1 = self.sa.query(RhodeCodeUi)\
170 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
170 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
171 hgsettings1.ui_value = form_result['web_push_ssl']
171 hgsettings1.ui_value = form_result['web_push_ssl']
172
172
173 hgsettings2 = self.sa.query(RhodeCodeUi)\
173 hgsettings2 = self.sa.query(RhodeCodeUi)\
174 .filter(RhodeCodeUi.ui_key == '/').one()
174 .filter(RhodeCodeUi.ui_key == '/').one()
175 hgsettings2.ui_value = form_result['paths_root_path']
175 hgsettings2.ui_value = form_result['paths_root_path']
176
176
177 #HOOKS
177 #HOOKS
178 hgsettings3 = self.sa.query(RhodeCodeUi)\
178 hgsettings3 = self.sa.query(RhodeCodeUi)\
179 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
179 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
180 hgsettings3.ui_active = \
180 hgsettings3.ui_active = \
181 bool(form_result['hooks_changegroup_update'])
181 bool(form_result['hooks_changegroup_update'])
182
182
183 hgsettings4 = self.sa.query(RhodeCodeUi)\
183 hgsettings4 = self.sa.query(RhodeCodeUi)\
184 .filter(RhodeCodeUi.ui_key ==
184 .filter(RhodeCodeUi.ui_key ==
185 'changegroup.repo_size').one()
185 'changegroup.repo_size').one()
186 hgsettings4.ui_active = \
186 hgsettings4.ui_active = \
187 bool(form_result['hooks_changegroup_repo_size'])
187 bool(form_result['hooks_changegroup_repo_size'])
188
188
189 hgsettings5 = self.sa.query(RhodeCodeUi)\
189 hgsettings5 = self.sa.query(RhodeCodeUi)\
190 .filter(RhodeCodeUi.ui_key ==
190 .filter(RhodeCodeUi.ui_key ==
191 'pretxnchangegroup.push_logger').one()
191 'pretxnchangegroup.push_logger').one()
192 hgsettings5.ui_active = \
192 hgsettings5.ui_active = \
193 bool(form_result['hooks_pretxnchangegroup'
193 bool(form_result['hooks_pretxnchangegroup'
194 '_push_logger'])
194 '_push_logger'])
195
195
196 hgsettings6 = self.sa.query(RhodeCodeUi)\
196 hgsettings6 = self.sa.query(RhodeCodeUi)\
197 .filter(RhodeCodeUi.ui_key ==
197 .filter(RhodeCodeUi.ui_key ==
198 'preoutgoing.pull_logger').one()
198 'preoutgoing.pull_logger').one()
199 hgsettings6.ui_active = \
199 hgsettings6.ui_active = \
200 bool(form_result['hooks_preoutgoing_pull_logger'])
200 bool(form_result['hooks_preoutgoing_pull_logger'])
201
201
202 self.sa.add(hgsettings1)
202 self.sa.add(hgsettings1)
203 self.sa.add(hgsettings2)
203 self.sa.add(hgsettings2)
204 self.sa.add(hgsettings3)
204 self.sa.add(hgsettings3)
205 self.sa.add(hgsettings4)
205 self.sa.add(hgsettings4)
206 self.sa.add(hgsettings5)
206 self.sa.add(hgsettings5)
207 self.sa.add(hgsettings6)
207 self.sa.add(hgsettings6)
208 self.sa.commit()
208 self.sa.commit()
209
209
210 h.flash(_('Updated mercurial settings'),
210 h.flash(_('Updated mercurial settings'),
211 category='success')
211 category='success')
212
212
213 except:
213 except:
214 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
215 h.flash(_('error occurred during updating '
215 h.flash(_('error occurred during updating '
216 'application settings'), category='error')
216 'application settings'), category='error')
217
217
218 self.sa.rollback()
218 self.sa.rollback()
219
219
220 except formencode.Invalid, errors:
220 except formencode.Invalid, errors:
221 return htmlfill.render(
221 return htmlfill.render(
222 render('admin/settings/settings.html'),
222 render('admin/settings/settings.html'),
223 defaults=errors.value,
223 defaults=errors.value,
224 errors=errors.error_dict or {},
224 errors=errors.error_dict or {},
225 prefix_error=False,
225 prefix_error=False,
226 encoding="UTF-8")
226 encoding="UTF-8")
227
227
228 return redirect(url('admin_settings'))
228 return redirect(url('admin_settings'))
229
229
230 @HasPermissionAllDecorator('hg.admin')
230 @HasPermissionAllDecorator('hg.admin')
231 def delete(self, setting_id):
231 def delete(self, setting_id):
232 """DELETE /admin/settings/setting_id: Delete an existing item"""
232 """DELETE /admin/settings/setting_id: Delete an existing item"""
233 # Forms posted to this method should contain a hidden field:
233 # Forms posted to this method should contain a hidden field:
234 # <input type="hidden" name="_method" value="DELETE" />
234 # <input type="hidden" name="_method" value="DELETE" />
235 # Or using helpers:
235 # Or using helpers:
236 # h.form(url('admin_setting', setting_id=ID),
236 # h.form(url('admin_setting', setting_id=ID),
237 # method='delete')
237 # method='delete')
238 # url('admin_setting', setting_id=ID)
238 # url('admin_setting', setting_id=ID)
239
239
240 @HasPermissionAllDecorator('hg.admin')
240 @HasPermissionAllDecorator('hg.admin')
241 def show(self, setting_id, format='html'):
241 def show(self, setting_id, format='html'):
242 """
242 """
243 GET /admin/settings/setting_id: Show a specific item"""
243 GET /admin/settings/setting_id: Show a specific item"""
244 # url('admin_setting', setting_id=ID)
244 # url('admin_setting', setting_id=ID)
245
245
246 @HasPermissionAllDecorator('hg.admin')
246 @HasPermissionAllDecorator('hg.admin')
247 def edit(self, setting_id, format='html'):
247 def edit(self, setting_id, format='html'):
248 """
248 """
249 GET /admin/settings/setting_id/edit: Form to
249 GET /admin/settings/setting_id/edit: Form to
250 edit an existing item"""
250 edit an existing item"""
251 # url('admin_edit_setting', setting_id=ID)
251 # url('admin_edit_setting', setting_id=ID)
252
252
253 @NotAnonymous()
253 @NotAnonymous()
254 def my_account(self):
254 def my_account(self):
255 """
255 """
256 GET /_admin/my_account Displays info about my account
256 GET /_admin/my_account Displays info about my account
257 """
257 """
258 # url('admin_settings_my_account')
258 # url('admin_settings_my_account')
259
259
260 c.user = UserModel().get(self.rhodecode_user.user_id, cache=False)
260 c.user = UserModel().get(self.rhodecode_user.user_id, cache=False)
261 all_repos = [r.repo_name for r in self.sa.query(Repository)\
261 all_repos = [r.repo_name for r in self.sa.query(Repository)\
262 .filter(Repository.user_id == c.user.user_id)\
262 .filter(Repository.user_id == c.user.user_id)\
263 .order_by(func.lower(Repository.repo_name)).all()]
263 .order_by(func.lower(Repository.repo_name)).all()]
264 c.user_repos = ScmModel().get_repos(all_repos)
264 c.user_repos = ScmModel().get_repos(all_repos)
265
265
266 if c.user.username == 'default':
266 if c.user.username == 'default':
267 h.flash(_("You can't edit this user since it's"
267 h.flash(_("You can't edit this user since it's"
268 " crucial for entire application"), category='warning')
268 " crucial for entire application"), category='warning')
269 return redirect(url('users'))
269 return redirect(url('users'))
270
270
271 defaults = c.user.get_dict()
271 defaults = c.user.get_dict()
272 return htmlfill.render(
272 return htmlfill.render(
273 render('admin/users/user_edit_my_account.html'),
273 render('admin/users/user_edit_my_account.html'),
274 defaults=defaults,
274 defaults=defaults,
275 encoding="UTF-8",
275 encoding="UTF-8",
276 force_defaults=False
276 force_defaults=False
277 )
277 )
278
278
279 def my_account_update(self):
279 def my_account_update(self):
280 """PUT /_admin/my_account_update: Update an existing item"""
280 """PUT /_admin/my_account_update: Update an existing item"""
281 # Forms posted to this method should contain a hidden field:
281 # Forms posted to this method should contain a hidden field:
282 # <input type="hidden" name="_method" value="PUT" />
282 # <input type="hidden" name="_method" value="PUT" />
283 # Or using helpers:
283 # Or using helpers:
284 # h.form(url('admin_settings_my_account_update'),
284 # h.form(url('admin_settings_my_account_update'),
285 # method='put')
285 # method='put')
286 # url('admin_settings_my_account_update', id=ID)
286 # url('admin_settings_my_account_update', id=ID)
287 user_model = UserModel()
287 user_model = UserModel()
288 uid = self.rhodecode_user.user_id
288 uid = self.rhodecode_user.user_id
289 _form = UserForm(edit=True,
289 _form = UserForm(edit=True,
290 old_data={'user_id': uid,
290 old_data={'user_id': uid,
291 'email': self.rhodecode_user.email})()
291 'email': self.rhodecode_user.email})()
292 form_result = {}
292 form_result = {}
293 try:
293 try:
294 form_result = _form.to_python(dict(request.POST))
294 form_result = _form.to_python(dict(request.POST))
295 user_model.update_my_account(uid, form_result)
295 user_model.update_my_account(uid, form_result)
296 h.flash(_('Your account was updated successfully'),
296 h.flash(_('Your account was updated successfully'),
297 category='success')
297 category='success')
298
298
299 except formencode.Invalid, errors:
299 except formencode.Invalid, errors:
300 c.user = user_model.get(self.rhodecode_user.user_id, cache=False)
300 c.user = user_model.get(self.rhodecode_user.user_id, cache=False)
301 c.user = UserModel().get(self.rhodecode_user.user_id, cache=False)
301 c.user = UserModel().get(self.rhodecode_user.user_id, cache=False)
302 all_repos = self.sa.query(Repository)\
302 all_repos = self.sa.query(Repository)\
303 .filter(Repository.user_id == c.user.user_id)\
303 .filter(Repository.user_id == c.user.user_id)\
304 .order_by(func.lower(Repository.repo_name))\
304 .order_by(func.lower(Repository.repo_name))\
305 .all()
305 .all()
306 c.user_repos = ScmModel().get_repos(all_repos)
306 c.user_repos = ScmModel().get_repos(all_repos)
307
307
308 return htmlfill.render(
308 return htmlfill.render(
309 render('admin/users/user_edit_my_account.html'),
309 render('admin/users/user_edit_my_account.html'),
310 defaults=errors.value,
310 defaults=errors.value,
311 errors=errors.error_dict or {},
311 errors=errors.error_dict or {},
312 prefix_error=False,
312 prefix_error=False,
313 encoding="UTF-8")
313 encoding="UTF-8")
314 except Exception:
314 except Exception:
315 log.error(traceback.format_exc())
315 log.error(traceback.format_exc())
316 h.flash(_('error occurred during update of user %s') \
316 h.flash(_('error occurred during update of user %s') \
317 % form_result.get('username'), category='error')
317 % form_result.get('username'), category='error')
318
318
319 return redirect(url('my_account'))
319 return redirect(url('my_account'))
320
320
321 @NotAnonymous()
321 @NotAnonymous()
322 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
322 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
323 def create_repository(self):
323 def create_repository(self):
324 """GET /_admin/create_repository: Form to create a new item"""
324 """GET /_admin/create_repository: Form to create a new item"""
325
325
326 c.repo_groups = [('', '')]
326 c.repo_groups = [('', '')]
327 parents_link = lambda k: h.literal('&raquo;'.join(
327 parents_link = lambda k: h.literal('&raquo;'.join(
328 map(lambda k: k.group_name,
328 map(lambda k: k.group_name,
329 k.parents + [k])
329 k.parents + [k])
330 )
330 )
331 )
331 )
332
332
333 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
333 c.repo_groups.extend([(x.group_id, parents_link(x)) for \
334 x in self.sa.query(Group).all()])
334 x in self.sa.query(Group).all()])
335 c.repo_groups = sorted(c.repo_groups,
336 key=lambda t: t[1].split('&raquo;')[0])
335 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
337 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
336
338
337 new_repo = request.GET.get('repo', '')
339 new_repo = request.GET.get('repo', '')
338 c.new_repo = repo_name_slug(new_repo)
340 c.new_repo = repo_name_slug(new_repo)
339
341
340 return render('admin/repos/repo_add_create_repository.html')
342 return render('admin/repos/repo_add_create_repository.html')
341
343
342 def get_hg_ui_settings(self):
344 def get_hg_ui_settings(self):
343 ret = self.sa.query(RhodeCodeUi).all()
345 ret = self.sa.query(RhodeCodeUi).all()
344
346
345 if not ret:
347 if not ret:
346 raise Exception('Could not get application ui settings !')
348 raise Exception('Could not get application ui settings !')
347 settings = {}
349 settings = {}
348 for each in ret:
350 for each in ret:
349 k = each.ui_key
351 k = each.ui_key
350 v = each.ui_value
352 v = each.ui_value
351 if k == '/':
353 if k == '/':
352 k = 'root_path'
354 k = 'root_path'
353
355
354 if k.find('.') != -1:
356 if k.find('.') != -1:
355 k = k.replace('.', '_')
357 k = k.replace('.', '_')
356
358
357 if each.ui_section == 'hooks':
359 if each.ui_section == 'hooks':
358 v = each.ui_active
360 v = each.ui_active
359
361
360 settings[each.ui_section + '_' + k] = v
362 settings[each.ui_section + '_' + k] = v
361
363
362 return settings
364 return settings
@@ -1,81 +1,80 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.home
3 rhodecode.controllers.home
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Home controller for Rhodecode
6 Home controller for Rhodecode
7
7
8 :created_on: Feb 18, 2010
8 :created_on: Feb 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 from operator import itemgetter
27 from operator import itemgetter
28
28
29 from pylons import tmpl_context as c, request
29 from pylons import tmpl_context as c, request
30 from paste.httpexceptions import HTTPBadRequest
30 from paste.httpexceptions import HTTPBadRequest
31
31
32 from rhodecode.lib.auth import LoginRequired
32 from rhodecode.lib.auth import LoginRequired
33 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.base import BaseController, render
34 from rhodecode.model.db import Group
34 from rhodecode.model.db import Group
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 class HomeController(BaseController):
39 class HomeController(BaseController):
40
40
41 @LoginRequired()
41 @LoginRequired()
42 def __before__(self):
42 def __before__(self):
43 super(HomeController, self).__before__()
43 super(HomeController, self).__before__()
44
44
45 def index(self):
45 def index(self):
46 sortables = ['name', 'description', 'last_change', 'tip', 'owner']
46 sortables = ['name', 'description', 'last_change', 'tip', 'owner']
47 current_sort = request.GET.get('sort', 'name')
47 current_sort = request.GET.get('sort', 'name')
48 current_sort_slug = current_sort.replace('-', '')
48 current_sort_slug = current_sort.replace('-', '')
49
49
50 if current_sort_slug not in sortables:
50 if current_sort_slug not in sortables:
51 c.sort_by = 'name'
51 c.sort_by = 'name'
52 current_sort_slug = c.sort_by
52 current_sort_slug = c.sort_by
53 else:
53 else:
54 c.sort_by = current_sort
54 c.sort_by = current_sort
55 c.sort_slug = current_sort_slug
55 c.sort_slug = current_sort_slug
56
56
57 sort_key = current_sort_slug + '_sort'
57 sort_key = current_sort_slug + '_sort'
58
58
59 if c.sort_by.startswith('-'):
59 if c.sort_by.startswith('-'):
60 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
60 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
61 reverse=True)
61 reverse=True)
62 else:
62 else:
63 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
63 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
64 reverse=False)
64 reverse=False)
65
65
66 c.repo_cnt = len(c.repos_list)
66 c.repo_cnt = len(c.repos_list)
67
67
68
68
69 c.groups = self.sa.query(Group)\
69 c.groups = Group.query().filter(Group.group_parent_id == None).all()
70 .filter(Group.group_parent_id == None).all()
71
70
72
71
73 return render('/index.html')
72 return render('/index.html')
74
73
75 def repo_switcher(self):
74 def repo_switcher(self):
76 if request.is_xhr:
75 if request.is_xhr:
77 c.repos_list = sorted(c.cached_repo_list,
76 c.repos_list = sorted(c.cached_repo_list,
78 key=itemgetter('name_sort'), reverse=False)
77 key=itemgetter('name_sort'), reverse=False)
79 return render('/repo_switcher_list.html')
78 return render('/repo_switcher_list.html')
80 else:
79 else:
81 return HTTPBadRequest()
80 return HTTPBadRequest()
@@ -1,547 +1,552 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import datetime
28 import datetime
29 from datetime import date
29 from datetime import date
30
30
31 from sqlalchemy import *
31 from sqlalchemy import *
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.orm import relationship, backref
33 from sqlalchemy.orm import relationship, backref
34 from sqlalchemy.orm.interfaces import MapperExtension
34 from sqlalchemy.orm.interfaces import MapperExtension
35
35
36 from rhodecode.lib import str2bool
36 from rhodecode.lib import str2bool
37 from rhodecode.model.meta import Base, Session
37 from rhodecode.model.meta import Base, Session
38 from rhodecode.model.caching_query import FromCache
38 from rhodecode.model.caching_query import FromCache
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42 #==============================================================================
42 #==============================================================================
43 # MAPPER EXTENSIONS
43 # MAPPER EXTENSIONS
44 #==============================================================================
44 #==============================================================================
45
45
46 class RepositoryMapper(MapperExtension):
46 class RepositoryMapper(MapperExtension):
47 def after_update(self, mapper, connection, instance):
47 def after_update(self, mapper, connection, instance):
48 pass
48 pass
49
49
50
50
51 class RhodeCodeSettings(Base):
51 class RhodeCodeSettings(Base):
52 __tablename__ = 'rhodecode_settings'
52 __tablename__ = 'rhodecode_settings'
53 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
53 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
54 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
54 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
55 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
55 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
57
57
58 def __init__(self, k='', v=''):
58 def __init__(self, k='', v=''):
59 self.app_settings_name = k
59 self.app_settings_name = k
60 self.app_settings_value = v
60 self.app_settings_value = v
61
61
62 def __repr__(self):
62 def __repr__(self):
63 return "<%s('%s:%s')>" % (self.__class__.__name__,
63 return "<%s('%s:%s')>" % (self.__class__.__name__,
64 self.app_settings_name, self.app_settings_value)
64 self.app_settings_name, self.app_settings_value)
65
65
66
66
67 @classmethod
67 @classmethod
68 def get_by_name(cls, ldap_key):
68 def get_by_name(cls, ldap_key):
69 return Session.query(cls)\
69 return Session.query(cls)\
70 .filter(cls.app_settings_name == ldap_key).scalar()
70 .filter(cls.app_settings_name == ldap_key).scalar()
71
71
72 @classmethod
72 @classmethod
73 def get_app_settings(cls, cache=False):
73 def get_app_settings(cls, cache=False):
74
74
75 ret = Session.query(cls)
75 ret = Session.query(cls)
76
76
77 if cache:
77 if cache:
78 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
78 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
79
79
80 if not ret:
80 if not ret:
81 raise Exception('Could not get application settings !')
81 raise Exception('Could not get application settings !')
82 settings = {}
82 settings = {}
83 for each in ret:
83 for each in ret:
84 settings['rhodecode_' + each.app_settings_name] = \
84 settings['rhodecode_' + each.app_settings_name] = \
85 each.app_settings_value
85 each.app_settings_value
86
86
87 return settings
87 return settings
88
88
89 @classmethod
89 @classmethod
90 def get_ldap_settings(cls, cache=False):
90 def get_ldap_settings(cls, cache=False):
91 ret = Session.query(cls)\
91 ret = Session.query(cls)\
92 .filter(cls.app_settings_name.startswith('ldap_'))\
92 .filter(cls.app_settings_name.startswith('ldap_'))\
93 .all()
93 .all()
94 fd = {}
94 fd = {}
95 for row in ret:
95 for row in ret:
96 fd.update({row.app_settings_name:row.app_settings_value})
96 fd.update({row.app_settings_name:row.app_settings_value})
97 return fd
97 return fd
98
98
99
99
100 class RhodeCodeUi(Base):
100 class RhodeCodeUi(Base):
101 __tablename__ = 'rhodecode_ui'
101 __tablename__ = 'rhodecode_ui'
102 __table_args__ = {'useexisting':True}
102 __table_args__ = {'useexisting':True}
103 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
103 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
104 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
104 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
107 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
107 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
108
108
109
109
110 @classmethod
111 def get_by_key(cls, key):
112 return Session.query(cls).filter(cls.ui_key == key)
113
114
110 class User(Base):
115 class User(Base):
111 __tablename__ = 'users'
116 __tablename__ = 'users'
112 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
117 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
113 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
118 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
114 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
119 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
115 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
120 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
116 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
121 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
117 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
122 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
118 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
123 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
119 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
124 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
120 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
125 email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
121 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
126 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
122 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
127 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
123 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
128 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
124
129
125 user_log = relationship('UserLog', cascade='all')
130 user_log = relationship('UserLog', cascade='all')
126 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
131 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
127
132
128 repositories = relationship('Repository')
133 repositories = relationship('Repository')
129 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
134 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
130 repo_to_perm = relationship('RepoToPerm', primaryjoin='RepoToPerm.user_id==User.user_id', cascade='all')
135 repo_to_perm = relationship('RepoToPerm', primaryjoin='RepoToPerm.user_id==User.user_id', cascade='all')
131
136
132 group_member = relationship('UsersGroupMember', cascade='all')
137 group_member = relationship('UsersGroupMember', cascade='all')
133
138
134 @property
139 @property
135 def full_contact(self):
140 def full_contact(self):
136 return '%s %s <%s>' % (self.name, self.lastname, self.email)
141 return '%s %s <%s>' % (self.name, self.lastname, self.email)
137
142
138 @property
143 @property
139 def short_contact(self):
144 def short_contact(self):
140 return '%s %s' % (self.name, self.lastname)
145 return '%s %s' % (self.name, self.lastname)
141
146
142
147
143 @property
148 @property
144 def is_admin(self):
149 def is_admin(self):
145 return self.admin
150 return self.admin
146
151
147 def __repr__(self):
152 def __repr__(self):
148 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
153 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
149 self.user_id, self.username)
154 self.user_id, self.username)
150
155
151 @classmethod
156 @classmethod
152 def by_username(cls, username):
157 def by_username(cls, username):
153 return Session.query(cls).filter(cls.username == username).one()
158 return Session.query(cls).filter(cls.username == username).one()
154
159
155
160
156 def update_lastlogin(self):
161 def update_lastlogin(self):
157 """Update user lastlogin"""
162 """Update user lastlogin"""
158
163
159 try:
164 try:
160 session = Session.object_session(self)
165 session = Session.object_session(self)
161 self.last_login = datetime.datetime.now()
166 self.last_login = datetime.datetime.now()
162 session.add(self)
167 session.add(self)
163 session.commit()
168 session.commit()
164 log.debug('updated user %s lastlogin', self.username)
169 log.debug('updated user %s lastlogin', self.username)
165 except (DatabaseError,):
170 except (DatabaseError,):
166 session.rollback()
171 session.rollback()
167
172
168
173
169 class UserLog(Base):
174 class UserLog(Base):
170 __tablename__ = 'user_logs'
175 __tablename__ = 'user_logs'
171 __table_args__ = {'useexisting':True}
176 __table_args__ = {'useexisting':True}
172 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
177 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
173 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
178 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
174 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
179 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
175 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
180 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
176 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
181 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
177 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
182 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
178 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
183 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
179
184
180 @property
185 @property
181 def action_as_day(self):
186 def action_as_day(self):
182 return date(*self.action_date.timetuple()[:3])
187 return date(*self.action_date.timetuple()[:3])
183
188
184 user = relationship('User')
189 user = relationship('User')
185 repository = relationship('Repository')
190 repository = relationship('Repository')
186
191
187
192
188 class UsersGroup(Base):
193 class UsersGroup(Base):
189 __tablename__ = 'users_groups'
194 __tablename__ = 'users_groups'
190 __table_args__ = {'useexisting':True}
195 __table_args__ = {'useexisting':True}
191
196
192 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
197 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
193 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
198 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
194 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
199 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
195
200
196 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
201 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
197
202
198
203
199 @classmethod
204 @classmethod
200 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
205 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
201 if case_insensitive:
206 if case_insensitive:
202 gr = Session.query(cls)\
207 gr = Session.query(cls)\
203 .filter(cls.users_group_name.ilike(group_name))
208 .filter(cls.users_group_name.ilike(group_name))
204 else:
209 else:
205 gr = Session.query(UsersGroup)\
210 gr = Session.query(UsersGroup)\
206 .filter(UsersGroup.users_group_name == group_name)
211 .filter(UsersGroup.users_group_name == group_name)
207 if cache:
212 if cache:
208 gr = gr.options(FromCache("sql_cache_short",
213 gr = gr.options(FromCache("sql_cache_short",
209 "get_user_%s" % group_name))
214 "get_user_%s" % group_name))
210 return gr.scalar()
215 return gr.scalar()
211
216
212 class UsersGroupMember(Base):
217 class UsersGroupMember(Base):
213 __tablename__ = 'users_groups_members'
218 __tablename__ = 'users_groups_members'
214 __table_args__ = {'useexisting':True}
219 __table_args__ = {'useexisting':True}
215
220
216 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
221 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
217 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
222 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
218 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
223 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
219
224
220 user = relationship('User', lazy='joined')
225 user = relationship('User', lazy='joined')
221 users_group = relationship('UsersGroup')
226 users_group = relationship('UsersGroup')
222
227
223 def __init__(self, gr_id='', u_id=''):
228 def __init__(self, gr_id='', u_id=''):
224 self.users_group_id = gr_id
229 self.users_group_id = gr_id
225 self.user_id = u_id
230 self.user_id = u_id
226
231
227 class Repository(Base):
232 class Repository(Base):
228 __tablename__ = 'repositories'
233 __tablename__ = 'repositories'
229 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
234 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
230 __mapper_args__ = {'extension':RepositoryMapper()}
235 __mapper_args__ = {'extension':RepositoryMapper()}
231
236
232 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
237 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
233 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
238 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
234 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
239 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
235 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
240 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
236 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
241 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
237 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
242 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
238 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
243 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
239 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
244 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
240 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
245 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
241 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
246 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
242
247
243 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
248 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
244 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
249 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
245
250
246
251
247 user = relationship('User')
252 user = relationship('User')
248 fork = relationship('Repository', remote_side=repo_id)
253 fork = relationship('Repository', remote_side=repo_id)
249 group = relationship('Group')
254 group = relationship('Group')
250 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
255 repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
251 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
256 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
252 stats = relationship('Statistics', cascade='all', uselist=False)
257 stats = relationship('Statistics', cascade='all', uselist=False)
253
258
254 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
259 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
255
260
256 logs = relationship('UserLog', cascade='all')
261 logs = relationship('UserLog', cascade='all')
257
262
258 def __repr__(self):
263 def __repr__(self):
259 return "<%s('%s:%s')>" % (self.__class__.__name__,
264 return "<%s('%s:%s')>" % (self.__class__.__name__,
260 self.repo_id, self.repo_name)
265 self.repo_id, self.repo_name)
261
266
262 @classmethod
267 @classmethod
263 def by_repo_name(cls, repo_name):
268 def by_repo_name(cls, repo_name):
264 return Session.query(cls).filter(cls.repo_name == repo_name).one()
269 return Session.query(cls).filter(cls.repo_name == repo_name).one()
265
270
266
271
267 @classmethod
272 @classmethod
268 def get_repo_forks(cls, repo_id):
273 def get_repo_forks(cls, repo_id):
269 return Session.query(cls).filter(Repository.fork_id == repo_id)
274 return Session.query(cls).filter(Repository.fork_id == repo_id)
270
275
271 @property
276 @property
272 def just_name(self):
277 def just_name(self):
273 return self.repo_name.split(os.sep)[-1]
278 return self.repo_name.split(os.sep)[-1]
274
279
275 @property
280 @property
276 def groups_with_parents(self):
281 def groups_with_parents(self):
277 groups = []
282 groups = []
278 if self.group is None:
283 if self.group is None:
279 return groups
284 return groups
280
285
281 cur_gr = self.group
286 cur_gr = self.group
282 groups.insert(0, cur_gr)
287 groups.insert(0, cur_gr)
283 while 1:
288 while 1:
284 gr = getattr(cur_gr, 'parent_group', None)
289 gr = getattr(cur_gr, 'parent_group', None)
285 cur_gr = cur_gr.parent_group
290 cur_gr = cur_gr.parent_group
286 if gr is None:
291 if gr is None:
287 break
292 break
288 groups.insert(0, gr)
293 groups.insert(0, gr)
289
294
290 return groups
295 return groups
291
296
292 @property
297 @property
293 def groups_and_repo(self):
298 def groups_and_repo(self):
294 return self.groups_with_parents, self.just_name
299 return self.groups_with_parents, self.just_name
295
300
296
301
297 class Group(Base):
302 class Group(Base):
298 __tablename__ = 'groups'
303 __tablename__ = 'groups'
299 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
304 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'), {'useexisting':True},)
300 __mapper_args__ = {'order_by':'group_name'}
305 __mapper_args__ = {'order_by':'group_name'}
301
306
302 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
307 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
303 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
308 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
304 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
309 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
305 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
310 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
306
311
307 parent_group = relationship('Group', remote_side=group_id)
312 parent_group = relationship('Group', remote_side=group_id)
308
313
309
314
310 def __init__(self, group_name='', parent_group=None):
315 def __init__(self, group_name='', parent_group=None):
311 self.group_name = group_name
316 self.group_name = group_name
312 self.parent_group = parent_group
317 self.parent_group = parent_group
313
318
314 def __repr__(self):
319 def __repr__(self):
315 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
320 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
316 self.group_name)
321 self.group_name)
317
322
318 @property
323 @property
319 def parents(self):
324 def parents(self):
320 groups = []
325 groups = []
321 if self.parent_group is None:
326 if self.parent_group is None:
322 return groups
327 return groups
323 cur_gr = self.parent_group
328 cur_gr = self.parent_group
324 groups.insert(0, cur_gr)
329 groups.insert(0, cur_gr)
325 while 1:
330 while 1:
326 gr = getattr(cur_gr, 'parent_group', None)
331 gr = getattr(cur_gr, 'parent_group', None)
327 cur_gr = cur_gr.parent_group
332 cur_gr = cur_gr.parent_group
328 if gr is None:
333 if gr is None:
329 break
334 break
330 groups.insert(0, gr)
335 groups.insert(0, gr)
331 return groups
336 return groups
332
337
333
338
334 @property
339 @property
335 def full_path(self):
340 def full_path(self):
336 return '/'.join([g.group_name for g in self.parents] +
341 return '/'.join([g.group_name for g in self.parents] +
337 [self.group_name])
342 [self.group_name])
338
343
339 @property
344 @property
340 def repositories(self):
345 def repositories(self):
341 return Session.query(Repository).filter(Repository.group == self)
346 return Session.query(Repository).filter(Repository.group == self)
342
347
343 class Permission(Base):
348 class Permission(Base):
344 __tablename__ = 'permissions'
349 __tablename__ = 'permissions'
345 __table_args__ = {'useexisting':True}
350 __table_args__ = {'useexisting':True}
346 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
351 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
347 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
352 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
348 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
353 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
349
354
350 def __repr__(self):
355 def __repr__(self):
351 return "<%s('%s:%s')>" % (self.__class__.__name__,
356 return "<%s('%s:%s')>" % (self.__class__.__name__,
352 self.permission_id, self.permission_name)
357 self.permission_id, self.permission_name)
353
358
354 @classmethod
359 @classmethod
355 def get_by_key(cls, key):
360 def get_by_key(cls, key):
356 return Session.query(cls).filter(cls.permission_name == key).scalar()
361 return Session.query(cls).filter(cls.permission_name == key).scalar()
357
362
358 class RepoToPerm(Base):
363 class RepoToPerm(Base):
359 __tablename__ = 'repo_to_perm'
364 __tablename__ = 'repo_to_perm'
360 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
365 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
361 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
366 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
362 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
367 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
363 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
368 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
364 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
369 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
365
370
366 user = relationship('User')
371 user = relationship('User')
367 permission = relationship('Permission')
372 permission = relationship('Permission')
368 repository = relationship('Repository')
373 repository = relationship('Repository')
369
374
370 class UserToPerm(Base):
375 class UserToPerm(Base):
371 __tablename__ = 'user_to_perm'
376 __tablename__ = 'user_to_perm'
372 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
377 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
373 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
378 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
374 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
379 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
375 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
380 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
376
381
377 user = relationship('User')
382 user = relationship('User')
378 permission = relationship('Permission')
383 permission = relationship('Permission')
379
384
380 @classmethod
385 @classmethod
381 def has_perm(cls, user_id, perm):
386 def has_perm(cls, user_id, perm):
382 if not isinstance(perm, Permission):
387 if not isinstance(perm, Permission):
383 raise Exception('perm needs to be an instance of Permission class')
388 raise Exception('perm needs to be an instance of Permission class')
384
389
385 return Session.query(cls).filter(cls.user_id == user_id)\
390 return Session.query(cls).filter(cls.user_id == user_id)\
386 .filter(cls.permission == perm).scalar() is not None
391 .filter(cls.permission == perm).scalar() is not None
387
392
388 @classmethod
393 @classmethod
389 def grant_perm(cls, user_id, perm):
394 def grant_perm(cls, user_id, perm):
390 if not isinstance(perm, Permission):
395 if not isinstance(perm, Permission):
391 raise Exception('perm needs to be an instance of Permission class')
396 raise Exception('perm needs to be an instance of Permission class')
392
397
393 new = cls()
398 new = cls()
394 new.user_id = user_id
399 new.user_id = user_id
395 new.permission = perm
400 new.permission = perm
396 try:
401 try:
397 Session.add(new)
402 Session.add(new)
398 Session.commit()
403 Session.commit()
399 except:
404 except:
400 Session.rollback()
405 Session.rollback()
401
406
402
407
403 @classmethod
408 @classmethod
404 def revoke_perm(cls, user_id, perm):
409 def revoke_perm(cls, user_id, perm):
405 if not isinstance(perm, Permission):
410 if not isinstance(perm, Permission):
406 raise Exception('perm needs to be an instance of Permission class')
411 raise Exception('perm needs to be an instance of Permission class')
407
412
408 try:
413 try:
409 Session.query(cls).filter(cls.user_id == user_id)\
414 Session.query(cls).filter(cls.user_id == user_id)\
410 .filter(cls.permission == perm).delete()
415 .filter(cls.permission == perm).delete()
411 Session.commit()
416 Session.commit()
412 except:
417 except:
413 Session.rollback()
418 Session.rollback()
414
419
415 class UsersGroupRepoToPerm(Base):
420 class UsersGroupRepoToPerm(Base):
416 __tablename__ = 'users_group_repo_to_perm'
421 __tablename__ = 'users_group_repo_to_perm'
417 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
422 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
418 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
423 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
419 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
424 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
420 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
425 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
421 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
426 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
422
427
423 users_group = relationship('UsersGroup')
428 users_group = relationship('UsersGroup')
424 permission = relationship('Permission')
429 permission = relationship('Permission')
425 repository = relationship('Repository')
430 repository = relationship('Repository')
426
431
427
432
428 class UsersGroupToPerm(Base):
433 class UsersGroupToPerm(Base):
429 __tablename__ = 'users_group_to_perm'
434 __tablename__ = 'users_group_to_perm'
430 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
435 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
431 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
436 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
432 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
437 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
433
438
434 users_group = relationship('UsersGroup')
439 users_group = relationship('UsersGroup')
435 permission = relationship('Permission')
440 permission = relationship('Permission')
436
441
437
442
438 @classmethod
443 @classmethod
439 def has_perm(cls, users_group_id, perm):
444 def has_perm(cls, users_group_id, perm):
440 if not isinstance(perm, Permission):
445 if not isinstance(perm, Permission):
441 raise Exception('perm needs to be an instance of Permission class')
446 raise Exception('perm needs to be an instance of Permission class')
442
447
443 return Session.query(cls).filter(cls.users_group_id ==
448 return Session.query(cls).filter(cls.users_group_id ==
444 users_group_id)\
449 users_group_id)\
445 .filter(cls.permission == perm)\
450 .filter(cls.permission == perm)\
446 .scalar() is not None
451 .scalar() is not None
447
452
448 @classmethod
453 @classmethod
449 def grant_perm(cls, users_group_id, perm):
454 def grant_perm(cls, users_group_id, perm):
450 if not isinstance(perm, Permission):
455 if not isinstance(perm, Permission):
451 raise Exception('perm needs to be an instance of Permission class')
456 raise Exception('perm needs to be an instance of Permission class')
452
457
453 new = cls()
458 new = cls()
454 new.users_group_id = users_group_id
459 new.users_group_id = users_group_id
455 new.permission = perm
460 new.permission = perm
456 try:
461 try:
457 Session.add(new)
462 Session.add(new)
458 Session.commit()
463 Session.commit()
459 except:
464 except:
460 Session.rollback()
465 Session.rollback()
461
466
462
467
463 @classmethod
468 @classmethod
464 def revoke_perm(cls, users_group_id, perm):
469 def revoke_perm(cls, users_group_id, perm):
465 if not isinstance(perm, Permission):
470 if not isinstance(perm, Permission):
466 raise Exception('perm needs to be an instance of Permission class')
471 raise Exception('perm needs to be an instance of Permission class')
467
472
468 try:
473 try:
469 Session.query(cls).filter(cls.users_group_id == users_group_id)\
474 Session.query(cls).filter(cls.users_group_id == users_group_id)\
470 .filter(cls.permission == perm).delete()
475 .filter(cls.permission == perm).delete()
471 Session.commit()
476 Session.commit()
472 except:
477 except:
473 Session.rollback()
478 Session.rollback()
474
479
475
480
476 class GroupToPerm(Base):
481 class GroupToPerm(Base):
477 __tablename__ = 'group_to_perm'
482 __tablename__ = 'group_to_perm'
478 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
483 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
479
484
480 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
485 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
481 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
486 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
482 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
487 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
483 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
488 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
484
489
485 user = relationship('User')
490 user = relationship('User')
486 permission = relationship('Permission')
491 permission = relationship('Permission')
487 group = relationship('Group')
492 group = relationship('Group')
488
493
489 class Statistics(Base):
494 class Statistics(Base):
490 __tablename__ = 'statistics'
495 __tablename__ = 'statistics'
491 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
496 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
492 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
497 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
493 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
498 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
494 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
499 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
495 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
500 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
496 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
501 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
497 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
502 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
498
503
499 repository = relationship('Repository', single_parent=True)
504 repository = relationship('Repository', single_parent=True)
500
505
501 class UserFollowing(Base):
506 class UserFollowing(Base):
502 __tablename__ = 'user_followings'
507 __tablename__ = 'user_followings'
503 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
508 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
504 UniqueConstraint('user_id', 'follows_user_id')
509 UniqueConstraint('user_id', 'follows_user_id')
505 , {'useexisting':True})
510 , {'useexisting':True})
506
511
507 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
512 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
508 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
513 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
509 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
514 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
510 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
515 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
511 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
516 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
512
517
513 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
518 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
514
519
515 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
520 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
516 follows_repository = relationship('Repository', order_by='Repository.repo_name')
521 follows_repository = relationship('Repository', order_by='Repository.repo_name')
517
522
518
523
519
524
520 @classmethod
525 @classmethod
521 def get_repo_followers(cls, repo_id):
526 def get_repo_followers(cls, repo_id):
522 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
527 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
523
528
524 class CacheInvalidation(Base):
529 class CacheInvalidation(Base):
525 __tablename__ = 'cache_invalidation'
530 __tablename__ = 'cache_invalidation'
526 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
531 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
527 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
532 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
528 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
533 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
529 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
534 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
530 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
535 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
531
536
532
537
533 def __init__(self, cache_key, cache_args=''):
538 def __init__(self, cache_key, cache_args=''):
534 self.cache_key = cache_key
539 self.cache_key = cache_key
535 self.cache_args = cache_args
540 self.cache_args = cache_args
536 self.cache_active = False
541 self.cache_active = False
537
542
538 def __repr__(self):
543 def __repr__(self):
539 return "<%s('%s:%s')>" % (self.__class__.__name__,
544 return "<%s('%s:%s')>" % (self.__class__.__name__,
540 self.cache_id, self.cache_key)
545 self.cache_id, self.cache_key)
541
546
542 class DbMigrateVersion(Base):
547 class DbMigrateVersion(Base):
543 __tablename__ = 'db_migrate_version'
548 __tablename__ = 'db_migrate_version'
544 __table_args__ = {'useexisting':True}
549 __table_args__ = {'useexisting':True}
545 repository_id = Column('repository_id', String(250), primary_key=True)
550 repository_id = Column('repository_id', String(250), primary_key=True)
546 repository_path = Column('repository_path', Text)
551 repository_path = Column('repository_path', Text)
547 version = Column('version', Integer)
552 version = Column('version', Integer)
@@ -1,619 +1,644 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25 import traceback
25 import traceback
26
26
27 import formencode
27 import formencode
28 from formencode import All
28 from formencode import All
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 Email, Bool, StringBoolean, Set
30 Email, Bool, StringBoolean, Set
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34
34
35 from rhodecode.lib.utils import repo_name_slug
35 from rhodecode.lib.utils import repo_name_slug
36 from rhodecode.lib.auth import authenticate, get_crypt_password
36 from rhodecode.lib.auth import authenticate, get_crypt_password
37 from rhodecode.lib.exceptions import LdapImportError
37 from rhodecode.lib.exceptions import LdapImportError
38 from rhodecode.model import meta
39 from rhodecode.model.user import UserModel
38 from rhodecode.model.user import UserModel
40 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.db import User, UsersGroup, Group
40 from rhodecode.model.db import User, UsersGroup, Group
42 from rhodecode import BACKENDS
41 from rhodecode import BACKENDS
43
42
44 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
45
44
46 #this is needed to translate the messages using _() in validators
45 #this is needed to translate the messages using _() in validators
47 class State_obj(object):
46 class State_obj(object):
48 _ = staticmethod(_)
47 _ = staticmethod(_)
49
48
50 #==============================================================================
49 #==============================================================================
51 # VALIDATORS
50 # VALIDATORS
52 #==============================================================================
51 #==============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
52 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token':_('Token mismatch')}
53 messages = {'invalid_token':_('Token mismatch')}
55
54
56 def validate_python(self, value, state):
55 def validate_python(self, value, state):
57
56
58 if value != authentication_token():
57 if value != authentication_token():
59 raise formencode.Invalid(self.message('invalid_token', state,
58 raise formencode.Invalid(self.message('invalid_token', state,
60 search_number=value), value, state)
59 search_number=value), value, state)
61
60
62 def ValidUsername(edit, old_data):
61 def ValidUsername(edit, old_data):
63 class _ValidUsername(formencode.validators.FancyValidator):
62 class _ValidUsername(formencode.validators.FancyValidator):
64
63
65 def validate_python(self, value, state):
64 def validate_python(self, value, state):
66 if value in ['default', 'new_user']:
65 if value in ['default', 'new_user']:
67 raise formencode.Invalid(_('Invalid username'), value, state)
66 raise formencode.Invalid(_('Invalid username'), value, state)
68 #check if user is unique
67 #check if user is unique
69 old_un = None
68 old_un = None
70 if edit:
69 if edit:
71 old_un = UserModel().get(old_data.get('user_id')).username
70 old_un = UserModel().get(old_data.get('user_id')).username
72
71
73 if old_un != value or not edit:
72 if old_un != value or not edit:
74 if UserModel().get_by_username(value, cache=False,
73 if UserModel().get_by_username(value, cache=False,
75 case_insensitive=True):
74 case_insensitive=True):
76 raise formencode.Invalid(_('This username already '
75 raise formencode.Invalid(_('This username already '
77 'exists') , value, state)
76 'exists') , value, state)
78
77
79 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
80 raise formencode.Invalid(_('Username may only contain '
79 raise formencode.Invalid(_('Username may only contain '
81 'alphanumeric characters '
80 'alphanumeric characters '
82 'underscores, periods or dashes '
81 'underscores, periods or dashes '
83 'and must begin with alphanumeric '
82 'and must begin with alphanumeric '
84 'character'), value, state)
83 'character'), value, state)
85
84
86 return _ValidUsername
85 return _ValidUsername
87
86
88
87
89 def ValidUsersGroup(edit, old_data):
88 def ValidUsersGroup(edit, old_data):
90
89
91 class _ValidUsersGroup(formencode.validators.FancyValidator):
90 class _ValidUsersGroup(formencode.validators.FancyValidator):
92
91
93 def validate_python(self, value, state):
92 def validate_python(self, value, state):
94 if value in ['default']:
93 if value in ['default']:
95 raise formencode.Invalid(_('Invalid group name'), value, state)
94 raise formencode.Invalid(_('Invalid group name'), value, state)
96 #check if group is unique
95 #check if group is unique
97 old_ugname = None
96 old_ugname = None
98 if edit:
97 if edit:
99 old_ugname = UsersGroup.get(
98 old_ugname = UsersGroup.get(
100 old_data.get('users_group_id')).users_group_name
99 old_data.get('users_group_id')).users_group_name
101
100
102 if old_ugname != value or not edit:
101 if old_ugname != value or not edit:
103 if UsersGroup.get_by_group_name(value, cache=False,
102 if UsersGroup.get_by_group_name(value, cache=False,
104 case_insensitive=True):
103 case_insensitive=True):
105 raise formencode.Invalid(_('This users group '
104 raise formencode.Invalid(_('This users group '
106 'already exists') , value,
105 'already exists') , value,
107 state)
106 state)
108
107
109
108
110 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
111 raise formencode.Invalid(_('Group name may only contain '
110 raise formencode.Invalid(_('Group name may only contain '
112 'alphanumeric characters '
111 'alphanumeric characters '
113 'underscores, periods or dashes '
112 'underscores, periods or dashes '
114 'and must begin with alphanumeric '
113 'and must begin with alphanumeric '
115 'character'), value, state)
114 'character'), value, state)
116
115
117 return _ValidUsersGroup
116 return _ValidUsersGroup
118
117
119
118
119 def ValidReposGroup(edit, old_data):
120
121 class _ValidReposGroup(formencode.validators.FancyValidator):
122
123 def validate_python(self, value, state):
124 #TODO WRITE VALIDATIONS
125 group_name = value.get('repos_group_name')
126 parent_id = value.get('repos_group_parent')
127
128 # slugify repo group just in case :)
129 slug = repo_name_slug(group_name)
130
131 # check filesystem
132 gr = Group.query().filter(Group.group_name == slug)\
133 .filter(Group.group_parent_id == parent_id).scalar()
134
135 if gr:
136 e_dict = {'repos_group_name':_('This group already exists')}
137 raise formencode.Invalid('', value, state,
138 error_dict=e_dict)
139 return _ValidReposGroup
120
140
121 class ValidPassword(formencode.validators.FancyValidator):
141 class ValidPassword(formencode.validators.FancyValidator):
122
142
123 def to_python(self, value, state):
143 def to_python(self, value, state):
124
144
125 if value:
145 if value:
126
146
127 if value.get('password'):
147 if value.get('password'):
128 try:
148 try:
129 value['password'] = get_crypt_password(value['password'])
149 value['password'] = get_crypt_password(value['password'])
130 except UnicodeEncodeError:
150 except UnicodeEncodeError:
131 e_dict = {'password':_('Invalid characters in password')}
151 e_dict = {'password':_('Invalid characters in password')}
132 raise formencode.Invalid('', value, state, error_dict=e_dict)
152 raise formencode.Invalid('', value, state, error_dict=e_dict)
133
153
134 if value.get('password_confirmation'):
154 if value.get('password_confirmation'):
135 try:
155 try:
136 value['password_confirmation'] = \
156 value['password_confirmation'] = \
137 get_crypt_password(value['password_confirmation'])
157 get_crypt_password(value['password_confirmation'])
138 except UnicodeEncodeError:
158 except UnicodeEncodeError:
139 e_dict = {'password_confirmation':_('Invalid characters in password')}
159 e_dict = {'password_confirmation':_('Invalid characters in password')}
140 raise formencode.Invalid('', value, state, error_dict=e_dict)
160 raise formencode.Invalid('', value, state, error_dict=e_dict)
141
161
142 if value.get('new_password'):
162 if value.get('new_password'):
143 try:
163 try:
144 value['new_password'] = \
164 value['new_password'] = \
145 get_crypt_password(value['new_password'])
165 get_crypt_password(value['new_password'])
146 except UnicodeEncodeError:
166 except UnicodeEncodeError:
147 e_dict = {'new_password':_('Invalid characters in password')}
167 e_dict = {'new_password':_('Invalid characters in password')}
148 raise formencode.Invalid('', value, state, error_dict=e_dict)
168 raise formencode.Invalid('', value, state, error_dict=e_dict)
149
169
150 return value
170 return value
151
171
152 class ValidPasswordsMatch(formencode.validators.FancyValidator):
172 class ValidPasswordsMatch(formencode.validators.FancyValidator):
153
173
154 def validate_python(self, value, state):
174 def validate_python(self, value, state):
155
175
156 if value['password'] != value['password_confirmation']:
176 if value['password'] != value['password_confirmation']:
157 e_dict = {'password_confirmation':
177 e_dict = {'password_confirmation':
158 _('Password do not match')}
178 _('Password do not match')}
159 raise formencode.Invalid('', value, state, error_dict=e_dict)
179 raise formencode.Invalid('', value, state, error_dict=e_dict)
160
180
161 class ValidAuth(formencode.validators.FancyValidator):
181 class ValidAuth(formencode.validators.FancyValidator):
162 messages = {
182 messages = {
163 'invalid_password':_('invalid password'),
183 'invalid_password':_('invalid password'),
164 'invalid_login':_('invalid user name'),
184 'invalid_login':_('invalid user name'),
165 'disabled_account':_('Your account is disabled')
185 'disabled_account':_('Your account is disabled')
166
186
167 }
187 }
168 #error mapping
188 #error mapping
169 e_dict = {'username':messages['invalid_login'],
189 e_dict = {'username':messages['invalid_login'],
170 'password':messages['invalid_password']}
190 'password':messages['invalid_password']}
171 e_dict_disable = {'username':messages['disabled_account']}
191 e_dict_disable = {'username':messages['disabled_account']}
172
192
173 def validate_python(self, value, state):
193 def validate_python(self, value, state):
174 password = value['password']
194 password = value['password']
175 username = value['username']
195 username = value['username']
176 user = UserModel().get_by_username(username)
196 user = UserModel().get_by_username(username)
177
197
178 if authenticate(username, password):
198 if authenticate(username, password):
179 return value
199 return value
180 else:
200 else:
181 if user and user.active is False:
201 if user and user.active is False:
182 log.warning('user %s is disabled', username)
202 log.warning('user %s is disabled', username)
183 raise formencode.Invalid(self.message('disabled_account',
203 raise formencode.Invalid(self.message('disabled_account',
184 state=State_obj),
204 state=State_obj),
185 value, state,
205 value, state,
186 error_dict=self.e_dict_disable)
206 error_dict=self.e_dict_disable)
187 else:
207 else:
188 log.warning('user %s not authenticated', username)
208 log.warning('user %s not authenticated', username)
189 raise formencode.Invalid(self.message('invalid_password',
209 raise formencode.Invalid(self.message('invalid_password',
190 state=State_obj), value, state,
210 state=State_obj), value, state,
191 error_dict=self.e_dict)
211 error_dict=self.e_dict)
192
212
193 class ValidRepoUser(formencode.validators.FancyValidator):
213 class ValidRepoUser(formencode.validators.FancyValidator):
194
214
195 def to_python(self, value, state):
215 def to_python(self, value, state):
196 sa = meta.Session()
197 try:
216 try:
198 self.user_db = sa.query(User)\
217 self.user_db = User.query()\
199 .filter(User.active == True)\
218 .filter(User.active == True)\
200 .filter(User.username == value).one()
219 .filter(User.username == value).one()
201 except Exception:
220 except Exception:
202 raise formencode.Invalid(_('This username is not valid'),
221 raise formencode.Invalid(_('This username is not valid'),
203 value, state)
222 value, state)
204 finally:
205 meta.Session.remove()
206
207 return value
223 return value
208
224
209 def ValidRepoName(edit, old_data):
225 def ValidRepoName(edit, old_data):
210 class _ValidRepoName(formencode.validators.FancyValidator):
226 class _ValidRepoName(formencode.validators.FancyValidator):
211 def to_python(self, value, state):
227 def to_python(self, value, state):
212
228
213 repo_name = value.get('repo_name')
229 repo_name = value.get('repo_name')
214
230
215 slug = repo_name_slug(repo_name)
231 slug = repo_name_slug(repo_name)
216 if slug in ['_admin', '']:
232 if slug in ['_admin', '']:
217 e_dict = {'repo_name': _('This repository name is disallowed')}
233 e_dict = {'repo_name': _('This repository name is disallowed')}
218 raise formencode.Invalid('', value, state, error_dict=e_dict)
234 raise formencode.Invalid('', value, state, error_dict=e_dict)
219
235
220
236
221 if value.get('repo_group'):
237 if value.get('repo_group'):
222 gr = Group.get(value.get('repo_group'))
238 gr = Group.get(value.get('repo_group'))
223 group_path = gr.full_path
239 group_path = gr.full_path
224 # value needs to be aware of group name
240 # value needs to be aware of group name
241 # it has to use '/'
225 repo_name_full = group_path + '/' + repo_name
242 repo_name_full = group_path + '/' + repo_name
226 else:
243 else:
227 group_path = ''
244 group_path = ''
228 repo_name_full = repo_name
245 repo_name_full = repo_name
229
246
230
247
231 value['repo_name_full'] = repo_name_full
248 value['repo_name_full'] = repo_name_full
232 if old_data.get('repo_name') != repo_name_full or not edit:
249 if old_data.get('repo_name') != repo_name_full or not edit:
233
250
234 if group_path != '':
251 if group_path != '':
235 if RepoModel().get_by_repo_name(repo_name_full,):
252 if RepoModel().get_by_repo_name(repo_name_full,):
236 e_dict = {'repo_name':_('This repository already '
253 e_dict = {'repo_name':_('This repository already '
237 'exists in group "%s"') %
254 'exists in group "%s"') %
238 gr.group_name}
255 gr.group_name}
239 raise formencode.Invalid('', value, state,
256 raise formencode.Invalid('', value, state,
240 error_dict=e_dict)
257 error_dict=e_dict)
241
258
242 else:
259 else:
243 if RepoModel().get_by_repo_name(repo_name_full):
260 if RepoModel().get_by_repo_name(repo_name_full):
244 e_dict = {'repo_name':_('This repository '
261 e_dict = {'repo_name':_('This repository '
245 'already exists')}
262 'already exists')}
246 raise formencode.Invalid('', value, state,
263 raise formencode.Invalid('', value, state,
247 error_dict=e_dict)
264 error_dict=e_dict)
248 return value
265 return value
249
266
250
267
251 return _ValidRepoName
268 return _ValidRepoName
252
269
253 def SlugifyRepo():
270 def SlugifyName():
254 class _SlugifyRepo(formencode.validators.FancyValidator):
271 class _SlugifyName(formencode.validators.FancyValidator):
255
272
256 def to_python(self, value, state):
273 def to_python(self, value, state):
257 return repo_name_slug(value)
274 return repo_name_slug(value)
258
275
259 return _SlugifyRepo
276 return _SlugifyName
260
277
261 def ValidCloneUri():
278 def ValidCloneUri():
262 from mercurial.httprepo import httprepository, httpsrepository
279 from mercurial.httprepo import httprepository, httpsrepository
263 from rhodecode.lib.utils import make_ui
280 from rhodecode.lib.utils import make_ui
264
281
265 class _ValidCloneUri(formencode.validators.FancyValidator):
282 class _ValidCloneUri(formencode.validators.FancyValidator):
266
283
267 def to_python(self, value, state):
284 def to_python(self, value, state):
268 if not value:
285 if not value:
269 pass
286 pass
270 elif value.startswith('https'):
287 elif value.startswith('https'):
271 try:
288 try:
272 httpsrepository(make_ui('db'), value).capabilities
289 httpsrepository(make_ui('db'), value).capabilities
273 except Exception, e:
290 except Exception, e:
274 log.error(traceback.format_exc())
291 log.error(traceback.format_exc())
275 raise formencode.Invalid(_('invalid clone url'), value,
292 raise formencode.Invalid(_('invalid clone url'), value,
276 state)
293 state)
277 elif value.startswith('http'):
294 elif value.startswith('http'):
278 try:
295 try:
279 httprepository(make_ui('db'), value).capabilities
296 httprepository(make_ui('db'), value).capabilities
280 except Exception, e:
297 except Exception, e:
281 log.error(traceback.format_exc())
298 log.error(traceback.format_exc())
282 raise formencode.Invalid(_('invalid clone url'), value,
299 raise formencode.Invalid(_('invalid clone url'), value,
283 state)
300 state)
284 else:
301 else:
285 raise formencode.Invalid(_('Invalid clone url, provide a '
302 raise formencode.Invalid(_('Invalid clone url, provide a '
286 'valid clone http\s url'), value,
303 'valid clone http\s url'), value,
287 state)
304 state)
288 return value
305 return value
289
306
290 return _ValidCloneUri
307 return _ValidCloneUri
291
308
292 def ValidForkType(old_data):
309 def ValidForkType(old_data):
293 class _ValidForkType(formencode.validators.FancyValidator):
310 class _ValidForkType(formencode.validators.FancyValidator):
294
311
295 def to_python(self, value, state):
312 def to_python(self, value, state):
296 if old_data['repo_type'] != value:
313 if old_data['repo_type'] != value:
297 raise formencode.Invalid(_('Fork have to be the same '
314 raise formencode.Invalid(_('Fork have to be the same '
298 'type as original'), value, state)
315 'type as original'), value, state)
299 return value
316 return value
300 return _ValidForkType
317 return _ValidForkType
301
318
302 class ValidPerms(formencode.validators.FancyValidator):
319 class ValidPerms(formencode.validators.FancyValidator):
303 messages = {'perm_new_member_name':_('This username or users group name'
320 messages = {'perm_new_member_name':_('This username or users group name'
304 ' is not valid')}
321 ' is not valid')}
305
322
306 def to_python(self, value, state):
323 def to_python(self, value, state):
307 perms_update = []
324 perms_update = []
308 perms_new = []
325 perms_new = []
309 #build a list of permission to update and new permission to create
326 #build a list of permission to update and new permission to create
310 for k, v in value.items():
327 for k, v in value.items():
311 #means new added member to permissions
328 #means new added member to permissions
312 if k.startswith('perm_new_member'):
329 if k.startswith('perm_new_member'):
313 new_perm = value.get('perm_new_member', False)
330 new_perm = value.get('perm_new_member', False)
314 new_member = value.get('perm_new_member_name', False)
331 new_member = value.get('perm_new_member_name', False)
315 new_type = value.get('perm_new_member_type')
332 new_type = value.get('perm_new_member_type')
316
333
317 if new_member and new_perm:
334 if new_member and new_perm:
318 if (new_member, new_perm, new_type) not in perms_new:
335 if (new_member, new_perm, new_type) not in perms_new:
319 perms_new.append((new_member, new_perm, new_type))
336 perms_new.append((new_member, new_perm, new_type))
320 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
337 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
321 member = k[7:]
338 member = k[7:]
322 t = {'u':'user',
339 t = {'u':'user',
323 'g':'users_group'}[k[0]]
340 'g':'users_group'}[k[0]]
324 if member == 'default':
341 if member == 'default':
325 if value['private']:
342 if value['private']:
326 #set none for default when updating to private repo
343 #set none for default when updating to private repo
327 v = 'repository.none'
344 v = 'repository.none'
328 perms_update.append((member, v, t))
345 perms_update.append((member, v, t))
329
346
330 value['perms_updates'] = perms_update
347 value['perms_updates'] = perms_update
331 value['perms_new'] = perms_new
348 value['perms_new'] = perms_new
332
349
333 #update permissions
350 #update permissions
334 sa = meta.Session
335 for k, v, t in perms_new:
351 for k, v, t in perms_new:
336 try:
352 try:
337 if t is 'user':
353 if t is 'user':
338 self.user_db = sa.query(User)\
354 self.user_db = User.query()\
339 .filter(User.active == True)\
355 .filter(User.active == True)\
340 .filter(User.username == k).one()
356 .filter(User.username == k).one()
341 if t is 'users_group':
357 if t is 'users_group':
342 self.user_db = sa.query(UsersGroup)\
358 self.user_db = UsersGroup.query()\
343 .filter(UsersGroup.users_group_active == True)\
359 .filter(UsersGroup.users_group_active == True)\
344 .filter(UsersGroup.users_group_name == k).one()
360 .filter(UsersGroup.users_group_name == k).one()
345
361
346 except Exception:
362 except Exception:
347 msg = self.message('perm_new_member_name',
363 msg = self.message('perm_new_member_name',
348 state=State_obj)
364 state=State_obj)
349 raise formencode.Invalid(msg, value, state,
365 raise formencode.Invalid(msg, value, state,
350 error_dict={'perm_new_member_name':msg})
366 error_dict={'perm_new_member_name':msg})
351 return value
367 return value
352
368
353 class ValidSettings(formencode.validators.FancyValidator):
369 class ValidSettings(formencode.validators.FancyValidator):
354
370
355 def to_python(self, value, state):
371 def to_python(self, value, state):
356 #settings form can't edit user
372 #settings form can't edit user
357 if value.has_key('user'):
373 if value.has_key('user'):
358 del['value']['user']
374 del['value']['user']
359
375
360 return value
376 return value
361
377
362 class ValidPath(formencode.validators.FancyValidator):
378 class ValidPath(formencode.validators.FancyValidator):
363 def to_python(self, value, state):
379 def to_python(self, value, state):
364
380
365 if not os.path.isdir(value):
381 if not os.path.isdir(value):
366 msg = _('This is not a valid path')
382 msg = _('This is not a valid path')
367 raise formencode.Invalid(msg, value, state,
383 raise formencode.Invalid(msg, value, state,
368 error_dict={'paths_root_path':msg})
384 error_dict={'paths_root_path':msg})
369 return value
385 return value
370
386
371 def UniqSystemEmail(old_data):
387 def UniqSystemEmail(old_data):
372 class _UniqSystemEmail(formencode.validators.FancyValidator):
388 class _UniqSystemEmail(formencode.validators.FancyValidator):
373 def to_python(self, value, state):
389 def to_python(self, value, state):
374 value = value.lower()
390 value = value.lower()
375 if old_data.get('email') != value:
391 if old_data.get('email') != value:
376 sa = meta.Session()
392 user = User.query().filter(User.email == value).scalar()
377 try:
378 user = sa.query(User).filter(User.email == value).scalar()
379 if user:
393 if user:
380 raise formencode.Invalid(_("This e-mail address is already taken") ,
394 raise formencode.Invalid(
395 _("This e-mail address is already taken"),
381 value, state)
396 value, state)
382 finally:
383 meta.Session.remove()
384
385 return value
397 return value
386
398
387 return _UniqSystemEmail
399 return _UniqSystemEmail
388
400
389 class ValidSystemEmail(formencode.validators.FancyValidator):
401 class ValidSystemEmail(formencode.validators.FancyValidator):
390 def to_python(self, value, state):
402 def to_python(self, value, state):
391 value = value.lower()
403 value = value.lower()
392 sa = meta.Session
404 user = User.query().filter(User.email == value).scalar()
393 try:
394 user = sa.query(User).filter(User.email == value).scalar()
395 if user is None:
405 if user is None:
396 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
406 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
397 value, state)
407 value, state)
398 finally:
399 meta.Session.remove()
400
408
401 return value
409 return value
402
410
403 class LdapLibValidator(formencode.validators.FancyValidator):
411 class LdapLibValidator(formencode.validators.FancyValidator):
404
412
405 def to_python(self, value, state):
413 def to_python(self, value, state):
406
414
407 try:
415 try:
408 import ldap
416 import ldap
409 except ImportError:
417 except ImportError:
410 raise LdapImportError
418 raise LdapImportError
411 return value
419 return value
412
420
413 class AttrLoginValidator(formencode.validators.FancyValidator):
421 class AttrLoginValidator(formencode.validators.FancyValidator):
414
422
415 def to_python(self, value, state):
423 def to_python(self, value, state):
416
424
417 if not value or not isinstance(value, (str, unicode)):
425 if not value or not isinstance(value, (str, unicode)):
418 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
426 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
419 "must be specified - this is the name "
427 "must be specified - this is the name "
420 "of the attribute that is equivalent "
428 "of the attribute that is equivalent "
421 "to 'username'"),
429 "to 'username'"),
422 value, state)
430 value, state)
423
431
424 return value
432 return value
425
433
426 #===============================================================================
434 #===============================================================================
427 # FORMS
435 # FORMS
428 #===============================================================================
436 #===============================================================================
429 class LoginForm(formencode.Schema):
437 class LoginForm(formencode.Schema):
430 allow_extra_fields = True
438 allow_extra_fields = True
431 filter_extra_fields = True
439 filter_extra_fields = True
432 username = UnicodeString(
440 username = UnicodeString(
433 strip=True,
441 strip=True,
434 min=1,
442 min=1,
435 not_empty=True,
443 not_empty=True,
436 messages={
444 messages={
437 'empty':_('Please enter a login'),
445 'empty':_('Please enter a login'),
438 'tooShort':_('Enter a value %(min)i characters long or more')}
446 'tooShort':_('Enter a value %(min)i characters long or more')}
439 )
447 )
440
448
441 password = UnicodeString(
449 password = UnicodeString(
442 strip=True,
450 strip=True,
443 min=6,
451 min=6,
444 not_empty=True,
452 not_empty=True,
445 messages={
453 messages={
446 'empty':_('Please enter a password'),
454 'empty':_('Please enter a password'),
447 'tooShort':_('Enter %(min)i characters or more')}
455 'tooShort':_('Enter %(min)i characters or more')}
448 )
456 )
449
457
450
458
451 #chained validators have access to all data
459 #chained validators have access to all data
452 chained_validators = [ValidAuth]
460 chained_validators = [ValidAuth]
453
461
454 def UserForm(edit=False, old_data={}):
462 def UserForm(edit=False, old_data={}):
455 class _UserForm(formencode.Schema):
463 class _UserForm(formencode.Schema):
456 allow_extra_fields = True
464 allow_extra_fields = True
457 filter_extra_fields = True
465 filter_extra_fields = True
458 username = All(UnicodeString(strip=True, min=1, not_empty=True),
466 username = All(UnicodeString(strip=True, min=1, not_empty=True),
459 ValidUsername(edit, old_data))
467 ValidUsername(edit, old_data))
460 if edit:
468 if edit:
461 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
469 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
462 admin = StringBoolean(if_missing=False)
470 admin = StringBoolean(if_missing=False)
463 else:
471 else:
464 password = All(UnicodeString(strip=True, min=6, not_empty=True))
472 password = All(UnicodeString(strip=True, min=6, not_empty=True))
465 active = StringBoolean(if_missing=False)
473 active = StringBoolean(if_missing=False)
466 name = UnicodeString(strip=True, min=1, not_empty=True)
474 name = UnicodeString(strip=True, min=1, not_empty=True)
467 lastname = UnicodeString(strip=True, min=1, not_empty=True)
475 lastname = UnicodeString(strip=True, min=1, not_empty=True)
468 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
476 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
469
477
470 chained_validators = [ValidPassword]
478 chained_validators = [ValidPassword]
471
479
472 return _UserForm
480 return _UserForm
473
481
474
482
475 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
483 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
476 class _UsersGroupForm(formencode.Schema):
484 class _UsersGroupForm(formencode.Schema):
477 allow_extra_fields = True
485 allow_extra_fields = True
478 filter_extra_fields = True
486 filter_extra_fields = True
479
487
480 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
488 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
481 ValidUsersGroup(edit, old_data))
489 ValidUsersGroup(edit, old_data))
482
490
483 users_group_active = StringBoolean(if_missing=False)
491 users_group_active = StringBoolean(if_missing=False)
484
492
485 if edit:
493 if edit:
486 users_group_members = OneOf(available_members, hideList=False,
494 users_group_members = OneOf(available_members, hideList=False,
487 testValueList=True,
495 testValueList=True,
488 if_missing=None, not_empty=False)
496 if_missing=None, not_empty=False)
489
497
490 return _UsersGroupForm
498 return _UsersGroupForm
491
499
500 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
501 class _ReposGroupForm(formencode.Schema):
502 allow_extra_fields = True
503 filter_extra_fields = True
504
505 repos_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
506 SlugifyName())
507 repos_group_description = UnicodeString(strip=True, min=1,
508 not_empty=True)
509 repos_group_parent = OneOf(available_groups, hideList=False,
510 testValueList=True,
511 if_missing=None, not_empty=False)
512
513 chained_validators = [ValidReposGroup(edit, old_data)]
514
515 return _ReposGroupForm
516
492 def RegisterForm(edit=False, old_data={}):
517 def RegisterForm(edit=False, old_data={}):
493 class _RegisterForm(formencode.Schema):
518 class _RegisterForm(formencode.Schema):
494 allow_extra_fields = True
519 allow_extra_fields = True
495 filter_extra_fields = True
520 filter_extra_fields = True
496 username = All(ValidUsername(edit, old_data),
521 username = All(ValidUsername(edit, old_data),
497 UnicodeString(strip=True, min=1, not_empty=True))
522 UnicodeString(strip=True, min=1, not_empty=True))
498 password = All(UnicodeString(strip=True, min=6, not_empty=True))
523 password = All(UnicodeString(strip=True, min=6, not_empty=True))
499 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
524 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
500 active = StringBoolean(if_missing=False)
525 active = StringBoolean(if_missing=False)
501 name = UnicodeString(strip=True, min=1, not_empty=True)
526 name = UnicodeString(strip=True, min=1, not_empty=True)
502 lastname = UnicodeString(strip=True, min=1, not_empty=True)
527 lastname = UnicodeString(strip=True, min=1, not_empty=True)
503 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
528 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
504
529
505 chained_validators = [ValidPasswordsMatch, ValidPassword]
530 chained_validators = [ValidPasswordsMatch, ValidPassword]
506
531
507 return _RegisterForm
532 return _RegisterForm
508
533
509 def PasswordResetForm():
534 def PasswordResetForm():
510 class _PasswordResetForm(formencode.Schema):
535 class _PasswordResetForm(formencode.Schema):
511 allow_extra_fields = True
536 allow_extra_fields = True
512 filter_extra_fields = True
537 filter_extra_fields = True
513 email = All(ValidSystemEmail(), Email(not_empty=True))
538 email = All(ValidSystemEmail(), Email(not_empty=True))
514 return _PasswordResetForm
539 return _PasswordResetForm
515
540
516 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
541 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
517 repo_groups=[]):
542 repo_groups=[]):
518 class _RepoForm(formencode.Schema):
543 class _RepoForm(formencode.Schema):
519 allow_extra_fields = True
544 allow_extra_fields = True
520 filter_extra_fields = False
545 filter_extra_fields = False
521 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
546 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
522 SlugifyRepo())
547 SlugifyName())
523 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
548 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
524 ValidCloneUri()())
549 ValidCloneUri()())
525 repo_group = OneOf(repo_groups, hideList=True)
550 repo_group = OneOf(repo_groups, hideList=True)
526 repo_type = OneOf(supported_backends)
551 repo_type = OneOf(supported_backends)
527 description = UnicodeString(strip=True, min=1, not_empty=True)
552 description = UnicodeString(strip=True, min=1, not_empty=True)
528 private = StringBoolean(if_missing=False)
553 private = StringBoolean(if_missing=False)
529 enable_statistics = StringBoolean(if_missing=False)
554 enable_statistics = StringBoolean(if_missing=False)
530 enable_downloads = StringBoolean(if_missing=False)
555 enable_downloads = StringBoolean(if_missing=False)
531
556
532 if edit:
557 if edit:
533 #this is repo owner
558 #this is repo owner
534 user = All(UnicodeString(not_empty=True), ValidRepoUser)
559 user = All(UnicodeString(not_empty=True), ValidRepoUser)
535
560
536 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
561 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
537 return _RepoForm
562 return _RepoForm
538
563
539 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
564 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
540 class _RepoForkForm(formencode.Schema):
565 class _RepoForkForm(formencode.Schema):
541 allow_extra_fields = True
566 allow_extra_fields = True
542 filter_extra_fields = False
567 filter_extra_fields = False
543 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
568 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
544 SlugifyRepo())
569 SlugifyName())
545 description = UnicodeString(strip=True, min=1, not_empty=True)
570 description = UnicodeString(strip=True, min=1, not_empty=True)
546 private = StringBoolean(if_missing=False)
571 private = StringBoolean(if_missing=False)
547 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
572 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
548 return _RepoForkForm
573 return _RepoForkForm
549
574
550 def RepoSettingsForm(edit=False, old_data={}):
575 def RepoSettingsForm(edit=False, old_data={}):
551 class _RepoForm(formencode.Schema):
576 class _RepoForm(formencode.Schema):
552 allow_extra_fields = True
577 allow_extra_fields = True
553 filter_extra_fields = False
578 filter_extra_fields = False
554 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
579 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
555 SlugifyRepo())
580 SlugifyName())
556 description = UnicodeString(strip=True, min=1, not_empty=True)
581 description = UnicodeString(strip=True, min=1, not_empty=True)
557 private = StringBoolean(if_missing=False)
582 private = StringBoolean(if_missing=False)
558
583
559 chained_validators = [ValidRepoName(edit, old_data), ValidPerms, ValidSettings]
584 chained_validators = [ValidRepoName(edit, old_data), ValidPerms, ValidSettings]
560 return _RepoForm
585 return _RepoForm
561
586
562
587
563 def ApplicationSettingsForm():
588 def ApplicationSettingsForm():
564 class _ApplicationSettingsForm(formencode.Schema):
589 class _ApplicationSettingsForm(formencode.Schema):
565 allow_extra_fields = True
590 allow_extra_fields = True
566 filter_extra_fields = False
591 filter_extra_fields = False
567 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
592 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
568 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
593 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
569 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
594 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
570
595
571 return _ApplicationSettingsForm
596 return _ApplicationSettingsForm
572
597
573 def ApplicationUiSettingsForm():
598 def ApplicationUiSettingsForm():
574 class _ApplicationUiSettingsForm(formencode.Schema):
599 class _ApplicationUiSettingsForm(formencode.Schema):
575 allow_extra_fields = True
600 allow_extra_fields = True
576 filter_extra_fields = False
601 filter_extra_fields = False
577 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
602 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
578 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
603 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
579 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
604 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
580 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
605 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
581 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
606 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
582 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
607 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
583
608
584 return _ApplicationUiSettingsForm
609 return _ApplicationUiSettingsForm
585
610
586 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
611 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
587 class _DefaultPermissionsForm(formencode.Schema):
612 class _DefaultPermissionsForm(formencode.Schema):
588 allow_extra_fields = True
613 allow_extra_fields = True
589 filter_extra_fields = True
614 filter_extra_fields = True
590 overwrite_default = StringBoolean(if_missing=False)
615 overwrite_default = StringBoolean(if_missing=False)
591 anonymous = OneOf(['True', 'False'], if_missing=False)
616 anonymous = OneOf(['True', 'False'], if_missing=False)
592 default_perm = OneOf(perms_choices)
617 default_perm = OneOf(perms_choices)
593 default_register = OneOf(register_choices)
618 default_register = OneOf(register_choices)
594 default_create = OneOf(create_choices)
619 default_create = OneOf(create_choices)
595
620
596 return _DefaultPermissionsForm
621 return _DefaultPermissionsForm
597
622
598
623
599 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
624 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
600 class _LdapSettingsForm(formencode.Schema):
625 class _LdapSettingsForm(formencode.Schema):
601 allow_extra_fields = True
626 allow_extra_fields = True
602 filter_extra_fields = True
627 filter_extra_fields = True
603 pre_validators = [LdapLibValidator]
628 pre_validators = [LdapLibValidator]
604 ldap_active = StringBoolean(if_missing=False)
629 ldap_active = StringBoolean(if_missing=False)
605 ldap_host = UnicodeString(strip=True,)
630 ldap_host = UnicodeString(strip=True,)
606 ldap_port = Number(strip=True,)
631 ldap_port = Number(strip=True,)
607 ldap_tls_kind = OneOf(tls_kind_choices)
632 ldap_tls_kind = OneOf(tls_kind_choices)
608 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
633 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
609 ldap_dn_user = UnicodeString(strip=True,)
634 ldap_dn_user = UnicodeString(strip=True,)
610 ldap_dn_pass = UnicodeString(strip=True,)
635 ldap_dn_pass = UnicodeString(strip=True,)
611 ldap_base_dn = UnicodeString(strip=True,)
636 ldap_base_dn = UnicodeString(strip=True,)
612 ldap_filter = UnicodeString(strip=True,)
637 ldap_filter = UnicodeString(strip=True,)
613 ldap_search_scope = OneOf(search_scope_choices)
638 ldap_search_scope = OneOf(search_scope_choices)
614 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
639 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
615 ldap_attr_firstname = UnicodeString(strip=True,)
640 ldap_attr_firstname = UnicodeString(strip=True,)
616 ldap_attr_lastname = UnicodeString(strip=True,)
641 ldap_attr_lastname = UnicodeString(strip=True,)
617 ldap_attr_email = UnicodeString(strip=True,)
642 ldap_attr_email = UnicodeString(strip=True,)
618
643
619 return _LdapSettingsForm
644 return _LdapSettingsForm
@@ -1,2658 +1,2665 b''
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
2 border:0;
2 border:0;
3 outline:0;
3 outline:0;
4 font-size:100%;
4 font-size:100%;
5 vertical-align:baseline;
5 vertical-align:baseline;
6 background:transparent;
6 background:transparent;
7 margin:0;
7 margin:0;
8 padding:0;
8 padding:0;
9 }
9 }
10
10
11 body {
11 body {
12 line-height:1;
12 line-height:1;
13 height:100%;
13 height:100%;
14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 font-size:12px;
16 font-size:12px;
17 color:#000;
17 color:#000;
18 margin:0;
18 margin:0;
19 padding:0;
19 padding:0;
20 }
20 }
21
21
22 ol,ul {
22 ol,ul {
23 list-style:none;
23 list-style:none;
24 }
24 }
25
25
26 blockquote,q {
26 blockquote,q {
27 quotes:none;
27 quotes:none;
28 }
28 }
29
29
30 blockquote:before,blockquote:after,q:before,q:after {
30 blockquote:before,blockquote:after,q:before,q:after {
31 content:none;
31 content:none;
32 }
32 }
33
33
34 :focus {
34 :focus {
35 outline:0;
35 outline:0;
36 }
36 }
37
37
38 del {
38 del {
39 text-decoration:line-through;
39 text-decoration:line-through;
40 }
40 }
41
41
42 table {
42 table {
43 border-collapse:collapse;
43 border-collapse:collapse;
44 border-spacing:0;
44 border-spacing:0;
45 }
45 }
46
46
47 html {
47 html {
48 height:100%;
48 height:100%;
49 }
49 }
50
50
51 a {
51 a {
52 color:#003367;
52 color:#003367;
53 text-decoration:none;
53 text-decoration:none;
54 cursor:pointer;
54 cursor:pointer;
55 font-weight:700;
55 font-weight:700;
56 }
56 }
57
57
58 a:hover {
58 a:hover {
59 color:#316293;
59 color:#316293;
60 text-decoration:underline;
60 text-decoration:underline;
61 }
61 }
62
62
63 h1,h2,h3,h4,h5,h6 {
63 h1,h2,h3,h4,h5,h6 {
64 color:#292929;
64 color:#292929;
65 font-weight:700;
65 font-weight:700;
66 }
66 }
67
67
68 h1 {
68 h1 {
69 font-size:22px;
69 font-size:22px;
70 }
70 }
71
71
72 h2 {
72 h2 {
73 font-size:20px;
73 font-size:20px;
74 }
74 }
75
75
76 h3 {
76 h3 {
77 font-size:18px;
77 font-size:18px;
78 }
78 }
79
79
80 h4 {
80 h4 {
81 font-size:16px;
81 font-size:16px;
82 }
82 }
83
83
84 h5 {
84 h5 {
85 font-size:14px;
85 font-size:14px;
86 }
86 }
87
87
88 h6 {
88 h6 {
89 font-size:11px;
89 font-size:11px;
90 }
90 }
91
91
92 ul.circle {
92 ul.circle {
93 list-style-type:circle;
93 list-style-type:circle;
94 }
94 }
95
95
96 ul.disc {
96 ul.disc {
97 list-style-type:disc;
97 list-style-type:disc;
98 }
98 }
99
99
100 ul.square {
100 ul.square {
101 list-style-type:square;
101 list-style-type:square;
102 }
102 }
103
103
104 ol.lower-roman {
104 ol.lower-roman {
105 list-style-type:lower-roman;
105 list-style-type:lower-roman;
106 }
106 }
107
107
108 ol.upper-roman {
108 ol.upper-roman {
109 list-style-type:upper-roman;
109 list-style-type:upper-roman;
110 }
110 }
111
111
112 ol.lower-alpha {
112 ol.lower-alpha {
113 list-style-type:lower-alpha;
113 list-style-type:lower-alpha;
114 }
114 }
115
115
116 ol.upper-alpha {
116 ol.upper-alpha {
117 list-style-type:upper-alpha;
117 list-style-type:upper-alpha;
118 }
118 }
119
119
120 ol.decimal {
120 ol.decimal {
121 list-style-type:decimal;
121 list-style-type:decimal;
122 }
122 }
123
123
124 div.color {
124 div.color {
125 clear:both;
125 clear:both;
126 overflow:hidden;
126 overflow:hidden;
127 position:absolute;
127 position:absolute;
128 background:#FFF;
128 background:#FFF;
129 margin:7px 0 0 60px;
129 margin:7px 0 0 60px;
130 padding:1px 1px 1px 0;
130 padding:1px 1px 1px 0;
131 }
131 }
132
132
133 div.color a {
133 div.color a {
134 width:15px;
134 width:15px;
135 height:15px;
135 height:15px;
136 display:block;
136 display:block;
137 float:left;
137 float:left;
138 margin:0 0 0 1px;
138 margin:0 0 0 1px;
139 padding:0;
139 padding:0;
140 }
140 }
141
141
142 div.options {
142 div.options {
143 clear:both;
143 clear:both;
144 overflow:hidden;
144 overflow:hidden;
145 position:absolute;
145 position:absolute;
146 background:#FFF;
146 background:#FFF;
147 margin:7px 0 0 162px;
147 margin:7px 0 0 162px;
148 padding:0;
148 padding:0;
149 }
149 }
150
150
151 div.options a {
151 div.options a {
152 height:1%;
152 height:1%;
153 display:block;
153 display:block;
154 text-decoration:none;
154 text-decoration:none;
155 margin:0;
155 margin:0;
156 padding:3px 8px;
156 padding:3px 8px;
157 }
157 }
158
158
159 .top-left-rounded-corner {
159 .top-left-rounded-corner {
160 -webkit-border-top-left-radius: 8px;
160 -webkit-border-top-left-radius: 8px;
161 -khtml-border-radius-topleft: 8px;
161 -khtml-border-radius-topleft: 8px;
162 -moz-border-radius-topleft: 8px;
162 -moz-border-radius-topleft: 8px;
163 border-top-left-radius: 8px;
163 border-top-left-radius: 8px;
164 }
164 }
165
165
166 .top-right-rounded-corner {
166 .top-right-rounded-corner {
167 -webkit-border-top-right-radius: 8px;
167 -webkit-border-top-right-radius: 8px;
168 -khtml-border-radius-topright: 8px;
168 -khtml-border-radius-topright: 8px;
169 -moz-border-radius-topright: 8px;
169 -moz-border-radius-topright: 8px;
170 border-top-right-radius: 8px;
170 border-top-right-radius: 8px;
171 }
171 }
172
172
173 .bottom-left-rounded-corner {
173 .bottom-left-rounded-corner {
174 -webkit-border-bottom-left-radius: 8px;
174 -webkit-border-bottom-left-radius: 8px;
175 -khtml-border-radius-bottomleft: 8px;
175 -khtml-border-radius-bottomleft: 8px;
176 -moz-border-radius-bottomleft: 8px;
176 -moz-border-radius-bottomleft: 8px;
177 border-bottom-left-radius: 8px;
177 border-bottom-left-radius: 8px;
178 }
178 }
179
179
180 .bottom-right-rounded-corner {
180 .bottom-right-rounded-corner {
181 -webkit-border-bottom-right-radius: 8px;
181 -webkit-border-bottom-right-radius: 8px;
182 -khtml-border-radius-bottomright: 8px;
182 -khtml-border-radius-bottomright: 8px;
183 -moz-border-radius-bottomright: 8px;
183 -moz-border-radius-bottomright: 8px;
184 border-bottom-right-radius: 8px;
184 border-bottom-right-radius: 8px;
185 }
185 }
186
186
187
187
188 #header {
188 #header {
189 margin:0;
189 margin:0;
190 padding:0 10px;
190 padding:0 10px;
191 }
191 }
192
192
193
193
194 #header ul#logged-user{
194 #header ul#logged-user{
195 margin-bottom:5px !important;
195 margin-bottom:5px !important;
196 -webkit-border-radius: 0px 0px 8px 8px;
196 -webkit-border-radius: 0px 0px 8px 8px;
197 -khtml-border-radius: 0px 0px 8px 8px;
197 -khtml-border-radius: 0px 0px 8px 8px;
198 -moz-border-radius: 0px 0px 8px 8px;
198 -moz-border-radius: 0px 0px 8px 8px;
199 border-radius: 0px 0px 8px 8px;
199 border-radius: 0px 0px 8px 8px;
200 height:37px;
200 height:37px;
201 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
201 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
202 }
202 }
203
203
204 #header ul#logged-user li {
204 #header ul#logged-user li {
205 list-style:none;
205 list-style:none;
206 float:left;
206 float:left;
207 margin:8px 0 0;
207 margin:8px 0 0;
208 padding:4px 12px;
208 padding:4px 12px;
209 border-left: 1px solid #316293;
209 border-left: 1px solid #316293;
210 }
210 }
211
211
212 #header ul#logged-user li.first {
212 #header ul#logged-user li.first {
213 border-left:none;
213 border-left:none;
214 margin:4px;
214 margin:4px;
215 }
215 }
216
216
217 #header ul#logged-user li.first div.gravatar {
217 #header ul#logged-user li.first div.gravatar {
218 margin-top:-2px;
218 margin-top:-2px;
219 }
219 }
220
220
221 #header ul#logged-user li.first div.account {
221 #header ul#logged-user li.first div.account {
222 padding-top:4px;
222 padding-top:4px;
223 float:left;
223 float:left;
224 }
224 }
225
225
226 #header ul#logged-user li.last {
226 #header ul#logged-user li.last {
227 border-right:none;
227 border-right:none;
228 }
228 }
229
229
230 #header ul#logged-user li a {
230 #header ul#logged-user li a {
231 color:#fff;
231 color:#fff;
232 font-weight:700;
232 font-weight:700;
233 text-decoration:none;
233 text-decoration:none;
234 }
234 }
235
235
236 #header ul#logged-user li a:hover {
236 #header ul#logged-user li a:hover {
237 text-decoration:underline;
237 text-decoration:underline;
238 }
238 }
239
239
240 #header ul#logged-user li.highlight a {
240 #header ul#logged-user li.highlight a {
241 color:#fff;
241 color:#fff;
242 }
242 }
243
243
244 #header ul#logged-user li.highlight a:hover {
244 #header ul#logged-user li.highlight a:hover {
245 color:#FFF;
245 color:#FFF;
246 }
246 }
247
247
248 #header #header-inner {
248 #header #header-inner {
249 height:40px;
249 height:40px;
250 clear:both;
250 clear:both;
251 position:relative;
251 position:relative;
252 background:#003367 url("../images/header_inner.png") repeat-x;
252 background:#003367 url("../images/header_inner.png") repeat-x;
253 border-bottom:2px solid #fff;
253 border-bottom:2px solid #fff;
254 margin:0;
254 margin:0;
255 padding:0;
255 padding:0;
256 }
256 }
257
257
258 #header #header-inner #home a {
258 #header #header-inner #home a {
259 height:40px;
259 height:40px;
260 width:46px;
260 width:46px;
261 display:block;
261 display:block;
262 background:url("../images/button_home.png");
262 background:url("../images/button_home.png");
263 background-position:0 0;
263 background-position:0 0;
264 margin:0;
264 margin:0;
265 padding:0;
265 padding:0;
266 }
266 }
267
267
268 #header #header-inner #home a:hover {
268 #header #header-inner #home a:hover {
269 background-position:0 -40px;
269 background-position:0 -40px;
270 }
270 }
271
271
272 #header #header-inner #logo h1 {
272 #header #header-inner #logo h1 {
273 color:#FFF;
273 color:#FFF;
274 font-size:18px;
274 font-size:18px;
275 margin:10px 0 0 13px;
275 margin:10px 0 0 13px;
276 padding:0;
276 padding:0;
277 }
277 }
278
278
279 #header #header-inner #logo a {
279 #header #header-inner #logo a {
280 color:#fff;
280 color:#fff;
281 text-decoration:none;
281 text-decoration:none;
282 }
282 }
283
283
284 #header #header-inner #logo a:hover {
284 #header #header-inner #logo a:hover {
285 color:#bfe3ff;
285 color:#bfe3ff;
286 }
286 }
287
287
288 #header #header-inner #quick,#header #header-inner #quick ul {
288 #header #header-inner #quick,#header #header-inner #quick ul {
289 position:relative;
289 position:relative;
290 float:right;
290 float:right;
291 list-style-type:none;
291 list-style-type:none;
292 list-style-position:outside;
292 list-style-position:outside;
293 margin:10px 5px 0 0;
293 margin:10px 5px 0 0;
294 padding:0;
294 padding:0;
295 }
295 }
296
296
297 #header #header-inner #quick li {
297 #header #header-inner #quick li {
298 position:relative;
298 position:relative;
299 float:left;
299 float:left;
300 margin:0 5px 0 0;
300 margin:0 5px 0 0;
301 padding:0;
301 padding:0;
302 }
302 }
303
303
304 #header #header-inner #quick li a {
304 #header #header-inner #quick li a {
305 top:0;
305 top:0;
306 left:0;
306 left:0;
307 height:1%;
307 height:1%;
308 display:block;
308 display:block;
309 clear:both;
309 clear:both;
310 overflow:hidden;
310 overflow:hidden;
311 color:#FFF;
311 color:#FFF;
312 font-weight:700;
312 font-weight:700;
313 text-decoration:none;
313 text-decoration:none;
314 background:#369 url("../images/quick_l.png") no-repeat top left;
314 background:#369 url("../images/quick_l.png") no-repeat top left;
315 padding:0;
315 padding:0;
316 }
316 }
317
317
318 #header #header-inner #quick li span.short {
318 #header #header-inner #quick li span.short {
319 padding:9px 6px 8px 6px;
319 padding:9px 6px 8px 6px;
320 }
320 }
321
321
322 #header #header-inner #quick li span {
322 #header #header-inner #quick li span {
323 top:0;
323 top:0;
324 right:0;
324 right:0;
325 height:1%;
325 height:1%;
326 display:block;
326 display:block;
327 float:left;
327 float:left;
328 background:url("../images/quick_r.png") no-repeat top right;
328 background:url("../images/quick_r.png") no-repeat top right;
329 border-left:1px solid #3f6f9f;
329 border-left:1px solid #3f6f9f;
330 margin:0;
330 margin:0;
331 padding:10px 12px 8px 10px;
331 padding:10px 12px 8px 10px;
332 }
332 }
333
333
334 #header #header-inner #quick li span.normal {
334 #header #header-inner #quick li span.normal {
335 border:none;
335 border:none;
336 padding:10px 12px 8px;
336 padding:10px 12px 8px;
337 }
337 }
338
338
339 #header #header-inner #quick li span.icon {
339 #header #header-inner #quick li span.icon {
340 top:0;
340 top:0;
341 left:0;
341 left:0;
342 border-left:none;
342 border-left:none;
343 background:url("../images/quick_l.png") no-repeat top left;
343 background:url("../images/quick_l.png") no-repeat top left;
344 border-right:1px solid #2e5c89;
344 border-right:1px solid #2e5c89;
345 padding:8px 8px 4px;
345 padding:8px 8px 4px;
346 }
346 }
347
347
348 #header #header-inner #quick li span.icon_short {
348 #header #header-inner #quick li span.icon_short {
349 top:0;
349 top:0;
350 left:0;
350 left:0;
351 border-left:none;
351 border-left:none;
352 background:url("../images/quick_l.png") no-repeat top left;
352 background:url("../images/quick_l.png") no-repeat top left;
353 border-right:1px solid #2e5c89;
353 border-right:1px solid #2e5c89;
354 padding:9px 4px 4px;
354 padding:9px 4px 4px;
355 }
355 }
356
356
357 #header #header-inner #quick li a:hover {
357 #header #header-inner #quick li a:hover {
358 background:#4e4e4e url("../images/quick_l_selected.png") no-repeat top left;
358 background:#4e4e4e url("../images/quick_l_selected.png") no-repeat top left;
359 }
359 }
360
360
361 #header #header-inner #quick li a:hover span {
361 #header #header-inner #quick li a:hover span {
362 border-left:1px solid #545454;
362 border-left:1px solid #545454;
363 background:url("../images/quick_r_selected.png") no-repeat top right;
363 background:url("../images/quick_r_selected.png") no-repeat top right;
364 }
364 }
365
365
366 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
366 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
367 border-left:none;
367 border-left:none;
368 border-right:1px solid #464646;
368 border-right:1px solid #464646;
369 background:url("../images/quick_l_selected.png") no-repeat top left;
369 background:url("../images/quick_l_selected.png") no-repeat top left;
370 }
370 }
371
371
372
372
373 #header #header-inner #quick ul {
373 #header #header-inner #quick ul {
374 top:29px;
374 top:29px;
375 right:0;
375 right:0;
376 min-width:200px;
376 min-width:200px;
377 display:none;
377 display:none;
378 position:absolute;
378 position:absolute;
379 background:#FFF;
379 background:#FFF;
380 border:1px solid #666;
380 border:1px solid #666;
381 border-top:1px solid #003367;
381 border-top:1px solid #003367;
382 z-index:100;
382 z-index:100;
383 margin:0;
383 margin:0;
384 padding:0;
384 padding:0;
385 }
385 }
386
386
387 #header #header-inner #quick ul.repo_switcher {
387 #header #header-inner #quick ul.repo_switcher {
388 max-height:275px;
388 max-height:275px;
389 overflow-x:hidden;
389 overflow-x:hidden;
390 overflow-y:auto;
390 overflow-y:auto;
391 }
391 }
392 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
392 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
393 float:none;
393 float:none;
394 margin:0;
394 margin:0;
395 border-bottom:2px solid #003367;
395 border-bottom:2px solid #003367;
396 }
396 }
397
397
398
398
399 #header #header-inner #quick .repo_switcher_type{
399 #header #header-inner #quick .repo_switcher_type{
400 position:absolute;
400 position:absolute;
401 left:0;
401 left:0;
402 top:9px;
402 top:9px;
403
403
404 }
404 }
405 #header #header-inner #quick li ul li {
405 #header #header-inner #quick li ul li {
406 border-bottom:1px solid #ddd;
406 border-bottom:1px solid #ddd;
407 }
407 }
408
408
409 #header #header-inner #quick li ul li a {
409 #header #header-inner #quick li ul li a {
410 width:182px;
410 width:182px;
411 height:auto;
411 height:auto;
412 display:block;
412 display:block;
413 float:left;
413 float:left;
414 background:#FFF;
414 background:#FFF;
415 color:#003367;
415 color:#003367;
416 font-weight:400;
416 font-weight:400;
417 margin:0;
417 margin:0;
418 padding:7px 9px;
418 padding:7px 9px;
419 }
419 }
420
420
421 #header #header-inner #quick li ul li a:hover {
421 #header #header-inner #quick li ul li a:hover {
422 color:#000;
422 color:#000;
423 background:#FFF;
423 background:#FFF;
424 }
424 }
425
425
426 #header #header-inner #quick ul ul {
426 #header #header-inner #quick ul ul {
427 top:auto;
427 top:auto;
428 }
428 }
429
429
430 #header #header-inner #quick li ul ul {
430 #header #header-inner #quick li ul ul {
431 right:200px;
431 right:200px;
432 max-height:275px;
432 max-height:275px;
433 overflow:auto;
433 overflow:auto;
434 overflow-x:hidden;
434 overflow-x:hidden;
435 white-space:normal;
435 white-space:normal;
436 }
436 }
437
437
438 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
438 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
439 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
439 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
440 width:167px;
440 width:167px;
441 margin:0;
441 margin:0;
442 padding:12px 9px 7px 24px;
442 padding:12px 9px 7px 24px;
443 }
443 }
444
444
445 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
445 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
446 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
446 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
447 min-width:167px;
447 min-width:167px;
448 margin:0;
448 margin:0;
449 padding:12px 9px 7px 24px;
449 padding:12px 9px 7px 24px;
450 }
450 }
451
451
452 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
452 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
453 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
453 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
454 min-width:167px;
454 min-width:167px;
455 margin:0;
455 margin:0;
456 padding:12px 9px 7px 24px;
456 padding:12px 9px 7px 24px;
457 }
457 }
458
458
459 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
459 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
460 background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
460 background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
461 min-width:167px;
461 min-width:167px;
462 margin:0 0 0 14px;
462 margin:0 0 0 14px;
463 padding:12px 9px 7px 24px;
463 padding:12px 9px 7px 24px;
464 }
464 }
465
465
466 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
466 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
467 background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
467 background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
468 min-width:167px;
468 min-width:167px;
469 margin:0 0 0 14px;
469 margin:0 0 0 14px;
470 padding:12px 9px 7px 24px;
470 padding:12px 9px 7px 24px;
471 }
471 }
472
472
473 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
473 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
474 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
474 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
475 width:167px;
475 width:167px;
476 margin:0;
476 margin:0;
477 padding:12px 9px 7px 24px;
477 padding:12px 9px 7px 24px;
478 }
478 }
479
479
480 #header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover {
481 background:url("../images/icons/database_link.png") no-repeat scroll 4px 9px #FFF;
482 width:167px;
483 margin:0;
484 padding:12px 9px 7px 24px;
485 }
486
480 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
487 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
481 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
488 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
482 width:167px;
489 width:167px;
483 margin:0;
490 margin:0;
484 padding:12px 9px 7px 24px;
491 padding:12px 9px 7px 24px;
485 }
492 }
486
493
487 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover {
494 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover {
488 background:#FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
495 background:#FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
489 width:167px;
496 width:167px;
490 margin:0;
497 margin:0;
491 padding:12px 9px 7px 24px;
498 padding:12px 9px 7px 24px;
492 }
499 }
493
500
494 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
501 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
495 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
502 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
496 width:167px;
503 width:167px;
497 margin:0;
504 margin:0;
498 padding:12px 9px 7px 24px;
505 padding:12px 9px 7px 24px;
499 }
506 }
500
507
501 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
508 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
502 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
509 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
503 width:167px;
510 width:167px;
504 margin:0;
511 margin:0;
505 padding:12px 9px 7px 24px;
512 padding:12px 9px 7px 24px;
506 }
513 }
507
514
508 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
515 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
509 background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
516 background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
510 width:167px;
517 width:167px;
511 margin:0;
518 margin:0;
512 padding:12px 9px 7px 24px;
519 padding:12px 9px 7px 24px;
513 }
520 }
514
521
515 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
522 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
516 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
523 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
517 width:167px;
524 width:167px;
518 margin:0;
525 margin:0;
519 padding:12px 9px 7px 24px;
526 padding:12px 9px 7px 24px;
520 }
527 }
521
528
522 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
529 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
523 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
530 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
524 width:167px;
531 width:167px;
525 margin:0;
532 margin:0;
526 padding:12px 9px 7px 24px;
533 padding:12px 9px 7px 24px;
527 }
534 }
528
535
529 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
536 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
530 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
537 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
531 width:167px;
538 width:167px;
532 margin:0;
539 margin:0;
533 padding:12px 9px 7px 24px;
540 padding:12px 9px 7px 24px;
534 }
541 }
535
542
536 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
543 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
537 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
544 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
538 width:167px;
545 width:167px;
539 margin:0;
546 margin:0;
540 padding:12px 9px 7px 24px;
547 padding:12px 9px 7px 24px;
541 }
548 }
542
549
543 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
550 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
544 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
551 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
545 width:167px;
552 width:167px;
546 margin:0;
553 margin:0;
547 padding:12px 9px 7px 24px;
554 padding:12px 9px 7px 24px;
548 }
555 }
549
556
550 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
557 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
551 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
558 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
552 width:167px;
559 width:167px;
553 margin:0;
560 margin:0;
554 padding:12px 9px 7px 24px;
561 padding:12px 9px 7px 24px;
555 }
562 }
556
563
557 #content #left {
564 #content #left {
558 left:0;
565 left:0;
559 width:280px;
566 width:280px;
560 position:absolute;
567 position:absolute;
561 }
568 }
562
569
563 #content #right {
570 #content #right {
564 margin:0 60px 10px 290px;
571 margin:0 60px 10px 290px;
565 }
572 }
566
573
567 #content div.box {
574 #content div.box {
568 clear:both;
575 clear:both;
569 overflow:hidden;
576 overflow:hidden;
570 background:#fff;
577 background:#fff;
571 margin:0 0 10px;
578 margin:0 0 10px;
572 padding:0 0 10px;
579 padding:0 0 10px;
573 }
580 }
574
581
575 #content div.box-left {
582 #content div.box-left {
576 width:49%;
583 width:49%;
577 clear:none;
584 clear:none;
578 float:left;
585 float:left;
579 margin:0 0 10px;
586 margin:0 0 10px;
580 }
587 }
581
588
582 #content div.box-right {
589 #content div.box-right {
583 width:49%;
590 width:49%;
584 clear:none;
591 clear:none;
585 float:right;
592 float:right;
586 margin:0 0 10px;
593 margin:0 0 10px;
587 }
594 }
588
595
589 #content div.box div.title {
596 #content div.box div.title {
590 clear:both;
597 clear:both;
591 overflow:hidden;
598 overflow:hidden;
592 background:#369 url("../images/header_inner.png") repeat-x;
599 background:#369 url("../images/header_inner.png") repeat-x;
593 margin:0 0 20px;
600 margin:0 0 20px;
594 padding:0;
601 padding:0;
595 }
602 }
596
603
597 #content div.box div.title h5 {
604 #content div.box div.title h5 {
598 float:left;
605 float:left;
599 border:none;
606 border:none;
600 color:#fff;
607 color:#fff;
601 text-transform:uppercase;
608 text-transform:uppercase;
602 margin:0;
609 margin:0;
603 padding:11px 0 11px 10px;
610 padding:11px 0 11px 10px;
604 }
611 }
605
612
606 #content div.box div.title ul.links li {
613 #content div.box div.title ul.links li {
607 list-style:none;
614 list-style:none;
608 float:left;
615 float:left;
609 margin:0;
616 margin:0;
610 padding:0;
617 padding:0;
611 }
618 }
612
619
613 #content div.box div.title ul.links li a {
620 #content div.box div.title ul.links li a {
614 border-left: 1px solid #316293;
621 border-left: 1px solid #316293;
615 color: #FFFFFF;
622 color: #FFFFFF;
616 display: block;
623 display: block;
617 float: left;
624 float: left;
618 font-size: 13px;
625 font-size: 13px;
619 font-weight: 700;
626 font-weight: 700;
620 height: 1%;
627 height: 1%;
621 margin: 0;
628 margin: 0;
622 padding: 11px 22px 12px;
629 padding: 11px 22px 12px;
623 text-decoration: none;
630 text-decoration: none;
624 }
631 }
625
632
626 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
633 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
627 clear:both;
634 clear:both;
628 overflow:hidden;
635 overflow:hidden;
629 border-bottom:1px solid #DDD;
636 border-bottom:1px solid #DDD;
630 margin:10px 20px;
637 margin:10px 20px;
631 padding:0 0 15px;
638 padding:0 0 15px;
632 }
639 }
633
640
634 #content div.box p {
641 #content div.box p {
635 color:#5f5f5f;
642 color:#5f5f5f;
636 font-size:12px;
643 font-size:12px;
637 line-height:150%;
644 line-height:150%;
638 margin:0 24px 10px;
645 margin:0 24px 10px;
639 padding:0;
646 padding:0;
640 }
647 }
641
648
642 #content div.box blockquote {
649 #content div.box blockquote {
643 border-left:4px solid #DDD;
650 border-left:4px solid #DDD;
644 color:#5f5f5f;
651 color:#5f5f5f;
645 font-size:11px;
652 font-size:11px;
646 line-height:150%;
653 line-height:150%;
647 margin:0 34px;
654 margin:0 34px;
648 padding:0 0 0 14px;
655 padding:0 0 0 14px;
649 }
656 }
650
657
651 #content div.box blockquote p {
658 #content div.box blockquote p {
652 margin:10px 0;
659 margin:10px 0;
653 padding:0;
660 padding:0;
654 }
661 }
655
662
656 #content div.box dl {
663 #content div.box dl {
657 margin:10px 24px;
664 margin:10px 24px;
658 }
665 }
659
666
660 #content div.box dt {
667 #content div.box dt {
661 font-size:12px;
668 font-size:12px;
662 margin:0;
669 margin:0;
663 }
670 }
664
671
665 #content div.box dd {
672 #content div.box dd {
666 font-size:12px;
673 font-size:12px;
667 margin:0;
674 margin:0;
668 padding:8px 0 8px 15px;
675 padding:8px 0 8px 15px;
669 }
676 }
670
677
671 #content div.box li {
678 #content div.box li {
672 font-size:12px;
679 font-size:12px;
673 padding:4px 0;
680 padding:4px 0;
674 }
681 }
675
682
676 #content div.box ul.disc,#content div.box ul.circle {
683 #content div.box ul.disc,#content div.box ul.circle {
677 margin:10px 24px 10px 38px;
684 margin:10px 24px 10px 38px;
678 }
685 }
679
686
680 #content div.box ul.square {
687 #content div.box ul.square {
681 margin:10px 24px 10px 40px;
688 margin:10px 24px 10px 40px;
682 }
689 }
683
690
684 #content div.box img.left {
691 #content div.box img.left {
685 border:none;
692 border:none;
686 float:left;
693 float:left;
687 margin:10px 10px 10px 0;
694 margin:10px 10px 10px 0;
688 }
695 }
689
696
690 #content div.box img.right {
697 #content div.box img.right {
691 border:none;
698 border:none;
692 float:right;
699 float:right;
693 margin:10px 0 10px 10px;
700 margin:10px 0 10px 10px;
694 }
701 }
695
702
696 #content div.box div.messages {
703 #content div.box div.messages {
697 clear:both;
704 clear:both;
698 overflow:hidden;
705 overflow:hidden;
699 margin:0 20px;
706 margin:0 20px;
700 padding:0;
707 padding:0;
701 }
708 }
702
709
703 #content div.box div.message {
710 #content div.box div.message {
704 clear:both;
711 clear:both;
705 overflow:hidden;
712 overflow:hidden;
706 margin:0;
713 margin:0;
707 padding:10px 0;
714 padding:10px 0;
708 }
715 }
709
716
710 #content div.box div.message a {
717 #content div.box div.message a {
711 font-weight:400 !important;
718 font-weight:400 !important;
712 }
719 }
713
720
714 #content div.box div.message div.image {
721 #content div.box div.message div.image {
715 float:left;
722 float:left;
716 margin:9px 0 0 5px;
723 margin:9px 0 0 5px;
717 padding:6px;
724 padding:6px;
718 }
725 }
719
726
720 #content div.box div.message div.image img {
727 #content div.box div.message div.image img {
721 vertical-align:middle;
728 vertical-align:middle;
722 margin:0;
729 margin:0;
723 }
730 }
724
731
725 #content div.box div.message div.text {
732 #content div.box div.message div.text {
726 float:left;
733 float:left;
727 margin:0;
734 margin:0;
728 padding:9px 6px;
735 padding:9px 6px;
729 }
736 }
730
737
731 #content div.box div.message div.dismiss a {
738 #content div.box div.message div.dismiss a {
732 height:16px;
739 height:16px;
733 width:16px;
740 width:16px;
734 display:block;
741 display:block;
735 background:url("../images/icons/cross.png") no-repeat;
742 background:url("../images/icons/cross.png") no-repeat;
736 margin:15px 14px 0 0;
743 margin:15px 14px 0 0;
737 padding:0;
744 padding:0;
738 }
745 }
739
746
740 #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 {
747 #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 {
741 border:none;
748 border:none;
742 margin:0;
749 margin:0;
743 padding:0;
750 padding:0;
744 }
751 }
745
752
746 #content div.box div.message div.text span {
753 #content div.box div.message div.text span {
747 height:1%;
754 height:1%;
748 display:block;
755 display:block;
749 margin:0;
756 margin:0;
750 padding:5px 0 0;
757 padding:5px 0 0;
751 }
758 }
752
759
753 #content div.box div.message-error {
760 #content div.box div.message-error {
754 height:1%;
761 height:1%;
755 clear:both;
762 clear:both;
756 overflow:hidden;
763 overflow:hidden;
757 background:#FBE3E4;
764 background:#FBE3E4;
758 border:1px solid #FBC2C4;
765 border:1px solid #FBC2C4;
759 color:#860006;
766 color:#860006;
760 }
767 }
761
768
762 #content div.box div.message-error h6 {
769 #content div.box div.message-error h6 {
763 color:#860006;
770 color:#860006;
764 }
771 }
765
772
766 #content div.box div.message-warning {
773 #content div.box div.message-warning {
767 height:1%;
774 height:1%;
768 clear:both;
775 clear:both;
769 overflow:hidden;
776 overflow:hidden;
770 background:#FFF6BF;
777 background:#FFF6BF;
771 border:1px solid #FFD324;
778 border:1px solid #FFD324;
772 color:#5f5200;
779 color:#5f5200;
773 }
780 }
774
781
775 #content div.box div.message-warning h6 {
782 #content div.box div.message-warning h6 {
776 color:#5f5200;
783 color:#5f5200;
777 }
784 }
778
785
779 #content div.box div.message-notice {
786 #content div.box div.message-notice {
780 height:1%;
787 height:1%;
781 clear:both;
788 clear:both;
782 overflow:hidden;
789 overflow:hidden;
783 background:#8FBDE0;
790 background:#8FBDE0;
784 border:1px solid #6BACDE;
791 border:1px solid #6BACDE;
785 color:#003863;
792 color:#003863;
786 }
793 }
787
794
788 #content div.box div.message-notice h6 {
795 #content div.box div.message-notice h6 {
789 color:#003863;
796 color:#003863;
790 }
797 }
791
798
792 #content div.box div.message-success {
799 #content div.box div.message-success {
793 height:1%;
800 height:1%;
794 clear:both;
801 clear:both;
795 overflow:hidden;
802 overflow:hidden;
796 background:#E6EFC2;
803 background:#E6EFC2;
797 border:1px solid #C6D880;
804 border:1px solid #C6D880;
798 color:#4e6100;
805 color:#4e6100;
799 }
806 }
800
807
801 #content div.box div.message-success h6 {
808 #content div.box div.message-success h6 {
802 color:#4e6100;
809 color:#4e6100;
803 }
810 }
804
811
805 #content div.box div.form div.fields div.field {
812 #content div.box div.form div.fields div.field {
806 height:1%;
813 height:1%;
807 border-bottom:1px solid #DDD;
814 border-bottom:1px solid #DDD;
808 clear:both;
815 clear:both;
809 margin:0;
816 margin:0;
810 padding:10px 0;
817 padding:10px 0;
811 }
818 }
812
819
813 #content div.box div.form div.fields div.field-first {
820 #content div.box div.form div.fields div.field-first {
814 padding:0 0 10px;
821 padding:0 0 10px;
815 }
822 }
816
823
817 #content div.box div.form div.fields div.field-noborder {
824 #content div.box div.form div.fields div.field-noborder {
818 border-bottom:0 !important;
825 border-bottom:0 !important;
819 }
826 }
820
827
821 #content div.box div.form div.fields div.field span.error-message {
828 #content div.box div.form div.fields div.field span.error-message {
822 height:1%;
829 height:1%;
823 display:inline-block;
830 display:inline-block;
824 color:red;
831 color:red;
825 margin:8px 0 0 4px;
832 margin:8px 0 0 4px;
826 padding:0;
833 padding:0;
827 }
834 }
828
835
829 #content div.box div.form div.fields div.field span.success {
836 #content div.box div.form div.fields div.field span.success {
830 height:1%;
837 height:1%;
831 display:block;
838 display:block;
832 color:#316309;
839 color:#316309;
833 margin:8px 0 0;
840 margin:8px 0 0;
834 padding:0;
841 padding:0;
835 }
842 }
836
843
837 #content div.box div.form div.fields div.field div.label {
844 #content div.box div.form div.fields div.field div.label {
838 left:70px;
845 left:70px;
839 width:auto;
846 width:auto;
840 position:absolute;
847 position:absolute;
841 margin:0;
848 margin:0;
842 padding:8px 0 0 5px;
849 padding:8px 0 0 5px;
843 }
850 }
844
851
845 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
852 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
846 clear:both;
853 clear:both;
847 overflow:hidden;
854 overflow:hidden;
848 left:0;
855 left:0;
849 width:auto;
856 width:auto;
850 position:relative;
857 position:relative;
851 margin:0;
858 margin:0;
852 padding:0 0 8px;
859 padding:0 0 8px;
853 }
860 }
854
861
855 #content div.box div.form div.fields div.field div.label-select {
862 #content div.box div.form div.fields div.field div.label-select {
856 padding:5px 0 0 5px;
863 padding:5px 0 0 5px;
857 }
864 }
858
865
859 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
866 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
860 padding:0 0 8px;
867 padding:0 0 8px;
861 }
868 }
862
869
863 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
870 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
864 padding:0 0 8px !important;
871 padding:0 0 8px !important;
865 }
872 }
866
873
867 #content div.box div.form div.fields div.field div.label label, div.label label{
874 #content div.box div.form div.fields div.field div.label label, div.label label{
868 color:#393939;
875 color:#393939;
869 font-weight:700;
876 font-weight:700;
870 }
877 }
871
878
872 #content div.box div.form div.fields div.field div.input {
879 #content div.box div.form div.fields div.field div.input {
873 margin:0 0 0 200px;
880 margin:0 0 0 200px;
874 }
881 }
875 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
882 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
876 margin:0 0 0 0px;
883 margin:0 0 0 0px;
877 }
884 }
878
885
879 #content div.box div.form div.fields div.field div.input input {
886 #content div.box div.form div.fields div.field div.input input {
880 background:#FFF;
887 background:#FFF;
881 border-top:1px solid #b3b3b3;
888 border-top:1px solid #b3b3b3;
882 border-left:1px solid #b3b3b3;
889 border-left:1px solid #b3b3b3;
883 border-right:1px solid #eaeaea;
890 border-right:1px solid #eaeaea;
884 border-bottom:1px solid #eaeaea;
891 border-bottom:1px solid #eaeaea;
885 color:#000;
892 color:#000;
886 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
893 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
887 font-size:11px;
894 font-size:11px;
888 margin:0;
895 margin:0;
889 padding:7px 7px 6px;
896 padding:7px 7px 6px;
890 }
897 }
891
898
892
899
893
900
894 #content div.box div.form div.fields div.field div.input input.small {
901 #content div.box div.form div.fields div.field div.input input.small {
895 width:30%;
902 width:30%;
896 }
903 }
897
904
898 #content div.box div.form div.fields div.field div.input input.medium {
905 #content div.box div.form div.fields div.field div.input input.medium {
899 width:55%;
906 width:55%;
900 }
907 }
901
908
902 #content div.box div.form div.fields div.field div.input input.large {
909 #content div.box div.form div.fields div.field div.input input.large {
903 width:85%;
910 width:85%;
904 }
911 }
905
912
906 #content div.box div.form div.fields div.field div.input input.date {
913 #content div.box div.form div.fields div.field div.input input.date {
907 width:177px;
914 width:177px;
908 }
915 }
909
916
910 #content div.box div.form div.fields div.field div.input input.button {
917 #content div.box div.form div.fields div.field div.input input.button {
911 background:#D4D0C8;
918 background:#D4D0C8;
912 border-top:1px solid #FFF;
919 border-top:1px solid #FFF;
913 border-left:1px solid #FFF;
920 border-left:1px solid #FFF;
914 border-right:1px solid #404040;
921 border-right:1px solid #404040;
915 border-bottom:1px solid #404040;
922 border-bottom:1px solid #404040;
916 color:#000;
923 color:#000;
917 margin:0;
924 margin:0;
918 padding:4px 8px;
925 padding:4px 8px;
919 }
926 }
920
927
921 #content div.box div.form div.fields div.field div.textarea {
928 #content div.box div.form div.fields div.field div.textarea {
922 border-top:1px solid #b3b3b3;
929 border-top:1px solid #b3b3b3;
923 border-left:1px solid #b3b3b3;
930 border-left:1px solid #b3b3b3;
924 border-right:1px solid #eaeaea;
931 border-right:1px solid #eaeaea;
925 border-bottom:1px solid #eaeaea;
932 border-bottom:1px solid #eaeaea;
926 margin:0 0 0 200px;
933 margin:0 0 0 200px;
927 padding:10px;
934 padding:10px;
928 }
935 }
929
936
930 #content div.box div.form div.fields div.field div.textarea-editor {
937 #content div.box div.form div.fields div.field div.textarea-editor {
931 border:1px solid #ddd;
938 border:1px solid #ddd;
932 padding:0;
939 padding:0;
933 }
940 }
934
941
935 #content div.box div.form div.fields div.field div.textarea textarea {
942 #content div.box div.form div.fields div.field div.textarea textarea {
936 width:100%;
943 width:100%;
937 height:220px;
944 height:220px;
938 overflow:hidden;
945 overflow:hidden;
939 background:#FFF;
946 background:#FFF;
940 color:#000;
947 color:#000;
941 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
948 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
942 font-size:11px;
949 font-size:11px;
943 outline:none;
950 outline:none;
944 border-width:0;
951 border-width:0;
945 margin:0;
952 margin:0;
946 padding:0;
953 padding:0;
947 }
954 }
948
955
949 #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 {
956 #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 {
950 width:100%;
957 width:100%;
951 height:100px;
958 height:100px;
952 }
959 }
953
960
954 #content div.box div.form div.fields div.field div.textarea table {
961 #content div.box div.form div.fields div.field div.textarea table {
955 width:100%;
962 width:100%;
956 border:none;
963 border:none;
957 margin:0;
964 margin:0;
958 padding:0;
965 padding:0;
959 }
966 }
960
967
961 #content div.box div.form div.fields div.field div.textarea table td {
968 #content div.box div.form div.fields div.field div.textarea table td {
962 background:#DDD;
969 background:#DDD;
963 border:none;
970 border:none;
964 padding:0;
971 padding:0;
965 }
972 }
966
973
967 #content div.box div.form div.fields div.field div.textarea table td table {
974 #content div.box div.form div.fields div.field div.textarea table td table {
968 width:auto;
975 width:auto;
969 border:none;
976 border:none;
970 margin:0;
977 margin:0;
971 padding:0;
978 padding:0;
972 }
979 }
973
980
974 #content div.box div.form div.fields div.field div.textarea table td table td {
981 #content div.box div.form div.fields div.field div.textarea table td table td {
975 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
982 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
976 font-size:11px;
983 font-size:11px;
977 padding:5px 5px 5px 0;
984 padding:5px 5px 5px 0;
978 }
985 }
979
986
980 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
987 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
981 background:#f6f6f6;
988 background:#f6f6f6;
982 border-color:#666;
989 border-color:#666;
983 }
990 }
984
991
985 div.form div.fields div.field div.button {
992 div.form div.fields div.field div.button {
986 margin:0;
993 margin:0;
987 padding:0 0 0 8px;
994 padding:0 0 0 8px;
988 }
995 }
989
996
990 div.form div.fields div.field div.highlight .ui-button {
997 div.form div.fields div.field div.highlight .ui-button {
991 background:#4e85bb url("../images/button_highlight.png") repeat-x;
998 background:#4e85bb url("../images/button_highlight.png") repeat-x;
992 border-top:1px solid #5c91a4;
999 border-top:1px solid #5c91a4;
993 border-left:1px solid #2a6f89;
1000 border-left:1px solid #2a6f89;
994 border-right:1px solid #2b7089;
1001 border-right:1px solid #2b7089;
995 border-bottom:1px solid #1a6480;
1002 border-bottom:1px solid #1a6480;
996 color:#FFF;
1003 color:#FFF;
997 margin:0;
1004 margin:0;
998 padding:6px 12px;
1005 padding:6px 12px;
999 }
1006 }
1000
1007
1001 div.form div.fields div.field div.highlight .ui-state-hover {
1008 div.form div.fields div.field div.highlight .ui-state-hover {
1002 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1009 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1003 border-top:1px solid #78acbf;
1010 border-top:1px solid #78acbf;
1004 border-left:1px solid #34819e;
1011 border-left:1px solid #34819e;
1005 border-right:1px solid #35829f;
1012 border-right:1px solid #35829f;
1006 border-bottom:1px solid #257897;
1013 border-bottom:1px solid #257897;
1007 color:#FFF;
1014 color:#FFF;
1008 margin:0;
1015 margin:0;
1009 padding:6px 12px;
1016 padding:6px 12px;
1010 }
1017 }
1011
1018
1012 #content div.box div.form div.fields div.buttons div.highlight input.ui-button {
1019 #content div.box div.form div.fields div.buttons div.highlight input.ui-button {
1013 background:#4e85bb url("../images/button_highlight.png") repeat-x;
1020 background:#4e85bb url("../images/button_highlight.png") repeat-x;
1014 border-top:1px solid #5c91a4;
1021 border-top:1px solid #5c91a4;
1015 border-left:1px solid #2a6f89;
1022 border-left:1px solid #2a6f89;
1016 border-right:1px solid #2b7089;
1023 border-right:1px solid #2b7089;
1017 border-bottom:1px solid #1a6480;
1024 border-bottom:1px solid #1a6480;
1018 color:#fff;
1025 color:#fff;
1019 margin:0;
1026 margin:0;
1020 padding:6px 12px;
1027 padding:6px 12px;
1021 }
1028 }
1022
1029
1023 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
1030 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
1024 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1031 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1025 border-top:1px solid #78acbf;
1032 border-top:1px solid #78acbf;
1026 border-left:1px solid #34819e;
1033 border-left:1px solid #34819e;
1027 border-right:1px solid #35829f;
1034 border-right:1px solid #35829f;
1028 border-bottom:1px solid #257897;
1035 border-bottom:1px solid #257897;
1029 color:#fff;
1036 color:#fff;
1030 margin:0;
1037 margin:0;
1031 padding:6px 12px;
1038 padding:6px 12px;
1032 }
1039 }
1033
1040
1034 #content div.box table {
1041 #content div.box table {
1035 width:100%;
1042 width:100%;
1036 border-collapse:collapse;
1043 border-collapse:collapse;
1037 margin:0;
1044 margin:0;
1038 padding:0;
1045 padding:0;
1039 }
1046 }
1040
1047
1041 #content div.box table th {
1048 #content div.box table th {
1042 background:#eee;
1049 background:#eee;
1043 border-bottom:1px solid #ddd;
1050 border-bottom:1px solid #ddd;
1044 padding:5px 0px 5px 5px;
1051 padding:5px 0px 5px 5px;
1045 }
1052 }
1046
1053
1047 #content div.box table th.left {
1054 #content div.box table th.left {
1048 text-align:left;
1055 text-align:left;
1049 }
1056 }
1050
1057
1051 #content div.box table th.right {
1058 #content div.box table th.right {
1052 text-align:right;
1059 text-align:right;
1053 }
1060 }
1054
1061
1055 #content div.box table th.center {
1062 #content div.box table th.center {
1056 text-align:center;
1063 text-align:center;
1057 }
1064 }
1058
1065
1059 #content div.box table th.selected {
1066 #content div.box table th.selected {
1060 vertical-align:middle;
1067 vertical-align:middle;
1061 padding:0;
1068 padding:0;
1062 }
1069 }
1063
1070
1064 #content div.box table td {
1071 #content div.box table td {
1065 background:#fff;
1072 background:#fff;
1066 border-bottom:1px solid #cdcdcd;
1073 border-bottom:1px solid #cdcdcd;
1067 vertical-align:middle;
1074 vertical-align:middle;
1068 padding:5px;
1075 padding:5px;
1069 }
1076 }
1070
1077
1071 #content div.box table tr.selected td {
1078 #content div.box table tr.selected td {
1072 background:#FFC;
1079 background:#FFC;
1073 }
1080 }
1074
1081
1075 #content div.box table td.selected {
1082 #content div.box table td.selected {
1076 width:3%;
1083 width:3%;
1077 text-align:center;
1084 text-align:center;
1078 vertical-align:middle;
1085 vertical-align:middle;
1079 padding:0;
1086 padding:0;
1080 }
1087 }
1081
1088
1082 #content div.box table td.action {
1089 #content div.box table td.action {
1083 width:45%;
1090 width:45%;
1084 text-align:left;
1091 text-align:left;
1085 }
1092 }
1086
1093
1087 #content div.box table td.date {
1094 #content div.box table td.date {
1088 width:33%;
1095 width:33%;
1089 text-align:center;
1096 text-align:center;
1090 }
1097 }
1091
1098
1092 #content div.box div.action {
1099 #content div.box div.action {
1093 float:right;
1100 float:right;
1094 background:#FFF;
1101 background:#FFF;
1095 text-align:right;
1102 text-align:right;
1096 margin:10px 0 0;
1103 margin:10px 0 0;
1097 padding:0;
1104 padding:0;
1098 }
1105 }
1099
1106
1100 #content div.box div.action select {
1107 #content div.box div.action select {
1101 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1108 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1102 font-size:11px;
1109 font-size:11px;
1103 margin:0;
1110 margin:0;
1104 }
1111 }
1105
1112
1106 #content div.box div.action .ui-selectmenu {
1113 #content div.box div.action .ui-selectmenu {
1107 margin:0;
1114 margin:0;
1108 padding:0;
1115 padding:0;
1109 }
1116 }
1110
1117
1111 #content div.box div.pagination {
1118 #content div.box div.pagination {
1112 height:1%;
1119 height:1%;
1113 clear:both;
1120 clear:both;
1114 overflow:hidden;
1121 overflow:hidden;
1115 margin:10px 0 0;
1122 margin:10px 0 0;
1116 padding:0;
1123 padding:0;
1117 }
1124 }
1118
1125
1119 #content div.box div.pagination ul.pager {
1126 #content div.box div.pagination ul.pager {
1120 float:right;
1127 float:right;
1121 text-align:right;
1128 text-align:right;
1122 margin:0;
1129 margin:0;
1123 padding:0;
1130 padding:0;
1124 }
1131 }
1125
1132
1126 #content div.box div.pagination ul.pager li {
1133 #content div.box div.pagination ul.pager li {
1127 height:1%;
1134 height:1%;
1128 float:left;
1135 float:left;
1129 list-style:none;
1136 list-style:none;
1130 background:#ebebeb url("../images/pager.png") repeat-x;
1137 background:#ebebeb url("../images/pager.png") repeat-x;
1131 border-top:1px solid #dedede;
1138 border-top:1px solid #dedede;
1132 border-left:1px solid #cfcfcf;
1139 border-left:1px solid #cfcfcf;
1133 border-right:1px solid #c4c4c4;
1140 border-right:1px solid #c4c4c4;
1134 border-bottom:1px solid #c4c4c4;
1141 border-bottom:1px solid #c4c4c4;
1135 color:#4A4A4A;
1142 color:#4A4A4A;
1136 font-weight:700;
1143 font-weight:700;
1137 margin:0 0 0 4px;
1144 margin:0 0 0 4px;
1138 padding:0;
1145 padding:0;
1139 }
1146 }
1140
1147
1141 #content div.box div.pagination ul.pager li.separator {
1148 #content div.box div.pagination ul.pager li.separator {
1142 padding:6px;
1149 padding:6px;
1143 }
1150 }
1144
1151
1145 #content div.box div.pagination ul.pager li.current {
1152 #content div.box div.pagination ul.pager li.current {
1146 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1153 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1147 border-top:1px solid #ccc;
1154 border-top:1px solid #ccc;
1148 border-left:1px solid #bebebe;
1155 border-left:1px solid #bebebe;
1149 border-right:1px solid #b1b1b1;
1156 border-right:1px solid #b1b1b1;
1150 border-bottom:1px solid #afafaf;
1157 border-bottom:1px solid #afafaf;
1151 color:#515151;
1158 color:#515151;
1152 padding:6px;
1159 padding:6px;
1153 }
1160 }
1154
1161
1155 #content div.box div.pagination ul.pager li a {
1162 #content div.box div.pagination ul.pager li a {
1156 height:1%;
1163 height:1%;
1157 display:block;
1164 display:block;
1158 float:left;
1165 float:left;
1159 color:#515151;
1166 color:#515151;
1160 text-decoration:none;
1167 text-decoration:none;
1161 margin:0;
1168 margin:0;
1162 padding:6px;
1169 padding:6px;
1163 }
1170 }
1164
1171
1165 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1172 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1166 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1173 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1167 border-top:1px solid #ccc;
1174 border-top:1px solid #ccc;
1168 border-left:1px solid #bebebe;
1175 border-left:1px solid #bebebe;
1169 border-right:1px solid #b1b1b1;
1176 border-right:1px solid #b1b1b1;
1170 border-bottom:1px solid #afafaf;
1177 border-bottom:1px solid #afafaf;
1171 margin:-1px;
1178 margin:-1px;
1172 }
1179 }
1173
1180
1174 #content div.box div.pagination-wh {
1181 #content div.box div.pagination-wh {
1175 height:1%;
1182 height:1%;
1176 clear:both;
1183 clear:both;
1177 overflow:hidden;
1184 overflow:hidden;
1178 text-align:right;
1185 text-align:right;
1179 margin:10px 0 0;
1186 margin:10px 0 0;
1180 padding:0;
1187 padding:0;
1181 }
1188 }
1182
1189
1183 #content div.box div.pagination-right {
1190 #content div.box div.pagination-right {
1184 float:right;
1191 float:right;
1185 }
1192 }
1186
1193
1187 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1194 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1188 height:1%;
1195 height:1%;
1189 float:left;
1196 float:left;
1190 background:#ebebeb url("../images/pager.png") repeat-x;
1197 background:#ebebeb url("../images/pager.png") repeat-x;
1191 border-top:1px solid #dedede;
1198 border-top:1px solid #dedede;
1192 border-left:1px solid #cfcfcf;
1199 border-left:1px solid #cfcfcf;
1193 border-right:1px solid #c4c4c4;
1200 border-right:1px solid #c4c4c4;
1194 border-bottom:1px solid #c4c4c4;
1201 border-bottom:1px solid #c4c4c4;
1195 color:#4A4A4A;
1202 color:#4A4A4A;
1196 font-weight:700;
1203 font-weight:700;
1197 margin:0 0 0 4px;
1204 margin:0 0 0 4px;
1198 padding:6px;
1205 padding:6px;
1199 }
1206 }
1200
1207
1201 #content div.box div.pagination-wh span.pager_curpage {
1208 #content div.box div.pagination-wh span.pager_curpage {
1202 height:1%;
1209 height:1%;
1203 float:left;
1210 float:left;
1204 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1211 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1205 border-top:1px solid #ccc;
1212 border-top:1px solid #ccc;
1206 border-left:1px solid #bebebe;
1213 border-left:1px solid #bebebe;
1207 border-right:1px solid #b1b1b1;
1214 border-right:1px solid #b1b1b1;
1208 border-bottom:1px solid #afafaf;
1215 border-bottom:1px solid #afafaf;
1209 color:#515151;
1216 color:#515151;
1210 font-weight:700;
1217 font-weight:700;
1211 margin:0 0 0 4px;
1218 margin:0 0 0 4px;
1212 padding:6px;
1219 padding:6px;
1213 }
1220 }
1214
1221
1215 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1222 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1216 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1223 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1217 border-top:1px solid #ccc;
1224 border-top:1px solid #ccc;
1218 border-left:1px solid #bebebe;
1225 border-left:1px solid #bebebe;
1219 border-right:1px solid #b1b1b1;
1226 border-right:1px solid #b1b1b1;
1220 border-bottom:1px solid #afafaf;
1227 border-bottom:1px solid #afafaf;
1221 text-decoration:none;
1228 text-decoration:none;
1222 }
1229 }
1223
1230
1224 #content div.box div.traffic div.legend {
1231 #content div.box div.traffic div.legend {
1225 clear:both;
1232 clear:both;
1226 overflow:hidden;
1233 overflow:hidden;
1227 border-bottom:1px solid #ddd;
1234 border-bottom:1px solid #ddd;
1228 margin:0 0 10px;
1235 margin:0 0 10px;
1229 padding:0 0 10px;
1236 padding:0 0 10px;
1230 }
1237 }
1231
1238
1232 #content div.box div.traffic div.legend h6 {
1239 #content div.box div.traffic div.legend h6 {
1233 float:left;
1240 float:left;
1234 border:none;
1241 border:none;
1235 margin:0;
1242 margin:0;
1236 padding:0;
1243 padding:0;
1237 }
1244 }
1238
1245
1239 #content div.box div.traffic div.legend li {
1246 #content div.box div.traffic div.legend li {
1240 list-style:none;
1247 list-style:none;
1241 float:left;
1248 float:left;
1242 font-size:11px;
1249 font-size:11px;
1243 margin:0;
1250 margin:0;
1244 padding:0 8px 0 4px;
1251 padding:0 8px 0 4px;
1245 }
1252 }
1246
1253
1247 #content div.box div.traffic div.legend li.visits {
1254 #content div.box div.traffic div.legend li.visits {
1248 border-left:12px solid #edc240;
1255 border-left:12px solid #edc240;
1249 }
1256 }
1250
1257
1251 #content div.box div.traffic div.legend li.pageviews {
1258 #content div.box div.traffic div.legend li.pageviews {
1252 border-left:12px solid #afd8f8;
1259 border-left:12px solid #afd8f8;
1253 }
1260 }
1254
1261
1255 #content div.box div.traffic table {
1262 #content div.box div.traffic table {
1256 width:auto;
1263 width:auto;
1257 }
1264 }
1258
1265
1259 #content div.box div.traffic table td {
1266 #content div.box div.traffic table td {
1260 background:transparent;
1267 background:transparent;
1261 border:none;
1268 border:none;
1262 padding:2px 3px 3px;
1269 padding:2px 3px 3px;
1263 }
1270 }
1264
1271
1265 #content div.box div.traffic table td.legendLabel {
1272 #content div.box div.traffic table td.legendLabel {
1266 padding:0 3px 2px;
1273 padding:0 3px 2px;
1267 }
1274 }
1268
1275
1269 #summary{
1276 #summary{
1270
1277
1271 }
1278 }
1272
1279
1273 #summary .desc{
1280 #summary .desc{
1274 white-space: pre;
1281 white-space: pre;
1275 width: 100%;
1282 width: 100%;
1276 }
1283 }
1277
1284
1278 #summary .repo_name{
1285 #summary .repo_name{
1279 font-size: 1.6em;
1286 font-size: 1.6em;
1280 font-weight: bold;
1287 font-weight: bold;
1281 vertical-align: baseline;
1288 vertical-align: baseline;
1282 clear:right
1289 clear:right
1283 }
1290 }
1284
1291
1285
1292
1286 #footer {
1293 #footer {
1287 clear:both;
1294 clear:both;
1288 overflow:hidden;
1295 overflow:hidden;
1289 text-align:right;
1296 text-align:right;
1290 margin:0;
1297 margin:0;
1291 padding:0 10px 4px;
1298 padding:0 10px 4px;
1292 margin:-10px 0 0;
1299 margin:-10px 0 0;
1293 }
1300 }
1294
1301
1295 #footer div#footer-inner {
1302 #footer div#footer-inner {
1296 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1303 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1297 border-top:2px solid #FFFFFF;
1304 border-top:2px solid #FFFFFF;
1298 }
1305 }
1299
1306
1300 #footer div#footer-inner p {
1307 #footer div#footer-inner p {
1301 padding:15px 25px 15px 0;
1308 padding:15px 25px 15px 0;
1302 color:#FFF;
1309 color:#FFF;
1303 font-weight:700;
1310 font-weight:700;
1304 }
1311 }
1305 #footer div#footer-inner .footer-link {
1312 #footer div#footer-inner .footer-link {
1306 float:left;
1313 float:left;
1307 padding-left:10px;
1314 padding-left:10px;
1308 }
1315 }
1309 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a {
1316 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a {
1310 color:#FFF;
1317 color:#FFF;
1311 }
1318 }
1312
1319
1313 #login div.title {
1320 #login div.title {
1314 width:420px;
1321 width:420px;
1315 clear:both;
1322 clear:both;
1316 overflow:hidden;
1323 overflow:hidden;
1317 position:relative;
1324 position:relative;
1318 background:#003367 url("../images/header_inner.png") repeat-x;
1325 background:#003367 url("../images/header_inner.png") repeat-x;
1319 margin:0 auto;
1326 margin:0 auto;
1320 padding:0;
1327 padding:0;
1321 }
1328 }
1322
1329
1323 #login div.inner {
1330 #login div.inner {
1324 width:380px;
1331 width:380px;
1325 background:#FFF url("../images/login.png") no-repeat top left;
1332 background:#FFF url("../images/login.png") no-repeat top left;
1326 border-top:none;
1333 border-top:none;
1327 border-bottom:none;
1334 border-bottom:none;
1328 margin:0 auto;
1335 margin:0 auto;
1329 padding:20px;
1336 padding:20px;
1330 }
1337 }
1331
1338
1332 #login div.form div.fields div.field div.label {
1339 #login div.form div.fields div.field div.label {
1333 width:173px;
1340 width:173px;
1334 float:left;
1341 float:left;
1335 text-align:right;
1342 text-align:right;
1336 margin:2px 10px 0 0;
1343 margin:2px 10px 0 0;
1337 padding:5px 0 0 5px;
1344 padding:5px 0 0 5px;
1338 }
1345 }
1339
1346
1340 #login div.form div.fields div.field div.input input {
1347 #login div.form div.fields div.field div.input input {
1341 width:176px;
1348 width:176px;
1342 background:#FFF;
1349 background:#FFF;
1343 border-top:1px solid #b3b3b3;
1350 border-top:1px solid #b3b3b3;
1344 border-left:1px solid #b3b3b3;
1351 border-left:1px solid #b3b3b3;
1345 border-right:1px solid #eaeaea;
1352 border-right:1px solid #eaeaea;
1346 border-bottom:1px solid #eaeaea;
1353 border-bottom:1px solid #eaeaea;
1347 color:#000;
1354 color:#000;
1348 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1355 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1349 font-size:11px;
1356 font-size:11px;
1350 margin:0;
1357 margin:0;
1351 padding:7px 7px 6px;
1358 padding:7px 7px 6px;
1352 }
1359 }
1353
1360
1354 #login div.form div.fields div.buttons {
1361 #login div.form div.fields div.buttons {
1355 clear:both;
1362 clear:both;
1356 overflow:hidden;
1363 overflow:hidden;
1357 border-top:1px solid #DDD;
1364 border-top:1px solid #DDD;
1358 text-align:right;
1365 text-align:right;
1359 margin:0;
1366 margin:0;
1360 padding:10px 0 0;
1367 padding:10px 0 0;
1361 }
1368 }
1362
1369
1363 #login div.form div.links {
1370 #login div.form div.links {
1364 clear:both;
1371 clear:both;
1365 overflow:hidden;
1372 overflow:hidden;
1366 margin:10px 0 0;
1373 margin:10px 0 0;
1367 padding:0 0 2px;
1374 padding:0 0 2px;
1368 }
1375 }
1369
1376
1370 #quick_login{
1377 #quick_login{
1371 top: 31px;
1378 top: 31px;
1372 background-color: rgb(0, 51, 103);
1379 background-color: rgb(0, 51, 103);
1373 z-index: 999;
1380 z-index: 999;
1374 height: 150px;
1381 height: 150px;
1375 position: absolute;
1382 position: absolute;
1376 margin-left: -16px;
1383 margin-left: -16px;
1377 width: 281px;
1384 width: 281px;
1378 border-radius: 0 0 8px 8px;
1385 border-radius: 0 0 8px 8px;
1379 }
1386 }
1380
1387
1381 #quick_login div.form div.fields{
1388 #quick_login div.form div.fields{
1382 padding-top: 2px;
1389 padding-top: 2px;
1383 padding-left:10px;
1390 padding-left:10px;
1384 }
1391 }
1385
1392
1386 #quick_login div.form div.fields div.field{
1393 #quick_login div.form div.fields div.field{
1387 padding: 5px;
1394 padding: 5px;
1388 }
1395 }
1389
1396
1390 #quick_login div.form div.fields div.field div.label label{
1397 #quick_login div.form div.fields div.field div.label label{
1391 color:#fff;
1398 color:#fff;
1392 padding-bottom: 3px;
1399 padding-bottom: 3px;
1393 }
1400 }
1394
1401
1395 #quick_login div.form div.fields div.field div.input input {
1402 #quick_login div.form div.fields div.field div.input input {
1396 width:236px;
1403 width:236px;
1397 background:#FFF;
1404 background:#FFF;
1398 border-top:1px solid #b3b3b3;
1405 border-top:1px solid #b3b3b3;
1399 border-left:1px solid #b3b3b3;
1406 border-left:1px solid #b3b3b3;
1400 border-right:1px solid #eaeaea;
1407 border-right:1px solid #eaeaea;
1401 border-bottom:1px solid #eaeaea;
1408 border-bottom:1px solid #eaeaea;
1402 color:#000;
1409 color:#000;
1403 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1410 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1404 font-size:11px;
1411 font-size:11px;
1405 margin:0;
1412 margin:0;
1406 padding:5px 7px 4px;
1413 padding:5px 7px 4px;
1407 }
1414 }
1408
1415
1409 #quick_login div.form div.fields div.buttons {
1416 #quick_login div.form div.fields div.buttons {
1410 clear:both;
1417 clear:both;
1411 overflow:hidden;
1418 overflow:hidden;
1412 text-align:right;
1419 text-align:right;
1413 margin:0;
1420 margin:0;
1414 padding:10px 14px 0;
1421 padding:10px 14px 0;
1415 }
1422 }
1416
1423
1417 #quick_login div.form div.fields div.buttons input.ui-button{
1424 #quick_login div.form div.fields div.buttons input.ui-button{
1418 background:#e5e3e3 url("../images/button.png") repeat-x;
1425 background:#e5e3e3 url("../images/button.png") repeat-x;
1419 border-top:1px solid #DDD;
1426 border-top:1px solid #DDD;
1420 border-left:1px solid #c6c6c6;
1427 border-left:1px solid #c6c6c6;
1421 border-right:1px solid #DDD;
1428 border-right:1px solid #DDD;
1422 border-bottom:1px solid #c6c6c6;
1429 border-bottom:1px solid #c6c6c6;
1423 color:#515151;
1430 color:#515151;
1424 margin:0;
1431 margin:0;
1425 padding:4px 10px;
1432 padding:4px 10px;
1426 }
1433 }
1427
1434
1428 #quick_login div.form div.links {
1435 #quick_login div.form div.links {
1429 clear:both;
1436 clear:both;
1430 overflow:hidden;
1437 overflow:hidden;
1431 margin:10px 0 0;
1438 margin:10px 0 0;
1432 padding:0 0 2px;
1439 padding:0 0 2px;
1433 }
1440 }
1434
1441
1435 #register div.title {
1442 #register div.title {
1436 clear:both;
1443 clear:both;
1437 overflow:hidden;
1444 overflow:hidden;
1438 position:relative;
1445 position:relative;
1439 background:#003367 url("../images/header_inner.png") repeat-x;
1446 background:#003367 url("../images/header_inner.png") repeat-x;
1440 margin:0 auto;
1447 margin:0 auto;
1441 padding:0;
1448 padding:0;
1442 }
1449 }
1443
1450
1444 #register div.inner {
1451 #register div.inner {
1445 background:#FFF;
1452 background:#FFF;
1446 border-top:none;
1453 border-top:none;
1447 border-bottom:none;
1454 border-bottom:none;
1448 margin:0 auto;
1455 margin:0 auto;
1449 padding:20px;
1456 padding:20px;
1450 }
1457 }
1451
1458
1452 #register div.form div.fields div.field div.label {
1459 #register div.form div.fields div.field div.label {
1453 width:135px;
1460 width:135px;
1454 float:left;
1461 float:left;
1455 text-align:right;
1462 text-align:right;
1456 margin:2px 10px 0 0;
1463 margin:2px 10px 0 0;
1457 padding:5px 0 0 5px;
1464 padding:5px 0 0 5px;
1458 }
1465 }
1459
1466
1460 #register div.form div.fields div.field div.input input {
1467 #register div.form div.fields div.field div.input input {
1461 width:300px;
1468 width:300px;
1462 background:#FFF;
1469 background:#FFF;
1463 border-top:1px solid #b3b3b3;
1470 border-top:1px solid #b3b3b3;
1464 border-left:1px solid #b3b3b3;
1471 border-left:1px solid #b3b3b3;
1465 border-right:1px solid #eaeaea;
1472 border-right:1px solid #eaeaea;
1466 border-bottom:1px solid #eaeaea;
1473 border-bottom:1px solid #eaeaea;
1467 color:#000;
1474 color:#000;
1468 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1475 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1469 font-size:11px;
1476 font-size:11px;
1470 margin:0;
1477 margin:0;
1471 padding:7px 7px 6px;
1478 padding:7px 7px 6px;
1472 }
1479 }
1473
1480
1474 #register div.form div.fields div.buttons {
1481 #register div.form div.fields div.buttons {
1475 clear:both;
1482 clear:both;
1476 overflow:hidden;
1483 overflow:hidden;
1477 border-top:1px solid #DDD;
1484 border-top:1px solid #DDD;
1478 text-align:left;
1485 text-align:left;
1479 margin:0;
1486 margin:0;
1480 padding:10px 0 0 150px;
1487 padding:10px 0 0 150px;
1481 }
1488 }
1482
1489
1483 #register div.form div.fields div.buttons div.highlight input.ui-button {
1490 #register div.form div.fields div.buttons div.highlight input.ui-button {
1484 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1491 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1485 color:#FFF;
1492 color:#FFF;
1486 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1493 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1487 border-style:solid;
1494 border-style:solid;
1488 border-width:1px;
1495 border-width:1px;
1489 }
1496 }
1490
1497
1491 #register div.form div.activation_msg {
1498 #register div.form div.activation_msg {
1492 padding-top:4px;
1499 padding-top:4px;
1493 padding-bottom:4px;
1500 padding-bottom:4px;
1494 }
1501 }
1495
1502
1496 #journal .journal_day{
1503 #journal .journal_day{
1497 font-size:20px;
1504 font-size:20px;
1498 padding:10px 0px;
1505 padding:10px 0px;
1499 border-bottom:2px solid #DDD;
1506 border-bottom:2px solid #DDD;
1500 margin-left:10px;
1507 margin-left:10px;
1501 margin-right:10px;
1508 margin-right:10px;
1502 }
1509 }
1503
1510
1504 #journal .journal_container{
1511 #journal .journal_container{
1505 padding:5px;
1512 padding:5px;
1506 clear:both;
1513 clear:both;
1507 margin:0px 5px 0px 10px;
1514 margin:0px 5px 0px 10px;
1508 }
1515 }
1509
1516
1510 #journal .journal_action_container{
1517 #journal .journal_action_container{
1511 padding-left:38px;
1518 padding-left:38px;
1512 }
1519 }
1513
1520
1514 #journal .journal_user{
1521 #journal .journal_user{
1515 color: #747474;
1522 color: #747474;
1516 font-size: 14px;
1523 font-size: 14px;
1517 font-weight: bold;
1524 font-weight: bold;
1518 height: 30px;
1525 height: 30px;
1519 }
1526 }
1520 #journal .journal_icon{
1527 #journal .journal_icon{
1521 clear: both;
1528 clear: both;
1522 float: left;
1529 float: left;
1523 padding-right: 4px;
1530 padding-right: 4px;
1524 padding-top: 3px;
1531 padding-top: 3px;
1525 }
1532 }
1526 #journal .journal_action{
1533 #journal .journal_action{
1527 padding-top:4px;
1534 padding-top:4px;
1528 min-height:2px;
1535 min-height:2px;
1529 float:left
1536 float:left
1530 }
1537 }
1531 #journal .journal_action_params{
1538 #journal .journal_action_params{
1532 clear: left;
1539 clear: left;
1533 padding-left: 22px;
1540 padding-left: 22px;
1534 }
1541 }
1535 #journal .journal_repo{
1542 #journal .journal_repo{
1536 float: left;
1543 float: left;
1537 margin-left: 6px;
1544 margin-left: 6px;
1538 padding-top: 3px;
1545 padding-top: 3px;
1539 }
1546 }
1540 #journal .date{
1547 #journal .date{
1541 clear: both;
1548 clear: both;
1542 color: #777777;
1549 color: #777777;
1543 font-size: 11px;
1550 font-size: 11px;
1544 padding-left: 22px;
1551 padding-left: 22px;
1545 }
1552 }
1546 #journal .journal_repo .journal_repo_name{
1553 #journal .journal_repo .journal_repo_name{
1547 font-weight: bold;
1554 font-weight: bold;
1548 font-size: 1.1em;
1555 font-size: 1.1em;
1549 }
1556 }
1550 #journal .compare_view{
1557 #journal .compare_view{
1551 padding: 5px 0px 5px 0px;
1558 padding: 5px 0px 5px 0px;
1552 width: 95px;
1559 width: 95px;
1553 }
1560 }
1554 .journal_highlight{
1561 .journal_highlight{
1555 font-weight: bold;
1562 font-weight: bold;
1556 padding: 0 2px;
1563 padding: 0 2px;
1557 vertical-align: bottom;
1564 vertical-align: bottom;
1558 }
1565 }
1559 .trending_language_tbl,.trending_language_tbl td {
1566 .trending_language_tbl,.trending_language_tbl td {
1560 border:0 !important;
1567 border:0 !important;
1561 margin:0 !important;
1568 margin:0 !important;
1562 padding:0 !important;
1569 padding:0 !important;
1563 }
1570 }
1564
1571
1565 .trending_language {
1572 .trending_language {
1566 background-color:#003367;
1573 background-color:#003367;
1567 color:#FFF;
1574 color:#FFF;
1568 display:block;
1575 display:block;
1569 min-width:20px;
1576 min-width:20px;
1570 text-decoration:none;
1577 text-decoration:none;
1571 height:12px;
1578 height:12px;
1572 margin-bottom:4px;
1579 margin-bottom:4px;
1573 margin-left:5px;
1580 margin-left:5px;
1574 white-space:pre;
1581 white-space:pre;
1575 padding:3px;
1582 padding:3px;
1576 }
1583 }
1577
1584
1578 h3.files_location {
1585 h3.files_location {
1579 font-size:1.8em;
1586 font-size:1.8em;
1580 font-weight:700;
1587 font-weight:700;
1581 border-bottom:none !important;
1588 border-bottom:none !important;
1582 margin:10px 0 !important;
1589 margin:10px 0 !important;
1583 }
1590 }
1584
1591
1585 #files_data dl dt {
1592 #files_data dl dt {
1586 float:left;
1593 float:left;
1587 width:115px;
1594 width:115px;
1588 margin:0 !important;
1595 margin:0 !important;
1589 padding:5px;
1596 padding:5px;
1590 }
1597 }
1591
1598
1592 #files_data dl dd {
1599 #files_data dl dd {
1593 margin:0 !important;
1600 margin:0 !important;
1594 padding:5px !important;
1601 padding:5px !important;
1595 }
1602 }
1596
1603
1597 #changeset_content {
1604 #changeset_content {
1598 border:1px solid #CCC;
1605 border:1px solid #CCC;
1599 padding:5px;
1606 padding:5px;
1600 }
1607 }
1601 #changeset_compare_view_content{
1608 #changeset_compare_view_content{
1602 border:1px solid #CCC;
1609 border:1px solid #CCC;
1603 padding:5px;
1610 padding:5px;
1604 }
1611 }
1605
1612
1606 #changeset_content .container {
1613 #changeset_content .container {
1607 min-height:120px;
1614 min-height:120px;
1608 font-size:1.2em;
1615 font-size:1.2em;
1609 overflow:hidden;
1616 overflow:hidden;
1610 }
1617 }
1611
1618
1612 #changeset_compare_view_content .compare_view_commits{
1619 #changeset_compare_view_content .compare_view_commits{
1613 width: auto !important;
1620 width: auto !important;
1614 }
1621 }
1615
1622
1616 #changeset_compare_view_content .compare_view_commits td{
1623 #changeset_compare_view_content .compare_view_commits td{
1617 padding:0px 0px 0px 12px !important;
1624 padding:0px 0px 0px 12px !important;
1618 }
1625 }
1619
1626
1620 #changeset_content .container .right {
1627 #changeset_content .container .right {
1621 float:right;
1628 float:right;
1622 width:25%;
1629 width:25%;
1623 text-align:right;
1630 text-align:right;
1624 }
1631 }
1625
1632
1626 #changeset_content .container .left .message {
1633 #changeset_content .container .left .message {
1627 font-style:italic;
1634 font-style:italic;
1628 color:#556CB5;
1635 color:#556CB5;
1629 white-space:pre-wrap;
1636 white-space:pre-wrap;
1630 }
1637 }
1631
1638
1632 .cs_files .cur_cs{
1639 .cs_files .cur_cs{
1633 margin:10px 2px;
1640 margin:10px 2px;
1634 font-weight: bold;
1641 font-weight: bold;
1635 }
1642 }
1636
1643
1637 .cs_files .node{
1644 .cs_files .node{
1638 float: left;
1645 float: left;
1639 }
1646 }
1640 .cs_files .changes{
1647 .cs_files .changes{
1641 float: right;
1648 float: right;
1642 }
1649 }
1643 .cs_files .changes .added{
1650 .cs_files .changes .added{
1644 background-color: #BBFFBB;
1651 background-color: #BBFFBB;
1645 float: left;
1652 float: left;
1646 text-align: center;
1653 text-align: center;
1647 font-size: 90%;
1654 font-size: 90%;
1648 }
1655 }
1649 .cs_files .changes .deleted{
1656 .cs_files .changes .deleted{
1650 background-color: #FF8888;
1657 background-color: #FF8888;
1651 float: left;
1658 float: left;
1652 text-align: center;
1659 text-align: center;
1653 font-size: 90%;
1660 font-size: 90%;
1654 }
1661 }
1655 .cs_files .cs_added {
1662 .cs_files .cs_added {
1656 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1663 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1657 height:16px;
1664 height:16px;
1658 padding-left:20px;
1665 padding-left:20px;
1659 margin-top:7px;
1666 margin-top:7px;
1660 text-align:left;
1667 text-align:left;
1661 }
1668 }
1662
1669
1663 .cs_files .cs_changed {
1670 .cs_files .cs_changed {
1664 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1671 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1665 height:16px;
1672 height:16px;
1666 padding-left:20px;
1673 padding-left:20px;
1667 margin-top:7px;
1674 margin-top:7px;
1668 text-align:left;
1675 text-align:left;
1669 }
1676 }
1670
1677
1671 .cs_files .cs_removed {
1678 .cs_files .cs_removed {
1672 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1679 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1673 height:16px;
1680 height:16px;
1674 padding-left:20px;
1681 padding-left:20px;
1675 margin-top:7px;
1682 margin-top:7px;
1676 text-align:left;
1683 text-align:left;
1677 }
1684 }
1678
1685
1679 #graph {
1686 #graph {
1680 overflow:hidden;
1687 overflow:hidden;
1681 }
1688 }
1682
1689
1683 #graph_nodes {
1690 #graph_nodes {
1684 width:160px;
1691 width:160px;
1685 float:left;
1692 float:left;
1686 margin-left:-50px;
1693 margin-left:-50px;
1687 margin-top:5px;
1694 margin-top:5px;
1688 }
1695 }
1689
1696
1690 #graph_content {
1697 #graph_content {
1691 width:800px;
1698 width:800px;
1692 float:left;
1699 float:left;
1693 }
1700 }
1694
1701
1695 #graph_content .container_header {
1702 #graph_content .container_header {
1696 border:1px solid #CCC;
1703 border:1px solid #CCC;
1697 padding:10px;
1704 padding:10px;
1698 }
1705 }
1699 #graph_content #rev_range_container{
1706 #graph_content #rev_range_container{
1700 padding:10px 0px;
1707 padding:10px 0px;
1701 }
1708 }
1702 #graph_content .container {
1709 #graph_content .container {
1703 border-bottom:1px solid #CCC;
1710 border-bottom:1px solid #CCC;
1704 border-left:1px solid #CCC;
1711 border-left:1px solid #CCC;
1705 border-right:1px solid #CCC;
1712 border-right:1px solid #CCC;
1706 min-height:80px;
1713 min-height:80px;
1707 overflow:hidden;
1714 overflow:hidden;
1708 font-size:1.2em;
1715 font-size:1.2em;
1709 }
1716 }
1710
1717
1711 #graph_content .container .right {
1718 #graph_content .container .right {
1712 float:right;
1719 float:right;
1713 width:28%;
1720 width:28%;
1714 text-align:right;
1721 text-align:right;
1715 padding-bottom:5px;
1722 padding-bottom:5px;
1716 }
1723 }
1717
1724
1718 #graph_content .container .left .date {
1725 #graph_content .container .left .date {
1719 font-weight:700;
1726 font-weight:700;
1720 padding-bottom:5px;
1727 padding-bottom:5px;
1721 }
1728 }
1722 #graph_content .container .left .date span{
1729 #graph_content .container .left .date span{
1723 vertical-align: text-top;
1730 vertical-align: text-top;
1724 }
1731 }
1725
1732
1726 #graph_content .container .left .message {
1733 #graph_content .container .left .message {
1727 font-size:100%;
1734 font-size:100%;
1728 padding-top:3px;
1735 padding-top:3px;
1729 white-space:pre-wrap;
1736 white-space:pre-wrap;
1730 }
1737 }
1731
1738
1732 .right div {
1739 .right div {
1733 clear:both;
1740 clear:both;
1734 }
1741 }
1735
1742
1736 .right .changes .added,.changed,.removed {
1743 .right .changes .added,.changed,.removed {
1737 border:1px solid #DDD;
1744 border:1px solid #DDD;
1738 display:block;
1745 display:block;
1739 float:right;
1746 float:right;
1740 text-align:center;
1747 text-align:center;
1741 min-width:15px;
1748 min-width:15px;
1742 cursor: help;
1749 cursor: help;
1743 }
1750 }
1744 .right .changes .large {
1751 .right .changes .large {
1745 border:1px solid #DDD;
1752 border:1px solid #DDD;
1746 display:block;
1753 display:block;
1747 float:right;
1754 float:right;
1748 text-align:center;
1755 text-align:center;
1749 min-width:45px;
1756 min-width:45px;
1750 cursor: help;
1757 cursor: help;
1751 background: #54A9F7;
1758 background: #54A9F7;
1752 }
1759 }
1753
1760
1754 .right .changes .added {
1761 .right .changes .added {
1755 background:#BFB;
1762 background:#BFB;
1756 }
1763 }
1757
1764
1758 .right .changes .changed {
1765 .right .changes .changed {
1759 background:#FD8;
1766 background:#FD8;
1760 }
1767 }
1761
1768
1762 .right .changes .removed {
1769 .right .changes .removed {
1763 background:#F88;
1770 background:#F88;
1764 }
1771 }
1765
1772
1766 .right .merge {
1773 .right .merge {
1767 vertical-align:top;
1774 vertical-align:top;
1768 font-size:0.75em;
1775 font-size:0.75em;
1769 font-weight:700;
1776 font-weight:700;
1770 }
1777 }
1771
1778
1772 .right .parent {
1779 .right .parent {
1773 font-size:90%;
1780 font-size:90%;
1774 font-family:monospace;
1781 font-family:monospace;
1775 }
1782 }
1776
1783
1777 .right .logtags .branchtag {
1784 .right .logtags .branchtag {
1778 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1785 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1779 display:block;
1786 display:block;
1780 font-size:0.8em;
1787 font-size:0.8em;
1781 padding:11px 16px 0 0;
1788 padding:11px 16px 0 0;
1782 }
1789 }
1783
1790
1784 .right .logtags .tagtag {
1791 .right .logtags .tagtag {
1785 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1792 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1786 display:block;
1793 display:block;
1787 font-size:0.8em;
1794 font-size:0.8em;
1788 padding:11px 16px 0 0;
1795 padding:11px 16px 0 0;
1789 }
1796 }
1790
1797
1791 div.browserblock {
1798 div.browserblock {
1792 overflow:hidden;
1799 overflow:hidden;
1793 border:1px solid #ccc;
1800 border:1px solid #ccc;
1794 background:#f8f8f8;
1801 background:#f8f8f8;
1795 font-size:100%;
1802 font-size:100%;
1796 line-height:125%;
1803 line-height:125%;
1797 padding:0;
1804 padding:0;
1798 }
1805 }
1799
1806
1800 div.browserblock .browser-header {
1807 div.browserblock .browser-header {
1801 background:#FFF;
1808 background:#FFF;
1802 padding:10px 0px 25px 0px;
1809 padding:10px 0px 25px 0px;
1803 width: 100%;
1810 width: 100%;
1804 }
1811 }
1805 div.browserblock .browser-nav {
1812 div.browserblock .browser-nav {
1806 float:left
1813 float:left
1807 }
1814 }
1808
1815
1809 div.browserblock .browser-branch {
1816 div.browserblock .browser-branch {
1810 float:left;
1817 float:left;
1811 }
1818 }
1812
1819
1813 div.browserblock .browser-branch label {
1820 div.browserblock .browser-branch label {
1814 color:#4A4A4A;
1821 color:#4A4A4A;
1815 vertical-align:text-top;
1822 vertical-align:text-top;
1816 }
1823 }
1817
1824
1818 div.browserblock .browser-header span {
1825 div.browserblock .browser-header span {
1819 margin-left:5px;
1826 margin-left:5px;
1820 font-weight:700;
1827 font-weight:700;
1821 }
1828 }
1822
1829
1823 div.browserblock .browser-body {
1830 div.browserblock .browser-body {
1824 background:#EEE;
1831 background:#EEE;
1825 border-top:1px solid #CCC;
1832 border-top:1px solid #CCC;
1826 }
1833 }
1827
1834
1828 table.code-browser {
1835 table.code-browser {
1829 border-collapse:collapse;
1836 border-collapse:collapse;
1830 width:100%;
1837 width:100%;
1831 }
1838 }
1832
1839
1833 table.code-browser tr {
1840 table.code-browser tr {
1834 margin:3px;
1841 margin:3px;
1835 }
1842 }
1836
1843
1837 table.code-browser thead th {
1844 table.code-browser thead th {
1838 background-color:#EEE;
1845 background-color:#EEE;
1839 height:20px;
1846 height:20px;
1840 font-size:1.1em;
1847 font-size:1.1em;
1841 font-weight:700;
1848 font-weight:700;
1842 text-align:left;
1849 text-align:left;
1843 padding-left:10px;
1850 padding-left:10px;
1844 }
1851 }
1845
1852
1846 table.code-browser tbody td {
1853 table.code-browser tbody td {
1847 padding-left:10px;
1854 padding-left:10px;
1848 height:20px;
1855 height:20px;
1849 }
1856 }
1850
1857
1851 table.code-browser .browser-file {
1858 table.code-browser .browser-file {
1852 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1859 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1853 height:16px;
1860 height:16px;
1854 padding-left:20px;
1861 padding-left:20px;
1855 text-align:left;
1862 text-align:left;
1856 }
1863 }
1857 .diffblock .changeset_file{
1864 .diffblock .changeset_file{
1858 background:url("../images/icons/file.png") no-repeat scroll 3px;
1865 background:url("../images/icons/file.png") no-repeat scroll 3px;
1859 height:16px;
1866 height:16px;
1860 padding-left:22px;
1867 padding-left:22px;
1861 text-align:left;
1868 text-align:left;
1862 font-size: 14px;
1869 font-size: 14px;
1863 }
1870 }
1864
1871
1865 .diffblock .changeset_header{
1872 .diffblock .changeset_header{
1866 margin-left: 6px !important;
1873 margin-left: 6px !important;
1867 }
1874 }
1868
1875
1869 table.code-browser .browser-dir {
1876 table.code-browser .browser-dir {
1870 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1877 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1871 height:16px;
1878 height:16px;
1872 padding-left:20px;
1879 padding-left:20px;
1873 text-align:left;
1880 text-align:left;
1874 }
1881 }
1875
1882
1876 .box .search {
1883 .box .search {
1877 clear:both;
1884 clear:both;
1878 overflow:hidden;
1885 overflow:hidden;
1879 margin:0;
1886 margin:0;
1880 padding:0 20px 10px;
1887 padding:0 20px 10px;
1881 }
1888 }
1882
1889
1883 .box .search div.search_path {
1890 .box .search div.search_path {
1884 background:none repeat scroll 0 0 #EEE;
1891 background:none repeat scroll 0 0 #EEE;
1885 border:1px solid #CCC;
1892 border:1px solid #CCC;
1886 color:blue;
1893 color:blue;
1887 margin-bottom:10px;
1894 margin-bottom:10px;
1888 padding:10px 0;
1895 padding:10px 0;
1889 }
1896 }
1890
1897
1891 .box .search div.search_path div.link {
1898 .box .search div.search_path div.link {
1892 font-weight:700;
1899 font-weight:700;
1893 margin-left:25px;
1900 margin-left:25px;
1894 }
1901 }
1895
1902
1896 .box .search div.search_path div.link a {
1903 .box .search div.search_path div.link a {
1897 color:#003367;
1904 color:#003367;
1898 cursor:pointer;
1905 cursor:pointer;
1899 text-decoration:none;
1906 text-decoration:none;
1900 }
1907 }
1901
1908
1902 #path_unlock {
1909 #path_unlock {
1903 color:red;
1910 color:red;
1904 font-size:1.2em;
1911 font-size:1.2em;
1905 padding-left:4px;
1912 padding-left:4px;
1906 }
1913 }
1907
1914
1908 .info_box span {
1915 .info_box span {
1909 margin-left:3px;
1916 margin-left:3px;
1910 margin-right:3px;
1917 margin-right:3px;
1911 }
1918 }
1912
1919
1913 .info_box .rev {
1920 .info_box .rev {
1914 color: #003367;
1921 color: #003367;
1915 font-size: 1.6em;
1922 font-size: 1.6em;
1916 font-weight: bold;
1923 font-weight: bold;
1917 vertical-align: sub;
1924 vertical-align: sub;
1918 }
1925 }
1919
1926
1920
1927
1921 .info_box input#at_rev,.info_box input#size {
1928 .info_box input#at_rev,.info_box input#size {
1922 background:#FFF;
1929 background:#FFF;
1923 border-top:1px solid #b3b3b3;
1930 border-top:1px solid #b3b3b3;
1924 border-left:1px solid #b3b3b3;
1931 border-left:1px solid #b3b3b3;
1925 border-right:1px solid #eaeaea;
1932 border-right:1px solid #eaeaea;
1926 border-bottom:1px solid #eaeaea;
1933 border-bottom:1px solid #eaeaea;
1927 color:#000;
1934 color:#000;
1928 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1935 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1929 font-size:12px;
1936 font-size:12px;
1930 margin:0;
1937 margin:0;
1931 padding:1px 5px 1px;
1938 padding:1px 5px 1px;
1932 }
1939 }
1933
1940
1934
1941
1935
1942
1936 .info_box input#view {
1943 .info_box input#view {
1937 text-align:center;
1944 text-align:center;
1938 padding:4px 3px 2px 2px;
1945 padding:4px 3px 2px 2px;
1939 }
1946 }
1940
1947
1941 .yui-overlay,.yui-panel-container {
1948 .yui-overlay,.yui-panel-container {
1942 visibility:hidden;
1949 visibility:hidden;
1943 position:absolute;
1950 position:absolute;
1944 z-index:2;
1951 z-index:2;
1945 }
1952 }
1946
1953
1947 .yui-tt {
1954 .yui-tt {
1948 visibility:hidden;
1955 visibility:hidden;
1949 position:absolute;
1956 position:absolute;
1950 color:#666;
1957 color:#666;
1951 background-color:#FFF;
1958 background-color:#FFF;
1952 font-family:arial, helvetica, verdana, sans-serif;
1959 font-family:arial, helvetica, verdana, sans-serif;
1953 border:2px solid #003367;
1960 border:2px solid #003367;
1954 font:100% sans-serif;
1961 font:100% sans-serif;
1955 width:auto;
1962 width:auto;
1956 opacity:1px;
1963 opacity:1px;
1957 padding:8px;
1964 padding:8px;
1958 white-space: pre;
1965 white-space: pre;
1959 -webkit-border-radius: 8px 8px 8px 8px;
1966 -webkit-border-radius: 8px 8px 8px 8px;
1960 -khtml-border-radius: 8px 8px 8px 8px;
1967 -khtml-border-radius: 8px 8px 8px 8px;
1961 -moz-border-radius: 8px 8px 8px 8px;
1968 -moz-border-radius: 8px 8px 8px 8px;
1962 border-radius: 8px 8px 8px 8px;
1969 border-radius: 8px 8px 8px 8px;
1963 }
1970 }
1964
1971
1965 .ac {
1972 .ac {
1966 vertical-align:top;
1973 vertical-align:top;
1967 }
1974 }
1968
1975
1969 .ac .yui-ac {
1976 .ac .yui-ac {
1970 position:relative;
1977 position:relative;
1971 font-family:arial;
1978 font-family:arial;
1972 font-size:100%;
1979 font-size:100%;
1973 }
1980 }
1974
1981
1975 .ac .perm_ac {
1982 .ac .perm_ac {
1976 width:15em;
1983 width:15em;
1977 }
1984 }
1978
1985
1979 .ac .yui-ac-input {
1986 .ac .yui-ac-input {
1980 width:100%;
1987 width:100%;
1981 }
1988 }
1982
1989
1983 .ac .yui-ac-container {
1990 .ac .yui-ac-container {
1984 position:absolute;
1991 position:absolute;
1985 top:1.6em;
1992 top:1.6em;
1986 width:100%;
1993 width:100%;
1987 }
1994 }
1988
1995
1989 .ac .yui-ac-content {
1996 .ac .yui-ac-content {
1990 position:absolute;
1997 position:absolute;
1991 width:100%;
1998 width:100%;
1992 border:1px solid gray;
1999 border:1px solid gray;
1993 background:#fff;
2000 background:#fff;
1994 overflow:hidden;
2001 overflow:hidden;
1995 z-index:9050;
2002 z-index:9050;
1996 }
2003 }
1997
2004
1998 .ac .yui-ac-shadow {
2005 .ac .yui-ac-shadow {
1999 position:absolute;
2006 position:absolute;
2000 width:100%;
2007 width:100%;
2001 background:#000;
2008 background:#000;
2002 -moz-opacity:0.1px;
2009 -moz-opacity:0.1px;
2003 opacity:.10;
2010 opacity:.10;
2004 filter:alpha(opacity = 10);
2011 filter:alpha(opacity = 10);
2005 z-index:9049;
2012 z-index:9049;
2006 margin:.3em;
2013 margin:.3em;
2007 }
2014 }
2008
2015
2009 .ac .yui-ac-content ul {
2016 .ac .yui-ac-content ul {
2010 width:100%;
2017 width:100%;
2011 margin:0;
2018 margin:0;
2012 padding:0;
2019 padding:0;
2013 }
2020 }
2014
2021
2015 .ac .yui-ac-content li {
2022 .ac .yui-ac-content li {
2016 cursor:default;
2023 cursor:default;
2017 white-space:nowrap;
2024 white-space:nowrap;
2018 margin:0;
2025 margin:0;
2019 padding:2px 5px;
2026 padding:2px 5px;
2020 }
2027 }
2021
2028
2022 .ac .yui-ac-content li.yui-ac-prehighlight {
2029 .ac .yui-ac-content li.yui-ac-prehighlight {
2023 background:#B3D4FF;
2030 background:#B3D4FF;
2024 }
2031 }
2025
2032
2026 .ac .yui-ac-content li.yui-ac-highlight {
2033 .ac .yui-ac-content li.yui-ac-highlight {
2027 background:#556CB5;
2034 background:#556CB5;
2028 color:#FFF;
2035 color:#FFF;
2029 }
2036 }
2030
2037
2031
2038
2032 .follow{
2039 .follow{
2033 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2040 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2034 height: 16px;
2041 height: 16px;
2035 width: 20px;
2042 width: 20px;
2036 cursor: pointer;
2043 cursor: pointer;
2037 display: block;
2044 display: block;
2038 float: right;
2045 float: right;
2039 margin-top: 2px;
2046 margin-top: 2px;
2040 }
2047 }
2041
2048
2042 .following{
2049 .following{
2043 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2050 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2044 height: 16px;
2051 height: 16px;
2045 width: 20px;
2052 width: 20px;
2046 cursor: pointer;
2053 cursor: pointer;
2047 display: block;
2054 display: block;
2048 float: right;
2055 float: right;
2049 margin-top: 2px;
2056 margin-top: 2px;
2050 }
2057 }
2051
2058
2052 .currently_following{
2059 .currently_following{
2053 padding-left: 10px;
2060 padding-left: 10px;
2054 padding-bottom:5px;
2061 padding-bottom:5px;
2055 }
2062 }
2056
2063
2057 .add_icon {
2064 .add_icon {
2058 background:url("../images/icons/add.png") no-repeat scroll 3px;
2065 background:url("../images/icons/add.png") no-repeat scroll 3px;
2059 padding-left:20px;
2066 padding-left:20px;
2060 padding-top:0px;
2067 padding-top:0px;
2061 text-align:left;
2068 text-align:left;
2062 }
2069 }
2063
2070
2064 .edit_icon {
2071 .edit_icon {
2065 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
2072 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
2066 padding-left:20px;
2073 padding-left:20px;
2067 padding-top:0px;
2074 padding-top:0px;
2068 text-align:left;
2075 text-align:left;
2069 }
2076 }
2070
2077
2071 .delete_icon {
2078 .delete_icon {
2072 background:url("../images/icons/delete.png") no-repeat scroll 3px;
2079 background:url("../images/icons/delete.png") no-repeat scroll 3px;
2073 padding-left:20px;
2080 padding-left:20px;
2074 padding-top:0px;
2081 padding-top:0px;
2075 text-align:left;
2082 text-align:left;
2076 }
2083 }
2077
2084
2078 .refresh_icon {
2085 .refresh_icon {
2079 background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
2086 background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
2080 padding-left:20px;
2087 padding-left:20px;
2081 padding-top:0px;
2088 padding-top:0px;
2082 text-align:left;
2089 text-align:left;
2083 }
2090 }
2084
2091
2085 .pull_icon {
2092 .pull_icon {
2086 background:url("../images/icons/connect.png") no-repeat scroll 3px;
2093 background:url("../images/icons/connect.png") no-repeat scroll 3px;
2087 padding-left:20px;
2094 padding-left:20px;
2088 padding-top:0px;
2095 padding-top:0px;
2089 text-align:left;
2096 text-align:left;
2090 }
2097 }
2091
2098
2092 .rss_icon {
2099 .rss_icon {
2093 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
2100 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
2094 padding-left:20px;
2101 padding-left:20px;
2095 padding-top:0px;
2102 padding-top:0px;
2096 text-align:left;
2103 text-align:left;
2097 }
2104 }
2098
2105
2099 .atom_icon {
2106 .atom_icon {
2100 background:url("../images/icons/atom.png") no-repeat scroll 3px;
2107 background:url("../images/icons/atom.png") no-repeat scroll 3px;
2101 padding-left:20px;
2108 padding-left:20px;
2102 padding-top:0px;
2109 padding-top:0px;
2103 text-align:left;
2110 text-align:left;
2104 }
2111 }
2105
2112
2106 .archive_icon {
2113 .archive_icon {
2107 background:url("../images/icons/compress.png") no-repeat scroll 3px;
2114 background:url("../images/icons/compress.png") no-repeat scroll 3px;
2108 padding-left:20px;
2115 padding-left:20px;
2109 text-align:left;
2116 text-align:left;
2110 padding-top:1px;
2117 padding-top:1px;
2111 }
2118 }
2112
2119
2113 .start_following_icon {
2120 .start_following_icon {
2114 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2121 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2115 padding-left:20px;
2122 padding-left:20px;
2116 text-align:left;
2123 text-align:left;
2117 padding-top:0px;
2124 padding-top:0px;
2118 }
2125 }
2119
2126
2120 .stop_following_icon {
2127 .stop_following_icon {
2121 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2128 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2122 padding-left:20px;
2129 padding-left:20px;
2123 text-align:left;
2130 text-align:left;
2124 padding-top:0px;
2131 padding-top:0px;
2125 }
2132 }
2126
2133
2127 .action_button {
2134 .action_button {
2128 border:0;
2135 border:0;
2129 display:inline;
2136 display:inline;
2130 }
2137 }
2131
2138
2132 .action_button:hover {
2139 .action_button:hover {
2133 border:0;
2140 border:0;
2134 text-decoration:underline;
2141 text-decoration:underline;
2135 cursor:pointer;
2142 cursor:pointer;
2136 }
2143 }
2137
2144
2138 #switch_repos {
2145 #switch_repos {
2139 position:absolute;
2146 position:absolute;
2140 height:25px;
2147 height:25px;
2141 z-index:1;
2148 z-index:1;
2142 }
2149 }
2143
2150
2144 #switch_repos select {
2151 #switch_repos select {
2145 min-width:150px;
2152 min-width:150px;
2146 max-height:250px;
2153 max-height:250px;
2147 z-index:1;
2154 z-index:1;
2148 }
2155 }
2149
2156
2150 .breadcrumbs {
2157 .breadcrumbs {
2151 border:medium none;
2158 border:medium none;
2152 color:#FFF;
2159 color:#FFF;
2153 float:left;
2160 float:left;
2154 text-transform:uppercase;
2161 text-transform:uppercase;
2155 font-weight:700;
2162 font-weight:700;
2156 font-size:14px;
2163 font-size:14px;
2157 margin:0;
2164 margin:0;
2158 padding:11px 0 11px 10px;
2165 padding:11px 0 11px 10px;
2159 }
2166 }
2160
2167
2161 .breadcrumbs a {
2168 .breadcrumbs a {
2162 color:#FFF;
2169 color:#FFF;
2163 }
2170 }
2164
2171
2165 .flash_msg ul {
2172 .flash_msg ul {
2166 margin:0;
2173 margin:0;
2167 padding:0 0 10px;
2174 padding:0 0 10px;
2168 }
2175 }
2169
2176
2170 .error_msg {
2177 .error_msg {
2171 background-color:#FFCFCF;
2178 background-color:#FFCFCF;
2172 background-image:url("../images/icons/error_msg.png");
2179 background-image:url("../images/icons/error_msg.png");
2173 border:1px solid #FF9595;
2180 border:1px solid #FF9595;
2174 color:#C30;
2181 color:#C30;
2175 }
2182 }
2176
2183
2177 .warning_msg {
2184 .warning_msg {
2178 background-color:#FFFBCC;
2185 background-color:#FFFBCC;
2179 background-image:url("../images/icons/warning_msg.png");
2186 background-image:url("../images/icons/warning_msg.png");
2180 border:1px solid #FFF35E;
2187 border:1px solid #FFF35E;
2181 color:#C69E00;
2188 color:#C69E00;
2182 }
2189 }
2183
2190
2184 .success_msg {
2191 .success_msg {
2185 background-color:#D5FFCF;
2192 background-color:#D5FFCF;
2186 background-image:url("../images/icons/success_msg.png");
2193 background-image:url("../images/icons/success_msg.png");
2187 border:1px solid #97FF88;
2194 border:1px solid #97FF88;
2188 color:#090;
2195 color:#090;
2189 }
2196 }
2190
2197
2191 .notice_msg {
2198 .notice_msg {
2192 background-color:#DCE3FF;
2199 background-color:#DCE3FF;
2193 background-image:url("../images/icons/notice_msg.png");
2200 background-image:url("../images/icons/notice_msg.png");
2194 border:1px solid #93A8FF;
2201 border:1px solid #93A8FF;
2195 color:#556CB5;
2202 color:#556CB5;
2196 }
2203 }
2197
2204
2198 .success_msg,.error_msg,.notice_msg,.warning_msg {
2205 .success_msg,.error_msg,.notice_msg,.warning_msg {
2199 background-position:10px center;
2206 background-position:10px center;
2200 background-repeat:no-repeat;
2207 background-repeat:no-repeat;
2201 font-size:12px;
2208 font-size:12px;
2202 font-weight:700;
2209 font-weight:700;
2203 min-height:14px;
2210 min-height:14px;
2204 line-height:14px;
2211 line-height:14px;
2205 margin-bottom:0;
2212 margin-bottom:0;
2206 margin-top:0;
2213 margin-top:0;
2207 display:block;
2214 display:block;
2208 overflow:auto;
2215 overflow:auto;
2209 padding:6px 10px 6px 40px;
2216 padding:6px 10px 6px 40px;
2210 }
2217 }
2211
2218
2212 #msg_close {
2219 #msg_close {
2213 background:transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
2220 background:transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
2214 cursor:pointer;
2221 cursor:pointer;
2215 height:16px;
2222 height:16px;
2216 position:absolute;
2223 position:absolute;
2217 right:5px;
2224 right:5px;
2218 top:5px;
2225 top:5px;
2219 width:16px;
2226 width:16px;
2220 }
2227 }
2221
2228
2222 div#legend_container table,div#legend_choices table {
2229 div#legend_container table,div#legend_choices table {
2223 width:auto !important;
2230 width:auto !important;
2224 }
2231 }
2225
2232
2226 table#permissions_manage {
2233 table#permissions_manage {
2227 width:0 !important;
2234 width:0 !important;
2228 }
2235 }
2229
2236
2230 table#permissions_manage span.private_repo_msg {
2237 table#permissions_manage span.private_repo_msg {
2231 font-size:0.8em;
2238 font-size:0.8em;
2232 opacity:0.6px;
2239 opacity:0.6px;
2233 }
2240 }
2234
2241
2235 table#permissions_manage td.private_repo_msg {
2242 table#permissions_manage td.private_repo_msg {
2236 font-size:0.8em;
2243 font-size:0.8em;
2237 }
2244 }
2238
2245
2239 table#permissions_manage tr#add_perm_input td {
2246 table#permissions_manage tr#add_perm_input td {
2240 vertical-align:middle;
2247 vertical-align:middle;
2241 }
2248 }
2242
2249
2243 div.gravatar {
2250 div.gravatar {
2244 background-color:#FFF;
2251 background-color:#FFF;
2245 border:1px solid #D0D0D0;
2252 border:1px solid #D0D0D0;
2246 float:left;
2253 float:left;
2247 margin-right:0.7em;
2254 margin-right:0.7em;
2248 padding:2px 2px 0;
2255 padding:2px 2px 0;
2249 }
2256 }
2250
2257
2251 #header,#content,#footer {
2258 #header,#content,#footer {
2252 min-width:978px;
2259 min-width:978px;
2253 }
2260 }
2254
2261
2255 #content {
2262 #content {
2256 min-height:100%;
2263 min-height:100%;
2257 clear:both;
2264 clear:both;
2258 overflow:hidden;
2265 overflow:hidden;
2259 padding:14px 10px;
2266 padding:14px 10px;
2260 }
2267 }
2261
2268
2262 #content div.box div.title div.search {
2269 #content div.box div.title div.search {
2263 background:url("../images/title_link.png") no-repeat top left;
2270 background:url("../images/title_link.png") no-repeat top left;
2264 border-left:1px solid #316293;
2271 border-left:1px solid #316293;
2265 }
2272 }
2266
2273
2267 #content div.box div.title div.search div.input input {
2274 #content div.box div.title div.search div.input input {
2268 border:1px solid #316293;
2275 border:1px solid #316293;
2269 }
2276 }
2270
2277
2271 #content div.box div.title div.search div.button input.ui-button {
2278 #content div.box div.title div.search div.button input.ui-button {
2272 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2279 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2273 border:1px solid #316293;
2280 border:1px solid #316293;
2274 border-left:none;
2281 border-left:none;
2275 color:#FFF;
2282 color:#FFF;
2276 }
2283 }
2277
2284
2278 #content div.box input.ui-button-small {
2285 #content div.box input.ui-button-small {
2279 background:#e5e3e3 url("../images/button.png") repeat-x;
2286 background:#e5e3e3 url("../images/button.png") repeat-x;
2280 border-top:1px solid #DDD;
2287 border-top:1px solid #DDD;
2281 border-left:1px solid #c6c6c6;
2288 border-left:1px solid #c6c6c6;
2282 border-right:1px solid #DDD;
2289 border-right:1px solid #DDD;
2283 border-bottom:1px solid #c6c6c6;
2290 border-bottom:1px solid #c6c6c6;
2284 color:#515151;
2291 color:#515151;
2285 outline:none;
2292 outline:none;
2286 margin:0;
2293 margin:0;
2287 }
2294 }
2288
2295
2289 #content div.box input.ui-button-small-blue {
2296 #content div.box input.ui-button-small-blue {
2290 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2297 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2291 border-top:1px solid #5c91a4;
2298 border-top:1px solid #5c91a4;
2292 border-left:1px solid #2a6f89;
2299 border-left:1px solid #2a6f89;
2293 border-right:1px solid #2b7089;
2300 border-right:1px solid #2b7089;
2294 border-bottom:1px solid #1a6480;
2301 border-bottom:1px solid #1a6480;
2295 color:#fff;
2302 color:#fff;
2296 }
2303 }
2297
2304
2298 #content div.box input.ui-button-small submit,button{
2305 #content div.box input.ui-button-small submit,button{
2299 cursor: pointer;
2306 cursor: pointer;
2300 }
2307 }
2301
2308
2302 #content div.box div.title div.search div.button input.ui-state-hover {
2309 #content div.box div.title div.search div.button input.ui-state-hover {
2303 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2310 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2304 border:1px solid #316293;
2311 border:1px solid #316293;
2305 border-left:none;
2312 border-left:none;
2306 color:#FFF;
2313 color:#FFF;
2307 }
2314 }
2308
2315
2309 #content div.box div.form div.fields div.field div.highlight .ui-button {
2316 #content div.box div.form div.fields div.field div.highlight .ui-button {
2310 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2317 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2311 border-top:1px solid #5c91a4;
2318 border-top:1px solid #5c91a4;
2312 border-left:1px solid #2a6f89;
2319 border-left:1px solid #2a6f89;
2313 border-right:1px solid #2b7089;
2320 border-right:1px solid #2b7089;
2314 border-bottom:1px solid #1a6480;
2321 border-bottom:1px solid #1a6480;
2315 color:#fff;
2322 color:#fff;
2316 }
2323 }
2317
2324
2318 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
2325 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
2319 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2326 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2320 border-top:1px solid #78acbf;
2327 border-top:1px solid #78acbf;
2321 border-left:1px solid #34819e;
2328 border-left:1px solid #34819e;
2322 border-right:1px solid #35829f;
2329 border-right:1px solid #35829f;
2323 border-bottom:1px solid #257897;
2330 border-bottom:1px solid #257897;
2324 color:#fff;
2331 color:#fff;
2325 }
2332 }
2326
2333
2327 ins,div.options a:hover {
2334 ins,div.options a:hover {
2328 text-decoration:none;
2335 text-decoration:none;
2329 }
2336 }
2330
2337
2331 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2338 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2332 border:none;
2339 border:none;
2333 }
2340 }
2334
2341
2335 img.icon,.right .merge img {
2342 img.icon,.right .merge img {
2336 vertical-align:bottom;
2343 vertical-align:bottom;
2337 }
2344 }
2338
2345
2339 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2346 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2340 float:right;
2347 float:right;
2341 margin:0;
2348 margin:0;
2342 padding:0;
2349 padding:0;
2343 }
2350 }
2344
2351
2345 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2352 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2346 float:left;
2353 float:left;
2347 }
2354 }
2348
2355
2349 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2356 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2350 display:none;
2357 display:none;
2351 }
2358 }
2352
2359
2353 #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 {
2360 #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 {
2354 display:block;
2361 display:block;
2355 }
2362 }
2356
2363
2357 #content div.graph{
2364 #content div.graph{
2358 padding:0 10px 10px;
2365 padding:0 10px 10px;
2359 }
2366 }
2360
2367
2361 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2368 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2362 color:#bfe3ff;
2369 color:#bfe3ff;
2363 }
2370 }
2364
2371
2365 #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 {
2372 #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 {
2366 margin:10px 24px 10px 44px;
2373 margin:10px 24px 10px 44px;
2367 }
2374 }
2368
2375
2369 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2376 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2370 clear:both;
2377 clear:both;
2371 overflow:hidden;
2378 overflow:hidden;
2372 margin:0;
2379 margin:0;
2373 padding:0 20px 10px;
2380 padding:0 20px 10px;
2374 }
2381 }
2375
2382
2376 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2383 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2377 clear:both;
2384 clear:both;
2378 overflow:hidden;
2385 overflow:hidden;
2379 margin:0;
2386 margin:0;
2380 padding:0;
2387 padding:0;
2381 }
2388 }
2382
2389
2383 #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 {
2390 #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 {
2384 height:1%;
2391 height:1%;
2385 display:block;
2392 display:block;
2386 color:#363636;
2393 color:#363636;
2387 margin:0;
2394 margin:0;
2388 padding:2px 0 0;
2395 padding:2px 0 0;
2389 }
2396 }
2390
2397
2391 #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 {
2398 #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 {
2392 background:#FBE3E4;
2399 background:#FBE3E4;
2393 border-top:1px solid #e1b2b3;
2400 border-top:1px solid #e1b2b3;
2394 border-left:1px solid #e1b2b3;
2401 border-left:1px solid #e1b2b3;
2395 border-right:1px solid #FBC2C4;
2402 border-right:1px solid #FBC2C4;
2396 border-bottom:1px solid #FBC2C4;
2403 border-bottom:1px solid #FBC2C4;
2397 }
2404 }
2398
2405
2399 #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 {
2406 #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 {
2400 background:#E6EFC2;
2407 background:#E6EFC2;
2401 border-top:1px solid #cebb98;
2408 border-top:1px solid #cebb98;
2402 border-left:1px solid #cebb98;
2409 border-left:1px solid #cebb98;
2403 border-right:1px solid #c6d880;
2410 border-right:1px solid #c6d880;
2404 border-bottom:1px solid #c6d880;
2411 border-bottom:1px solid #c6d880;
2405 }
2412 }
2406
2413
2407 #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 {
2414 #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 {
2408 margin:0;
2415 margin:0;
2409 }
2416 }
2410
2417
2411 #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{
2418 #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{
2412 margin:0 0 0 0px !important;
2419 margin:0 0 0 0px !important;
2413 padding:0;
2420 padding:0;
2414 }
2421 }
2415
2422
2416 #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 {
2423 #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 {
2417 margin:0 0 0 200px;
2424 margin:0 0 0 200px;
2418 padding:0;
2425 padding:0;
2419 }
2426 }
2420
2427
2421
2428
2422 #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 {
2429 #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 {
2423 color:#000;
2430 color:#000;
2424 text-decoration:none;
2431 text-decoration:none;
2425 }
2432 }
2426
2433
2427 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2434 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2428 border:1px solid #666;
2435 border:1px solid #666;
2429 }
2436 }
2430
2437
2431 #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 {
2438 #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 {
2432 clear:both;
2439 clear:both;
2433 overflow:hidden;
2440 overflow:hidden;
2434 margin:0;
2441 margin:0;
2435 padding:8px 0 2px;
2442 padding:8px 0 2px;
2436 }
2443 }
2437
2444
2438 #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 {
2445 #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 {
2439 float:left;
2446 float:left;
2440 margin:0;
2447 margin:0;
2441 }
2448 }
2442
2449
2443 #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 {
2450 #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 {
2444 height:1%;
2451 height:1%;
2445 display:block;
2452 display:block;
2446 float:left;
2453 float:left;
2447 margin:2px 0 0 4px;
2454 margin:2px 0 0 4px;
2448 }
2455 }
2449
2456
2450 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2457 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2451 color:#000;
2458 color:#000;
2452 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2459 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2453 font-size:11px;
2460 font-size:11px;
2454 font-weight:700;
2461 font-weight:700;
2455 margin:0;
2462 margin:0;
2456 }
2463 }
2457
2464
2458 div.form div.fields div.field div.button .ui-button,#content div.box div.form div.fields div.buttons input.ui-button {
2465 div.form div.fields div.field div.button .ui-button,#content div.box div.form div.fields div.buttons input.ui-button {
2459 background:#e5e3e3 url("../images/button.png") repeat-x;
2466 background:#e5e3e3 url("../images/button.png") repeat-x;
2460 border-top:1px solid #DDD;
2467 border-top:1px solid #DDD;
2461 border-left:1px solid #c6c6c6;
2468 border-left:1px solid #c6c6c6;
2462 border-right:1px solid #DDD;
2469 border-right:1px solid #DDD;
2463 border-bottom:1px solid #c6c6c6;
2470 border-bottom:1px solid #c6c6c6;
2464 color:#515151;
2471 color:#515151;
2465 outline:none;
2472 outline:none;
2466 margin:0;
2473 margin:0;
2467 padding:6px 12px;
2474 padding:6px 12px;
2468 }
2475 }
2469
2476
2470 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2477 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2471 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2478 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2472 border-top:1px solid #ccc;
2479 border-top:1px solid #ccc;
2473 border-left:1px solid #bebebe;
2480 border-left:1px solid #bebebe;
2474 border-right:1px solid #b1b1b1;
2481 border-right:1px solid #b1b1b1;
2475 border-bottom:1px solid #afafaf;
2482 border-bottom:1px solid #afafaf;
2476 color:#515151;
2483 color:#515151;
2477 outline:none;
2484 outline:none;
2478 margin:0;
2485 margin:0;
2479 padding:6px 12px;
2486 padding:6px 12px;
2480 }
2487 }
2481
2488
2482 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2489 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2483 display:inline;
2490 display:inline;
2484 }
2491 }
2485
2492
2486 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2493 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2487 margin:10px 0 0 200px;
2494 margin:10px 0 0 200px;
2488 padding:0;
2495 padding:0;
2489 }
2496 }
2490
2497
2491 #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 {
2498 #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 {
2492 margin:10px 0 0;
2499 margin:10px 0 0;
2493 }
2500 }
2494
2501
2495 #content div.box table td.user,#content div.box table td.address {
2502 #content div.box table td.user,#content div.box table td.address {
2496 width:10%;
2503 width:10%;
2497 text-align:center;
2504 text-align:center;
2498 }
2505 }
2499
2506
2500 #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 {
2507 #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 {
2501 text-align:right;
2508 text-align:right;
2502 margin:6px 0 0;
2509 margin:6px 0 0;
2503 padding:0;
2510 padding:0;
2504 }
2511 }
2505
2512
2506 #content div.box div.action div.button input.ui-button,#login div.form div.fields div.buttons input.ui-button,#register div.form div.fields div.buttons input.ui-button {
2513 #content div.box div.action div.button input.ui-button,#login div.form div.fields div.buttons input.ui-button,#register div.form div.fields div.buttons input.ui-button {
2507 background:#e5e3e3 url("../images/button.png") repeat-x;
2514 background:#e5e3e3 url("../images/button.png") repeat-x;
2508 border-top:1px solid #DDD;
2515 border-top:1px solid #DDD;
2509 border-left:1px solid #c6c6c6;
2516 border-left:1px solid #c6c6c6;
2510 border-right:1px solid #DDD;
2517 border-right:1px solid #DDD;
2511 border-bottom:1px solid #c6c6c6;
2518 border-bottom:1px solid #c6c6c6;
2512 color:#515151;
2519 color:#515151;
2513 margin:0;
2520 margin:0;
2514 padding:6px 12px;
2521 padding:6px 12px;
2515 }
2522 }
2516
2523
2517 #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 {
2524 #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 {
2518 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2525 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2519 border-top:1px solid #ccc;
2526 border-top:1px solid #ccc;
2520 border-left:1px solid #bebebe;
2527 border-left:1px solid #bebebe;
2521 border-right:1px solid #b1b1b1;
2528 border-right:1px solid #b1b1b1;
2522 border-bottom:1px solid #afafaf;
2529 border-bottom:1px solid #afafaf;
2523 color:#515151;
2530 color:#515151;
2524 margin:0;
2531 margin:0;
2525 padding:6px 12px;
2532 padding:6px 12px;
2526 }
2533 }
2527
2534
2528 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2535 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2529 text-align:left;
2536 text-align:left;
2530 float:left;
2537 float:left;
2531 margin:0;
2538 margin:0;
2532 padding:0;
2539 padding:0;
2533 }
2540 }
2534
2541
2535 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2542 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2536 height:1%;
2543 height:1%;
2537 display:block;
2544 display:block;
2538 float:left;
2545 float:left;
2539 background:#ebebeb url("../images/pager.png") repeat-x;
2546 background:#ebebeb url("../images/pager.png") repeat-x;
2540 border-top:1px solid #dedede;
2547 border-top:1px solid #dedede;
2541 border-left:1px solid #cfcfcf;
2548 border-left:1px solid #cfcfcf;
2542 border-right:1px solid #c4c4c4;
2549 border-right:1px solid #c4c4c4;
2543 border-bottom:1px solid #c4c4c4;
2550 border-bottom:1px solid #c4c4c4;
2544 color:#4A4A4A;
2551 color:#4A4A4A;
2545 font-weight:700;
2552 font-weight:700;
2546 margin:0;
2553 margin:0;
2547 padding:6px 8px;
2554 padding:6px 8px;
2548 }
2555 }
2549
2556
2550 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2557 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2551 color:#B4B4B4;
2558 color:#B4B4B4;
2552 padding:6px;
2559 padding:6px;
2553 }
2560 }
2554
2561
2555 #login,#register {
2562 #login,#register {
2556 width:520px;
2563 width:520px;
2557 margin:10% auto 0;
2564 margin:10% auto 0;
2558 padding:0;
2565 padding:0;
2559 }
2566 }
2560
2567
2561 #login div.color,#register div.color {
2568 #login div.color,#register div.color {
2562 clear:both;
2569 clear:both;
2563 overflow:hidden;
2570 overflow:hidden;
2564 background:#FFF;
2571 background:#FFF;
2565 margin:10px auto 0;
2572 margin:10px auto 0;
2566 padding:3px 3px 3px 0;
2573 padding:3px 3px 3px 0;
2567 }
2574 }
2568
2575
2569 #login div.color a,#register div.color a {
2576 #login div.color a,#register div.color a {
2570 width:20px;
2577 width:20px;
2571 height:20px;
2578 height:20px;
2572 display:block;
2579 display:block;
2573 float:left;
2580 float:left;
2574 margin:0 0 0 3px;
2581 margin:0 0 0 3px;
2575 padding:0;
2582 padding:0;
2576 }
2583 }
2577
2584
2578 #login div.title h5,#register div.title h5 {
2585 #login div.title h5,#register div.title h5 {
2579 color:#fff;
2586 color:#fff;
2580 margin:10px;
2587 margin:10px;
2581 padding:0;
2588 padding:0;
2582 }
2589 }
2583
2590
2584 #login div.form div.fields div.field,#register div.form div.fields div.field {
2591 #login div.form div.fields div.field,#register div.form div.fields div.field {
2585 clear:both;
2592 clear:both;
2586 overflow:hidden;
2593 overflow:hidden;
2587 margin:0;
2594 margin:0;
2588 padding:0 0 10px;
2595 padding:0 0 10px;
2589 }
2596 }
2590
2597
2591 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2598 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2592 height:1%;
2599 height:1%;
2593 display:block;
2600 display:block;
2594 color:red;
2601 color:red;
2595 margin:8px 0 0;
2602 margin:8px 0 0;
2596 padding:0;
2603 padding:0;
2597 max-width: 320px;
2604 max-width: 320px;
2598 }
2605 }
2599
2606
2600 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2607 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2601 color:#000;
2608 color:#000;
2602 font-weight:700;
2609 font-weight:700;
2603 }
2610 }
2604
2611
2605 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2612 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2606 float:left;
2613 float:left;
2607 margin:0;
2614 margin:0;
2608 padding:0;
2615 padding:0;
2609 }
2616 }
2610
2617
2611 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2618 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2612 margin:0 0 0 184px;
2619 margin:0 0 0 184px;
2613 padding:0;
2620 padding:0;
2614 }
2621 }
2615
2622
2616 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2623 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2617 color:#565656;
2624 color:#565656;
2618 font-weight:700;
2625 font-weight:700;
2619 }
2626 }
2620
2627
2621 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2628 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2622 color:#000;
2629 color:#000;
2623 font-size:1em;
2630 font-size:1em;
2624 font-weight:700;
2631 font-weight:700;
2625 font-family:Verdana, Helvetica, Sans-Serif;
2632 font-family:Verdana, Helvetica, Sans-Serif;
2626 margin:0;
2633 margin:0;
2627 }
2634 }
2628
2635
2629 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2636 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2630 width:600px;
2637 width:600px;
2631 }
2638 }
2632
2639
2633 #changeset_content .container .left,#graph_content .container .left {
2640 #changeset_content .container .left,#graph_content .container .left {
2634 float:left;
2641 float:left;
2635 width:70%;
2642 width:70%;
2636 padding-left:5px;
2643 padding-left:5px;
2637 }
2644 }
2638
2645
2639 #changeset_content .container .left .date,.ac .match {
2646 #changeset_content .container .left .date,.ac .match {
2640 font-weight:700;
2647 font-weight:700;
2641 padding-top: 5px;
2648 padding-top: 5px;
2642 padding-bottom:5px;
2649 padding-bottom:5px;
2643 }
2650 }
2644
2651
2645 div#legend_container table td,div#legend_choices table td {
2652 div#legend_container table td,div#legend_choices table td {
2646 border:none !important;
2653 border:none !important;
2647 height:20px !important;
2654 height:20px !important;
2648 padding:0 !important;
2655 padding:0 !important;
2649 }
2656 }
2650
2657
2651 #q_filter{
2658 #q_filter{
2652 border:0 none;
2659 border:0 none;
2653 color:#AAAAAA;
2660 color:#AAAAAA;
2654 margin-bottom:-4px;
2661 margin-bottom:-4px;
2655 margin-top:-4px;
2662 margin-top:-4px;
2656 padding-left:3px;
2663 padding-left:3px;
2657 }
2664 }
2658
2665
@@ -1,61 +1,60 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 ${h.form(url('repos'))}
3 ${h.form(url('repos'))}
4 <div class="form">
4 <div class="form">
5 <!-- fields -->
5 <!-- fields -->
6 <div class="fields">
6 <div class="fields">
7 <div class="field">
7 <div class="field">
8 <div class="label">
8 <div class="label">
9 <label for="repo_name">${_('Name')}:</label>
9 <label for="repo_name">${_('Name')}:</label>
10 </div>
10 </div>
11 <div class="input">
11 <div class="input">
12 ${h.text('repo_name',c.new_repo,class_="small")}
12 ${h.text('repo_name',c.new_repo,class_="small")}
13 </div>
13 </div>
14 </div>
14 </div>
15 <div class="field">
15 <div class="field">
16 <div class="label">
16 <div class="label">
17 <label for="clone_uri">${_('Clone from')}:</label>
17 <label for="clone_uri">${_('Clone from')}:</label>
18 </div>
18 </div>
19 <div class="input">
19 <div class="input">
20 ${h.text('clone_uri',class_="small")}
20 ${h.text('clone_uri',class_="small")}
21 </div>
21 </div>
22 </div>
22 </div>
23 <div class="field">
23 <div class="field">
24 <div class="label">
24 <div class="label">
25 <label for="repo_group">${_('Repository group')}:</label>
25 <label for="repo_group">${_('Repository group')}:</label>
26 </div>
26 </div>
27 <div class="input">
27 <div class="input">
28 ${h.select('repo_group','',c.repo_groups,class_="medium")}
28 ${h.select('repo_group','',c.repo_groups,class_="medium")}
29 <span>${h.link_to(_('add new group'),h.url(''))}</span>
30 </div>
29 </div>
31 </div>
30 </div>
32 <div class="field">
31 <div class="field">
33 <div class="label">
32 <div class="label">
34 <label for="repo_type">${_('Type')}:</label>
33 <label for="repo_type">${_('Type')}:</label>
35 </div>
34 </div>
36 <div class="input">
35 <div class="input">
37 ${h.select('repo_type','hg',c.backends,class_="small")}
36 ${h.select('repo_type','hg',c.backends,class_="small")}
38 </div>
37 </div>
39 </div>
38 </div>
40 <div class="field">
39 <div class="field">
41 <div class="label label-textarea">
40 <div class="label label-textarea">
42 <label for="description">${_('Description')}:</label>
41 <label for="description">${_('Description')}:</label>
43 </div>
42 </div>
44 <div class="textarea text-area editor">
43 <div class="textarea text-area editor">
45 ${h.textarea('description',cols=23,rows=5)}
44 ${h.textarea('description',cols=23,rows=5)}
46 </div>
45 </div>
47 </div>
46 </div>
48 <div class="field">
47 <div class="field">
49 <div class="label label-checkbox">
48 <div class="label label-checkbox">
50 <label for="private">${_('Private')}:</label>
49 <label for="private">${_('Private')}:</label>
51 </div>
50 </div>
52 <div class="checkboxes">
51 <div class="checkboxes">
53 ${h.checkbox('private',value="True")}
52 ${h.checkbox('private',value="True")}
54 </div>
53 </div>
55 </div>
54 </div>
56 <div class="buttons">
55 <div class="buttons">
57 ${h.submit('add','add',class_="ui-button")}
56 ${h.submit('add','add',class_="ui-button")}
58 </div>
57 </div>
59 </div>
58 </div>
60 </div>
59 </div>
61 ${h.end_form()}
60 ${h.end_form()}
@@ -1,383 +1,382 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(_('Repositories'),h.url('repos'))}
11 ${h.link_to(_('Repositories'),h.url('repos'))}
12 &raquo;
12 &raquo;
13 ${_('edit')} &raquo; ${h.link_to(c.repo_info.just_name,h.url('summary_home',repo_name=c.repo_name))}
13 ${_('edit')} &raquo; ${h.link_to(c.repo_info.just_name,h.url('summary_home',repo_name=c.repo_name))}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box box-left">
21 <div class="box box-left">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 <div class="form">
27 <div class="form">
28 <!-- fields -->
28 <!-- fields -->
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="repo_name">${_('Name')}:</label>
32 <label for="repo_name">${_('Name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('repo_name',class_="medium")}
35 ${h.text('repo_name',class_="medium")}
36 </div>
36 </div>
37 </div>
37 </div>
38 <div class="field">
38 <div class="field">
39 <div class="label">
39 <div class="label">
40 <label for="clone_uri">${_('Clone uri')}:</label>
40 <label for="clone_uri">${_('Clone uri')}:</label>
41 </div>
41 </div>
42 <div class="input">
42 <div class="input">
43 ${h.text('clone_uri',class_="medium")}
43 ${h.text('clone_uri',class_="medium")}
44 </div>
44 </div>
45 </div>
45 </div>
46 <div class="field">
46 <div class="field">
47 <div class="label">
47 <div class="label">
48 <label for="repo_group">${_('Repository group')}:</label>
48 <label for="repo_group">${_('Repository group')}:</label>
49 </div>
49 </div>
50 <div class="input">
50 <div class="input">
51 ${h.select('repo_group','',c.repo_groups,class_="medium")}
51 ${h.select('repo_group','',c.repo_groups,class_="medium")}
52 <span>${h.link_to(_('add new group'),h.url(''))}</span>
53 </div>
52 </div>
54 </div>
53 </div>
55 <div class="field">
54 <div class="field">
56 <div class="label">
55 <div class="label">
57 <label for="repo_type">${_('Type')}:</label>
56 <label for="repo_type">${_('Type')}:</label>
58 </div>
57 </div>
59 <div class="input">
58 <div class="input">
60 ${h.select('repo_type','hg',c.backends,class_="medium")}
59 ${h.select('repo_type','hg',c.backends,class_="medium")}
61 </div>
60 </div>
62 </div>
61 </div>
63 <div class="field">
62 <div class="field">
64 <div class="label label-textarea">
63 <div class="label label-textarea">
65 <label for="description">${_('Description')}:</label>
64 <label for="description">${_('Description')}:</label>
66 </div>
65 </div>
67 <div class="textarea text-area editor">
66 <div class="textarea text-area editor">
68 ${h.textarea('description',cols=23,rows=5)}
67 ${h.textarea('description',cols=23,rows=5)}
69 </div>
68 </div>
70 </div>
69 </div>
71
70
72 <div class="field">
71 <div class="field">
73 <div class="label label-checkbox">
72 <div class="label label-checkbox">
74 <label for="private">${_('Private')}:</label>
73 <label for="private">${_('Private')}:</label>
75 </div>
74 </div>
76 <div class="checkboxes">
75 <div class="checkboxes">
77 ${h.checkbox('private',value="True")}
76 ${h.checkbox('private',value="True")}
78 </div>
77 </div>
79 </div>
78 </div>
80 <div class="field">
79 <div class="field">
81 <div class="label label-checkbox">
80 <div class="label label-checkbox">
82 <label for="enable_statistics">${_('Enable statistics')}:</label>
81 <label for="enable_statistics">${_('Enable statistics')}:</label>
83 </div>
82 </div>
84 <div class="checkboxes">
83 <div class="checkboxes">
85 ${h.checkbox('enable_statistics',value="True")}
84 ${h.checkbox('enable_statistics',value="True")}
86 </div>
85 </div>
87 </div>
86 </div>
88 <div class="field">
87 <div class="field">
89 <div class="label label-checkbox">
88 <div class="label label-checkbox">
90 <label for="enable_downloads">${_('Enable downloads')}:</label>
89 <label for="enable_downloads">${_('Enable downloads')}:</label>
91 </div>
90 </div>
92 <div class="checkboxes">
91 <div class="checkboxes">
93 ${h.checkbox('enable_downloads',value="True")}
92 ${h.checkbox('enable_downloads',value="True")}
94 </div>
93 </div>
95 </div>
94 </div>
96 <div class="field">
95 <div class="field">
97 <div class="label">
96 <div class="label">
98 <label for="user">${_('Owner')}:</label>
97 <label for="user">${_('Owner')}:</label>
99 </div>
98 </div>
100 <div class="input input-small ac">
99 <div class="input input-small ac">
101 <div class="perm_ac">
100 <div class="perm_ac">
102 ${h.text('user',class_='yui-ac-input')}
101 ${h.text('user',class_='yui-ac-input')}
103 <div id="owner_container"></div>
102 <div id="owner_container"></div>
104 </div>
103 </div>
105 </div>
104 </div>
106 </div>
105 </div>
107
106
108 <div class="field">
107 <div class="field">
109 <div class="label">
108 <div class="label">
110 <label for="input">${_('Permissions')}:</label>
109 <label for="input">${_('Permissions')}:</label>
111 </div>
110 </div>
112 <div class="input">
111 <div class="input">
113 <%include file="repo_edit_perms.html"/>
112 <%include file="repo_edit_perms.html"/>
114 </div>
113 </div>
115
114
116 <div class="buttons">
115 <div class="buttons">
117 ${h.submit('save','Save',class_="ui-button")}
116 ${h.submit('save','Save',class_="ui-button")}
118 ${h.reset('reset','Reset',class_="ui-button")}
117 ${h.reset('reset','Reset',class_="ui-button")}
119 </div>
118 </div>
120 </div>
119 </div>
121 </div>
120 </div>
122 </div>
121 </div>
123 ${h.end_form()}
122 ${h.end_form()}
124 <script type="text/javascript">
123 <script type="text/javascript">
125 YAHOO.util.Event.onDOMReady(function(){
124 YAHOO.util.Event.onDOMReady(function(){
126 var D = YAHOO.util.Dom;
125 var D = YAHOO.util.Dom;
127 if(!D.hasClass('perm_new_member_name','error')){
126 if(!D.hasClass('perm_new_member_name','error')){
128 D.setStyle('add_perm_input','display','none');
127 D.setStyle('add_perm_input','display','none');
129 }
128 }
130 YAHOO.util.Event.addListener('add_perm','click',function(){
129 YAHOO.util.Event.addListener('add_perm','click',function(){
131 D.setStyle('add_perm_input','display','');
130 D.setStyle('add_perm_input','display','');
132 D.setStyle('add_perm','opacity','0.6');
131 D.setStyle('add_perm','opacity','0.6');
133 D.setStyle('add_perm','cursor','default');
132 D.setStyle('add_perm','cursor','default');
134 });
133 });
135 });
134 });
136 </script>
135 </script>
137 <script type="text/javascript">
136 <script type="text/javascript">
138 YAHOO.example.FnMultipleFields = function(){
137 YAHOO.example.FnMultipleFields = function(){
139 var myUsers = ${c.users_array|n};
138 var myUsers = ${c.users_array|n};
140 var myGroups = ${c.users_groups_array|n};
139 var myGroups = ${c.users_groups_array|n};
141
140
142 // Define a custom search function for the DataSource of users
141 // Define a custom search function for the DataSource of users
143 var matchUsers = function(sQuery) {
142 var matchUsers = function(sQuery) {
144 // Case insensitive matching
143 // Case insensitive matching
145 var query = sQuery.toLowerCase();
144 var query = sQuery.toLowerCase();
146 var i=0;
145 var i=0;
147 var l=myUsers.length;
146 var l=myUsers.length;
148 var matches = [];
147 var matches = [];
149
148
150 // Match against each name of each contact
149 // Match against each name of each contact
151 for(; i<l; i++) {
150 for(; i<l; i++) {
152 contact = myUsers[i];
151 contact = myUsers[i];
153 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
152 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
154 (contact.lname.toLowerCase().indexOf(query) > -1) ||
153 (contact.lname.toLowerCase().indexOf(query) > -1) ||
155 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
154 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
156 matches[matches.length] = contact;
155 matches[matches.length] = contact;
157 }
156 }
158 }
157 }
159 return matches;
158 return matches;
160 };
159 };
161
160
162 // Define a custom search function for the DataSource of usersGroups
161 // Define a custom search function for the DataSource of usersGroups
163 var matchGroups = function(sQuery) {
162 var matchGroups = function(sQuery) {
164 // Case insensitive matching
163 // Case insensitive matching
165 var query = sQuery.toLowerCase();
164 var query = sQuery.toLowerCase();
166 var i=0;
165 var i=0;
167 var l=myGroups.length;
166 var l=myGroups.length;
168 var matches = [];
167 var matches = [];
169
168
170 // Match against each name of each contact
169 // Match against each name of each contact
171 for(; i<l; i++) {
170 for(; i<l; i++) {
172 matched_group = myGroups[i];
171 matched_group = myGroups[i];
173 if(matched_group.grname.toLowerCase().indexOf(query) > -1) {
172 if(matched_group.grname.toLowerCase().indexOf(query) > -1) {
174 matches[matches.length] = matched_group;
173 matches[matches.length] = matched_group;
175 }
174 }
176 }
175 }
177 return matches;
176 return matches;
178 };
177 };
179
178
180 //match all
179 //match all
181 var matchAll = function(sQuery){
180 var matchAll = function(sQuery){
182 u = matchUsers(sQuery);
181 u = matchUsers(sQuery);
183 g = matchGroups(sQuery);
182 g = matchGroups(sQuery);
184 return u.concat(g);
183 return u.concat(g);
185 };
184 };
186
185
187 // DataScheme for members
186 // DataScheme for members
188 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
187 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
189 memberDS.responseSchema = {
188 memberDS.responseSchema = {
190 fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
189 fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
191 };
190 };
192
191
193 // DataScheme for owner
192 // DataScheme for owner
194 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
193 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
195 ownerDS.responseSchema = {
194 ownerDS.responseSchema = {
196 fields: ["id", "fname", "lname", "nname"]
195 fields: ["id", "fname", "lname", "nname"]
197 };
196 };
198
197
199 // Instantiate AutoComplete for perms
198 // Instantiate AutoComplete for perms
200 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
199 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
201 membersAC.useShadow = false;
200 membersAC.useShadow = false;
202 membersAC.resultTypeList = false;
201 membersAC.resultTypeList = false;
203
202
204 // Instantiate AutoComplete for owner
203 // Instantiate AutoComplete for owner
205 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
204 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
206 ownerAC.useShadow = false;
205 ownerAC.useShadow = false;
207 ownerAC.resultTypeList = false;
206 ownerAC.resultTypeList = false;
208
207
209
208
210 // Helper highlight function for the formatter
209 // Helper highlight function for the formatter
211 var highlightMatch = function(full, snippet, matchindex) {
210 var highlightMatch = function(full, snippet, matchindex) {
212 return full.substring(0, matchindex) +
211 return full.substring(0, matchindex) +
213 "<span class='match'>" +
212 "<span class='match'>" +
214 full.substr(matchindex, snippet.length) +
213 full.substr(matchindex, snippet.length) +
215 "</span>" +
214 "</span>" +
216 full.substring(matchindex + snippet.length);
215 full.substring(matchindex + snippet.length);
217 };
216 };
218
217
219 // Custom formatter to highlight the matching letters
218 // Custom formatter to highlight the matching letters
220 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
219 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
221 var query = sQuery.toLowerCase();
220 var query = sQuery.toLowerCase();
222
221
223 if (oResultData.grname != undefined){
222 if (oResultData.grname != undefined){
224 var grname = oResultData.grname;
223 var grname = oResultData.grname;
225 var grmembers = oResultData.grmembers;
224 var grmembers = oResultData.grmembers;
226 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
225 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
227 var grprefix = "${_('Group')}: ";
226 var grprefix = "${_('Group')}: ";
228 var grsuffix = " ("+grmembers+" ${_('members')})";
227 var grsuffix = " ("+grmembers+" ${_('members')})";
229
228
230 if (grnameMatchIndex > -1){
229 if (grnameMatchIndex > -1){
231 return grprefix+highlightMatch(grname,query,grnameMatchIndex)+grsuffix;
230 return grprefix+highlightMatch(grname,query,grnameMatchIndex)+grsuffix;
232 }
231 }
233
232
234 return grprefix+oResultData.grname+grsuffix;
233 return grprefix+oResultData.grname+grsuffix;
235 }
234 }
236 else if(oResultData.fname != undefined){
235 else if(oResultData.fname != undefined){
237
236
238 var fname = oResultData.fname,
237 var fname = oResultData.fname,
239 lname = oResultData.lname,
238 lname = oResultData.lname,
240 nname = oResultData.nname || "", // Guard against null value
239 nname = oResultData.nname || "", // Guard against null value
241 fnameMatchIndex = fname.toLowerCase().indexOf(query),
240 fnameMatchIndex = fname.toLowerCase().indexOf(query),
242 lnameMatchIndex = lname.toLowerCase().indexOf(query),
241 lnameMatchIndex = lname.toLowerCase().indexOf(query),
243 nnameMatchIndex = nname.toLowerCase().indexOf(query),
242 nnameMatchIndex = nname.toLowerCase().indexOf(query),
244 displayfname, displaylname, displaynname;
243 displayfname, displaylname, displaynname;
245
244
246 if(fnameMatchIndex > -1) {
245 if(fnameMatchIndex > -1) {
247 displayfname = highlightMatch(fname, query, fnameMatchIndex);
246 displayfname = highlightMatch(fname, query, fnameMatchIndex);
248 }
247 }
249 else {
248 else {
250 displayfname = fname;
249 displayfname = fname;
251 }
250 }
252
251
253 if(lnameMatchIndex > -1) {
252 if(lnameMatchIndex > -1) {
254 displaylname = highlightMatch(lname, query, lnameMatchIndex);
253 displaylname = highlightMatch(lname, query, lnameMatchIndex);
255 }
254 }
256 else {
255 else {
257 displaylname = lname;
256 displaylname = lname;
258 }
257 }
259
258
260 if(nnameMatchIndex > -1) {
259 if(nnameMatchIndex > -1) {
261 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
260 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
262 }
261 }
263 else {
262 else {
264 displaynname = nname ? "(" + nname + ")" : "";
263 displaynname = nname ? "(" + nname + ")" : "";
265 }
264 }
266
265
267 return displayfname + " " + displaylname + " " + displaynname;
266 return displayfname + " " + displaylname + " " + displaynname;
268 }
267 }
269 else{
268 else{
270 return '';
269 return '';
271 }
270 }
272 };
271 };
273 membersAC.formatResult = custom_formatter;
272 membersAC.formatResult = custom_formatter;
274 ownerAC.formatResult = custom_formatter;
273 ownerAC.formatResult = custom_formatter;
275
274
276 var myHandler = function(sType, aArgs) {
275 var myHandler = function(sType, aArgs) {
277
276
278 var myAC = aArgs[0]; // reference back to the AC instance
277 var myAC = aArgs[0]; // reference back to the AC instance
279 var elLI = aArgs[1]; // reference to the selected LI element
278 var elLI = aArgs[1]; // reference to the selected LI element
280 var oData = aArgs[2]; // object literal of selected item's result data
279 var oData = aArgs[2]; // object literal of selected item's result data
281
280
282 //fill the autocomplete with value
281 //fill the autocomplete with value
283 if(oData.nname != undefined){
282 if(oData.nname != undefined){
284 //users
283 //users
285 myAC.getInputEl().value = oData.nname;
284 myAC.getInputEl().value = oData.nname;
286 YUD.get('perm_new_member_type').value = 'user';
285 YUD.get('perm_new_member_type').value = 'user';
287 }
286 }
288 else{
287 else{
289 //groups
288 //groups
290 myAC.getInputEl().value = oData.grname;
289 myAC.getInputEl().value = oData.grname;
291 YUD.get('perm_new_member_type').value = 'users_group';
290 YUD.get('perm_new_member_type').value = 'users_group';
292 }
291 }
293
292
294 };
293 };
295
294
296 membersAC.itemSelectEvent.subscribe(myHandler);
295 membersAC.itemSelectEvent.subscribe(myHandler);
297 ownerAC.itemSelectEvent.subscribe(myHandler);
296 ownerAC.itemSelectEvent.subscribe(myHandler);
298
297
299 return {
298 return {
300 memberDS: memberDS,
299 memberDS: memberDS,
301 ownerDS: ownerDS,
300 ownerDS: ownerDS,
302 membersAC: membersAC,
301 membersAC: membersAC,
303 ownerAC: ownerAC,
302 ownerAC: ownerAC,
304 };
303 };
305 }();
304 }();
306
305
307 </script>
306 </script>
308
307
309 </div>
308 </div>
310
309
311 <div class="box box-right">
310 <div class="box box-right">
312 <div class="title">
311 <div class="title">
313 <h5>${_('Administration')}</h5>
312 <h5>${_('Administration')}</h5>
314 </div>
313 </div>
315
314
316 <h3>${_('Statistics')}</h3>
315 <h3>${_('Statistics')}</h3>
317 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
316 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
318 <div class="form">
317 <div class="form">
319 <div class="fields">
318 <div class="fields">
320 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
319 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
321 <div class="field" style="border:none">
320 <div class="field" style="border:none">
322 <ul>
321 <ul>
323 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
322 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
324 <li>${_('Percentage of stats gathered')}: ${c.stats_percentage} %</li>
323 <li>${_('Percentage of stats gathered')}: ${c.stats_percentage} %</li>
325 </ul>
324 </ul>
326 </div>
325 </div>
327
326
328 </div>
327 </div>
329 </div>
328 </div>
330 ${h.end_form()}
329 ${h.end_form()}
331
330
332 %if c.repo_info.clone_uri:
331 %if c.repo_info.clone_uri:
333 <h3>${_('Remote')}</h3>
332 <h3>${_('Remote')}</h3>
334 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
333 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
335 <div class="form">
334 <div class="form">
336 <div class="fields">
335 <div class="fields">
337 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="pull_icon action_button",onclick="return confirm('Confirm to pull changes from remote side');")}
336 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="pull_icon action_button",onclick="return confirm('Confirm to pull changes from remote side');")}
338 <div class="field" style="border:none">
337 <div class="field" style="border:none">
339 <ul>
338 <ul>
340 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
339 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
341 </ul>
340 </ul>
342 </div>
341 </div>
343 </div>
342 </div>
344 </div>
343 </div>
345 ${h.end_form()}
344 ${h.end_form()}
346 %endif
345 %endif
347
346
348 <h3>${_('Cache')}</h3>
347 <h3>${_('Cache')}</h3>
349 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
348 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
350 <div class="form">
349 <div class="form">
351 <div class="fields">
350 <div class="fields">
352 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="refresh_icon action_button",onclick="return confirm('Confirm to invalidate repository cache');")}
351 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="refresh_icon action_button",onclick="return confirm('Confirm to invalidate repository cache');")}
353 </div>
352 </div>
354 </div>
353 </div>
355 ${h.end_form()}
354 ${h.end_form()}
356
355
357 <h3>${_('Public journal')}</h3>
356 <h3>${_('Public journal')}</h3>
358 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
357 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
359 <div class="form">
358 <div class="form">
360 <div class="fields">
359 <div class="fields">
361 ${h.hidden('auth_token',str(h.get_token()))}
360 ${h.hidden('auth_token',str(h.get_token()))}
362 %if c.in_public_journal:
361 %if c.in_public_journal:
363 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="stop_following_icon action_button")}
362 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="stop_following_icon action_button")}
364 %else:
363 %else:
365 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="start_following_icon action_button")}
364 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="start_following_icon action_button")}
366 %endif
365 %endif
367 </div>
366 </div>
368 </div>
367 </div>
369 ${h.end_form()}
368 ${h.end_form()}
370
369
371 <h3>${_('Delete')}</h3>
370 <h3>${_('Delete')}</h3>
372 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
371 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
373 <div class="form">
372 <div class="form">
374 <div class="fields">
373 <div class="fields">
375 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
374 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
376 </div>
375 </div>
377 </div>
376 </div>
378 ${h.end_form()}
377 ${h.end_form()}
379
378
380 </div>
379 </div>
381
380
382
381
383 </%def> No newline at end of file
382 </%def>
@@ -1,400 +1,401 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <!-- HEADER -->
4 <!-- HEADER -->
5 <div id="header">
5 <div id="header">
6 <!-- user -->
6 <!-- user -->
7 <ul id="logged-user">
7 <ul id="logged-user">
8 <li class="first">
8 <li class="first">
9
9
10 <div id="quick_login" style="display:none">
10 <div id="quick_login" style="display:none">
11 ${h.form(h.url('login_home',came_from=h.url.current()))}
11 ${h.form(h.url('login_home',came_from=h.url.current()))}
12 <div class="form">
12 <div class="form">
13 <div class="fields">
13 <div class="fields">
14 <div class="field">
14 <div class="field">
15 <div class="label">
15 <div class="label">
16 <label for="username">${_('Username')}:</label>
16 <label for="username">${_('Username')}:</label>
17 </div>
17 </div>
18 <div class="input">
18 <div class="input">
19 ${h.text('username',class_='focus',size=40)}
19 ${h.text('username',class_='focus',size=40)}
20 </div>
20 </div>
21
21
22 </div>
22 </div>
23 <div class="field">
23 <div class="field">
24 <div class="label">
24 <div class="label">
25 <label for="password">${_('Password')}:</label>
25 <label for="password">${_('Password')}:</label>
26 </div>
26 </div>
27 <div class="input">
27 <div class="input">
28 ${h.password('password',class_='focus',size=40)}
28 ${h.password('password',class_='focus',size=40)}
29 </div>
29 </div>
30
30
31 </div>
31 </div>
32 <div class="buttons">
32 <div class="buttons">
33 ${h.submit('sign_in','Sign In',class_="ui-button")}
33 ${h.submit('sign_in','Sign In',class_="ui-button")}
34 </div>
34 </div>
35 </div>
35 </div>
36 </div>
36 </div>
37 ${h.end_form()}
37 ${h.end_form()}
38 <script type="text/javascript">
38 <script type="text/javascript">
39 YUE.on('quick_login_link','click',function(e){
39 YUE.on('quick_login_link','click',function(e){
40
40
41 if(YUD.hasClass('quick_login_link','enabled')){
41 if(YUD.hasClass('quick_login_link','enabled')){
42 YUD.setStyle('quick_login','display','none');
42 YUD.setStyle('quick_login','display','none');
43 YUD.removeClass('quick_login_link','enabled');
43 YUD.removeClass('quick_login_link','enabled');
44 }
44 }
45 else{
45 else{
46 YUD.setStyle('quick_login','display','');
46 YUD.setStyle('quick_login','display','');
47 YUD.addClass('quick_login_link','enabled');
47 YUD.addClass('quick_login_link','enabled');
48 YUD.get('username').focus();
48 YUD.get('username').focus();
49 }
49 }
50 //make sure we don't redirect
50 //make sure we don't redirect
51 YUE.preventDefault(e);
51 YUE.preventDefault(e);
52 });
52 });
53
53
54 </script>
54 </script>
55 </div>
55 </div>
56
56
57 <div class="gravatar">
57 <div class="gravatar">
58 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
58 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
59 </div>
59 </div>
60 <div class="account">
60 <div class="account">
61 %if c.rhodecode_user.username == 'default':
61 %if c.rhodecode_user.username == 'default':
62 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
62 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
63 %else:
63 %else:
64 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
64 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
65 %endif
65 %endif
66 </div>
66 </div>
67 </li>
67 </li>
68 <li>
68 <li>
69 <a href="${h.url('home')}">${_('Home')}</a>
69 <a href="${h.url('home')}">${_('Home')}</a>
70 </li>
70 </li>
71 %if c.rhodecode_user.username != 'default':
71 %if c.rhodecode_user.username != 'default':
72 <li>
72 <li>
73 <a href="${h.url('journal')}">${_('Journal')}</a>
73 <a href="${h.url('journal')}">${_('Journal')}</a>
74 ##(${c.unread_journal}
74 ##(${c.unread_journal}
75 </li>
75 </li>
76 %endif
76 %endif
77 %if c.rhodecode_user.username == 'default':
77 %if c.rhodecode_user.username == 'default':
78 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'),id='quick_login_link')}</li>
78 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'),id='quick_login_link')}</li>
79 %else:
79 %else:
80 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
80 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
81 %endif
81 %endif
82 </ul>
82 </ul>
83 <!-- end user -->
83 <!-- end user -->
84 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
84 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
85 <div id="logo">
85 <div id="logo">
86 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
86 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
87 </div>
87 </div>
88 <!-- MENU -->
88 <!-- MENU -->
89 ${self.page_nav()}
89 ${self.page_nav()}
90 <!-- END MENU -->
90 <!-- END MENU -->
91 ${self.body()}
91 ${self.body()}
92 </div>
92 </div>
93 </div>
93 </div>
94 <!-- END HEADER -->
94 <!-- END HEADER -->
95
95
96 <!-- CONTENT -->
96 <!-- CONTENT -->
97 <div id="content">
97 <div id="content">
98 <div class="flash_msg">
98 <div class="flash_msg">
99 <% messages = h.flash.pop_messages() %>
99 <% messages = h.flash.pop_messages() %>
100 % if messages:
100 % if messages:
101 <ul id="flash-messages">
101 <ul id="flash-messages">
102 % for message in messages:
102 % for message in messages:
103 <li class="${message.category}_msg">${message}</li>
103 <li class="${message.category}_msg">${message}</li>
104 % endfor
104 % endfor
105 </ul>
105 </ul>
106 % endif
106 % endif
107 </div>
107 </div>
108 <div id="main">
108 <div id="main">
109 ${next.main()}
109 ${next.main()}
110 </div>
110 </div>
111 </div>
111 </div>
112 <!-- END CONTENT -->
112 <!-- END CONTENT -->
113
113
114 <!-- FOOTER -->
114 <!-- FOOTER -->
115 <div id="footer">
115 <div id="footer">
116 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
116 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
117 <div>
117 <div>
118 <p class="footer-link">
118 <p class="footer-link">
119 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
119 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
120 </p>
120 </p>
121 <p class="footer-link-right">
121 <p class="footer-link-right">
122 <a href="${h.url('rhodecode_official')}">RhodeCode</a>
122 <a href="${h.url('rhodecode_official')}">RhodeCode</a>
123 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
123 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
124 </p>
124 </p>
125 </div>
125 </div>
126 </div>
126 </div>
127 <script type="text/javascript">
127 <script type="text/javascript">
128 function tooltip_activate(){
128 function tooltip_activate(){
129 ${h.tooltip.activate()}
129 ${h.tooltip.activate()}
130 }
130 }
131 tooltip_activate();
131 tooltip_activate();
132 </script>
132 </script>
133 </div>
133 </div>
134 <!-- END FOOTER -->
134 <!-- END FOOTER -->
135
135
136 ### MAKO DEFS ###
136 ### MAKO DEFS ###
137 <%def name="page_nav()">
137 <%def name="page_nav()">
138 ${self.menu()}
138 ${self.menu()}
139 </%def>
139 </%def>
140
140
141 <%def name="breadcrumbs()">
141 <%def name="breadcrumbs()">
142 <div class="breadcrumbs">
142 <div class="breadcrumbs">
143 ${self.breadcrumbs_links()}
143 ${self.breadcrumbs_links()}
144 </div>
144 </div>
145 </%def>
145 </%def>
146
146
147
147
148 <%def name="menu(current=None)">
148 <%def name="menu(current=None)">
149 <%
149 <%
150 def is_current(selected):
150 def is_current(selected):
151 if selected == current:
151 if selected == current:
152 return h.literal('class="current"')
152 return h.literal('class="current"')
153 %>
153 %>
154 %if current not in ['home','admin']:
154 %if current not in ['home','admin']:
155 ##REGULAR MENU
155 ##REGULAR MENU
156 <ul id="quick">
156 <ul id="quick">
157 <!-- repo switcher -->
157 <!-- repo switcher -->
158 <li>
158 <li>
159 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
159 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
160 <span class="icon">
160 <span class="icon">
161 <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
161 <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
162 </span>
162 </span>
163 <span>&darr;</span>
163 <span>&darr;</span>
164 </a>
164 </a>
165 <ul id="repo_switcher_list" class="repo_switcher">
165 <ul id="repo_switcher_list" class="repo_switcher">
166 <li>
166 <li>
167 <a href="#">${_('loading...')}</a>
167 <a href="#">${_('loading...')}</a>
168 </li>
168 </li>
169 </ul>
169 </ul>
170 <script type="text/javascript">
170 <script type="text/javascript">
171 YUE.on('repo_switcher','mouseover',function(){
171 YUE.on('repo_switcher','mouseover',function(){
172 function qfilter(){
172 function qfilter(){
173 var S = YAHOO.util.Selector;
173 var S = YAHOO.util.Selector;
174
174
175 var q_filter = YUD.get('q_filter_rs');
175 var q_filter = YUD.get('q_filter_rs');
176 var F = YAHOO.namespace('q_filter_rs');
176 var F = YAHOO.namespace('q_filter_rs');
177
177
178 YUE.on(q_filter,'click',function(){
178 YUE.on(q_filter,'click',function(){
179 q_filter.value = '';
179 q_filter.value = '';
180 });
180 });
181
181
182 F.filterTimeout = null;
182 F.filterTimeout = null;
183
183
184 F.updateFilter = function() {
184 F.updateFilter = function() {
185 // Reset timeout
185 // Reset timeout
186 F.filterTimeout = null;
186 F.filterTimeout = null;
187
187
188 var obsolete = [];
188 var obsolete = [];
189 var nodes = S.query('ul#repo_switcher_list li a.repo_name');
189 var nodes = S.query('ul#repo_switcher_list li a.repo_name');
190 var req = YUD.get('q_filter_rs').value;
190 var req = YUD.get('q_filter_rs').value;
191 for (n in nodes){
191 for (n in nodes){
192 YUD.setStyle(nodes[n].parentNode,'display','')
192 YUD.setStyle(nodes[n].parentNode,'display','')
193 }
193 }
194 if (req){
194 if (req){
195 for (n in nodes){
195 for (n in nodes){
196 console.log(n);
196 console.log(n);
197 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
197 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
198 obsolete.push(nodes[n]);
198 obsolete.push(nodes[n]);
199 }
199 }
200 }
200 }
201 if(obsolete){
201 if(obsolete){
202 for (n in obsolete){
202 for (n in obsolete){
203 YUD.setStyle(obsolete[n].parentNode,'display','none');
203 YUD.setStyle(obsolete[n].parentNode,'display','none');
204 }
204 }
205 }
205 }
206 }
206 }
207 }
207 }
208
208
209 YUE.on(q_filter,'keyup',function(e){
209 YUE.on(q_filter,'keyup',function(e){
210 clearTimeout(F.filterTimeout);
210 clearTimeout(F.filterTimeout);
211 setTimeout(F.updateFilter,600);
211 setTimeout(F.updateFilter,600);
212 });
212 });
213 }
213 }
214 var loaded = YUD.hasClass('repo_switcher','loaded');
214 var loaded = YUD.hasClass('repo_switcher','loaded');
215 if(!loaded){
215 if(!loaded){
216 YUD.addClass('repo_switcher','loaded');
216 YUD.addClass('repo_switcher','loaded');
217 YAHOO.util.Connect.asyncRequest('GET',"${h.url('repo_switcher')}",{
217 YAHOO.util.Connect.asyncRequest('GET',"${h.url('repo_switcher')}",{
218 success:function(o){
218 success:function(o){
219 YUD.get('repo_switcher_list').innerHTML = o.responseText;
219 YUD.get('repo_switcher_list').innerHTML = o.responseText;
220 qfilter();
220 qfilter();
221 },
221 },
222 failure:function(o){
222 failure:function(o){
223 YUD.removeClass('repo_switcher','loaded');
223 YUD.removeClass('repo_switcher','loaded');
224 }
224 }
225 },null);
225 },null);
226 }
226 }
227 return false;
227 return false;
228 });
228 });
229 </script>
229 </script>
230 </li>
230 </li>
231
231
232 <li ${is_current('summary')}>
232 <li ${is_current('summary')}>
233 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
233 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
234 <span class="icon">
234 <span class="icon">
235 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
235 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
236 </span>
236 </span>
237 <span>${_('Summary')}</span>
237 <span>${_('Summary')}</span>
238 </a>
238 </a>
239 </li>
239 </li>
240 ##<li ${is_current('shortlog')}>
240 ##<li ${is_current('shortlog')}>
241 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
241 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
242 ## <span class="icon">
242 ## <span class="icon">
243 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
243 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
244 ## </span>
244 ## </span>
245 ## <span>${_('Shortlog')}</span>
245 ## <span>${_('Shortlog')}</span>
246 ## </a>
246 ## </a>
247 ##</li>
247 ##</li>
248 <li ${is_current('changelog')}>
248 <li ${is_current('changelog')}>
249 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
249 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
250 <span class="icon">
250 <span class="icon">
251 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
251 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
252 </span>
252 </span>
253 <span>${_('Changelog')}</span>
253 <span>${_('Changelog')}</span>
254 </a>
254 </a>
255 </li>
255 </li>
256
256
257 <li ${is_current('switch_to')}>
257 <li ${is_current('switch_to')}>
258 <a title="${_('Switch to')}" href="#">
258 <a title="${_('Switch to')}" href="#">
259 <span class="icon">
259 <span class="icon">
260 <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
260 <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
261 </span>
261 </span>
262 <span>${_('Switch to')}</span>
262 <span>${_('Switch to')}</span>
263 </a>
263 </a>
264 <ul>
264 <ul>
265 <li>
265 <li>
266 ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
266 ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
267 <ul>
267 <ul>
268 %if c.rhodecode_repo.branches.values():
268 %if c.rhodecode_repo.branches.values():
269 %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
269 %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
270 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
270 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
271 %endfor
271 %endfor
272 %else:
272 %else:
273 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
273 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
274 %endif
274 %endif
275 </ul>
275 </ul>
276 </li>
276 </li>
277 <li>
277 <li>
278 ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
278 ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
279 <ul>
279 <ul>
280 %if c.rhodecode_repo.tags.values():
280 %if c.rhodecode_repo.tags.values():
281 %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
281 %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
282 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
282 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
283 %endfor
283 %endfor
284 %else:
284 %else:
285 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
285 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
286 %endif
286 %endif
287 </ul>
287 </ul>
288 </li>
288 </li>
289 </ul>
289 </ul>
290 </li>
290 </li>
291 <li ${is_current('files')}>
291 <li ${is_current('files')}>
292 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
292 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
293 <span class="icon">
293 <span class="icon">
294 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
294 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
295 </span>
295 </span>
296 <span>${_('Files')}</span>
296 <span>${_('Files')}</span>
297 </a>
297 </a>
298 </li>
298 </li>
299
299
300 <li ${is_current('options')}>
300 <li ${is_current('options')}>
301 <a title="${_('Options')}" href="#">
301 <a title="${_('Options')}" href="#">
302 <span class="icon">
302 <span class="icon">
303 <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
303 <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
304 </span>
304 </span>
305 <span>${_('Options')}</span>
305 <span>${_('Options')}</span>
306 </a>
306 </a>
307 <ul>
307 <ul>
308 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
308 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
309 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
309 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
310 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
310 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
311 %else:
311 %else:
312 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
312 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
313 %endif
313 %endif
314 %endif
314 %endif
315 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
315 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
316 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
316 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
317
317
318 % if h.HasPermissionAll('hg.admin')('access admin main page'):
318 % if h.HasPermissionAll('hg.admin')('access admin main page'):
319 <li>
319 <li>
320 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
320 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
321 <%def name="admin_menu()">
321 <%def name="admin_menu()">
322 <ul>
322 <ul>
323 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
323 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
324 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
324 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
325 <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
325 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
326 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
326 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
327 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
327 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
328 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
328 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
329 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
329 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
330 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
330 </ul>
331 </ul>
331 </%def>
332 </%def>
332
333
333 ${admin_menu()}
334 ${admin_menu()}
334 </li>
335 </li>
335 % endif
336 % endif
336 </ul>
337 </ul>
337 </li>
338 </li>
338
339
339 <li>
340 <li>
340 <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
341 <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
341 <span class="icon_short">
342 <span class="icon_short">
342 <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
343 <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
343 </span>
344 </span>
344 <span id="current_followers_count" class="short">${c.repository_followers}</span>
345 <span id="current_followers_count" class="short">${c.repository_followers}</span>
345 </a>
346 </a>
346 </li>
347 </li>
347 <li>
348 <li>
348 <a title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
349 <a title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
349 <span class="icon_short">
350 <span class="icon_short">
350 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
351 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
351 </span>
352 </span>
352 <span class="short">${c.repository_forks}</span>
353 <span class="short">${c.repository_forks}</span>
353 </a>
354 </a>
354 </li>
355 </li>
355
356
356 </ul>
357 </ul>
357 %else:
358 %else:
358 ##ROOT MENU
359 ##ROOT MENU
359 <ul id="quick">
360 <ul id="quick">
360 <li>
361 <li>
361 <a title="${_('Home')}" href="${h.url('home')}">
362 <a title="${_('Home')}" href="${h.url('home')}">
362 <span class="icon">
363 <span class="icon">
363 <img src="${h.url('/images/icons/home_16.png')}" alt="${_('Home')}" />
364 <img src="${h.url('/images/icons/home_16.png')}" alt="${_('Home')}" />
364 </span>
365 </span>
365 <span>${_('Home')}</span>
366 <span>${_('Home')}</span>
366 </a>
367 </a>
367 </li>
368 </li>
368 % if c.rhodecode_user.username != 'default':
369 % if c.rhodecode_user.username != 'default':
369 <li>
370 <li>
370 <a title="${_('Journal')}" href="${h.url('journal')}">
371 <a title="${_('Journal')}" href="${h.url('journal')}">
371 <span class="icon">
372 <span class="icon">
372 <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
373 <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
373 </span>
374 </span>
374 <span>${_('Journal')}</span>
375 <span>${_('Journal')}</span>
375 </a>
376 </a>
376 </li>
377 </li>
377 % endif
378 % endif
378 <li>
379 <li>
379 <a title="${_('Search')}" href="${h.url('search')}">
380 <a title="${_('Search')}" href="${h.url('search')}">
380 <span class="icon">
381 <span class="icon">
381 <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
382 <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
382 </span>
383 </span>
383 <span>${_('Search')}</span>
384 <span>${_('Search')}</span>
384 </a>
385 </a>
385 </li>
386 </li>
386
387
387 %if h.HasPermissionAll('hg.admin')('access admin main page'):
388 %if h.HasPermissionAll('hg.admin')('access admin main page'):
388 <li ${is_current('admin')}>
389 <li ${is_current('admin')}>
389 <a title="${_('Admin')}" href="${h.url('admin_home')}">
390 <a title="${_('Admin')}" href="${h.url('admin_home')}">
390 <span class="icon">
391 <span class="icon">
391 <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
392 <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
392 </span>
393 </span>
393 <span>${_('Admin')}</span>
394 <span>${_('Admin')}</span>
394 </a>
395 </a>
395 ${admin_menu()}
396 ${admin_menu()}
396 </li>
397 </li>
397 %endif
398 %endif
398 </ul>
399 </ul>
399 %endif
400 %endif
400 </%def> No newline at end of file
401 </%def>
General Comments 0
You need to be logged in to leave comments. Login now