server/helpers/utils.js

"use strict";

require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.symbol.iterator.js");
require("core-js/modules/es.array.from.js");
require("core-js/modules/es.array.slice.js");
require("core-js/modules/es.object.get-own-property-descriptor.js");
require("core-js/modules/es.regexp.to-string.js");
require("core-js/modules/es.weak-map.js");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.attachAttributes = attachAttributes;
exports.createEntityPageTitle = createEntityPageTitle;
exports.entityToOption = entityToOption;
exports.filterIdentifierTypesByEntity = filterIdentifierTypesByEntity;
exports.generateIdenfierState = generateIdenfierState;
exports.getAdditionalRelations = getAdditionalRelations;
exports.getDateBeforeDays = getDateBeforeDays;
exports.getIdByField = getIdByField;
exports.getIdByLabel = getIdByLabel;
exports.getIntFromQueryParams = getIntFromQueryParams;
exports.incrementEditorEditCountById = incrementEditorEditCountById;
exports.parseInitialState = parseInitialState;
exports.parseLanguages = parseLanguages;
exports.parseQuery = parseQuery;
exports.searchOption = searchOption;
exports.template = template;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
require("core-js/modules/es.array.filter.js");
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/es.array.join.js");
require("core-js/modules/es.function.name.js");
require("core-js/modules/es.object.assign.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.parse-int.js");
require("core-js/modules/es.promise.js");
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.set.js");
require("core-js/modules/es.string.includes.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/es.string.replace.js");
require("core-js/modules/web.dom-collections.for-each.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/web.url-search-params.js");
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _upperFirst2 = _interopRequireDefault(require("lodash/upperFirst"));
var _isNil2 = _interopRequireDefault(require("lodash/isNil"));
var search = _interopRequireWildcard(require("../../common/helpers/search"));
var _utils = require("../../common/helpers/utils");
var cache;
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } /*
 * Copyright (C) 2015       Ben Ockmore
 *               2015-2017  Sean Burke
 				 2019       Akhilesh Kumar (@akhilesh26)
 				 2020		Prabal Singh
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
function getDateBeforeDays(days) {
  var date = new Date();
  date.setDate(date.getDate() - days);
  return date;
}
function filterIdentifierTypesByEntity(identifierTypes, entity) {
  var typesOnEntity = new Set();
  if (!entity.identifierSet || entity.identifierSet.identifiers.length < 1) {
    /*
     * If there are no identifiers, skip the work of trying to add types
     * which shouldn't be on this entity.
     */
    return (0, _utils.filterIdentifierTypesByEntityType)(identifierTypes, entity.type);
  }
  var _iterator = _createForOfIteratorHelper(entity.identifierSet.identifiers),
    _step;
  try {
    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      var identifier = _step.value;
      typesOnEntity.add(identifier.type.id);
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }
  return identifierTypes.filter(function (type) {
    return type.entityType === entity.type || typesOnEntity.has(type.id);
  });
}

/**
 * Helper-function / template-tag that allows the values of an object that
 * is passed in at a later time to be interpolated into a
 * string.
 *
 * Cribbed from MDN documentation on template literals:
 * https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals
 *
 * @param {string[]} strings - Array of string literals from template
 * @returns {function(*)} - Takes an object/array as an argument.
 * When invoked, it will return a string with all the key names from
 * the tagged template literal replaced with their corresponding values
 * from the newly passed in object.
 */

function template(strings) {
  for (var _len = arguments.length, keys = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    keys[_key - 1] = arguments[_key];
  }
  return function (values) {
    var result = [strings[0]];
    keys.forEach(function (key, i) {
      result.push(values[key], strings[i + 1]);
    });
    return result.join('');
  };
}

/**
 * Generates a page title for an entity row
 *
 * @param {object} entity - Entity object
 * @param {string} titleForUnnamed - Fallback title in case entity has no name
 * @param {function} templateForNamed - Accepts an object with a name field and
 * uses it to generate a title string
 * @returns {string} - Title string
 */
function createEntityPageTitle(entity, titleForUnnamed, templateForNamed) {
  /**
   * User-visible strings should _never_ be created by concatenation; when we
   * start to implement localization, it will create problems for users of
   * many languages. This helper is here to make it a little easier to do the
   * right thing.
   */
  var title = titleForUnnamed;

  // Accept template with a "name" replacement field
  if (entity && entity.defaultAlias && entity.defaultAlias.name) {
    title = templateForNamed({
      name: entity.defaultAlias.name
    });
  }
  return title;
}

/**
 * Adds 1 to the edit count of the specified editor
 *
 * @param {object} orm - the BookBrainz ORM, initialized during app setup
 * @param {string} id - row ID of editor to be updated
 * @param {object} transacting - Bookshelf transaction object (must be in
 * progress)
 * @returns {Promise} - Resolves to the updated editor model
 */
function incrementEditorEditCountById(orm, id, transacting) {
  var Editor = orm.Editor;
  return new Editor({
    id: id
  }).fetch({
    require: true,
    transacting: transacting
  }).then(function (editor) {
    editor.incrementEditCount();
    return editor.save(null, {
      transacting: transacting
    });
  }).catch(Editor.NotFoundError, function (err) {
    return new Promise(function (resolve, reject) {
      return reject(err);
    });
  });
}

/**
 * Return additional relations to withRelated array according to modelType
 *
 * @param {string} modelType - type of the model or entity
 * @returns {array} array of additional relations
 */
function getAdditionalRelations(modelType) {
  if (modelType === 'Work') {
    return ['disambiguation', 'workType', 'languageSet.languages'];
  } else if (modelType === 'Edition') {
    return ['disambiguation', 'releaseEventSet.releaseEvents', 'identifierSet.identifiers.type', 'editionFormat'];
  }
  return [];
}

/**
 * Takes an entity and converts it to a format acceptable to react-select.
 *
 * @param {Object} entity the entity to convert
 * @returns {Object} the formatted data
 */
function entityToOption(entity) {
  return (0, _isNil2.default)(entity) ? null : {
    defaultAlias: entity.defaultAlias,
    disambiguation: entity.disambiguation ? entity.disambiguation.comment : null,
    id: entity.bbid,
    text: entity.defaultAlias ? entity.defaultAlias.name : '(unnamed)',
    type: entity.type
  };
}

/**
 * Takes an array of relationships and attach the deeply nested
 * relationship attributes to the first level of the relationship object.
 *
 * @param {Array} relationships the array of relationships
 */
function attachAttributes(relationships) {
  relationships.forEach(function (relationship) {
    var _relationship$attribu;
    if ((_relationship$attribu = relationship.attributeSet) !== null && _relationship$attribu !== void 0 && _relationship$attribu.relationshipAttributes) {
      relationship.attributeSet.relationshipAttributes.forEach(function (attribute) {
        relationship["".concat(attribute.type.name)] = attribute.value.textValue;
      });
    }
  });
}

/**
 * Fetch id related with label
 *
 * @param {object[]} fromOptions - Options
 * @param {string} label - related label
 * @param {string} keyName - key associated
 * @returns {number} - assigned id
 */
function getIdByLabel(fromOptions, label, keyName) {
  var _iterator2 = _createForOfIteratorHelper(fromOptions),
    _step2;
  try {
    for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
      var option = _step2.value;
      if (option[keyName] === label) {
        return option.id;
      }
    }
  } catch (err) {
    _iterator2.e(err);
  } finally {
    _iterator2.f();
  }
  return null;
}

/**
 * Fetch Id of a model using field value
 *
 * @param {object} model - Model  eg. Language
 * @param {string} fieldName - given field eg. name
 * @param {string} fieldValue - given field value eg. English
 * @returns {Promise} - Resolves to required id
 */
function getIdByField(_x, _x2, _x3) {
  return _getIdByField.apply(this, arguments);
}
/**
 * Generate Identifier state from req body
 *
 * @param {object} sourceIdentifierState - source state in format of t{typeId}:value
 * @returns {object} - correctly formatted identifierEditor state
 */
function _getIdByField() {
  _getIdByField = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee(model, fieldName, fieldValue) {
    var _yield$model$query$fe, _yield$model$query$fe2;
    var _t, _t2, _t3, _t4, _t5, _t6;
    return _regenerator.default.wrap(function (_context) {
      while (1) switch (_context.prev = _context.next) {
        case 0:
          _context.next = 1;
          return model.query({
            where: (0, _defineProperty2.default)({}, fieldName, fieldValue)
          }).fetch({
            require: false
          });
        case 1:
          _t3 = _yield$model$query$fe2 = _context.sent;
          _t2 = _t3 === null;
          if (_t2) {
            _context.next = 2;
            break;
          }
          _t2 = _yield$model$query$fe2 === void 0;
        case 2:
          if (!_t2) {
            _context.next = 3;
            break;
          }
          _t4 = void 0;
          _context.next = 4;
          break;
        case 3:
          _t4 = _yield$model$query$fe2.get('id');
        case 4:
          _t5 = _yield$model$query$fe = _t4;
          _t = _t5 !== null;
          if (!_t) {
            _context.next = 5;
            break;
          }
          _t = _yield$model$query$fe !== void 0;
        case 5:
          if (!_t) {
            _context.next = 6;
            break;
          }
          _t6 = _yield$model$query$fe;
          _context.next = 7;
          break;
        case 6:
          _t6 = null;
        case 7:
          return _context.abrupt("return", _t6);
        case 8:
        case "end":
          return _context.stop();
      }
    }, _callee);
  }));
  return _getIdByField.apply(this, arguments);
}
function generateIdenfierState(sourceIdentifierState) {
  var index = 0;
  var identifierState = {};
  for (var typeKey in sourceIdentifierState) {
    if (Object.prototype.hasOwnProperty.call(sourceIdentifierState, typeKey)) {
      identifierState["".concat(index)] = {
        type: parseInt(typeKey.replace('t', ''), 10),
        value: sourceIdentifierState[typeKey]
      };
      index++;
    }
  }
  return identifierState;
}

/**
 * Generate EntitySection Language state from req body
 *
 * @param {object} sourceEntitySection - source entity section state in format of languages{index}:value
 * @param {object} orm - orm object
 *  @returns {Promise} - Resolves to modified state
 */
function parseLanguages(_x4, _x5) {
  return _parseLanguages.apply(this, arguments);
}
/**
 * Generate react-select option from query
 * @param {object} orm - orm
 * @param {string} type - type eg. area
 * @param {string} query - query string
 * @param {string} idKey - key corresponding to id
 * @param {boolean} exactMatch - exact matching the query string
 * @returns {Promise} - resolves to option object
 */
function _parseLanguages() {
  _parseLanguages = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2(sourceEntitySection, orm) {
    var Language, languages, langKey, _t7, _t8, _t9, _t0, _t1;
    return _regenerator.default.wrap(function (_context2) {
      while (1) switch (_context2.prev = _context2.next) {
        case 0:
          if (sourceEntitySection) {
            _context2.next = 1;
            break;
          }
          return _context2.abrupt("return", sourceEntitySection);
        case 1:
          Language = orm.Language;
          languages = [];
          _t7 = _regenerator.default.keys(sourceEntitySection);
        case 2:
          if ((_t8 = _t7()).done) {
            _context2.next = 5;
            break;
          }
          langKey = _t8.value;
          if (!Object.prototype.hasOwnProperty.call(sourceEntitySection, langKey)) {
            _context2.next = 4;
            break;
          }
          if (!langKey.includes('languages')) {
            _context2.next = 4;
            break;
          }
          _t9 = languages;
          _t0 = (0, _upperFirst2.default)(sourceEntitySection[langKey]);
          _context2.next = 3;
          return getIdByField(Language, 'name', (0, _upperFirst2.default)(sourceEntitySection[langKey]));
        case 3:
          _t1 = _context2.sent;
          _t9.push.call(_t9, {
            label: _t0,
            value: _t1
          });
          delete sourceEntitySection[langKey];
        case 4:
          _context2.next = 2;
          break;
        case 5:
          sourceEntitySection.languages = languages;
          return _context2.abrupt("return", sourceEntitySection);
        case 6:
        case "end":
          return _context2.stop();
      }
    }, _callee2);
  }));
  return _parseLanguages.apply(this, arguments);
}
function searchOption(_x6, _x7, _x8) {
  return _searchOption.apply(this, arguments);
}
/**
 * Parse NameSection, IdentifierEditor, AnnotationSection state from request body
 *
 * @param {object} req - Request object
 * @param {string} type - entity type
 * @returns {Promise} - Resolves to Entity initialState
 */
function _searchOption() {
  _searchOption = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3(orm, type, query) {
    var idKey,
      exactMatch,
      results,
      firstMatch,
      option,
      _args3 = arguments;
    return _regenerator.default.wrap(function (_context3) {
      while (1) switch (_context3.prev = _context3.next) {
        case 0:
          idKey = _args3.length > 3 && _args3[3] !== undefined ? _args3[3] : 'id';
          exactMatch = _args3.length > 4 && _args3[4] !== undefined ? _args3[4] : false;
          if (!exactMatch) {
            _context3.next = 2;
            break;
          }
          _context3.next = 1;
          return search.checkIfExists(orm, query, type);
        case 1:
          results = _context3.sent;
          _context3.next = 4;
          break;
        case 2:
          _context3.next = 3;
          return search.autocomplete(orm, query, type, 1);
        case 3:
          results = _context3.sent;
        case 4:
          if (!results.length) {
            _context3.next = 5;
            break;
          }
          firstMatch = results[0];
          option = {
            disambiguation: idKey === 'id' ? firstMatch.disambiguation.comment : null,
            id: firstMatch[idKey],
            text: firstMatch.defaultAlias.name,
            type: firstMatch.type
          };
          return _context3.abrupt("return", option);
        case 5:
          return _context3.abrupt("return", null);
        case 6:
        case "end":
          return _context3.stop();
      }
    }, _callee3);
  }));
  return _searchOption.apply(this, arguments);
}
function parseInitialState(_x9, _x0) {
  return _parseInitialState.apply(this, arguments);
}
function _parseInitialState() {
  _parseInitialState = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee4(req, type) {
    var emptyState, entity, orm, Language, initialState;
    return _regenerator.default.wrap(function (_context4) {
      while (1) switch (_context4.prev = _context4.next) {
        case 0:
          emptyState = {
            nameSection: {
              disambiguation: '',
              exactMatches: null,
              language: null,
              name: '',
              searchResults: null,
              sortName: ''
            }
          };
          entity = (0, _utils.unflatten)(req.body);
          orm = req.app.locals.orm;
          Language = orm.Language; // NameSection State
          initialState = Object.assign(emptyState, entity); // We allow Editions (but not other entities) to have the same primary name as another Edition without requiring a disambiguation
          if (!(initialState.nameSection.name && type !== 'edition')) {
            _context4.next = 3;
            break;
          }
          _context4.next = 1;
          return search.autocomplete(orm, initialState.nameSection.name, type, 10);
        case 1:
          initialState.nameSection.searchResults = _context4.sent;
          _context4.next = 2;
          return search.checkIfExists(orm, initialState.nameSection.name, type);
        case 2:
          initialState.nameSection.exactMatches = _context4.sent;
        case 3:
          if (!initialState.nameSection.language) {
            _context4.next = 5;
            break;
          }
          _context4.next = 4;
          return getIdByField(Language, 'name', initialState.nameSection.language);
        case 4:
          initialState.nameSection.language = _context4.sent;
        case 5:
          // IdentifierEditor State
          if (initialState.identifierEditor) {
            initialState.identifierEditor = generateIdenfierState(initialState.identifierEditor);
          }
          // AnnotationSection State
          if (initialState.annotationSection) {
            initialState.annotationSection = {
              content: initialState.annotationSection
            };
          }
          // SubmissionSection State
          if (initialState.submissionSection) {
            initialState.submissionSection = {
              note: initialState.submissionSection,
              submitError: '',
              submitted: false
            };
          }
          return _context4.abrupt("return", initialState);
        case 6:
        case "end":
          return _context4.stop();
      }
    }, _callee4);
  }));
  return _parseInitialState.apply(this, arguments);
}
function parseQuery(url) {
  return new URLSearchParams(url.replace(/^.+?\?/, ''));
}
function getIntFromQueryParams(query, name) {
  var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
  return parseInt(query.get(name), 10) || fallback;
}
//# sourceMappingURL=utils.js.map