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