Show More
@@ -89,10 +89,8 b' class ReposController(BaseController):' | |||||
89 | """ |
|
89 | """ | |
90 | self.__load_defaults() |
|
90 | self.__load_defaults() | |
91 |
|
91 | |||
92 | repo, dbrepo = ScmModel().get(repo_name, retval='repo') |
|
92 | c.repo_info = db_repo = Repository.by_repo_name(repo_name) | |
93 |
|
93 | repo = scm_repo = db_repo.scm_instance | ||
94 | repo_model = RepoModel() |
|
|||
95 | c.repo_info = repo_model.get_by_repo_name(repo_name) |
|
|||
96 |
|
94 | |||
97 | if c.repo_info is None: |
|
95 | if c.repo_info is None: | |
98 | h.flash(_('%s repository is not mapped to db perhaps' |
|
96 | h.flash(_('%s repository is not mapped to db perhaps' | |
@@ -153,10 +151,9 b' class ReposController(BaseController):' | |||||
153 | """GET /repos: All items in the collection""" |
|
151 | """GET /repos: All items in the collection""" | |
154 | # url('repos') |
|
152 | # url('repos') | |
155 |
|
153 | |||
156 | all_repos = [r.repo_name for r in Repository.query().all()] |
|
154 | c.repos_list = ScmModel().get_repos(Repository.query() | |
157 |
|
155 | .order_by(Repository.repo_name) | ||
158 | cached_repo_list = ScmModel().get_repos(all_repos) |
|
156 | .all(), sort_key='name_sort') | |
159 | c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort')) |
|
|||
160 | return render('admin/repos/repos.html') |
|
157 | return render('admin/repos/repos.html') | |
161 |
|
158 | |||
162 | @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') |
|
159 | @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') |
@@ -181,12 +181,14 b' class ReposGroupsController(BaseControll' | |||||
181 | """GET /repos_groups/id: Show a specific item""" |
|
181 | """GET /repos_groups/id: Show a specific item""" | |
182 | # url('repos_group', id=ID) |
|
182 | # url('repos_group', id=ID) | |
183 |
|
183 | |||
184 | c.group = Group.get(id) |
|
184 | gr = c.group = Group.get(id) | |
|
185 | ||||
185 | if c.group: |
|
186 | if c.group: | |
186 | c.group_repos = c.group.repositories.all() |
|
187 | c.group_repos = c.group.repositories.all() | |
187 | else: |
|
188 | else: | |
188 | return redirect(url('repos_group')) |
|
189 | return redirect(url('repos_group')) | |
189 |
|
190 | |||
|
191 | ||||
190 | sortables = ['name', 'description', 'last_change', 'tip', 'owner'] |
|
192 | sortables = ['name', 'description', 'last_change', 'tip', 'owner'] | |
191 | current_sort = request.GET.get('sort', 'name') |
|
193 | current_sort = request.GET.get('sort', 'name') | |
192 | current_sort_slug = current_sort.replace('-', '') |
|
194 | current_sort_slug = current_sort.replace('-', '') | |
@@ -201,18 +203,12 b' class ReposGroupsController(BaseControll' | |||||
201 | sort_key = current_sort_slug + '_sort' |
|
203 | sort_key = current_sort_slug + '_sort' | |
202 |
|
204 | |||
203 | #overwrite our cached list with current filter |
|
205 | #overwrite our cached list with current filter | |
204 |
gr_filter = |
|
206 | gr_filter = c.group_repos | |
205 | c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter) |
|
207 | c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter) | |
206 |
|
208 | |||
207 | if c.sort_by.startswith('-'): |
|
209 | c.repos_list = c.cached_repo_list | |
208 | c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), |
|
|||
209 | reverse=True) |
|
|||
210 | else: |
|
|||
211 | c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), |
|
|||
212 | reverse=False) |
|
|||
213 |
|
210 | |||
214 |
c.repo_cnt = |
|
211 | c.repo_cnt = 0 | |
215 |
|
||||
216 |
|
212 | |||
217 | c.groups = self.sa.query(Group).order_by(Group.group_name)\ |
|
213 | c.groups = self.sa.query(Group).order_by(Group.group_name)\ | |
218 | .filter(Group.group_parent_id == id).all() |
|
214 | .filter(Group.group_parent_id == id).all() |
@@ -258,9 +258,10 b' class SettingsController(BaseController)' | |||||
258 | # url('admin_settings_my_account') |
|
258 | # url('admin_settings_my_account') | |
259 |
|
259 | |||
260 | c.user = UserModel().get(self.rhodecode_user.user_id, cache=False) |
|
260 | c.user = UserModel().get(self.rhodecode_user.user_id, cache=False) | |
261 |
all_repos = |
|
261 | all_repos = self.sa.query(Repository)\ | |
262 | .filter(Repository.user_id == c.user.user_id)\ |
|
262 | .filter(Repository.user_id == c.user.user_id)\ | |
263 |
.order_by(func.lower(Repository.repo_name)).all() |
|
263 | .order_by(func.lower(Repository.repo_name)).all() | |
|
264 | ||||
264 | c.user_repos = ScmModel().get_repos(all_repos) |
|
265 | c.user_repos = ScmModel().get_repos(all_repos) | |
265 |
|
266 | |||
266 | if c.user.username == 'default': |
|
267 | if c.user.username == 'default': |
@@ -31,7 +31,7 b' from paste.httpexceptions import HTTPBad' | |||||
31 |
|
31 | |||
32 | from rhodecode.lib.auth import LoginRequired |
|
32 | from rhodecode.lib.auth import LoginRequired | |
33 | from rhodecode.lib.base import BaseController, render |
|
33 | from rhodecode.lib.base import BaseController, render | |
34 | from rhodecode.model.db import Group |
|
34 | from rhodecode.model.db import Group, Repository | |
35 |
|
35 | |||
36 | log = logging.getLogger(__name__) |
|
36 | log = logging.getLogger(__name__) | |
37 |
|
37 | |||
@@ -56,16 +56,11 b' class HomeController(BaseController):' | |||||
56 |
|
56 | |||
57 | sort_key = current_sort_slug + '_sort' |
|
57 | sort_key = current_sort_slug + '_sort' | |
58 |
|
58 | |||
59 | if c.sort_by.startswith('-'): |
|
59 | ||
60 | c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), |
|
60 | c.repos_list = self.scm_model.get_repos(sort_key=sort_key) | |
61 | reverse=True) |
|
|||
62 | else: |
|
|||
63 | c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), |
|
|||
64 | reverse=False) |
|
|||
65 |
|
61 | |||
66 | c.repo_cnt = len(c.repos_list) |
|
62 | c.repo_cnt = len(c.repos_list) | |
67 |
|
63 | |||
68 |
|
||||
69 | c.groups = Group.query().filter(Group.group_parent_id == None).all() |
|
64 | c.groups = Group.query().filter(Group.group_parent_id == None).all() | |
70 |
|
65 | |||
71 |
|
66 | |||
@@ -73,8 +68,9 b' class HomeController(BaseController):' | |||||
73 |
|
68 | |||
74 | def repo_switcher(self): |
|
69 | def repo_switcher(self): | |
75 | if request.is_xhr: |
|
70 | if request.is_xhr: | |
76 | c.repos_list = sorted(c.cached_repo_list, |
|
71 | all_repos = Repository.query().order_by(Repository.repo_name).all() | |
77 | key=itemgetter('name_sort'), reverse=False) |
|
72 | c.repos_list = self.scm_model.get_repos(all_repos, | |
|
73 | sort_key='name_sort') | |||
78 | return render('/repo_switcher_list.html') |
|
74 | return render('/repo_switcher_list.html') | |
79 | else: |
|
75 | else: | |
80 | return HTTPBadRequest() |
|
76 | return HTTPBadRequest() |
@@ -155,6 +155,7 b' class SettingsController(BaseRepoControl' | |||||
155 | invalidate_cache('get_repo_cached_%s' % repo_name) |
|
155 | invalidate_cache('get_repo_cached_%s' % repo_name) | |
156 | h.flash(_('deleted repository %s') % repo_name, category='success') |
|
156 | h.flash(_('deleted repository %s') % repo_name, category='success') | |
157 | except Exception: |
|
157 | except Exception: | |
|
158 | log.error(traceback.format_exc()) | |||
158 | h.flash(_('An error occurred during deletion of %s') % repo_name, |
|
159 | h.flash(_('An error occurred during deletion of %s') % repo_name, | |
159 | category='error') |
|
160 | category='error') | |
160 |
|
161 | |||
@@ -205,4 +206,9 b' class SettingsController(BaseRepoControl' | |||||
205 | errors=errors.error_dict or {}, |
|
206 | errors=errors.error_dict or {}, | |
206 | prefix_error=False, |
|
207 | prefix_error=False, | |
207 | encoding="UTF-8") |
|
208 | encoding="UTF-8") | |
|
209 | except Exception: | |||
|
210 | log.error(traceback.format_exc()) | |||
|
211 | h.flash(_('An error occurred during repository forking %s') % | |||
|
212 | repo_name, category='error') | |||
|
213 | ||||
208 | return redirect(url('home')) |
|
214 | return redirect(url('home')) |
@@ -12,6 +12,7 b' from rhodecode.lib.utils import get_repo' | |||||
12 | from rhodecode.model import meta |
|
12 | from rhodecode.model import meta | |
13 | from rhodecode.model.scm import ScmModel |
|
13 | from rhodecode.model.scm import ScmModel | |
14 | from rhodecode import BACKENDS |
|
14 | from rhodecode import BACKENDS | |
|
15 | from rhodecode.model.db import Repository | |||
15 |
|
16 | |||
16 |
|
17 | |||
17 | class BaseController(WSGIController): |
|
18 | class BaseController(WSGIController): | |
@@ -26,7 +27,7 b' class BaseController(WSGIController):' | |||||
26 |
|
27 | |||
27 | self.sa = meta.Session() |
|
28 | self.sa = meta.Session() | |
28 | self.scm_model = ScmModel(self.sa) |
|
29 | self.scm_model = ScmModel(self.sa) | |
29 | c.cached_repo_list = self.scm_model.get_repos() |
|
30 | ||
30 | #c.unread_journal = scm_model.get_unread_journal() |
|
31 | #c.unread_journal = scm_model.get_unread_journal() | |
31 |
|
32 | |||
32 | def __call__(self, environ, start_response): |
|
33 | def __call__(self, environ, start_response): | |
@@ -62,8 +63,7 b' class BaseRepoController(BaseController)' | |||||
62 | super(BaseRepoController, self).__before__() |
|
63 | super(BaseRepoController, self).__before__() | |
63 | if c.repo_name: |
|
64 | if c.repo_name: | |
64 |
|
65 | |||
65 |
c.rhodecode_repo |
|
66 | c.rhodecode_repo = Repository.by_repo_name(c.repo_name).scm_instance | |
66 | retval='repo') |
|
|||
67 |
|
67 | |||
68 | if c.rhodecode_repo is not None: |
|
68 | if c.rhodecode_repo is not None: | |
69 | c.repository_followers = \ |
|
69 | c.repository_followers = \ |
@@ -102,7 +102,6 b' def get_commits_stats(repo_name, ts_min_' | |||||
102 | lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, |
|
102 | lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, | |
103 | ts_max_y) |
|
103 | ts_max_y) | |
104 | lockkey_path = dn(dn(dn(dn(os.path.abspath(__file__))))) |
|
104 | lockkey_path = dn(dn(dn(dn(os.path.abspath(__file__))))) | |
105 | print jn(lockkey_path, lockkey) |
|
|||
106 | log.info('running task with lockkey %s', lockkey) |
|
105 | log.info('running task with lockkey %s', lockkey) | |
107 | try: |
|
106 | try: | |
108 | lock = l = DaemonLock(jn(lockkey_path, lockkey)) |
|
107 | lock = l = DaemonLock(jn(lockkey_path, lockkey)) |
@@ -372,8 +372,7 b' def action_parser(user_log, feed=False):' | |||||
372 | repo_name = user_log.repository.repo_name |
|
372 | repo_name = user_log.repository.repo_name | |
373 |
|
373 | |||
374 | from rhodecode.model.scm import ScmModel |
|
374 | from rhodecode.model.scm import ScmModel | |
375 | repo, dbrepo = ScmModel().get(repo_name, retval='repo', |
|
375 | repo = user_log.repository.scm_instance | |
376 | invalidation_list=[]) |
|
|||
377 |
|
376 | |||
378 | message = lambda rev: get_changeset_safe(repo, rev).message |
|
377 | message = lambda rev: get_changeset_safe(repo, rev).message | |
379 | cs_links = [] |
|
378 | cs_links = [] |
@@ -472,7 +472,7 b' def create_test_index(repo_location, ful' | |||||
472 | shutil.rmtree(index_location) |
|
472 | shutil.rmtree(index_location) | |
473 |
|
473 | |||
474 | try: |
|
474 | try: | |
475 |
l = DaemonLock(file=jn(dn( |
|
475 | l = DaemonLock(file=jn(dn(index_location), 'make_index.lock')) | |
476 | WhooshIndexingDaemon(index_location=index_location, |
|
476 | WhooshIndexingDaemon(index_location=index_location, | |
477 | repo_location=repo_location)\ |
|
477 | repo_location=repo_location)\ | |
478 | .run(full_index=full_index) |
|
478 | .run(full_index=full_index) |
@@ -26,13 +26,23 b'' | |||||
26 | import os |
|
26 | import os | |
27 | import logging |
|
27 | import logging | |
28 | import datetime |
|
28 | import datetime | |
|
29 | import traceback | |||
29 | from datetime import date |
|
30 | from datetime import date | |
30 |
|
31 | |||
31 | from sqlalchemy import * |
|
32 | from sqlalchemy import * | |
32 | from sqlalchemy.exc import DatabaseError |
|
33 | from sqlalchemy.exc import DatabaseError | |
33 | from sqlalchemy.orm import relationship, backref |
|
34 | from sqlalchemy.orm import relationship, backref, joinedload | |
34 | from sqlalchemy.orm.interfaces import MapperExtension |
|
35 | from sqlalchemy.orm.interfaces import MapperExtension | |
35 |
|
36 | |||
|
37 | from beaker.cache import cache_region, region_invalidate | |||
|
38 | ||||
|
39 | ||||
|
40 | from vcs import get_backend | |||
|
41 | from vcs.utils.helpers import get_scm | |||
|
42 | from vcs.exceptions import RepositoryError, VCSError | |||
|
43 | from vcs.utils.lazy import LazyProperty | |||
|
44 | from vcs.nodes import FileNode | |||
|
45 | ||||
36 | from rhodecode.lib import str2bool |
|
46 | from rhodecode.lib import str2bool | |
37 | from rhodecode.model.meta import Base, Session |
|
47 | from rhodecode.model.meta import Base, Session | |
38 | from rhodecode.model.caching_query import FromCache |
|
48 | from rhodecode.model.caching_query import FromCache | |
@@ -150,6 +160,7 b' class User(Base):' | |||||
150 | return self.admin |
|
160 | return self.admin | |
151 |
|
161 | |||
152 | def __repr__(self): |
|
162 | def __repr__(self): | |
|
163 | return 'ahmmm' | |||
153 | return "<%s('id:%s:%s')>" % (self.__class__.__name__, |
|
164 | return "<%s('id:%s:%s')>" % (self.__class__.__name__, | |
154 | self.user_id, self.username) |
|
165 | self.user_id, self.username) | |
155 |
|
166 | |||
@@ -266,8 +277,13 b' class Repository(Base):' | |||||
266 |
|
277 | |||
267 | @classmethod |
|
278 | @classmethod | |
268 | def by_repo_name(cls, repo_name): |
|
279 | def by_repo_name(cls, repo_name): | |
269 |
|
|
280 | q = Session.query(cls).filter(cls.repo_name == repo_name) | |
270 |
|
281 | |||
|
282 | q = q.options(joinedload(Repository.fork))\ | |||
|
283 | .options(joinedload(Repository.user))\ | |||
|
284 | .options(joinedload(Repository.group))\ | |||
|
285 | ||||
|
286 | return q.one() | |||
271 |
|
287 | |||
272 | @classmethod |
|
288 | @classmethod | |
273 | def get_repo_forks(cls, repo_id): |
|
289 | def get_repo_forks(cls, repo_id): | |
@@ -298,6 +314,127 b' class Repository(Base):' | |||||
298 | def groups_and_repo(self): |
|
314 | def groups_and_repo(self): | |
299 | return self.groups_with_parents, self.just_name |
|
315 | return self.groups_with_parents, self.just_name | |
300 |
|
316 | |||
|
317 | @LazyProperty | |||
|
318 | def repo_path(self): | |||
|
319 | """ | |||
|
320 | Returns base full path for that repository means where it actually | |||
|
321 | exists on a filesystem | |||
|
322 | """ | |||
|
323 | ||||
|
324 | q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one() | |||
|
325 | return q.ui_value | |||
|
326 | ||||
|
327 | @property | |||
|
328 | def repo_full_path(self): | |||
|
329 | p = [self.repo_path] | |||
|
330 | # we need to split the name by / since this is how we store the | |||
|
331 | # names in the database, but that eventually needs to be converted | |||
|
332 | # into a valid system path | |||
|
333 | p += self.repo_name.split('/') | |||
|
334 | return os.path.join(*p) | |||
|
335 | ||||
|
336 | @property | |||
|
337 | def _ui(self): | |||
|
338 | """ | |||
|
339 | Creates an db based ui object for this repository | |||
|
340 | """ | |||
|
341 | from mercurial import ui | |||
|
342 | from mercurial import config | |||
|
343 | baseui = ui.ui() | |||
|
344 | ||||
|
345 | #clean the baseui object | |||
|
346 | baseui._ocfg = config.config() | |||
|
347 | baseui._ucfg = config.config() | |||
|
348 | baseui._tcfg = config.config() | |||
|
349 | ||||
|
350 | ||||
|
351 | ret = Session.query(RhodeCodeUi)\ | |||
|
352 | .options(FromCache("sql_cache_short", | |||
|
353 | "repository_repo_ui")).all() | |||
|
354 | ||||
|
355 | hg_ui = ret | |||
|
356 | for ui_ in hg_ui: | |||
|
357 | if ui_.ui_active: | |||
|
358 | log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, | |||
|
359 | ui_.ui_key, ui_.ui_value) | |||
|
360 | baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value) | |||
|
361 | ||||
|
362 | return baseui | |||
|
363 | ||||
|
364 | #========================================================================== | |||
|
365 | # SCM CACHE INSTANCE | |||
|
366 | #========================================================================== | |||
|
367 | ||||
|
368 | @property | |||
|
369 | def invalidate(self): | |||
|
370 | """ | |||
|
371 | Returns Invalidation object if this repo should be invalidated | |||
|
372 | None otherwise. `cache_active = False` means that this cache | |||
|
373 | state is not valid and needs to be invalidated | |||
|
374 | """ | |||
|
375 | return Session.query(CacheInvalidation)\ | |||
|
376 | .filter(CacheInvalidation.cache_key == self.repo_name)\ | |||
|
377 | .filter(CacheInvalidation.cache_active == False)\ | |||
|
378 | .scalar() | |||
|
379 | ||||
|
380 | @property | |||
|
381 | def set_invalidate(self): | |||
|
382 | """ | |||
|
383 | set a cache for invalidation for this instance | |||
|
384 | """ | |||
|
385 | inv = Session.query(CacheInvalidation)\ | |||
|
386 | .filter(CacheInvalidation.cache_key == self.repo_name)\ | |||
|
387 | .scalar() | |||
|
388 | ||||
|
389 | if inv is None: | |||
|
390 | inv = CacheInvalidation(self.repo_name) | |||
|
391 | inv.cache_active = True | |||
|
392 | Session.add(inv) | |||
|
393 | Session.commit() | |||
|
394 | ||||
|
395 | @property | |||
|
396 | def scm_instance(self): | |||
|
397 | return self.__get_instance(self.repo_name) | |||
|
398 | ||||
|
399 | @property | |||
|
400 | def scm_instance_cached(self): | |||
|
401 | @cache_region('long_term') | |||
|
402 | def _c(repo_name): | |||
|
403 | return self.__get_instance(repo_name) | |||
|
404 | ||||
|
405 | inv = self.invalidate | |||
|
406 | if inv: | |||
|
407 | region_invalidate(_c, None, self.repo_name) | |||
|
408 | #update our cache | |||
|
409 | inv.cache_key.cache_active = True | |||
|
410 | Session.add(inv) | |||
|
411 | Session.commit() | |||
|
412 | ||||
|
413 | return _c(self.repo_name) | |||
|
414 | ||||
|
415 | def __get_instance(self, repo_name): | |||
|
416 | try: | |||
|
417 | alias = get_scm(self.repo_full_path)[0] | |||
|
418 | log.debug('Creating instance of %s repository', alias) | |||
|
419 | backend = get_backend(alias) | |||
|
420 | except VCSError: | |||
|
421 | log.error(traceback.format_exc()) | |||
|
422 | log.error('Perhaps this repository is in db and not in ' | |||
|
423 | 'filesystem run rescan repositories with ' | |||
|
424 | '"destroy old data " option from admin panel') | |||
|
425 | return | |||
|
426 | ||||
|
427 | if alias == 'hg': | |||
|
428 | repo = backend(self.repo_full_path, create=False, | |||
|
429 | baseui=self._ui) | |||
|
430 | #skip hidden web repository | |||
|
431 | if repo._get_hidden(): | |||
|
432 | return | |||
|
433 | else: | |||
|
434 | repo = backend(self.repo_full_path, create=False) | |||
|
435 | ||||
|
436 | return repo | |||
|
437 | ||||
301 |
|
438 | |||
302 | class Group(Base): |
|
439 | class Group(Base): | |
303 | __tablename__ = 'groups' |
|
440 | __tablename__ = 'groups' |
@@ -280,6 +280,13 b' def ValidRepoName(edit, old_data):' | |||||
280 |
|
280 | |||
281 | return _ValidRepoName |
|
281 | return _ValidRepoName | |
282 |
|
282 | |||
|
283 | def ValidForkName(): | |||
|
284 | class _ValidForkName(formencode.validators.FancyValidator): | |||
|
285 | def to_python(self, value, state): | |||
|
286 | return value | |||
|
287 | return _ValidForkName | |||
|
288 | ||||
|
289 | ||||
283 | def SlugifyName(): |
|
290 | def SlugifyName(): | |
284 | class _SlugifyName(formencode.validators.FancyValidator): |
|
291 | class _SlugifyName(formencode.validators.FancyValidator): | |
285 |
|
292 | |||
@@ -326,6 +333,7 b' def ValidForkType(old_data):' | |||||
326 | if old_data['repo_type'] != value: |
|
333 | if old_data['repo_type'] != value: | |
327 | raise formencode.Invalid(_('Fork have to be the same ' |
|
334 | raise formencode.Invalid(_('Fork have to be the same ' | |
328 | 'type as original'), value, state) |
|
335 | 'type as original'), value, state) | |
|
336 | ||||
329 | return value |
|
337 | return value | |
330 | return _ValidForkType |
|
338 | return _ValidForkType | |
331 |
|
339 | |||
@@ -583,6 +591,9 b' def RepoForkForm(edit=False, old_data={}' | |||||
583 | description = UnicodeString(strip=True, min=1, not_empty=True) |
|
591 | description = UnicodeString(strip=True, min=1, not_empty=True) | |
584 | private = StringBoolean(if_missing=False) |
|
592 | private = StringBoolean(if_missing=False) | |
585 | repo_type = All(ValidForkType(old_data), OneOf(supported_backends)) |
|
593 | repo_type = All(ValidForkType(old_data), OneOf(supported_backends)) | |
|
594 | ||||
|
595 | chained_validators = [ValidForkName()] | |||
|
596 | ||||
586 | return _RepoForkForm |
|
597 | return _RepoForkForm | |
587 |
|
598 | |||
588 | def RepoSettingsForm(edit=False, old_data={}): |
|
599 | def RepoSettingsForm(edit=False, old_data={}): |
@@ -70,28 +70,6 b' class RepoModel(BaseModel):' | |||||
70 | "get_repo_%s" % repo_name)) |
|
70 | "get_repo_%s" % repo_name)) | |
71 | return repo.scalar() |
|
71 | return repo.scalar() | |
72 |
|
72 | |||
73 | def get_full(self, repo_name, cache=False, invalidate=False): |
|
|||
74 | repo = self.sa.query(Repository)\ |
|
|||
75 | .options(joinedload(Repository.fork))\ |
|
|||
76 | .options(joinedload(Repository.user))\ |
|
|||
77 | .options(joinedload(Repository.group))\ |
|
|||
78 | .filter(Repository.repo_name == repo_name)\ |
|
|||
79 |
|
||||
80 | if cache: |
|
|||
81 | repo = repo.options(FromCache("sql_cache_long", |
|
|||
82 | "get_repo_full_%s" % repo_name)) |
|
|||
83 | if invalidate and cache: |
|
|||
84 | repo.invalidate() |
|
|||
85 |
|
||||
86 | ret = repo.scalar() |
|
|||
87 |
|
||||
88 | #make transient for sake of errors |
|
|||
89 | make_transient(ret) |
|
|||
90 | for k in ['fork', 'user', 'group']: |
|
|||
91 | attr = getattr(ret, k, False) |
|
|||
92 | if attr: |
|
|||
93 | make_transient(attr) |
|
|||
94 | return ret |
|
|||
95 |
|
73 | |||
96 | def get_users_js(self): |
|
74 | def get_users_js(self): | |
97 |
|
75 | |||
@@ -193,12 +171,13 b' class RepoModel(BaseModel):' | |||||
193 | raise |
|
171 | raise | |
194 |
|
172 | |||
195 | def create(self, form_data, cur_user, just_db=False, fork=False): |
|
173 | def create(self, form_data, cur_user, just_db=False, fork=False): | |
|
174 | ||||
196 | try: |
|
175 | try: | |
197 | if fork: |
|
176 | if fork: | |
198 | #force str since hg doesn't go with unicode |
|
177 | #force str since hg doesn't go with unicode | |
199 | repo_name = str(form_data['fork_name']) |
|
178 | repo_name = str(form_data['fork_name']) | |
200 | org_name = str(form_data['repo_name']) |
|
179 | org_name = str(form_data['repo_name']) | |
201 |
org_full_name = str(form_data[' |
|
180 | org_full_name = org_name#str(form_data['fork_name_full']) | |
202 |
|
181 | |||
203 | else: |
|
182 | else: | |
204 | org_name = repo_name = str(form_data['repo_name']) |
|
183 | org_name = repo_name = str(form_data['repo_name']) | |
@@ -208,7 +187,10 b' class RepoModel(BaseModel):' | |||||
208 | new_repo.enable_statistics = False |
|
187 | new_repo.enable_statistics = False | |
209 | for k, v in form_data.items(): |
|
188 | for k, v in form_data.items(): | |
210 | if k == 'repo_name': |
|
189 | if k == 'repo_name': | |
211 |
|
|
190 | if fork: | |
|
191 | v = repo_name | |||
|
192 | else: | |||
|
193 | v = repo_name_full | |||
212 | if k == 'repo_group': |
|
194 | if k == 'repo_group': | |
213 | k = 'group_id' |
|
195 | k = 'group_id' | |
214 |
|
196 | |||
@@ -216,7 +198,7 b' class RepoModel(BaseModel):' | |||||
216 |
|
198 | |||
217 | if fork: |
|
199 | if fork: | |
218 | parent_repo = self.sa.query(Repository)\ |
|
200 | parent_repo = self.sa.query(Repository)\ | |
219 |
.filter(Repository.repo_name == org_full_name). |
|
201 | .filter(Repository.repo_name == org_full_name).one() | |
220 | new_repo.fork = parent_repo |
|
202 | new_repo.fork = parent_repo | |
221 |
|
203 | |||
222 | new_repo.user_id = cur_user.user_id |
|
204 | new_repo.user_id = cur_user.user_id |
@@ -70,6 +70,75 b' class RepoTemp(object):' | |||||
70 | def __repr__(self): |
|
70 | def __repr__(self): | |
71 | return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id) |
|
71 | return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id) | |
72 |
|
72 | |||
|
73 | class CachedRepoList(object): | |||
|
74 | ||||
|
75 | def __init__(self, db_repo_list, invalidation_list, repos_path, | |||
|
76 | order_by=None): | |||
|
77 | self.db_repo_list = db_repo_list | |||
|
78 | self.invalidation_list = invalidation_list | |||
|
79 | self.repos_path = repos_path | |||
|
80 | self.order_by = order_by | |||
|
81 | self.reversed = (order_by or '').startswith('-') | |||
|
82 | ||||
|
83 | def __len__(self): | |||
|
84 | return len(self.db_repo_list) | |||
|
85 | ||||
|
86 | def __repr__(self): | |||
|
87 | return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) | |||
|
88 | ||||
|
89 | def __iter__(self): | |||
|
90 | for db_repo in self.db_repo_list: | |||
|
91 | dbr = db_repo | |||
|
92 | ||||
|
93 | # invalidate the repo cache if needed before getting the | |||
|
94 | # scm instance | |||
|
95 | ||||
|
96 | scm_invalidate = False | |||
|
97 | if self.invalidation_list is not None: | |||
|
98 | scm_invalidate = dbr.repo_name in self.invalidation_list | |||
|
99 | ||||
|
100 | if scm_invalidate: | |||
|
101 | log.info('invalidating cache for repository %s', | |||
|
102 | dbr.repo_name) | |||
|
103 | db_repo.set_invalidate | |||
|
104 | ||||
|
105 | scmr = db_repo.scm_instance_cached | |||
|
106 | ||||
|
107 | #check permission at this level | |||
|
108 | if not HasRepoPermissionAny('repository.read', | |||
|
109 | 'repository.write', | |||
|
110 | 'repository.admin')(dbr.repo_name, | |||
|
111 | 'get repo check'): | |||
|
112 | continue | |||
|
113 | ||||
|
114 | ||||
|
115 | ||||
|
116 | ||||
|
117 | ||||
|
118 | last_change = scmr.last_change | |||
|
119 | tip = h.get_changeset_safe(scmr, 'tip') | |||
|
120 | ||||
|
121 | tmp_d = {} | |||
|
122 | tmp_d['name'] = dbr.repo_name | |||
|
123 | tmp_d['name_sort'] = tmp_d['name'].lower() | |||
|
124 | tmp_d['description'] = dbr.description | |||
|
125 | tmp_d['description_sort'] = tmp_d['description'] | |||
|
126 | tmp_d['last_change'] = last_change | |||
|
127 | tmp_d['last_change_sort'] = time.mktime(last_change \ | |||
|
128 | .timetuple()) | |||
|
129 | tmp_d['tip'] = tip.raw_id | |||
|
130 | tmp_d['tip_sort'] = tip.revision | |||
|
131 | tmp_d['rev'] = tip.revision | |||
|
132 | tmp_d['contact'] = dbr.user.full_contact | |||
|
133 | tmp_d['contact_sort'] = tmp_d['contact'] | |||
|
134 | tmp_d['owner_sort'] = tmp_d['contact'] | |||
|
135 | tmp_d['repo_archives'] = list(scmr._get_archives()) | |||
|
136 | tmp_d['last_msg'] = tip.message | |||
|
137 | tmp_d['repo'] = scmr | |||
|
138 | tmp_d['dbrepo'] = dbr.get_dict() | |||
|
139 | tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork \ | |||
|
140 | else {} | |||
|
141 | yield tmp_d | |||
73 |
|
142 | |||
74 | class ScmModel(BaseModel): |
|
143 | class ScmModel(BaseModel): | |
75 | """Generic Scm Model |
|
144 | """Generic Scm Model | |
@@ -118,7 +187,7 b' class ScmModel(BaseModel):' | |||||
118 |
|
187 | |||
119 | return repos_list |
|
188 | return repos_list | |
120 |
|
189 | |||
121 | def get_repos(self, all_repos=None): |
|
190 | def get_repos(self, all_repos=None, sort_key=None): | |
122 | """ |
|
191 | """ | |
123 | Get all repos from db and for each repo create it's |
|
192 | Get all repos from db and for each repo create it's | |
124 | backend instance and fill that backed with information from database |
|
193 | backend instance and fill that backed with information from database | |
@@ -127,120 +196,21 b' class ScmModel(BaseModel):' | |||||
127 | give specific repositories list, good for filtering |
|
196 | give specific repositories list, good for filtering | |
128 | """ |
|
197 | """ | |
129 | if all_repos is None: |
|
198 | if all_repos is None: | |
130 | repos = self.sa.query(Repository)\ |
|
199 | all_repos = self.sa.query(Repository)\ | |
131 | .filter(Repository.group_id == None)\ |
|
200 | .filter(Repository.group_id == None)\ | |
132 | .order_by(Repository.repo_name).all() |
|
201 | .order_by(Repository.repo_name).all() | |
133 | all_repos = [r.repo_name for r in repos] |
|
|||
134 |
|
202 | |||
135 | #get the repositories that should be invalidated |
|
203 | #get the repositories that should be invalidated | |
136 | invalidation_list = [str(x.cache_key) for x in \ |
|
204 | invalidation_list = [str(x.cache_key) for x in \ | |
137 | self.sa.query(CacheInvalidation.cache_key)\ |
|
205 | self.sa.query(CacheInvalidation.cache_key)\ | |
138 | .filter(CacheInvalidation.cache_active == False)\ |
|
206 | .filter(CacheInvalidation.cache_active == False)\ | |
139 | .all()] |
|
207 | .all()] | |
140 | for r_name in all_repos: |
|
|||
141 | r_dbr = self.get(r_name, invalidation_list) |
|
|||
142 | if r_dbr is not None: |
|
|||
143 | repo, dbrepo = r_dbr |
|
|||
144 |
|
||||
145 | if repo is None or dbrepo is None: |
|
|||
146 | log.error('Repository "%s" looks somehow corrupted ' |
|
|||
147 | 'fs-repo:%s,db-repo:%s both values should be ' |
|
|||
148 | 'present', r_name, repo, dbrepo) |
|
|||
149 | continue |
|
|||
150 | last_change = repo.last_change |
|
|||
151 | tip = h.get_changeset_safe(repo, 'tip') |
|
|||
152 |
|
||||
153 | tmp_d = {} |
|
|||
154 | tmp_d['name'] = dbrepo.repo_name |
|
|||
155 | tmp_d['name_sort'] = tmp_d['name'].lower() |
|
|||
156 | tmp_d['description'] = dbrepo.description |
|
|||
157 | tmp_d['description_sort'] = tmp_d['description'] |
|
|||
158 | tmp_d['last_change'] = last_change |
|
|||
159 | tmp_d['last_change_sort'] = time.mktime(last_change \ |
|
|||
160 | .timetuple()) |
|
|||
161 | tmp_d['tip'] = tip.raw_id |
|
|||
162 | tmp_d['tip_sort'] = tip.revision |
|
|||
163 | tmp_d['rev'] = tip.revision |
|
|||
164 | tmp_d['contact'] = dbrepo.user.full_contact |
|
|||
165 | tmp_d['contact_sort'] = tmp_d['contact'] |
|
|||
166 | tmp_d['owner_sort'] = tmp_d['contact'] |
|
|||
167 | tmp_d['repo_archives'] = list(repo._get_archives()) |
|
|||
168 | tmp_d['last_msg'] = tip.message |
|
|||
169 | tmp_d['repo'] = repo |
|
|||
170 | tmp_d['dbrepo'] = dbrepo.get_dict() |
|
|||
171 | tmp_d['dbrepo_fork'] = dbrepo.fork.get_dict() if dbrepo.fork \ |
|
|||
172 | else {} |
|
|||
173 | yield tmp_d |
|
|||
174 |
|
||||
175 | def get(self, repo_name, invalidation_list=None, retval='all'): |
|
|||
176 | """Returns a tuple of Repository,DbRepository, |
|
|||
177 | Get's repository from given name, creates BackendInstance and |
|
|||
178 | propagates it's data from database with all additional information |
|
|||
179 |
|
||||
180 | :param repo_name: |
|
|||
181 | :param invalidation_list: if a invalidation list is given the get |
|
|||
182 | method should not manually check if this repository needs |
|
|||
183 | invalidation and just invalidate the repositories in list |
|
|||
184 | :param retval: string specifing what to return one of 'repo','dbrepo', |
|
|||
185 | 'all'if repo or dbrepo is given it'll just lazy load chosen type |
|
|||
186 | and return None as the second |
|
|||
187 | """ |
|
|||
188 | if not HasRepoPermissionAny('repository.read', 'repository.write', |
|
|||
189 | 'repository.admin')(repo_name, 'get repo check'): |
|
|||
190 | return |
|
|||
191 |
|
208 | |||
192 | #====================================================================== |
|
209 | repo_iter = CachedRepoList(all_repos, invalidation_list, | |
193 | # CACHE FUNCTION |
|
210 | repos_path=self.repos_path, | |
194 | #====================================================================== |
|
211 | order_by=sort_key) | |
195 | @cache_region('long_term') |
|
|||
196 | def _get_repo(repo_name): |
|
|||
197 |
|
||||
198 | repo_path = os.path.join(self.repos_path, repo_name) |
|
|||
199 |
|
||||
200 | try: |
|
|||
201 | alias = get_scm(repo_path)[0] |
|
|||
202 | log.debug('Creating instance of %s repository', alias) |
|
|||
203 | backend = get_backend(alias) |
|
|||
204 | except VCSError: |
|
|||
205 | log.error(traceback.format_exc()) |
|
|||
206 | log.error('Perhaps this repository is in db and not in ' |
|
|||
207 | 'filesystem run rescan repositories with ' |
|
|||
208 | '"destroy old data " option from admin panel') |
|
|||
209 | return |
|
|||
210 |
|
212 | |||
211 | if alias == 'hg': |
|
213 | return repo_iter | |
212 | repo = backend(repo_path, create=False, baseui=make_ui('db')) |
|
|||
213 | #skip hidden web repository |
|
|||
214 | if repo._get_hidden(): |
|
|||
215 | return |
|
|||
216 | else: |
|
|||
217 | repo = backend(repo_path, create=False) |
|
|||
218 |
|
||||
219 | return repo |
|
|||
220 |
|
||||
221 | pre_invalidate = True |
|
|||
222 | dbinvalidate = False |
|
|||
223 |
|
||||
224 | if invalidation_list is not None: |
|
|||
225 | pre_invalidate = repo_name in invalidation_list |
|
|||
226 |
|
||||
227 | if pre_invalidate: |
|
|||
228 | #this returns object to invalidate |
|
|||
229 | invalidate = self._should_invalidate(repo_name) |
|
|||
230 | if invalidate: |
|
|||
231 | log.info('invalidating cache for repository %s', repo_name) |
|
|||
232 | region_invalidate(_get_repo, None, repo_name) |
|
|||
233 | self._mark_invalidated(invalidate) |
|
|||
234 | dbinvalidate = True |
|
|||
235 |
|
||||
236 | r, dbr = None, None |
|
|||
237 | if retval == 'repo' or 'all': |
|
|||
238 | r = _get_repo(repo_name) |
|
|||
239 | if retval == 'dbrepo' or 'all': |
|
|||
240 | dbr = RepoModel().get_full(repo_name, cache=True, |
|
|||
241 | invalidate=dbinvalidate) |
|
|||
242 |
|
||||
243 | return r, dbr |
|
|||
244 |
|
214 | |||
245 | def mark_for_invalidation(self, repo_name): |
|
215 | def mark_for_invalidation(self, repo_name): | |
246 | """Puts cache invalidation task into db for |
|
216 | """Puts cache invalidation task into db for |
@@ -65,7 +65,7 b'' | |||||
65 | <label for="new_password">${_('New password')}:</label> |
|
65 | <label for="new_password">${_('New password')}:</label> | |
66 | </div> |
|
66 | </div> | |
67 | <div class="input"> |
|
67 | <div class="input"> | |
68 | ${h.password('new_password',class_='medium')} |
|
68 | ${h.password('new_password',class_='medium',autocomplete="off")} | |
69 | </div> |
|
69 | </div> | |
70 | </div> |
|
70 | </div> | |
71 |
|
71 |
@@ -54,7 +54,7 b'' | |||||
54 | <label for="new_password">${_('New password')}:</label> |
|
54 | <label for="new_password">${_('New password')}:</label> | |
55 | </div> |
|
55 | </div> | |
56 | <div class="input"> |
|
56 | <div class="input"> | |
57 | ${h.password('new_password',class_="medium")} |
|
57 | ${h.password('new_password',class_="medium",autocomplete="off")} | |
58 | </div> |
|
58 | </div> | |
59 | </div> |
|
59 | </div> | |
60 |
|
60 |
@@ -7,6 +7,9 b' command.' | |||||
7 | This module initializes the application via ``websetup`` (`paster |
|
7 | This module initializes the application via ``websetup`` (`paster | |
8 | setup-app`) and provides the base testing objects. |
|
8 | setup-app`) and provides the base testing objects. | |
9 | """ |
|
9 | """ | |
|
10 | import os | |||
|
11 | from os.path import join as jn | |||
|
12 | ||||
10 | from unittest import TestCase |
|
13 | from unittest import TestCase | |
11 |
|
14 | |||
12 | from paste.deploy import loadapp |
|
15 | from paste.deploy import loadapp | |
@@ -14,7 +17,7 b' from paste.script.appinstall import Setu' | |||||
14 | from pylons import config, url |
|
17 | from pylons import config, url | |
15 | from routes.util import URLGenerator |
|
18 | from routes.util import URLGenerator | |
16 | from webtest import TestApp |
|
19 | from webtest import TestApp | |
17 | import os |
|
20 | ||
18 | from rhodecode.model import meta |
|
21 | from rhodecode.model import meta | |
19 | import logging |
|
22 | import logging | |
20 |
|
23 | |||
@@ -35,7 +38,7 b' import pylons.test' | |||||
35 | environ = {} |
|
38 | environ = {} | |
36 |
|
39 | |||
37 | #SOME GLOBALS FOR TESTS |
|
40 | #SOME GLOBALS FOR TESTS | |
38 |
TESTS_TMP_PATH = '/ |
|
41 | TESTS_TMP_PATH = jn('/', 'tmp') | |
39 |
|
42 | |||
40 | HG_REPO = 'vcs_test_hg' |
|
43 | HG_REPO = 'vcs_test_hg' | |
41 | GIT_REPO = 'vcs_test_git' |
|
44 | GIT_REPO = 'vcs_test_git' | |
@@ -64,8 +67,8 b' class TestController(TestCase):' | |||||
64 | 'password':password}) |
|
67 | 'password':password}) | |
65 |
|
68 | |||
66 | if 'invalid user name' in response.body: |
|
69 | if 'invalid user name' in response.body: | |
67 |
|
|
70 | self.fail('could not login using %s %s' % (username, password)) | |
68 |
|
71 | |||
69 | assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status |
|
72 | self.assertEqual(response.status, '302 Found') | |
70 | assert response.session['rhodecode_user'].username == username, 'wrong logged in user got %s expected %s' % (response.session['rhodecode_user'].username, username) |
|
73 | self.assertEqual(response.session['rhodecode_user'].username, username) | |
71 | return response.follow() |
|
74 | return response.follow() |
@@ -6,6 +6,11 b' from rhodecode.tests import *' | |||||
6 |
|
6 | |||
7 | class TestAdminReposController(TestController): |
|
7 | class TestAdminReposController(TestController): | |
8 |
|
8 | |||
|
9 | ||||
|
10 | def __make_repo(self): | |||
|
11 | pass | |||
|
12 | ||||
|
13 | ||||
9 | def test_index(self): |
|
14 | def test_index(self): | |
10 | self.log_user() |
|
15 | self.log_user() | |
11 | response = self.app.get(url('repos')) |
|
16 | response = self.app.get(url('repos')) | |
@@ -21,31 +26,39 b' class TestAdminReposController(TestContr' | |||||
21 | private = False |
|
26 | private = False | |
22 | response = self.app.post(url('repos'), {'repo_name':repo_name, |
|
27 | response = self.app.post(url('repos'), {'repo_name':repo_name, | |
23 | 'repo_type':'hg', |
|
28 | 'repo_type':'hg', | |
|
29 | 'clone_uri':'', | |||
|
30 | 'repo_group':'', | |||
24 | 'description':description, |
|
31 | 'description':description, | |
25 | 'private':private}) |
|
32 | 'private':private}) | |
26 |
|
33 | self.assertTrue('flash' in response.session) | ||
27 |
|
34 | |||
28 | #test if we have a message for that repository |
|
35 | #test if we have a message for that repository | |
29 |
assert |
|
36 | self.assertTrue('''created repository %s''' % (repo_name) in | |
|
37 | response.session['flash'][0]) | |||
30 |
|
38 | |||
31 |
#test if the |
|
39 | #test if the repo was created in the database | |
32 |
new_repo = self.sa.query(Repository).filter(Repository.repo_name == |
|
40 | new_repo = self.sa.query(Repository).filter(Repository.repo_name == | |
|
41 | repo_name).one() | |||
33 |
|
42 | |||
34 |
assert |
|
43 | self.assertEqual(new_repo.repo_name, repo_name) | |
35 |
assert |
|
44 | self.assertEqual(new_repo.description, description) | |
36 |
|
45 | |||
37 | #test if repository is visible in the list ? |
|
46 | #test if repository is visible in the list ? | |
38 | response = response.follow() |
|
47 | response = response.follow() | |
39 |
|
48 | |||
40 | assert repo_name in response.body, 'missing new repo from the main repos list' |
|
49 | self.assertTrue(repo_name in response.body) | |
41 |
|
50 | |||
42 |
|
51 | |||
43 | #test if repository was created on filesystem |
|
52 | #test if repository was created on filesystem | |
44 | try: |
|
53 | try: | |
45 | vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name)) |
|
54 | vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name)) | |
46 | except: |
|
55 | except: | |
47 |
|
|
56 | self.fail('no repo in filesystem') | |
|
57 | ||||
48 |
|
58 | |||
|
59 | def test_create_hg_in_group(self): | |||
|
60 | #TODO: write test ! | |||
|
61 | pass | |||
49 |
|
62 | |||
50 | def test_create_git(self): |
|
63 | def test_create_git(self): | |
51 | return |
|
64 | return | |
@@ -55,6 +68,8 b' class TestAdminReposController(TestContr' | |||||
55 | private = False |
|
68 | private = False | |
56 | response = self.app.post(url('repos'), {'repo_name':repo_name, |
|
69 | response = self.app.post(url('repos'), {'repo_name':repo_name, | |
57 | 'repo_type':'git', |
|
70 | 'repo_type':'git', | |
|
71 | 'clone_uri':'', | |||
|
72 | 'repo_group':'', | |||
58 | 'description':description, |
|
73 | 'description':description, | |
59 | 'private':private}) |
|
74 | 'private':private}) | |
60 |
|
75 | |||
@@ -90,58 +105,74 b' class TestAdminReposController(TestContr' | |||||
90 | response = self.app.put(url('repo', repo_name=HG_REPO)) |
|
105 | response = self.app.put(url('repo', repo_name=HG_REPO)) | |
91 |
|
106 | |||
92 | def test_update_browser_fakeout(self): |
|
107 | def test_update_browser_fakeout(self): | |
93 |
response = self.app.post(url('repo', repo_name=HG_REPO), |
|
108 | response = self.app.post(url('repo', repo_name=HG_REPO), | |
|
109 | params=dict(_method='put')) | |||
94 |
|
110 | |||
95 | def test_delete(self): |
|
111 | def test_delete(self): | |
96 | self.log_user() |
|
112 | self.log_user() | |
97 | repo_name = 'vcs_test_new_to_delete' |
|
113 | repo_name = 'vcs_test_new_to_delete' | |
98 | description = 'description for newly created repo' |
|
114 | description = 'description for newly created repo' | |
99 | private = False |
|
115 | private = False | |
|
116 | ||||
100 | response = self.app.post(url('repos'), {'repo_name':repo_name, |
|
117 | response = self.app.post(url('repos'), {'repo_name':repo_name, | |
101 | 'repo_type':'hg', |
|
118 | 'repo_type':'hg', | |
102 |
' |
|
119 | 'clone_uri':'', | |
103 |
' |
|
120 | 'repo_group':'', | |
104 |
|
121 | 'description':description, | ||
|
122 | 'private':private}) | |||
|
123 | self.assertTrue('flash' in response.session) | |||
105 |
|
124 | |||
106 | #test if we have a message for that repository |
|
125 | #test if we have a message for that repository | |
107 |
assert |
|
126 | self.assertTrue('''created repository %s''' % (repo_name) in | |
|
127 | response.session['flash'][0]) | |||
108 |
|
128 | |||
109 | #test if the repo was created in the database |
|
129 | #test if the repo was created in the database | |
110 |
new_repo = self.sa.query(Repository).filter(Repository.repo_name == |
|
130 | new_repo = self.sa.query(Repository).filter(Repository.repo_name == | |
|
131 | repo_name).one() | |||
111 |
|
132 | |||
112 |
assert |
|
133 | self.assertEqual(new_repo.repo_name, repo_name) | |
113 |
assert |
|
134 | self.assertEqual(new_repo.description, description) | |
114 |
|
135 | |||
115 | #test if repository is visible in the list ? |
|
136 | #test if repository is visible in the list ? | |
116 | response = response.follow() |
|
137 | response = response.follow() | |
117 |
|
138 | |||
118 | assert repo_name in response.body, 'missing new repo from the main repos list' |
|
139 | self.assertTrue(repo_name in response.body) | |
119 |
|
140 | |||
120 |
|
141 | |||
121 | response = self.app.delete(url('repo', repo_name=repo_name)) |
|
142 | response = self.app.delete(url('repo', repo_name=repo_name)) | |
122 |
|
143 | |||
123 | assert '''deleted repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about delete repo' |
|
144 | self.assertTrue('''deleted repository %s''' % (repo_name) in | |
|
145 | response.session['flash'][0]) | |||
124 |
|
146 | |||
125 | response.follow() |
|
147 | response.follow() | |
126 |
|
148 | |||
127 | #check if repo was deleted from db |
|
149 | #check if repo was deleted from db | |
128 |
deleted_repo = self.sa.query(Repository).filter(Repository.repo_name |
|
150 | deleted_repo = self.sa.query(Repository).filter(Repository.repo_name | |
|
151 | == repo_name).scalar() | |||
|
152 | ||||
|
153 | self.assertEqual(deleted_repo, None) | |||
129 |
|
154 | |||
130 | assert deleted_repo is None, 'Deleted repository was found in db' |
|
155 | ||
|
156 | def test_delete_repo_with_group(self): | |||
|
157 | #TODO: | |||
|
158 | pass | |||
131 |
|
159 | |||
132 |
|
160 | |||
133 | def test_delete_browser_fakeout(self): |
|
161 | def test_delete_browser_fakeout(self): | |
134 |
response = self.app.post(url('repo', repo_name=HG_REPO), |
|
162 | response = self.app.post(url('repo', repo_name=HG_REPO), | |
|
163 | params=dict(_method='delete')) | |||
135 |
|
164 | |||
136 | def test_show(self): |
|
165 | def test_show(self): | |
137 | self.log_user() |
|
166 | self.log_user() | |
138 | response = self.app.get(url('repo', repo_name=HG_REPO)) |
|
167 | response = self.app.get(url('repo', repo_name=HG_REPO)) | |
139 |
|
168 | |||
140 | def test_show_as_xml(self): |
|
169 | def test_show_as_xml(self): | |
141 |
response = self.app.get(url('formatted_repo', repo_name=HG_REPO, |
|
170 | response = self.app.get(url('formatted_repo', repo_name=HG_REPO, | |
|
171 | format='xml')) | |||
142 |
|
172 | |||
143 | def test_edit(self): |
|
173 | def test_edit(self): | |
144 | response = self.app.get(url('edit_repo', repo_name=HG_REPO)) |
|
174 | response = self.app.get(url('edit_repo', repo_name=HG_REPO)) | |
145 |
|
175 | |||
146 | def test_edit_as_xml(self): |
|
176 | def test_edit_as_xml(self): | |
147 |
response = self.app.get(url('formatted_edit_repo', repo_name=HG_REPO, |
|
177 | response = self.app.get(url('formatted_edit_repo', repo_name=HG_REPO, | |
|
178 | format='xml')) |
@@ -1,3 +1,5 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
1 | from rhodecode.lib.auth import get_crypt_password, check_password |
|
3 | from rhodecode.lib.auth import get_crypt_password, check_password | |
2 | from rhodecode.model.db import User, RhodeCodeSettings |
|
4 | from rhodecode.model.db import User, RhodeCodeSettings | |
3 | from rhodecode.tests import * |
|
5 | from rhodecode.tests import * | |
@@ -42,7 +44,8 b' class TestAdminSettingsController(TestCo' | |||||
42 | response = self.app.get(url('admin_edit_setting', setting_id=1)) |
|
44 | response = self.app.get(url('admin_edit_setting', setting_id=1)) | |
43 |
|
45 | |||
44 | def test_edit_as_xml(self): |
|
46 | def test_edit_as_xml(self): | |
45 |
response = self.app.get(url('formatted_admin_edit_setting', |
|
47 | response = self.app.get(url('formatted_admin_edit_setting', | |
|
48 | setting_id=1, format='xml')) | |||
46 |
|
49 | |||
47 |
|
50 | |||
48 | def test_ga_code_active(self): |
|
51 | def test_ga_code_active(self): | |
@@ -58,11 +61,14 b' class TestAdminSettingsController(TestCo' | |||||
58 | rhodecode_ga_code=new_ga_code |
|
61 | rhodecode_ga_code=new_ga_code | |
59 | )) |
|
62 | )) | |
60 |
|
63 | |||
61 | assert 'Updated application settings' in response.session['flash'][0][1], 'no flash message about success of change' |
|
64 | self.assertTrue('Updated application settings' in | |
62 | assert RhodeCodeSettings.get_app_settings()['rhodecode_ga_code'] == new_ga_code, 'change not in database' |
|
65 | response.session['flash'][0][1]) | |
|
66 | self.assertEqual(RhodeCodeSettings | |||
|
67 | .get_app_settings()['rhodecode_ga_code'], new_ga_code) | |||
63 |
|
68 | |||
64 | response = response.follow() |
|
69 | response = response.follow() | |
65 |
assert |
|
70 | self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code | |
|
71 | in response.body) | |||
66 |
|
72 | |||
67 | def test_ga_code_inactive(self): |
|
73 | def test_ga_code_inactive(self): | |
68 | self.log_user() |
|
74 | self.log_user() | |
@@ -77,11 +83,14 b' class TestAdminSettingsController(TestCo' | |||||
77 | rhodecode_ga_code=new_ga_code |
|
83 | rhodecode_ga_code=new_ga_code | |
78 | )) |
|
84 | )) | |
79 |
|
85 | |||
80 | assert 'Updated application settings' in response.session['flash'][0][1], 'no flash message about success of change' |
|
86 | self.assertTrue('Updated application settings' in | |
81 | assert RhodeCodeSettings.get_app_settings()['rhodecode_ga_code'] == new_ga_code, 'change not in database' |
|
87 | response.session['flash'][0][1]) | |
|
88 | self.assertEqual(RhodeCodeSettings | |||
|
89 | .get_app_settings()['rhodecode_ga_code'], new_ga_code) | |||
82 |
|
90 | |||
83 | response = response.follow() |
|
91 | response = response.follow() | |
84 |
assert |
|
92 | self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code | |
|
93 | not in response.body) | |||
85 |
|
94 | |||
86 |
|
95 | |||
87 | def test_title_change(self): |
|
96 | def test_title_change(self): | |
@@ -89,27 +98,33 b' class TestAdminSettingsController(TestCo' | |||||
89 | old_title = 'RhodeCode' |
|
98 | old_title = 'RhodeCode' | |
90 | new_title = old_title + '_changed' |
|
99 | new_title = old_title + '_changed' | |
91 | old_realm = 'RhodeCode authentication' |
|
100 | old_realm = 'RhodeCode authentication' | |
92 | response = self.app.post(url('admin_setting', setting_id='global'), |
|
101 | ||
93 | params=dict( |
|
102 | for new_title in ['Changed', 'Żółwik', old_title]: | |
94 | _method='put', |
|
103 | response = self.app.post(url('admin_setting', setting_id='global'), | |
95 |
|
|
104 | params=dict( | |
96 |
|
|
105 | _method='put', | |
97 |
rhodecode_ |
|
106 | rhodecode_title=new_title, | |
98 |
|
|
107 | rhodecode_realm=old_realm, | |
|
108 | rhodecode_ga_code='' | |||
|
109 | )) | |||
99 |
|
110 | |||
100 |
|
111 | |||
101 | assert 'Updated application settings' in response.session['flash'][0][1], 'no flash message about success of change' |
|
112 | self.assertTrue('Updated application settings' in | |
102 | assert RhodeCodeSettings.get_app_settings()['rhodecode_title'] == new_title, 'change not in database' |
|
113 | response.session['flash'][0][1]) | |
|
114 | self.assertEqual(RhodeCodeSettings | |||
|
115 | .get_app_settings()['rhodecode_title'], | |||
|
116 | new_title.decode('utf-8')) | |||
103 |
|
117 | |||
104 | response = response.follow() |
|
118 | response = response.follow() | |
105 |
assert |
|
119 | self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title | |
|
120 | in response.body) | |||
106 |
|
121 | |||
107 |
|
122 | |||
108 | def test_my_account(self): |
|
123 | def test_my_account(self): | |
109 | self.log_user() |
|
124 | self.log_user() | |
110 | response = self.app.get(url('admin_settings_my_account')) |
|
125 | response = self.app.get(url('admin_settings_my_account')) | |
111 | print response |
|
126 | ||
112 |
assert |
|
127 | self.assertTrue('value="test_admin' in response.body) | |
113 |
|
128 | |||
114 | def test_my_account_update(self): |
|
129 | def test_my_account_update(self): | |
115 | self.log_user() |
|
130 | self.log_user() | |
@@ -120,14 +135,14 b' class TestAdminSettingsController(TestCo' | |||||
120 | new_password = 'test123' |
|
135 | new_password = 'test123' | |
121 |
|
136 | |||
122 |
|
137 | |||
123 |
response = self.app.post(url('admin_settings_my_account_update'), |
|
138 | response = self.app.post(url('admin_settings_my_account_update'), | |
124 |
|
|
139 | params=dict(_method='put', | |
125 |
|
|
140 | username='test_admin', | |
126 |
|
|
141 | new_password=new_password, | |
127 |
|
|
142 | password='', | |
128 |
|
|
143 | name=new_name, | |
129 |
|
|
144 | lastname=new_lastname, | |
130 |
|
|
145 | email=new_email,)) | |
131 | response.follow() |
|
146 | response.follow() | |
132 |
|
147 | |||
133 | assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change' |
|
148 | assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change' |
@@ -45,11 +45,11 b' class TestLoginController(TestController' | |||||
45 |
|
45 | |||
46 | def test_login_short_password(self): |
|
46 | def test_login_short_password(self): | |
47 | response = self.app.post(url(controller='login', action='index'), |
|
47 | response = self.app.post(url(controller='login', action='index'), | |
48 |
{'username':' |
|
48 | {'username':'test_admin', | |
49 |
'password':' |
|
49 | 'password':'as'}) | |
50 | assert response.status == '200 OK', 'Wrong response from login page' |
|
50 | self.assertEqual(response.status, '200 OK') | |
51 | print response.body |
|
51 | print response.body | |
52 |
assert |
|
52 | self.assertTrue('Enter 3 characters or more' in response.body) | |
53 |
|
53 | |||
54 | def test_login_wrong_username_password(self): |
|
54 | def test_login_wrong_username_password(self): | |
55 | response = self.app.post(url(controller='login', action='index'), |
|
55 | response = self.app.post(url(controller='login', action='index'), |
@@ -6,22 +6,38 b' class TestSummaryController(TestControll' | |||||
6 |
|
6 | |||
7 | def test_index(self): |
|
7 | def test_index(self): | |
8 | self.log_user() |
|
8 | self.log_user() | |
9 |
response = self.app.get(url(controller='summary', |
|
9 | response = self.app.get(url(controller='summary', | |
|
10 | action='index', repo_name=HG_REPO)) | |||
10 |
|
11 | |||
11 | #repo type |
|
12 | #repo type | |
12 | assert """<img style="margin-bottom:2px" class="icon" title="Mercurial repository" alt="Mercurial repository" src="/images/icons/hgicon.png"/>""" in response.body |
|
13 | self.assertTrue("""<img style="margin-bottom:2px" class="icon" """ | |
13 | assert """<img style="margin-bottom:2px" class="icon" title="public repository" alt="public repository" src="/images/icons/lock_open.png"/>""" in response.body |
|
14 | """title="Mercurial repository" alt="Mercurial """ | |
|
15 | """repository" src="/images/icons/hgicon.png"/>""" | |||
|
16 | in response.body) | |||
|
17 | self.assertTrue("""<img style="margin-bottom:2px" class="icon" """ | |||
|
18 | """title="public repository" alt="public """ | |||
|
19 | """repository" src="/images/icons/lock_open.png"/>""" | |||
|
20 | in response.body) | |||
14 |
|
21 | |||
15 | #codes stats |
|
22 | #codes stats | |
|
23 | self._enable_stats() | |||
16 |
|
24 | |||
17 |
|
25 | |||
18 | self._enable_stats() |
|
|||
19 | invalidate_cache('get_repo_cached_%s' % HG_REPO) |
|
26 | invalidate_cache('get_repo_cached_%s' % HG_REPO) | |
20 |
response = self.app.get(url(controller='summary', action='index', |
|
27 | response = self.app.get(url(controller='summary', action='index', | |
21 | assert """var data = {"Python": 42, "Rst": 11, "Bash": 2, "Makefile": 1, "Batch": 1, "Ini": 1, "Css": 1};""" in response.body, 'wrong info about % of codes stats' |
|
28 | repo_name=HG_REPO)) | |
|
29 | ||||
|
30 | self.assertTrue("""var data = {"py": {"count": 42, "desc": """ | |||
|
31 | """["Python"]}, "rst": {"count": 11, "desc": """ | |||
|
32 | """["Rst"]}, "sh": {"count": 2, "desc": ["Bash"]}, """ | |||
|
33 | """"makefile": {"count": 1, "desc": ["Makefile", """ | |||
|
34 | """"Makefile"]}, "cfg": {"count": 1, "desc": ["Ini"]},""" | |||
|
35 | """ "css": {"count": 1, "desc": ["Css"]}, "bat": """ | |||
|
36 | """{"count": 1, "desc": ["Batch"]}};""" | |||
|
37 | in response.body) | |||
22 |
|
38 | |||
23 | # clone url... |
|
39 | # clone url... | |
24 |
assert |
|
40 | self.assertTrue("""<input type="text" id="clone_url" readonly="readonly" value="hg clone http://test_admin@localhost:80/%s" size="70"/>""" % HG_REPO in response.body) | |
25 |
|
41 | |||
26 |
|
42 | |||
27 | def _enable_stats(self): |
|
43 | def _enable_stats(self): |
@@ -7,6 +7,7 b'' | |||||
7 |
|
7 | |||
8 | [DEFAULT] |
|
8 | [DEFAULT] | |
9 | debug = true |
|
9 | debug = true | |
|
10 | pdebug = false | |||
10 | ################################################################################ |
|
11 | ################################################################################ | |
11 | ## Uncomment and replace with the address which should receive ## |
|
12 | ## Uncomment and replace with the address which should receive ## | |
12 | ## any error reports after application crash ## |
|
13 | ## any error reports after application crash ## |
General Comments 0
You need to be logged in to leave comments.
Login now