Show More
@@ -89,10 +89,8 b' class ReposController(BaseController):' | |||
|
89 | 89 | """ |
|
90 | 90 | self.__load_defaults() |
|
91 | 91 | |
|
92 | repo, dbrepo = ScmModel().get(repo_name, retval='repo') | |
|
93 | ||
|
94 | repo_model = RepoModel() | |
|
95 | c.repo_info = repo_model.get_by_repo_name(repo_name) | |
|
92 | c.repo_info = db_repo = Repository.by_repo_name(repo_name) | |
|
93 | repo = scm_repo = db_repo.scm_instance | |
|
96 | 94 | |
|
97 | 95 | if c.repo_info is None: |
|
98 | 96 | h.flash(_('%s repository is not mapped to db perhaps' |
@@ -153,10 +151,9 b' class ReposController(BaseController):' | |||
|
153 | 151 | """GET /repos: All items in the collection""" |
|
154 | 152 | # url('repos') |
|
155 | 153 | |
|
156 | all_repos = [r.repo_name for r in Repository.query().all()] | |
|
157 | ||
|
158 | cached_repo_list = ScmModel().get_repos(all_repos) | |
|
159 | c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort')) | |
|
154 | c.repos_list = ScmModel().get_repos(Repository.query() | |
|
155 | .order_by(Repository.repo_name) | |
|
156 | .all(), sort_key='name_sort') | |
|
160 | 157 | return render('admin/repos/repos.html') |
|
161 | 158 | |
|
162 | 159 | @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') |
@@ -181,12 +181,14 b' class ReposGroupsController(BaseControll' | |||
|
181 | 181 | """GET /repos_groups/id: Show a specific item""" |
|
182 | 182 | # url('repos_group', id=ID) |
|
183 | 183 | |
|
184 | c.group = Group.get(id) | |
|
184 | gr = c.group = Group.get(id) | |
|
185 | ||
|
185 | 186 | if c.group: |
|
186 | 187 | c.group_repos = c.group.repositories.all() |
|
187 | 188 | else: |
|
188 | 189 | return redirect(url('repos_group')) |
|
189 | 190 | |
|
191 | ||
|
190 | 192 | sortables = ['name', 'description', 'last_change', 'tip', 'owner'] |
|
191 | 193 | current_sort = request.GET.get('sort', 'name') |
|
192 | 194 | current_sort_slug = current_sort.replace('-', '') |
@@ -201,18 +203,12 b' class ReposGroupsController(BaseControll' | |||
|
201 | 203 | sort_key = current_sort_slug + '_sort' |
|
202 | 204 | |
|
203 | 205 | #overwrite our cached list with current filter |
|
204 |
gr_filter = |
|
|
206 | gr_filter = c.group_repos | |
|
205 | 207 | c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter) |
|
206 | 208 | |
|
207 | if c.sort_by.startswith('-'): | |
|
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) | |
|
209 | c.repos_list = c.cached_repo_list | |
|
213 | 210 | |
|
214 |
c.repo_cnt = |
|
|
215 | ||
|
211 | c.repo_cnt = 0 | |
|
216 | 212 | |
|
217 | 213 | c.groups = self.sa.query(Group).order_by(Group.group_name)\ |
|
218 | 214 | .filter(Group.group_parent_id == id).all() |
@@ -258,9 +258,10 b' class SettingsController(BaseController)' | |||
|
258 | 258 | # url('admin_settings_my_account') |
|
259 | 259 | |
|
260 | 260 | c.user = UserModel().get(self.rhodecode_user.user_id, cache=False) |
|
261 |
all_repos = |
|
|
261 | all_repos = self.sa.query(Repository)\ | |
|
262 | 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 | 265 | c.user_repos = ScmModel().get_repos(all_repos) |
|
265 | 266 | |
|
266 | 267 | if c.user.username == 'default': |
@@ -31,7 +31,7 b' from paste.httpexceptions import HTTPBad' | |||
|
31 | 31 | |
|
32 | 32 | from rhodecode.lib.auth import LoginRequired |
|
33 | 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 | 36 | log = logging.getLogger(__name__) |
|
37 | 37 | |
@@ -56,16 +56,11 b' class HomeController(BaseController):' | |||
|
56 | 56 | |
|
57 | 57 | sort_key = current_sort_slug + '_sort' |
|
58 | 58 | |
|
59 | if c.sort_by.startswith('-'): | |
|
60 | c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), | |
|
61 | reverse=True) | |
|
62 | else: | |
|
63 | c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), | |
|
64 | reverse=False) | |
|
59 | ||
|
60 | c.repos_list = self.scm_model.get_repos(sort_key=sort_key) | |
|
65 | 61 | |
|
66 | 62 | c.repo_cnt = len(c.repos_list) |
|
67 | 63 | |
|
68 | ||
|
69 | 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 | 69 | def repo_switcher(self): |
|
75 | 70 | if request.is_xhr: |
|
76 | c.repos_list = sorted(c.cached_repo_list, | |
|
77 | key=itemgetter('name_sort'), reverse=False) | |
|
71 | all_repos = Repository.query().order_by(Repository.repo_name).all() | |
|
72 | c.repos_list = self.scm_model.get_repos(all_repos, | |
|
73 | sort_key='name_sort') | |
|
78 | 74 | return render('/repo_switcher_list.html') |
|
79 | 75 | else: |
|
80 | 76 | return HTTPBadRequest() |
@@ -155,6 +155,7 b' class SettingsController(BaseRepoControl' | |||
|
155 | 155 | invalidate_cache('get_repo_cached_%s' % repo_name) |
|
156 | 156 | h.flash(_('deleted repository %s') % repo_name, category='success') |
|
157 | 157 | except Exception: |
|
158 | log.error(traceback.format_exc()) | |
|
158 | 159 | h.flash(_('An error occurred during deletion of %s') % repo_name, |
|
159 | 160 | category='error') |
|
160 | 161 | |
@@ -205,4 +206,9 b' class SettingsController(BaseRepoControl' | |||
|
205 | 206 | errors=errors.error_dict or {}, |
|
206 | 207 | prefix_error=False, |
|
207 | 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 | 214 | return redirect(url('home')) |
@@ -12,6 +12,7 b' from rhodecode.lib.utils import get_repo' | |||
|
12 | 12 | from rhodecode.model import meta |
|
13 | 13 | from rhodecode.model.scm import ScmModel |
|
14 | 14 | from rhodecode import BACKENDS |
|
15 | from rhodecode.model.db import Repository | |
|
15 | 16 | |
|
16 | 17 | |
|
17 | 18 | class BaseController(WSGIController): |
@@ -26,7 +27,7 b' class BaseController(WSGIController):' | |||
|
26 | 27 | |
|
27 | 28 | self.sa = meta.Session() |
|
28 | 29 | self.scm_model = ScmModel(self.sa) |
|
29 | c.cached_repo_list = self.scm_model.get_repos() | |
|
30 | ||
|
30 | 31 | #c.unread_journal = scm_model.get_unread_journal() |
|
31 | 32 | |
|
32 | 33 | def __call__(self, environ, start_response): |
@@ -62,8 +63,7 b' class BaseRepoController(BaseController)' | |||
|
62 | 63 | super(BaseRepoController, self).__before__() |
|
63 | 64 | if c.repo_name: |
|
64 | 65 | |
|
65 |
c.rhodecode_repo |
|
|
66 | retval='repo') | |
|
66 | c.rhodecode_repo = Repository.by_repo_name(c.repo_name).scm_instance | |
|
67 | 67 | |
|
68 | 68 | if c.rhodecode_repo is not None: |
|
69 | 69 | c.repository_followers = \ |
@@ -102,7 +102,6 b' def get_commits_stats(repo_name, ts_min_' | |||
|
102 | 102 | lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, |
|
103 | 103 | ts_max_y) |
|
104 | 104 | lockkey_path = dn(dn(dn(dn(os.path.abspath(__file__))))) |
|
105 | print jn(lockkey_path, lockkey) | |
|
106 | 105 | log.info('running task with lockkey %s', lockkey) |
|
107 | 106 | try: |
|
108 | 107 | lock = l = DaemonLock(jn(lockkey_path, lockkey)) |
@@ -372,8 +372,7 b' def action_parser(user_log, feed=False):' | |||
|
372 | 372 | repo_name = user_log.repository.repo_name |
|
373 | 373 | |
|
374 | 374 | from rhodecode.model.scm import ScmModel |
|
375 | repo, dbrepo = ScmModel().get(repo_name, retval='repo', | |
|
376 | invalidation_list=[]) | |
|
375 | repo = user_log.repository.scm_instance | |
|
377 | 376 | |
|
378 | 377 | message = lambda rev: get_changeset_safe(repo, rev).message |
|
379 | 378 | cs_links = [] |
@@ -472,7 +472,7 b' def create_test_index(repo_location, ful' | |||
|
472 | 472 | shutil.rmtree(index_location) |
|
473 | 473 | |
|
474 | 474 | try: |
|
475 |
l = DaemonLock(file=jn(dn( |
|
|
475 | l = DaemonLock(file=jn(dn(index_location), 'make_index.lock')) | |
|
476 | 476 | WhooshIndexingDaemon(index_location=index_location, |
|
477 | 477 | repo_location=repo_location)\ |
|
478 | 478 | .run(full_index=full_index) |
@@ -26,13 +26,23 b'' | |||
|
26 | 26 | import os |
|
27 | 27 | import logging |
|
28 | 28 | import datetime |
|
29 | import traceback | |
|
29 | 30 | from datetime import date |
|
30 | 31 | |
|
31 | 32 | from sqlalchemy import * |
|
32 | 33 | from sqlalchemy.exc import DatabaseError |
|
33 | from sqlalchemy.orm import relationship, backref | |
|
34 | from sqlalchemy.orm import relationship, backref, joinedload | |
|
34 | 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 | 46 | from rhodecode.lib import str2bool |
|
37 | 47 | from rhodecode.model.meta import Base, Session |
|
38 | 48 | from rhodecode.model.caching_query import FromCache |
@@ -150,6 +160,7 b' class User(Base):' | |||
|
150 | 160 | return self.admin |
|
151 | 161 | |
|
152 | 162 | def __repr__(self): |
|
163 | return 'ahmmm' | |
|
153 | 164 | return "<%s('id:%s:%s')>" % (self.__class__.__name__, |
|
154 | 165 | self.user_id, self.username) |
|
155 | 166 | |
@@ -266,8 +277,13 b' class Repository(Base):' | |||
|
266 | 277 | |
|
267 | 278 | @classmethod |
|
268 | 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 | 288 | @classmethod |
|
273 | 289 | def get_repo_forks(cls, repo_id): |
@@ -298,6 +314,127 b' class Repository(Base):' | |||
|
298 | 314 | def groups_and_repo(self): |
|
299 | 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 | 439 | class Group(Base): |
|
303 | 440 | __tablename__ = 'groups' |
@@ -280,6 +280,13 b' def ValidRepoName(edit, old_data):' | |||
|
280 | 280 | |
|
281 | 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 | 290 | def SlugifyName(): |
|
284 | 291 | class _SlugifyName(formencode.validators.FancyValidator): |
|
285 | 292 | |
@@ -326,6 +333,7 b' def ValidForkType(old_data):' | |||
|
326 | 333 | if old_data['repo_type'] != value: |
|
327 | 334 | raise formencode.Invalid(_('Fork have to be the same ' |
|
328 | 335 | 'type as original'), value, state) |
|
336 | ||
|
329 | 337 | return value |
|
330 | 338 | return _ValidForkType |
|
331 | 339 | |
@@ -583,6 +591,9 b' def RepoForkForm(edit=False, old_data={}' | |||
|
583 | 591 | description = UnicodeString(strip=True, min=1, not_empty=True) |
|
584 | 592 | private = StringBoolean(if_missing=False) |
|
585 | 593 | repo_type = All(ValidForkType(old_data), OneOf(supported_backends)) |
|
594 | ||
|
595 | chained_validators = [ValidForkName()] | |
|
596 | ||
|
586 | 597 | return _RepoForkForm |
|
587 | 598 | |
|
588 | 599 | def RepoSettingsForm(edit=False, old_data={}): |
@@ -70,28 +70,6 b' class RepoModel(BaseModel):' | |||
|
70 | 70 | "get_repo_%s" % repo_name)) |
|
71 | 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 | 74 | def get_users_js(self): |
|
97 | 75 | |
@@ -193,12 +171,13 b' class RepoModel(BaseModel):' | |||
|
193 | 171 | raise |
|
194 | 172 | |
|
195 | 173 | def create(self, form_data, cur_user, just_db=False, fork=False): |
|
174 | ||
|
196 | 175 | try: |
|
197 | 176 | if fork: |
|
198 | 177 | #force str since hg doesn't go with unicode |
|
199 | 178 | repo_name = str(form_data['fork_name']) |
|
200 | 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 | 182 | else: |
|
204 | 183 | org_name = repo_name = str(form_data['repo_name']) |
@@ -208,6 +187,9 b' class RepoModel(BaseModel):' | |||
|
208 | 187 | new_repo.enable_statistics = False |
|
209 | 188 | for k, v in form_data.items(): |
|
210 | 189 | if k == 'repo_name': |
|
190 | if fork: | |
|
191 | v = repo_name | |
|
192 | else: | |
|
211 | 193 | v = repo_name_full |
|
212 | 194 | if k == 'repo_group': |
|
213 | 195 | k = 'group_id' |
@@ -216,7 +198,7 b' class RepoModel(BaseModel):' | |||
|
216 | 198 | |
|
217 | 199 | if fork: |
|
218 | 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 | 202 | new_repo.fork = parent_repo |
|
221 | 203 | |
|
222 | 204 | new_repo.user_id = cur_user.user_id |
@@ -70,6 +70,75 b' class RepoTemp(object):' | |||
|
70 | 70 | def __repr__(self): |
|
71 | 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 | 143 | class ScmModel(BaseModel): |
|
75 | 144 | """Generic Scm Model |
@@ -118,7 +187,7 b' class ScmModel(BaseModel):' | |||
|
118 | 187 | |
|
119 | 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 | 192 | Get all repos from db and for each repo create it's |
|
124 | 193 | backend instance and fill that backed with information from database |
@@ -127,120 +196,21 b' class ScmModel(BaseModel):' | |||
|
127 | 196 | give specific repositories list, good for filtering |
|
128 | 197 | """ |
|
129 | 198 | if all_repos is None: |
|
130 | repos = self.sa.query(Repository)\ | |
|
199 | all_repos = self.sa.query(Repository)\ | |
|
131 | 200 | .filter(Repository.group_id == None)\ |
|
132 | 201 | .order_by(Repository.repo_name).all() |
|
133 | all_repos = [r.repo_name for r in repos] | |
|
134 | 202 | |
|
135 | 203 | #get the repositories that should be invalidated |
|
136 | 204 | invalidation_list = [str(x.cache_key) for x in \ |
|
137 | 205 | self.sa.query(CacheInvalidation.cache_key)\ |
|
138 | 206 | .filter(CacheInvalidation.cache_active == False)\ |
|
139 | 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 | #====================================================================== | |
|
193 | # CACHE FUNCTION | |
|
194 | #====================================================================== | |
|
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 | |
|
209 | repo_iter = CachedRepoList(all_repos, invalidation_list, | |
|
210 | repos_path=self.repos_path, | |
|
211 | order_by=sort_key) | |
|
210 | 212 | |
|
211 | if alias == 'hg': | |
|
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 | |
|
213 | return repo_iter | |
|
244 | 214 | |
|
245 | 215 | def mark_for_invalidation(self, repo_name): |
|
246 | 216 | """Puts cache invalidation task into db for |
@@ -65,7 +65,7 b'' | |||
|
65 | 65 | <label for="new_password">${_('New password')}:</label> |
|
66 | 66 | </div> |
|
67 | 67 | <div class="input"> |
|
68 | ${h.password('new_password',class_='medium')} | |
|
68 | ${h.password('new_password',class_='medium',autocomplete="off")} | |
|
69 | 69 | </div> |
|
70 | 70 | </div> |
|
71 | 71 |
@@ -54,7 +54,7 b'' | |||
|
54 | 54 | <label for="new_password">${_('New password')}:</label> |
|
55 | 55 | </div> |
|
56 | 56 | <div class="input"> |
|
57 | ${h.password('new_password',class_="medium")} | |
|
57 | ${h.password('new_password',class_="medium",autocomplete="off")} | |
|
58 | 58 | </div> |
|
59 | 59 | </div> |
|
60 | 60 |
@@ -7,6 +7,9 b' command.' | |||
|
7 | 7 | This module initializes the application via ``websetup`` (`paster |
|
8 | 8 | setup-app`) and provides the base testing objects. |
|
9 | 9 | """ |
|
10 | import os | |
|
11 | from os.path import join as jn | |
|
12 | ||
|
10 | 13 | from unittest import TestCase |
|
11 | 14 | |
|
12 | 15 | from paste.deploy import loadapp |
@@ -14,7 +17,7 b' from paste.script.appinstall import Setu' | |||
|
14 | 17 | from pylons import config, url |
|
15 | 18 | from routes.util import URLGenerator |
|
16 | 19 | from webtest import TestApp |
|
17 | import os | |
|
20 | ||
|
18 | 21 | from rhodecode.model import meta |
|
19 | 22 | import logging |
|
20 | 23 | |
@@ -35,7 +38,7 b' import pylons.test' | |||
|
35 | 38 | environ = {} |
|
36 | 39 | |
|
37 | 40 | #SOME GLOBALS FOR TESTS |
|
38 |
TESTS_TMP_PATH = '/ |
|
|
41 | TESTS_TMP_PATH = jn('/', 'tmp') | |
|
39 | 42 | |
|
40 | 43 | HG_REPO = 'vcs_test_hg' |
|
41 | 44 | GIT_REPO = 'vcs_test_git' |
@@ -64,8 +67,8 b' class TestController(TestCase):' | |||
|
64 | 67 | 'password':password}) |
|
65 | 68 | |
|
66 | 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 | |
|
70 | assert response.session['rhodecode_user'].username == username, 'wrong logged in user got %s expected %s' % (response.session['rhodecode_user'].username, username) | |
|
72 | self.assertEqual(response.status, '302 Found') | |
|
73 | self.assertEqual(response.session['rhodecode_user'].username, username) | |
|
71 | 74 | return response.follow() |
@@ -6,6 +6,11 b' from rhodecode.tests import *' | |||
|
6 | 6 | |
|
7 | 7 | class TestAdminReposController(TestController): |
|
8 | 8 | |
|
9 | ||
|
10 | def __make_repo(self): | |
|
11 | pass | |
|
12 | ||
|
13 | ||
|
9 | 14 | def test_index(self): |
|
10 | 15 | self.log_user() |
|
11 | 16 | response = self.app.get(url('repos')) |
@@ -21,31 +26,39 b' class TestAdminReposController(TestContr' | |||
|
21 | 26 | private = False |
|
22 | 27 | response = self.app.post(url('repos'), {'repo_name':repo_name, |
|
23 | 28 | 'repo_type':'hg', |
|
29 | 'clone_uri':'', | |
|
30 | 'repo_group':'', | |
|
24 | 31 | 'description':description, |
|
25 | 32 | 'private':private}) |
|
26 | ||
|
33 | self.assertTrue('flash' in response.session) | |
|
27 | 34 | |
|
28 | 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 |
|
|
32 |
new_repo = self.sa.query(Repository).filter(Repository.repo_name == |
|
|
39 | #test if the repo was created in the database | |
|
40 | new_repo = self.sa.query(Repository).filter(Repository.repo_name == | |
|
41 | repo_name).one() | |
|
33 | 42 | |
|
34 |
assert |
|
|
35 |
assert |
|
|
43 | self.assertEqual(new_repo.repo_name, repo_name) | |
|
44 | self.assertEqual(new_repo.description, description) | |
|
36 | 45 | |
|
37 | 46 | #test if repository is visible in the list ? |
|
38 | 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 | 52 | #test if repository was created on filesystem |
|
44 | 53 | try: |
|
45 | 54 | vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name)) |
|
46 | 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 | 63 | def test_create_git(self): |
|
51 | 64 | return |
@@ -55,6 +68,8 b' class TestAdminReposController(TestContr' | |||
|
55 | 68 | private = False |
|
56 | 69 | response = self.app.post(url('repos'), {'repo_name':repo_name, |
|
57 | 70 | 'repo_type':'git', |
|
71 | 'clone_uri':'', | |
|
72 | 'repo_group':'', | |
|
58 | 73 | 'description':description, |
|
59 | 74 | 'private':private}) |
|
60 | 75 | |
@@ -90,58 +105,74 b' class TestAdminReposController(TestContr' | |||
|
90 | 105 | response = self.app.put(url('repo', repo_name=HG_REPO)) |
|
91 | 106 | |
|
92 | 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 | 111 | def test_delete(self): |
|
96 | 112 | self.log_user() |
|
97 | 113 | repo_name = 'vcs_test_new_to_delete' |
|
98 | 114 | description = 'description for newly created repo' |
|
99 | 115 | private = False |
|
116 | ||
|
100 | 117 | response = self.app.post(url('repos'), {'repo_name':repo_name, |
|
101 | 118 | 'repo_type':'hg', |
|
119 | 'clone_uri':'', | |
|
120 | 'repo_group':'', | |
|
102 | 121 | 'description':description, |
|
103 | 122 | 'private':private}) |
|
104 | ||
|
123 | self.assertTrue('flash' in response.session) | |
|
105 | 124 | |
|
106 | 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 | 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 |
|
|
113 |
assert |
|
|
133 | self.assertEqual(new_repo.repo_name, repo_name) | |
|
134 | self.assertEqual(new_repo.description, description) | |
|
114 | 135 | |
|
115 | 136 | #test if repository is visible in the list ? |
|
116 | 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 | 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 | 147 | response.follow() |
|
126 | 148 | |
|
127 | 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 | 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 | 165 | def test_show(self): |
|
137 | 166 | self.log_user() |
|
138 | 167 | response = self.app.get(url('repo', repo_name=HG_REPO)) |
|
139 | 168 | |
|
140 | 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 | 173 | def test_edit(self): |
|
144 | 174 | response = self.app.get(url('edit_repo', repo_name=HG_REPO)) |
|
145 | 175 | |
|
146 | 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 | 3 | from rhodecode.lib.auth import get_crypt_password, check_password |
|
2 | 4 | from rhodecode.model.db import User, RhodeCodeSettings |
|
3 | 5 | from rhodecode.tests import * |
@@ -42,7 +44,8 b' class TestAdminSettingsController(TestCo' | |||
|
42 | 44 | response = self.app.get(url('admin_edit_setting', setting_id=1)) |
|
43 | 45 | |
|
44 | 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 | 51 | def test_ga_code_active(self): |
@@ -58,11 +61,14 b' class TestAdminSettingsController(TestCo' | |||
|
58 | 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' | |
|
62 | assert RhodeCodeSettings.get_app_settings()['rhodecode_ga_code'] == new_ga_code, 'change not in database' | |
|
64 | self.assertTrue('Updated application settings' in | |
|
65 | response.session['flash'][0][1]) | |
|
66 | self.assertEqual(RhodeCodeSettings | |
|
67 | .get_app_settings()['rhodecode_ga_code'], new_ga_code) | |
|
63 | 68 | |
|
64 | 69 | response = response.follow() |
|
65 |
assert |
|
|
70 | self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code | |
|
71 | in response.body) | |
|
66 | 72 | |
|
67 | 73 | def test_ga_code_inactive(self): |
|
68 | 74 | self.log_user() |
@@ -77,11 +83,14 b' class TestAdminSettingsController(TestCo' | |||
|
77 | 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' | |
|
81 | assert RhodeCodeSettings.get_app_settings()['rhodecode_ga_code'] == new_ga_code, 'change not in database' | |
|
86 | self.assertTrue('Updated application settings' in | |
|
87 | response.session['flash'][0][1]) | |
|
88 | self.assertEqual(RhodeCodeSettings | |
|
89 | .get_app_settings()['rhodecode_ga_code'], new_ga_code) | |
|
82 | 90 | |
|
83 | 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 | 96 | def test_title_change(self): |
@@ -89,6 +98,8 b' class TestAdminSettingsController(TestCo' | |||
|
89 | 98 | old_title = 'RhodeCode' |
|
90 | 99 | new_title = old_title + '_changed' |
|
91 | 100 | old_realm = 'RhodeCode authentication' |
|
101 | ||
|
102 | for new_title in ['Changed', 'Żółwik', old_title]: | |
|
92 | 103 | response = self.app.post(url('admin_setting', setting_id='global'), |
|
93 | 104 | params=dict( |
|
94 | 105 | _method='put', |
@@ -98,18 +109,22 b' class TestAdminSettingsController(TestCo' | |||
|
98 | 109 | )) |
|
99 | 110 | |
|
100 | 111 | |
|
101 | assert 'Updated application settings' in response.session['flash'][0][1], 'no flash message about success of change' | |
|
102 | assert RhodeCodeSettings.get_app_settings()['rhodecode_title'] == new_title, 'change not in database' | |
|
112 | self.assertTrue('Updated application settings' in | |
|
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 | 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 | 123 | def test_my_account(self): |
|
109 | 124 | self.log_user() |
|
110 | 125 | response = self.app.get(url('admin_settings_my_account')) |
|
111 | print response | |
|
112 |
assert |
|
|
126 | ||
|
127 | self.assertTrue('value="test_admin' in response.body) | |
|
113 | 128 | |
|
114 | 129 | def test_my_account_update(self): |
|
115 | 130 | self.log_user() |
@@ -120,8 +135,8 b' class TestAdminSettingsController(TestCo' | |||
|
120 | 135 | new_password = 'test123' |
|
121 | 136 | |
|
122 | 137 | |
|
123 |
response = self.app.post(url('admin_settings_my_account_update'), |
|
|
124 |
|
|
|
138 | response = self.app.post(url('admin_settings_my_account_update'), | |
|
139 | params=dict(_method='put', | |
|
125 | 140 |
|
|
126 | 141 |
|
|
127 | 142 |
|
@@ -45,11 +45,11 b' class TestLoginController(TestController' | |||
|
45 | 45 | |
|
46 | 46 | def test_login_short_password(self): |
|
47 | 47 | response = self.app.post(url(controller='login', action='index'), |
|
48 |
{'username':' |
|
|
49 |
'password':' |
|
|
50 | assert response.status == '200 OK', 'Wrong response from login page' | |
|
48 | {'username':'test_admin', | |
|
49 | 'password':'as'}) | |
|
50 | self.assertEqual(response.status, '200 OK') | |
|
51 | 51 | print response.body |
|
52 |
assert |
|
|
52 | self.assertTrue('Enter 3 characters or more' in response.body) | |
|
53 | 53 | |
|
54 | 54 | def test_login_wrong_username_password(self): |
|
55 | 55 | response = self.app.post(url(controller='login', action='index'), |
@@ -6,22 +6,38 b' class TestSummaryController(TestControll' | |||
|
6 | 6 | |
|
7 | 7 | def test_index(self): |
|
8 | 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 | 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 | assert """<img style="margin-bottom:2px" class="icon" title="public repository" alt="public repository" src="/images/icons/lock_open.png"/>""" in response.body | |
|
13 | self.assertTrue("""<img style="margin-bottom:2px" class="icon" """ | |
|
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 | 22 | #codes stats |
|
23 | self._enable_stats() | |
|
16 | 24 | |
|
17 | 25 | |
|
18 | self._enable_stats() | |
|
19 | 26 | invalidate_cache('get_repo_cached_%s' % HG_REPO) |
|
20 |
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' | |
|
27 | response = self.app.get(url(controller='summary', action='index', | |
|
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 | 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 | 43 | def _enable_stats(self): |
General Comments 0
You need to be logged in to leave comments.
Login now