Show More
@@ -0,0 +1,85 b'' | |||||
|
1 | <div> | |||
|
2 | ${h.form(url('admin_settings_my_account_update'),method='put')} | |||
|
3 | <div class="form"> | |||
|
4 | ||||
|
5 | <div class="field"> | |||
|
6 | <div class="gravatar_box"> | |||
|
7 | <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div> | |||
|
8 | <p> | |||
|
9 | %if c.use_gravatar: | |||
|
10 | <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong> | |||
|
11 | <br/>${_('Using')} ${c.user.email} | |||
|
12 | %else: | |||
|
13 | <br/>${c.user.email} | |||
|
14 | %endif | |||
|
15 | </p> | |||
|
16 | </div> | |||
|
17 | </div> | |||
|
18 | <div class="field"> | |||
|
19 | <div class="label"> | |||
|
20 | <label>${_('API key')}</label> ${c.user.api_key} | |||
|
21 | </div> | |||
|
22 | </div> | |||
|
23 | <div class="fields"> | |||
|
24 | <div class="field"> | |||
|
25 | <div class="label"> | |||
|
26 | <label for="username">${_('Username')}:</label> | |||
|
27 | </div> | |||
|
28 | <div class="input"> | |||
|
29 | ${h.text('username',class_="medium")} | |||
|
30 | </div> | |||
|
31 | </div> | |||
|
32 | ||||
|
33 | <div class="field"> | |||
|
34 | <div class="label"> | |||
|
35 | <label for="new_password">${_('New password')}:</label> | |||
|
36 | </div> | |||
|
37 | <div class="input"> | |||
|
38 | ${h.password('new_password',class_="medium",autocomplete="off")} | |||
|
39 | </div> | |||
|
40 | </div> | |||
|
41 | ||||
|
42 | <div class="field"> | |||
|
43 | <div class="label"> | |||
|
44 | <label for="password_confirmation">${_('New password confirmation')}:</label> | |||
|
45 | </div> | |||
|
46 | <div class="input"> | |||
|
47 | ${h.password('password_confirmation',class_="medium",autocomplete="off")} | |||
|
48 | </div> | |||
|
49 | </div> | |||
|
50 | ||||
|
51 | <div class="field"> | |||
|
52 | <div class="label"> | |||
|
53 | <label for="name">${_('First Name')}:</label> | |||
|
54 | </div> | |||
|
55 | <div class="input"> | |||
|
56 | ${h.text('name',class_="medium")} | |||
|
57 | </div> | |||
|
58 | </div> | |||
|
59 | ||||
|
60 | <div class="field"> | |||
|
61 | <div class="label"> | |||
|
62 | <label for="lastname">${_('Last Name')}:</label> | |||
|
63 | </div> | |||
|
64 | <div class="input"> | |||
|
65 | ${h.text('lastname',class_="medium")} | |||
|
66 | </div> | |||
|
67 | </div> | |||
|
68 | ||||
|
69 | <div class="field"> | |||
|
70 | <div class="label"> | |||
|
71 | <label for="email">${_('Email')}:</label> | |||
|
72 | </div> | |||
|
73 | <div class="input"> | |||
|
74 | ${h.text('email',class_="medium")} | |||
|
75 | </div> | |||
|
76 | </div> | |||
|
77 | ||||
|
78 | <div class="buttons"> | |||
|
79 | ${h.submit('save',_('Save'),class_="ui-button")} | |||
|
80 | ${h.reset('reset',_('Reset'),class_="ui-button")} | |||
|
81 | </div> | |||
|
82 | </div> | |||
|
83 | </div> | |||
|
84 | ${h.end_form()} | |||
|
85 | </div> No newline at end of file |
@@ -25,7 +25,7 b' Or::' | |||||
25 | pip install rhodecode |
|
25 | pip install rhodecode | |
26 |
|
26 | |||
27 | If you prefer to install RhodeCode manually simply grab latest release from |
|
27 | If you prefer to install RhodeCode manually simply grab latest release from | |
28 |
http://pypi.python.org/pypi/ |
|
28 | http://pypi.python.org/pypi/RhodeCode, decompress the archive and run:: | |
29 |
|
29 | |||
30 | python setup.py install |
|
30 | python setup.py install | |
31 |
|
31 |
@@ -338,12 +338,14 b' class SettingsController(BaseController)' | |||||
338 | return redirect(url('users')) |
|
338 | return redirect(url('users')) | |
339 |
|
339 | |||
340 | defaults = c.user.get_dict() |
|
340 | defaults = c.user.get_dict() | |
341 | return htmlfill.render( |
|
341 | ||
342 | render('admin/users/user_edit_my_account.html'), |
|
342 | c.form = htmlfill.render( | |
|
343 | render('admin/users/user_edit_my_account_form.html'), | |||
343 | defaults=defaults, |
|
344 | defaults=defaults, | |
344 | encoding="UTF-8", |
|
345 | encoding="UTF-8", | |
345 | force_defaults=False |
|
346 | force_defaults=False | |
346 | ) |
|
347 | ) | |
|
348 | return render('admin/users/user_edit_my_account.html') | |||
347 |
|
349 | |||
348 | def my_account_update(self): |
|
350 | def my_account_update(self): | |
349 | """PUT /_admin/my_account_update: Update an existing item""" |
|
351 | """PUT /_admin/my_account_update: Update an existing item""" | |
@@ -373,12 +375,13 b' class SettingsController(BaseController)' | |||||
373 | .all() |
|
375 | .all() | |
374 | c.user_repos = ScmModel().get_repos(all_repos) |
|
376 | c.user_repos = ScmModel().get_repos(all_repos) | |
375 |
|
377 | |||
376 |
|
|
378 | c.form = htmlfill.render( | |
377 | render('admin/users/user_edit_my_account.html'), |
|
379 | render('admin/users/user_edit_my_account_form.html'), | |
378 | defaults=errors.value, |
|
380 | defaults=errors.value, | |
379 | errors=errors.error_dict or {}, |
|
381 | errors=errors.error_dict or {}, | |
380 | prefix_error=False, |
|
382 | prefix_error=False, | |
381 | encoding="UTF-8") |
|
383 | encoding="UTF-8") | |
|
384 | return render('admin/users/user_edit_my_account.html') | |||
382 | except Exception: |
|
385 | except Exception: | |
383 | log.error(traceback.format_exc()) |
|
386 | log.error(traceback.format_exc()) | |
384 | h.flash(_('error occurred during update of user %s') \ |
|
387 | h.flash(_('error occurred during update of user %s') \ |
@@ -27,11 +27,13 b' import os' | |||||
27 | import logging |
|
27 | import logging | |
28 | import datetime |
|
28 | import datetime | |
29 | import traceback |
|
29 | import traceback | |
|
30 | import hashlib | |||
30 | from collections import defaultdict |
|
31 | from collections import defaultdict | |
31 |
|
32 | |||
32 | from sqlalchemy import * |
|
33 | from sqlalchemy import * | |
33 | from sqlalchemy.ext.hybrid import hybrid_property |
|
34 | from sqlalchemy.ext.hybrid import hybrid_property | |
34 | from sqlalchemy.orm import relationship, joinedload, class_mapper, validates |
|
35 | from sqlalchemy.orm import relationship, joinedload, class_mapper, validates | |
|
36 | from sqlalchemy.exc import DatabaseError | |||
35 | from beaker.cache import cache_region, region_invalidate |
|
37 | from beaker.cache import cache_region, region_invalidate | |
36 |
|
38 | |||
37 | from pylons.i18n.translation import lazy_ugettext as _ |
|
39 | from pylons.i18n.translation import lazy_ugettext as _ | |
@@ -47,8 +49,7 b' from rhodecode.lib.compat import json' | |||||
47 | from rhodecode.lib.caching_query import FromCache |
|
49 | from rhodecode.lib.caching_query import FromCache | |
48 |
|
50 | |||
49 | from rhodecode.model.meta import Base, Session |
|
51 | from rhodecode.model.meta import Base, Session | |
50 | import hashlib |
|
52 | ||
51 | from sqlalchemy.exc import DatabaseError |
|
|||
52 |
|
53 | |||
53 | URL_SEP = '/' |
|
54 | URL_SEP = '/' | |
54 | log = logging.getLogger(__name__) |
|
55 | log = logging.getLogger(__name__) | |
@@ -155,6 +156,7 b' class BaseModel(object):' | |||||
155 | return safe_str(self.__unicode__()) |
|
156 | return safe_str(self.__unicode__()) | |
156 | return '<DB:%s>' % (self.__class__.__name__) |
|
157 | return '<DB:%s>' % (self.__class__.__name__) | |
157 |
|
158 | |||
|
159 | ||||
158 | class RhodeCodeSetting(Base, BaseModel): |
|
160 | class RhodeCodeSetting(Base, BaseModel): | |
159 | __tablename__ = 'rhodecode_settings' |
|
161 | __tablename__ = 'rhodecode_settings' | |
160 | __table_args__ = ( |
|
162 | __table_args__ = ( | |
@@ -225,7 +227,7 b' class RhodeCodeSetting(Base, BaseModel):' | |||||
225 | .filter(cls.app_settings_name.startswith('ldap_')).all() |
|
227 | .filter(cls.app_settings_name.startswith('ldap_')).all() | |
226 | fd = {} |
|
228 | fd = {} | |
227 | for row in ret: |
|
229 | for row in ret: | |
228 | fd.update({row.app_settings_name:row.app_settings_value}) |
|
230 | fd.update({row.app_settings_name: row.app_settings_value}) | |
229 |
|
231 | |||
230 | return fd |
|
232 | return fd | |
231 |
|
233 | |||
@@ -761,18 +763,27 b' class Repository(Base, BaseModel):' | |||||
761 | def scm_instance(self): |
|
763 | def scm_instance(self): | |
762 | return self.__get_instance() |
|
764 | return self.__get_instance() | |
763 |
|
765 | |||
764 | @property |
|
766 | def scm_instance_cached(self, cache_map=None): | |
765 | def scm_instance_cached(self): |
|
|||
766 | @cache_region('long_term') |
|
767 | @cache_region('long_term') | |
767 | def _c(repo_name): |
|
768 | def _c(repo_name): | |
768 | return self.__get_instance() |
|
769 | return self.__get_instance() | |
769 | rn = self.repo_name |
|
770 | rn = self.repo_name | |
770 | log.debug('Getting cached instance of repo') |
|
771 | log.debug('Getting cached instance of repo') | |
771 | inv = self.invalidate |
|
772 | ||
772 | if inv is not None: |
|
773 | if cache_map: | |
|
774 | # get using prefilled cache_map | |||
|
775 | invalidate_repo = cache_map[self.repo_name] | |||
|
776 | if invalidate_repo: | |||
|
777 | invalidate_repo = (None if invalidate_repo.cache_active | |||
|
778 | else invalidate_repo) | |||
|
779 | else: | |||
|
780 | # get from invalidate | |||
|
781 | invalidate_repo = self.invalidate | |||
|
782 | ||||
|
783 | if invalidate_repo is not None: | |||
773 | region_invalidate(_c, None, rn) |
|
784 | region_invalidate(_c, None, rn) | |
774 | # update our cache |
|
785 | # update our cache | |
775 | CacheInvalidation.set_valid(inv.cache_key) |
|
786 | CacheInvalidation.set_valid(invalidate_repo.cache_key) | |
776 | return _c(rn) |
|
787 | return _c(rn) | |
777 |
|
788 | |||
778 | def __get_instance(self): |
|
789 | def __get_instance(self): | |
@@ -1140,6 +1151,7 b' class CacheInvalidation(Base, BaseModel)' | |||||
1140 | __tablename__ = 'cache_invalidation' |
|
1151 | __tablename__ = 'cache_invalidation' | |
1141 | __table_args__ = ( |
|
1152 | __table_args__ = ( | |
1142 | UniqueConstraint('cache_key'), |
|
1153 | UniqueConstraint('cache_key'), | |
|
1154 | Index('key_idx', 'cache_key'), | |||
1143 | {'extend_existing': True, 'mysql_engine': 'InnoDB', |
|
1155 | {'extend_existing': True, 'mysql_engine': 'InnoDB', | |
1144 | 'mysql_charset': 'utf8'}, |
|
1156 | 'mysql_charset': 'utf8'}, | |
1145 | ) |
|
1157 | ) | |
@@ -1156,6 +1168,7 b' class CacheInvalidation(Base, BaseModel)' | |||||
1156 | def __unicode__(self): |
|
1168 | def __unicode__(self): | |
1157 | return u"<%s('%s:%s')>" % (self.__class__.__name__, |
|
1169 | return u"<%s('%s:%s')>" % (self.__class__.__name__, | |
1158 | self.cache_id, self.cache_key) |
|
1170 | self.cache_id, self.cache_key) | |
|
1171 | ||||
1159 | @classmethod |
|
1172 | @classmethod | |
1160 | def clear_cache(cls): |
|
1173 | def clear_cache(cls): | |
1161 | cls.query().delete() |
|
1174 | cls.query().delete() | |
@@ -1242,6 +1255,40 b' class CacheInvalidation(Base, BaseModel)' | |||||
1242 | Session.add(inv_obj) |
|
1255 | Session.add(inv_obj) | |
1243 | Session.commit() |
|
1256 | Session.commit() | |
1244 |
|
1257 | |||
|
1258 | @classmethod | |||
|
1259 | def get_cache_map(cls): | |||
|
1260 | ||||
|
1261 | class cachemapdict(dict): | |||
|
1262 | ||||
|
1263 | def __init__(self, *args, **kwargs): | |||
|
1264 | fixkey = kwargs.get('fixkey') | |||
|
1265 | if fixkey: | |||
|
1266 | del kwargs['fixkey'] | |||
|
1267 | self.fixkey = fixkey | |||
|
1268 | super(cachemapdict, self).__init__(*args, **kwargs) | |||
|
1269 | ||||
|
1270 | def __getattr__(self, name): | |||
|
1271 | key = name | |||
|
1272 | if self.fixkey: | |||
|
1273 | key, _prefix, _org_key = cls._get_key(key) | |||
|
1274 | if key in self.__dict__: | |||
|
1275 | return self.__dict__[key] | |||
|
1276 | else: | |||
|
1277 | return self[key] | |||
|
1278 | ||||
|
1279 | def __getitem__(self, key): | |||
|
1280 | if self.fixkey: | |||
|
1281 | key, _prefix, _org_key = cls._get_key(key) | |||
|
1282 | try: | |||
|
1283 | return super(cachemapdict, self).__getitem__(key) | |||
|
1284 | except KeyError: | |||
|
1285 | return | |||
|
1286 | ||||
|
1287 | cache_map = cachemapdict(fixkey=True) | |||
|
1288 | for obj in cls.query().all(): | |||
|
1289 | cache_map[obj.cache_key] = cachemapdict(obj.get_dict()) | |||
|
1290 | return cache_map | |||
|
1291 | ||||
1245 |
|
1292 | |||
1246 | class ChangesetComment(Base, BaseModel): |
|
1293 | class ChangesetComment(Base, BaseModel): | |
1247 | __tablename__ = 'changeset_comments' |
|
1294 | __tablename__ = 'changeset_comments' |
@@ -28,6 +28,8 b' import traceback' | |||||
28 | import logging |
|
28 | import logging | |
29 | import cStringIO |
|
29 | import cStringIO | |
30 |
|
30 | |||
|
31 | from sqlalchemy import func | |||
|
32 | ||||
31 | from rhodecode.lib.vcs import get_backend |
|
33 | from rhodecode.lib.vcs import get_backend | |
32 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
34 | from rhodecode.lib.vcs.exceptions import RepositoryError | |
33 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
35 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
@@ -77,8 +79,12 b' class CachedRepoList(object):' | |||||
77 | return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) |
|
79 | return '<%s (%s)>' % (self.__class__.__name__, self.__len__()) | |
78 |
|
80 | |||
79 | def __iter__(self): |
|
81 | def __iter__(self): | |
|
82 | # pre-propagated cache_map to save executing select statements | |||
|
83 | # for each repo | |||
|
84 | cache_map = CacheInvalidation.get_cache_map() | |||
|
85 | ||||
80 | for dbr in self.db_repo_list: |
|
86 | for dbr in self.db_repo_list: | |
81 | scmr = dbr.scm_instance_cached |
|
87 | scmr = dbr.scm_instance_cached(cache_map) | |
82 | # check permission at this level |
|
88 | # check permission at this level | |
83 | if not HasRepoPermissionAny( |
|
89 | if not HasRepoPermissionAny( | |
84 | 'repository.read', 'repository.write', 'repository.admin' |
|
90 | 'repository.read', 'repository.write', 'repository.admin' | |
@@ -219,7 +225,7 b' class ScmModel(BaseModel):' | |||||
219 | if all_repos is None: |
|
225 | if all_repos is None: | |
220 | all_repos = self.sa.query(Repository)\ |
|
226 | all_repos = self.sa.query(Repository)\ | |
221 | .filter(Repository.group_id == None)\ |
|
227 | .filter(Repository.group_id == None)\ | |
222 | .order_by(Repository.repo_name).all() |
|
228 | .order_by(func.lower(Repository.repo_name)).all() | |
223 |
|
229 | |||
224 | repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path, |
|
230 | repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path, | |
225 | order_by=sort_key) |
|
231 | order_by=sort_key) |
@@ -21,91 +21,7 b'' | |||||
21 | ${self.breadcrumbs()} |
|
21 | ${self.breadcrumbs()} | |
22 | </div> |
|
22 | </div> | |
23 | <!-- end box / title --> |
|
23 | <!-- end box / title --> | |
24 | <div> |
|
24 | ${c.form|n} | |
25 | ${h.form(url('admin_settings_my_account_update'),method='put')} |
|
|||
26 | <div class="form"> |
|
|||
27 |
|
||||
28 | <div class="field"> |
|
|||
29 | <div class="gravatar_box"> |
|
|||
30 | <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div> |
|
|||
31 | <p> |
|
|||
32 | %if c.use_gravatar: |
|
|||
33 | <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong> |
|
|||
34 | <br/>${_('Using')} ${c.user.email} |
|
|||
35 | %else: |
|
|||
36 | <br/>${c.user.email} |
|
|||
37 | %endif |
|
|||
38 | </p> |
|
|||
39 | </div> |
|
|||
40 | </div> |
|
|||
41 | <div class="field"> |
|
|||
42 | <div class="label"> |
|
|||
43 | <label>${_('API key')}</label> ${c.user.api_key} |
|
|||
44 | </div> |
|
|||
45 | </div> |
|
|||
46 | <div class="fields"> |
|
|||
47 | <div class="field"> |
|
|||
48 | <div class="label"> |
|
|||
49 | <label for="username">${_('Username')}:</label> |
|
|||
50 | </div> |
|
|||
51 | <div class="input"> |
|
|||
52 | ${h.text('username',class_="medium")} |
|
|||
53 | </div> |
|
|||
54 | </div> |
|
|||
55 |
|
||||
56 | <div class="field"> |
|
|||
57 | <div class="label"> |
|
|||
58 | <label for="new_password">${_('New password')}:</label> |
|
|||
59 | </div> |
|
|||
60 | <div class="input"> |
|
|||
61 | ${h.password('new_password',class_="medium",autocomplete="off")} |
|
|||
62 | </div> |
|
|||
63 | </div> |
|
|||
64 |
|
||||
65 | <div class="field"> |
|
|||
66 | <div class="label"> |
|
|||
67 | <label for="password_confirmation">${_('New password confirmation')}:</label> |
|
|||
68 | </div> |
|
|||
69 | <div class="input"> |
|
|||
70 | ${h.password('password_confirmation',class_="medium",autocomplete="off")} |
|
|||
71 | </div> |
|
|||
72 | </div> |
|
|||
73 |
|
||||
74 | <div class="field"> |
|
|||
75 | <div class="label"> |
|
|||
76 | <label for="name">${_('First Name')}:</label> |
|
|||
77 | </div> |
|
|||
78 | <div class="input"> |
|
|||
79 | ${h.text('name',class_="medium")} |
|
|||
80 | </div> |
|
|||
81 | </div> |
|
|||
82 |
|
||||
83 | <div class="field"> |
|
|||
84 | <div class="label"> |
|
|||
85 | <label for="lastname">${_('Last Name')}:</label> |
|
|||
86 | </div> |
|
|||
87 | <div class="input"> |
|
|||
88 | ${h.text('lastname',class_="medium")} |
|
|||
89 | </div> |
|
|||
90 | </div> |
|
|||
91 |
|
||||
92 | <div class="field"> |
|
|||
93 | <div class="label"> |
|
|||
94 | <label for="email">${_('Email')}:</label> |
|
|||
95 | </div> |
|
|||
96 | <div class="input"> |
|
|||
97 | ${h.text('email',class_="medium")} |
|
|||
98 | </div> |
|
|||
99 | </div> |
|
|||
100 |
|
||||
101 | <div class="buttons"> |
|
|||
102 | ${h.submit('save',_('Save'),class_="ui-button")} |
|
|||
103 | ${h.reset('reset',_('Reset'),class_="ui-button")} |
|
|||
104 | </div> |
|
|||
105 | </div> |
|
|||
106 | </div> |
|
|||
107 | ${h.end_form()} |
|
|||
108 | </div> |
|
|||
109 | </div> |
|
25 | </div> | |
110 |
|
26 | |||
111 | <div class="box box-right"> |
|
27 | <div class="box box-right"> |
General Comments 0
You need to be logged in to leave comments.
Login now