Commit a8819ef3 authored by Marko Kuder's avatar Marko Kuder
Browse files

Merge branch 'feature/user-delete' into 'development'

Delete user

See merge request !13
parents 4012b596 b33d0894
......@@ -330,6 +330,11 @@ def opsi_user_list(context, data_dict):
return {'success': True}
def opsi_user_delete(context, data_dict):
# Sysadmins only
return {'success': False, 'msg': _('Only sysadmins can delete publishers')}
def dgu_organization_delete(context, data_dict):
# Sysadmins only
return { 'success': False, 'msg': _('Only sysadmins can delete publishers') }
......
# -*- coding: utf-8 -*-
import ckan.plugins.toolkit as t
import ckan.lib.helpers as h
import ckan.logic as logic
......@@ -6,6 +8,8 @@ import ckan.new_authz as new_authz
from ckan.lib.base import BaseController, abort, render
from ckan.controllers.user import UserController as CoreUserController
from ckan.common import _, request
from ckanext.dgu.lib.user_helpers import merge_users_on_delete, move_user
from ckanext.dgu.lib.reports import refresh_opsi_reports_async
c = t.c
get_action = logic.get_action
......@@ -13,6 +17,7 @@ check_access = logic.check_access
NotFound = logic.NotFound
NotAuthorized = logic.NotAuthorized
class UserController(CoreUserController):
def me(self, locale=None):
if not c.user:
......@@ -69,3 +74,67 @@ class UserController(CoreUserController):
c.users = users_list
return render('user/list.html')
def delete(self, id):
errors = {}
context = {'model': model, 'session': model.Session,
'user': c.user or c.author, 'auth_user_obj': c.userobj,
'for_view': True}
data_dict = {'id': id,
'user_obj': c.userobj}
context['with_related'] = False
try:
check_access('user_delete', context, data_dict)
except NotAuthorized:
abort(401, _('Not authorized to see this page'))
c.is_sysadmin = new_authz.is_sysadmin(c.user)
try:
user_dict = get_action('user_show')(context, data_dict)
except NotFound:
abort(404, _('User not found'))
except NotAuthorized:
abort(401, _('Not authorized to see this page'))
c.user_dict = user_dict
c.is_myself = user_dict['name'] == c.user
if request.POST:
if 'cancel' in request.params:
h.redirect_to(h.url_for(controller='ckanext.dgu.controllers.user:UserController', action='read', id=id))
return
else:
if c.is_myself:
errors['user'] = "Uporabnika ni dovoljeno izbrisati."
new_user_id = request.params.get('creator_user_id', None)
if c.user_dict['number_administered_packages'] > 0:
if not new_user_id:
errors[_('Editor')] = _("This field is required")
if new_user_id == c.user_dict['id'] or new_user_id == c.user_dict['name']:
errors[_('Editor')] = u"Napačen izbor urednika (%s)" % c.user_dict['display_name']
if not errors:
if c.user_dict['number_administered_packages'] > 0:
merged_users = merge_users_on_delete(c.user_dict['id'], new_user_id, context)
_error = merged_users.get('error', None)
else:
_error = None
if _error:
errors[_('Editor')] = _error
else:
try:
get_action('user_delete')(context, data_dict)
user_index = h.url_for(controller='ckanext.dgu.controllers.user:UserController', action='index')
h.flash_success(_('%s has been deleted.') % _('User'))
h.redirect_to(user_index)
except NotAuthorized:
msg = _('Unauthorized to delete user with id "{user_id}".')
abort(401, msg.format(user_id=id))
c.errors = errors
return render('user/delete.html')
import logging
from helpers import user_get_groups
from helpers import user_get_roles
import ckan.logic as logic
from ckan import model
from ckan.common import _
from ckanext.dgu.model.publisher_request import PublisherRequest
from ckanext.dgu.model import publisher_request
log = logging.getLogger(__name__)
get_action = logic.get_action
# a couple of users have different mails on multiple accounts
# provide proper exceptions for these by specifying mappings
# from their email hashes to the ID of matching duplicate user
......@@ -192,3 +196,26 @@ def move_user (old_id, new_id):
model.Session.add(role_obj)
log.debug('Merged user ' + old_id + ' to ' + new_id)
def merge_users_on_delete(user_id, new_user_id, context):
result = {}
new_user = model.User.get(new_user_id)
if not isinstance(new_user, model.User):
log.error('Could not migrate data from ' + str(user_id) + ' to ' + str(new_user_id) + ', new user not found!')
result['error'] = '%s (%s)' % (_('User not found'), str(new_user_id))
return result
packages = model.Session.query(model.Package) \
.filter(model.Package.creator_user_id == user_id)
for pkg in packages:
role_show_dict = {'domain_object': pkg.id, 'roles': ['admin']}
existing_roles = logic.get_action('roles_show')(context, role_show_dict)
role_update_dict_list = [{'user': new_user.id, 'roles': ['admin']}]
for role in existing_roles.get('roles', []):
if role.get('role', '') == 'admin' and role.get('user_id', '') != new_user:
role_update_dict_list.append({'user': role.get('user_id'), 'roles': []})
updated_roles = logic.get_action('user_role_bulk_update')(context, {'domain_object': pkg.id, 'user_roles': role_update_dict_list})
return result
......@@ -18,7 +18,8 @@ from ckanext.dgu.authorize import (
opsi_extra_fields_editable,
opsi_dataset_delete, opsi_user_list, opsi_user_show,
dgu_organization_delete, dgu_group_change_state,
opsi_bulk_publish
opsi_bulk_publish,
opsi_user_delete
)
from ckanext.report.interfaces import IReport
from ckan.lib.helpers import url_for
......@@ -203,6 +204,7 @@ class ThemePlugin(p.SingletonPlugin):
# Remap the /user/me to the DGU version of the User controller
with SubMapper(map, controller=user_controller) as m:
m.connect('/data/user/me', action='me')
m.connect('user_delete', '/data/user/delete/{id}', action='delete', conditions=dict(method=['GET', 'POST']))
m.connect('user_datasets', '/data/user/{id:.*}', action='read',
ckan_icon='sitemap')
m.connect('user_index', '/data/user', action='index')
......@@ -267,7 +269,8 @@ class AuthApiPlugin(p.SingletonPlugin):
'organization_delete': dgu_organization_delete,
'organization_update': opsi_organization_update,
'group_change_state': dgu_group_change_state,
'bulk_publish': opsi_bulk_publish
'bulk_publish': opsi_bulk_publish,
'user_delete': opsi_user_delete
}
......
......@@ -42,8 +42,9 @@
</thead>
<tbody>
{% for u in c.page.items %}
{% if u.state != 'deleted' or h.is_sysadmin() %}
<tr>
<td><a href="/data/user/{{u.name}}">{{u.display_name}}</a></td>
<td><a href="/data/user/{{u.name}}">{{u.display_name}}{% if u.state == 'deleted'%} (izbrisan){% endif %}</a></td>
<td>{{u.email}}</td>
<td>{{u.number_administered_packages()}}</td>
<td>{{u.number_of_edits()}}</td>
......@@ -57,6 +58,7 @@
</td>
<td>{{h.render_datetime(u.created, date_format="%d-%m-%Y")}}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
......@@ -67,4 +69,4 @@
</div>
{% endblock %}
\ No newline at end of file
{% endblock %}
{% extends "page.html" %}
{% block optional_head %}
<script type="text/javascript">
jQuery(function ($) {
CKAN.Dgu.setupUserAutocomplete(jQuery('input.autocomplete-creator'));
});
if ( window.history.replaceState ) {
//window.history.replaceState( null, null, window.location.href );
}
</script>
{% endblock %}
{% block pre_primary %}
<div class="row expanded titlebar">
<div class="small-12 columns">
<div class="icon ckan"></div>
<div class="title center"><h1>{{ _('Delete')}} {{ c.user_dict['display_name'] }}</h1></div>
</div>
</div>
{% endblock %}
{% block secondary %}{% endblock %}
{% block primary_content_inner %}
{% import "/_dgu_jinja_util.html" as m with context %}
{% import 'macros/form.html' as form %}
<div class="row dataset">
<div class="small-12 columns container">
{% if c.errors %}
<div id="errors" class="panel error">
<div class="panel-heading"><strong>Napake v obrazcu</strong></div>
<div class="panel-body">
<p>{{ _('The form contains invalid entries:') }}</p>
{{ m.dump(c.errors) }}
</div>
</div>
{% endif %}
<div class="dataset-edit-form">
<div class="panel panel-danger">
<div class="panel-heading">{{ _('Confirm Delete') }}</div>
<div class="panel-body">
<form id="user-delete" method="post" class="package_create_form ckan {% if errors %}has-errors{% endif %}">
<p>{{ _('Are you sure you want to delete this User?') }}</p>
{% if c.user_dict['number_administered_packages'] %}
<div class="module-content">
<div class="row">
<div class="small-12 large-12 columns">
<div class="tabs-content">
<hr>
<h5>Spremeni lastnika zbirk ({{ c.user_dict['number_administered_packages'] }})</h5>
<p>Opozorilo: Ob spremembi lastnika zbirk se prepričajte, da je član organizacije, kateri pripadajo zbirke. V nasprotnem primeru lastnik ne bo mogel urejati zbirke, kljub temu da jo bo lahko videl v svojem uredništvu.</p>
<div class="well">
<span>
<input class="autocomplete-creator" id="creator_user_id_chooser" name="creator_user_id_chooser" value="">
<input class="chosen-user" type="hidden" id="creator_user_id" name="creator_user_id" value="">
</span>
</div>
<hr>
</div>
</div>
</div>
</div>
{% endif %}
<input id="delete-button" class="button btn btn-danger" name="delete" type="submit" value="{{_('Confirm Delete')}}"/>
<input id="cancel-button" class="button btn" name="cancel" type="submit" value="{{_('Cancel')}}"/>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
......@@ -13,6 +13,14 @@ Variables set in the controller (and has not changed in master as of 16/11/2015)
{% extends "page.html" %}
{% import "_dgu_jinja_util.html" as m with context %}
{% block optional_head %}
<script type="text/javascript">
if ( window.history.replaceState ) {
//window.history.replaceState( null, null, window.location.href );
}
</script>
{% endblock %}
{% block title %}{{ c.user_dict['display_name'] }} - Uporabniški profil - {{ super() }}{% endblock %}
{% block breadcrumb_content %}
......@@ -39,7 +47,7 @@ Variables set in the controller (and has not changed in master as of 16/11/2015)
<tr>
<td class="boxed whitebox">
<h2>
<span>{{ c.user_dict['fullname'] or c.user_dict['name'] }}</span>
<span>{{ c.user_dict['fullname'] or c.user_dict['name'] }}{% if c.user_dict['state'] == 'deleted' %} (IZBRISAN UPORABNIK){% endif %}</span>
</h2>
<dl class="vcard">
<dt>ID</dt>
......@@ -125,5 +133,21 @@ Variables set in the controller (and has not changed in master as of 16/11/2015)
</tr>
</tbody>
</table>
{% if c.is_sysadmin and not c.is_myself %}
<table class="user-page-table">
<tbody>
<tr>
<td class="boxed whitebox listing text-right">
<a href="{{ h.url_for(controller='ckanext.dgu.controllers.user:UserController', action='delete', id=c.user_dict['name']) }}">
<button class="button btn btn-default" type="button" onclick="void(0);">
<span class="wrap-icon">
<i class="fi fi-trash"></i>
</span>Odstrani uporabnika</button>
</a>
</td>
</tr>
</tbody>
</table>
{% endif %}
{% endblock %}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment