UNPKG

@stackend/api

Version:

JS bindings to api.stackend.com

1,326 lines 48.4 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCommunityUrl = exports.createUrl = exports._getConfig = exports.getConfig = exports.getXpressToken = exports.post = exports.getJsonOutsideApi = exports.getJson = exports.addRelatedObjectsToStore = exports.getApiUrl = exports._getApiUrl = exports.getCurrentCommunityPermalink = exports.getCurrentCommunity = exports._getAbsoluteApiBaseUrl = exports.getAbsoluteApiBaseUrl = exports.getEffectiveCommunityPath = exports.getAbsoluteCommunityPath = exports.getCommunityPathFromStore = exports.getCommunityPath = exports._getServerWithContextPath = exports.getServerWithContextPathFromStore = exports.getServerWithContextPath = exports._getContextPath = exports.getContextPath = exports._getDeployProfile = exports.getDeployProfile = exports._getServer = exports.getServer = exports.resetConfiguration = exports.setConfiguration = exports.getConfiguration = exports._constructConfig = exports.RICH_CONTENT_CHAIN_PARAMETER = exports.COMMUNITY_PARAMETER = exports.VOTES = exports.LIKES = exports.EXTRA_OBJECTS = exports.RELATED_OBJECTS = exports.DEFAULT_COMMUNITY = exports.setRunningServerSide = exports.isRunningInBrowser = exports.isRunningServerSide = exports.setConfigDefaults = exports.configDefaults = exports.DeployProfile = exports.STACKEND_DEFAULT_CONTEXT_PATH = exports.STACKEND_DEFAULT_SERVER = exports.setLogger = exports.getLogger = exports.logger = void 0; exports.getHashCode = exports.logJsError = exports.getInitialStoreValues = exports.addModuleExtraParameters = exports.getTypeName = exports.newXcapJsonErrorResult = exports.newXcapJsonResult = exports._newXcapJsonResult = exports.getJsonErrorText = exports.postProcessApiResult = exports.argsToObject = void 0; var LoadJson_1 = require("./LoadJson"); var get_1 = __importDefault(require("lodash/get")); var forIn_1 = __importDefault(require("lodash/forIn")); var referenceActions_1 = require("./referenceActions"); var request_1 = require("../request"); var stackend_1 = require("../stackend"); var throbberActions_1 = require("../throbber/throbberActions"); var configReducer_1 = require("./configReducer"); var Logger_1 = require("../util/Logger"); var AccessToken_1 = require("./AccessToken"); var actions_1 = require("./actions"); var extraObjectActions_1 = require("./extraObjectActions"); function createDefaultLogger() { return new Logger_1.ConsoleLogger('stackend'); } /** * Stackend logger */ exports.logger = createDefaultLogger(); /** * Get the stackend logger */ function getLogger() { if (!exports.logger) { exports.logger = createDefaultLogger(); } return exports.logger; } exports.getLogger = getLogger; /** * Set the default logger * @param newLogger */ function setLogger(newLogger) { exports.logger = newLogger; } exports.setLogger = setLogger; exports.STACKEND_DEFAULT_SERVER = 'https://api.stackend.com'; exports.STACKEND_DEFAULT_CONTEXT_PATH = ''; /** * Known deploy profiles */ var DeployProfile; (function (DeployProfile) { DeployProfile["STACKEND"] = "stackend"; })(DeployProfile = exports.DeployProfile || (exports.DeployProfile = {})); exports.configDefaults = { server: exports.STACKEND_DEFAULT_SERVER, contextPath: '', apiUrl: exports.STACKEND_DEFAULT_SERVER + exports.STACKEND_DEFAULT_CONTEXT_PATH + '/api', recaptchaSiteKey: null, gaKey: null, deployProfile: DeployProfile.STACKEND }; /** * Set default configuration options * @param defaults */ function setConfigDefaults(defaults) { exports.configDefaults = defaults; } exports.setConfigDefaults = setConfigDefaults; var __xcapRunningServerSide = false; /** * Is the app running server side? */ function isRunningServerSide() { return __xcapRunningServerSide; } exports.isRunningServerSide = isRunningServerSide; /** * Is the app running in the browser */ function isRunningInBrowser() { return !__xcapRunningServerSide && typeof window !== 'undefined'; } exports.isRunningInBrowser = isRunningInBrowser; function setRunningServerSide(ssr) { __xcapRunningServerSide = ssr; } exports.setRunningServerSide = setRunningServerSide; /** * The default community ("stackend") * @type {string} */ exports.DEFAULT_COMMUNITY = 'stackend'; /** * Key holding related objects in the json response. * @type {string} */ exports.RELATED_OBJECTS = '__relatedObjects'; /** * Key holding related objects that are not IdAware in the json response. * @type {string} */ exports.EXTRA_OBJECTS = '__extraObjects'; /** * Key holding related likes in the json response. * @type {string} */ exports.LIKES = 'likes'; /** * Key holding related votes in the json response. * @type {string} */ exports.VOTES = 'votes'; /** * Parameter name holding the community * @type {string} */ exports.COMMUNITY_PARAMETER = '__community'; /** * Parameter specifying an alternative rich content chain used to serialize the result * @type {string} */ exports.RICH_CONTENT_CHAIN_PARAMETER = 'xcap.rich-content-chain'; /** * Xcap types and their names */ var typeNames = { 'se.josh.xcap.comment.Comment': 'Comment', 'se.josh.xcap.comment.impl.CommentImpl': 'Comment', 'net.josh.community.user.User': 'User', 'net.josh.community.group.Group': 'Group', 'net.josh.community.user.backend.xcap.XcapUser': 'User', 'net.josh.community.blog.BlogEntry': 'Post', 'net.josh.community.abuse.ReferencedAbuse': 'Abuse report', 'net.josh.community.forum.ForumThread': 'Question', 'net.josh.community.forum.impl.ForumThreadImpl': 'Question', 'net.josh.community.forum.ForumThreadEntry': 'Answer', 'net.josh.community.forum.impl.ForumThreadEntryImpl': 'Answer', 'net.josh.community.forum.Forum': 'Forum', 'net.josh.community.forum.impl.ForumImpl': 'Forum', 'net.josh.community.media.Media': 'Media', 'net.josh.community.media.Image': 'Image', 'net.josh.community.media.Document': 'Document', 'net.josh.community.media.Audio': 'Audio', 'net.josh.community.media.Video': 'Video', 'se.josh.xcap.cms.Content': 'CMS Content', 'se.josh.xcap.cms.impl.ContentImpl': 'CMS Content', 'se.josh.xcap.community.Community': 'Site' }; /** * Construct basic configuration from the environment. */ function _constructConfig() { var c = Object.assign({ server: exports.STACKEND_DEFAULT_SERVER, contextPath: exports.STACKEND_DEFAULT_CONTEXT_PATH, deployProfile: DeployProfile.STACKEND, apiUrl: null, gaKey: null, recaptchaSiteKey: null }, exports.configDefaults); if (!c.apiUrl) { c.apiUrl = c.server + c.contextPath + '/api'; } return c; } exports._constructConfig = _constructConfig; /** * Get the API configuration object * @type {Thunk<Config>} */ function getConfiguration() { return function (dispatch, getState) { var c = (0, get_1.default)(getState(), 'config'); if (c) { return c; } // FIXME: Push to store? return _constructConfig(); }; } exports.getConfiguration = getConfiguration; /** * Set the API configuration * @param config */ function setConfiguration(config) { return function (dispatch, _getState) { return dispatch({ type: configReducer_1.XCAP_SET_CONFIG, config: config }); }; } exports.setConfiguration = setConfiguration; /** * Reset the API configuration to the defaults */ function resetConfiguration() { return setConfiguration({ server: exports.STACKEND_DEFAULT_SERVER, contextPath: exports.STACKEND_DEFAULT_CONTEXT_PATH, deployProfile: DeployProfile.STACKEND, gaKey: null, recaptchaSiteKey: null }); } exports.resetConfiguration = resetConfiguration; /** * Server domain enabling CORS calls * @type {string} */ function getServer() { return function (dispatch, getState) { var s = undefined; if (typeof getState !== 'function') { exports.logger.error('getServer: Wrong invocation'); } else { s = (0, get_1.default)(getState(), 'config.server'); if (s) { return s; } } return _constructConfig().server; }; } exports.getServer = getServer; /** * Server domain enabling CORS calls * @type {string} */ function _getServer(config) { var s = (0, get_1.default)(config, 'server'); if (s) { return s; } return _constructConfig().server; } exports._getServer = _getServer; /** * @deprecated bad practise to dispatch getters which doesn't set any state, use api._getDeployProfile instead * Get the deploy profile name. Allows customized styling for different deployments * @return a profile name, or the empty string. */ function getDeployProfile() { return function (dispatch, getState) { if (typeof getState !== 'function') { exports.logger.error('getDeployProfile: Wrong invocation'); } else { var s = (0, get_1.default)(getState(), 'config.deployProfile'); if (s) { return s; } } return _constructConfig().deployProfile; }; } exports.getDeployProfile = getDeployProfile; /** * Get the deploy profile name. Allows customized styling for different deployments * @return a profile name, or the empty string. */ function _getDeployProfile(config) { var s = (0, get_1.default)(config, 'deployProfile'); if (s) { return s; } return _constructConfig().deployProfile; } exports._getDeployProfile = _getDeployProfile; /** * ContextPath of Api server * @return {Thunk<string>} */ function getContextPath() { return function (dispatch, getState) { if (typeof getState !== 'function') { exports.logger.error('getContextPath: Wrong invocation'); } else { var s = (0, get_1.default)(getState(), 'config.contextPath'); if (s) { return s; } } return _constructConfig().contextPath; }; } exports.getContextPath = getContextPath; /** * ContextPath of Api server * @type {string} */ function _getContextPath(config) { var s = (0, get_1.default)(config, 'contextPath'); if (s) { return s; } return _constructConfig().contextPath; } exports._getContextPath = _getContextPath; /** * Server domain address with ContextPath * @return {Thunk<string>} */ function getServerWithContextPath() { return function (dispatch, getState) { var server, contextPath; if (typeof getState !== 'function') { exports.logger.error('getServerWithContextPath: Wrong invocation'); } else { var state = getState(); server = (0, get_1.default)(state, 'config.server'); contextPath = (0, get_1.default)(state, 'config.contextPath'); } if (!server || !contextPath) { var c = _constructConfig(); server = server || c.server; contextPath = contextPath || c.contextPath; } return server + contextPath; }; } exports.getServerWithContextPath = getServerWithContextPath; /** * Server domain address with ContextPath from redux store */ function getServerWithContextPathFromStore(config) { // FIXME: Duplicate of nex function var c = config; if (!config.server || !config.contextPath) { c = _constructConfig(); } return c.server + c.contextPath; } exports.getServerWithContextPathFromStore = getServerWithContextPathFromStore; /** * Server domain address with ContextPath */ function _getServerWithContextPath(config) { var c = config; if (!config.server || !config.contextPath) { c = _constructConfig(); } return c.server + c.contextPath; } exports._getServerWithContextPath = _getServerWithContextPath; /** * Get the path to the current community. * For example "/stackend/test" * @return never null */ function getCommunityPath() { return function (dispatch, getState) { if (typeof getState !== 'function') { throw Error('getCommunityPath : Wrong invocation'); } return (0, get_1.default)(getState(), 'request.communityUrl', ''); }; } exports.getCommunityPath = getCommunityPath; /** * Get the path to the current community. * For example "/stackend/test" * @return never null */ function getCommunityPathFromStore(_a) { var request = _a.request; return (0, get_1.default)(request, 'communityUrl', ''); } exports.getCommunityPathFromStore = getCommunityPathFromStore; /** * Get the absolute path to the current community, including host name. * For example "stackend.com/stackend/test" * Same as request.absoluteCommunityUrl. * @return {Thunk<string>} */ function getAbsoluteCommunityPath() { return function (dispatch, getState) { if (typeof getState !== 'function') { throw Error('getAbsoluteCommunityPath: Wrong invocation'); } return (0, get_1.default)(getState(), 'request.absoluteCommunityUrl', ''); }; } exports.getAbsoluteCommunityPath = getAbsoluteCommunityPath; /** * Get the community path. In stackend /stacks/, return the context path, not the current community path. * @return {Thunk<string>} */ function getEffectiveCommunityPath() { return function (dispatch, getState) { var state = getState(); if (/\/stacks\//.exec((0, get_1.default)(state, 'request.location.pathname', ''))) { // Ignore /stacks/xxx return _getContextPath(state.config); } // Outside stackend var p = (0, get_1.default)(state, 'request.communityPath', null); if (p !== null) { return p; } return _getContextPath(state.config); }; } exports.getEffectiveCommunityPath = getEffectiveCommunityPath; /** * Api url containing server and ContextPath if necessary. * @param community Optional community * @return {Thunk<string>} */ function getAbsoluteApiBaseUrl(community) { return function (dispatch, getState) { var state = getState(); var server = _getServer(state.config); var contextPath = _getContextPath(state.config); var pfx = server + contextPath; // The default community does not use a prefix if (typeof community === 'undefined' || community === null || community === exports.DEFAULT_COMMUNITY || community === '') { return pfx + '/api'; } return pfx + '/' + community + '/api'; }; } exports.getAbsoluteApiBaseUrl = getAbsoluteApiBaseUrl; /** * Api url containing server and ContextPath if necessary. * @param config Xcap config * @param communityPermalink Optional community permalink * @type {string} */ function _getAbsoluteApiBaseUrl(_a) { var config = _a.config, communityPermalink = _a.communityPermalink; var server = _getServer(config); var contextPath = _getContextPath(config); var pfx = server + contextPath; // The default community does not use a prefix if (typeof communityPermalink === 'undefined' || communityPermalink === null || communityPermalink === exports.DEFAULT_COMMUNITY || communityPermalink === '') { return pfx + '/api'; } return pfx + '/' + communityPermalink + '/api'; } exports._getAbsoluteApiBaseUrl = _getAbsoluteApiBaseUrl; /** * Get the current community name (For example "c123") * @return may return null */ function getCurrentCommunity() { return function (dispatch, getState) { return (0, get_1.default)(getState(), 'communities.community', null); }; } exports.getCurrentCommunity = getCurrentCommunity; /** * Get the current community permalink as used in name (For example "test"). * * @return May return null */ function getCurrentCommunityPermalink() { return function (dispatch, getState) { return (0, get_1.default)(getState(), 'communities.community.permalink', null); }; } exports.getCurrentCommunityPermalink = getCurrentCommunityPermalink; /** * Get the base url to the api server. * Typically '/APP/api/endpoint' * @param state Store state * @param url extra url * @param parameters extra parameters (optional) * @param notFromApi boolean if the url is not in the api * @param community community name * @param componentName Component name used to look up config * @param context Context name used to look up config * @returns {String} the api url * @see COMMUNITY_PARAMETER */ function _getApiUrl(_a) { var state = _a.state, url = _a.url, parameters = _a.parameters, _b = _a.notFromApi, notFromApi = _b === void 0 ? false : _b, community = _a.community, componentName = _a.componentName, context = _a.context; //the api url var params = argsToObject(parameters); if (typeof community === 'undefined') { if (params) { community = params[exports.COMMUNITY_PARAMETER]; delete params[exports.COMMUNITY_PARAMETER]; } if (typeof community === 'undefined') { community = (0, get_1.default)(state, 'communities.community.permalink', exports.DEFAULT_COMMUNITY); } } var path = ''; if (notFromApi) { path = url; } else { /* Calls to /api/* */ var server = _getConfig({ config: state.config || {}, componentName: componentName, context: context, key: 'server', defaultValue: _getServer(state.config) }); var contextPath = _getConfig({ config: state.config || {}, componentName: componentName, context: context, key: 'contextPath', defaultValue: _getContextPath(state.config) }); var apiUrlOverride = _getConfig({ config: state.config || {}, componentName: componentName, context: context, key: 'api-url' }); var pfx = server + contextPath; if (apiUrlOverride) { pfx = apiUrlOverride; } // The default community does not use a prefix else if (typeof community === 'undefined' || community === null || community === exports.DEFAULT_COMMUNITY || community === '') { pfx += '/api'; } else { pfx += '/' + community + '/api'; } path = pfx + url; path = (0, AccessToken_1.appendAccessToken)(path); } var args = (0, LoadJson_1.urlEncodeParameters)(params); return (0, LoadJson_1.appendQueryString)(path, args); } exports._getApiUrl = _getApiUrl; /** * Get the base url to the api server. * Typically '/APP/api/endpoint' * @param url extra url * @param parameters extra parameters (optional) * @param notFromApi boolean if the url is not in the api * @param community community name * @param componentName Component name used to look up config * @param context Context name used to look up config * @returns {Thunk} the api url * @see COMMUNITY_PARAMETER */ function getApiUrl(_a) { var url = _a.url, parameters = _a.parameters, _b = _a.notFromApi, notFromApi = _b === void 0 ? false : _b, community = _a.community, componentName = _a.componentName, context = _a.context; return function (dispatch, getState) { return _getApiUrl({ state: getState(), url: url, parameters: parameters, notFromApi: notFromApi, community: community, componentName: componentName, context: context }); }; } exports.getApiUrl = getApiUrl; /** * Add any related objects received to the store * @param dispatch * @param json */ function addRelatedObjectsToStore(dispatch, json) { if (!!json[exports.RELATED_OBJECTS] && Object.keys(json[exports.RELATED_OBJECTS]).length > 0) { var relatedObjects = json[exports.RELATED_OBJECTS]; var rr = { entries: relatedObjects }; dispatch((0, referenceActions_1.receiveReferences)(rr)); dispatch((0, referenceActions_1.applyReferenceHandlers)(rr)); } var extraObjects = json[exports.EXTRA_OBJECTS]; if (extraObjects && Object.keys(extraObjects).length > 0) { dispatch((0, extraObjectActions_1.applyExtraObjectHandlers)(extraObjects)); } } exports.addRelatedObjectsToStore = addRelatedObjectsToStore; /** * Get json from the api. * * @param url * @param parameters * @param notFromApi boolean if the url is not in the api * @param community Current community name * @param componentName Component name used for config (for example "like") * @param context Community context used for config (for example "forum") * @param cookie Optional cookie string to pass on. Typically used for SSR only * @returns {Thunk} */ function getJson(_a) { var _this = this; var url = _a.url, parameters = _a.parameters, _b = _a.notFromApi, notFromApi = _b === void 0 ? false : _b, community = _a.community, componentName = _a.componentName, context = _a.context, cookie = _a.cookie; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var p, c, runningServerSide, request, requestStartTime, result, t, r, e_1; return __generator(this, function (_a) { switch (_a.label) { case 0: p = url; _a.label = 1; case 1: _a.trys.push([1, 6, , 7]); dispatch((0, throbberActions_1.setLoadingThrobberVisible)(true)); return [4 /*yield*/, dispatch(getApiUrl({ url: url, parameters: argsToObject(parameters), notFromApi: notFromApi, community: community, componentName: componentName, context: context }))]; case 2: p = _a.sent(); c = cookie; runningServerSide = isRunningServerSide(); if (!((typeof c === 'undefined' || c == null) && runningServerSide)) return [3 /*break*/, 4]; return [4 /*yield*/, dispatch((0, request_1.getRequest)())]; case 3: request = _a.sent(); c = request.cookie; _a.label = 4; case 4: requestStartTime = Date.now(); exports.logger.debug('GET ' + p); return [4 /*yield*/, (0, LoadJson_1.LoadJson)({ url: p, cookie: c })]; case 5: result = _a.sent(); t = Date.now() - requestStartTime; if (t > 500 && runningServerSide) { exports.logger.warn('Slow API request: ' + t + 'ms:' + p); } if (result.json) { (0, AccessToken_1.handleAccessToken)(result.json); if (result.error) { exports.logger.error(getJsonErrorText(result.json) + ' ' + p); dispatch((0, throbberActions_1.setLoadingThrobberVisible)(false)); dispatch((0, actions_1.signalApiAccessFailed)(p, result)); if (result.status === 403) { // Unauthorized exports.logger.warn('Session has expired: ' + p); /* FIXME: At this point the user should be prompted to login again. Preferably using a popup dispatch(refreshLoginData({ force : true })); // Breaks because of circular dependencies */ } return [2 /*return*/, result.json]; } r = postProcessApiResult(result.json); addRelatedObjectsToStore(dispatch, r); dispatch((0, throbberActions_1.setLoadingThrobberVisible)(false)); return [2 /*return*/, r]; } exports.logger.error('No result received: ' + p); dispatch((0, throbberActions_1.setLoadingThrobberVisible)(false)); return [2 /*return*/, newXcapJsonErrorResult('No result received')]; case 6: e_1 = _a.sent(); // 404, connection refused etc exports.logger.error("Couldn't getJson: " + p, e_1); dispatch((0, throbberActions_1.setLoadingThrobberVisible)(false)); return [2 /*return*/, newXcapJsonErrorResult("Couldn't getJson: " + e_1)]; case 7: return [2 /*return*/]; } }); }); }; } exports.getJson = getJson; /** * Get json from the api. * * @param url * @param parameters * @returns {Promise} */ function getJsonOutsideApi(_a) { var _this = this; var url = _a.url, parameters = _a.parameters; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var p, result, r; return __generator(this, function (_a) { switch (_a.label) { case 0: p = (0, LoadJson_1.appendQueryString)(url, (0, LoadJson_1.urlEncodeParameters)(argsToObject(parameters))); return [4 /*yield*/, (0, LoadJson_1.LoadJson)({ url: p })]; case 1: result = _a.sent(); if (result) { if (result.error) { exports.logger.warn(result.error + p); return [2 /*return*/, newXcapJsonErrorResult(result.error)]; } if (result.json) { if (result.json.error) { exports.logger.warn(getJsonErrorText(result.json) + p); return [2 /*return*/, result.json]; } r = postProcessApiResult(result.json); addRelatedObjectsToStore(dispatch, r); return [2 /*return*/, r]; } } return [2 /*return*/, newXcapJsonErrorResult('No result received')]; } }); }); }; } exports.getJsonOutsideApi = getJsonOutsideApi; /** * Post using the json api. * @param url * @param parameters * @param community Current community name * @param componentName Component name used for config (for example "like") * @param context Community context used for config (for example "forum") * @returns {Thunk} */ function post(_a) { var _this = this; var url = _a.url, parameters = _a.parameters, community = _a.community, componentName = _a.componentName, context = _a.context; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var xpressToken, params, p, result, r; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, dispatch(getXpressToken({ community: community, componentName: componentName, context: context }))]; case 1: xpressToken = _a.sent(); params = argsToObject(parameters); if (typeof community === 'undefined' && params && typeof params[exports.COMMUNITY_PARAMETER] !== 'undefined') { community = params[exports.COMMUNITY_PARAMETER]; } p = dispatch(getApiUrl({ url: url, notFromApi: false, community: community, componentName: componentName, context: context })); return [4 /*yield*/, (0, LoadJson_1.LoadJson)({ url: p, method: 'POST', parameters: params, xpressToken: xpressToken.xpressToken })]; case 2: result = _a.sent(); if (result) { if (result.error) { exports.logger.warn(result.error + ': ' + p); return [2 /*return*/, newXcapJsonErrorResult('Post failed: ' + result.error)]; } if (result.json) { (0, AccessToken_1.handleAccessToken)(result.json); if (result.json.error) { exports.logger.warn(getJsonErrorText(result.json) + ': ' + p); } r = postProcessApiResult(result.json); addRelatedObjectsToStore(dispatch, r); return [2 /*return*/, r]; } } return [2 /*return*/, newXcapJsonErrorResult('Post failed: no response')]; } }); }); }; } exports.post = post; /** * Get a token used for CSRF prevention. */ function getXpressToken(_a) { var community = _a.community, componentName = _a.componentName, context = _a.context; return getJson({ url: '/xpresstoken', community: community, componentName: componentName, context: context }); } exports.getXpressToken = getXpressToken; /** * Get a configuration variable. * * <p>When looking up a key, the following order is used:</p> * <ol> * <li>COMPONENT.CONTEXT.KEY</li> * <li>COMPONENT.KEY</li> * <li>KEY</li> * <li>Default value</li> * </ol> * * @param key configuration key * @param componentName Component name (Optional) * @param context Community context(Optional) * @param defaultValue Default value (Optional) */ function getConfig(_a) { var key = _a.key, componentName = _a.componentName, context = _a.context, _b = _a.defaultValue, defaultValue = _b === void 0 ? '' : _b; return function (dispatch, getState) { var config = (0, get_1.default)(getState(), 'config'); return _getConfig({ config: config, key: key, componentName: componentName, context: context, defaultValue: defaultValue }); }; } exports.getConfig = getConfig; function _getConfig(_a) { var config = _a.config, key = _a.key, componentName = _a.componentName, context = _a.context, _b = _a.defaultValue, defaultValue = _b === void 0 ? '' : _b; if (typeof config === 'undefined') { exports.logger.warn('getConfig: config is not present in store'); return defaultValue; } var v = undefined; if (!componentName) { v = config[key]; if (typeof v !== 'undefined') { return v; } } else { if (!context) { v = config[componentName + '.' + key]; if (typeof v !== 'undefined') { return v; } return _getConfig({ config: config, key: key, defaultValue: defaultValue }); } else { v = config[componentName + '.' + context + '.' + key]; if (typeof v !== 'undefined') { return v; } return _getConfig({ config: config, key: key, componentName: componentName, defaultValue: defaultValue }); } } return defaultValue; } exports._getConfig = _getConfig; /** * Construct an url to the UI. * * @param path Path * @param parameters Parameters map * @param hash */ function createUrl(_a) { var path = _a.path, params = _a.params, hash = _a.hash; var loc = path; if (params) { var hasQ = loc.indexOf('?') !== -1; for (var p in params) { if (Object.prototype.hasOwnProperty.call(params, p)) { loc += hasQ ? '&' : '?'; var v = params[p]; if (!v) { loc += encodeURIComponent(p); } else { if (typeof v === 'object') { for (var i = 0; i < v.length; i++) { var w = v[i]; loc += (i > 0 ? '&' : '') + encodeURIComponent(p) + '=' + encodeURIComponent(w); } } else { loc += encodeURIComponent(p) + '=' + encodeURIComponent(v); } } hasQ = true; } } } if (hash) { loc += hash.startsWith('#') ? hash : '#' + hash; } return loc; } exports.createUrl = createUrl; /** * Construct an url to a community in the UI. * * @param request Request object from requestReducers.ts * @param path Path * @param parameters Parameters map * @param hash * @param absolute Should the url be absolute (boolean) */ function createCommunityUrl(_a) { var request = _a.request, path = _a.path, params = _a.params, hash = _a.hash, absolute = _a.absolute; var pfx = ''; if (!!absolute && absolute) { if (request) { pfx = request.absoluteCommunityUrl; } else { //pfx = getAbsoluteCommunityPath(); pfx = 'FIXME'; } } else { if (request) { pfx = request.communityUrl; } else { //pfx = getCommunityPath(); pfx = 'FIXME'; } } return createUrl({ path: pfx + path, params: params, hash: hash }); } exports.createCommunityUrl = createCommunityUrl; /** * Convert an Arguments, Array or Object to an object * @param args * @return {Object} */ function argsToObject(args) { var _a; if (typeof args === 'string') { return _a = {}, _a[args] = args, _a; } if (!args) { return null; } var r = {}; if (typeof args.length === 'undefined') { r = args; // Plain object } else { // Arguments or Arguments object for (var i = 0; i < args.length; i++) { Object.assign(r, args[i]); } } // Remove undefined values var o = r; for (var k in o) { if (Object.prototype.hasOwnProperty.call(o, k) && typeof o[k] === 'undefined') { delete o[k]; } } return r; } exports.argsToObject = argsToObject; /** * Post process data from the XCAP json api. * * - Turns timestamps into Date objects * - Resolves references to objects * * The method modifies data in place to avoid copying. * * @param result * @return {Object} */ function postProcessApiResult(result) { var likes = result[exports.LIKES] ? result[exports.LIKES] : undefined; var votes = result[exports.VOTES] ? result[exports.VOTES] : undefined; return _postProcessApiResult(result, result[exports.RELATED_OBJECTS] || {}, likes, votes); } exports.postProcessApiResult = postProcessApiResult; function _postProcessApiResult(result, relatedObjects, likes, votes) { if (result === null) { return null; } if (!relatedObjects) { exports.logger.error('No related objects in result: ' + JSON.stringify(result)); } var d = result; for (var n in result) { if (!Object.prototype.hasOwnProperty.call(result, n) || n === exports.RELATED_OBJECTS) { // Skip } else if (n.endsWith('Ref')) { /*This disables ssr due to wrong-formating in json-response if (n === "createdDate" || n === "modifiedDate" || n === "publishDate" || n === "expiresDate") { var v = result[n]; if (typeof v === "number") { result[n] = new Date(v); } }*/ var v = result[n]; if (typeof v === 'string') { var r = relatedObjects[v]; result[n] = r; if (r === null) { exports.logger.error('Could not resolve related object ' + n + '=' + v); } else { result[n] = _postProcessApiResult(r, relatedObjects, likes); } } else if (typeof v === 'object' && v !== null && v.constructor === Array) { for (var i = 0; i < v.length; i++) { var ref = v[i]; var r = relatedObjects[ref] || ref; v[i] = r; if (r === null) { exports.logger.error('Could not resolve related object ' + ref); } } } } else if (n === 'obfuscatedReference') { //Check for likes var likeObject = (0, get_1.default)(likes, "[".concat(result[n], "]"), undefined); if (likeObject) { result.likedByCurrentUser = likeObject; } //Check for votes var voteObject = (0, get_1.default)(votes, "[".concat(result[n], "].voteByCurrentUser"), undefined); if (voteObject) { result.voteByCurrentUser = voteObject; } } // Objects, arrays else { var v = result[n]; if (v !== null && typeof v === 'object') { if (v.constructor === Array) { for (var i = 0; i < v.length; i++) { v[i] = _postProcessApiResult(v[i], relatedObjects, likes, votes); } } else { result[n] = _postProcessApiResult(v, relatedObjects, likes, votes); } } } } return d; } /** * Format the response action and field errors object to a string. * @return {String} */ function getJsonErrorText(response) { if (typeof response === 'undefined') { return 'No JSON response received'; } var t = typeof response.error; if (t === 'undefined') { return 'No JSON response received'; } if (t === 'string') { return t; } var m = ''; if (!response.error) { return m; } if (response.error.actionErrors) { for (var i = 0; i < response.error.actionErrors.length; i++) { if (i > 0) { m += '\n'; } m += response.error.actionErrors[i]; } } (0, forIn_1.default)(response.error.fieldErrors, function (value, key) { if (m.length > 0) { m += '\n'; } m += key + ': ' + value; }); return m; } exports.getJsonErrorText = getJsonErrorText; /** * Construct a new XcapJsonResult * @param resultCode * @param actionErrors * @param fieldErrors * @param data */ function _newXcapJsonResult(resultCode, actionErrors, fieldErrors, data) { var x = __assign({ __resultCode: resultCode }, data); if (actionErrors || fieldErrors) { var ae = void 0; if (typeof actionErrors === 'undefined') { ae = []; } else if (typeof actionErrors === 'string') { ae = [actionErrors]; } else { ae = actionErrors; } x.error = { actionErrors: ae, fieldErrors: fieldErrors || {} }; } else if (resultCode === 'error') { x.error = { actionErrors: ['error'] }; } return x; } exports._newXcapJsonResult = _newXcapJsonResult; /** * Construct a new API result * @param resultCode * @param data */ function newXcapJsonResult(resultCode, data) { return _newXcapJsonResult(resultCode, undefined, undefined, data); } exports.newXcapJsonResult = newXcapJsonResult; /** * Construct a new API result * @param actionErrors * @param fieldErrors */ function newXcapJsonErrorResult(actionErrors, fieldErrors) { return _newXcapJsonResult('error', actionErrors, fieldErrors); } exports.newXcapJsonErrorResult = newXcapJsonErrorResult; /** * Get a human readable type of an xcap object * @param objectOrClassName * @return {String} */ function getTypeName(objectOrClassName) { if (typeof objectOrClassName === 'string') { return typeNames[objectOrClassName]; } else { var tn = objectOrClassName['__type']; if (typeof tn === 'string') { var n = typeNames[tn]; if (n) { return n; } var i = tn.lastIndexOf('.'); return i === -1 ? tn : tn.substring(i + 1); } } return 'Unknown type'; } exports.getTypeName = getTypeName; /** * Add all extra parameters * @param params * @param moduleKey * @param moduleId (may be 0 if not used) * @param referenceId (may be 0 if not used) * @param values */ function addModuleExtraParameters(params, moduleKey, moduleId, referenceId, values) { var mk = moduleKey; if (mk.startsWith('stackend-')) { mk = mk.substring('stackend-'.length); } var x = params[mk]; if (!x) { x = {}; params[mk] = x; } var key = moduleId + '_' + referenceId; var y = x[key]; if (!y) { y = {}; x[key] = y; } Object.assign(y, values); } exports.addModuleExtraParameters = addModuleExtraParameters; /** * Load the initial store values */ function getInitialStoreValues(params) { var pl = undefined; if (params.productListings && params.productListings.length !== 0) { pl = params.productListings.map(function (q) { return JSON.stringify(q); }); } var d = undefined; if (params.moduleExtraParameters) { d = JSON.stringify(params.moduleExtraParameters); } var q = Object.assign({}, params, { productListings: pl, d: d }); delete q.moduleExtraParameters; var p = q; return getJson({ url: '/init', parameters: p, community: exports.DEFAULT_COMMUNITY, cookie: params.cookie }); } exports.getInitialStoreValues = getInitialStoreValues; /** * Log a javascript error * @param error Browser Error object * @param store */ function logJsError(error /* Error */, store) { return __awaiter(this, void 0, void 0, function () { var communityId, message, params, url, r, e_2; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!error) { return [2 /*return*/]; } communityId = 0; message = error.toString() + (error.stack ? '\n' + error.stack : ''); params = { communityId: communityId, store: store, error: error.name + (error.number ? ' (' + error.number + ')' : ''), message: message, line: error.lineNumber || -1, column: error.columnNumber || -1, url: error.fileName || '', pageUrl: document.location.href }; url = null; if (!store) return [3 /*break*/, 2]; return [4 /*yield*/, store.dispatch(getApiUrl({ url: '/js-log', community: stackend_1.STACKEND_COMMUNITY }))]; case 1: url = _a.sent(); return [3 /*break*/, 3]; case 2: url = _getServer(null) + _getContextPath(null) + '/api/js-log'; url = (0, AccessToken_1.appendAccessToken)(url); _a.label = 3; case 3: r = null; _a.label = 4; case 4: _a.trys.push([4, 6, , 7]); return [4 /*yield*/, (0, LoadJson_1.LoadJson)({ url: url, method: 'POST', parameters: params })]; case 5: r = _a.sent(); return [3 /*break*/, 7]; case 6: e_2 = _a.sent(); exports.logger.error('Failed to log: ' + JSON.stringify(params), '\nCause: ' + JSON.stringify(e_2)); return [3 /*break*/, 7]; case 7: return [2 /*return*/, r]; } }); }); } exports.logJsError = logJsError; /** * Create a hash code of a string. Roughly the same impl as java. * @param str * @returns {number} */ function getHashCode(str) { if (!str) { return 0; } return str.split('').reduce(function (prevHash, currVal) { return ((prevHash << 5) - prevHash + currVal.charCodeAt(0)) | 0; }, 0); } exports.getHashCode = getHashCode; //# sourceMappingURL=index.js.map