Skip to content

Commit

Permalink
Merge pull request #96 from qld-gov-au/develop
Browse files Browse the repository at this point in the history
Develop to master - handle 'delete all' without JavaScript
  • Loading branch information
ThrawnCA committed Oct 26, 2023
2 parents c541441 + c221156 commit 795759e
Show file tree
Hide file tree
Showing 14 changed files with 332 additions and 265 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
run: bin/test.sh
timeout-minutes: 20

- name: Retrieve logs
if: always()
run: ahoy logs
timeout-minutes: 5

- name: Retrieve screenshots
if: failure()
run: bin/process-artifacts.sh
Expand Down
64 changes: 47 additions & 17 deletions ckanext/datarequests/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ckan.plugins import toolkit as tk
from ckan.plugins.toolkit import h, config

from . import constants, db, validator
from . import common, constants, db, validator


log = logging.getLogger(__name__)
Expand All @@ -53,23 +53,23 @@ def _get_user(user_id):
USERS_CACHE[user_id] = user
return user
except Exception as e:
log.warn(e)
log.warning(e)


def _get_organization(organization_id):
try:
organization_show = tk.get_action('organization_show')
return organization_show({'ignore_auth': True}, {'id': organization_id, 'include_users': True})
except Exception as e:
log.warn(e)
log.warning(e)


def _get_package(package_id):
try:
package_show = tk.get_action('package_show')
return package_show({'ignore_auth': True}, {'id': package_id})
except Exception as e:
log.warn(e)
log.warning(e)


def _dictize_datarequest(datarequest):
Expand Down Expand Up @@ -155,17 +155,17 @@ def _get_datarequest_involved_users(context, datarequest_dict):
users.update([follower.user_id for follower in db.DataRequestFollower.get(datarequest_id=datarequest_id)])
users.update([comment['user_id'] for comment in list_datarequest_comments(new_context, {'datarequest_id': datarequest_id})])

if datarequest_dict['organization']:
users.update([user['id'] for user in datarequest_dict['organization']['users']])
org = datarequest_dict.get('organization')
if org:
users.update(_get_admin_users_from_organisation(org))

# Notifications are not sent to the user that performs the action
users.discard(context['auth_user_obj'].id)

return users


def _send_mail(user_ids, action_type, datarequest):

def _send_mail(user_ids, action_type, datarequest, job_title=None):
for user_id in user_ids:
try:
user_data = model.User.get(user_id)
Expand All @@ -179,12 +179,19 @@ def _send_mail(user_ids, action_type, datarequest):
subject = tk.render('emails/subjects/{0}.txt'.format(action_type), extra_vars)
body = tk.render('emails/bodies/{0}.txt'.format(action_type), extra_vars)

mailer.mail_user(user_data, subject, body)

tk.enqueue_job(mailer.mail_user, [user_data, subject, body], title=job_title)
except Exception:
log.exception("Error sending notification to {0}".format(user_id))


def _get_admin_users_from_organisation(org_dict):
all_users = org_dict.get('users', [])
if common.get_config_bool_value('ckanext.datarequests.notify_all_members', True):
return {user['id'] for user in all_users}
else:
return {user['id'] for user in all_users if user.get('capacity') == 'admin'}


def throttle_datarequest(creator):
""" Check that the account is not creating requests too quickly.
This should happen after validation, so a request that fails
Expand Down Expand Up @@ -234,7 +241,7 @@ def create_datarequest(context, data_dict):
:param description: A brief description for your data request
:type description: string
:param organiztion_id: The ID of the organization you want to asign the
:param organization_id: The ID of the organization you want to asign the
data request (optional).
:type organization_id: string
Expand Down Expand Up @@ -267,10 +274,11 @@ def create_datarequest(context, data_dict):

datarequest_dict = _dictize_datarequest(data_req)

if datarequest_dict['organization']:
users = {user['id'] for user in datarequest_dict['organization']['users']}
org = datarequest_dict.get('organization')
if org:
users = _get_admin_users_from_organisation(org)
users.discard(creator.id)
_send_mail(users, 'new_datarequest', datarequest_dict)
_send_mail(users, 'new_datarequest', datarequest_dict, 'Data Request Created Email')

return datarequest_dict

Expand Down Expand Up @@ -331,7 +339,7 @@ def update_datarequest(context, data_dict):
:param description: A brief description for your data request
:type description: string
:param organiztion_id: The ID of the organization you want to asign the
:param organization_id: The ID of the organization you want to asign the
data request.
:type organization_id: string
Expand Down Expand Up @@ -363,13 +371,34 @@ def update_datarequest(context, data_dict):
# Validate data
validator.validate_datarequest(context, data_dict)

# Determine whether organisation has changed
organisation_updated = data_req.organization_id != data_dict['organization_id']
if organisation_updated:
unassigned_organisation_id = data_req.organization_id

# Set the data provided by the user in the data_red
_undictize_datarequest_basic(data_req, data_dict)

session.add(data_req)
session.commit()

return _dictize_datarequest(data_req)
datarequest_dict = _dictize_datarequest(data_req)

if organisation_updated and common.get_config_bool_value('ckanext.datarequests.notify_on_update'):
org = datarequest_dict['organization']
# Email Admin users of the assigned organisation
if org:
users = _get_admin_users_from_organisation(org)
users.discard(context['auth_user_obj'].id)
_send_mail(users, 'new_datarequest_organisation',
datarequest_dict, 'Data Request Assigned Email')
# Email Admin users of unassigned organisation
users = _get_admin_users_from_organisation(_get_organization(unassigned_organisation_id))
users.discard(context['auth_user_obj'].id)
_send_mail(users, 'unassigned_datarequest_organisation',
datarequest_dict, 'Data Request Unassigned Email')

return datarequest_dict


def list_datarequests(context, data_dict):
Expand Down Expand Up @@ -602,7 +631,8 @@ def close_datarequest(context, data_dict):

# Mailing
users = _get_datarequest_involved_users(context, datarequest_dict)
_send_mail(users, 'close_datarequest', datarequest_dict)
_send_mail(users, 'close_datarequest',
datarequest_dict, 'Data Request Closed Send Email')

return datarequest_dict

Expand Down
58 changes: 32 additions & 26 deletions ckanext/datarequests/controllers/controller_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ def pager_url(state=None, sort=None, q=None, page=None):
return tk.render(file_to_render, extra_vars=extra_vars)
except ValueError as e:
# This exception should only occur if the page value is not valid
log.warn(e)
log.warning(e)
return tk.abort(400, tk._('"page" parameter must be an integer'))
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('Unauthorized to list Data Requests'))


Expand All @@ -174,7 +174,7 @@ def _process_post(action, context):
return tk.redirect_to(tk.url_for('datarequest.show', id=result['id']))

except tk.ValidationError as e:
log.warn(e)
log.warning(e)
# Fill the fields that will display some information in the page
c.datarequest = {
'id': data_dict.get('id', ''),
Expand Down Expand Up @@ -210,7 +210,7 @@ def new():
post_result = _process_post(constants.CREATE_DATAREQUEST, context)
return post_result or tk.render('datarequests/new.html')
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('Unauthorized to create a Data Request'))


Expand All @@ -229,7 +229,7 @@ def show(id):
except tk.ObjectNotFound:
return tk.abort(404, tk._('Data Request %s not found') % id)
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to view the Data Request %s' % id))


Expand All @@ -249,10 +249,10 @@ def update(id):
post_result = _process_post(constants.UPDATE_DATAREQUEST, context)
return post_result or tk.render('datarequests/edit.html')
except tk.ObjectNotFound as e:
log.warn(e)
log.warning(e)
return tk.abort(404, tk._('Data Request %s not found') % id)
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to update the Data Request %s' % id))


Expand All @@ -266,10 +266,10 @@ def delete(id):
h.flash_notice(tk._('Data Request %s has been deleted') % datarequest.get('title', ''))
return tk.redirect_to(tk.url_for('datarequest.index'))
except tk.ObjectNotFound as e:
log.warn(e)
log.warning(e)
return tk.abort(404, tk._('Data Request %s not found') % id)
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to delete the Data Request %s' % id))


Expand Down Expand Up @@ -353,14 +353,14 @@ def _return_page(errors=None, errors_summary=None):
return _return_page()

except tk.ValidationError as e: # Accepted Dataset is not valid
log.warn(e)
log.warning(e)
errors_summary = _get_errors_summary(e.error_dict)
return _return_page(e.error_dict, errors_summary)
except tk.ObjectNotFound as e:
log.warn(e)
log.warning(e)
return tk.abort(404, tk._('Data Request %s not found') % id)
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to close the Data Request %s' % id))


Expand Down Expand Up @@ -398,14 +398,14 @@ def comment(id):
h.flash_notice(flash_message)

except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to %s' % action_text))
except tk.ValidationError as e:
log.warn(e)
log.warning(e)
c.errors = e.error_dict
c.errors_summary = _get_errors_summary(c.errors)
except tk.ObjectNotFound as e:
log.warn(e)
log.warning(e)
return tk.abort(404, tk._(str(e)))
# Other exceptions are not expected. Otherwise, the request will fail.

Expand All @@ -426,11 +426,11 @@ def comment(id):
return tk.render('datarequests/comment.html')

except tk.ObjectNotFound as e:
log.warn(e)
log.warning(e)
return tk.abort(404, tk._('Data Request %s not found' % id))

except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to list the comments of the Data Request %s' % id))


Expand All @@ -443,10 +443,10 @@ def delete_comment(datarequest_id, comment_id):
h.flash_notice(tk._('Comment has been deleted'))
return tk.redirect_to(tk.url_for('datarequest.comment', id=datarequest_id))
except tk.ObjectNotFound as e:
log.warn(e)
log.warning(e)
return tk.abort(404, tk._('Comment %s not found') % comment_id)
except tk.NotAuthorized as e:
log.warn(e)
log.warning(e)
return tk.abort(403, tk._('You are not authorized to delete this comment'))


Expand All @@ -467,11 +467,17 @@ def purge(user_id):
data_dict = {'user_id': user_id}
context = _get_context()

try:
tk.get_action(constants.PURGE_DATAREQUESTS)(context, data_dict)
except tk.ObjectNotFound as e:
log.warn(e)
return tk.abort(404, tk._('User %s not found') % user_id)
post_params = request_helpers.get_post_params()
if post_params:
if 'cancel' in post_params:
return tk.redirect_to('datarequest.index')

h.flash_notice(tk._('Deleted data request(s) for user'))
return tk.redirect_to('datarequest.index')
try:
tk.get_action(constants.PURGE_DATAREQUESTS)(context, data_dict)
h.flash_notice(tk._('Deleted data request(s) for user'))
return tk.redirect_to('datarequest.index')
except tk.ObjectNotFound as e:
log.warning(e)
return tk.abort(404, tk._('User %s not found') % user_id)
else:
return tk.render('datarequests/confirm_delete_all.html', extra_vars={'user_id': user_id})
2 changes: 1 addition & 1 deletion ckanext/datarequests/plugin_mixins/flask_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def get_blueprint(self):
"/{}/purge/<user_id>".format(constants.DATAREQUESTS_MAIN_PATH),
"purge",
controller_functions.purge,
('POST',),
('GET', 'POST',),
),
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{% extends "page.html" %}

{% block subtitle %}{{ _("Confirm Delete") }}{% endblock %}

{% block maintag %}<div class="row" role="main">{% endblock %}

{% block main_content %}
<section class="module col-md-6 col-md-offset-3">
<div class="module-content">
{% block form %}
<p>{{ _('Are you sure you want to delete ALL data requests for user {user_id}?').format(user_id=user_id) }}</p>
<p class="form-actions">
<form id="confirm-datarequest-delete-all-form" action="{% url_for 'datarequest.purge', user_id=user_id %}" method="POST">
{% if 'csrf_input' in h %}
{{ h.csrf_input() }}
{% endif %}
<button class="btn btn-danger" type="submit" name="cancel" >{{ _('Cancel') }}</button>
<button class="btn btn-primary" type="submit" name="delete" >{{ _('Confirm Delete') }}</button>
</form>
</p>
{% endblock %}
</div>
</section>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ <h3 class="dataset-heading">
</h3>
{% if g.userobj.sysadmin %}
<div class="btn-group pull-right">
<a class="btn btn-danger btn-danger-serious" href="{% url_for 'datarequest.purge', user_id=datarequest.user_id %}" data-module="confirm-action" data-module-content="Are you sure you want to delete ALL data requests for this user?" title="Delete all for this user">
<a class="btn btn-danger btn-danger-serious" href="{% url_for 'datarequest.purge', user_id=datarequest.user_id %}" title="Delete all for this user">
<i class="fa fa-skull"></i>
</a>
</div>
Expand Down
Loading

0 comments on commit 795759e

Please sign in to comment.