cspace-ui
Version:
CollectionSpace user interface for browsers
370 lines (364 loc) • 12.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unrelateBidirectional = exports.unrelate = exports.showRelationNotification = exports.find = exports.deleteRelation = exports.createBidirectional = exports.create = exports.clearState = exports.checkForRelations = exports.batchUnrelateBidirectional = exports.batchUnrelate = exports.batchCreateBidirectional = exports.batchCreate = void 0;
var _immutable = _interopRequireDefault(require("immutable"));
var _reactIntl = require("react-intl");
var _get = _interopRequireDefault(require("lodash/get"));
var _session = _interopRequireDefault(require("../helpers/session"));
var _notification = require("./notification");
var _getErrorDescription = _interopRequireDefault(require("../helpers/getErrorDescription"));
var _reducers = require("../reducers");
var _errorCodes = require("../constants/errorCodes");
var _notificationStatusCodes = require("../constants/notificationStatusCodes");
var _actionCodes = require("../constants/actionCodes");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const clearState = () => ({
type: _actionCodes.CLEAR_RELATION_STATE
});
exports.clearState = clearState;
const messages = (0, _reactIntl.defineMessages)({
related: {
"id": "action.relation.related",
"defaultMessage": "{objectCount, plural, =0 {No records} one {# record} other {# records}} related to {subjectTitle}."
},
batchCreateError: {
"id": "action.relation.batchCreateError",
"defaultMessage": "Some records could not be related: {error}"
},
batchUnrelateError: {
"id": "action.relation.batchUnrelateError",
"defaultMessage": "Some records could not be unrelated: {error}"
}
});
const notificationID = 'action.relation';
const showRelationNotification = (message, values) => (0, _notification.showNotification)({
items: [{
message,
values
}],
date: new Date(),
status: _notificationStatusCodes.STATUS_SUCCESS,
autoClose: true
}, notificationID);
/*
* Find a relation, given at least the subject csid and object csid, and optionally the subject
* record type, object record type, and predicate. This function assumes that there will be very
* few (typically zero or one) results, and retrieves them all without paginating.
*/
exports.showRelationNotification = showRelationNotification;
const find = (config, subject, object, predicate) => (dispatch, getState) => {
if (!(subject.csid || object.csid)) {
throw new Error('subject csid or object csid must be supplied');
}
if ((0, _reducers.getRelationFindResult)(getState(), subject, object, predicate)) {
// Already have a result for this descriptor. Do nothing.
// TODO: Also check for a pending find request.
return null;
}
dispatch({
type: _actionCodes.RELATION_FIND_STARTED,
meta: {
subject,
object,
predicate
}
});
const params = {
prd: predicate,
wf_deleted: 'false',
pgSz: '0'
};
if (subject) {
const {
csid,
recordType
} = subject;
params.sbj = csid;
if (recordType) {
params.sbjType = (0, _get.default)(config, ['recordTypes', recordType, 'serviceConfig', 'objectName']);
}
}
if (object) {
const {
csid,
recordType
} = object;
params.obj = csid;
if (recordType) {
params.objType = (0, _get.default)(config, ['recordTypes', recordType, 'serviceConfig', 'objectName']);
}
}
const requestConfig = {
params
};
return (0, _session.default)().read('/relations', requestConfig).then(response => dispatch({
type: _actionCodes.RELATION_FIND_FULFILLED,
payload: response,
meta: {
subject,
object,
predicate
}
})).catch(error => dispatch({
type: _actionCodes.RELATION_FIND_REJECTED,
payload: {
code: _errorCodes.ERR_API,
error
},
meta: {
subject,
object,
predicate
}
}));
};
/**
* Check if any relations exist for a given record csid and predicate, and optionally, a related
* csid. Resolves to true or false.
*/
exports.find = find;
const checkForRelations = (csid1, predicate, csid2) => () => {
const params = {
prd: predicate,
sbj: csid1,
andReciprocal: 'true',
wf_deleted: 'false',
pgSz: '1'
};
if (typeof csid2 !== 'undefined') {
params.obj = csid2;
}
const requestConfig = {
params
};
return (0, _session.default)().read('/relations', requestConfig).then(response => {
const totalItems = (0, _get.default)(response, ['data', 'rel:relations-common-list', 'totalItems']);
return totalItems && parseInt(totalItems, 10) > 0;
});
};
exports.checkForRelations = checkForRelations;
const deleteRelation = csid => dispatch => {
if (!csid) {
throw new Error('csid must be supplied');
}
// return Promise.resolve();
dispatch({
type: _actionCodes.RELATION_DELETE_STARTED,
meta: {
csid
}
});
return (0, _session.default)().delete(`/relations/${csid}`).then(response => dispatch({
type: _actionCodes.RELATION_DELETE_FULFILLED,
payload: response,
meta: {
csid
}
})).catch(error => {
dispatch({
type: _actionCodes.RELATION_DELETE_REJECTED,
payload: {
code: _errorCodes.ERR_API,
error
},
meta: {
csid
}
});
return Promise.reject(error);
});
};
exports.deleteRelation = deleteRelation;
const doUnrelate = (config, subject, object, predicate) => (dispatch, getState) => {
if (!(subject.csid && object.csid)) {
throw new Error('subject csid and object csid must be supplied');
}
const existingResult = (0, _reducers.getRelationFindResult)(getState(), subject, object, predicate);
let promise;
if (existingResult) {
promise = Promise.resolve(existingResult);
} else {
promise = dispatch(find(config, subject, object, predicate)).then(() => (0, _reducers.getRelationFindResult)(getState(), subject, object, predicate));
}
return promise.then(findResult => {
const list = findResult.get('rel:relations-common-list');
let items = list.get('relation-list-item');
if (!_immutable.default.List.isList(items)) {
items = _immutable.default.List.of(items);
}
return Promise.all(items.map(item => dispatch(deleteRelation(item.get('csid')))));
});
};
const unrelate = (config, subject, object, predicate) => dispatch => dispatch(doUnrelate(config, subject, object, predicate)).then(() => dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
})).catch(() => {});
exports.unrelate = unrelate;
const unrelateBidirectional = (config, subject, object, predicate) => dispatch => dispatch(unrelate(config, subject, object, predicate)).then(() => dispatch(unrelate(config, object, subject, predicate))).catch(() => {});
exports.unrelateBidirectional = unrelateBidirectional;
const batchUnrelate = (config, subject, objects, predicate) => dispatch => objects.reduce((promise, object) => promise.then(() => dispatch(doUnrelate(config, subject, object, predicate))), Promise.resolve()).then(() => dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
})).catch(error => {
dispatch((0, _notification.showNotification)({
items: [{
message: messages.batchUnrelateError,
values: {
error: (0, _getErrorDescription.default)(error)
}
}],
date: new Date(),
status: _notificationStatusCodes.STATUS_ERROR
}, notificationID));
});
exports.batchUnrelate = batchUnrelate;
const batchUnrelateBidirectional = (config, subject, objects, predicate) => dispatch =>
// For the passed subject, we only want to dispatch SUBJECT_RELATIONS_UPDATED once at the end, so
// doUnrelate is used. The passed objects should be unique; for the reverse relations (where the
// object becomes the subject), SUBJECT_RELATIONS_UPDATED may be dispatched immediately, so
// unrelate is used.
// Send these requests one at a time, to avoid DOSing the server.
objects.reduce((promise, object) => promise.then(() => dispatch(doUnrelate(config, subject, object, predicate))).then(() => dispatch(unrelate(config, object, subject, predicate))), Promise.resolve()).then(() => dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
})).catch(error => {
dispatch((0, _notification.showNotification)({
items: [{
message: messages.batchUnrelateError,
values: {
error: (0, _getErrorDescription.default)(error)
}
}],
date: new Date(),
status: _notificationStatusCodes.STATUS_ERROR
}, notificationID));
});
exports.batchUnrelateBidirectional = batchUnrelateBidirectional;
const doCreate = (subject, object, predicate) => dispatch => {
dispatch({
type: _actionCodes.RELATION_SAVE_STARTED,
meta: {
subject,
object,
predicate
}
});
const config = {
data: {
document: {
'rel:relations_common': {
'@xmlns:rel': 'http://collectionspace.org/services/relation',
subjectCsid: subject.csid,
objectCsid: object.csid,
relationshipType: predicate
}
}
}
};
return (0, _session.default)().create('/relations', config).then(response => dispatch({
type: _actionCodes.RELATION_SAVE_FULFILLED,
payload: response,
meta: {
subject,
object,
predicate
}
})).catch(error => {
dispatch({
type: _actionCodes.RELATION_SAVE_REJECTED,
payload: {
code: _errorCodes.ERR_API,
error
},
meta: {
subject,
object,
predicate
}
});
return Promise.reject(error);
});
};
const batchCreate = (subject, objects, predicate) => dispatch => objects.reduce((promise, object) => promise.then(() => dispatch(checkForRelations(subject.csid, predicate, object.csid))).then(relationExists => {
if (relationExists) {
return Promise.resolve();
}
return dispatch(doCreate(subject, object, predicate));
}), Promise.resolve()).then(() => dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
})).catch(error => {
dispatch((0, _notification.showNotification)({
items: [{
message: messages.batchCreateError,
values: {
error: (0, _getErrorDescription.default)(error)
}
}],
date: new Date(),
status: _notificationStatusCodes.STATUS_ERROR
}, notificationID));
});
exports.batchCreate = batchCreate;
const batchCreateBidirectional = (subject, objects, predicate) => dispatch =>
// Send these requests one at a time, to avoid DOSing the server.
objects.reduce((promise, object) => promise.then(() => dispatch(checkForRelations(subject.csid, predicate, object.csid))).then(relationExists => {
if (relationExists) {
return Promise.resolve();
}
return dispatch(doCreate(subject, object, predicate)).then(() => dispatch(doCreate(object, subject, predicate)));
}), Promise.resolve()).then(() => {
dispatch(showRelationNotification(messages.related, {
objectCount: objects.length,
subjectTitle: subject.title
}));
dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
});
}).catch(error => {
dispatch((0, _notification.showNotification)({
items: [{
message: messages.batchCreateError,
values: {
error: (0, _getErrorDescription.default)(error)
}
}],
date: new Date(),
status: _notificationStatusCodes.STATUS_ERROR
}, notificationID));
});
exports.batchCreateBidirectional = batchCreateBidirectional;
const create = (subject, object, predicate) => dispatch => dispatch(doCreate(subject, object, predicate)).then(() => dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
})).catch(() => {});
exports.create = create;
const createBidirectional = (subject, object, predicate) => dispatch => dispatch(doCreate(subject, object, predicate)).then(() => dispatch(doCreate(object, subject, predicate))).then(() => dispatch({
type: _actionCodes.SUBJECT_RELATIONS_UPDATED,
meta: {
subject,
updatedTime: new Date().toISOString()
}
})).catch(() => {});
exports.createBidirectional = createBidirectional;
;