diff --git a/docs/installation.rst b/docs/installation.rst --- a/docs/installation.rst +++ b/docs/installation.rst @@ -25,7 +25,7 @@ Or:: pip install rhodecode If you prefer to install RhodeCode manually simply grab latest release from -http://pypi.python.org/pypi/rhodecode, decompress the archive and run:: +http://pypi.python.org/pypi/RhodeCode, decompress the archive and run:: python setup.py install diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -338,12 +338,14 @@ class SettingsController(BaseController) return redirect(url('users')) defaults = c.user.get_dict() - return htmlfill.render( - render('admin/users/user_edit_my_account.html'), + + c.form = htmlfill.render( + render('admin/users/user_edit_my_account_form.html'), defaults=defaults, encoding="UTF-8", force_defaults=False ) + return render('admin/users/user_edit_my_account.html') def my_account_update(self): """PUT /_admin/my_account_update: Update an existing item""" @@ -373,12 +375,13 @@ class SettingsController(BaseController) .all() c.user_repos = ScmModel().get_repos(all_repos) - return htmlfill.render( - render('admin/users/user_edit_my_account.html'), + c.form = htmlfill.render( + render('admin/users/user_edit_my_account_form.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, encoding="UTF-8") + return render('admin/users/user_edit_my_account.html') except Exception: log.error(traceback.format_exc()) h.flash(_('error occurred during update of user %s') \ diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -27,11 +27,13 @@ import os import logging import datetime import traceback +import hashlib from collections import defaultdict from sqlalchemy import * from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship, joinedload, class_mapper, validates +from sqlalchemy.exc import DatabaseError from beaker.cache import cache_region, region_invalidate from pylons.i18n.translation import lazy_ugettext as _ @@ -47,8 +49,7 @@ from rhodecode.lib.compat import json from rhodecode.lib.caching_query import FromCache from rhodecode.model.meta import Base, Session -import hashlib -from sqlalchemy.exc import DatabaseError + URL_SEP = '/' log = logging.getLogger(__name__) @@ -155,6 +156,7 @@ class BaseModel(object): return safe_str(self.__unicode__()) return '' % (self.__class__.__name__) + class RhodeCodeSetting(Base, BaseModel): __tablename__ = 'rhodecode_settings' __table_args__ = ( @@ -225,7 +227,7 @@ class RhodeCodeSetting(Base, BaseModel): .filter(cls.app_settings_name.startswith('ldap_')).all() fd = {} for row in ret: - fd.update({row.app_settings_name:row.app_settings_value}) + fd.update({row.app_settings_name: row.app_settings_value}) return fd @@ -761,18 +763,27 @@ class Repository(Base, BaseModel): def scm_instance(self): return self.__get_instance() - @property - def scm_instance_cached(self): + def scm_instance_cached(self, cache_map=None): @cache_region('long_term') def _c(repo_name): return self.__get_instance() rn = self.repo_name log.debug('Getting cached instance of repo') - inv = self.invalidate - if inv is not None: + + if cache_map: + # get using prefilled cache_map + invalidate_repo = cache_map[self.repo_name] + if invalidate_repo: + invalidate_repo = (None if invalidate_repo.cache_active + else invalidate_repo) + else: + # get from invalidate + invalidate_repo = self.invalidate + + if invalidate_repo is not None: region_invalidate(_c, None, rn) # update our cache - CacheInvalidation.set_valid(inv.cache_key) + CacheInvalidation.set_valid(invalidate_repo.cache_key) return _c(rn) def __get_instance(self): @@ -1140,6 +1151,7 @@ class CacheInvalidation(Base, BaseModel) __tablename__ = 'cache_invalidation' __table_args__ = ( UniqueConstraint('cache_key'), + Index('key_idx', 'cache_key'), {'extend_existing': True, 'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'}, ) @@ -1156,6 +1168,7 @@ class CacheInvalidation(Base, BaseModel) def __unicode__(self): return u"<%s('%s:%s')>" % (self.__class__.__name__, self.cache_id, self.cache_key) + @classmethod def clear_cache(cls): cls.query().delete() @@ -1242,6 +1255,40 @@ class CacheInvalidation(Base, BaseModel) Session.add(inv_obj) Session.commit() + @classmethod + def get_cache_map(cls): + + class cachemapdict(dict): + + def __init__(self, *args, **kwargs): + fixkey = kwargs.get('fixkey') + if fixkey: + del kwargs['fixkey'] + self.fixkey = fixkey + super(cachemapdict, self).__init__(*args, **kwargs) + + def __getattr__(self, name): + key = name + if self.fixkey: + key, _prefix, _org_key = cls._get_key(key) + if key in self.__dict__: + return self.__dict__[key] + else: + return self[key] + + def __getitem__(self, key): + if self.fixkey: + key, _prefix, _org_key = cls._get_key(key) + try: + return super(cachemapdict, self).__getitem__(key) + except KeyError: + return + + cache_map = cachemapdict(fixkey=True) + for obj in cls.query().all(): + cache_map[obj.cache_key] = cachemapdict(obj.get_dict()) + return cache_map + class ChangesetComment(Base, BaseModel): __tablename__ = 'changeset_comments' diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py --- a/rhodecode/model/scm.py +++ b/rhodecode/model/scm.py @@ -28,6 +28,8 @@ import traceback import logging import cStringIO +from sqlalchemy import func + from rhodecode.lib.vcs import get_backend from rhodecode.lib.vcs.exceptions import RepositoryError from rhodecode.lib.vcs.utils.lazy import LazyProperty @@ -77,8 +79,12 @@ class CachedRepoList(object): return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) def __iter__(self): + # pre-propagated cache_map to save executing select statements + # for each repo + cache_map = CacheInvalidation.get_cache_map() + for dbr in self.db_repo_list: - scmr = dbr.scm_instance_cached + scmr = dbr.scm_instance_cached(cache_map) # check permission at this level if not HasRepoPermissionAny( 'repository.read', 'repository.write', 'repository.admin' @@ -219,7 +225,7 @@ class ScmModel(BaseModel): if all_repos is None: all_repos = self.sa.query(Repository)\ .filter(Repository.group_id == None)\ - .order_by(Repository.repo_name).all() + .order_by(func.lower(Repository.repo_name)).all() repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path, order_by=sort_key) diff --git a/rhodecode/templates/admin/users/user_edit_my_account.html b/rhodecode/templates/admin/users/user_edit_my_account.html --- a/rhodecode/templates/admin/users/user_edit_my_account.html +++ b/rhodecode/templates/admin/users/user_edit_my_account.html @@ -21,91 +21,7 @@ ${self.breadcrumbs()} -
- ${h.form(url('admin_settings_my_account_update'),method='put')} -
- -
-
-
gravatar
-

- %if c.use_gravatar: - ${_('Change your avatar at')} gravatar.com -
${_('Using')} ${c.user.email} - %else: -
${c.user.email} - %endif -

-
-
-
-
- ${c.user.api_key} -
-
-
-
-
- -
-
- ${h.text('username',class_="medium")} -
-
- -
-
- -
-
- ${h.password('new_password',class_="medium",autocomplete="off")} -
-
- -
-
- -
-
- ${h.password('password_confirmation',class_="medium",autocomplete="off")} -
-
- -
-
- -
-
- ${h.text('name',class_="medium")} -
-
- -
-
- -
-
- ${h.text('lastname',class_="medium")} -
-
- -
-
- -
-
- ${h.text('email',class_="medium")} -
-
- -
- ${h.submit('save',_('Save'),class_="ui-button")} - ${h.reset('reset',_('Reset'),class_="ui-button")} -
-
-
- ${h.end_form()} -
+ ${c.form|n}
diff --git a/rhodecode/templates/admin/users/user_edit_my_account_form.html b/rhodecode/templates/admin/users/user_edit_my_account_form.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/admin/users/user_edit_my_account_form.html @@ -0,0 +1,85 @@ +
+ ${h.form(url('admin_settings_my_account_update'),method='put')} +
+ +
+
+
gravatar
+

+ %if c.use_gravatar: + ${_('Change your avatar at')} gravatar.com +
${_('Using')} ${c.user.email} + %else: +
${c.user.email} + %endif +

+
+
+
+
+ ${c.user.api_key} +
+
+
+
+
+ +
+
+ ${h.text('username',class_="medium")} +
+
+ +
+
+ +
+
+ ${h.password('new_password',class_="medium",autocomplete="off")} +
+
+ +
+
+ +
+
+ ${h.password('password_confirmation',class_="medium",autocomplete="off")} +
+
+ +
+
+ +
+
+ ${h.text('name',class_="medium")} +
+
+ +
+
+ +
+
+ ${h.text('lastname',class_="medium")} +
+
+ +
+
+ +
+
+ ${h.text('email',class_="medium")} +
+
+ +
+ ${h.submit('save',_('Save'),class_="ui-button")} + ${h.reset('reset',_('Reset'),class_="ui-button")} +
+
+
+ ${h.end_form()} +
\ No newline at end of file