aboutsummaryrefslogtreecommitdiff
path: root/rhodecode/controllers
diff options
context:
space:
mode:
authorMilo Casagrande <milo@ubuntu.com>2013-02-13 18:35:00 +0100
committerMilo Casagrande <milo@ubuntu.com>2013-02-13 18:35:00 +0100
commitf6e9d7be791b269967311ba281b5705361112669 (patch)
tree3da66a5f98dbb2975d00085dc2a3a781ec73d808 /rhodecode/controllers
parentd6b2ec12ceddb987c6f9df411f1c02fe32b1fe0a (diff)
parent637fcc9fc3f7f177097ed2c590d98a077cbeee26 (diff)
Merge branch 'master' into linaro
Fixed conflicts: setup.py
Diffstat (limited to 'rhodecode/controllers')
-rw-r--r--rhodecode/controllers/admin/notifications.py12
-rw-r--r--rhodecode/controllers/admin/permissions.py81
-rw-r--r--rhodecode/controllers/admin/repos.py38
-rw-r--r--rhodecode/controllers/admin/repos_groups.py48
-rw-r--r--rhodecode/controllers/admin/settings.py61
-rw-r--r--rhodecode/controllers/admin/users.py44
-rw-r--r--rhodecode/controllers/api/__init__.py24
-rw-r--r--rhodecode/controllers/api/api.py170
-rw-r--r--rhodecode/controllers/changeset.py25
-rw-r--r--rhodecode/controllers/compare.py7
-rw-r--r--rhodecode/controllers/home.py54
-rw-r--r--rhodecode/controllers/journal.py81
-rw-r--r--rhodecode/controllers/login.py7
-rw-r--r--rhodecode/controllers/pullrequests.py7
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()