# -*- coding: utf-8 -*-
"""
rhodecode.controllers.admin.users_groups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Users Groups crud controller for pylons
:created_on: Jan 25, 2011
:author: marcink
:copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
:license: GPLv3, see COPYING for more details.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import traceback
import formencode
from formencode import htmlfill
from pylons import request, session, tmpl_context as c, url, config
from pylons.controllers.util import abort, redirect
from pylons.i18n.translation import _
from rhodecode.lib import helpers as h
from rhodecode.lib.exceptions import UsersGroupsAssignedException
from rhodecode.lib.utils2 import safe_unicode, str2bool
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
from rhodecode.lib.base import BaseController, render
from rhodecode.model.users_group import UsersGroupModel
from rhodecode.model.db import User, UsersGroup
from rhodecode.model.db import User, UsersGroup, UsersGroupToPerm,\
UsersGroupRepoToPerm, UsersGroupRepoGroupToPerm
from rhodecode.model.forms import UsersGroupForm
from rhodecode.model.meta import Session
from rhodecode.lib.utils import action_logger
from sqlalchemy.orm import joinedload
log = logging.getLogger(__name__)
class UsersGroupsController(BaseController):
"""REST Controller styled on the Atom Publishing Protocol"""
# To properly map this controller, ensure your config/routing.py
# file has a resource setup:
# map.resource('users_group', 'users_groups')
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
def __before__(self):
c.admin_user = session.get('admin_user')
c.admin_username = session.get('admin_username')
super(UsersGroupsController, self).__before__()
c.available_permissions = config['available_permissions']
def index(self, format='html'):
"""GET /users_groups: All items in the collection"""
# url('users_groups')
c.users_groups_list = UsersGroup().query().all()
return render('admin/users_groups/users_groups.html')
def create(self):
"""POST /users_groups: Create a new item"""
users_group_form = UsersGroupForm()()
try:
form_result = users_group_form.to_python(dict(request.POST))
UsersGroupModel().create(name=form_result['users_group_name'],
active=form_result['users_group_active'])
gr = form_result['users_group_name']
action_logger(self.rhodecode_user,
'admin_created_users_group:%s' % gr,
None, self.ip_addr, self.sa)
h.flash(_('created users group %s') % gr, category='success')
Session().commit()
except formencode.Invalid, errors:
return htmlfill.render(
render('admin/users_groups/users_group_add.html'),
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8")
except Exception:
log.error(traceback.format_exc())
h.flash(_('error occurred during creation of users group %s') \
% request.POST.get('users_group_name'), category='error')
return redirect(url('users_groups'))
def new(self, format='html'):
"""GET /users_groups/new: Form to create a new item"""
# url('new_users_group')
return render('admin/users_groups/users_group_add.html')
def _load_data(self, id):
c.users_group.permissions = {
'repositories': {},
'repositories_groups': {}
}
ugroup_repo_perms = UsersGroupRepoToPerm.query()\
.options(joinedload(UsersGroupRepoToPerm.permission))\
.options(joinedload(UsersGroupRepoToPerm.repository))\
.filter(UsersGroupRepoToPerm.users_group_id == id)\
.all()
for gr in ugroup_repo_perms:
c.users_group.permissions['repositories'][gr.repository.repo_name] \
= gr.permission.permission_name
ugroup_group_perms = UsersGroupRepoGroupToPerm.query()\
.options(joinedload(UsersGroupRepoGroupToPerm.permission))\
.options(joinedload(UsersGroupRepoGroupToPerm.group))\
.filter(UsersGroupRepoGroupToPerm.users_group_id == id)\
for gr in ugroup_group_perms:
c.users_group.permissions['repositories_groups'][gr.group.group_name] \
c.group_members_obj = [x.user for x in c.users_group.members]
c.group_members = [(x.user_id, x.username) for x in
c.group_members_obj]
c.available_members = [(x.user_id, x.username) for x in
User.query().all()]
def update(self, id):
"""PUT /users_groups/id: Update an existing item"""
# Forms posted to this method should contain a hidden field:
# <input type="hidden" name="_method" value="PUT" />
# Or using helpers:
# h.form(url('users_group', id=ID),
# method='put')
# url('users_group', id=ID)
c.users_group = UsersGroup.get(id)
c.users_group = UsersGroup.get_or_404(id)
self._load_data(id)
available_members = [safe_unicode(x[0]) for x in c.available_members]
users_group_form = UsersGroupForm(edit=True,
old_data=c.users_group.get_dict(),
available_members=available_members)()
form_result = users_group_form.to_python(request.POST)
UsersGroupModel().update(c.users_group, form_result)
'admin_updated_users_group:%s' % gr,
h.flash(_('updated users group %s') % gr, category='success')
ug_model = UsersGroupModel()
defaults = errors.value
e = errors.error_dict or {}
defaults.update({
'create_repo_perm': ug_model.has_perm(id,
'hg.create.repository'),
'fork_repo_perm': ug_model.has_perm(id,
'hg.fork.repository'),
'_method': 'put'
})
render('admin/users_groups/users_group_edit.html'),
defaults=defaults,
errors=e,
h.flash(_('error occurred during update of users group %s') \
return redirect(url('edit_users_group', id=id))
def delete(self, id):
"""DELETE /users_groups/id: Delete an existing item"""
# <input type="hidden" name="_method" value="DELETE" />
# method='delete')
usr_gr = UsersGroup.get_or_404(id)
UsersGroupModel().delete(usr_gr)
h.flash(_('successfully deleted users group'), category='success')
except UsersGroupsAssignedException, e:
h.flash(e, category='error')
h.flash(_('An error occurred during deletion of users group'),
category='error')
def show(self, id, format='html'):
"""GET /users_groups/id: Show a specific item"""
def edit(self, id, format='html'):
"""GET /users_groups/id/edit: Form to edit an existing item"""
# url('edit_users_group', id=ID)
c.users_group.permissions = {}
defaults = c.users_group.get_dict()
'create_repo_perm': ug_model.has_perm(c.users_group,
'fork_repo_perm': ug_model.has_perm(c.users_group,
encoding="UTF-8",
force_defaults=False
)
def update_perm(self, id):
"""PUT /users_perm/id: Update an existing item"""
# url('users_group_perm', id=ID, method='put')
users_group = UsersGroup.get_or_404(id)
grant_create_perm = str2bool(request.POST.get('create_repo_perm'))
grant_fork_perm = str2bool(request.POST.get('fork_repo_perm'))
inherit_perms = str2bool(request.POST.get('inherit_default_permissions'))
usersgroup_model = UsersGroupModel()
users_group.inherit_default_permissions = inherit_perms
Session().add(users_group)
if grant_create_perm:
usersgroup_model.revoke_perm(id, 'hg.create.none')
usersgroup_model.grant_perm(id, 'hg.create.repository')
h.flash(_("Granted 'repository create' permission to users group"),
category='success')
else:
usersgroup_model.revoke_perm(id, 'hg.create.repository')
usersgroup_model.grant_perm(id, 'hg.create.none')
h.flash(_("Revoked 'repository create' permission to users group"),
if grant_fork_perm:
usersgroup_model.revoke_perm(id, 'hg.fork.none')
usersgroup_model.grant_perm(id, 'hg.fork.repository')
h.flash(_("Granted 'repository fork' permission to users group"),
usersgroup_model.revoke_perm(id, 'hg.fork.repository')
usersgroup_model.grant_perm(id, 'hg.fork.none')
h.flash(_("Revoked 'repository fork' permission to users group"),
h.flash(_('An error occurred during permissions saving'),
@@ -3842,198 +3842,199 @@ div.form div.fields div.field div.highli
#login div.form div.fields div.field,#register div.form div.fields div.field
{
clear: both;
overflow: hidden;
margin: 0;
padding: 0 0 10px;
#login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message
height: 1%;
display: block;
color: red;
margin: 8px 0 0;
padding: 0;
max-width: 320px;
#login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label
color: #000;
font-weight: 700;
#login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
float: left;
#login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
margin: 0 0 0 184px;
#login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
color: #565656;
#login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
font-size: 1em;
#changeset_content .container .wrapper,#graph_content .container .wrapper
width: 600px;
#changeset_content .container .left {
width: 75%;
padding-left: 5px;
#changeset_content .container .left .date,.ac .match {
padding-top: 5px;
padding-bottom: 5px;
div#legend_container table td,div#legend_choices table td {
border: none !important;
height: 20px !important;
padding: 0 !important;
.q_filter_box {
-webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: 0 none;
color: #AAAAAA;
margin-bottom: -4px;
margin-top: -4px;
padding-left: 3px;
#node_filter {
border: 0px solid #545454;
.group_members_wrap{
min-height: 85px;
padding-left: 20px;
.group_members .group_member{
height: 30px;
padding:0px 0px 0px 10px;
padding:0px 0px 0px 0px;
.reviewers_member{
height: 15px;
.emails_wrap{
padding: 0px 20px;
.emails_wrap .email_entry{
.emails_wrap .email_entry .email{
float: left
.emails_wrap .email_entry .email_action{
/*README STYLE*/
div.readme {
padding:0px;
div.readme h2 {
font-weight: normal;
div.readme .readme_box {
background-color: #fafafa;
clear:both;
overflow:hidden;
margin:0;
padding:0 20px 10px;
div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
border-bottom: 0 !important;
margin: 0 !important;
line-height: 1.5em !important;
div.readme .readme_box h1:first-child {
padding-top: .25em !important;
div.readme .readme_box h2, div.readme .readme_box h3 {
margin: 1em 0 !important;
div.readme .readme_box h2 {
margin-top: 1.5em !important;
border-top: 4px solid #e0e0e0 !important;
padding-top: .5em !important;
div.readme .readme_box p {
color: black !important;
div.readme .readme_box ul {
list-style: disc !important;
margin: 1em 0 1em 2em !important;
div.readme .readme_box ol {
list-style: decimal;
div.readme .readme_box pre, code {
font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
div.readme .readme_box code {
font-size: 12px !important;
background-color: ghostWhite !important;
color: #444 !important;
padding: 0 .2em !important;
border: 1px solid #dedede !important;
div.readme .readme_box pre code {
@@ -52,114 +52,177 @@
<div class="select">
<table>
<tr>
<td>
<div>
<div style="float:left">
<div class="text" style="padding: 0px 0px 6px;">${_('Choosen group members')}</div>
${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")}
<div id="remove_all_elements" style="cursor:pointer;text-align:center">
${_('Remove all elements')}
<img alt="remove" style="vertical-align:text-bottom" src="${h.url('/images/icons/arrow_right.png')}"/>
</div>
<div style="float:left;width:20px;padding-top:50px">
<img alt="add" id="add_element"
style="padding:2px;cursor:pointer"
src="${h.url('/images/icons/arrow_left.png')}"/>
<br />
<img alt="remove" id="remove_element"
src="${h.url('/images/icons/arrow_right.png')}"/>
<div class="text" style="padding: 0px 0px 6px;">${_('Available members')}</div>
${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")}
<div id="add_all_elements" style="cursor:pointer;text-align:center">
<img alt="add" style="vertical-align:text-bottom" src="${h.url('/images/icons/arrow_left.png')}"/>
${_('Add all elements')}
</td>
</tr>
</table>
<div class="buttons">
${h.submit('save',_('save'),class_="ui-btn large")}
${h.end_form()}
<div class="box box-right">
<!-- box / title -->
<div class="title">
<h5>${_('Permissions')}</h5>
${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')}
<div class="form">
<!-- fields -->
<div class="fields">
<div class="field">
<div class="label label-checkbox">
<label for="inherit_permissions">${_('Inherit default permissions')}:</label>
<div class="checkboxes">
${h.checkbox('inherit_default_permissions',value=True)}
<span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. '
'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span>
<div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" >
<label for="create_repo_perm">${_('Create repositories')}:</label>
${h.checkbox('create_repo_perm',value=True)}
<label for="fork_repo_perm">${_('Fork repositories')}:</label>
${h.checkbox('fork_repo_perm',value=True)}
${h.submit('save',_('Save'),class_="ui-btn large")}
${h.reset('reset',_('Reset'),class_="ui-btn large")}
<h5>${_('Group members')}</h5>
<div class="group_members_wrap">
% if c.group_members_obj:
<ul class="group_members">
%for user in c.group_members_obj:
<li>
<div class="group_member">
<div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div>
<div>${user.username}</div>
<div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div>
<div>${user.full_name}</div>
</li>
%endfor
</ul>
%else:
<span class="empty_data">${_('No members yet')}</span>
%endif
<div class="box box-left">
<h5>${_('Permissions defined for this group')}</h5>
## permissions overview
<div id="perms" class="table">
%for section in sorted(c.users_group.permissions.keys()):
<div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
%if not c.users_group.permissions:
<span class="empty_data">${_('No permissions set yet')}</span>
<div id='tbl_list_wrap_${section}' class="yui-skin-sam">
<table id="tbl_list_repository">
<thead>
<th class="left">${_('Name')}</th>
<th class="left">${_('Permission')}</th>
<th class="left">${_('Edit Permission')}</th>
</thead>
<tbody>
%for k in c.users_group.permissions[section]:
<%
section_perm = c.users_group.permissions[section].get(k)
_perm = section_perm.split('.')[-1]
%>
%if section == 'repositories':
<a href="${h.url('summary_home',repo_name=k)}">${k}</a>
%elif section == 'repositories_groups':
<a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
<span class="perm_tag ${_perm}">${section_perm}</span>
<a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a>
<a href="${h.url('edit_repos_group',id=k,anchor='permissions_manage')}">${_('edit')}</a>
--
</tbody>
<script type="text/javascript">
MultiSelectWidget('users_group_members','available_members','edit_users_group');
</script>
</%def>
Status change: