diff --git a/ckanext/dataset_subscriptions/actions/__init__.py b/ckanext/dataset_subscriptions/actions/__init__.py index 66d7167..e69de29 100644 --- a/ckanext/dataset_subscriptions/actions/__init__.py +++ b/ckanext/dataset_subscriptions/actions/__init__.py @@ -1,64 +0,0 @@ -import ckan.plugins.toolkit as toolkit -import ckan.logic as logic -from ckanext.activity.email_notifications import send_notification -import ckanext.dataset_subscriptions.helpers as helpers -import ckanext.activity.email_notifications as email_notifications -import ckan.model as model -import ckan.lib.base as base -from ckan.common import config -import unihandecode - - -@toolkit.chained_action -@toolkit.side_effect_free -def send_email_notifications(original_action, context, data_dict): - email_notifications._notifications_functions = [dms_notification_provider] - email_notifications.send_notification = latin_username_send_notification - return original_action(context, data_dict) - - -def latin_username_send_notification(user, email_dict): - # fix for AWS SES not supporting UTF8 encoding of recepient field - # https://docs.aws.amazon.com/cli/latest/reference/ses/send-email.html - user['display_name'] = unihandecode.unidecode(user['display_name']) - return send_notification(user, email_dict) - - -def dms_notification_provider(user_dict, since): - if not user_dict.get('activity_streams_email_notifications'): - return [] - context = {'model': model, 'session': model.Session, - 'user': user_dict['id']} - activity_list = logic.get_action('dashboard_activity_list')(context, {}) - dataset_activity_list = [activity for activity in activity_list - if activity['user_id'] != user_dict['id'] - and 'package' in activity['activity_type']] - # We want a notification per changed dataset, not a list of all changes - timestamp_sorted_activity_list = sorted(dataset_activity_list, - key=lambda item: item['timestamp']) - deduplicated_activity_list = list({item["object_id"]: - item for item in timestamp_sorted_activity_list}.values()) - activity_list_with_dataset_name = helpers.add_dataset_details_to_activity_list(deduplicated_activity_list, context) - recent_activity_list = helpers.filter_out_old_activites(activity_list_with_dataset_name, since) - return dms_notifications_for_activities(recent_activity_list, user_dict) - - -def dms_notifications_for_activities(activities, user_dict): - if not activities: - return [] - if not user_dict.get('activity_streams_email_notifications'): - return [] - subject = toolkit.ungettext( - "{n} new notification from Department of HIV and AIDS Document Management System", - "{n} new notifications from Department of HIV and AIDS Document Management System", - len(activities)).format( - site_title=config.get('ckan.site_title'), - n=len(activities)) - body = base.render( - 'dataset-subscriptions_email_body.j2', - extra_vars={'activities': activities}) - notifications = [{ - 'subject': subject, - 'body': body - }] - return notifications diff --git a/ckanext/dataset_subscriptions/actions/email_notifications.py b/ckanext/dataset_subscriptions/actions/email_notifications.py new file mode 100644 index 0000000..29391dc --- /dev/null +++ b/ckanext/dataset_subscriptions/actions/email_notifications.py @@ -0,0 +1,57 @@ +import ckan.plugins.toolkit as toolkit +import ckanext.dataset_subscriptions.helpers as helpers +import ckanext.activity.email_notifications as email_notifications +import unihandecode + + +@toolkit.chained_action +@toolkit.side_effect_free +def send_email_notifications(original_action, context, data_dict): + email_notifications._notifications_functions = [dms_notification_provider] + email_notifications.send_notification = latin_username_send_notification + return original_action(context, data_dict) + + +def latin_username_send_notification(user, email_dict): + # fix for AWS SES not supporting UTF8 encoding of recepient field + # https://docs.aws.amazon.com/cli/latest/reference/ses/send-email.html + user['display_name'] = unihandecode.unidecode(user['display_name']) + return email_notifications.send_notification(user, email_dict) + + +def dms_notification_provider(user_dict, since): + if not user_dict.get('activity_streams_email_notifications'): + return [] + activity_list = toolkit.get_action('dashboard_activity_list')({'user': user_dict['id']}, {}) + dataset_activity_list = [activity for activity in activity_list + if activity['user_id'] != user_dict['id'] + and 'package' in activity['activity_type']] + # We want a notification per changed dataset, not a list of all changes + timestamp_sorted_activity_list = sorted(dataset_activity_list, + key=lambda item: item['timestamp']) + deduplicated_activity_list = list({item["object_id"]: + item for item in timestamp_sorted_activity_list}.values()) + activity_list_with_dataset_name = helpers.add_dataset_details_to_activity_list(deduplicated_activity_list) + recent_activity_list = helpers.filter_out_old_activites(activity_list_with_dataset_name, since) + return dms_notifications_for_activities(recent_activity_list, user_dict) + + +def dms_notifications_for_activities(activities, user_dict): + if not activities: + return [] + if not user_dict.get('activity_streams_email_notifications'): + return [] + subject = toolkit.ungettext( + "{n} new notification from {site_title}", + "{n} new notifications from {site_title}", + len(activities)).format( + site_title=toolkit.config.get('ckan.site_title'), + n=len(activities)) + body = toolkit.render( + 'dataset-subscriptions_email_body.j2', + extra_vars={'activities': activities}) + notifications = [{ + 'subject': subject, + 'body': body + }] + return notifications diff --git a/ckanext/dataset_subscriptions/actions/sms_notifications.py b/ckanext/dataset_subscriptions/actions/sms_notifications.py deleted file mode 100644 index 55c98b9..0000000 --- a/ckanext/dataset_subscriptions/actions/sms_notifications.py +++ /dev/null @@ -1,200 +0,0 @@ -import copy -import logging -from ckan.plugins import toolkit -import ckan.lib.base as base -import ckan.logic as logic -import ckan.model as model -from twilio.rest import Client -from twilio.base.exceptions import TwilioRestException -from datetime import timedelta, datetime -from ckanext.dataset_subscriptions import helpers -from ckan.common import request - - -logger = logging.getLogger(__name__) - - -ACCOUNT_SID = toolkit.config.get('ckanext.dataset_subscriptions.twilio_account_sid') -AUTH_TOKEN = toolkit.config.get('ckanext.dataset_subscriptions.twilio_auth_token') -SENDER_NR = toolkit.config.get('ckanext.dataset_subscriptions.sms_sender_nr') -client = Client(ACCOUNT_SID, AUTH_TOKEN) - - -CUSTOM_FIELDS = [ - {'name': 'phonenumber', 'default': ''}, - {'name': 'activity_streams_sms_notifications', 'default': False}, -] - -DATASET_SUBSCRIPTIONS = 'dataset_subscriptions' - - -@toolkit.chained_action -@toolkit.side_effect_free -def user_show(original_action, context, data_dict): - user = original_action(context, data_dict) - user_obj = _get_user_obj(context) - - plugin_extras = _init_plugin_extras(user_obj.plugin_extras) - dataset_subscriptions_extras = _validate_plugin_extras(plugin_extras[DATASET_SUBSCRIPTIONS]) - for field in CUSTOM_FIELDS: - user[field['name']] = dataset_subscriptions_extras[field['name']] - - return user - - -@toolkit.chained_action -def user_create(original_action, context, data_dict): - for field in CUSTOM_FIELDS: - if not field['name'] in data_dict: - data_dict[field['name']] = field['default'] - - user_dict = original_action(context, data_dict) - user_obj = _get_user_obj(context) - - plugin_extras = _init_plugin_extras(user_obj.plugin_extras) - dataset_subscriptions_extras = plugin_extras[DATASET_SUBSCRIPTIONS] - for field in CUSTOM_FIELDS: - dataset_subscriptions_extras[field['name']] = data_dict[field['name']] - user_obj.plugin_extras = plugin_extras - model_ = context.get('model', model) - model_.Session.commit() - - for field in CUSTOM_FIELDS: - user_dict[field['name']] = dataset_subscriptions_extras[field['name']] - return user_dict - - -@toolkit.chained_action -def user_update(original_action, context, data_dict): - for field in CUSTOM_FIELDS: - if not field['name'] in data_dict: - data_dict[field['name']] = field['default'] - - user_dict = original_action(context, data_dict) - user_obj = _get_user_obj(context) - - plugin_extras = _init_plugin_extras(user_obj.plugin_extras) - dataset_subscriptions_extras = plugin_extras[DATASET_SUBSCRIPTIONS] - for field in CUSTOM_FIELDS: - dataset_subscriptions_extras[field['name']] = data_dict[field['name']] - user_obj.plugin_extras = plugin_extras - model_ = context.get('model', model) - model_.Session.commit() - - for field in CUSTOM_FIELDS: - user_dict[field['name']] = dataset_subscriptions_extras[field['name']] - return user_dict - - -def _init_plugin_extras(plugin_extras): - out_dict = copy.deepcopy(plugin_extras) - if not out_dict: - out_dict = {} - if DATASET_SUBSCRIPTIONS not in out_dict: - out_dict[DATASET_SUBSCRIPTIONS] = {} - return out_dict - - -def _get_user_obj(context): - if 'user_obj' in context: - return context['user_obj'] - user = context.get('user') - model_ = context.get('model', model) - user_obj = model_.User.get(user) - if not user_obj: - raise toolkit.ObjectNotFound("User not found") - return user_obj - - -def _validate_plugin_extras(extras): - if not extras: - extras = {} - out_dict = {} - for field in CUSTOM_FIELDS: - out_dict[field['name']] = extras.get(field['name'], field['default']) - return out_dict - - -def sms_notifications_enabled(user_dict): - if user_dict.get("activity_streams_sms_notifications") and user_dict.get("phonenumber"): - return True - return False - - -def get_phonenumber(user_dict): - phonenumber = user_dict["phonenumber"] - return phonenumber - - -def send_sms_notifications(context, data_dict): - toolkit.check_access('send_email_notifications', context, data_dict) - context = {'model': model, 'session': model.Session, 'ignore_auth': True} - users = logic.get_action('user_list')(context, {'all_fields': True}) - notification_sids = [] - for user in users: - user = logic.get_action('user_show')(context, {'id': user['id'], - 'include_plugin_extras': False}) - if sms_notifications_enabled(user): - get_phonenumber(user) - notification_sids.append(prepare_sms_notifications(user)) - return notification_sids - - -def _sms_notification_time_delta_utc(): - since_hours = toolkit.config.get( - 'ckanext.dataset_subscriptions.sms_notifications_hours_since', 1) - since_delta = timedelta(hours=int(since_hours)) - since_datetime = (datetime.utcnow() - since_delta) - return since_datetime - - -def prepare_sms_notifications(user): - sms_notifications_since = _sms_notification_time_delta_utc() - activity_stream_last_viewed = ( - model.Dashboard.get(user['id']).activity_stream_last_viewed) - since = max(sms_notifications_since, activity_stream_last_viewed) - return dms_sms_notification_provider(user, since) - - -def dms_sms_notification_provider(user_dict, since): - context = {'model': model, 'session': model.Session, - 'user': user_dict['id']} - activity_list = logic.get_action('dashboard_activity_list')(context, {}) - dataset_activity_list = [activity for activity in activity_list - if activity['user_id'] != user_dict['id'] - and 'package' in activity['activity_type']] - # We want a notification per changed dataset, not a list of all changes - timestamp_sorted_activity_list = sorted(dataset_activity_list, - key=lambda item: item['timestamp']) - deduplicated_activity_list = list({item["object_id"]: - item for item in timestamp_sorted_activity_list}.values()) - activity_list_with_dataset_name = helpers.add_dataset_details_to_activity_list(deduplicated_activity_list, context) - recent_activity_list = helpers.filter_out_old_activites(activity_list_with_dataset_name, since) - if recent_activity_list: - user_phonenumber = get_phonenumber(user_dict) - return send_sms_notification(recent_activity_list, user_phonenumber) - - -def send_sms_notification(activities, phonenumber): - from_nr = SENDER_NR - to_nr = phonenumber - nr_of_datasets_to_display = toolkit.config.get('ckanext.dataset_subscriptions.sms_nr_of_datasets_to_display', 2) - header = toolkit.ungettext( - "{n} dataset have recently been updated in {site_title}", - "{n} datasets have recently been updated in {site_title}", - len(activities)).format( - site_title=toolkit.config.get('ckan.site_title'), - n=len(activities)) - message_body = base.render( - 'dataset-subscriptions_sms_body.j2', - extra_vars={'activities': activities, 'header': header, 'nr_of_datasets_to_display': nr_of_datasets_to_display}) - try: - message = client.messages.create( - from_=from_nr, - body=message_body, - to=to_nr - ) - except TwilioRestException: - logger.exception("Failed to send sms message", exc_info=True) - return - return message.sid diff --git a/ckanext/dataset_subscriptions/actions/summary_notifications.py b/ckanext/dataset_subscriptions/actions/summary_notifications.py new file mode 100644 index 0000000..ad74c34 --- /dev/null +++ b/ckanext/dataset_subscriptions/actions/summary_notifications.py @@ -0,0 +1,110 @@ +import logging +from ckan.plugins import toolkit +from twilio.rest import Client +from twilio.base.exceptions import TwilioRestException +from datetime import timedelta, datetime, timezone +from ckanext.dataset_subscriptions import helpers + + +ACCOUNT_SID = toolkit.config.get('ckanext.dataset_subscriptions.twilio_account_sid') +AUTH_TOKEN = toolkit.config.get('ckanext.dataset_subscriptions.twilio_auth_token') +SENDER_NR = toolkit.config.get('ckanext.dataset_subscriptions.sms_sender_nr') + + +client = Client(ACCOUNT_SID, AUTH_TOKEN) +logger = logging.getLogger(__name__) + + +def send_summary_notifications(context, data_dict): + message_sids = [] + toolkit.check_access('send_email_notifications', context, data_dict) + users = toolkit.get_action('user_list')({'ignore_auth': True}, {'all_fields': True}) + for user in users: + if _summary_notifications_enabled(user): + recent_activities = _get_recent_activity_list(user, context) + if recent_activities: + message_body = _create_message(recent_activities) + if _sms_notifications_enabled(user): + message_sids.append(_send_sms_message(message_body, user['phonenumber'])) + if _whatsapp_notifications_enabled(user): + message_sids.append(_send_whatsapp_message(message_body, user['phonenumber'])) + return message_sids + + +def _sms_notifications_enabled(user_dict): + if user_dict.get("activity_streams_sms_notifications") and user_dict.get("phonenumber"): + return True + return False + + +def _whatsapp_notifications_enabled(user_dict): + if user_dict.get("activity_streams_whatsapp_notifications") and user_dict.get("phonenumber"): + return True + return False + + +def _summary_notifications_enabled(user_dict): + if _sms_notifications_enabled(user_dict) or _whatsapp_notifications_enabled(user_dict): + return True + return False + + +def _summary_notification_time_delta_utc(): + since_hours = toolkit.config.get('ckanext.dataset_subscriptions.sms_notifications_hours_since', 1) + since_delta = timedelta(hours=int(since_hours)) + since_datetime = (datetime.now(timezone.utc) - since_delta) + return since_datetime + + +def _get_recent_activity_list(user_dict, context): + # Only raise notifications for activities since last message, or last view of the dashboard + dashboard_last_viewed = (context['model'].Dashboard.get(user_dict['id']).activity_stream_last_viewed) + since = max(_summary_notification_time_delta_utc(), dashboard_last_viewed) + # Get activities for only changes to datasets, within the desired period, not made by notifiee + activity_list = toolkit.get_action('dashboard_activity_list')({'user': user_dict['id']}, {}) + dataset_activity_list = [activity for activity in activity_list + if activity['user_id'] != user_dict['id'] + and 'package' in activity['activity_type']] + # We want the latest notification per changed dataset, not all changes + timestamp_sorted_activity_list = sorted(dataset_activity_list, key=lambda item: item['timestamp']) + deduplicated_activity_list = list({ + item["object_id"]: item for item in timestamp_sorted_activity_list + }.values()) + activity_list_with_dataset_name = helpers.add_dataset_details_to_activity_list(deduplicated_activity_list) + recent_activity_list = helpers.filter_out_old_activites(activity_list_with_dataset_name, since) + return recent_activity_list + + +def _create_message(activities): + nr_of_datasets_to_display = toolkit.config.get('ckanext.dataset_subscriptions.sms_nr_of_datasets_to_display', 2) + header = toolkit.ungettext( + "{n} dataset have recently been updated in {site_title}", + "{n} datasets have recently been updated in {site_title}", + len(activities)).format( + site_title=toolkit.config.get('ckan.site_title'), + n=len(activities)) + return toolkit.render( + 'dataset-subscriptions_sms_body.j2', + extra_vars={ + 'activities': activities, + 'header': header, + 'nr_of_datasets_to_display': nr_of_datasets_to_display + } + ) + + +def _send_sms_message(message_body, phonenumber): + try: + message = client.messages.create( + from_=SENDER_NR, + body=message_body, + to=phonenumber + ) + except TwilioRestException: + logger.exception(f"Failed to send sms message to {phonenumber}", exc_info=True) + return + return message.sid + + +def _send_whatsapp_message(message_body, phonenumber): + return f"whatsapp-message-sid-{phonenumber}" diff --git a/ckanext/dataset_subscriptions/actions/user.py b/ckanext/dataset_subscriptions/actions/user.py new file mode 100644 index 0000000..f4a6b1f --- /dev/null +++ b/ckanext/dataset_subscriptions/actions/user.py @@ -0,0 +1,115 @@ +import copy +import logging +from ckan.plugins import toolkit +import ckan.model as model + + +logger = logging.getLogger(__name__) + + +CUSTOM_FIELDS = [ + {'name': 'phonenumber', 'default': ''}, + {'name': 'activity_streams_sms_notifications', 'default': False}, + {'name': 'activity_streams_whatsapp_notifications', 'default': False}, +] + +DATASET_SUBSCRIPTIONS = 'dataset_subscriptions' + + +@toolkit.chained_action +@toolkit.side_effect_free +def user_show(original_action, context, data_dict): + user = original_action(context, data_dict) + user_obj = _get_user_obj(context) + + plugin_extras = _init_plugin_extras(user_obj.plugin_extras) + dataset_subscriptions_extras = _validate_plugin_extras(plugin_extras[DATASET_SUBSCRIPTIONS]) + for field in CUSTOM_FIELDS: + user[field['name']] = dataset_subscriptions_extras[field['name']] + + return user + + +@toolkit.chained_action +def user_create(original_action, context, data_dict): + for field in CUSTOM_FIELDS: + if not field['name'] in data_dict: + data_dict[field['name']] = field['default'] + + user_dict = original_action(context, data_dict) + user_obj = _get_user_obj(context) + + plugin_extras = _init_plugin_extras(user_obj.plugin_extras) + dataset_subscriptions_extras = plugin_extras[DATASET_SUBSCRIPTIONS] + for field in CUSTOM_FIELDS: + dataset_subscriptions_extras[field['name']] = data_dict[field['name']] + user_obj.plugin_extras = plugin_extras + model_ = context.get('model', model) + model_.Session.commit() + + for field in CUSTOM_FIELDS: + user_dict[field['name']] = dataset_subscriptions_extras[field['name']] + return user_dict + + +@toolkit.chained_action +def user_update(original_action, context, data_dict): + for field in CUSTOM_FIELDS: + if not field['name'] in data_dict: + data_dict[field['name']] = field['default'] + + user_dict = original_action(context, data_dict) + user_obj = _get_user_obj(context) + + plugin_extras = _init_plugin_extras(user_obj.plugin_extras) + dataset_subscriptions_extras = plugin_extras[DATASET_SUBSCRIPTIONS] + for field in CUSTOM_FIELDS: + dataset_subscriptions_extras[field['name']] = data_dict[field['name']] + user_obj.plugin_extras = plugin_extras + model_ = context.get('model', model) + model_.Session.commit() + + for field in CUSTOM_FIELDS: + user_dict[field['name']] = dataset_subscriptions_extras[field['name']] + return user_dict + + +@toolkit.chained_action +@toolkit.side_effect_free +def user_list(original_action, context, data_dict): + user_list = original_action(context, data_dict) + include_plugin_extras = all_fields = toolkit.asbool(data_dict.get('include_plugin_extras', False)) + all_fields = toolkit.asbool(data_dict.get('all_fields', True)) + if all_fields and include_plugin_extras: + for user in user_list: + user = toolkit.get_action('user_show')(context, {'id': user['name']}) + return user_list + + +def _init_plugin_extras(plugin_extras): + out_dict = copy.deepcopy(plugin_extras) + if not out_dict: + out_dict = {} + if DATASET_SUBSCRIPTIONS not in out_dict: + out_dict[DATASET_SUBSCRIPTIONS] = {} + return out_dict + + +def _get_user_obj(context): + if 'user_obj' in context: + return context['user_obj'] + user = context.get('user') + model_ = context.get('model', model) + user_obj = model_.User.get(user) + if not user_obj: + raise toolkit.ObjectNotFound("User not found") + return user_obj + + +def _validate_plugin_extras(extras): + if not extras: + extras = {} + out_dict = {} + for field in CUSTOM_FIELDS: + out_dict[field['name']] = extras.get(field['name'], field['default']) + return out_dict diff --git a/ckanext/dataset_subscriptions/helpers.py b/ckanext/dataset_subscriptions/helpers.py index 3497572..1d1c519 100644 --- a/ckanext/dataset_subscriptions/helpers.py +++ b/ckanext/dataset_subscriptions/helpers.py @@ -6,11 +6,11 @@ logger = logging.getLogger(__name__) -def add_dataset_details_to_activity_list(activity_list, context): +def add_dataset_details_to_activity_list(activity_list): for index, activity in enumerate(activity_list): object_id = activity['object_id'] try: - dataset = toolkit.get_action('package_show')(context, {'id': object_id}) + dataset = toolkit.get_action('package_show')({}, {'id': object_id}) except Exception: logger.exception(f"Unable to get details of package: {object_id}") return [] diff --git a/ckanext/dataset_subscriptions/plugin.py b/ckanext/dataset_subscriptions/plugin.py index fbdb4f8..d7374f4 100644 --- a/ckanext/dataset_subscriptions/plugin.py +++ b/ckanext/dataset_subscriptions/plugin.py @@ -1,7 +1,6 @@ import ckan.plugins as plugins import ckan.plugins.toolkit as toolkit -from ckanext.dataset_subscriptions import actions -from ckanext.dataset_subscriptions.actions import sms_notifications +from ckanext.dataset_subscriptions.actions import summary_notifications, email_notifications, user class DatasetSubscriptionsPlugin(plugins.SingletonPlugin): @@ -17,9 +16,10 @@ def update_config(self, config_): # IActions def get_actions(self): return { - 'send_email_notifications': actions.send_email_notifications, - 'send_sms_notifications': sms_notifications.send_sms_notifications, - 'user_create': sms_notifications.user_create, - 'user_update': sms_notifications.user_update, - 'user_show': sms_notifications.user_show + 'send_email_notifications': email_notifications.send_email_notifications, + 'send_sms_notifications': summary_notifications.send_summary_notifications, + 'user_create': user.user_create, + 'user_update': user.user_update, + 'user_show': user.user_show, + 'user_list': user.user_list } diff --git a/ckanext/dataset_subscriptions/tests/test_actions.py b/ckanext/dataset_subscriptions/tests/actions/test_email_notifications.py similarity index 100% rename from ckanext/dataset_subscriptions/tests/test_actions.py rename to ckanext/dataset_subscriptions/tests/actions/test_email_notifications.py diff --git a/ckanext/dataset_subscriptions/tests/actions/test_sms_notifications.py b/ckanext/dataset_subscriptions/tests/actions/test_sms_notifications.py index 849ebdf..370f3c4 100644 --- a/ckanext/dataset_subscriptions/tests/actions/test_sms_notifications.py +++ b/ckanext/dataset_subscriptions/tests/actions/test_sms_notifications.py @@ -2,45 +2,10 @@ from ckan.tests import helpers from ckan.tests import factories as ckan_factories from ckanext.dataset_subscriptions.tests import factories -from ckanext.dataset_subscriptions.actions import sms_notifications +from ckanext.dataset_subscriptions.actions import summary_notifications from unittest import mock -@pytest.mark.usefixtures("clean_db") -@pytest.mark.usefixtures("with_plugins") -def test_user_create_supports_plugin_extras(sysadmin_context): - user_dict = { - "name": "test_user_001", - "fullname": "Mr. Test User", - "password": "fjelltopp", - "display_name": "Mr. Test User", - "email": "test_user_001@ckan.org", - "phonenumber": 123, - "activity_streams_sms_notifications": True - } - - created_user = helpers.call_action('user_create', context=sysadmin_context, **user_dict) - - for key in ["phonenumber", "activity_streams_sms_notifications"]: - assert created_user[key] == user_dict[key] - - -@pytest.mark.usefixtures("clean_db") -@pytest.mark.usefixtures("with_plugins") -def test_user_update_supports_plugin_extras(sysadmin_context): - user = factories.User() - user_dict = {**user, **{ - "phonenumber": 123, - "activity_streams_sms_notifications": True - } - } - helpers.call_action('user_update', **user_dict) - updated_user = helpers.call_action('user_show', context=sysadmin_context, include_plugin_extras=True, **user_dict) - - for key in ["phonenumber", "activity_streams_sms_notifications"]: - assert updated_user[key] == user_dict[key] - - @pytest.fixture def sysadmin_context(): sysadmin = ckan_factories.Sysadmin() @@ -52,11 +17,7 @@ def sysadmin_context(): @pytest.mark.ckan_config('ckan.plugins') @pytest.mark.usefixtures("with_plugins") @pytest.mark.usefixtures("clean_db") -def create_user_with_resources(with_activity, with_notifications_enabled): - if with_notifications_enabled: - notifications_enabled = True - else: - notifications_enabled = False +def create_user_with_resources(with_activity, notifications_enabled): subscribed_user = factories.User(name='user1', activity_streams_sms_notifications=notifications_enabled, phonenumber="+1234") @@ -84,21 +45,12 @@ def create_user_with_resources(with_activity, with_notifications_enabled): return subscribed_user -@pytest.mark.usefixtures("clean_db") -@pytest.mark.usefixtures("with_plugins") -@pytest.mark.parametrize("notifications_enabled", [(False), (True)]) -def test_get_phonenumber(notifications_enabled): - user = create_user_with_resources(with_activity=True, with_notifications_enabled=notifications_enabled) - phonenumber = sms_notifications.get_phonenumber(user) - assert phonenumber == "+1234" - - @pytest.mark.usefixtures("clean_db") @pytest.mark.usefixtures("with_plugins") @pytest.mark.parametrize("notifications_enabled", [(False), (True)]) def test_sms_notifications_disabled_enabled(notifications_enabled): - user = create_user_with_resources(with_activity=True, with_notifications_enabled=notifications_enabled) - notifications = sms_notifications.sms_notifications_enabled(user) + user = create_user_with_resources(True, notifications_enabled) + notifications = summary_notifications._sms_notifications_enabled(user) assert notifications == notifications_enabled diff --git a/ckanext/dataset_subscriptions/tests/actions/test_user.py b/ckanext/dataset_subscriptions/tests/actions/test_user.py new file mode 100644 index 0000000..d2ffa49 --- /dev/null +++ b/ckanext/dataset_subscriptions/tests/actions/test_user.py @@ -0,0 +1,38 @@ +import pytest +from ckan.tests import helpers +from ckan.tests import factories + + +@pytest.mark.usefixtures("clean_db") +@pytest.mark.usefixtures("with_plugins") +def test_user_create_supports_plugin_extras(sysadmin_context): + user_dict = { + "name": "test_user_001", + "fullname": "Mr. Test User", + "password": "fjelltopp", + "display_name": "Mr. Test User", + "email": "test_user_001@ckan.org", + "phonenumber": 123, + "activity_streams_sms_notifications": True + } + + created_user = helpers.call_action('user_create', context=sysadmin_context, **user_dict) + + for key in ["phonenumber", "activity_streams_sms_notifications"]: + assert created_user[key] == user_dict[key] + + +@pytest.mark.usefixtures("clean_db") +@pytest.mark.usefixtures("with_plugins") +def test_user_update_supports_plugin_extras(sysadmin_context): + user = factories.User() + user_dict = {**user, **{ + "phonenumber": 123, + "activity_streams_sms_notifications": True + } + } + helpers.call_action('user_update', **user_dict) + updated_user = helpers.call_action('user_show', context=sysadmin_context, include_plugin_extras=True, **user_dict) + + for key in ["phonenumber", "activity_streams_sms_notifications"]: + assert updated_user[key] == user_dict[key]