diff --git a/lib/registries/addon/branded/moderation/-components/upload-csv/template.hbs b/lib/registries/addon/branded/moderation/-components/upload-csv/template.hbs
index f13fc24c63d..783fd3fc5d7 100644
--- a/lib/registries/addon/branded/moderation/-components/upload-csv/template.hbs
+++ b/lib/registries/addon/branded/moderation/-components/upload-csv/template.hbs
@@ -16,6 +16,7 @@
@clickable={{array
(concat '.' (local-class 'upload-zone'))
}}
+ data-test-bulk-upload-widget
>
@@ -36,22 +37,22 @@
@onClose={{this.closeErrorModal}}
as |dialog|
>
-
+
{{t 'registries.moderation.settings.uploadError'}}
-
-
+
+
{{t 'registries.moderation.settings.generalErrorMessage' htmlSafe=true}}
-
+
{{#each this.errorMessages as |msg|}}
{{#if msg.cell}}
-
- {{t 'registries.moderation.settings.cell'}} {{msg.cell}}
+ - {{t 'registries.moderation.settings.cell'}} {{msg.cell}}
{{/if}}
- - {{msg.title}}
- - {{msg.detail}}
+ - {{msg.title}}
+ - {{msg.detail}}
{{/each}}
diff --git a/lib/registries/addon/branded/moderation/settings/controller.ts b/lib/registries/addon/branded/moderation/settings/controller.ts
index 774543b425d..de05ff74cd2 100644
--- a/lib/registries/addon/branded/moderation/settings/controller.ts
+++ b/lib/registries/addon/branded/moderation/settings/controller.ts
@@ -3,11 +3,16 @@ import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import config from 'ember-get-config';
import pathJoin from 'ember-osf-web/utils/path-join';
+import { ReviewPermissions } from 'ember-osf-web/models/provider';
export default class BrandedModerationSettingsController extends Controller {
userSettingsLink = pathJoin(config.OSF.url, 'settings', 'notifications');
@alias('model.id') providerId?: string;
+ get shouldShowBulkUploadWidget() {
+ return this.model.permissions.includes(ReviewPermissions.AddModerator);
+ }
+
@computed('providerId')
get subscriptionIds() {
return this.providerId
diff --git a/lib/registries/addon/branded/moderation/settings/template.hbs b/lib/registries/addon/branded/moderation/settings/template.hbs
index 77b64da7b73..91e47e7ba53 100644
--- a/lib/registries/addon/branded/moderation/settings/template.hbs
+++ b/lib/registries/addon/branded/moderation/settings/template.hbs
@@ -16,10 +16,12 @@
/>
-
- {{t 'registries.moderation.settings.bulkUpload'}}
-
-
- {{t 'registries.moderation.settings.bulkUploadHelpText'}}
-
-
\ No newline at end of file
+{{#if this.shouldShowBulkUploadWidget}}
+
+ {{t 'registries.moderation.settings.bulkUpload'}}
+
+
+ {{t 'registries.moderation.settings.bulkUploadHelpText'}}
+
+
+{{/if}}
\ No newline at end of file
diff --git a/tests/engines/registries/acceptance/branded/moderation/settings-test.ts b/tests/engines/registries/acceptance/branded/moderation/settings-test.ts
index 8cfe97b5b93..9dbd9724746 100644
--- a/tests/engines/registries/acceptance/branded/moderation/settings-test.ts
+++ b/tests/engines/registries/acceptance/branded/moderation/settings-test.ts
@@ -4,8 +4,11 @@ import { percySnapshot } from 'ember-percy';
import { module, test } from 'qunit';
import { SubscriptionFrequency } from 'ember-osf-web/models/subscription';
-import { visit } from 'ember-osf-web/tests/helpers';
+import { click, visit } from 'ember-osf-web/tests/helpers';
import { setupEngineApplicationTest } from 'ember-osf-web/tests/helpers/engines';
+import { triggerEvent, settled } from '@ember/test-helpers';
+import { t } from 'ember-intl/test-support';
+import stripHtmlTags from 'ember-osf-web/utils/strip-html-tags';
module('Registries | Acceptance | branded.moderation | settings', hooks => {
setupEngineApplicationTest(hooks, 'registries');
@@ -41,13 +44,13 @@ module('Registries | Acceptance | branded.moderation | settings', hooks => {
assert.equal(currentRouteName(), 'registries.page-not-found', 'Non-moderators are rerouted');
});
- test('notifications list for moderators', async assert => {
+ test('notifications list shows for moderators, but not bulk upload widget', async assert => {
const regProvider = server.schema.registrationProviders.find('mdr8n');
const currentUser = server.create('user', 'loggedIn');
server.create('moderator', { id: currentUser.id, user: currentUser, provider: regProvider }, 'asModerator');
regProvider.update({ permissions: ['view_submissions'] });
await visit('/registries/mdr8n/moderation/settings');
- await percySnapshot('moderation settings page');
+ await percySnapshot('moderation settings page for moderators');
assert.equal(currentRouteName(), 'registries.branded.moderation.settings',
'On the settings page of registries reviews');
assert.dom('[data-test-subscription-list]').exists('Subscription list shown');
@@ -59,5 +62,158 @@ module('Registries | Acceptance | branded.moderation | settings', hooks => {
.doesNotExist('Other subscriptions are not shown');
assert.dom('[data-test-subscription-list-row="mdr8n_new_pending_withdraw_requests"] [data-test-power-select]')
.hasText('Instant', 'Subscription frequency is shown correctly');
+ assert.dom('[data-test-bulk-upload-widget]').doesNotExist();
+ });
+
+ test('notifications list and bulk upload widget shows for admins', async assert => {
+ const regProvider = server.schema.registrationProviders.find('mdr8n');
+ const currentUser = server.create('user', 'loggedIn');
+ server.create('moderator', { id: currentUser.id, user: currentUser, provider: regProvider }, 'asModerator');
+ regProvider.update({ permissions: ['view_submissions', 'add_moderator'] });
+ await visit('/registries/mdr8n/moderation/settings');
+ await percySnapshot('moderation settings page for admins');
+ assert.equal(currentRouteName(), 'registries.branded.moderation.settings',
+ 'On the settings page of registries reviews');
+ assert.dom('[data-test-subscription-list]').exists('Subscription list shown');
+ assert.dom('[data-test-subscription-list-row="mdr8n_new_pending_submissions"]')
+ .exists('Pending submissions notification shown');
+ assert.dom('[data-test-subscription-list-row="mdr8n_new_pending_withdraw_requests"]')
+ .exists('Pending withdraw requests notification shown');
+ assert.dom('[data-test-subscription-list-row="cat_photo_repository_subscription"]')
+ .doesNotExist('Other subscriptions are not shown');
+ assert.dom('[data-test-subscription-list-row="mdr8n_new_pending_withdraw_requests"] [data-test-power-select]')
+ .hasText('Instant', 'Subscription frequency is shown correctly');
+ assert.dom('[data-test-bulk-upload-widget]').exists();
+ });
+
+ test('test bulk upload widget', async assert => {
+ const filename = 'itzy.csv';
+ const triggerFileUpload = () => triggerEvent(
+ '[data-test-bulk-upload-widget]',
+ 'drop',
+ {
+ dataTransfer: {
+ files: [new File(['Loco!'], filename)],
+ },
+ },
+ );
+ const regProvider = server.schema.registrationProviders.find('mdr8n');
+ const currentUser = server.create('user', 'loggedIn');
+ server.create('moderator', { id: currentUser.id, user: currentUser, provider: regProvider }, 'asModerator');
+ regProvider.update({ permissions: ['view_submissions', 'add_moderator'] });
+ await visit('/registries/mdr8n/moderation/settings');
+ assert.dom('[data-test-bulk-upload-widget]').exists();
+ server.namespace = '/_';
+
+ // upload successful
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({}), 204);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('#toast-container', document as unknown as Element).hasTextContaining(
+ t('registries.moderation.settings.uploadSuccess'),
+ 'Toast message shows and contains success msg',
+ );
+
+ // invalid schema id
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({
+ errors: [{ type: 'invalidSchemaId'}],
+ }), 400);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('[data-test-error-modal-heading]').hasText(t('registries.moderation.settings.uploadError'));
+ assert.dom('[data-test-error-modal-general-message]').
+ hasText(stripHtmlTags(t('registries.moderation.settings.generalErrorMessage')));
+ assert.dom('[data-test-error-modal-message-title]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-title]')
+ .hasText(t('registries.moderation.settings.invalidSchemaId.title'));
+ assert.dom('[data-test-error-modal-message-detail]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-detail]')
+ .hasText(t('registries.moderation.settings.invalidSchemaId.detail'));
+ await click('[data-test-close-dialog]');
+
+ // invalid column id
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({
+ errors: [{ type: 'invalidColumnId'}],
+ }), 400);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('[data-test-error-modal-message-title]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-title]')
+ .hasText(t('registries.moderation.settings.invalidColumnId.title'));
+ assert.dom('[data-test-error-modal-message-detail]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-detail]')
+ .hasText(t('registries.moderation.settings.invalidColumnId.detail'));
+ await click('[data-test-close-dialog]');
+
+ // size exceeds limit
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({
+ errors: [{ type: 'sizeExceedsLimit'}],
+ }), 400);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('[data-test-error-modal-message-title]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-title]')
+ .hasText(t('registries.moderation.settings.sizeExceedsLimit.title'));
+ assert.dom('[data-test-error-modal-message-detail]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-detail]')
+ .hasText(stripHtmlTags(t('registries.moderation.settings.sizeExceedsLimit.detail')));
+ await click('[data-test-close-dialog]');
+
+ // bulk upload job exists
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({
+ errors: [{ type: 'bulkUploadJobExists'}],
+ }), 400);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('[data-test-error-modal-message-title]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-title]')
+ .hasText(t('registries.moderation.settings.bulkUploadJobExists.title'));
+ assert.dom('[data-test-error-modal-message-detail]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-detail]')
+ .hasText(t('registries.moderation.settings.bulkUploadJobExists.detail'));
+ await click('[data-test-close-dialog]');
+
+ // invalid file type
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({
+ errors: [{ type: 'invalidFileType'}],
+ }), 400);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('[data-test-error-modal-message-title]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-title]')
+ .hasText(t('registries.moderation.settings.invalidFileType.title'));
+ assert.dom('[data-test-error-modal-message-detail]').exists({ count: 1 });
+ assert.dom('[data-test-error-modal-message-detail]')
+ .hasText(stripHtmlTags(t('registries.moderation.settings.invalidFileType.detail')));
+ await click('[data-test-close-dialog]');
+
+ // invalid cells
+ const errors = [
+ { type: 'invalidProjectId', row_index: 52, column_index: 'B' },
+ { type: 'invalidInstitutionName', row_index: 52, column_index: 'B' },
+ { type: 'invalidLicenseName', row_index: 52, column_index: 'B' },
+ { type: 'invalidSubjectName', row_index: 52, column_index: 'B' },
+ { type: 'invalidCategoryName', row_index: 52, column_index: 'B' },
+ { type: 'invalidResponse', row_index: 52, column_index: 'B' },
+ { type: 'invalidContributors', row_index: 52, column_index: 'B' },
+ ];
+ server.put(`/registries/mdr8n/bulk_create/${filename}`, () => ({
+ errors,
+ }), 400);
+ await triggerFileUpload();
+ await settled();
+ assert.dom('[data-test-error-modal-cell-identifier]').exists({ count: 7 });
+ const cellIdElements = document.querySelectorAll('[data-test-error-modal-cell-identifier]');
+ cellIdElements.forEach(element => assert.equal(element.textContent, 'Cell B52'));
+ assert.dom('[data-test-error-modal-message-title]').exists({ count: 7 });
+ const msgTitleElements = document.querySelectorAll('[data-test-error-modal-message-title]');
+ msgTitleElements.forEach((element, index) => assert.equal(
+ element.textContent, t(`registries.moderation.settings.${errors[index].type}.title`),
+ ));
+ assert.dom('[data-test-error-modal-message-detail]').exists({ count: 7 });
+ const msgDetailElements = document.querySelectorAll('[data-test-error-modal-message-detail]');
+ msgDetailElements.forEach((element, index) => assert.equal(
+ element.textContent, stripHtmlTags(t(`registries.moderation.settings.${errors[index].type}.detail`)),
+ ));
});
});