diff options
author | Milo Casagrande <milo@ubuntu.com> | 2013-02-13 18:35:00 +0100 |
---|---|---|
committer | Milo Casagrande <milo@ubuntu.com> | 2013-02-13 18:35:00 +0100 |
commit | f6e9d7be791b269967311ba281b5705361112669 (patch) | |
tree | 3da66a5f98dbb2975d00085dc2a3a781ec73d808 /rhodecode/controllers | |
parent | d6b2ec12ceddb987c6f9df411f1c02fe32b1fe0a (diff) | |
parent | 637fcc9fc3f7f177097ed2c590d98a077cbeee26 (diff) |
Merge branch 'master' into linaro
Fixed conflicts:
setup.py
Diffstat (limited to 'rhodecode/controllers')
-rw-r--r-- | rhodecode/controllers/admin/notifications.py | 12 | ||||
-rw-r--r-- | rhodecode/controllers/admin/permissions.py | 81 | ||||
-rw-r--r-- | rhodecode/controllers/admin/repos.py | 38 | ||||
-rw-r--r-- | rhodecode/controllers/admin/repos_groups.py | 48 | ||||
-rw-r--r-- | rhodecode/controllers/admin/settings.py | 61 | ||||
-rw-r--r-- | rhodecode/controllers/admin/users.py | 44 | ||||
-rw-r--r-- | rhodecode/controllers/api/__init__.py | 24 | ||||
-rw-r--r-- | rhodecode/controllers/api/api.py | 170 | ||||
-rw-r--r-- | rhodecode/controllers/changeset.py | 25 | ||||
-rw-r--r-- | rhodecode/controllers/compare.py | 7 | ||||
-rw-r--r-- | rhodecode/controllers/home.py | 54 | ||||
-rw-r--r-- | rhodecode/controllers/journal.py | 81 | ||||
-rw-r--r-- | rhodecode/controllers/login.py | 7 | ||||
-rw-r--r-- | rhodecode/controllers/pullrequests.py | 7 |
14 files changed, 405 insertions, 254 deletions
diff --git a/rhodecode/controllers/admin/notifications.py b/rhodecode/controllers/admin/notifications.py index 90cfd69b..221aa00b 100644 --- a/rhodecode/controllers/admin/notifications.py +++ b/rhodecode/controllers/admin/notifications.py @@ -110,8 +110,8 @@ class NotificationsController(BaseController): # url('notification', notification_id=ID) try: no = Notification.get(notification_id) - owner = lambda: (no.notifications_to_users.user.user_id - == c.rhodecode_user.user_id) + owner = all(un.user.user_id == c.rhodecode_user.user_id + for un in no.notifications_to_users) if h.HasPermissionAny('hg.admin')() or owner: NotificationModel().mark_read(c.rhodecode_user.user_id, no) Session().commit() @@ -132,8 +132,8 @@ class NotificationsController(BaseController): try: no = Notification.get(notification_id) - owner = lambda: (no.notifications_to_users.user.user_id - == c.rhodecode_user.user_id) + owner = all(un.user.user_id == c.rhodecode_user.user_id + for un in no.notifications_to_users) if h.HasPermissionAny('hg.admin')() or owner: NotificationModel().delete(c.rhodecode_user.user_id, no) Session().commit() @@ -149,8 +149,8 @@ class NotificationsController(BaseController): c.user = self.rhodecode_user no = Notification.get(notification_id) - owner = lambda: (no.notifications_to_users.user.user_id - == c.user.user_id) + owner = all(un.user.user_id == c.rhodecode_user.user_id + for un in no.notifications_to_users) if no and (h.HasPermissionAny('hg.admin', 'repository.admin')() or owner): unotification = NotificationModel()\ .get_user_notification(c.user.user_id, no) diff --git a/rhodecode/controllers/admin/permissions.py b/rhodecode/controllers/admin/permissions.py index bdbaeddd..8acee302 100644 --- a/rhodecode/controllers/admin/permissions.py +++ b/rhodecode/controllers/admin/permissions.py @@ -33,11 +33,12 @@ from pylons.controllers.util import abort, redirect from pylons.i18n.translation import _ from rhodecode.lib import helpers as h -from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator,\ + AuthUser from rhodecode.lib.base import BaseController, render from rhodecode.model.forms import DefaultPermissionsForm from rhodecode.model.permission import PermissionModel -from rhodecode.model.db import User +from rhodecode.model.db import User, UserIpMap from rhodecode.model.meta import Session log = logging.getLogger(__name__) @@ -105,36 +106,41 @@ class PermissionsController(BaseController): # h.form(url('permission', id=ID), # method='put') # url('permission', id=ID) - - permission_model = PermissionModel() - - _form = DefaultPermissionsForm([x[0] for x in self.repo_perms_choices], - [x[0] for x in self.group_perms_choices], - [x[0] for x in self.register_choices], - [x[0] for x in self.create_choices], - [x[0] for x in self.fork_choices])() - - try: - form_result = _form.to_python(dict(request.POST)) - form_result.update({'perm_user_name': id}) - permission_model.update(form_result) - Session().commit() - h.flash(_('Default permissions updated successfully'), - category='success') - - except formencode.Invalid, errors: - defaults = errors.value - - return htmlfill.render( - render('admin/permissions/permissions.html'), - defaults=defaults, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8") - except Exception: - log.error(traceback.format_exc()) - h.flash(_('error occurred during update of permissions'), - category='error') + if id == 'default': + c.user = default_user = User.get_by_username('default') + c.perm_user = AuthUser(user_id=default_user.user_id) + c.user_ip_map = UserIpMap.query()\ + .filter(UserIpMap.user == default_user).all() + permission_model = PermissionModel() + + _form = DefaultPermissionsForm( + [x[0] for x in self.repo_perms_choices], + [x[0] for x in self.group_perms_choices], + [x[0] for x in self.register_choices], + [x[0] for x in self.create_choices], + [x[0] for x in self.fork_choices])() + + try: + form_result = _form.to_python(dict(request.POST)) + form_result.update({'perm_user_name': id}) + permission_model.update(form_result) + Session().commit() + h.flash(_('Default permissions updated successfully'), + category='success') + + except formencode.Invalid, errors: + defaults = errors.value + + return htmlfill.render( + render('admin/permissions/permissions.html'), + defaults=defaults, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8") + except Exception: + log.error(traceback.format_exc()) + h.flash(_('error occurred during update of permissions'), + category='error') return redirect(url('edit_permission', id=id)) @@ -157,10 +163,11 @@ class PermissionsController(BaseController): #this form can only edit default user permissions if id == 'default': - default_user = User.get_by_username('default') - defaults = {'_method': 'put', - 'anonymous': default_user.active} - + c.user = default_user = User.get_by_username('default') + defaults = {'anonymous': default_user.active} + c.perm_user = AuthUser(user_id=default_user.user_id) + c.user_ip_map = UserIpMap.query()\ + .filter(UserIpMap.user == default_user).all() for p in default_user.user_perms: if p.permission.permission_name.startswith('repository.'): defaults['default_repo_perm'] = p.permission.permission_name @@ -181,7 +188,7 @@ class PermissionsController(BaseController): render('admin/permissions/permissions.html'), defaults=defaults, encoding="UTF-8", - force_defaults=True, + force_defaults=False ) else: return redirect(url('admin_home')) diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py index ff9efd1a..ac9372e0 100644 --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -135,40 +135,10 @@ class ReposController(BaseController): .order_by(func.lower(Repository.repo_name))\ .all() - repos_data = [] - total_records = len(c.repos_list) - - _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup - template = _tmpl_lookup.get_template('data_table/_dt_elements.html') - - quick_menu = lambda repo_name: (template.get_def("quick_menu") - .render(repo_name, _=_, h=h, c=c)) - repo_lnk = lambda name, rtype, private, fork_of: ( - template.get_def("repo_name") - .render(name, rtype, private, fork_of, short_name=False, - admin=True, _=_, h=h, c=c)) - - repo_actions = lambda repo_name: (template.get_def("repo_actions") - .render(repo_name, _=_, h=h, c=c)) - - for repo in c.repos_list: - repos_data.append({ - "menu": quick_menu(repo.repo_name), - "raw_name": repo.repo_name.lower(), - "name": repo_lnk(repo.repo_name, repo.repo_type, - repo.private, repo.fork), - "desc": repo.description, - "owner": repo.user.username, - "action": repo_actions(repo.repo_name), - }) - - c.data = json.dumps({ - "totalRecords": total_records, - "startIndex": 0, - "sort": "name", - "dir": "asc", - "records": repos_data - }) + repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, + admin=True) + #json used to render the grid + c.data = json.dumps(repos_data) return render('admin/repos/repos.html') diff --git a/rhodecode/controllers/admin/repos_groups.py b/rhodecode/controllers/admin/repos_groups.py index 6f62ee8e..97ded63d 100644 --- a/rhodecode/controllers/admin/repos_groups.py +++ b/rhodecode/controllers/admin/repos_groups.py @@ -295,54 +295,18 @@ class ReposGroupsController(BaseController): c.groups = self.scm_model.get_repos_groups(groups) if c.visual.lightweight_dashboard is False: - c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter) - - c.repos_list = c.cached_repo_list + c.repos_list = self.scm_model.get_repos(all_repos=gr_filter) ## lightweight version of dashboard else: c.repos_list = Repository.query()\ .filter(Repository.group_id == id)\ .order_by(func.lower(Repository.repo_name))\ .all() - repos_data = [] - total_records = len(c.repos_list) - - _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup - template = _tmpl_lookup.get_template('data_table/_dt_elements.html') - - quick_menu = lambda repo_name: (template.get_def("quick_menu") - .render(repo_name, _=_, h=h, c=c)) - repo_lnk = lambda name, rtype, private, fork_of: ( - template.get_def("repo_name") - .render(name, rtype, private, fork_of, short_name=False, - admin=False, _=_, h=h, c=c)) - last_change = lambda last_change: (template.get_def("last_change") - .render(last_change, _=_, h=h, c=c)) - rss_lnk = lambda repo_name: (template.get_def("rss") - .render(repo_name, _=_, h=h, c=c)) - atom_lnk = lambda repo_name: (template.get_def("atom") - .render(repo_name, _=_, h=h, c=c)) - - for repo in c.repos_list: - repos_data.append({ - "menu": quick_menu(repo.repo_name), - "raw_name": repo.repo_name.lower(), - "name": repo_lnk(repo.repo_name, repo.repo_type, - repo.private, repo.fork), - "last_change": last_change(repo.last_db_change), - "desc": repo.description, - "owner": h.person(repo.user.username), - "rss": rss_lnk(repo.repo_name), - "atom": atom_lnk(repo.repo_name), - }) - - c.data = json.dumps({ - "totalRecords": total_records, - "startIndex": 0, - "sort": "name", - "dir": "asc", - "records": repos_data - }) + + repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, + admin=False) + #json used to render the grid + c.data = json.dumps(repos_data) return render('admin/repos_groups/repos_groups.html') diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py index 32ba99a2..30181d62 100644 --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -48,11 +48,12 @@ from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \ ApplicationUiSettingsForm, ApplicationVisualisationForm from rhodecode.model.scm import ScmModel from rhodecode.model.user import UserModel +from rhodecode.model.repo import RepoModel from rhodecode.model.db import User from rhodecode.model.notification import EmailNotificationModel from rhodecode.model.meta import Session -from rhodecode.lib.utils2 import str2bool - +from rhodecode.lib.utils2 import str2bool, safe_unicode +from rhodecode.lib.compat import json log = logging.getLogger(__name__) @@ -119,10 +120,11 @@ class SettingsController(BaseController): invalidate_cache('get_repo_cached_%s' % repo_name) added, removed = repo2db_mapper(initial, rm_obsolete) - - h.flash(_('Repositories successfully' - ' rescanned added: %s,removed: %s') % (added, removed), - category='success') + _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' + h.flash(_('Repositories successfully ' + 'rescanned added: %s ; removed: %s') % + (_repr(added), _repr(removed)), + category='success') if setting_id == 'whoosh': repo_location = self._get_hg_ui_settings()['paths_root_path'] @@ -336,7 +338,7 @@ class SettingsController(BaseController): .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT, body=test_email_body) - recipients = [test_email] if [test_email] else None + recipients = [test_email] if test_email else None run_task(tasks.send_email, recipients, test_email_subj, test_email_body, test_email_html_body) @@ -381,6 +383,17 @@ class SettingsController(BaseController): force_defaults=False ) + def _load_my_repos_data(self): + repos_list = Session().query(Repository)\ + .filter(Repository.user_id == + self.rhodecode_user.user_id)\ + .order_by(func.lower(Repository.repo_name)).all() + + repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list, + admin=True) + #json used to render the grid + return json.dumps(repos_data) + @NotAnonymous() def my_account(self): """ @@ -389,17 +402,16 @@ class SettingsController(BaseController): # url('admin_settings_my_account') c.user = User.get(self.rhodecode_user.user_id) - all_repos = Session().query(Repository)\ - .filter(Repository.user_id == c.user.user_id)\ - .order_by(func.lower(Repository.repo_name)).all() - - c.user_repos = ScmModel().get_repos(all_repos) + c.ldap_dn = c.user.ldap_dn if c.user.username == 'default': h.flash(_("You can't edit this user since it's" " crucial for entire application"), category='warning') return redirect(url('users')) + #json used to render the grid + c.data = self._load_my_repos_data() + defaults = c.user.get_dict() c.form = htmlfill.render( @@ -420,19 +432,25 @@ class SettingsController(BaseController): # method='put') # url('admin_settings_my_account_update', id=ID) uid = self.rhodecode_user.user_id + c.user = User.get(self.rhodecode_user.user_id) + c.ldap_dn = c.user.ldap_dn email = self.rhodecode_user.email _form = UserForm(edit=True, old_data={'user_id': uid, 'email': email})() form_result = {} try: form_result = _form.to_python(dict(request.POST)) - UserModel().update_my_account(uid, form_result) + skip_attrs = ['admin', 'active'] # skip attr for my account + if c.ldap_dn: + #forbid updating username for ldap accounts + skip_attrs.append('username') + UserModel().update(uid, form_result, skip_attrs=skip_attrs) h.flash(_('Your account was updated successfully'), category='success') Session().commit() except formencode.Invalid, errors: - c.user = User.get(self.rhodecode_user.user_id) - + #json used to render the grid + c.data = self._load_my_repos_data() c.form = htmlfill.render( render('admin/users/user_edit_my_account_form.html'), defaults=errors.value, @@ -448,23 +466,14 @@ class SettingsController(BaseController): return redirect(url('my_account')) @NotAnonymous() - def my_account_my_repos(self): - all_repos = Session().query(Repository)\ - .filter(Repository.user_id == self.rhodecode_user.user_id)\ - .order_by(func.lower(Repository.repo_name))\ - .all() - c.user_repos = ScmModel().get_repos(all_repos) - return render('admin/users/user_edit_my_account_repos.html') - - @NotAnonymous() def my_account_my_pullrequests(self): c.my_pull_requests = PullRequest.query()\ - .filter(PullRequest.user_id== + .filter(PullRequest.user_id == self.rhodecode_user.user_id)\ .all() c.participate_in_pull_requests = \ [x.pull_request for x in PullRequestReviewers.query()\ - .filter(PullRequestReviewers.user_id== + .filter(PullRequestReviewers.user_id == self.rhodecode_user.user_id)\ .all()] return render('admin/users/user_edit_my_account_pullrequests.html') diff --git a/rhodecode/controllers/admin/users.py b/rhodecode/controllers/admin/users.py index e8d222ef..6b815bf4 100644 --- a/rhodecode/controllers/admin/users.py +++ b/rhodecode/controllers/admin/users.py @@ -41,7 +41,7 @@ from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \ AuthUser from rhodecode.lib.base import BaseController, render -from rhodecode.model.db import User, UserEmailMap +from rhodecode.model.db import User, UserEmailMap, UserIpMap from rhodecode.model.forms import UserForm from rhodecode.model.user import UserModel from rhodecode.model.meta import Session @@ -159,7 +159,7 @@ class UsersController(BaseController): user_model = UserModel() c.user = user_model.get(id) c.ldap_dn = c.user.ldap_dn - c.perm_user = AuthUser(user_id=id) + c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr) _form = UserForm(edit=True, old_data={'user_id': id, 'email': c.user.email})() form_result = {} @@ -178,6 +178,8 @@ class UsersController(BaseController): except formencode.Invalid, errors: c.user_email_map = UserEmailMap.query()\ .filter(UserEmailMap.user == c.user).all() + c.user_ip_map = UserIpMap.query()\ + .filter(UserIpMap.user == c.user).all() defaults = errors.value e = errors.error_dict or {} defaults.update({ @@ -231,12 +233,14 @@ class UsersController(BaseController): h.flash(_("You can't edit this user"), category='warning') return redirect(url('users')) - c.perm_user = AuthUser(user_id=id) + c.perm_user = AuthUser(user_id=id, ip_addr=self.ip_addr) c.user.permissions = {} c.granted_permissions = UserModel().fill_perms(c.user)\ .permissions['global'] c.user_email_map = UserEmailMap.query()\ .filter(UserEmailMap.user == c.user).all() + c.user_ip_map = UserIpMap.query()\ + .filter(UserIpMap.user == c.user).all() user_model = UserModel() c.ldap_dn = c.user.ldap_dn defaults = c.user.get_dict() @@ -299,7 +303,6 @@ class UsersController(BaseController): """POST /user_emails:Add an existing item""" # url('user_emails', id=ID, method='put') - #TODO: validation and form !!! email = request.POST.get('new_email') user_model = UserModel() @@ -324,3 +327,36 @@ class UsersController(BaseController): Session().commit() h.flash(_("Removed email from user"), category='success') return redirect(url('edit_user', id=id)) + + def add_ip(self, id): + """POST /user_ips:Add an existing item""" + # url('user_ips', id=ID, method='put') + + ip = request.POST.get('new_ip') + user_model = UserModel() + + try: + user_model.add_extra_ip(id, ip) + Session().commit() + h.flash(_("Added ip %s to user") % ip, category='success') + except formencode.Invalid, error: + msg = error.error_dict['ip'] + h.flash(msg, category='error') + except Exception: + log.error(traceback.format_exc()) + h.flash(_('An error occurred during ip saving'), + category='error') + if 'default_user' in request.POST: + return redirect(url('edit_permission', id='default')) + return redirect(url('edit_user', id=id)) + + def delete_ip(self, id): + """DELETE /user_ips_delete/id: Delete an existing item""" + # url('user_ips_delete', id=ID, method='delete') + user_model = UserModel() + user_model.delete_extra_ip(id, request.POST.get('del_ip')) + Session().commit() + h.flash(_("Removed ip from user"), category='success') + if 'default_user' in request.POST: + return redirect(url('edit_permission', id='default')) + return redirect(url('edit_user', id=id)) diff --git a/rhodecode/controllers/api/__init__.py b/rhodecode/controllers/api/__init__.py index 13fd7033..2f4e1416 100644 --- a/rhodecode/controllers/api/__init__.py +++ b/rhodecode/controllers/api/__init__.py @@ -32,17 +32,15 @@ import urllib import traceback import time -from rhodecode.lib.compat import izip_longest, json - from paste.response import replace_header - from pylons.controllers import WSGIController - from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \ HTTPBadRequest, HTTPError from rhodecode.model.db import User +from rhodecode.model import meta +from rhodecode.lib.compat import izip_longest, json from rhodecode.lib.auth import AuthUser from rhodecode.lib.base import _get_ip_addr, _get_access_path from rhodecode.lib.utils2 import safe_unicode @@ -86,6 +84,9 @@ class JSONRPCController(WSGIController): """ + def _get_ip_addr(self, environ): + return _get_ip_addr(environ) + def _get_method_args(self): """ Return `self._rpc_args` to dispatched controller method @@ -99,6 +100,7 @@ class JSONRPCController(WSGIController): controller and if it exists, dispatch to it. """ start = time.time() + ip_addr = self.ip_addr = self._get_ip_addr(environ) self._req_id = None if 'CONTENT_LENGTH' not in environ: log.debug("No Content-Length") @@ -130,6 +132,9 @@ class JSONRPCController(WSGIController): self._req_id = json_body['id'] self._req_method = json_body['method'] self._request_params = json_body['args'] + if not isinstance(self._request_params, dict): + self._request_params = {} + log.debug( 'method: %s, params: %s' % (self._req_method, self._request_params) @@ -144,7 +149,15 @@ class JSONRPCController(WSGIController): if u is None: return jsonrpc_error(retid=self._req_id, message='Invalid API KEY') - auth_u = AuthUser(u.user_id, self._req_api_key) + + #check if we are allowed to use this IP + auth_u = AuthUser(u.user_id, self._req_api_key, ip_addr=ip_addr) + if not auth_u.ip_allowed: + return jsonrpc_error(retid=self._req_id, + message='request from IP:%s not allowed' % (ip_addr)) + else: + log.info('Access for IP:%s allowed' % (ip_addr)) + except Exception, e: return jsonrpc_error(retid=self._req_id, message='Invalid API KEY') @@ -202,6 +215,7 @@ class JSONRPCController(WSGIController): ) self._rpc_args = {USER_SESSION_ATTR: u} + self._rpc_args.update(self._request_params) self._rpc_args['action'] = self._req_method diff --git a/rhodecode/controllers/api/api.py b/rhodecode/controllers/api/api.py index 93bec581..fc185df0 100644 --- a/rhodecode/controllers/api/api.py +++ b/rhodecode/controllers/api/api.py @@ -27,10 +27,12 @@ import traceback import logging +from pylons.controllers.util import abort from rhodecode.controllers.api import JSONRPCController, JSONRPCError -from rhodecode.lib.auth import HasPermissionAllDecorator, \ - HasPermissionAnyDecorator, PasswordGenerator, AuthUser +from rhodecode.lib.auth import PasswordGenerator, AuthUser, \ + HasPermissionAllDecorator, HasPermissionAnyDecorator, \ + HasPermissionAnyApi, HasRepoPermissionAnyApi from rhodecode.lib.utils import map_groups, repo2db_mapper from rhodecode.model.meta import Session from rhodecode.model.scm import ScmModel @@ -38,11 +40,27 @@ from rhodecode.model.repo import RepoModel from rhodecode.model.user import UserModel from rhodecode.model.users_group import UsersGroupModel from rhodecode.model.permission import PermissionModel -from rhodecode.model.db import Repository +from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap log = logging.getLogger(__name__) +class OptionalAttr(object): + """ + Special Optional Option that defines other attribute + """ + def __init__(self, attr_name): + self.attr_name = attr_name + + def __repr__(self): + return '<OptionalAttr:%s>' % self.attr_name + + def __call__(self): + return self +#alias +OAttr = OptionalAttr + + class Optional(object): """ Defines an optional parameter:: @@ -184,10 +202,11 @@ class ApiController(JSONRPCController): 'Error occurred during rescan repositories action' ) - @HasPermissionAllDecorator('hg.admin') - def lock(self, apiuser, repoid, userid, locked): + def lock(self, apiuser, repoid, locked, userid=Optional(OAttr('apiuser'))): """ - Set locking state on particular repository by given user + Set locking state on particular repository by given user, if + this command is runned by non-admin account userid is set to user + who is calling this method :param apiuser: :param repoid: @@ -195,6 +214,22 @@ class ApiController(JSONRPCController): :param locked: """ repo = get_repo_or_error(repoid) + if HasPermissionAnyApi('hg.admin')(user=apiuser): + pass + elif HasRepoPermissionAnyApi('repository.admin', + 'repository.write')(user=apiuser, + repo_name=repo.repo_name): + #make sure normal user does not pass someone else userid, + #he is not allowed to do that + if not isinstance(userid, Optional) and userid != apiuser.user_id: + raise JSONRPCError( + 'userid is not the same as your user' + ) + else: + raise JSONRPCError('repository `%s` does not exist' % (repoid)) + + if isinstance(userid, Optional): + userid = apiuser.user_id user = get_user_or_error(userid) locked = bool(locked) try: @@ -212,13 +247,38 @@ class ApiController(JSONRPCController): ) @HasPermissionAllDecorator('hg.admin') - def get_user(self, apiuser, userid): + def show_ip(self, apiuser, userid): + """ + Shows IP address as seen from RhodeCode server, together with all + defined IP addresses for given user + + :param apiuser: + :param userid: + """ + user = get_user_or_error(userid) + ips = UserIpMap.query().filter(UserIpMap.user == user).all() + return dict( + ip_addr_server=self.ip_addr, + user_ips=ips + ) + + def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))): """" - Get a user by username + Get a user by username, or userid, if userid is given :param apiuser: :param userid: """ + if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: + #make sure normal user does not pass someone else userid, + #he is not allowed to do that + if not isinstance(userid, Optional) and userid != apiuser.user_id: + raise JSONRPCError( + 'userid is not the same as your user' + ) + + if isinstance(userid, Optional): + userid = apiuser.user_id user = get_user_or_error(userid) data = user.get_api_data() @@ -479,7 +539,6 @@ class ApiController(JSONRPCController): ) ) - @HasPermissionAnyDecorator('hg.admin') def get_repo(self, apiuser, repoid): """" Get repository by name @@ -489,6 +548,12 @@ class ApiController(JSONRPCController): """ repo = get_repo_or_error(repoid) + if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: + # check if we have admin permission for this repo ! + if HasRepoPermissionAnyApi('repository.admin')(user=apiuser, + repo_name=repo.repo_name) is False: + raise JSONRPCError('repository `%s` does not exist' % (repoid)) + members = [] for user in repo.repo_to_perm: perm = user.permission.permission_name @@ -510,20 +575,23 @@ class ApiController(JSONRPCController): data['members'] = members return data - @HasPermissionAnyDecorator('hg.admin') def get_repos(self, apiuser): """" Get all repositories :param apiuser: """ - result = [] - for repo in RepoModel().get_all(): + if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: + repos = RepoModel().get_all_user_repos(user=apiuser) + else: + repos = RepoModel().get_all() + + for repo in repos: result.append(repo.get_api_data()) return result - @HasPermissionAnyDecorator('hg.admin') + @HasPermissionAllDecorator('hg.admin') def get_repo_nodes(self, apiuser, repoid, revision, root_path, ret_type='all'): """ @@ -556,12 +624,16 @@ class ApiController(JSONRPCController): ) @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository') - def create_repo(self, apiuser, repo_name, owner, repo_type, + def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')), + repo_type=Optional('hg'), description=Optional(''), private=Optional(False), - clone_uri=Optional(None), landing_rev=Optional('tip')): + clone_uri=Optional(None), landing_rev=Optional('tip'), + enable_statistics=Optional(False), + enable_locking=Optional(False), + enable_downloads=Optional(False)): """ Create repository, if clone_url is given it makes a remote clone - if repo_name is withina group name the groups will be created + if repo_name is within a group name the groups will be created automatically if they aren't present :param apiuser: @@ -573,12 +645,32 @@ class ApiController(JSONRPCController): :param clone_uri: :param landing_rev: """ + if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: + if not isinstance(owner, Optional): + #forbid setting owner for non-admins + raise JSONRPCError( + 'Only RhodeCode admin can specify `owner` param' + ) + if isinstance(owner, Optional): + owner = apiuser.user_id + owner = get_user_or_error(owner) if RepoModel().get_by_repo_name(repo_name): raise JSONRPCError("repo `%s` already exist" % repo_name) - private = Optional.extract(private) + defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True) + if isinstance(private, Optional): + private = defs.get('repo_private') or Optional.extract(private) + if isinstance(repo_type, Optional): + repo_type = defs.get('repo_type') + if isinstance(enable_statistics, Optional): + enable_statistics = defs.get('repo_enable_statistics') + if isinstance(enable_locking, Optional): + enable_locking = defs.get('repo_enable_locking') + if isinstance(enable_downloads, Optional): + enable_downloads = defs.get('repo_enable_downloads') + clone_uri = Optional.extract(clone_uri) description = Optional.extract(description) landing_rev = Optional.extract(landing_rev) @@ -596,32 +688,51 @@ class ApiController(JSONRPCController): clone_uri=clone_uri, repos_group=group, landing_rev=landing_rev, + enable_statistics=enable_statistics, + enable_downloads=enable_downloads, + enable_locking=enable_locking ) Session().commit() - return dict( msg="Created new repository `%s`" % (repo.repo_name), repo=repo.get_api_data() ) - except Exception: log.error(traceback.format_exc()) raise JSONRPCError('failed to create repository `%s`' % repo_name) - @HasPermissionAnyDecorator('hg.admin') - def fork_repo(self, apiuser, repoid, fork_name, owner, + @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') + def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')), description=Optional(''), copy_permissions=Optional(False), private=Optional(False), landing_rev=Optional('tip')): repo = get_repo_or_error(repoid) repo_name = repo.repo_name - owner = get_user_or_error(owner) _repo = RepoModel().get_by_repo_name(fork_name) if _repo: type_ = 'fork' if _repo.fork else 'repo' raise JSONRPCError("%s `%s` already exist" % (type_, fork_name)) + if HasPermissionAnyApi('hg.admin')(user=apiuser): + pass + elif HasRepoPermissionAnyApi('repository.admin', + 'repository.write', + 'repository.read')(user=apiuser, + repo_name=repo.repo_name): + if not isinstance(owner, Optional): + #forbid setting owner for non-admins + raise JSONRPCError( + 'Only RhodeCode admin can specify `owner` param' + ) + else: + raise JSONRPCError('repository `%s` does not exist' % (repoid)) + + if isinstance(owner, Optional): + owner = apiuser.user_id + + owner = get_user_or_error(owner) + try: # create structure of groups and return the last group group = map_groups(fork_name) @@ -652,7 +763,6 @@ class ApiController(JSONRPCController): fork_name) ) - @HasPermissionAnyDecorator('hg.admin') def delete_repo(self, apiuser, repoid): """ Deletes a given repository @@ -662,6 +772,12 @@ class ApiController(JSONRPCController): """ repo = get_repo_or_error(repoid) + if HasPermissionAnyApi('hg.admin')(user=apiuser) is False: + # check if we have admin permission for this repo ! + if HasRepoPermissionAnyApi('repository.admin')(user=apiuser, + repo_name=repo.repo_name) is False: + raise JSONRPCError('repository `%s` does not exist' % (repoid)) + try: RepoModel().delete(repo) Session().commit() @@ -675,7 +791,7 @@ class ApiController(JSONRPCController): 'failed to delete repository `%s`' % repo.repo_name ) - @HasPermissionAnyDecorator('hg.admin') + @HasPermissionAllDecorator('hg.admin') def grant_user_permission(self, apiuser, repoid, userid, perm): """ Grant permission for user on given repository, or update existing one @@ -708,7 +824,7 @@ class ApiController(JSONRPCController): ) ) - @HasPermissionAnyDecorator('hg.admin') + @HasPermissionAllDecorator('hg.admin') def revoke_user_permission(self, apiuser, repoid, userid): """ Revoke permission for user on given repository @@ -739,7 +855,7 @@ class ApiController(JSONRPCController): ) ) - @HasPermissionAnyDecorator('hg.admin') + @HasPermissionAllDecorator('hg.admin') def grant_users_group_permission(self, apiuser, repoid, usersgroupid, perm): """ @@ -778,7 +894,7 @@ class ApiController(JSONRPCController): ) ) - @HasPermissionAnyDecorator('hg.admin') + @HasPermissionAllDecorator('hg.admin') def revoke_users_group_permission(self, apiuser, repoid, usersgroupid): """ Revoke permission for users group on given repository diff --git a/rhodecode/controllers/changeset.py b/rhodecode/controllers/changeset.py index 68a21d37..f982f04f 100644 --- a/rhodecode/controllers/changeset.py +++ b/rhodecode/controllers/changeset.py @@ -221,13 +221,25 @@ class ChangesetController(BaseRepoController): for changeset in c.cs_ranges: inlines = [] if method == 'show': - c.statuses.extend([ChangesetStatusModel()\ - .get_status(c.rhodecode_db_repo.repo_id, - changeset.raw_id)]) + c.statuses.extend([ChangesetStatusModel().get_status( + c.rhodecode_db_repo.repo_id, changeset.raw_id)]) c.comments.extend(ChangesetCommentsModel()\ .get_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id)) + + #comments from PR + st = ChangesetStatusModel().get_statuses( + c.rhodecode_db_repo.repo_id, changeset.raw_id, + with_revisions=True) + # from associated statuses, check the pull requests, and + # show comments from them + + prs = set([x.pull_request for x in + filter(lambda x: x.pull_request != None, st)]) + + for pr in prs: + c.comments.extend(pr.comments) inlines = ChangesetCommentsModel()\ .get_inline_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id) @@ -269,6 +281,9 @@ class ChangesetController(BaseRepoController): cs_changes[''] = [None, None, None, None, diff, None] c.changes[changeset.raw_id] = cs_changes + #sort comments by how they were generated + c.comments = sorted(c.comments, key=lambda x: x.comment_id) + # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): @@ -342,7 +357,7 @@ class ChangesetController(BaseRepoController): ) except StatusChangeOnClosedPullRequestError: log.error(traceback.format_exc()) - msg = _('Changing status on a changeset associated with' + msg = _('Changing status on a changeset associated with ' 'a closed pull request is not allowed') h.flash(msg, category='warning') return redirect(h.url('changeset_home', repo_name=repo_name, @@ -371,7 +386,7 @@ class ChangesetController(BaseRepoController): @jsonify def delete_comment(self, repo_name, comment_id): co = ChangesetComment.get(comment_id) - owner = lambda: co.author.user_id == c.rhodecode_user.user_id + owner = co.author.user_id == c.rhodecode_user.user_id if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner: ChangesetCommentsModel().delete(comment=co) Session().commit() diff --git a/rhodecode/controllers/compare.py b/rhodecode/controllers/compare.py index 9479c641..2f05a35e 100644 --- a/rhodecode/controllers/compare.py +++ b/rhodecode/controllers/compare.py @@ -103,8 +103,11 @@ class CompareController(BaseRepoController): c.org_repo = org_repo = Repository.get_by_repo_name(org_repo) c.other_repo = other_repo = Repository.get_by_repo_name(other_repo) - if c.org_repo is None or c.other_repo is None: - log.error('Could not found repo %s or %s' % (org_repo, other_repo)) + if c.org_repo is None: + log.error('Could not find org repo %s' % org_repo) + raise HTTPNotFound + if c.other_repo is None: + log.error('Could not find other repo %s' % other_repo) raise HTTPNotFound if c.org_repo != c.other_repo and h.is_git(c.rhodecode_repo): diff --git a/rhodecode/controllers/home.py b/rhodecode/controllers/home.py index bc94da7f..3515cb08 100644 --- a/rhodecode/controllers/home.py +++ b/rhodecode/controllers/home.py @@ -28,6 +28,7 @@ import logging from pylons import tmpl_context as c, request from pylons.i18n.translation import _ from webob.exc import HTTPBadRequest +from sqlalchemy.sql.expression import func import rhodecode from rhodecode.lib import helpers as h @@ -35,7 +36,8 @@ from rhodecode.lib.ext_json import json from rhodecode.lib.auth import LoginRequired from rhodecode.lib.base import BaseController, render from rhodecode.model.db import Repository -from sqlalchemy.sql.expression import func +from rhodecode.model.repo import RepoModel + log = logging.getLogger(__name__) @@ -58,51 +60,11 @@ class HomeController(BaseController): .filter(Repository.group_id == None)\ .order_by(func.lower(Repository.repo_name))\ .all() - repos_data = [] - total_records = len(c.repos_list) - - _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup - template = _tmpl_lookup.get_template('data_table/_dt_elements.html') - - quick_menu = lambda repo_name: (template.get_def("quick_menu") - .render(repo_name, _=_, h=h, c=c)) - repo_lnk = lambda name, rtype, private, fork_of: ( - template.get_def("repo_name") - .render(name, rtype, private, fork_of, short_name=False, - admin=False, _=_, h=h, c=c)) - last_change = lambda last_change: (template.get_def("last_change") - .render(last_change, _=_, h=h, c=c)) - rss_lnk = lambda repo_name: (template.get_def("rss") - .render(repo_name, _=_, h=h, c=c)) - atom_lnk = lambda repo_name: (template.get_def("atom") - .render(repo_name, _=_, h=h, c=c)) - - def desc(desc): - if c.visual.stylify_metatags: - return h.urlify_text(h.desc_stylize(h.truncate(desc, 60))) - else: - return h.urlify_text(h.truncate(desc, 60)) - - for repo in c.repos_list: - repos_data.append({ - "menu": quick_menu(repo.repo_name), - "raw_name": repo.repo_name.lower(), - "name": repo_lnk(repo.repo_name, repo.repo_type, - repo.private, repo.fork), - "last_change": last_change(repo.last_db_change), - "desc": desc(repo.description), - "owner": h.person(repo.user.username), - "rss": rss_lnk(repo.repo_name), - "atom": atom_lnk(repo.repo_name), - }) - - c.data = json.dumps({ - "totalRecords": total_records, - "startIndex": 0, - "sort": "name", - "dir": "asc", - "records": repos_data - }) + + repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, + admin=False) + #json used to render the grid + c.data = json.dumps(repos_data) return render('/index.html') diff --git a/rhodecode/controllers/journal.py b/rhodecode/controllers/journal.py index 9d499d19..5894cf73 100644 --- a/rhodecode/controllers/journal.py +++ b/rhodecode/controllers/journal.py @@ -27,6 +27,8 @@ from itertools import groupby from sqlalchemy import or_ from sqlalchemy.orm import joinedload +from sqlalchemy.sql.expression import func + from webhelpers.paginate import Page from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed @@ -39,10 +41,10 @@ from rhodecode.lib.auth import LoginRequired, NotAnonymous from rhodecode.lib.base import BaseController, render from rhodecode.model.db import UserLog, UserFollowing, Repository, User from rhodecode.model.meta import Session -from sqlalchemy.sql.expression import func -from rhodecode.model.scm import ScmModel from rhodecode.lib.utils2 import safe_int, AttributeDict from rhodecode.controllers.admin.admin import _journal_filter +from rhodecode.model.repo import RepoModel +from rhodecode.lib.compat import json log = logging.getLogger(__name__) @@ -78,18 +80,73 @@ class JournalController(BaseController): c.journal_data = render('journal/journal_data.html') if request.environ.get('HTTP_X_PARTIAL_XHR'): return c.journal_data - return render('journal/journal.html') - @LoginRequired() - @NotAnonymous() - def index_my_repos(self): - c.user = User.get(self.rhodecode_user.user_id) - if request.environ.get('HTTP_X_PARTIAL_XHR'): - all_repos = self.sa.query(Repository)\ - .filter(Repository.user_id == c.user.user_id)\ + repos_list = Session().query(Repository)\ + .filter(Repository.user_id == + self.rhodecode_user.user_id)\ .order_by(func.lower(Repository.repo_name)).all() - c.user_repos = ScmModel().get_repos(all_repos) - return render('journal/journal_page_repos.html') + + repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list, + admin=True) + #json used to render the grid + c.data = json.dumps(repos_data) + + watched_repos_data = [] + + ## watched repos + _render = RepoModel._render_datatable + + def quick_menu(repo_name): + return _render('quick_menu', repo_name) + + def repo_lnk(name, rtype, private, fork_of): + return _render('repo_name', name, rtype, private, fork_of, + short_name=False, admin=False) + + def last_rev(repo_name, cs_cache): + return _render('revision', repo_name, cs_cache.get('revision'), + cs_cache.get('raw_id'), cs_cache.get('author'), + cs_cache.get('message')) + + def desc(desc): + from pylons import tmpl_context as c + if c.visual.stylify_metatags: + return h.urlify_text(h.desc_stylize(h.truncate(desc, 60))) + else: + return h.urlify_text(h.truncate(desc, 60)) + + def repo_actions(repo_name): + return _render('repo_actions', repo_name) + + def owner_actions(user_id, username): + return _render('user_name', user_id, username) + + def toogle_follow(repo_id): + return _render('toggle_follow', repo_id) + + for entry in c.following: + repo = entry.follows_repository + cs_cache = repo.changeset_cache + row = { + "menu": quick_menu(repo.repo_name), + "raw_name": repo.repo_name.lower(), + "name": repo_lnk(repo.repo_name, repo.repo_type, + repo.private, repo.fork), + "last_changeset": last_rev(repo.repo_name, cs_cache), + "raw_tip": cs_cache.get('revision'), + "action": toogle_follow(repo.repo_id) + } + + watched_repos_data.append(row) + + c.watched_data = json.dumps({ + "totalRecords": len(c.following), + "startIndex": 0, + "sort": "name", + "dir": "asc", + "records": watched_repos_data + }) + return render('journal/journal.html') @LoginRequired(api_access=True) @NotAnonymous() diff --git a/rhodecode/controllers/login.py b/rhodecode/controllers/login.py index 1e75bb49..da9c07f8 100644 --- a/rhodecode/controllers/login.py +++ b/rhodecode/controllers/login.py @@ -54,10 +54,9 @@ class LoginController(BaseController): def index(self): # redirect if already logged in c.came_from = request.GET.get('came_from') - - if self.rhodecode_user.is_authenticated \ - and self.rhodecode_user.username != 'default': - + not_default = self.rhodecode_user.username != 'default' + ip_allowed = self.rhodecode_user.ip_allowed + if self.rhodecode_user.is_authenticated and not_default and ip_allowed: return redirect(url('home')) if request.POST: diff --git a/rhodecode/controllers/pullrequests.py b/rhodecode/controllers/pullrequests.py index 1ed6192d..fa08b632 100644 --- a/rhodecode/controllers/pullrequests.py +++ b/rhodecode/controllers/pullrequests.py @@ -97,7 +97,7 @@ class PullrequestsController(BaseRepoController): return repo.branches.keys()[0] def _get_is_allowed_change_status(self, pull_request): - owner = self.rhodecode_user.user_id == pull_request.user_id + owner = self.rhodecode_user.user_id == pull_request.user_id reviewer = self.rhodecode_user.user_id in [x.user_id for x in pull_request.reviewers] return (self.rhodecode_user.admin or owner or reviewer) @@ -299,7 +299,7 @@ class PullrequestsController(BaseRepoController): else EmptyChangeset(), 'raw_id')) c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges]) - c.target_repo = c.repo_name + c.target_repo = other_repo.repo_name # defines that we need hidden inputs with changesets c.as_form = request.GET.get('as_form', False) @@ -339,7 +339,6 @@ class PullrequestsController(BaseRepoController): c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() c.pull_request = PullRequest.get_or_404(pull_request_id) - c.target_repo = c.pull_request.org_repo.repo_name c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request) cc_model = ChangesetCommentsModel() cs_model = ChangesetStatusModel() @@ -478,7 +477,7 @@ class PullrequestsController(BaseRepoController): #don't allow deleting comments on closed pull request raise HTTPForbidden() - owner = lambda: co.author.user_id == c.rhodecode_user.user_id + owner = co.author.user_id == c.rhodecode_user.user_id if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner: ChangesetCommentsModel().delete(comment=co) Session().commit() |