##// END OF EJS Templates
dirty fix for issue #87
marcink -
r825:81ca8a76 beta
parent child Browse files
Show More
@@ -1,52 +1,53 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 package.rhodecode.controllers.admin.admin
4 4 ~~~~~~~~~~~~~~
5 5
6 Controller for Admin pannel of Rhodecode
6 Controller for Admin panel of Rhodecode
7
7 8 :created_on: Apr 7, 2010
8 9 :author: marcink
9 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 11 :license: GPLv3, see COPYING for more details.
11 12 """
12 13 # This program is free software; you can redistribute it and/or
13 14 # modify it under the terms of the GNU General Public License
14 15 # as published by the Free Software Foundation; version 2
15 16 # of the License or (at your opinion) any later version of the license.
16 17 #
17 18 # This program is distributed in the hope that it will be useful,
18 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 21 # GNU General Public License for more details.
21 22 #
22 23 # You should have received a copy of the GNU General Public License
23 24 # along with this program; if not, write to the Free Software
24 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 26 # MA 02110-1301, USA.
26 27
27 28 import logging
28 29 from pylons import request, tmpl_context as c
29 30 from rhodecode.lib.base import BaseController, render
30 31 from rhodecode.model.db import UserLog
31 32 from webhelpers.paginate import Page
32 33 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
33 34
34 35 log = logging.getLogger(__name__)
35 36
36 37 class AdminController(BaseController):
37 38
38 39 @LoginRequired()
39 40 def __before__(self):
40 41 super(AdminController, self).__before__()
41 42
42 43 @HasPermissionAllDecorator('hg.admin')
43 44 def index(self):
44 45
45 46 users_log = self.sa.query(UserLog).order_by(UserLog.action_date.desc())
46 47 p = int(request.params.get('page', 1))
47 48 c.users_log = Page(users_log, page=p, items_per_page=10)
48 49 c.log_data = render('admin/admin_log.html')
49 50 if request.params.get('partial'):
50 51 return c.log_data
51 52 return render('admin/admin.html')
52 53
@@ -1,377 +1,383 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-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27 import os
28 28 import time
29 29 import traceback
30 30 import logging
31 31
32 32 from vcs import get_backend
33 33 from vcs.utils.helpers import get_scm
34 34 from vcs.exceptions import RepositoryError, VCSError
35 35 from vcs.utils.lazy import LazyProperty
36 36
37 37 from mercurial import ui
38 38
39 39 from beaker.cache import cache_region, region_invalidate
40 40
41 41 from rhodecode import BACKENDS
42 42 from rhodecode.lib import helpers as h
43 43 from rhodecode.lib.auth import HasRepoPermissionAny
44 44 from rhodecode.lib.utils import get_repos, make_ui, action_logger
45 45 from rhodecode.model import BaseModel
46 46 from rhodecode.model.user import UserModel
47 47
48 48 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
49 49 UserFollowing, UserLog
50 50 from rhodecode.model.caching_query import FromCache
51 51
52 52 from sqlalchemy.orm import joinedload
53 53 from sqlalchemy.orm.session import make_transient
54 54 from sqlalchemy.exc import DatabaseError
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 class RepoTemp(object):
63 63 def __init__(self, repo_id):
64 64 self.repo_id = repo_id
65 65
66 66 class ScmModel(BaseModel):
67 67 """Generic Scm Model
68 68 """
69 69
70 70 @LazyProperty
71 71 def repos_path(self):
72 72 """Get's the repositories root path from database
73 73 """
74 74
75 75 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
76 76
77 77 return q.ui_value
78 78
79 79 def repo_scan(self, repos_path, baseui):
80 80 """Listing of repositories in given path. This path should not be a
81 81 repository itself. Return a dictionary of repository objects
82 82
83 83 :param repos_path: path to directory containing repositories
84 84 :param baseui
85 85 """
86 86
87 87 log.info('scanning for repositories in %s', repos_path)
88 88
89 89 if not isinstance(baseui, ui.ui):
90 90 baseui = make_ui('db')
91 91 repos_list = {}
92 92
93 93 for name, path in get_repos(repos_path):
94 94 try:
95 95 if repos_list.has_key(name):
96 96 raise RepositoryError('Duplicate repository name %s '
97 97 'found in %s' % (name, path))
98 98 else:
99 99
100 100 klass = get_backend(path[0])
101 101
102 102 if path[0] == 'hg' and path[0] in BACKENDS.keys():
103 103 repos_list[name] = klass(path[1], baseui=baseui)
104 104
105 105 if path[0] == 'git' and path[0] in BACKENDS.keys():
106 106 repos_list[name] = klass(path[1])
107 107 except OSError:
108 108 continue
109 109
110 110 return repos_list
111 111
112 112 def get_repos(self, all_repos=None):
113 113 """Get all repos from db and for each repo create it's backend instance.
114 114 and fill that backed with information from database
115 115
116 116 :param all_repos: give specific repositories list, good for filtering
117 117 """
118 118
119 119 if all_repos is None:
120 120 all_repos = self.sa.query(Repository)\
121 121 .order_by(Repository.repo_name).all()
122 122
123 123 #get the repositories that should be invalidated
124 124 invalidation_list = [str(x.cache_key) for x in \
125 125 self.sa.query(CacheInvalidation.cache_key)\
126 126 .filter(CacheInvalidation.cache_active == False)\
127 127 .all()]
128 128
129 129 for r in all_repos:
130 130
131 131 repo = self.get(r.repo_name, invalidation_list)
132 132
133 133 if repo is not None:
134 134 last_change = repo.last_change
135 135 tip = h.get_changeset_safe(repo, 'tip')
136 136
137 137 tmp_d = {}
138 138 tmp_d['name'] = repo.name
139 139 tmp_d['name_sort'] = tmp_d['name'].lower()
140 140 tmp_d['description'] = repo.dbrepo.description
141 141 tmp_d['description_sort'] = tmp_d['description']
142 142 tmp_d['last_change'] = last_change
143 143 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
144 144 tmp_d['tip'] = tip.raw_id
145 145 tmp_d['tip_sort'] = tip.revision
146 146 tmp_d['rev'] = tip.revision
147 tmp_d['contact'] = repo.dbrepo.user.full_contact
147
148 #dirty hack for some problems
149 usr = repo.dbrepo.user
150 if isinstance(usr, basestring):
151 usr = UserModel(self.sa).get_by_username(repo.dbrepo.user)
152
153 tmp_d['contact'] = usr.full_contact
148 154 tmp_d['contact_sort'] = tmp_d['contact']
149 155 tmp_d['repo_archives'] = list(repo._get_archives())
150 156 tmp_d['last_msg'] = tip.message
151 157 tmp_d['repo'] = repo
152 158 yield tmp_d
153 159
154 160 def get_repo(self, repo_name):
155 161 return self.get(repo_name)
156 162
157 163 def get(self, repo_name, invalidation_list=None):
158 164 """Get's repository from given name, creates BackendInstance and
159 165 propagates it's data from database with all additional information
160 166
161 167 :param repo_name:
162 168 :param invalidation_list: if a invalidation list is given the get
163 169 method should not manually check if this repository needs
164 170 invalidation and just invalidate the repositories in list
165 171
166 172 """
167 173 if not HasRepoPermissionAny('repository.read', 'repository.write',
168 174 'repository.admin')(repo_name, 'get repo check'):
169 175 return
170 176
171 177 #======================================================================
172 178 # CACHE FUNCTION
173 179 #======================================================================
174 180 @cache_region('long_term')
175 181 def _get_repo(repo_name):
176 182
177 183 repo_path = os.path.join(self.repos_path, repo_name)
178 184
179 185 try:
180 186 alias = get_scm(repo_path)[0]
181 187
182 188 log.debug('Creating instance of %s repository', alias)
183 189 backend = get_backend(alias)
184 190 except VCSError:
185 191 log.error(traceback.format_exc())
186 192 return
187 193
188 194 if alias == 'hg':
189 195 from pylons import app_globals as g
190 196 repo = backend(repo_path, create=False, baseui=g.baseui)
191 197 #skip hidden web repository
192 198 if repo._get_hidden():
193 199 return
194 200 else:
195 201 repo = backend(repo_path, create=False)
196 202
197 203 dbrepo = self.sa.query(Repository)\
198 204 .options(joinedload(Repository.fork))\
199 205 .options(joinedload(Repository.user))\
200 206 .filter(Repository.repo_name == repo_name)\
201 207 .scalar()
202 208
203 209 make_transient(dbrepo)
204 210 if dbrepo.user:
205 211 make_transient(dbrepo.user)
206 212 if dbrepo.fork:
207 213 make_transient(dbrepo.fork)
208 214
209 215 repo.dbrepo = dbrepo
210 216 return repo
211 217
212 218 pre_invalidate = True
213 219 if invalidation_list is not None:
214 220 pre_invalidate = repo_name in invalidation_list
215 221
216 222 if pre_invalidate:
217 223 invalidate = self._should_invalidate(repo_name)
218 224
219 225 if invalidate:
220 226 log.info('invalidating cache for repository %s', repo_name)
221 227 region_invalidate(_get_repo, None, repo_name)
222 228 self._mark_invalidated(invalidate)
223 229
224 230 return _get_repo(repo_name)
225 231
226 232
227 233
228 234 def mark_for_invalidation(self, repo_name):
229 235 """Puts cache invalidation task into db for
230 236 further global cache invalidation
231 237
232 238 :param repo_name: this repo that should invalidation take place
233 239 """
234 240
235 241 log.debug('marking %s for invalidation', repo_name)
236 242 cache = self.sa.query(CacheInvalidation)\
237 243 .filter(CacheInvalidation.cache_key == repo_name).scalar()
238 244
239 245 if cache:
240 246 #mark this cache as inactive
241 247 cache.cache_active = False
242 248 else:
243 249 log.debug('cache key not found in invalidation db -> creating one')
244 250 cache = CacheInvalidation(repo_name)
245 251
246 252 try:
247 253 self.sa.add(cache)
248 254 self.sa.commit()
249 255 except (DatabaseError,):
250 256 log.error(traceback.format_exc())
251 257 self.sa.rollback()
252 258
253 259
254 260 def toggle_following_repo(self, follow_repo_id, user_id):
255 261
256 262 f = self.sa.query(UserFollowing)\
257 263 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
258 264 .filter(UserFollowing.user_id == user_id).scalar()
259 265
260 266 if f is not None:
261 267
262 268 try:
263 269 self.sa.delete(f)
264 270 self.sa.commit()
265 271 action_logger(UserTemp(user_id),
266 272 'stopped_following_repo',
267 273 RepoTemp(follow_repo_id))
268 274 return
269 275 except:
270 276 log.error(traceback.format_exc())
271 277 self.sa.rollback()
272 278 raise
273 279
274 280
275 281 try:
276 282 f = UserFollowing()
277 283 f.user_id = user_id
278 284 f.follows_repo_id = follow_repo_id
279 285 self.sa.add(f)
280 286 self.sa.commit()
281 287 action_logger(UserTemp(user_id),
282 288 'started_following_repo',
283 289 RepoTemp(follow_repo_id))
284 290 except:
285 291 log.error(traceback.format_exc())
286 292 self.sa.rollback()
287 293 raise
288 294
289 295 def toggle_following_user(self, follow_user_id , user_id):
290 296 f = self.sa.query(UserFollowing)\
291 297 .filter(UserFollowing.follows_user_id == follow_user_id)\
292 298 .filter(UserFollowing.user_id == user_id).scalar()
293 299
294 300 if f is not None:
295 301 try:
296 302 self.sa.delete(f)
297 303 self.sa.commit()
298 304 return
299 305 except:
300 306 log.error(traceback.format_exc())
301 307 self.sa.rollback()
302 308 raise
303 309
304 310 try:
305 311 f = UserFollowing()
306 312 f.user_id = user_id
307 313 f.follows_user_id = follow_user_id
308 314 self.sa.add(f)
309 315 self.sa.commit()
310 316 except:
311 317 log.error(traceback.format_exc())
312 318 self.sa.rollback()
313 319 raise
314 320
315 321 def is_following_repo(self, repo_name, user_id):
316 322 r = self.sa.query(Repository)\
317 323 .filter(Repository.repo_name == repo_name).scalar()
318 324
319 325 f = self.sa.query(UserFollowing)\
320 326 .filter(UserFollowing.follows_repository == r)\
321 327 .filter(UserFollowing.user_id == user_id).scalar()
322 328
323 329 return f is not None
324 330
325 331 def is_following_user(self, username, user_id):
326 332 u = UserModel(self.sa).get_by_username(username)
327 333
328 334 f = self.sa.query(UserFollowing)\
329 335 .filter(UserFollowing.follows_user == u)\
330 336 .filter(UserFollowing.user_id == user_id).scalar()
331 337
332 338 return f is not None
333 339
334 340 def get_followers(self, repo_id):
335 341 return self.sa.query(UserFollowing)\
336 342 .filter(UserFollowing.follows_repo_id == repo_id).count()
337 343
338 344 def get_forks(self, repo_id):
339 345 return self.sa.query(Repository)\
340 346 .filter(Repository.fork_id == repo_id).count()
341 347
342 348
343 349 def get_unread_journal(self):
344 350 return self.sa.query(UserLog).count()
345 351
346 352
347 353 def _should_invalidate(self, repo_name):
348 354 """Looks up database for invalidation signals for this repo_name
349 355
350 356 :param repo_name:
351 357 """
352 358
353 359 ret = self.sa.query(CacheInvalidation)\
354 360 .options(FromCache('sql_cache_short',
355 361 'get_invalidation_%s' % repo_name))\
356 362 .filter(CacheInvalidation.cache_key == repo_name)\
357 363 .filter(CacheInvalidation.cache_active == False)\
358 364 .scalar()
359 365
360 366 return ret
361 367
362 368 def _mark_invalidated(self, cache_key):
363 369 """ Marks all occurences of cache to invaldation as already invalidated
364 370
365 371 :param cache_key:
366 372 """
367 373
368 374 if cache_key:
369 375 log.debug('marking %s as already invalidated', cache_key)
370 376 try:
371 377 cache_key.cache_active = True
372 378 self.sa.add(cache_key)
373 379 self.sa.commit()
374 380 except (DatabaseError,):
375 381 log.error(traceback.format_exc())
376 382 self.sa.rollback()
377 383
General Comments 0
You need to be logged in to leave comments. Login now