##// END OF EJS Templates
#109, added manual pull of changes for repositories that have remote location filled in....
marcink -
r1114:4de3fa62 beta
parent child Browse files
Show More
@@ -1,232 +1,236 b''
1 1 """
2 2 Routes configuration
3 3
4 4 The more specific and detailed routes should be defined first so they
5 5 may take precedent over the more generic routes. For more information
6 6 refer to the routes manual at http://routes.groovie.org/docs/
7 7 """
8 8 from __future__ import with_statement
9 9 from routes import Mapper
10 10 from rhodecode.lib.utils import check_repo_fast as cr
11 11
12 12 def make_map(config):
13 13 """Create, configure and return the routes Mapper"""
14 14 routes_map = Mapper(directory=config['pylons.paths']['controllers'],
15 15 always_scan=config['debug'])
16 16 routes_map.minimization = False
17 17 routes_map.explicit = False
18 18
19 19 def check_repo(environ, match_dict):
20 20 """
21 21 check for valid repository for proper 404 handling
22 22
23 23 :param environ:
24 24 :param match_dict:
25 25 """
26 26 repo_name = match_dict.get('repo_name')
27 27 return not cr(repo_name, config['base_path'])
28 28
29 29 # The ErrorController route (handles 404/500 error pages); it should
30 30 # likely stay at the top, ensuring it can always be resolved
31 31 routes_map.connect('/error/{action}', controller='error')
32 32 routes_map.connect('/error/{action}/{id}', controller='error')
33 33
34 34 #==========================================================================
35 35 # CUSTOM ROUTES HERE
36 36 #==========================================================================
37 37
38 38 #MAIN PAGE
39 39 routes_map.connect('home', '/', controller='home', action='index')
40 40 routes_map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
41 41 routes_map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
42 42 #ADMIN REPOSITORY REST ROUTES
43 43 with routes_map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
44 44 m.connect("repos", "/repos",
45 45 action="create", conditions=dict(method=["POST"]))
46 46 m.connect("repos", "/repos",
47 47 action="index", conditions=dict(method=["GET"]))
48 48 m.connect("formatted_repos", "/repos.{format}",
49 49 action="index",
50 50 conditions=dict(method=["GET"]))
51 51 m.connect("new_repo", "/repos/new",
52 52 action="new", conditions=dict(method=["GET"]))
53 53 m.connect("formatted_new_repo", "/repos/new.{format}",
54 54 action="new", conditions=dict(method=["GET"]))
55 55 m.connect("/repos/{repo_name:.*}",
56 56 action="update", conditions=dict(method=["PUT"],
57 57 function=check_repo))
58 58 m.connect("/repos/{repo_name:.*}",
59 59 action="delete", conditions=dict(method=["DELETE"],
60 60 function=check_repo))
61 61 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
62 62 action="edit", conditions=dict(method=["GET"],
63 63 function=check_repo))
64 64 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
65 65 action="edit", conditions=dict(method=["GET"],
66 66 function=check_repo))
67 67 m.connect("repo", "/repos/{repo_name:.*}",
68 68 action="show", conditions=dict(method=["GET"],
69 69 function=check_repo))
70 70 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
71 71 action="show", conditions=dict(method=["GET"],
72 72 function=check_repo))
73 73 #ajax delete repo perm user
74 74 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
75 75 action="delete_perm_user", conditions=dict(method=["DELETE"],
76 76 function=check_repo))
77 77 #ajax delete repo perm users_group
78 78 m.connect('delete_repo_users_group', "/repos_delete_users_group/{repo_name:.*}",
79 79 action="delete_perm_users_group", conditions=dict(method=["DELETE"],
80 80 function=check_repo))
81 81
82 82 #settings actions
83 83 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
84 84 action="repo_stats", conditions=dict(method=["DELETE"],
85 85 function=check_repo))
86 86 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
87 87 action="repo_cache", conditions=dict(method=["DELETE"],
88 88 function=check_repo))
89 89 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
90 90 action="repo_public_journal", conditions=dict(method=["PUT"],
91 91 function=check_repo))
92 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
93 action="repo_pull", conditions=dict(method=["PUT"],
94 function=check_repo))
95
92 96
93 97 #ADMIN USER REST ROUTES
94 98 routes_map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
95 99
96 100 #ADMIN USER REST ROUTES
97 101 routes_map.resource('users_group', 'users_groups', controller='admin/users_groups', path_prefix='/_admin')
98 102
99 103 #ADMIN GROUP REST ROUTES
100 104 routes_map.resource('group', 'groups', controller='admin/groups', path_prefix='/_admin')
101 105
102 106 #ADMIN PERMISSIONS REST ROUTES
103 107 routes_map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
104 108
105 109 ##ADMIN LDAP SETTINGS
106 110 routes_map.connect('ldap_settings', '/_admin/ldap', controller='admin/ldap_settings',
107 111 action='ldap_settings', conditions=dict(method=["POST"]))
108 112 routes_map.connect('ldap_home', '/_admin/ldap', controller='admin/ldap_settings',)
109 113
110 114
111 115 #ADMIN SETTINGS REST ROUTES
112 116 with routes_map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
113 117 m.connect("admin_settings", "/settings",
114 118 action="create", conditions=dict(method=["POST"]))
115 119 m.connect("admin_settings", "/settings",
116 120 action="index", conditions=dict(method=["GET"]))
117 121 m.connect("formatted_admin_settings", "/settings.{format}",
118 122 action="index", conditions=dict(method=["GET"]))
119 123 m.connect("admin_new_setting", "/settings/new",
120 124 action="new", conditions=dict(method=["GET"]))
121 125 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
122 126 action="new", conditions=dict(method=["GET"]))
123 127 m.connect("/settings/{setting_id}",
124 128 action="update", conditions=dict(method=["PUT"]))
125 129 m.connect("/settings/{setting_id}",
126 130 action="delete", conditions=dict(method=["DELETE"]))
127 131 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
128 132 action="edit", conditions=dict(method=["GET"]))
129 133 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
130 134 action="edit", conditions=dict(method=["GET"]))
131 135 m.connect("admin_setting", "/settings/{setting_id}",
132 136 action="show", conditions=dict(method=["GET"]))
133 137 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
134 138 action="show", conditions=dict(method=["GET"]))
135 139 m.connect("admin_settings_my_account", "/my_account",
136 140 action="my_account", conditions=dict(method=["GET"]))
137 141 m.connect("admin_settings_my_account_update", "/my_account_update",
138 142 action="my_account_update", conditions=dict(method=["PUT"]))
139 143 m.connect("admin_settings_create_repository", "/create_repository",
140 144 action="create_repository", conditions=dict(method=["GET"]))
141 145
142 146 #ADMIN MAIN PAGES
143 147 with routes_map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
144 148 m.connect('admin_home', '', action='index')#main page
145 149 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
146 150 action='add_repo')
147 151
148 152
149 153 #USER JOURNAL
150 154 routes_map.connect('journal', '/_admin/journal', controller='journal',)
151 155 routes_map.connect('public_journal', '/_admin/public_journal', controller='journal', action="public_journal")
152 156 routes_map.connect('public_journal_rss', '/_admin/public_journal_rss', controller='journal', action="public_journal_rss")
153 157 routes_map.connect('public_journal_atom', '/_admin/public_journal_atom', controller='journal', action="public_journal_atom")
154 158
155 159 routes_map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
156 160 action='toggle_following', conditions=dict(method=["POST"]))
157 161
158 162
159 163 #SEARCH
160 164 routes_map.connect('search', '/_admin/search', controller='search',)
161 165 routes_map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
162 166
163 167 #LOGIN/LOGOUT/REGISTER/SIGN IN
164 168 routes_map.connect('login_home', '/_admin/login', controller='login')
165 169 routes_map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
166 170 routes_map.connect('register', '/_admin/register', controller='login', action='register')
167 171 routes_map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
168 172
169 173 #FEEDS
170 174 routes_map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
171 175 controller='feed', action='rss',
172 176 conditions=dict(function=check_repo))
173 177 routes_map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
174 178 controller='feed', action='atom',
175 179 conditions=dict(function=check_repo))
176 180
177 181
178 182 #REPOSITORY ROUTES
179 183 routes_map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
180 184 controller='changeset', revision='tip',
181 185 conditions=dict(function=check_repo))
182 186 routes_map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
183 187 controller='changeset', action='raw_changeset', revision='tip',
184 188 conditions=dict(function=check_repo))
185 189 routes_map.connect('summary_home', '/{repo_name:.*}',
186 190 controller='summary', conditions=dict(function=check_repo))
187 191 routes_map.connect('summary_home', '/{repo_name:.*}/summary',
188 192 controller='summary', conditions=dict(function=check_repo))
189 193 routes_map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
190 194 controller='shortlog', conditions=dict(function=check_repo))
191 195 routes_map.connect('branches_home', '/{repo_name:.*}/branches',
192 196 controller='branches', conditions=dict(function=check_repo))
193 197 routes_map.connect('tags_home', '/{repo_name:.*}/tags',
194 198 controller='tags', conditions=dict(function=check_repo))
195 199 routes_map.connect('changelog_home', '/{repo_name:.*}/changelog',
196 200 controller='changelog', conditions=dict(function=check_repo))
197 201 routes_map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
198 202 controller='files', revision='tip', f_path='',
199 203 conditions=dict(function=check_repo))
200 204 routes_map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
201 205 controller='files', action='diff', revision='tip', f_path='',
202 206 conditions=dict(function=check_repo))
203 207 routes_map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
204 208 controller='files', action='rawfile', revision='tip', f_path='',
205 209 conditions=dict(function=check_repo))
206 210 routes_map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
207 211 controller='files', action='raw', revision='tip', f_path='',
208 212 conditions=dict(function=check_repo))
209 213 routes_map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
210 214 controller='files', action='annotate', revision='tip', f_path='',
211 215 conditions=dict(function=check_repo))
212 216 routes_map.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
213 217 controller='files', action='archivefile',
214 218 conditions=dict(function=check_repo))
215 219 routes_map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
216 220 controller='settings', action="delete",
217 221 conditions=dict(method=["DELETE"], function=check_repo))
218 222 routes_map.connect('repo_settings_update', '/{repo_name:.*}/settings',
219 223 controller='settings', action="update",
220 224 conditions=dict(method=["PUT"], function=check_repo))
221 225 routes_map.connect('repo_settings_home', '/{repo_name:.*}/settings',
222 226 controller='settings', action='index',
223 227 conditions=dict(function=check_repo))
224 228
225 229 routes_map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
226 230 controller='settings', action='fork_create',
227 231 conditions=dict(function=check_repo, method=["POST"]))
228 232 routes_map.connect('repo_fork_home', '/{repo_name:.*}/fork',
229 233 controller='settings', action='fork',
230 234 conditions=dict(function=check_repo))
231 235
232 236 return routes_map
@@ -1,395 +1,410 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Admin controller for RhodeCode
7 7
8 8 :created_on: Apr 7, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import logging
29 29 import traceback
30 30 import formencode
31 31 from operator import itemgetter
32 32 from formencode import htmlfill
33 33
34 34 from paste.httpexceptions import HTTPInternalServerError
35 35 from pylons import request, response, session, tmpl_context as c, url
36 36 from pylons.controllers.util import abort, redirect
37 37 from pylons.i18n.translation import _
38 38
39 39 from rhodecode.lib import helpers as h
40 40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
41 41 HasPermissionAnyDecorator
42 42 from rhodecode.lib.base import BaseController, render
43 43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
44 44 from rhodecode.lib.helpers import get_token
45 45 from rhodecode.model.db import User, Repository, UserFollowing, Group
46 46 from rhodecode.model.forms import RepoForm
47 47 from rhodecode.model.scm import ScmModel
48 48 from rhodecode.model.repo import RepoModel
49 49
50 50 log = logging.getLogger(__name__)
51 51
52 52 class ReposController(BaseController):
53 53 """
54 54 REST Controller styled on the Atom Publishing Protocol"""
55 55 # To properly map this controller, ensure your config/routing.py
56 56 # file has a resource setup:
57 57 # map.resource('repo', 'repos')
58 58
59 59 @LoginRequired()
60 60 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
61 61 def __before__(self):
62 62 c.admin_user = session.get('admin_user')
63 63 c.admin_username = session.get('admin_username')
64 64 super(ReposController, self).__before__()
65 65
66 66
67 67
68 68 def __load_data(self, repo_name):
69 69 """
70 70 Load defaults settings for edit, and update
71 71
72 72 :param repo_name:
73 73 """
74 74 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
75 75
76 76 repo_model = RepoModel()
77 77 c.repo_info = repo_model.get_by_repo_name(repo_name)
78 78
79 79 if c.repo_info is None:
80 80 h.flash(_('%s repository is not mapped to db perhaps'
81 81 ' it was created or renamed from the filesystem'
82 82 ' please run the application again'
83 83 ' in order to rescan repositories') % repo_name,
84 84 category='error')
85 85
86 86 return redirect(url('repos'))
87 87
88 88
89 89
90 90 c.repo_groups = [('', '')]
91 91 c.repo_groups.extend([(x.group_id, x.group_name) for x in self.sa.query(Group).all()])
92 92
93 93 c.default_user_id = User.by_username('default').user_id
94 94 c.in_public_journal = self.sa.query(UserFollowing)\
95 95 .filter(UserFollowing.user_id == c.default_user_id)\
96 96 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
97 97
98 98 if c.repo_info.stats:
99 99 last_rev = c.repo_info.stats.stat_on_revision
100 100 else:
101 101 last_rev = 0
102 102 c.stats_revision = last_rev
103 103
104 104 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
105 105
106 106 if last_rev == 0 or c.repo_last_rev == 0:
107 107 c.stats_percentage = 0
108 108 else:
109 109 c.stats_percentage = '%.2f' % ((float((last_rev)) /
110 110 c.repo_last_rev) * 100)
111 111
112 112 c.users_array = repo_model.get_users_js()
113 113 c.users_groups_array = repo_model.get_users_groups_js()
114 114
115 115 defaults = c.repo_info.get_dict()
116 116 group, repo_name = c.repo_info.groups_and_repo
117 117 defaults['repo_name'] = repo_name
118 118 defaults['repo_group'] = getattr(group, 'group_id', None)
119 119 #fill owner
120 120 if c.repo_info.user:
121 121 defaults.update({'user':c.repo_info.user.username})
122 122 else:
123 123 replacement_user = self.sa.query(User)\
124 124 .filter(User.admin == True).first().username
125 125 defaults.update({'user':replacement_user})
126 126
127 127
128 128 #fill repository users
129 129 for p in c.repo_info.repo_to_perm:
130 130 defaults.update({'u_perm_%s' % p.user.username:
131 131 p.permission.permission_name})
132 132
133 133 #fill repository groups
134 134 for p in c.repo_info.users_group_to_perm:
135 135 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
136 136 p.permission.permission_name})
137 137
138 138
139 139 return defaults
140 140
141 141
142 142 @HasPermissionAllDecorator('hg.admin')
143 143 def index(self, format='html'):
144 144 """GET /repos: All items in the collection"""
145 145 # url('repos')
146 146 cached_repo_list = ScmModel().get_repos()
147 147 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
148 148 return render('admin/repos/repos.html')
149 149
150 150 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
151 151 def create(self):
152 152 """
153 153 POST /repos: Create a new item"""
154 154 # url('repos')
155 155 repo_model = RepoModel()
156 156 c.repo_groups = [('', '')]
157 157 c.repo_groups.extend([(x.group_id, x.group_name) for x in self.sa.query(Group).all()])
158 158 form_result = {}
159 159 try:
160 160 form_result = RepoForm()(repo_groups=c.repo_groups).to_python(dict(request.POST))
161 161 repo_model.create(form_result, c.rhodecode_user)
162 162 if form_result['clone_uri']:
163 163 h.flash(_('created repository %s from %s') \
164 164 % (form_result['repo_name'], form_result['clone_uri']),
165 165 category='success')
166 166 else:
167 167 h.flash(_('created repository %s') % form_result['repo_name'],
168 168 category='success')
169 169
170 170 if request.POST.get('user_created'):
171 171 action_logger(self.rhodecode_user, 'user_created_repo',
172 172 form_result['repo_name'], '', self.sa)
173 173 else:
174 174 action_logger(self.rhodecode_user, 'admin_created_repo',
175 175 form_result['repo_name'], '', self.sa)
176 176
177 177 except formencode.Invalid, errors:
178 178
179 179 c.new_repo = errors.value['repo_name']
180 180 c.repo_groups = [('', '')]
181 181 c.repo_groups.extend([(x.group_id, x.group_name) for x in self.sa.query(Group).all()])
182 182
183 183 if request.POST.get('user_created'):
184 184 r = render('admin/repos/repo_add_create_repository.html')
185 185 else:
186 186 r = render('admin/repos/repo_add.html')
187 187
188 188 return htmlfill.render(
189 189 r,
190 190 defaults=errors.value,
191 191 errors=errors.error_dict or {},
192 192 prefix_error=False,
193 193 encoding="UTF-8")
194 194
195 195 except Exception:
196 196 log.error(traceback.format_exc())
197 197 msg = _('error occurred during creation of repository %s') \
198 198 % form_result.get('repo_name')
199 199 h.flash(msg, category='error')
200 200 if request.POST.get('user_created'):
201 201 return redirect(url('home'))
202 202 return redirect(url('repos'))
203 203
204 204 @HasPermissionAllDecorator('hg.admin')
205 205 def new(self, format='html'):
206 206 """GET /repos/new: Form to create a new item"""
207 207 new_repo = request.GET.get('repo', '')
208 208 c.new_repo = repo_name_slug(new_repo)
209 209 c.repo_groups = [('', '')]
210 210 c.repo_groups.extend([(x.group_id, x.group_name) for x in self.sa.query(Group).all()])
211 211 return render('admin/repos/repo_add.html')
212 212
213 213 @HasPermissionAllDecorator('hg.admin')
214 214 def update(self, repo_name):
215 215 """
216 216 PUT /repos/repo_name: Update an existing item"""
217 217 # Forms posted to this method should contain a hidden field:
218 218 # <input type="hidden" name="_method" value="PUT" />
219 219 # Or using helpers:
220 220 # h.form(url('repo', repo_name=ID),
221 221 # method='put')
222 222 # url('repo', repo_name=ID)
223 223 repo_model = RepoModel()
224 224 changed_name = repo_name
225 225 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
226 226 try:
227 227 form_result = _form.to_python(dict(request.POST))
228 228 repo_model.update(repo_name, form_result)
229 229 invalidate_cache('get_repo_cached_%s' % repo_name)
230 230 h.flash(_('Repository %s updated successfully' % repo_name),
231 231 category='success')
232 232 changed_name = form_result['repo_name']
233 233 action_logger(self.rhodecode_user, 'admin_updated_repo',
234 234 changed_name, '', self.sa)
235 235
236 236 except formencode.Invalid, errors:
237 237 defaults = self.__load_data(repo_name)
238 238 defaults.update(errors.value)
239 239 return htmlfill.render(
240 240 render('admin/repos/repo_edit.html'),
241 241 defaults=defaults,
242 242 errors=errors.error_dict or {},
243 243 prefix_error=False,
244 244 encoding="UTF-8")
245 245
246 246 except Exception:
247 247 log.error(traceback.format_exc())
248 248 h.flash(_('error occurred during update of repository %s') \
249 249 % repo_name, category='error')
250 250 return redirect(url('edit_repo', repo_name=changed_name))
251 251
252 252 @HasPermissionAllDecorator('hg.admin')
253 253 def delete(self, repo_name):
254 254 """
255 255 DELETE /repos/repo_name: Delete an existing item"""
256 256 # Forms posted to this method should contain a hidden field:
257 257 # <input type="hidden" name="_method" value="DELETE" />
258 258 # Or using helpers:
259 259 # h.form(url('repo', repo_name=ID),
260 260 # method='delete')
261 261 # url('repo', repo_name=ID)
262 262
263 263 repo_model = RepoModel()
264 264 repo = repo_model.get_by_repo_name(repo_name)
265 265 if not repo:
266 266 h.flash(_('%s repository is not mapped to db perhaps'
267 267 ' it was moved or renamed from the filesystem'
268 268 ' please run the application again'
269 269 ' in order to rescan repositories') % repo_name,
270 270 category='error')
271 271
272 272 return redirect(url('repos'))
273 273 try:
274 274 action_logger(self.rhodecode_user, 'admin_deleted_repo',
275 275 repo_name, '', self.sa)
276 276 repo_model.delete(repo)
277 277 invalidate_cache('get_repo_cached_%s' % repo_name)
278 278 h.flash(_('deleted repository %s') % repo_name, category='success')
279 279
280 280 except Exception, e:
281 281 log.error(traceback.format_exc())
282 282 h.flash(_('An error occurred during deletion of %s') % repo_name,
283 283 category='error')
284 284
285 285 return redirect(url('repos'))
286 286
287 287 @HasPermissionAllDecorator('hg.admin')
288 288 def delete_perm_user(self, repo_name):
289 289 """
290 290 DELETE an existing repository permission user
291 291
292 292 :param repo_name:
293 293 """
294 294
295 295 try:
296 296 repo_model = RepoModel()
297 297 repo_model.delete_perm_user(request.POST, repo_name)
298 298 except Exception, e:
299 299 h.flash(_('An error occurred during deletion of repository user'),
300 300 category='error')
301 301 raise HTTPInternalServerError()
302 302
303 303 @HasPermissionAllDecorator('hg.admin')
304 304 def delete_perm_users_group(self, repo_name):
305 305 """
306 306 DELETE an existing repository permission users group
307 307
308 308 :param repo_name:
309 309 """
310 310 try:
311 311 repo_model = RepoModel()
312 312 repo_model.delete_perm_users_group(request.POST, repo_name)
313 313 except Exception, e:
314 314 h.flash(_('An error occurred during deletion of repository'
315 315 ' users groups'),
316 316 category='error')
317 317 raise HTTPInternalServerError()
318 318
319 319 @HasPermissionAllDecorator('hg.admin')
320 320 def repo_stats(self, repo_name):
321 321 """
322 322 DELETE an existing repository statistics
323 323
324 324 :param repo_name:
325 325 """
326 326
327 327 try:
328 328 repo_model = RepoModel()
329 329 repo_model.delete_stats(repo_name)
330 330 except Exception, e:
331 331 h.flash(_('An error occurred during deletion of repository stats'),
332 332 category='error')
333 333 return redirect(url('edit_repo', repo_name=repo_name))
334 334
335 335 @HasPermissionAllDecorator('hg.admin')
336 336 def repo_cache(self, repo_name):
337 337 """
338 338 INVALIDATE existing repository cache
339 339
340 340 :param repo_name:
341 341 """
342 342
343 343 try:
344 344 ScmModel().mark_for_invalidation(repo_name)
345 345 except Exception, e:
346 346 h.flash(_('An error occurred during cache invalidation'),
347 347 category='error')
348 348 return redirect(url('edit_repo', repo_name=repo_name))
349 349
350 350 @HasPermissionAllDecorator('hg.admin')
351 351 def repo_public_journal(self, repo_name):
352 352 """
353 353 Set's this repository to be visible in public journal,
354 354 in other words assing default user to follow this repo
355 355
356 356 :param repo_name:
357 357 """
358 358
359 359 cur_token = request.POST.get('auth_token')
360 360 token = get_token()
361 361 if cur_token == token:
362 362 try:
363 363 repo_id = Repository.by_repo_name(repo_name).repo_id
364 364 user_id = User.by_username('default').user_id
365 365 self.scm_model.toggle_following_repo(repo_id, user_id)
366 366 h.flash(_('Updated repository visibility in public journal'),
367 367 category='success')
368 368 except:
369 369 h.flash(_('An error occurred during setting this'
370 370 ' repository in public journal'),
371 371 category='error')
372 372
373 373 else:
374 374 h.flash(_('Token mismatch'), category='error')
375 375 return redirect(url('edit_repo', repo_name=repo_name))
376 376
377 @HasPermissionAllDecorator('hg.admin')
378 def repo_pull(self, repo_name):
379 """
380 Runs task to update given repository with remote changes,
381 ie. make pull on remote location
377 382
383 :param repo_name:
384 """
385 try:
386 ScmModel().pull_changes(repo_name, c.rhodecode_user.username)
387 h.flash(_('Pulled from remote location'), category='success')
388 except Exception, e:
389 h.flash(_('An error occurred during pull from remote location'),
390 category='error')
391
392 return redirect(url('edit_repo', repo_name=repo_name))
378 393
379 394 @HasPermissionAllDecorator('hg.admin')
380 395 def show(self, repo_name, format='html'):
381 396 """GET /repos/repo_name: Show a specific item"""
382 397 # url('repo', repo_name=ID)
383 398
384 399 @HasPermissionAllDecorator('hg.admin')
385 400 def edit(self, repo_name, format='html'):
386 401 """GET /repos/repo_name/edit: Form to edit an existing item"""
387 402 # url('edit_repo', repo_name=ID)
388 403 defaults = self.__load_data(repo_name)
389 404
390 405 return htmlfill.render(
391 406 render('admin/repos/repo_edit.html'),
392 407 defaults=defaults,
393 408 encoding="UTF-8",
394 409 force_defaults=False
395 410 )
@@ -1,691 +1,694 b''
1 1 """Helper functions
2 2
3 3 Consists of functions to typically be used within templates, but also
4 4 available to Controllers. This module is available to both as 'h'.
5 5 """
6 6 import random
7 7 import hashlib
8 8 import StringIO
9 9 import urllib
10 10
11 11 from pygments.formatters import HtmlFormatter
12 12 from pygments import highlight as code_highlight
13 13 from pylons import url, request
14 14 from pylons.i18n.translation import _, ungettext
15 15
16 16 from webhelpers.html import literal, HTML, escape
17 17 from webhelpers.html.tools import *
18 18 from webhelpers.html.builder import make_tag
19 19 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
20 20 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
21 21 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
22 22 password, textarea, title, ul, xml_declaration, radio
23 23 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
24 24 mail_to, strip_links, strip_tags, tag_re
25 25 from webhelpers.number import format_byte_size, format_bit_size
26 26 from webhelpers.pylonslib import Flash as _Flash
27 27 from webhelpers.pylonslib.secure_form import secure_form
28 28 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
29 29 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
30 30 replace_whitespace, urlify, truncate, wrap_paragraphs
31 31 from webhelpers.date import time_ago_in_words
32 32 from webhelpers.paginate import Page
33 33 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
34 34 convert_boolean_attrs, NotGiven
35 35
36 36 from vcs.utils.annotate import annotate_highlight
37 37 from rhodecode.lib.utils import repo_name_slug
38 38
39 39 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
40 40 """Reset button
41 41 """
42 42 _set_input_attrs(attrs, type, name, value)
43 43 _set_id_attr(attrs, id, name)
44 44 convert_boolean_attrs(attrs, ["disabled"])
45 45 return HTML.input(**attrs)
46 46
47 47 reset = _reset
48 48
49 49
50 50 def get_token():
51 51 """Return the current authentication token, creating one if one doesn't
52 52 already exist.
53 53 """
54 54 token_key = "_authentication_token"
55 55 from pylons import session
56 56 if not token_key in session:
57 57 try:
58 58 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
59 59 except AttributeError: # Python < 2.4
60 60 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
61 61 session[token_key] = token
62 62 if hasattr(session, 'save'):
63 63 session.save()
64 64 return session[token_key]
65 65
66 66 class _GetError(object):
67 67 """Get error from form_errors, and represent it as span wrapped error
68 68 message
69 69
70 70 :param field_name: field to fetch errors for
71 71 :param form_errors: form errors dict
72 72 """
73 73
74 74 def __call__(self, field_name, form_errors):
75 75 tmpl = """<span class="error_msg">%s</span>"""
76 76 if form_errors and form_errors.has_key(field_name):
77 77 return literal(tmpl % form_errors.get(field_name))
78 78
79 79 get_error = _GetError()
80 80
81 81 class _ToolTip(object):
82 82
83 83 def __call__(self, tooltip_title, trim_at=50):
84 84 """Special function just to wrap our text into nice formatted
85 85 autowrapped text
86 86
87 87 :param tooltip_title:
88 88 """
89 89
90 90 return wrap_paragraphs(escape(tooltip_title), trim_at)\
91 91 .replace('\n', '<br/>')
92 92
93 93 def activate(self):
94 94 """Adds tooltip mechanism to the given Html all tooltips have to have
95 95 set class `tooltip` and set attribute `tooltip_title`.
96 96 Then a tooltip will be generated based on that. All with yui js tooltip
97 97 """
98 98
99 99 js = '''
100 100 YAHOO.util.Event.onDOMReady(function(){
101 101 function toolTipsId(){
102 102 var ids = [];
103 103 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
104 104
105 105 for (var i = 0; i < tts.length; i++) {
106 106 //if element doesn't not have and id autogenerate one for tooltip
107 107
108 108 if (!tts[i].id){
109 109 tts[i].id='tt'+i*100;
110 110 }
111 111 ids.push(tts[i].id);
112 112 }
113 113 return ids
114 114 };
115 115 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
116 116 context: toolTipsId(),
117 117 monitorresize:false,
118 118 xyoffset :[0,0],
119 119 autodismissdelay:300000,
120 120 hidedelay:5,
121 121 showdelay:20,
122 122 });
123 123
124 124 // Set the text for the tooltip just before we display it. Lazy method
125 125 myToolTips.contextTriggerEvent.subscribe(
126 126 function(type, args) {
127 127
128 128 var context = args[0];
129 129
130 130 //positioning of tooltip
131 131 var tt_w = this.element.clientWidth;//tooltip width
132 132 var tt_h = this.element.clientHeight;//tooltip height
133 133
134 134 var context_w = context.offsetWidth;
135 135 var context_h = context.offsetHeight;
136 136
137 137 var pos_x = YAHOO.util.Dom.getX(context);
138 138 var pos_y = YAHOO.util.Dom.getY(context);
139 139
140 140 var display_strategy = 'right';
141 141 var xy_pos = [0,0];
142 142 switch (display_strategy){
143 143
144 144 case 'top':
145 145 var cur_x = (pos_x+context_w/2)-(tt_w/2);
146 146 var cur_y = (pos_y-tt_h-4);
147 147 xy_pos = [cur_x,cur_y];
148 148 break;
149 149 case 'bottom':
150 150 var cur_x = (pos_x+context_w/2)-(tt_w/2);
151 151 var cur_y = pos_y+context_h+4;
152 152 xy_pos = [cur_x,cur_y];
153 153 break;
154 154 case 'left':
155 155 var cur_x = (pos_x-tt_w-4);
156 156 var cur_y = pos_y-((tt_h/2)-context_h/2);
157 157 xy_pos = [cur_x,cur_y];
158 158 break;
159 159 case 'right':
160 160 var cur_x = (pos_x+context_w+4);
161 161 var cur_y = pos_y-((tt_h/2)-context_h/2);
162 162 xy_pos = [cur_x,cur_y];
163 163 break;
164 164 default:
165 165 var cur_x = (pos_x+context_w/2)-(tt_w/2);
166 166 var cur_y = pos_y-tt_h-4;
167 167 xy_pos = [cur_x,cur_y];
168 168 break;
169 169
170 170 }
171 171
172 172 this.cfg.setProperty("xy",xy_pos);
173 173
174 174 });
175 175
176 176 //Mouse out
177 177 myToolTips.contextMouseOutEvent.subscribe(
178 178 function(type, args) {
179 179 var context = args[0];
180 180
181 181 });
182 182 });
183 183 '''
184 184 return literal(js)
185 185
186 186 tooltip = _ToolTip()
187 187
188 188 class _FilesBreadCrumbs(object):
189 189
190 190 def __call__(self, repo_name, rev, paths):
191 191 if isinstance(paths, str):
192 192 paths = paths.decode('utf-8', 'replace')
193 193 url_l = [link_to(repo_name, url('files_home',
194 194 repo_name=repo_name,
195 195 revision=rev, f_path=''))]
196 196 paths_l = paths.split('/')
197 197 for cnt, p in enumerate(paths_l):
198 198 if p != '':
199 199 url_l.append(link_to(p, url('files_home',
200 200 repo_name=repo_name,
201 201 revision=rev,
202 202 f_path='/'.join(paths_l[:cnt + 1]))))
203 203
204 204 return literal('/'.join(url_l))
205 205
206 206 files_breadcrumbs = _FilesBreadCrumbs()
207 207
208 208 class CodeHtmlFormatter(HtmlFormatter):
209 209 """My code Html Formatter for source codes
210 210 """
211 211
212 212 def wrap(self, source, outfile):
213 213 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
214 214
215 215 def _wrap_code(self, source):
216 216 for cnt, it in enumerate(source):
217 217 i, t = it
218 218 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
219 219 yield i, t
220 220
221 221 def _wrap_tablelinenos(self, inner):
222 222 dummyoutfile = StringIO.StringIO()
223 223 lncount = 0
224 224 for t, line in inner:
225 225 if t:
226 226 lncount += 1
227 227 dummyoutfile.write(line)
228 228
229 229 fl = self.linenostart
230 230 mw = len(str(lncount + fl - 1))
231 231 sp = self.linenospecial
232 232 st = self.linenostep
233 233 la = self.lineanchors
234 234 aln = self.anchorlinenos
235 235 nocls = self.noclasses
236 236 if sp:
237 237 lines = []
238 238
239 239 for i in range(fl, fl + lncount):
240 240 if i % st == 0:
241 241 if i % sp == 0:
242 242 if aln:
243 243 lines.append('<a href="#%s%d" class="special">%*d</a>' %
244 244 (la, i, mw, i))
245 245 else:
246 246 lines.append('<span class="special">%*d</span>' % (mw, i))
247 247 else:
248 248 if aln:
249 249 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
250 250 else:
251 251 lines.append('%*d' % (mw, i))
252 252 else:
253 253 lines.append('')
254 254 ls = '\n'.join(lines)
255 255 else:
256 256 lines = []
257 257 for i in range(fl, fl + lncount):
258 258 if i % st == 0:
259 259 if aln:
260 260 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
261 261 else:
262 262 lines.append('%*d' % (mw, i))
263 263 else:
264 264 lines.append('')
265 265 ls = '\n'.join(lines)
266 266
267 267 # in case you wonder about the seemingly redundant <div> here: since the
268 268 # content in the other cell also is wrapped in a div, some browsers in
269 269 # some configurations seem to mess up the formatting...
270 270 if nocls:
271 271 yield 0, ('<table class="%stable">' % self.cssclass +
272 272 '<tr><td><div class="linenodiv" '
273 273 'style="background-color: #f0f0f0; padding-right: 10px">'
274 274 '<pre style="line-height: 125%">' +
275 275 ls + '</pre></div></td><td class="code">')
276 276 else:
277 277 yield 0, ('<table class="%stable">' % self.cssclass +
278 278 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
279 279 ls + '</pre></div></td><td class="code">')
280 280 yield 0, dummyoutfile.getvalue()
281 281 yield 0, '</td></tr></table>'
282 282
283 283
284 284 def pygmentize(filenode, **kwargs):
285 285 """pygmentize function using pygments
286 286
287 287 :param filenode:
288 288 """
289 289
290 290 return literal(code_highlight(filenode.content,
291 291 filenode.lexer, CodeHtmlFormatter(**kwargs)))
292 292
293 293 def pygmentize_annotation(filenode, **kwargs):
294 294 """pygmentize function for annotation
295 295
296 296 :param filenode:
297 297 """
298 298
299 299 color_dict = {}
300 300 def gen_color(n=10000):
301 301 """generator for getting n of evenly distributed colors using
302 302 hsv color and golden ratio. It always return same order of colors
303 303
304 304 :returns: RGB tuple
305 305 """
306 306 import colorsys
307 307 golden_ratio = 0.618033988749895
308 308 h = 0.22717784590367374
309 309
310 310 for c in xrange(n):
311 311 h += golden_ratio
312 312 h %= 1
313 313 HSV_tuple = [h, 0.95, 0.95]
314 314 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
315 315 yield map(lambda x:str(int(x * 256)), RGB_tuple)
316 316
317 317 cgenerator = gen_color()
318 318
319 319 def get_color_string(cs):
320 320 if color_dict.has_key(cs):
321 321 col = color_dict[cs]
322 322 else:
323 323 col = color_dict[cs] = cgenerator.next()
324 324 return "color: rgb(%s)! important;" % (', '.join(col))
325 325
326 326 def url_func(changeset):
327 327 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
328 328 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
329 329
330 330 tooltip_html = tooltip_html % (changeset.author,
331 331 changeset.date,
332 332 tooltip(changeset.message))
333 333 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
334 334 short_id(changeset.raw_id))
335 335 uri = link_to(
336 336 lnk_format,
337 337 url('changeset_home', repo_name=changeset.repository.name,
338 338 revision=changeset.raw_id),
339 339 style=get_color_string(changeset.raw_id),
340 340 class_='tooltip',
341 341 title=tooltip_html
342 342 )
343 343
344 344 uri += '\n'
345 345 return uri
346 346 return literal(annotate_highlight(filenode, url_func, **kwargs))
347 347
348 348 def get_changeset_safe(repo, rev):
349 349 from vcs.backends.base import BaseRepository
350 350 from vcs.exceptions import RepositoryError
351 351 if not isinstance(repo, BaseRepository):
352 352 raise Exception('You must pass an Repository '
353 353 'object as first argument got %s', type(repo))
354 354
355 355 try:
356 356 cs = repo.get_changeset(rev)
357 357 except RepositoryError:
358 358 from rhodecode.lib.utils import EmptyChangeset
359 359 cs = EmptyChangeset()
360 360 return cs
361 361
362 362
363 363 def is_following_repo(repo_name, user_id):
364 364 from rhodecode.model.scm import ScmModel
365 365 return ScmModel().is_following_repo(repo_name, user_id)
366 366
367 367 flash = _Flash()
368 368
369 369
370 370 #==============================================================================
371 371 # MERCURIAL FILTERS available via h.
372 372 #==============================================================================
373 373 from mercurial import util
374 374 from mercurial.templatefilters import person as _person
375 375
376 376 def _age(curdate):
377 377 """turns a datetime into an age string."""
378 378
379 379 if not curdate:
380 380 return ''
381 381
382 382 from datetime import timedelta, datetime
383 383
384 384 agescales = [("year", 3600 * 24 * 365),
385 385 ("month", 3600 * 24 * 30),
386 386 ("day", 3600 * 24),
387 387 ("hour", 3600),
388 388 ("minute", 60),
389 389 ("second", 1), ]
390 390
391 391 age = datetime.now() - curdate
392 392 age_seconds = (age.days * agescales[2][1]) + age.seconds
393 393 pos = 1
394 394 for scale in agescales:
395 395 if scale[1] <= age_seconds:
396 396 if pos == 6:pos = 5
397 397 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
398 398 pos += 1
399 399
400 400 return _('just now')
401 401
402 402 age = lambda x:_age(x)
403 403 capitalize = lambda x: x.capitalize()
404 404 email = util.email
405 405 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
406 406 person = lambda x: _person(x)
407 407 short_id = lambda x: x[:12]
408 408
409 409
410 410 def bool2icon(value):
411 411 """Returns True/False values represented as small html image of true/false
412 412 icons
413 413
414 414 :param value: bool value
415 415 """
416 416
417 417 if value is True:
418 418 return HTML.tag('img', src=url("/images/icons/accept.png"),
419 419 alt=_('True'))
420 420
421 421 if value is False:
422 422 return HTML.tag('img', src=url("/images/icons/cancel.png"),
423 423 alt=_('False'))
424 424
425 425 return value
426 426
427 427
428 428 def action_parser(user_log, feed=False):
429 429 """This helper will action_map the specified string action into translated
430 430 fancy names with icons and links
431 431
432 432 :param user_log: user log instance
433 433 :param feed: use output for feeds (no html and fancy icons)
434 434 """
435 435
436 436 action = user_log.action
437 437 action_params = ' '
438 438
439 439 x = action.split(':')
440 440
441 441 if len(x) > 1:
442 442 action, action_params = x
443 443
444 444 def get_cs_links():
445 445 revs_limit = 5 #display this amount always
446 446 revs_top_limit = 50 #show upto this amount of changesets hidden
447 447 revs = action_params.split(',')
448 448 repo_name = user_log.repository.repo_name
449 449
450 450 from rhodecode.model.scm import ScmModel
451 451 repo, dbrepo = ScmModel().get(repo_name, retval='repo',
452 452 invalidation_list=[])
453 453
454 454 message = lambda rev: get_changeset_safe(repo, rev).message
455 455
456 456 cs_links = " " + ', '.join ([link_to(rev,
457 457 url('changeset_home',
458 458 repo_name=repo_name,
459 459 revision=rev), title=tooltip(message(rev)),
460 460 class_='tooltip') for rev in revs[:revs_limit] ])
461 461
462 462 compare_view = (' <div class="compare_view tooltip" title="%s">'
463 463 '<a href="%s">%s</a> '
464 464 '</div>' % (_('Show all combined changesets %s->%s' \
465 465 % (revs[0], revs[-1])),
466 466 url('changeset_home', repo_name=repo_name,
467 467 revision='%s...%s' % (revs[0], revs[-1])
468 468 ),
469 469 _('compare view'))
470 470 )
471 471
472 472 if len(revs) > revs_limit:
473 473 uniq_id = revs[0]
474 474 html_tmpl = ('<span> %s '
475 475 '<a class="show_more" id="_%s" href="#more">%s</a> '
476 476 '%s</span>')
477 477 if not feed:
478 478 cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
479 479 % (len(revs) - revs_limit),
480 480 _('revisions'))
481 481
482 482 if not feed:
483 483 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
484 484 else:
485 485 html_tmpl = '<span id="%s"> %s </span>'
486 486
487 487 cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
488 488 url('changeset_home',
489 489 repo_name=repo_name, revision=rev),
490 490 title=message(rev), class_='tooltip')
491 491 for rev in revs[revs_limit:revs_top_limit]]))
492 492 if len(revs) > 1:
493 493 cs_links += compare_view
494 494 return cs_links
495 495
496 496 def get_fork_name():
497 497 repo_name = action_params
498 498 return _('fork name ') + str(link_to(action_params, url('summary_home',
499 499 repo_name=repo_name,)))
500 500
501 501 action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
502 502 'user_created_repo':(_('[created] repository'), None),
503 503 'user_forked_repo':(_('[forked] repository'), get_fork_name),
504 504 'user_updated_repo':(_('[updated] repository'), None),
505 505 'admin_deleted_repo':(_('[delete] repository'), None),
506 506 'admin_created_repo':(_('[created] repository'), None),
507 507 'admin_forked_repo':(_('[forked] repository'), None),
508 508 'admin_updated_repo':(_('[updated] repository'), None),
509 509 'push':(_('[pushed] into'), get_cs_links),
510 'push_remote':(_('[pulled from remote] into'), get_cs_links),
510 511 'pull':(_('[pulled] from'), None),
511 512 'started_following_repo':(_('[started following] repository'), None),
512 513 'stopped_following_repo':(_('[stopped following] repository'), None),
513 514 }
514 515
515 516 action_str = action_map.get(action, action)
516 517 if feed:
517 518 action = action_str[0].replace('[', '').replace(']', '')
518 519 else:
519 520 action = action_str[0].replace('[', '<span class="journal_highlight">')\
520 521 .replace(']', '</span>')
522
521 523 action_params_func = lambda :""
522 524
523 if action_str[1] is not None:
525 if callable(action_str[1]):
524 526 action_params_func = action_str[1]
525 527
526 528 return [literal(action), action_params_func]
527 529
528 530 def action_parser_icon(user_log):
529 531 action = user_log.action
530 532 action_params = None
531 533 x = action.split(':')
532 534
533 535 if len(x) > 1:
534 536 action, action_params = x
535 537
536 tmpl = """<img src="%s/%s" alt="%s"/>"""
538 tmpl = """<img src="%s%s" alt="%s"/>"""
537 539 map = {'user_deleted_repo':'database_delete.png',
538 540 'user_created_repo':'database_add.png',
539 541 'user_forked_repo':'arrow_divide.png',
540 542 'user_updated_repo':'database_edit.png',
541 543 'admin_deleted_repo':'database_delete.png',
542 544 'admin_created_repo':'database_add.png',
543 545 'admin_forked_repo':'arrow_divide.png',
544 546 'admin_updated_repo':'database_edit.png',
545 547 'push':'script_add.png',
548 'push_remote':'connect.png',
546 549 'pull':'down_16.png',
547 550 'started_following_repo':'heart_add.png',
548 551 'stopped_following_repo':'heart_delete.png',
549 552 }
550 553 return literal(tmpl % ((url('/images/icons/')),
551 554 map.get(action, action), action))
552 555
553 556
554 557 #==============================================================================
555 558 # PERMS
556 559 #==============================================================================
557 560 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
558 561 HasRepoPermissionAny, HasRepoPermissionAll
559 562
560 563 #==============================================================================
561 564 # GRAVATAR URL
562 565 #==============================================================================
563 566
564 567 def gravatar_url(email_address, size=30):
565 568 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
566 569 default = 'identicon'
567 570 baseurl_nossl = "http://www.gravatar.com/avatar/"
568 571 baseurl_ssl = "https://secure.gravatar.com/avatar/"
569 572 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
570 573
571 574 if isinstance(email_address, unicode):
572 575 #hashlib crashes on unicode items
573 576 email_address = email_address.encode('utf8', 'replace')
574 577 # construct the url
575 578 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
576 579 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
577 580
578 581 return gravatar_url
579 582
580 583
581 584 #==============================================================================
582 585 # REPO PAGER
583 586 #==============================================================================
584 587 class RepoPage(Page):
585 588
586 589 def __init__(self, collection, page=1, items_per_page=20,
587 590 item_count=None, url=None, branch_name=None, **kwargs):
588 591
589 592 """Create a "RepoPage" instance. special pager for paging
590 593 repository
591 594 """
592 595 self._url_generator = url
593 596
594 597 # Safe the kwargs class-wide so they can be used in the pager() method
595 598 self.kwargs = kwargs
596 599
597 600 # Save a reference to the collection
598 601 self.original_collection = collection
599 602
600 603 self.collection = collection
601 604
602 605 # The self.page is the number of the current page.
603 606 # The first page has the number 1!
604 607 try:
605 608 self.page = int(page) # make it int() if we get it as a string
606 609 except (ValueError, TypeError):
607 610 self.page = 1
608 611
609 612 self.items_per_page = items_per_page
610 613
611 614 # Unless the user tells us how many items the collections has
612 615 # we calculate that ourselves.
613 616 if item_count is not None:
614 617 self.item_count = item_count
615 618 else:
616 619 self.item_count = len(self.collection)
617 620
618 621 # Compute the number of the first and last available page
619 622 if self.item_count > 0:
620 623 self.first_page = 1
621 624 self.page_count = ((self.item_count - 1) / self.items_per_page) + 1
622 625 self.last_page = self.first_page + self.page_count - 1
623 626
624 627 # Make sure that the requested page number is the range of valid pages
625 628 if self.page > self.last_page:
626 629 self.page = self.last_page
627 630 elif self.page < self.first_page:
628 631 self.page = self.first_page
629 632
630 633 # Note: the number of items on this page can be less than
631 634 # items_per_page if the last page is not full
632 635 self.first_item = max(0, (self.item_count) - (self.page * items_per_page))
633 636 self.last_item = ((self.item_count - 1) - items_per_page * (self.page - 1))
634 637
635 638 iterator = self.collection.get_changesets(start=self.first_item,
636 639 end=self.last_item,
637 640 reverse=True,
638 641 branch_name=branch_name)
639 642 self.items = list(iterator)
640 643
641 644 # Links to previous and next page
642 645 if self.page > self.first_page:
643 646 self.previous_page = self.page - 1
644 647 else:
645 648 self.previous_page = None
646 649
647 650 if self.page < self.last_page:
648 651 self.next_page = self.page + 1
649 652 else:
650 653 self.next_page = None
651 654
652 655 # No items available
653 656 else:
654 657 self.first_page = None
655 658 self.page_count = 0
656 659 self.last_page = None
657 660 self.first_item = None
658 661 self.last_item = None
659 662 self.previous_page = None
660 663 self.next_page = None
661 664 self.items = []
662 665
663 666 # This is a subclass of the 'list' type. Initialise the list now.
664 667 list.__init__(self, self.items)
665 668
666 669
667 670 def safe_unicode(str):
668 671 """safe unicode function. In case of UnicodeDecode error we try to return
669 672 unicode with errors replace, if this failes we return unicode with
670 673 string_escape decoding """
671 674
672 675 try:
673 676 u_str = unicode(str)
674 677 except UnicodeDecodeError:
675 678 try:
676 679 u_str = unicode(str, 'utf-8', 'replace')
677 680 except UnicodeDecodeError:
678 681 #incase we have a decode error just represent as byte string
679 682 u_str = unicode(str(str).encode('string_escape'))
680 683
681 684 return u_str
682 685
683 686 def changed_tooltip(nodes):
684 687 if nodes:
685 688 pref = ': <br/> '
686 689 suf = ''
687 690 if len(nodes) > 30:
688 691 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
689 692 return literal(pref + '<br/> '.join([x.path.decode('utf-8', 'replace') for x in nodes[:30]]) + suf)
690 693 else:
691 694 return ': ' + _('No Files')
@@ -1,116 +1,116 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.hooks
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Hooks runned by rhodecode
7 7
8 8 :created_on: Aug 6, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27 import os
28 28 import sys
29 29 import getpass
30 30
31 31 from mercurial.cmdutil import revrange
32 32 from mercurial.node import nullrev
33 33
34 34 from rhodecode.lib import helpers as h
35 35 from rhodecode.lib.utils import action_logger
36 36
37 37 def repo_size(ui, repo, hooktype=None, **kwargs):
38 38 """Presents size of repository after push
39 39
40 40 :param ui:
41 41 :param repo:
42 42 :param hooktype:
43 43 """
44 44
45 45 if hooktype != 'changegroup':
46 46 return False
47 47 size_hg, size_root = 0, 0
48 48 for path, dirs, files in os.walk(repo.root):
49 49 if path.find('.hg') != -1:
50 50 for f in files:
51 51 try:
52 52 size_hg += os.path.getsize(os.path.join(path, f))
53 53 except OSError:
54 54 pass
55 55 else:
56 56 for f in files:
57 57 try:
58 58 size_root += os.path.getsize(os.path.join(path, f))
59 59 except OSError:
60 60 pass
61 61
62 62 size_hg_f = h.format_byte_size(size_hg)
63 63 size_root_f = h.format_byte_size(size_root)
64 64 size_total_f = h.format_byte_size(size_root + size_hg)
65 65 sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
66 66 % (size_hg_f, size_root_f, size_total_f))
67 67
68 68 def log_pull_action(ui, repo, **kwargs):
69 69 """Logs user last pull action
70 70
71 71 :param ui:
72 72 :param repo:
73 73 """
74 74
75 75 extra_params = dict(repo.ui.configitems('rhodecode_extras'))
76 76 username = extra_params['username']
77 77 repository = extra_params['repository']
78 78 action = 'pull'
79 79
80 80 action_logger(username, action, repository, extra_params['ip'])
81 81
82 82 return 0
83 83
84 84 def log_push_action(ui, repo, **kwargs):
85 85 """Maps user last push action to new changeset id, from mercurial
86 86
87 87 :param ui:
88 88 :param repo:
89 89 """
90 90
91 91 extra_params = dict(repo.ui.configitems('rhodecode_extras'))
92 92 username = extra_params['username']
93 93 repository = extra_params['repository']
94 action = 'push:%s'
94 action = extra_params['action'] + ':%s'
95 95 node = kwargs['node']
96 96
97 97 def get_revs(repo, rev_opt):
98 98 if rev_opt:
99 99 revs = revrange(repo, rev_opt)
100 100
101 101 if len(revs) == 0:
102 102 return (nullrev, nullrev)
103 103 return (max(revs), min(revs))
104 104 else:
105 105 return (len(repo) - 1, 0)
106 106
107 107 stop, start = get_revs(repo, [node + ':'])
108 108
109 109 revs = (str(repo[r]) for r in xrange(start, stop + 1))
110 110
111 111 action = action % ','.join(revs)
112 112
113 113 action_logger(username, action, repository, extra_params['ip'])
114 114
115 115 return 0
116 116
@@ -1,395 +1,412 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.scm
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Scm model for RhodeCode
7 7
8 8 :created_on: Apr 9, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27 import os
28 28 import time
29 29 import traceback
30 30 import logging
31 31
32 32 from mercurial import ui
33 33
34 34 from sqlalchemy.exc import DatabaseError
35 35 from sqlalchemy.orm import make_transient
36 36
37 37 from beaker.cache import cache_region, region_invalidate
38 38
39 39 from vcs import get_backend
40 40 from vcs.utils.helpers import get_scm
41 41 from vcs.exceptions import RepositoryError, VCSError
42 42 from vcs.utils.lazy import LazyProperty
43 43
44 44 from rhodecode import BACKENDS
45 45 from rhodecode.lib import helpers as h
46 46 from rhodecode.lib.auth import HasRepoPermissionAny
47 47 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
48 48 action_logger
49 49 from rhodecode.model import BaseModel
50 50 from rhodecode.model.user import UserModel
51 51 from rhodecode.model.repo import RepoModel
52 52 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
53 53 UserFollowing, UserLog
54 54 from rhodecode.model.caching_query import FromCache
55 55
56 56 log = logging.getLogger(__name__)
57 57
58 58
59 59 class UserTemp(object):
60 60 def __init__(self, user_id):
61 61 self.user_id = user_id
62 62
63 63 def __repr__(self):
64 64 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
65 65
66 66 class RepoTemp(object):
67 67 def __init__(self, repo_id):
68 68 self.repo_id = repo_id
69 69
70 70 def __repr__(self):
71 71 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
72 72
73 73 class ScmModel(BaseModel):
74 74 """Generic Scm Model
75 75 """
76 76
77 77 @LazyProperty
78 78 def repos_path(self):
79 79 """Get's the repositories root path from database
80 80 """
81 81
82 82 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
83 83
84 84 return q.ui_value
85 85
86 86 def repo_scan(self, repos_path=None):
87 87 """Listing of repositories in given path. This path should not be a
88 88 repository itself. Return a dictionary of repository objects
89 89
90 90 :param repos_path: path to directory containing repositories
91 91 """
92 92
93 93 log.info('scanning for repositories in %s', repos_path)
94 94
95 95 if repos_path is None:
96 96 repos_path = self.repos_path
97 97
98 98 baseui = make_ui('db')
99 99 repos_list = {}
100 100
101 101 for name, path in get_filesystem_repos(repos_path, recursive=True):
102 102 try:
103 103 if repos_list.has_key(name):
104 104 raise RepositoryError('Duplicate repository name %s '
105 105 'found in %s' % (name, path))
106 106 else:
107 107
108 108 klass = get_backend(path[0])
109 109
110 110 if path[0] == 'hg' and path[0] in BACKENDS.keys():
111 111 repos_list[name] = klass(path[1], baseui=baseui)
112 112
113 113 if path[0] == 'git' and path[0] in BACKENDS.keys():
114 114 repos_list[name] = klass(path[1])
115 115 except OSError:
116 116 continue
117 117
118 118 return repos_list
119 119
120 120 def get_repos(self, all_repos=None):
121 121 """Get all repos from db and for each repo create it's backend instance.
122 122 and fill that backed with information from database
123 123
124 124 :param all_repos: give specific repositories list, good for filtering
125 125 this have to be a list of just the repository names
126 126 """
127 127 if all_repos is None:
128 128 all_repos = [r.repo_name for r in self.sa.query(Repository)\
129 129 .order_by(Repository.repo_name).all()]
130 130
131 131 #get the repositories that should be invalidated
132 132 invalidation_list = [str(x.cache_key) for x in \
133 133 self.sa.query(CacheInvalidation.cache_key)\
134 134 .filter(CacheInvalidation.cache_active == False)\
135 135 .all()]
136 136 for r_name in all_repos:
137 137 r_dbr = self.get(r_name, invalidation_list)
138 138 if r_dbr is not None:
139 139 repo, dbrepo = r_dbr
140 140
141 141 last_change = repo.last_change
142 142 tip = h.get_changeset_safe(repo, 'tip')
143 143
144 144 tmp_d = {}
145 145 tmp_d['name'] = dbrepo.repo_name
146 146 tmp_d['name_sort'] = tmp_d['name'].lower()
147 147 tmp_d['description'] = dbrepo.description
148 148 tmp_d['description_sort'] = tmp_d['description']
149 149 tmp_d['last_change'] = last_change
150 150 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
151 151 tmp_d['tip'] = tip.raw_id
152 152 tmp_d['tip_sort'] = tip.revision
153 153 tmp_d['rev'] = tip.revision
154 154 tmp_d['contact'] = dbrepo.user.full_contact
155 155 tmp_d['contact_sort'] = tmp_d['contact']
156 156 tmp_d['owner_sort'] = tmp_d['contact']
157 157 tmp_d['repo_archives'] = list(repo._get_archives())
158 158 tmp_d['last_msg'] = tip.message
159 159 tmp_d['repo'] = repo
160 160 tmp_d['dbrepo'] = dbrepo.get_dict()
161 161 tmp_d['dbrepo_fork'] = dbrepo.fork.get_dict() if dbrepo.fork else {}
162 162 yield tmp_d
163 163
164 164 def get(self, repo_name, invalidation_list=None, retval='all'):
165 165 """Returns a tuple of Repository,DbRepository,
166 166 Get's repository from given name, creates BackendInstance and
167 167 propagates it's data from database with all additional information
168 168
169 169 :param repo_name:
170 170 :param invalidation_list: if a invalidation list is given the get
171 171 method should not manually check if this repository needs
172 172 invalidation and just invalidate the repositories in list
173 173 :param retval: string specifing what to return one of 'repo','dbrepo',
174 174 'all'if repo or dbrepo is given it'll just lazy load chosen type
175 175 and return None as the second
176 176 """
177 177 if not HasRepoPermissionAny('repository.read', 'repository.write',
178 178 'repository.admin')(repo_name, 'get repo check'):
179 179 return
180 180
181 181 #======================================================================
182 182 # CACHE FUNCTION
183 183 #======================================================================
184 184 @cache_region('long_term')
185 185 def _get_repo(repo_name):
186 186
187 187 repo_path = os.path.join(self.repos_path, repo_name)
188 188
189 189 try:
190 190 alias = get_scm(repo_path)[0]
191 191 log.debug('Creating instance of %s repository', alias)
192 192 backend = get_backend(alias)
193 193 except VCSError:
194 194 log.error(traceback.format_exc())
195 195 log.error('Perhaps this repository is in db and not in '
196 196 'filesystem run rescan repositories with '
197 197 '"destroy old data " option from admin panel')
198 198 return
199 199
200 200 if alias == 'hg':
201 201 repo = backend(repo_path, create=False, baseui=make_ui('db'))
202 202 #skip hidden web repository
203 203 if repo._get_hidden():
204 204 return
205 205 else:
206 206 repo = backend(repo_path, create=False)
207 207
208 208 return repo
209 209
210 210 pre_invalidate = True
211 211 dbinvalidate = False
212 212
213 213 if invalidation_list is not None:
214 214 pre_invalidate = repo_name in invalidation_list
215 215
216 216 if pre_invalidate:
217 217 #this returns object to invalidate
218 218 invalidate = self._should_invalidate(repo_name)
219 219 if invalidate:
220 220 log.info('invalidating cache for repository %s', repo_name)
221 221 region_invalidate(_get_repo, None, repo_name)
222 222 self._mark_invalidated(invalidate)
223 223 dbinvalidate = True
224 224
225 225 r, dbr = None, None
226 226 if retval == 'repo' or 'all':
227 227 r = _get_repo(repo_name)
228 228 if retval == 'dbrepo' or 'all':
229 229 dbr = RepoModel().get_full(repo_name, cache=True,
230 230 invalidate=dbinvalidate)
231 231
232 232
233 233 return r, dbr
234 234
235
236
237 235 def mark_for_invalidation(self, repo_name):
238 236 """Puts cache invalidation task into db for
239 237 further global cache invalidation
240 238
241 239 :param repo_name: this repo that should invalidation take place
242 240 """
243 241
244 242 log.debug('marking %s for invalidation', repo_name)
245 243 cache = self.sa.query(CacheInvalidation)\
246 244 .filter(CacheInvalidation.cache_key == repo_name).scalar()
247 245
248 246 if cache:
249 247 #mark this cache as inactive
250 248 cache.cache_active = False
251 249 else:
252 250 log.debug('cache key not found in invalidation db -> creating one')
253 251 cache = CacheInvalidation(repo_name)
254 252
255 253 try:
256 254 self.sa.add(cache)
257 255 self.sa.commit()
258 256 except (DatabaseError,):
259 257 log.error(traceback.format_exc())
260 258 self.sa.rollback()
261 259
262 260
263 261 def toggle_following_repo(self, follow_repo_id, user_id):
264 262
265 263 f = self.sa.query(UserFollowing)\
266 264 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
267 265 .filter(UserFollowing.user_id == user_id).scalar()
268 266
269 267 if f is not None:
270 268
271 269 try:
272 270 self.sa.delete(f)
273 271 self.sa.commit()
274 272 action_logger(UserTemp(user_id),
275 273 'stopped_following_repo',
276 274 RepoTemp(follow_repo_id))
277 275 return
278 276 except:
279 277 log.error(traceback.format_exc())
280 278 self.sa.rollback()
281 279 raise
282 280
283 281
284 282 try:
285 283 f = UserFollowing()
286 284 f.user_id = user_id
287 285 f.follows_repo_id = follow_repo_id
288 286 self.sa.add(f)
289 287 self.sa.commit()
290 288 action_logger(UserTemp(user_id),
291 289 'started_following_repo',
292 290 RepoTemp(follow_repo_id))
293 291 except:
294 292 log.error(traceback.format_exc())
295 293 self.sa.rollback()
296 294 raise
297 295
298 296 def toggle_following_user(self, follow_user_id , user_id):
299 297 f = self.sa.query(UserFollowing)\
300 298 .filter(UserFollowing.follows_user_id == follow_user_id)\
301 299 .filter(UserFollowing.user_id == user_id).scalar()
302 300
303 301 if f is not None:
304 302 try:
305 303 self.sa.delete(f)
306 304 self.sa.commit()
307 305 return
308 306 except:
309 307 log.error(traceback.format_exc())
310 308 self.sa.rollback()
311 309 raise
312 310
313 311 try:
314 312 f = UserFollowing()
315 313 f.user_id = user_id
316 314 f.follows_user_id = follow_user_id
317 315 self.sa.add(f)
318 316 self.sa.commit()
319 317 except:
320 318 log.error(traceback.format_exc())
321 319 self.sa.rollback()
322 320 raise
323 321
324 322 def is_following_repo(self, repo_name, user_id, cache=False):
325 323 r = self.sa.query(Repository)\
326 324 .filter(Repository.repo_name == repo_name).scalar()
327 325
328 326 f = self.sa.query(UserFollowing)\
329 327 .filter(UserFollowing.follows_repository == r)\
330 328 .filter(UserFollowing.user_id == user_id).scalar()
331 329
332 330 return f is not None
333 331
334 332 def is_following_user(self, username, user_id, cache=False):
335 333 u = UserModel(self.sa).get_by_username(username)
336 334
337 335 f = self.sa.query(UserFollowing)\
338 336 .filter(UserFollowing.follows_user == u)\
339 337 .filter(UserFollowing.user_id == user_id).scalar()
340 338
341 339 return f is not None
342 340
343 341 def get_followers(self, repo_id):
344 342 if isinstance(repo_id, int):
345 343 return self.sa.query(UserFollowing)\
346 344 .filter(UserFollowing.follows_repo_id == repo_id).count()
347 345 else:
348 346 return self.sa.query(UserFollowing)\
349 347 .filter(UserFollowing.follows_repository \
350 348 == RepoModel().get_by_repo_name(repo_id)).count()
351 349
352 350 def get_forks(self, repo_id):
353 351 if isinstance(repo_id, int):
354 352 return self.sa.query(Repository)\
355 353 .filter(Repository.fork_id == repo_id).count()
356 354 else:
357 355 return self.sa.query(Repository)\
358 356 .filter(Repository.fork \
359 357 == RepoModel().get_by_repo_name(repo_id)).count()
360 358
361 359
360 def pull_changes(self, repo_name, username):
361 repo, dbrepo = self.get(repo_name, retval='all')
362
363 try:
364 extras = {'ip':'',
365 'username':username,
366 'action':'push_remote',
367 'repository':repo_name}
368
369 #inject ui extra param to log this action via push logger
370 for k, v in extras.items():
371 repo._repo.ui.setconfig('rhodecode_extras', k, v)
372
373 repo.pull(dbrepo.clone_uri)
374 self.mark_for_invalidation(repo_name)
375 except:
376 log.error(traceback.format_exc())
377 raise
378
362 379 def get_unread_journal(self):
363 380 return self.sa.query(UserLog).count()
364 381
365 382
366 383 def _should_invalidate(self, repo_name):
367 384 """Looks up database for invalidation signals for this repo_name
368 385
369 386 :param repo_name:
370 387 """
371 388
372 389 ret = self.sa.query(CacheInvalidation)\
373 390 .filter(CacheInvalidation.cache_key == repo_name)\
374 391 .filter(CacheInvalidation.cache_active == False)\
375 392 .scalar()
376 393
377 394 return ret
378 395
379 396 def _mark_invalidated(self, cache_key):
380 397 """ Marks all occurrences of cache to invalidation as already
381 398 invalidated
382 399
383 400 :param cache_key:
384 401 """
385 402
386 403 if cache_key:
387 404 log.debug('marking %s as already invalidated', cache_key)
388 405 try:
389 406 cache_key.cache_active = True
390 407 self.sa.add(cache_key)
391 408 self.sa.commit()
392 409 except (DatabaseError,):
393 410 log.error(traceback.format_exc())
394 411 self.sa.rollback()
395 412
@@ -1,2508 +1,2516 b''
1 1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
2 2 border:0;
3 3 outline:0;
4 4 font-size:100%;
5 5 vertical-align:baseline;
6 6 background:transparent;
7 7 margin:0;
8 8 padding:0;
9 9 }
10 10
11 11 body {
12 12 line-height:1;
13 13 height:100%;
14 14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 16 font-size:12px;
17 17 color:#000;
18 18 margin:0;
19 19 padding:0;
20 20 }
21 21
22 22 ol,ul {
23 23 list-style:none;
24 24 }
25 25
26 26 blockquote,q {
27 27 quotes:none;
28 28 }
29 29
30 30 blockquote:before,blockquote:after,q:before,q:after {
31 31 content:none;
32 32 }
33 33
34 34 :focus {
35 35 outline:0;
36 36 }
37 37
38 38 del {
39 39 text-decoration:line-through;
40 40 }
41 41
42 42 table {
43 43 border-collapse:collapse;
44 44 border-spacing:0;
45 45 }
46 46
47 47 html {
48 48 height:100%;
49 49 }
50 50
51 51 a {
52 52 color:#003367;
53 53 text-decoration:none;
54 54 cursor:pointer;
55 55 font-weight:700;
56 56 }
57 57
58 58 a:hover {
59 59 color:#316293;
60 60 text-decoration:underline;
61 61 }
62 62
63 63 h1,h2,h3,h4,h5,h6 {
64 64 color:#292929;
65 65 font-weight:700;
66 66 }
67 67
68 68 h1 {
69 69 font-size:22px;
70 70 }
71 71
72 72 h2 {
73 73 font-size:20px;
74 74 }
75 75
76 76 h3 {
77 77 font-size:18px;
78 78 }
79 79
80 80 h4 {
81 81 font-size:16px;
82 82 }
83 83
84 84 h5 {
85 85 font-size:14px;
86 86 }
87 87
88 88 h6 {
89 89 font-size:11px;
90 90 }
91 91
92 92 ul.circle {
93 93 list-style-type:circle;
94 94 }
95 95
96 96 ul.disc {
97 97 list-style-type:disc;
98 98 }
99 99
100 100 ul.square {
101 101 list-style-type:square;
102 102 }
103 103
104 104 ol.lower-roman {
105 105 list-style-type:lower-roman;
106 106 }
107 107
108 108 ol.upper-roman {
109 109 list-style-type:upper-roman;
110 110 }
111 111
112 112 ol.lower-alpha {
113 113 list-style-type:lower-alpha;
114 114 }
115 115
116 116 ol.upper-alpha {
117 117 list-style-type:upper-alpha;
118 118 }
119 119
120 120 ol.decimal {
121 121 list-style-type:decimal;
122 122 }
123 123
124 124 div.color {
125 125 clear:both;
126 126 overflow:hidden;
127 127 position:absolute;
128 128 background:#FFF;
129 129 margin:7px 0 0 60px;
130 130 padding:1px 1px 1px 0;
131 131 }
132 132
133 133 div.color a {
134 134 width:15px;
135 135 height:15px;
136 136 display:block;
137 137 float:left;
138 138 margin:0 0 0 1px;
139 139 padding:0;
140 140 }
141 141
142 142 div.options {
143 143 clear:both;
144 144 overflow:hidden;
145 145 position:absolute;
146 146 background:#FFF;
147 147 margin:7px 0 0 162px;
148 148 padding:0;
149 149 }
150 150
151 151 div.options a {
152 152 height:1%;
153 153 display:block;
154 154 text-decoration:none;
155 155 margin:0;
156 156 padding:3px 8px;
157 157 }
158 158
159 159 .top-left-rounded-corner {
160 160 -webkit-border-top-left-radius: 8px;
161 161 -khtml-border-radius-topleft: 8px;
162 162 -moz-border-radius-topleft: 8px;
163 163 border-top-left-radius: 8px;
164 164 }
165 165
166 166 .top-right-rounded-corner {
167 167 -webkit-border-top-right-radius: 8px;
168 168 -khtml-border-radius-topright: 8px;
169 169 -moz-border-radius-topright: 8px;
170 170 border-top-right-radius: 8px;
171 171 }
172 172
173 173 .bottom-left-rounded-corner {
174 174 -webkit-border-bottom-left-radius: 8px;
175 175 -khtml-border-radius-bottomleft: 8px;
176 176 -moz-border-radius-bottomleft: 8px;
177 177 border-bottom-left-radius: 8px;
178 178 }
179 179
180 180 .bottom-right-rounded-corner {
181 181 -webkit-border-bottom-right-radius: 8px;
182 182 -khtml-border-radius-bottomright: 8px;
183 183 -moz-border-radius-bottomright: 8px;
184 184 border-bottom-right-radius: 8px;
185 185 }
186 186
187 187
188 188 #header {
189 189 margin:0;
190 190 padding:0 30px;
191 191 }
192 192
193 193
194 194 #header ul#logged-user{
195 195 margin-bottom:5px !important;
196 196 -webkit-border-radius: 0px 0px 8px 8px;
197 197 -khtml-border-radius: 0px 0px 8px 8px;
198 198 -moz-border-radius: 0px 0px 8px 8px;
199 199 border-radius: 0px 0px 8px 8px;
200 200 height:37px;
201 201 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
202 202 }
203 203
204 204 #header ul#logged-user li {
205 205 list-style:none;
206 206 float:left;
207 207 margin:8px 0 0;
208 208 padding:4px 12px;
209 209 border-left: 1px solid #316293;
210 210 }
211 211
212 212 #header ul#logged-user li.first {
213 213 border-left:none;
214 214 margin:4px;
215 215 }
216 216
217 217 #header ul#logged-user li.first div.gravatar {
218 218 margin-top:-2px;
219 219 }
220 220
221 221 #header ul#logged-user li.first div.account {
222 222 padding-top:4px;
223 223 float:left;
224 224 }
225 225
226 226 #header ul#logged-user li.last {
227 227 border-right:none;
228 228 }
229 229
230 230 #header ul#logged-user li a {
231 231 color:#fff;
232 232 font-weight:700;
233 233 text-decoration:none;
234 234 }
235 235
236 236 #header ul#logged-user li a:hover {
237 237 text-decoration:underline;
238 238 }
239 239
240 240 #header ul#logged-user li.highlight a {
241 241 color:#fff;
242 242 }
243 243
244 244 #header ul#logged-user li.highlight a:hover {
245 245 color:#FFF;
246 246 }
247 247
248 248 #header #header-inner {
249 249 height:40px;
250 250 clear:both;
251 251 position:relative;
252 252 background:#003367 url("../images/header_inner.png") repeat-x;
253 253 border-bottom:2px solid #fff;
254 254 margin:0;
255 255 padding:0;
256 256 }
257 257
258 258 #header #header-inner #home a {
259 259 height:40px;
260 260 width:46px;
261 261 display:block;
262 262 background:url("../images/button_home.png");
263 263 background-position:0 0;
264 264 margin:0;
265 265 padding:0;
266 266 }
267 267
268 268 #header #header-inner #home a:hover {
269 269 background-position:0 -40px;
270 270 }
271 271
272 272 #header #header-inner #logo h1 {
273 273 color:#FFF;
274 274 font-size:18px;
275 275 margin:10px 0 0 13px;
276 276 padding:0;
277 277 }
278 278
279 279 #header #header-inner #logo a {
280 280 color:#fff;
281 281 text-decoration:none;
282 282 }
283 283
284 284 #header #header-inner #logo a:hover {
285 285 color:#bfe3ff;
286 286 }
287 287
288 288 #header #header-inner #quick,#header #header-inner #quick ul {
289 289 position:relative;
290 290 float:right;
291 291 list-style-type:none;
292 292 list-style-position:outside;
293 293 margin:10px 5px 0 0;
294 294 padding:0;
295 295 }
296 296
297 297 #header #header-inner #quick li {
298 298 position:relative;
299 299 float:left;
300 300 margin:0 5px 0 0;
301 301 padding:0;
302 302 }
303 303
304 304 #header #header-inner #quick li a {
305 305 top:0;
306 306 left:0;
307 307 height:1%;
308 308 display:block;
309 309 clear:both;
310 310 overflow:hidden;
311 311 color:#FFF;
312 312 font-weight:700;
313 313 text-decoration:none;
314 314 background:#369 url("../images/quick_l.png") no-repeat top left;
315 315 padding:0;
316 316 }
317 317
318 318 #header #header-inner #quick li span.short {
319 319 padding:9px 6px 8px 6px;
320 320 }
321 321
322 322 #header #header-inner #quick li span {
323 323 top:0;
324 324 right:0;
325 325 height:1%;
326 326 display:block;
327 327 float:left;
328 328 background:url("../images/quick_r.png") no-repeat top right;
329 329 border-left:1px solid #3f6f9f;
330 330 margin:0;
331 331 padding:10px 12px 8px 10px;
332 332 }
333 333
334 334 #header #header-inner #quick li span.normal {
335 335 border:none;
336 336 padding:10px 12px 8px;
337 337 }
338 338
339 339 #header #header-inner #quick li span.icon {
340 340 top:0;
341 341 left:0;
342 342 border-left:none;
343 343 background:url("../images/quick_l.png") no-repeat top left;
344 344 border-right:1px solid #2e5c89;
345 345 padding:8px 8px 4px;
346 346 }
347 347
348 348 #header #header-inner #quick li span.icon_short {
349 349 top:0;
350 350 left:0;
351 351 border-left:none;
352 352 background:url("../images/quick_l.png") no-repeat top left;
353 353 border-right:1px solid #2e5c89;
354 354 padding:9px 4px 4px;
355 355 }
356 356
357 357 #header #header-inner #quick li a:hover {
358 358 background:#4e4e4e url("../images/quick_l_selected.png") no-repeat top left;
359 359 }
360 360
361 361 #header #header-inner #quick li a:hover span {
362 362 border-left:1px solid #545454;
363 363 background:url("../images/quick_r_selected.png") no-repeat top right;
364 364 }
365 365
366 366 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
367 367 border-left:none;
368 368 border-right:1px solid #464646;
369 369 background:url("../images/quick_l_selected.png") no-repeat top left;
370 370 }
371 371
372 372
373 373 #header #header-inner #quick ul {
374 374 top:29px;
375 375 right:0;
376 376 min-width:200px;
377 377 display:none;
378 378 position:absolute;
379 379 background:#FFF;
380 380 border:1px solid #666;
381 381 border-top:1px solid #003367;
382 382 z-index:100;
383 383 margin:0;
384 384 padding:0;
385 385 }
386 386
387 387 #header #header-inner #quick ul.repo_switcher {
388 388 max-height:275px;
389 389 overflow-x:hidden;
390 390 overflow-y:auto;
391 391 }
392 392
393 393 #header #header-inner #quick .repo_switcher_type{
394 394 position:absolute;
395 395 left:0;
396 396 top:9px;
397 397
398 398 }
399 399 #header #header-inner #quick li ul li {
400 400 border-bottom:1px solid #ddd;
401 401 }
402 402
403 403 #header #header-inner #quick li ul li a {
404 404 width:182px;
405 405 height:auto;
406 406 display:block;
407 407 float:left;
408 408 background:#FFF;
409 409 color:#003367;
410 410 font-weight:400;
411 411 margin:0;
412 412 padding:7px 9px;
413 413 }
414 414
415 415 #header #header-inner #quick li ul li a:hover {
416 416 color:#000;
417 417 background:#FFF;
418 418 }
419 419
420 420 #header #header-inner #quick ul ul {
421 421 top:auto;
422 422 }
423 423
424 424 #header #header-inner #quick li ul ul {
425 425 right:200px;
426 426 max-height:275px;
427 427 overflow:auto;
428 428 overflow-x:hidden;
429 429 white-space:normal;
430 430 }
431 431
432 432 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
433 433 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
434 434 width:167px;
435 435 margin:0;
436 436 padding:12px 9px 7px 24px;
437 437 }
438 438
439 439 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
440 440 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
441 441 min-width:167px;
442 442 margin:0;
443 443 padding:12px 9px 7px 24px;
444 444 }
445 445
446 446 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
447 447 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
448 448 min-width:167px;
449 449 margin:0;
450 450 padding:12px 9px 7px 24px;
451 451 }
452 452
453 453 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
454 454 background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
455 455 min-width:167px;
456 456 margin:0 0 0 14px;
457 457 padding:12px 9px 7px 24px;
458 458 }
459 459
460 460 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
461 461 background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
462 462 min-width:167px;
463 463 margin:0 0 0 14px;
464 464 padding:12px 9px 7px 24px;
465 465 }
466 466
467 467 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
468 468 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
469 469 width:167px;
470 470 margin:0;
471 471 padding:12px 9px 7px 24px;
472 472 }
473 473
474 474 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
475 475 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
476 476 width:167px;
477 477 margin:0;
478 478 padding:12px 9px 7px 24px;
479 479 }
480 480
481 481 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover {
482 482 background:#FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
483 483 width:167px;
484 484 margin:0;
485 485 padding:12px 9px 7px 24px;
486 486 }
487 487
488 488 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
489 489 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
490 490 width:167px;
491 491 margin:0;
492 492 padding:12px 9px 7px 24px;
493 493 }
494 494
495 495 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
496 496 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
497 497 width:167px;
498 498 margin:0;
499 499 padding:12px 9px 7px 24px;
500 500 }
501 501
502 502 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
503 503 background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
504 504 width:167px;
505 505 margin:0;
506 506 padding:12px 9px 7px 24px;
507 507 }
508 508
509 509 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
510 510 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
511 511 width:167px;
512 512 margin:0;
513 513 padding:12px 9px 7px 24px;
514 514 }
515 515
516 516 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
517 517 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
518 518 width:167px;
519 519 margin:0;
520 520 padding:12px 9px 7px 24px;
521 521 }
522 522
523 523 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
524 524 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
525 525 width:167px;
526 526 margin:0;
527 527 padding:12px 9px 7px 24px;
528 528 }
529 529
530 530 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
531 531 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
532 532 width:167px;
533 533 margin:0;
534 534 padding:12px 9px 7px 24px;
535 535 }
536 536
537 537 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
538 538 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
539 539 width:167px;
540 540 margin:0;
541 541 padding:12px 9px 7px 24px;
542 542 }
543 543
544 544 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
545 545 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
546 546 width:167px;
547 547 margin:0;
548 548 padding:12px 9px 7px 24px;
549 549 }
550 550
551 551 #content #left {
552 552 left:0;
553 553 width:280px;
554 554 position:absolute;
555 555 }
556 556
557 557 #content #right {
558 558 margin:0 60px 10px 290px;
559 559 }
560 560
561 561 #content div.box {
562 562 clear:both;
563 563 overflow:hidden;
564 564 background:#fff;
565 565 margin:0 0 10px;
566 566 padding:0 0 10px;
567 567 }
568 568
569 569 #content div.box-left {
570 570 width:49%;
571 571 clear:none;
572 572 float:left;
573 573 margin:0 0 10px;
574 574 }
575 575
576 576 #content div.box-right {
577 577 width:49%;
578 578 clear:none;
579 579 float:right;
580 580 margin:0 0 10px;
581 581 }
582 582
583 583 #content div.box div.title {
584 584 clear:both;
585 585 overflow:hidden;
586 586 background:#369 url("../images/header_inner.png") repeat-x;
587 587 margin:0 0 20px;
588 588 padding:0;
589 589 }
590 590
591 591 #content div.box div.title h5 {
592 592 float:left;
593 593 border:none;
594 594 color:#fff;
595 595 text-transform:uppercase;
596 596 margin:0;
597 597 padding:11px 0 11px 10px;
598 598 }
599 599
600 600 #content div.box div.title ul.links li {
601 601 list-style:none;
602 602 float:left;
603 603 margin:0;
604 604 padding:0;
605 605 }
606 606
607 607 #content div.box div.title ul.links li a {
608 608 border-left: 1px solid #316293;
609 609 color: #FFFFFF;
610 610 display: block;
611 611 float: left;
612 612 font-size: 13px;
613 613 font-weight: 700;
614 614 height: 1%;
615 615 margin: 0;
616 616 padding: 11px 22px 12px;
617 617 text-decoration: none;
618 618 }
619 619
620 620 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
621 621 clear:both;
622 622 overflow:hidden;
623 623 border-bottom:1px solid #DDD;
624 624 margin:10px 20px;
625 625 padding:0 0 15px;
626 626 }
627 627
628 628 #content div.box p {
629 629 color:#5f5f5f;
630 630 font-size:12px;
631 631 line-height:150%;
632 632 margin:0 24px 10px;
633 633 padding:0;
634 634 }
635 635
636 636 #content div.box blockquote {
637 637 border-left:4px solid #DDD;
638 638 color:#5f5f5f;
639 639 font-size:11px;
640 640 line-height:150%;
641 641 margin:0 34px;
642 642 padding:0 0 0 14px;
643 643 }
644 644
645 645 #content div.box blockquote p {
646 646 margin:10px 0;
647 647 padding:0;
648 648 }
649 649
650 650 #content div.box dl {
651 651 margin:10px 24px;
652 652 }
653 653
654 654 #content div.box dt {
655 655 font-size:12px;
656 656 margin:0;
657 657 }
658 658
659 659 #content div.box dd {
660 660 font-size:12px;
661 661 margin:0;
662 662 padding:8px 0 8px 15px;
663 663 }
664 664
665 665 #content div.box li {
666 666 font-size:12px;
667 667 padding:4px 0;
668 668 }
669 669
670 670 #content div.box ul.disc,#content div.box ul.circle {
671 671 margin:10px 24px 10px 38px;
672 672 }
673 673
674 674 #content div.box ul.square {
675 675 margin:10px 24px 10px 40px;
676 676 }
677 677
678 678 #content div.box img.left {
679 679 border:none;
680 680 float:left;
681 681 margin:10px 10px 10px 0;
682 682 }
683 683
684 684 #content div.box img.right {
685 685 border:none;
686 686 float:right;
687 687 margin:10px 0 10px 10px;
688 688 }
689 689
690 690 #content div.box div.messages {
691 691 clear:both;
692 692 overflow:hidden;
693 693 margin:0 20px;
694 694 padding:0;
695 695 }
696 696
697 697 #content div.box div.message {
698 698 clear:both;
699 699 overflow:hidden;
700 700 margin:0;
701 701 padding:10px 0;
702 702 }
703 703
704 704 #content div.box div.message a {
705 705 font-weight:400 !important;
706 706 }
707 707
708 708 #content div.box div.message div.image {
709 709 float:left;
710 710 margin:9px 0 0 5px;
711 711 padding:6px;
712 712 }
713 713
714 714 #content div.box div.message div.image img {
715 715 vertical-align:middle;
716 716 margin:0;
717 717 }
718 718
719 719 #content div.box div.message div.text {
720 720 float:left;
721 721 margin:0;
722 722 padding:9px 6px;
723 723 }
724 724
725 725 #content div.box div.message div.dismiss a {
726 726 height:16px;
727 727 width:16px;
728 728 display:block;
729 729 background:url("../images/icons/cross.png") no-repeat;
730 730 margin:15px 14px 0 0;
731 731 padding:0;
732 732 }
733 733
734 734 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6 {
735 735 border:none;
736 736 margin:0;
737 737 padding:0;
738 738 }
739 739
740 740 #content div.box div.message div.text span {
741 741 height:1%;
742 742 display:block;
743 743 margin:0;
744 744 padding:5px 0 0;
745 745 }
746 746
747 747 #content div.box div.message-error {
748 748 height:1%;
749 749 clear:both;
750 750 overflow:hidden;
751 751 background:#FBE3E4;
752 752 border:1px solid #FBC2C4;
753 753 color:#860006;
754 754 }
755 755
756 756 #content div.box div.message-error h6 {
757 757 color:#860006;
758 758 }
759 759
760 760 #content div.box div.message-warning {
761 761 height:1%;
762 762 clear:both;
763 763 overflow:hidden;
764 764 background:#FFF6BF;
765 765 border:1px solid #FFD324;
766 766 color:#5f5200;
767 767 }
768 768
769 769 #content div.box div.message-warning h6 {
770 770 color:#5f5200;
771 771 }
772 772
773 773 #content div.box div.message-notice {
774 774 height:1%;
775 775 clear:both;
776 776 overflow:hidden;
777 777 background:#8FBDE0;
778 778 border:1px solid #6BACDE;
779 779 color:#003863;
780 780 }
781 781
782 782 #content div.box div.message-notice h6 {
783 783 color:#003863;
784 784 }
785 785
786 786 #content div.box div.message-success {
787 787 height:1%;
788 788 clear:both;
789 789 overflow:hidden;
790 790 background:#E6EFC2;
791 791 border:1px solid #C6D880;
792 792 color:#4e6100;
793 793 }
794 794
795 795 #content div.box div.message-success h6 {
796 796 color:#4e6100;
797 797 }
798 798
799 799 #content div.box div.form div.fields div.field {
800 800 height:1%;
801 801 border-bottom:1px solid #DDD;
802 802 clear:both;
803 803 margin:0;
804 804 padding:10px 0;
805 805 }
806 806
807 807 #content div.box div.form div.fields div.field-first {
808 808 padding:0 0 10px;
809 809 }
810 810
811 811 #content div.box div.form div.fields div.field-noborder {
812 812 border-bottom:0 !important;
813 813 }
814 814
815 815 #content div.box div.form div.fields div.field span.error-message {
816 816 height:1%;
817 817 display:inline-block;
818 818 color:red;
819 819 margin:8px 0 0 4px;
820 820 padding:0;
821 821 }
822 822
823 823 #content div.box div.form div.fields div.field span.success {
824 824 height:1%;
825 825 display:block;
826 826 color:#316309;
827 827 margin:8px 0 0;
828 828 padding:0;
829 829 }
830 830
831 831 #content div.box div.form div.fields div.field div.label {
832 832 left:80px;
833 833 width:auto;
834 834 position:absolute;
835 835 margin:0;
836 836 padding:8px 0 0 5px;
837 837 }
838 838
839 839 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
840 840 clear:both;
841 841 overflow:hidden;
842 842 left:0;
843 843 width:auto;
844 844 position:relative;
845 845 margin:0;
846 846 padding:0 0 8px;
847 847 }
848 848
849 849 #content div.box div.form div.fields div.field div.label-select {
850 850 padding:5px 0 0 5px;
851 851 }
852 852
853 853 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
854 854 padding:0 0 8px;
855 855 }
856 856
857 857 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
858 858 padding:0 0 8px !important;
859 859 }
860 860
861 861 #content div.box div.form div.fields div.field div.label label {
862 862 color:#393939;
863 863 font-weight:700;
864 864 }
865 865
866 866 #content div.box div.form div.fields div.field div.input {
867 867 margin:0 0 0 200px;
868 868 }
869 869 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
870 870 margin:0 0 0 0px;
871 871 }
872 872
873 873 #content div.box div.form div.fields div.field div.input input {
874 874 background:#FFF;
875 875 border-top:1px solid #b3b3b3;
876 876 border-left:1px solid #b3b3b3;
877 877 border-right:1px solid #eaeaea;
878 878 border-bottom:1px solid #eaeaea;
879 879 color:#000;
880 880 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
881 881 font-size:11px;
882 882 margin:0;
883 883 padding:7px 7px 6px;
884 884 }
885 885
886 886
887 887
888 888 #content div.box div.form div.fields div.field div.input input.small {
889 889 width:30%;
890 890 }
891 891
892 892 #content div.box div.form div.fields div.field div.input input.medium {
893 893 width:55%;
894 894 }
895 895
896 896 #content div.box div.form div.fields div.field div.input input.large {
897 897 width:85%;
898 898 }
899 899
900 900 #content div.box div.form div.fields div.field div.input input.date {
901 901 width:177px;
902 902 }
903 903
904 904 #content div.box div.form div.fields div.field div.input input.button {
905 905 background:#D4D0C8;
906 906 border-top:1px solid #FFF;
907 907 border-left:1px solid #FFF;
908 908 border-right:1px solid #404040;
909 909 border-bottom:1px solid #404040;
910 910 color:#000;
911 911 margin:0;
912 912 padding:4px 8px;
913 913 }
914 914
915 915 #content div.box div.form div.fields div.field div.textarea {
916 916 border-top:1px solid #b3b3b3;
917 917 border-left:1px solid #b3b3b3;
918 918 border-right:1px solid #eaeaea;
919 919 border-bottom:1px solid #eaeaea;
920 920 margin:0 0 0 200px;
921 921 padding:10px;
922 922 }
923 923
924 924 #content div.box div.form div.fields div.field div.textarea-editor {
925 925 border:1px solid #ddd;
926 926 padding:0;
927 927 }
928 928
929 929 #content div.box div.form div.fields div.field div.textarea textarea {
930 930 width:100%;
931 931 height:220px;
932 932 overflow:hidden;
933 933 background:#FFF;
934 934 color:#000;
935 935 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
936 936 font-size:11px;
937 937 outline:none;
938 938 border-width:0;
939 939 margin:0;
940 940 padding:0;
941 941 }
942 942
943 943 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea {
944 944 width:100%;
945 945 height:100px;
946 946 }
947 947
948 948 #content div.box div.form div.fields div.field div.textarea table {
949 949 width:100%;
950 950 border:none;
951 951 margin:0;
952 952 padding:0;
953 953 }
954 954
955 955 #content div.box div.form div.fields div.field div.textarea table td {
956 956 background:#DDD;
957 957 border:none;
958 958 padding:0;
959 959 }
960 960
961 961 #content div.box div.form div.fields div.field div.textarea table td table {
962 962 width:auto;
963 963 border:none;
964 964 margin:0;
965 965 padding:0;
966 966 }
967 967
968 968 #content div.box div.form div.fields div.field div.textarea table td table td {
969 969 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
970 970 font-size:11px;
971 971 padding:5px 5px 5px 0;
972 972 }
973 973
974 974 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
975 975 background:#f6f6f6;
976 976 border-color:#666;
977 977 }
978 978
979 979 div.form div.fields div.field div.button {
980 980 margin:0;
981 981 padding:0 0 0 8px;
982 982 }
983 983
984 984 div.form div.fields div.field div.highlight .ui-button {
985 985 background:#4e85bb url("../images/button_highlight.png") repeat-x;
986 986 border-top:1px solid #5c91a4;
987 987 border-left:1px solid #2a6f89;
988 988 border-right:1px solid #2b7089;
989 989 border-bottom:1px solid #1a6480;
990 990 color:#FFF;
991 991 margin:0;
992 992 padding:6px 12px;
993 993 }
994 994
995 995 div.form div.fields div.field div.highlight .ui-state-hover {
996 996 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
997 997 border-top:1px solid #78acbf;
998 998 border-left:1px solid #34819e;
999 999 border-right:1px solid #35829f;
1000 1000 border-bottom:1px solid #257897;
1001 1001 color:#FFF;
1002 1002 margin:0;
1003 1003 padding:6px 12px;
1004 1004 }
1005 1005
1006 1006 #content div.box div.form div.fields div.buttons div.highlight input.ui-button {
1007 1007 background:#4e85bb url("../images/button_highlight.png") repeat-x;
1008 1008 border-top:1px solid #5c91a4;
1009 1009 border-left:1px solid #2a6f89;
1010 1010 border-right:1px solid #2b7089;
1011 1011 border-bottom:1px solid #1a6480;
1012 1012 color:#fff;
1013 1013 margin:0;
1014 1014 padding:6px 12px;
1015 1015 }
1016 1016
1017 1017 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
1018 1018 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1019 1019 border-top:1px solid #78acbf;
1020 1020 border-left:1px solid #34819e;
1021 1021 border-right:1px solid #35829f;
1022 1022 border-bottom:1px solid #257897;
1023 1023 color:#fff;
1024 1024 margin:0;
1025 1025 padding:6px 12px;
1026 1026 }
1027 1027
1028 1028 #content div.box table {
1029 1029 width:100%;
1030 1030 border-collapse:collapse;
1031 1031 margin:0;
1032 1032 padding:0;
1033 1033 }
1034 1034
1035 1035 #content div.box table th {
1036 1036 background:#eee;
1037 1037 border-bottom:1px solid #ddd;
1038 1038 padding:5px 0px 5px 5px;
1039 1039 }
1040 1040
1041 1041 #content div.box table th.left {
1042 1042 text-align:left;
1043 1043 }
1044 1044
1045 1045 #content div.box table th.right {
1046 1046 text-align:right;
1047 1047 }
1048 1048
1049 1049 #content div.box table th.center {
1050 1050 text-align:center;
1051 1051 }
1052 1052
1053 1053 #content div.box table th.selected {
1054 1054 vertical-align:middle;
1055 1055 padding:0;
1056 1056 }
1057 1057
1058 1058 #content div.box table td {
1059 1059 background:#fff;
1060 1060 border-bottom:1px solid #cdcdcd;
1061 1061 vertical-align:middle;
1062 1062 padding:5px;
1063 1063 }
1064 1064
1065 1065 #content div.box table tr.selected td {
1066 1066 background:#FFC;
1067 1067 }
1068 1068
1069 1069 #content div.box table td.selected {
1070 1070 width:3%;
1071 1071 text-align:center;
1072 1072 vertical-align:middle;
1073 1073 padding:0;
1074 1074 }
1075 1075
1076 1076 #content div.box table td.action {
1077 1077 width:45%;
1078 1078 text-align:left;
1079 1079 }
1080 1080
1081 1081 #content div.box table td.date {
1082 1082 width:33%;
1083 1083 text-align:center;
1084 1084 }
1085 1085
1086 1086 #content div.box div.action {
1087 1087 float:right;
1088 1088 background:#FFF;
1089 1089 text-align:right;
1090 1090 margin:10px 0 0;
1091 1091 padding:0;
1092 1092 }
1093 1093
1094 1094 #content div.box div.action select {
1095 1095 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1096 1096 font-size:11px;
1097 1097 margin:0;
1098 1098 }
1099 1099
1100 1100 #content div.box div.action .ui-selectmenu {
1101 1101 margin:0;
1102 1102 padding:0;
1103 1103 }
1104 1104
1105 1105 #content div.box div.pagination {
1106 1106 height:1%;
1107 1107 clear:both;
1108 1108 overflow:hidden;
1109 1109 margin:10px 0 0;
1110 1110 padding:0;
1111 1111 }
1112 1112
1113 1113 #content div.box div.pagination ul.pager {
1114 1114 float:right;
1115 1115 text-align:right;
1116 1116 margin:0;
1117 1117 padding:0;
1118 1118 }
1119 1119
1120 1120 #content div.box div.pagination ul.pager li {
1121 1121 height:1%;
1122 1122 float:left;
1123 1123 list-style:none;
1124 1124 background:#ebebeb url("../images/pager.png") repeat-x;
1125 1125 border-top:1px solid #dedede;
1126 1126 border-left:1px solid #cfcfcf;
1127 1127 border-right:1px solid #c4c4c4;
1128 1128 border-bottom:1px solid #c4c4c4;
1129 1129 color:#4A4A4A;
1130 1130 font-weight:700;
1131 1131 margin:0 0 0 4px;
1132 1132 padding:0;
1133 1133 }
1134 1134
1135 1135 #content div.box div.pagination ul.pager li.separator {
1136 1136 padding:6px;
1137 1137 }
1138 1138
1139 1139 #content div.box div.pagination ul.pager li.current {
1140 1140 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1141 1141 border-top:1px solid #ccc;
1142 1142 border-left:1px solid #bebebe;
1143 1143 border-right:1px solid #b1b1b1;
1144 1144 border-bottom:1px solid #afafaf;
1145 1145 color:#515151;
1146 1146 padding:6px;
1147 1147 }
1148 1148
1149 1149 #content div.box div.pagination ul.pager li a {
1150 1150 height:1%;
1151 1151 display:block;
1152 1152 float:left;
1153 1153 color:#515151;
1154 1154 text-decoration:none;
1155 1155 margin:0;
1156 1156 padding:6px;
1157 1157 }
1158 1158
1159 1159 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1160 1160 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1161 1161 border-top:1px solid #ccc;
1162 1162 border-left:1px solid #bebebe;
1163 1163 border-right:1px solid #b1b1b1;
1164 1164 border-bottom:1px solid #afafaf;
1165 1165 margin:-1px;
1166 1166 }
1167 1167
1168 1168 #content div.box div.pagination-wh {
1169 1169 height:1%;
1170 1170 clear:both;
1171 1171 overflow:hidden;
1172 1172 text-align:right;
1173 1173 margin:10px 0 0;
1174 1174 padding:0;
1175 1175 }
1176 1176
1177 1177 #content div.box div.pagination-right {
1178 1178 float:right;
1179 1179 }
1180 1180
1181 1181 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1182 1182 height:1%;
1183 1183 float:left;
1184 1184 background:#ebebeb url("../images/pager.png") repeat-x;
1185 1185 border-top:1px solid #dedede;
1186 1186 border-left:1px solid #cfcfcf;
1187 1187 border-right:1px solid #c4c4c4;
1188 1188 border-bottom:1px solid #c4c4c4;
1189 1189 color:#4A4A4A;
1190 1190 font-weight:700;
1191 1191 margin:0 0 0 4px;
1192 1192 padding:6px;
1193 1193 }
1194 1194
1195 1195 #content div.box div.pagination-wh span.pager_curpage {
1196 1196 height:1%;
1197 1197 float:left;
1198 1198 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1199 1199 border-top:1px solid #ccc;
1200 1200 border-left:1px solid #bebebe;
1201 1201 border-right:1px solid #b1b1b1;
1202 1202 border-bottom:1px solid #afafaf;
1203 1203 color:#515151;
1204 1204 font-weight:700;
1205 1205 margin:0 0 0 4px;
1206 1206 padding:6px;
1207 1207 }
1208 1208
1209 1209 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1210 1210 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1211 1211 border-top:1px solid #ccc;
1212 1212 border-left:1px solid #bebebe;
1213 1213 border-right:1px solid #b1b1b1;
1214 1214 border-bottom:1px solid #afafaf;
1215 1215 text-decoration:none;
1216 1216 }
1217 1217
1218 1218 #content div.box div.traffic div.legend {
1219 1219 clear:both;
1220 1220 overflow:hidden;
1221 1221 border-bottom:1px solid #ddd;
1222 1222 margin:0 0 10px;
1223 1223 padding:0 0 10px;
1224 1224 }
1225 1225
1226 1226 #content div.box div.traffic div.legend h6 {
1227 1227 float:left;
1228 1228 border:none;
1229 1229 margin:0;
1230 1230 padding:0;
1231 1231 }
1232 1232
1233 1233 #content div.box div.traffic div.legend li {
1234 1234 list-style:none;
1235 1235 float:left;
1236 1236 font-size:11px;
1237 1237 margin:0;
1238 1238 padding:0 8px 0 4px;
1239 1239 }
1240 1240
1241 1241 #content div.box div.traffic div.legend li.visits {
1242 1242 border-left:12px solid #edc240;
1243 1243 }
1244 1244
1245 1245 #content div.box div.traffic div.legend li.pageviews {
1246 1246 border-left:12px solid #afd8f8;
1247 1247 }
1248 1248
1249 1249 #content div.box div.traffic table {
1250 1250 width:auto;
1251 1251 }
1252 1252
1253 1253 #content div.box div.traffic table td {
1254 1254 background:transparent;
1255 1255 border:none;
1256 1256 padding:2px 3px 3px;
1257 1257 }
1258 1258
1259 1259 #content div.box div.traffic table td.legendLabel {
1260 1260 padding:0 3px 2px;
1261 1261 }
1262 1262
1263 1263 #footer {
1264 1264 clear:both;
1265 1265 overflow:hidden;
1266 1266 text-align:right;
1267 1267 margin:0;
1268 1268 padding:0 30px 4px;
1269 1269 margin:-10px 0 0;
1270 1270 }
1271 1271
1272 1272 #footer div#footer-inner {
1273 1273 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1274 1274 border-top:2px solid #FFFFFF;
1275 1275 }
1276 1276
1277 1277 #footer div#footer-inner p {
1278 1278 padding:15px 25px 15px 0;
1279 1279 color:#FFF;
1280 1280 font-weight:700;
1281 1281 }
1282 1282 #footer div#footer-inner .footer-link {
1283 1283 float:left;
1284 1284 padding-left:10px;
1285 1285 }
1286 1286 #footer div#footer-inner .footer-link a {
1287 1287 color:#FFF;
1288 1288 }
1289 1289
1290 1290 #login div.title {
1291 1291 width:420px;
1292 1292 clear:both;
1293 1293 overflow:hidden;
1294 1294 position:relative;
1295 1295 background:#003367 url("../images/header_inner.png") repeat-x;
1296 1296 margin:0 auto;
1297 1297 padding:0;
1298 1298 }
1299 1299
1300 1300 #login div.inner {
1301 1301 width:380px;
1302 1302 background:#FFF url("../images/login.png") no-repeat top left;
1303 1303 border-top:none;
1304 1304 border-bottom:none;
1305 1305 margin:0 auto;
1306 1306 padding:20px;
1307 1307 }
1308 1308
1309 1309 #login div.form div.fields div.field div.label {
1310 1310 width:173px;
1311 1311 float:left;
1312 1312 text-align:right;
1313 1313 margin:2px 10px 0 0;
1314 1314 padding:5px 0 0 5px;
1315 1315 }
1316 1316
1317 1317 #login div.form div.fields div.field div.input input {
1318 1318 width:176px;
1319 1319 background:#FFF;
1320 1320 border-top:1px solid #b3b3b3;
1321 1321 border-left:1px solid #b3b3b3;
1322 1322 border-right:1px solid #eaeaea;
1323 1323 border-bottom:1px solid #eaeaea;
1324 1324 color:#000;
1325 1325 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1326 1326 font-size:11px;
1327 1327 margin:0;
1328 1328 padding:7px 7px 6px;
1329 1329 }
1330 1330
1331 1331 #login div.form div.fields div.buttons {
1332 1332 clear:both;
1333 1333 overflow:hidden;
1334 1334 border-top:1px solid #DDD;
1335 1335 text-align:right;
1336 1336 margin:0;
1337 1337 padding:10px 0 0;
1338 1338 }
1339 1339
1340 1340 #login div.form div.links {
1341 1341 clear:both;
1342 1342 overflow:hidden;
1343 1343 margin:10px 0 0;
1344 1344 padding:0 0 2px;
1345 1345 }
1346 1346
1347 1347 #register div.title {
1348 1348 clear:both;
1349 1349 overflow:hidden;
1350 1350 position:relative;
1351 1351 background:#003367 url("../images/header_inner.png") repeat-x;
1352 1352 margin:0 auto;
1353 1353 padding:0;
1354 1354 }
1355 1355
1356 1356 #register div.inner {
1357 1357 background:#FFF;
1358 1358 border-top:none;
1359 1359 border-bottom:none;
1360 1360 margin:0 auto;
1361 1361 padding:20px;
1362 1362 }
1363 1363
1364 1364 #register div.form div.fields div.field div.label {
1365 1365 width:135px;
1366 1366 float:left;
1367 1367 text-align:right;
1368 1368 margin:2px 10px 0 0;
1369 1369 padding:5px 0 0 5px;
1370 1370 }
1371 1371
1372 1372 #register div.form div.fields div.field div.input input {
1373 1373 width:300px;
1374 1374 background:#FFF;
1375 1375 border-top:1px solid #b3b3b3;
1376 1376 border-left:1px solid #b3b3b3;
1377 1377 border-right:1px solid #eaeaea;
1378 1378 border-bottom:1px solid #eaeaea;
1379 1379 color:#000;
1380 1380 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1381 1381 font-size:11px;
1382 1382 margin:0;
1383 1383 padding:7px 7px 6px;
1384 1384 }
1385 1385
1386 1386 #register div.form div.fields div.buttons {
1387 1387 clear:both;
1388 1388 overflow:hidden;
1389 1389 border-top:1px solid #DDD;
1390 1390 text-align:left;
1391 1391 margin:0;
1392 1392 padding:10px 0 0 150px;
1393 1393 }
1394 1394
1395 1395 #register div.form div.fields div.buttons div.highlight input.ui-button {
1396 1396 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1397 1397 color:#FFF;
1398 1398 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1399 1399 border-style:solid;
1400 1400 border-width:1px;
1401 1401 }
1402 1402
1403 1403 #register div.form div.activation_msg {
1404 1404 padding-top:4px;
1405 1405 padding-bottom:4px;
1406 1406 }
1407 1407
1408 1408 #journal .journal_day{
1409 1409 font-size:20px;
1410 1410 padding:10px 0px;
1411 1411 border-bottom:2px solid #DDD;
1412 1412 margin-left:10px;
1413 1413 margin-right:10px;
1414 1414 }
1415 1415
1416 1416 #journal .journal_container{
1417 1417 padding:5px;
1418 1418 clear:both;
1419 1419 margin:0px 5px 0px 10px;
1420 1420 }
1421 1421
1422 1422 #journal .journal_action_container{
1423 1423 padding-left:38px;
1424 1424 }
1425 1425
1426 1426 #journal .journal_user{
1427 1427 color: #747474;
1428 1428 font-size: 14px;
1429 1429 font-weight: bold;
1430 1430 height: 30px;
1431 1431 }
1432 1432 #journal .journal_icon{
1433 1433 clear: both;
1434 1434 float: left;
1435 1435 padding-right: 4px;
1436 1436 padding-top: 3px;
1437 1437 }
1438 1438 #journal .journal_action{
1439 1439 padding-top:4px;
1440 1440 min-height:2px;
1441 1441 float:left
1442 1442 }
1443 1443 #journal .journal_action_params{
1444 1444 clear: left;
1445 1445 padding-left: 22px;
1446 1446 }
1447 1447 #journal .journal_repo{
1448 1448 float: left;
1449 1449 margin-left: 6px;
1450 1450 padding-top: 3px;
1451 1451 }
1452 1452 #journal .date{
1453 1453 clear: both;
1454 1454 color: #777777;
1455 1455 font-size: 11px;
1456 1456 padding-left: 22px;
1457 1457 }
1458 1458 #journal .journal_repo .journal_repo_name{
1459 1459 font-weight: bold;
1460 1460 font-size: 1.1em;
1461 1461 }
1462 1462 #journal .compare_view{
1463 1463 padding: 5px 0px 5px 0px;
1464 1464 width: 95px;
1465 1465 }
1466 1466 .journal_highlight{
1467 1467 font-weight: bold;
1468 1468 padding: 0 2px;
1469 1469 vertical-align: bottom;
1470 1470 }
1471 1471 .trending_language_tbl,.trending_language_tbl td {
1472 1472 border:0 !important;
1473 1473 margin:0 !important;
1474 1474 padding:0 !important;
1475 1475 }
1476 1476
1477 1477 .trending_language {
1478 1478 background-color:#003367;
1479 1479 color:#FFF;
1480 1480 display:block;
1481 1481 min-width:20px;
1482 1482 text-decoration:none;
1483 1483 height:12px;
1484 1484 margin-bottom:4px;
1485 1485 margin-left:5px;
1486 1486 white-space:pre;
1487 1487 padding:3px;
1488 1488 }
1489 1489
1490 1490 h3.files_location {
1491 1491 font-size:1.8em;
1492 1492 font-weight:700;
1493 1493 border-bottom:none !important;
1494 1494 margin:10px 0 !important;
1495 1495 }
1496 1496
1497 1497 #files_data dl dt {
1498 1498 float:left;
1499 1499 width:115px;
1500 1500 margin:0 !important;
1501 1501 padding:5px;
1502 1502 }
1503 1503
1504 1504 #files_data dl dd {
1505 1505 margin:0 !important;
1506 1506 padding:5px !important;
1507 1507 }
1508 1508
1509 1509 #changeset_content {
1510 1510 border:1px solid #CCC;
1511 1511 padding:5px;
1512 1512 }
1513 1513 #changeset_compare_view_content{
1514 1514 border:1px solid #CCC;
1515 1515 padding:5px;
1516 1516 }
1517 1517
1518 1518 #changeset_content .container {
1519 1519 min-height:120px;
1520 1520 font-size:1.2em;
1521 1521 overflow:hidden;
1522 1522 }
1523 1523
1524 1524 #changeset_compare_view_content .compare_view_commits{
1525 1525 width: auto !important;
1526 1526 }
1527 1527
1528 1528 #changeset_compare_view_content .compare_view_commits td{
1529 1529 padding:0px 0px 0px 12px !important;
1530 1530 }
1531 1531
1532 1532 #changeset_content .container .right {
1533 1533 float:right;
1534 1534 width:25%;
1535 1535 text-align:right;
1536 1536 }
1537 1537
1538 1538 #changeset_content .container .left .message {
1539 1539 font-style:italic;
1540 1540 color:#556CB5;
1541 1541 white-space:pre-wrap;
1542 1542 }
1543 1543
1544 1544 .cs_files .cur_cs{
1545 1545 margin:10px 2px;
1546 1546 font-weight: bold;
1547 1547 }
1548 1548
1549 1549 .cs_files .cs_added {
1550 1550 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1551 1551 height:16px;
1552 1552 padding-left:20px;
1553 1553 margin-top:7px;
1554 1554 text-align:left;
1555 1555 }
1556 1556
1557 1557 .cs_files .cs_changed {
1558 1558 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1559 1559 height:16px;
1560 1560 padding-left:20px;
1561 1561 margin-top:7px;
1562 1562 text-align:left;
1563 1563 }
1564 1564
1565 1565 .cs_files .cs_removed {
1566 1566 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1567 1567 height:16px;
1568 1568 padding-left:20px;
1569 1569 margin-top:7px;
1570 1570 text-align:left;
1571 1571 }
1572 1572
1573 1573 #graph {
1574 1574 overflow:hidden;
1575 1575 }
1576 1576
1577 1577 #graph_nodes {
1578 1578 width:160px;
1579 1579 float:left;
1580 1580 margin-left:-50px;
1581 1581 margin-top:5px;
1582 1582 }
1583 1583
1584 1584 #graph_content {
1585 1585 width:800px;
1586 1586 float:left;
1587 1587 }
1588 1588
1589 1589 #graph_content .container_header {
1590 1590 border:1px solid #CCC;
1591 1591 padding:10px;
1592 1592 }
1593 1593 #graph_content #rev_range_container{
1594 1594 padding:10px 0px;
1595 1595 }
1596 1596 #graph_content .container {
1597 1597 border-bottom:1px solid #CCC;
1598 1598 border-left:1px solid #CCC;
1599 1599 border-right:1px solid #CCC;
1600 1600 min-height:80px;
1601 1601 overflow:hidden;
1602 1602 font-size:1.2em;
1603 1603 }
1604 1604
1605 1605 #graph_content .container .right {
1606 1606 float:right;
1607 1607 width:28%;
1608 1608 text-align:right;
1609 1609 padding-bottom:5px;
1610 1610 }
1611 1611
1612 1612 #graph_content .container .left .date {
1613 1613 font-weight:700;
1614 1614 padding-bottom:5px;
1615 1615 }
1616 1616 #graph_content .container .left .date span{
1617 1617 vertical-align: text-top;
1618 1618 }
1619 1619
1620 1620 #graph_content .container .left .message {
1621 1621 font-size:100%;
1622 1622 padding-top:3px;
1623 1623 white-space:pre-wrap;
1624 1624 }
1625 1625
1626 1626 .right div {
1627 1627 clear:both;
1628 1628 }
1629 1629
1630 1630 .right .changes .added,.changed,.removed {
1631 1631 border:1px solid #DDD;
1632 1632 display:block;
1633 1633 float:right;
1634 1634 text-align:center;
1635 1635 min-width:15px;
1636 1636 cursor: help;
1637 1637 }
1638 1638
1639 1639 .right .changes .added {
1640 1640 background:#BFB;
1641 1641 }
1642 1642
1643 1643 .right .changes .changed {
1644 1644 background:#FD8;
1645 1645 }
1646 1646
1647 1647 .right .changes .removed {
1648 1648 background:#F88;
1649 1649 }
1650 1650
1651 1651 .right .merge {
1652 1652 vertical-align:top;
1653 1653 font-size:0.75em;
1654 1654 font-weight:700;
1655 1655 }
1656 1656
1657 1657 .right .parent {
1658 1658 font-size:90%;
1659 1659 font-family:monospace;
1660 1660 }
1661 1661
1662 1662 .right .logtags .branchtag {
1663 1663 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1664 1664 display:block;
1665 1665 font-size:0.8em;
1666 1666 padding:11px 16px 0 0;
1667 1667 }
1668 1668
1669 1669 .right .logtags .tagtag {
1670 1670 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1671 1671 display:block;
1672 1672 font-size:0.8em;
1673 1673 padding:11px 16px 0 0;
1674 1674 }
1675 1675
1676 1676 div.browserblock {
1677 1677 overflow:hidden;
1678 1678 border:1px solid #ccc;
1679 1679 background:#f8f8f8;
1680 1680 font-size:100%;
1681 1681 line-height:125%;
1682 1682 padding:0;
1683 1683 }
1684 1684
1685 1685 div.browserblock .browser-header {
1686 1686 background:#FFF;
1687 1687 padding:10px 0px 35px 0px;
1688 1688 width: 100%;
1689 1689 }
1690 1690 div.browserblock .browser-nav {
1691 1691 float:left
1692 1692 }
1693 1693
1694 1694 div.browserblock .browser-branch {
1695 1695 padding:10px 0 0 0;
1696 1696 float:left;
1697 1697 }
1698 1698 div.browserblock .browser-branch label {
1699 1699 color:#4A4A4A;
1700 1700 vertical-align:text-top;
1701 1701 }
1702 1702
1703 1703 div.browserblock .browser-header span {
1704 1704 margin-left:25px;
1705 1705 font-weight:700;
1706 1706 }
1707 1707
1708 1708 div.browserblock .browser-body {
1709 1709 background:#EEE;
1710 1710 border-top:1px solid #CCC;
1711 1711 }
1712 1712
1713 1713 table.code-browser {
1714 1714 border-collapse:collapse;
1715 1715 width:100%;
1716 1716 }
1717 1717
1718 1718 table.code-browser tr {
1719 1719 margin:3px;
1720 1720 }
1721 1721
1722 1722 table.code-browser thead th {
1723 1723 background-color:#EEE;
1724 1724 height:20px;
1725 1725 font-size:1.1em;
1726 1726 font-weight:700;
1727 1727 text-align:left;
1728 1728 padding-left:10px;
1729 1729 }
1730 1730
1731 1731 table.code-browser tbody td {
1732 1732 padding-left:10px;
1733 1733 height:20px;
1734 1734 }
1735 1735
1736 1736 table.code-browser .browser-file {
1737 1737 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1738 1738 height:16px;
1739 1739 padding-left:20px;
1740 1740 text-align:left;
1741 1741 }
1742 1742 .diffblock .changeset_file{
1743 1743 background:url("../images/icons/file.png") no-repeat scroll 3px;
1744 1744 height:16px;
1745 1745 padding-left:22px;
1746 1746 text-align:left;
1747 1747 font-size: 14px;
1748 1748 }
1749 1749
1750 1750 .diffblock .changeset_header{
1751 1751 margin-left: 6px !important;
1752 1752 }
1753 1753
1754 1754 table.code-browser .browser-dir {
1755 1755 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1756 1756 height:16px;
1757 1757 padding-left:20px;
1758 1758 text-align:left;
1759 1759 }
1760 1760
1761 1761 .box .search {
1762 1762 clear:both;
1763 1763 overflow:hidden;
1764 1764 margin:0;
1765 1765 padding:0 20px 10px;
1766 1766 }
1767 1767
1768 1768 .box .search div.search_path {
1769 1769 background:none repeat scroll 0 0 #EEE;
1770 1770 border:1px solid #CCC;
1771 1771 color:blue;
1772 1772 margin-bottom:10px;
1773 1773 padding:10px 0;
1774 1774 }
1775 1775
1776 1776 .box .search div.search_path div.link {
1777 1777 font-weight:700;
1778 1778 margin-left:25px;
1779 1779 }
1780 1780
1781 1781 .box .search div.search_path div.link a {
1782 1782 color:#003367;
1783 1783 cursor:pointer;
1784 1784 text-decoration:none;
1785 1785 }
1786 1786
1787 1787 #path_unlock {
1788 1788 color:red;
1789 1789 font-size:1.2em;
1790 1790 padding-left:4px;
1791 1791 }
1792 1792
1793 1793 .info_box * {
1794 1794 background:url("../images/pager.png") repeat-x scroll 0 0 #EBEBEB;
1795 1795 color:#4A4A4A;
1796 1796 font-weight:700;
1797 1797 height:1%;
1798 1798 display:inline;
1799 1799 border-color:#DEDEDE #C4C4C4 #C4C4C4 #CFCFCF;
1800 1800 border-style:solid;
1801 1801 border-width:1px;
1802 1802 padding:4px 6px;
1803 1803 }
1804 1804
1805 1805 .info_box span {
1806 1806 margin-left:3px;
1807 1807 margin-right:3px;
1808 1808 }
1809 1809
1810 1810 .info_box input#at_rev {
1811 1811 text-align:center;
1812 1812 padding:5px 3px 3px 2px;
1813 1813 }
1814 1814
1815 1815 .info_box input#view {
1816 1816 text-align:center;
1817 1817 padding:4px 3px 2px 2px;
1818 1818 }
1819 1819
1820 1820 .yui-overlay,.yui-panel-container {
1821 1821 visibility:hidden;
1822 1822 position:absolute;
1823 1823 z-index:2;
1824 1824 }
1825 1825
1826 1826 .yui-tt {
1827 1827 visibility:hidden;
1828 1828 position:absolute;
1829 1829 color:#666;
1830 1830 background-color:#FFF;
1831 1831 font-family:arial, helvetica, verdana, sans-serif;
1832 1832 border:2px solid #003367;
1833 1833 font:100% sans-serif;
1834 1834 width:auto;
1835 1835 opacity:1px;
1836 1836 padding:8px;
1837 1837 white-space: pre;
1838 1838 -webkit-border-radius: 8px 8px 8px 8px;
1839 1839 -khtml-border-radius: 8px 8px 8px 8px;
1840 1840 -moz-border-radius: 8px 8px 8px 8px;
1841 1841 border-radius: 8px 8px 8px 8px;
1842 1842 }
1843 1843
1844 1844 .ac {
1845 1845 vertical-align:top;
1846 1846 }
1847 1847
1848 1848 .ac .yui-ac {
1849 1849 position:relative;
1850 1850 font-family:arial;
1851 1851 font-size:100%;
1852 1852 }
1853 1853
1854 1854 .ac .perm_ac {
1855 1855 width:15em;
1856 1856 }
1857 1857
1858 1858 .ac .yui-ac-input {
1859 1859 width:100%;
1860 1860 }
1861 1861
1862 1862 .ac .yui-ac-container {
1863 1863 position:absolute;
1864 1864 top:1.6em;
1865 1865 width:100%;
1866 1866 }
1867 1867
1868 1868 .ac .yui-ac-content {
1869 1869 position:absolute;
1870 1870 width:100%;
1871 1871 border:1px solid gray;
1872 1872 background:#fff;
1873 1873 overflow:hidden;
1874 1874 z-index:9050;
1875 1875 }
1876 1876
1877 1877 .ac .yui-ac-shadow {
1878 1878 position:absolute;
1879 1879 width:100%;
1880 1880 background:#000;
1881 1881 -moz-opacity:0.1px;
1882 1882 opacity:.10;
1883 1883 filter:alpha(opacity = 10);
1884 1884 z-index:9049;
1885 1885 margin:.3em;
1886 1886 }
1887 1887
1888 1888 .ac .yui-ac-content ul {
1889 1889 width:100%;
1890 1890 margin:0;
1891 1891 padding:0;
1892 1892 }
1893 1893
1894 1894 .ac .yui-ac-content li {
1895 1895 cursor:default;
1896 1896 white-space:nowrap;
1897 1897 margin:0;
1898 1898 padding:2px 5px;
1899 1899 }
1900 1900
1901 1901 .ac .yui-ac-content li.yui-ac-prehighlight {
1902 1902 background:#B3D4FF;
1903 1903 }
1904 1904
1905 1905 .ac .yui-ac-content li.yui-ac-highlight {
1906 1906 background:#556CB5;
1907 1907 color:#FFF;
1908 1908 }
1909 1909
1910 1910 .follow{
1911 1911 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
1912 1912 height: 16px;
1913 1913 width: 20px;
1914 1914 cursor: pointer;
1915 1915 display: block;
1916 1916 float: right;
1917 1917 margin-top: 2px;
1918 1918 }
1919 1919
1920 1920 .following{
1921 1921 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
1922 1922 height: 16px;
1923 1923 width: 20px;
1924 1924 cursor: pointer;
1925 1925 display: block;
1926 1926 float: right;
1927 1927 margin-top: 2px;
1928 1928 }
1929 1929
1930 1930 .currently_following{
1931 1931 padding-left: 10px;
1932 1932 padding-bottom:5px;
1933 1933 }
1934 1934
1935 1935 .add_icon {
1936 1936 background:url("../images/icons/add.png") no-repeat scroll 3px;
1937 1937 height:16px;
1938 1938 padding-left:20px;
1939 1939 padding-top:1px;
1940 1940 text-align:left;
1941 1941 }
1942 1942
1943 1943 .edit_icon {
1944 1944 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1945 1945 height:16px;
1946 1946 padding-left:20px;
1947 1947 padding-top:1px;
1948 1948 text-align:left;
1949 1949 }
1950 1950
1951 1951 .delete_icon {
1952 1952 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1953 1953 height:16px;
1954 1954 padding-left:20px;
1955 1955 padding-top:1px;
1956 1956 text-align:left;
1957 1957 }
1958 1958
1959 1959 .refresh_icon {
1960 1960 background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
1961 1961 height:16px;
1962 1962 padding-left:20px;
1963 1963 padding-top:1px;
1964 1964 text-align:left;
1965 1965 }
1966 1966
1967 .pull_icon {
1968 background:url("../images/icons/connect.png") no-repeat scroll 3px;
1969 height:16px;
1970 padding-left:20px;
1971 padding-top:1px;
1972 text-align:left;
1973 }
1974
1967 1975 .rss_icon {
1968 1976 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
1969 1977 height:16px;
1970 1978 padding-left:20px;
1971 1979 padding-top:1px;
1972 1980 text-align:left;
1973 1981 }
1974 1982
1975 1983 .atom_icon {
1976 1984 background:url("../images/icons/atom.png") no-repeat scroll 3px;
1977 1985 height:16px;
1978 1986 padding-left:20px;
1979 1987 padding-top:1px;
1980 1988 text-align:left;
1981 1989 }
1982 1990
1983 1991 .archive_icon {
1984 1992 background:url("../images/icons/compress.png") no-repeat scroll 3px;
1985 1993 height:16px;
1986 1994 padding-left:20px;
1987 1995 text-align:left;
1988 1996 padding-top:1px;
1989 1997 }
1990 1998 .start_following_icon {
1991 1999 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
1992 2000 height:16px;
1993 2001 padding-left:20px;
1994 2002 text-align:left;
1995 2003 padding-top:1px;
1996 2004 }
1997 2005 .stop_following_icon {
1998 2006 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
1999 2007 height:16px;
2000 2008 padding-left:20px;
2001 2009 text-align:left;
2002 2010 padding-top:1px;
2003 2011 }
2004 2012
2005 2013 .action_button {
2006 2014 border:0;
2007 2015 display:block;
2008 2016 }
2009 2017
2010 2018 .action_button:hover {
2011 2019 border:0;
2012 2020 text-decoration:underline;
2013 2021 cursor:pointer;
2014 2022 }
2015 2023
2016 2024 #switch_repos {
2017 2025 position:absolute;
2018 2026 height:25px;
2019 2027 z-index:1;
2020 2028 }
2021 2029
2022 2030 #switch_repos select {
2023 2031 min-width:150px;
2024 2032 max-height:250px;
2025 2033 z-index:1;
2026 2034 }
2027 2035
2028 2036 .breadcrumbs {
2029 2037 border:medium none;
2030 2038 color:#FFF;
2031 2039 float:left;
2032 2040 text-transform:uppercase;
2033 2041 font-weight:700;
2034 2042 font-size:14px;
2035 2043 margin:0;
2036 2044 padding:11px 0 11px 10px;
2037 2045 }
2038 2046
2039 2047 .breadcrumbs a {
2040 2048 color:#FFF;
2041 2049 }
2042 2050
2043 2051 .flash_msg ul {
2044 2052 margin:0;
2045 2053 padding:0 0 10px;
2046 2054 }
2047 2055
2048 2056 .error_msg {
2049 2057 background-color:#FFCFCF;
2050 2058 background-image:url("../images/icons/error_msg.png");
2051 2059 border:1px solid #FF9595;
2052 2060 color:#C30;
2053 2061 }
2054 2062
2055 2063 .warning_msg {
2056 2064 background-color:#FFFBCC;
2057 2065 background-image:url("../images/icons/warning_msg.png");
2058 2066 border:1px solid #FFF35E;
2059 2067 color:#C69E00;
2060 2068 }
2061 2069
2062 2070 .success_msg {
2063 2071 background-color:#D5FFCF;
2064 2072 background-image:url("../images/icons/success_msg.png");
2065 2073 border:1px solid #97FF88;
2066 2074 color:#090;
2067 2075 }
2068 2076
2069 2077 .notice_msg {
2070 2078 background-color:#DCE3FF;
2071 2079 background-image:url("../images/icons/notice_msg.png");
2072 2080 border:1px solid #93A8FF;
2073 2081 color:#556CB5;
2074 2082 }
2075 2083
2076 2084 .success_msg,.error_msg,.notice_msg,.warning_msg {
2077 2085 background-position:10px center;
2078 2086 background-repeat:no-repeat;
2079 2087 font-size:12px;
2080 2088 font-weight:700;
2081 2089 min-height:14px;
2082 2090 line-height:14px;
2083 2091 margin-bottom:0;
2084 2092 margin-top:0;
2085 2093 display:block;
2086 2094 overflow:auto;
2087 2095 padding:6px 10px 6px 40px;
2088 2096 }
2089 2097
2090 2098 #msg_close {
2091 2099 background:transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
2092 2100 cursor:pointer;
2093 2101 height:16px;
2094 2102 position:absolute;
2095 2103 right:5px;
2096 2104 top:5px;
2097 2105 width:16px;
2098 2106 }
2099 2107
2100 2108 div#legend_container table,div#legend_choices table {
2101 2109 width:auto !important;
2102 2110 }
2103 2111
2104 2112 table#permissions_manage {
2105 2113 width:0 !important;
2106 2114 }
2107 2115
2108 2116 table#permissions_manage span.private_repo_msg {
2109 2117 font-size:0.8em;
2110 2118 opacity:0.6px;
2111 2119 }
2112 2120
2113 2121 table#permissions_manage td.private_repo_msg {
2114 2122 font-size:0.8em;
2115 2123 }
2116 2124
2117 2125 table#permissions_manage tr#add_perm_input td {
2118 2126 vertical-align:middle;
2119 2127 }
2120 2128
2121 2129 div.gravatar {
2122 2130 background-color:#FFF;
2123 2131 border:1px solid #D0D0D0;
2124 2132 float:left;
2125 2133 margin-right:0.7em;
2126 2134 padding:2px 2px 0;
2127 2135 }
2128 2136
2129 2137 #header,#content,#footer {
2130 2138 min-width:1024px;
2131 2139 }
2132 2140
2133 2141 #content {
2134 2142 min-height:100%;
2135 2143 clear:both;
2136 2144 overflow:hidden;
2137 2145 padding:14px 30px;
2138 2146 }
2139 2147
2140 2148 #content div.box div.title div.search {
2141 2149 background:url("../images/title_link.png") no-repeat top left;
2142 2150 border-left:1px solid #316293;
2143 2151 }
2144 2152
2145 2153 #content div.box div.title div.search div.input input {
2146 2154 border:1px solid #316293;
2147 2155 }
2148 2156
2149 2157 #content div.box div.title div.search div.button input.ui-button {
2150 2158 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2151 2159 border:1px solid #316293;
2152 2160 border-left:none;
2153 2161 color:#FFF;
2154 2162 }
2155 2163
2156 2164 #content div.box div.title div.search div.button input.ui-state-hover {
2157 2165 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2158 2166 border:1px solid #316293;
2159 2167 border-left:none;
2160 2168 color:#FFF;
2161 2169 }
2162 2170
2163 2171 #content div.box div.form div.fields div.field div.highlight .ui-button {
2164 2172 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2165 2173 border-top:1px solid #5c91a4;
2166 2174 border-left:1px solid #2a6f89;
2167 2175 border-right:1px solid #2b7089;
2168 2176 border-bottom:1px solid #1a6480;
2169 2177 color:#fff;
2170 2178 }
2171 2179
2172 2180 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
2173 2181 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2174 2182 border-top:1px solid #78acbf;
2175 2183 border-left:1px solid #34819e;
2176 2184 border-right:1px solid #35829f;
2177 2185 border-bottom:1px solid #257897;
2178 2186 color:#fff;
2179 2187 }
2180 2188
2181 2189 ins,div.options a:hover {
2182 2190 text-decoration:none;
2183 2191 }
2184 2192
2185 2193 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2186 2194 border:none;
2187 2195 }
2188 2196
2189 2197 img.icon,.right .merge img {
2190 2198 vertical-align:bottom;
2191 2199 }
2192 2200
2193 2201 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2194 2202 float:right;
2195 2203 margin:0;
2196 2204 padding:0;
2197 2205 }
2198 2206
2199 2207 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2200 2208 float:left;
2201 2209 }
2202 2210
2203 2211 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2204 2212 display:none;
2205 2213 }
2206 2214
2207 2215 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded {
2208 2216 display:block;
2209 2217 }
2210 2218
2211 2219 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2212 2220 color:#bfe3ff;
2213 2221 }
2214 2222
2215 2223 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal {
2216 2224 margin:10px 24px 10px 44px;
2217 2225 }
2218 2226
2219 2227 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2220 2228 clear:both;
2221 2229 overflow:hidden;
2222 2230 margin:0;
2223 2231 padding:0 20px 10px;
2224 2232 }
2225 2233
2226 2234 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2227 2235 clear:both;
2228 2236 overflow:hidden;
2229 2237 margin:0;
2230 2238 padding:0;
2231 2239 }
2232 2240
2233 2241 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span {
2234 2242 height:1%;
2235 2243 display:block;
2236 2244 color:#363636;
2237 2245 margin:0;
2238 2246 padding:2px 0 0;
2239 2247 }
2240 2248
2241 2249 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error {
2242 2250 background:#FBE3E4;
2243 2251 border-top:1px solid #e1b2b3;
2244 2252 border-left:1px solid #e1b2b3;
2245 2253 border-right:1px solid #FBC2C4;
2246 2254 border-bottom:1px solid #FBC2C4;
2247 2255 }
2248 2256
2249 2257 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success {
2250 2258 background:#E6EFC2;
2251 2259 border-top:1px solid #cebb98;
2252 2260 border-left:1px solid #cebb98;
2253 2261 border-right:1px solid #c6d880;
2254 2262 border-bottom:1px solid #c6d880;
2255 2263 }
2256 2264
2257 2265 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input {
2258 2266 margin:0;
2259 2267 }
2260 2268
2261 2269 #content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios{
2262 2270 margin:0 0 0 0px !important;
2263 2271 padding:0;
2264 2272 }
2265 2273
2266 2274 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios {
2267 2275 margin:0 0 0 200px;
2268 2276 padding:0;
2269 2277 }
2270 2278
2271 2279
2272 2280 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover {
2273 2281 color:#000;
2274 2282 text-decoration:none;
2275 2283 }
2276 2284
2277 2285 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2278 2286 border:1px solid #666;
2279 2287 }
2280 2288
2281 2289 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio {
2282 2290 clear:both;
2283 2291 overflow:hidden;
2284 2292 margin:0;
2285 2293 padding:8px 0 2px;
2286 2294 }
2287 2295
2288 2296 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input {
2289 2297 float:left;
2290 2298 margin:0;
2291 2299 }
2292 2300
2293 2301 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label {
2294 2302 height:1%;
2295 2303 display:block;
2296 2304 float:left;
2297 2305 margin:2px 0 0 4px;
2298 2306 }
2299 2307
2300 2308 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2301 2309 color:#000;
2302 2310 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2303 2311 font-size:11px;
2304 2312 font-weight:700;
2305 2313 margin:0;
2306 2314 }
2307 2315
2308 2316 div.form div.fields div.field div.button .ui-button,#content div.box div.form div.fields div.buttons input.ui-button {
2309 2317 background:#e5e3e3 url("../images/button.png") repeat-x;
2310 2318 border-top:1px solid #DDD;
2311 2319 border-left:1px solid #c6c6c6;
2312 2320 border-right:1px solid #DDD;
2313 2321 border-bottom:1px solid #c6c6c6;
2314 2322 color:#515151;
2315 2323 outline:none;
2316 2324 margin:0;
2317 2325 padding:6px 12px;
2318 2326 }
2319 2327
2320 2328 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2321 2329 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2322 2330 border-top:1px solid #ccc;
2323 2331 border-left:1px solid #bebebe;
2324 2332 border-right:1px solid #b1b1b1;
2325 2333 border-bottom:1px solid #afafaf;
2326 2334 color:#515151;
2327 2335 outline:none;
2328 2336 margin:0;
2329 2337 padding:6px 12px;
2330 2338 }
2331 2339
2332 2340 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2333 2341 display:inline;
2334 2342 }
2335 2343
2336 2344 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2337 2345 margin:10px 0 0 200px;
2338 2346 padding:0;
2339 2347 }
2340 2348
2341 2349 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons {
2342 2350 margin:10px 0 0;
2343 2351 }
2344 2352
2345 2353 #content div.box table td.user,#content div.box table td.address {
2346 2354 width:10%;
2347 2355 text-align:center;
2348 2356 }
2349 2357
2350 2358 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link {
2351 2359 text-align:right;
2352 2360 margin:6px 0 0;
2353 2361 padding:0;
2354 2362 }
2355 2363
2356 2364 #content div.box div.action div.button input.ui-button,#login div.form div.fields div.buttons input.ui-button,#register div.form div.fields div.buttons input.ui-button {
2357 2365 background:#e5e3e3 url("../images/button.png") repeat-x;
2358 2366 border-top:1px solid #DDD;
2359 2367 border-left:1px solid #c6c6c6;
2360 2368 border-right:1px solid #DDD;
2361 2369 border-bottom:1px solid #c6c6c6;
2362 2370 color:#515151;
2363 2371 margin:0;
2364 2372 padding:6px 12px;
2365 2373 }
2366 2374
2367 2375 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover {
2368 2376 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2369 2377 border-top:1px solid #ccc;
2370 2378 border-left:1px solid #bebebe;
2371 2379 border-right:1px solid #b1b1b1;
2372 2380 border-bottom:1px solid #afafaf;
2373 2381 color:#515151;
2374 2382 margin:0;
2375 2383 padding:6px 12px;
2376 2384 }
2377 2385
2378 2386 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2379 2387 text-align:left;
2380 2388 float:left;
2381 2389 margin:0;
2382 2390 padding:0;
2383 2391 }
2384 2392
2385 2393 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2386 2394 height:1%;
2387 2395 display:block;
2388 2396 float:left;
2389 2397 background:#ebebeb url("../images/pager.png") repeat-x;
2390 2398 border-top:1px solid #dedede;
2391 2399 border-left:1px solid #cfcfcf;
2392 2400 border-right:1px solid #c4c4c4;
2393 2401 border-bottom:1px solid #c4c4c4;
2394 2402 color:#4A4A4A;
2395 2403 font-weight:700;
2396 2404 margin:0;
2397 2405 padding:6px 8px;
2398 2406 }
2399 2407
2400 2408 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2401 2409 color:#B4B4B4;
2402 2410 padding:6px;
2403 2411 }
2404 2412
2405 2413 #login,#register {
2406 2414 width:520px;
2407 2415 margin:10% auto 0;
2408 2416 padding:0;
2409 2417 }
2410 2418
2411 2419 #login div.color,#register div.color {
2412 2420 clear:both;
2413 2421 overflow:hidden;
2414 2422 background:#FFF;
2415 2423 margin:10px auto 0;
2416 2424 padding:3px 3px 3px 0;
2417 2425 }
2418 2426
2419 2427 #login div.color a,#register div.color a {
2420 2428 width:20px;
2421 2429 height:20px;
2422 2430 display:block;
2423 2431 float:left;
2424 2432 margin:0 0 0 3px;
2425 2433 padding:0;
2426 2434 }
2427 2435
2428 2436 #login div.title h5,#register div.title h5 {
2429 2437 color:#fff;
2430 2438 margin:10px;
2431 2439 padding:0;
2432 2440 }
2433 2441
2434 2442 #login div.form div.fields div.field,#register div.form div.fields div.field {
2435 2443 clear:both;
2436 2444 overflow:hidden;
2437 2445 margin:0;
2438 2446 padding:0 0 10px;
2439 2447 }
2440 2448
2441 2449 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2442 2450 height:1%;
2443 2451 display:block;
2444 2452 color:red;
2445 2453 margin:8px 0 0;
2446 2454 padding:0;
2447 2455 max-width: 320px;
2448 2456 }
2449 2457
2450 2458 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2451 2459 color:#000;
2452 2460 font-weight:700;
2453 2461 }
2454 2462
2455 2463 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2456 2464 float:left;
2457 2465 margin:0;
2458 2466 padding:0;
2459 2467 }
2460 2468
2461 2469 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2462 2470 margin:0 0 0 184px;
2463 2471 padding:0;
2464 2472 }
2465 2473
2466 2474 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2467 2475 color:#565656;
2468 2476 font-weight:700;
2469 2477 }
2470 2478
2471 2479 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2472 2480 color:#000;
2473 2481 font-size:1em;
2474 2482 font-weight:700;
2475 2483 font-family:Verdana, Helvetica, Sans-Serif;
2476 2484 margin:0;
2477 2485 }
2478 2486
2479 2487 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2480 2488 width:600px;
2481 2489 }
2482 2490
2483 2491 #changeset_content .container .left,#graph_content .container .left {
2484 2492 float:left;
2485 2493 width:70%;
2486 2494 padding-left:5px;
2487 2495 }
2488 2496
2489 2497 #changeset_content .container .left .date,.ac .match {
2490 2498 font-weight:700;
2491 2499 padding-top: 5px;
2492 2500 padding-bottom:5px;
2493 2501 }
2494 2502
2495 2503 div#legend_container table td,div#legend_choices table td {
2496 2504 border:none !important;
2497 2505 height:20px !important;
2498 2506 padding:0 !important;
2499 2507 }
2500 2508
2501 2509 #q_filter{
2502 2510 border:0 none;
2503 2511 color:#AAAAAA;
2504 2512 margin-bottom:-4px;
2505 2513 margin-top:-4px;
2506 2514 padding-left:3px;
2507 2515 }
2508 2516
@@ -1,368 +1,383 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${h.link_to(_('Repositories'),h.url('repos'))}
12 12 &raquo;
13 13 ${_('edit')} &raquo; ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
14 14 </%def>
15 15
16 16 <%def name="page_nav()">
17 17 ${self.menu('admin')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21 <div class="box box-left">
22 22 <!-- box / title -->
23 23 <div class="title">
24 24 ${self.breadcrumbs()}
25 25 </div>
26 26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 27 <div class="form">
28 28 <!-- fields -->
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label">
32 32 <label for="repo_name">${_('Name')}:</label>
33 33 </div>
34 34 <div class="input">
35 35 ${h.text('repo_name',class_="medium")}
36 36 </div>
37 37 </div>
38 38 <div class="field">
39 39 <div class="label">
40 40 <label for="clone_uri">${_('Clone uri')}:</label>
41 41 </div>
42 42 <div class="input">
43 43 ${h.text('clone_uri',class_="small")}
44 44 </div>
45 45 </div>
46 46 <div class="field">
47 47 <div class="label">
48 48 <label for="repo_group">${_('Repository group')}:</label>
49 49 </div>
50 50 <div class="input">
51 51 ${h.select('repo_group','',c.repo_groups,class_="medium")}
52 52 <span>${h.link_to(_('add new group'),h.url(''))}</span>
53 53 </div>
54 54 </div>
55 55 <div class="field">
56 56 <div class="label">
57 57 <label for="repo_type">${_('Type')}:</label>
58 58 </div>
59 59 <div class="input">
60 60 ${h.select('repo_type','hg',c.backends,class_="medium")}
61 61 </div>
62 62 </div>
63 63 <div class="field">
64 64 <div class="label label-textarea">
65 65 <label for="description">${_('Description')}:</label>
66 66 </div>
67 67 <div class="textarea text-area editor">
68 68 ${h.textarea('description',cols=23,rows=5)}
69 69 </div>
70 70 </div>
71 71
72 72 <div class="field">
73 73 <div class="label label-checkbox">
74 74 <label for="private">${_('Private')}:</label>
75 75 </div>
76 76 <div class="checkboxes">
77 77 ${h.checkbox('private',value="True")}
78 78 </div>
79 79 </div>
80 80 <div class="field">
81 81 <div class="label label-checkbox">
82 82 <label for="enable_statistics">${_('Enable statistics')}:</label>
83 83 </div>
84 84 <div class="checkboxes">
85 85 ${h.checkbox('enable_statistics',value="True")}
86 86 </div>
87 87 </div>
88 88 <div class="field">
89 89 <div class="label label-checkbox">
90 90 <label for="enable_downloads">${_('Enable downloads')}:</label>
91 91 </div>
92 92 <div class="checkboxes">
93 93 ${h.checkbox('enable_downloads',value="True")}
94 94 </div>
95 95 </div>
96 96 <div class="field">
97 97 <div class="label">
98 98 <label for="user">${_('Owner')}:</label>
99 99 </div>
100 100 <div class="input input-small ac">
101 101 <div class="perm_ac">
102 102 ${h.text('user',class_='yui-ac-input')}
103 103 <div id="owner_container"></div>
104 104 </div>
105 105 </div>
106 106 </div>
107 107
108 108 <div class="field">
109 109 <div class="label">
110 110 <label for="input">${_('Permissions')}:</label>
111 111 </div>
112 112 <div class="input">
113 113 <%include file="repo_edit_perms.html"/>
114 114 </div>
115 115
116 116 <div class="buttons">
117 117 ${h.submit('save','Save',class_="ui-button")}
118 118 ${h.reset('reset','Reset',class_="ui-button")}
119 119 </div>
120 120 </div>
121 121 </div>
122 122 </div>
123 123 ${h.end_form()}
124 124 <script type="text/javascript">
125 125 YAHOO.util.Event.onDOMReady(function(){
126 126 var D = YAHOO.util.Dom;
127 127 if(!D.hasClass('perm_new_member_name','error')){
128 128 D.setStyle('add_perm_input','display','none');
129 129 }
130 130 YAHOO.util.Event.addListener('add_perm','click',function(){
131 131 D.setStyle('add_perm_input','display','');
132 132 D.setStyle('add_perm','opacity','0.6');
133 133 D.setStyle('add_perm','cursor','default');
134 134 });
135 135 });
136 136 </script>
137 137 <script type="text/javascript">
138 138 YAHOO.example.FnMultipleFields = function(){
139 139 var myUsers = ${c.users_array|n};
140 140 var myGroups = ${c.users_groups_array|n};
141 141
142 142 // Define a custom search function for the DataSource of users
143 143 var matchUsers = function(sQuery) {
144 144 // Case insensitive matching
145 145 var query = sQuery.toLowerCase();
146 146 var i=0;
147 147 var l=myUsers.length;
148 148 var matches = [];
149 149
150 150 // Match against each name of each contact
151 151 for(; i<l; i++) {
152 152 contact = myUsers[i];
153 153 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
154 154 (contact.lname.toLowerCase().indexOf(query) > -1) ||
155 155 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
156 156 matches[matches.length] = contact;
157 157 }
158 158 }
159 159 return matches;
160 160 };
161 161
162 162 // Define a custom search function for the DataSource of usersGroups
163 163 var matchGroups = function(sQuery) {
164 164 // Case insensitive matching
165 165 var query = sQuery.toLowerCase();
166 166 var i=0;
167 167 var l=myGroups.length;
168 168 var matches = [];
169 169
170 170 // Match against each name of each contact
171 171 for(; i<l; i++) {
172 172 matched_group = myGroups[i];
173 173 if(matched_group.grname.toLowerCase().indexOf(query) > -1) {
174 174 matches[matches.length] = matched_group;
175 175 }
176 176 }
177 177 return matches;
178 178 };
179 179
180 180 //match all
181 181 var matchAll = function(sQuery){
182 182 u = matchUsers(sQuery);
183 183 g = matchGroups(sQuery);
184 184 return u.concat(g);
185 185 };
186 186
187 187 // DataScheme for members
188 188 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
189 189 memberDS.responseSchema = {
190 190 fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
191 191 };
192 192
193 193 // DataScheme for owner
194 194 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
195 195 ownerDS.responseSchema = {
196 196 fields: ["id", "fname", "lname", "nname"]
197 197 };
198 198
199 199 // Instantiate AutoComplete for perms
200 200 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
201 201 membersAC.useShadow = false;
202 202 membersAC.resultTypeList = false;
203 203
204 204 // Instantiate AutoComplete for owner
205 205 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
206 206 ownerAC.useShadow = false;
207 207 ownerAC.resultTypeList = false;
208 208
209 209
210 210 // Helper highlight function for the formatter
211 211 var highlightMatch = function(full, snippet, matchindex) {
212 212 return full.substring(0, matchindex) +
213 213 "<span class='match'>" +
214 214 full.substr(matchindex, snippet.length) +
215 215 "</span>" +
216 216 full.substring(matchindex + snippet.length);
217 217 };
218 218
219 219 // Custom formatter to highlight the matching letters
220 220 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
221 221 var query = sQuery.toLowerCase();
222 222
223 223 if (oResultData.grname != undefined){
224 224 var grname = oResultData.grname;
225 225 var grmembers = oResultData.grmembers;
226 226 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
227 227 var grprefix = "${_('Group')}: ";
228 228 var grsuffix = " ("+grmembers+" ${_('members')})";
229 229
230 230 if (grnameMatchIndex > -1){
231 231 return grprefix+highlightMatch(grname,query,grnameMatchIndex)+grsuffix;
232 232 }
233 233
234 234 return grprefix+oResultData.grname+grsuffix;
235 235 }
236 236 else if(oResultData.fname != undefined){
237 237
238 238 var fname = oResultData.fname,
239 239 lname = oResultData.lname,
240 240 nname = oResultData.nname || "", // Guard against null value
241 241 fnameMatchIndex = fname.toLowerCase().indexOf(query),
242 242 lnameMatchIndex = lname.toLowerCase().indexOf(query),
243 243 nnameMatchIndex = nname.toLowerCase().indexOf(query),
244 244 displayfname, displaylname, displaynname;
245 245
246 246 if(fnameMatchIndex > -1) {
247 247 displayfname = highlightMatch(fname, query, fnameMatchIndex);
248 248 }
249 249 else {
250 250 displayfname = fname;
251 251 }
252 252
253 253 if(lnameMatchIndex > -1) {
254 254 displaylname = highlightMatch(lname, query, lnameMatchIndex);
255 255 }
256 256 else {
257 257 displaylname = lname;
258 258 }
259 259
260 260 if(nnameMatchIndex > -1) {
261 261 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
262 262 }
263 263 else {
264 264 displaynname = nname ? "(" + nname + ")" : "";
265 265 }
266 266
267 267 return displayfname + " " + displaylname + " " + displaynname;
268 268 }
269 269 else{
270 270 return '';
271 271 }
272 272 };
273 273 membersAC.formatResult = custom_formatter;
274 274 ownerAC.formatResult = custom_formatter;
275 275
276 276 var myHandler = function(sType, aArgs) {
277 277
278 278 var myAC = aArgs[0]; // reference back to the AC instance
279 279 var elLI = aArgs[1]; // reference to the selected LI element
280 280 var oData = aArgs[2]; // object literal of selected item's result data
281 281
282 282 //fill the autocomplete with value
283 283 if(oData.nname != undefined){
284 284 //users
285 285 myAC.getInputEl().value = oData.nname;
286 286 YUD.get('perm_new_member_type').value = 'user';
287 287 }
288 288 else{
289 289 //groups
290 290 myAC.getInputEl().value = oData.grname;
291 291 YUD.get('perm_new_member_type').value = 'users_group';
292 292 }
293 293
294 294 };
295 295
296 296 membersAC.itemSelectEvent.subscribe(myHandler);
297 297 ownerAC.itemSelectEvent.subscribe(myHandler);
298 298
299 299 return {
300 300 memberDS: memberDS,
301 301 ownerDS: ownerDS,
302 302 membersAC: membersAC,
303 303 ownerAC: ownerAC,
304 304 };
305 305 }();
306 306
307 307 </script>
308 308
309 309 </div>
310 310
311 311 <div class="box box-right">
312 312 <div class="title">
313 313 <h5>${_('Administration')}</h5>
314 314 </div>
315 315
316 316 <h3>${_('Statistics')}</h3>
317
318 317 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
319 318 <div class="form">
320 319 <div class="fields">
321 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');")}
322 <div class="field">
321 <div class="field" style="border:none">
323 322 <ul>
324 323 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
325 324 <li>${_('Percentage of stats gathered')}: ${c.stats_percentage} %</li>
326 325 </ul>
327 326 </div>
328 327
329 328 </div>
330 329 </div>
331 330 ${h.end_form()}
332 331
332 %if c.repo_info.clone_uri:
333 <h3>${_('Remote')}</h3>
334 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
335 <div class="form">
336 <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');")}
338 <div class="field" style="border:none">
339 <ul>
340 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
341 </ul>
342 </div>
343 </div>
344 </div>
345 ${h.end_form()}
346 %endif
347
333 348 <h3>${_('Cache')}</h3>
334 349 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
335 350 <div class="form">
336 351 <div class="fields">
337 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');")}
338 353 </div>
339 354 </div>
340 355 ${h.end_form()}
341 356
342 357 <h3>${_('Public journal')}</h3>
343 358 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
344 359 <div class="form">
345 360 <div class="fields">
346 361 ${h.hidden('auth_token',str(h.get_token()))}
347 362 %if c.in_public_journal:
348 363 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="stop_following_icon action_button")}
349 364 %else:
350 365 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="start_following_icon action_button")}
351 366 %endif
352 367 </div>
353 368 </div>
354 369 ${h.end_form()}
355 370
356 371 <h3>${_('Delete')}</h3>
357 372 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
358 373 <div class="form">
359 374 <div class="fields">
360 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');")}
361 376 </div>
362 377 </div>
363 378 ${h.end_form()}
364 379
365 380 </div>
366 381
367 382
368 383 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now