diff --git a/.gitignore b/.gitignore index d009c69af..200fd22e7 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,7 @@ src/styles/css .vagrant -src/discovery.vars.js +src/config/discovery.vars.js grunt/requirejs.js .* !.babelrc diff --git a/src/config/discovery.vars.js b/src/config/discovery.vars.js deleted file mode 100644 index 386622fb1..000000000 --- a/src/config/discovery.vars.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Main App Variables - */ -define({ - clientVersion: '', - apiRoot: 'https://api.adsabs.harvard.edu/v1/', - orcidProxy: '/oauth/', - bootstrapUrls: ['/accounts/bootstrap'], - routerConf: { - pushState: true, - root: '/', - }, - debugExportBBB: true, - debug: false, - useCache: false, - googleTrackingCode: 'UA-37369750-7', - googleTrackingOptions: 'auto', - orcidClientId: 'APP-P5ANJTQRRTMA6GXZ', - orcidLoginEndpoint: 'https://sandbox.orcid.org/oauth/authorize', - orcidApiEndpoint: 'https://api.adsabs.harvard.edu/v1/orcid', - recaptchaKey: "6LcvRD8UAAAAAKcEK0rYJUwf0bsF6GHo4EG36wo5", - hourly: false -}); diff --git a/src/js/components/api_targets.js b/src/js/components/api_targets.js index ab6a4657a..4e6fcec82 100644 --- a/src/js/components/api_targets.js +++ b/src/js/components/api_targets.js @@ -72,6 +72,7 @@ function ( // can get info about all libraries, or list of bibcodes associated w/specific lib (libraries/id) // post to /libraries/ to create a library LIBRARIES: 'biblib/libraries', + LIBRARY_TRANSFER: 'biblib/transfer', // can post, put, and delete changes to individual libs using this endpoint DOCUMENTS: 'biblib/documents', PERMISSIONS: 'biblib/permissions', diff --git a/src/js/components/library_controller.js b/src/js/components/library_controller.js index 1640656bb..00aa7d798 100644 --- a/src/js/components/library_controller.js +++ b/src/js/components/library_controller.js @@ -445,6 +445,18 @@ function ( return this.composeRequest(endpoint, 'POST', { data: data }); }, + transferOwnership: function (libId, newOwnerEmail) { + if (!newOwnerEmail || !_.isString(newOwnerEmail)) { + throw 'new owner email address must be a string'; + } + if (!libId || !_.isString(libId)) { + throw 'library Id must be a string'; + } + const endpoint = ApiTargets.LIBRARY_TRANSFER + '/' + libId; + const data = { email: newOwnerEmail }; + return this.composeRequest(endpoint, 'POST', { data }); + }, + // /* // * email, permission, value @@ -571,6 +583,7 @@ function ( updateLibraryMetadata: 'updateLibraryMetadata', importLibraries: 'importLibraries', + transferOwnership: 'transferOwnership', // currently called by library individual widget to get // lists of bibs to pass to export, metrics, vis widgets etc diff --git a/src/js/widgets/library_individual/templates/make-public.html b/src/js/widgets/library_individual/templates/make-public.html index 54a88ca21..bdf9ae624 100644 --- a/src/js/widgets/library_individual/templates/make-public.html +++ b/src/js/widgets/library_individual/templates/make-public.html @@ -1,34 +1,53 @@ - - - {{#if public}} - -

This Library is Public

- -
- -

Public libraries are available for all to read.

-

Private libraries are visible to only you and any collaborators.

- -

The public address of this library is https://ui.adsabs.harvard.edu/public-libraries/{{id}}

-

- +
+ {{#if public}} +
+
+

This Library is Public

- - {{else}} - -

This Library is Private

- -
- -

Public libraries are available for all to read.

-

Private libraries are visible to only you and any collaborators.

- -

- -

+
+
+
+
+
+

Public libraries are available for all to read.

+

Private libraries are visible to only you and any collaborators.

+

The public address of this library is https://ui.adsabs.harvard.edu/public-libraries/{{id}} +

+
+ + +
+
+
- - {{/if}} - - +
+ {{else}} +
+
+

This Library is Private

+
+
+
+
+
+
+

Public libraries are available for all to read.

+

Private libraries are visible to only you and any collaborators.

+

The public address of this library is https://ui.adsabs.harvard.edu/public-libraries/{{id}} +

+
+ + +
+
+
+
+
+ {{/if}}
diff --git a/src/js/widgets/library_individual/templates/transfer-ownership-modal.html b/src/js/widgets/library_individual/templates/transfer-ownership-modal.html new file mode 100644 index 000000000..ff43f6ea3 --- /dev/null +++ b/src/js/widgets/library_individual/templates/transfer-ownership-modal.html @@ -0,0 +1,47 @@ + diff --git a/src/js/widgets/library_individual/views/manage_permissions.js b/src/js/widgets/library_individual/views/manage_permissions.js index 0c264e8a7..ce3b6452a 100644 --- a/src/js/widgets/library_individual/views/manage_permissions.js +++ b/src/js/widgets/library_individual/views/manage_permissions.js @@ -1,58 +1,143 @@ -define([ - 'marionette', +define(['marionette', 'hbs!js/widgets/library_individual/templates/manage-permissions-container', 'hbs!js/widgets/library_individual/templates/make-public', - 'bootstrap' -], function ( - Marionette, - ManagePermissionsContainer, - MakePublicTemplate, - Bootstrap -) { - var PermissionsModel = Backbone.Model.extend({ - - }); - + 'hbs!../templates/transfer-ownership-modal' +], function (Marionette, ManagePermissionsContainer, MakePublicTemplate, transferOwnershipModal) { + var PermissionsModel = Backbone.Model.extend({}); var PermissionsCollection = Backbone.Collection.extend({ - model: PermissionsModel - }); + const TransferOwnershipModalView = Backbone.View.extend({ + initialize() { + this.render = _.debounce(this.render, 500); + this.onConfirm = _.debounce(this.onConfirm, 1000); + this.model = new (Backbone.Model.extend({ + defaults: { + error: false, + loading: false + } + })); + const container = document.createElement('div'); + document.body.appendChild(container); + this.setElement(container); + this.model.on('change:error', () => { this.showErrorMessage(); }); + this.model.on('change:loading', () => { this.showLoading(); }); + this.model.on('change:success', () => { this.showSuccessMessage(); }); + }, + showErrorMessage() { + const error = this.model.get('error'); + const el = $('#error-message', this.el); + if (error && error.length > 0) { + el.fadeIn(); + $('span', el).text(error); + } else { + el.hide(); + } + }, + showSuccessMessage() { + const success = this.model.get('success'); + const el = $('#success-message', this.el); + if (success && success.length > 0) { + el.fadeIn(); + $('span', el).text(success); + } else { + el.hide(); + } + }, + showLoading() { + const loading = this.model.get('loading'); + const el = $('#loader', this.el); + loading ? el.show() : el.hide(); + }, + getModal() { + return $('#transferOwnershipModal', this.$el); + }, + render() { + this.$el.html(transferOwnershipModal(this.model.toJSON())); + this.getModal().off().on('show.bs.modal', () => { + this.model.clear().set(this.model.defaults); + }).on('shown.bs.modal', () => { + $('input', this.$el).focus(); + }); + }, + events: { + 'click .confirm-button': '_onConfirm', + 'submit form': '_onConfirm' + }, + getEmailAddress() { + return $('input', this.el).val(); + }, + _onConfirm(e) { + this.model.set({ + loading: true, + error: false + }); + + const msg = 'Are you sure?'; + if (confirm(msg)) { + this.onConfirm(e); + } else { + this.model.set({ + loading: false, + error: true + }); + } - var ManagePermissionsView = Marionette.ItemView.extend({ + }, + onConfirm(e) { + e.preventDefault(); + const email = this.getEmailAddress(); + this.trigger('confirm-transfer-ownership', email, { + done: () => { + this.model.set({ + success: `Success! Ownership has been transferred to ${ email }`, + loading: false + }); + setTimeout(() => { + this.getModal().modal('hide'); + this.trigger('reset-and-navigate'); + }, 2000); + }, + fail: ({ responseJSON }) => { + if (responseJSON && responseJSON.error) { + this.model.set({ + error: responseJSON.error, + loading: false + }); + } + } + }); + } + }); + var ManagePermissionsView = Marionette.ItemView.extend({ className: 'library-admin-view', - initialize: function (options) { var options = options || {}; - this.model.set('host', window.location.host); - }, + this.modal = new TransferOwnershipModalView(); + // just forward any trigger calls + this.modal.on('all', (...args) => this.trigger(...args)); + }, events: { 'click .public-button': 'togglePublicState' }, - togglePublicState: function (e) { var pub = $(e.target).hasClass('make-public'); this.trigger('update-public-status', pub); }, - modelEvents: { - 'change:public': 'render' - }, - template: ManagePermissionsContainer, - onRender: function () { - this.$('.public-container').html(MakePublicTemplate(this.model.toJSON())); - } + this.$('.public-container').html(MakePublicTemplate(this.model + .toJSON())); + this.modal.render(); + } }); - - return ManagePermissionsView; }); diff --git a/src/js/widgets/library_individual/widget.js b/src/js/widgets/library_individual/widget.js index 9c76d7fd6..d093b64d7 100644 --- a/src/js/widgets/library_individual/widget.js +++ b/src/js/widgets/library_individual/widget.js @@ -141,11 +141,13 @@ function ( handleAdminEvents: function (event, arg1, arg2) { var that = this; + const libController = this.getBeeHive().getObject('LibraryController'); + switch (event) { case 'update-public-status': var data = { 'public': arg1 }, id = this.model.get('id'); - this.getBeeHive().getObject('LibraryController') + libController .updateLibraryMetadata(id, data) .done(function (response, status) { // re-render the admin view @@ -154,6 +156,19 @@ function ( .fail(function () { }); break; + case 'confirm-transfer-ownership': + libController + .transferOwnership(this.model.get('id'), arg1) + .done(arg2.done) + .fail(arg2.fail); + break; + case 'reset-and-navigate': + const ps = this.getPubSub(); + + // invalidates the cache of entries so the list gets refreshed + ps.publish(ps.CUSTOM_EVENT, 'invalidate-library-metadata'); + ps.publish(ps.NAVIGATE, 'AllLibrariesWidget'); + break; } }, @@ -163,6 +178,8 @@ function ( pubsub = this.getBeeHive().getService('PubSub'), libController = this.getBeeHive().getObject('LibraryController'); + console.log('headerEvent', event); + switch (event) { case 'updateVal': // from header view diff --git a/test/mocha/js/components/library_controller.spec.js b/test/mocha/js/components/library_controller.spec.js index 0fb6cfb95..0df7d9ebf 100644 --- a/test/mocha/js/components/library_controller.spec.js +++ b/test/mocha/js/components/library_controller.spec.js @@ -46,6 +46,7 @@ define([ "updateLibraryContents", "updateLibraryMetadata", "importLibraries", + "transferOwnership", "getLibraryBibcodes", "performLibraryOperation", "__facade__",