@stackend/api
Version:
JS bindings to api.stackend.com
1,326 lines • 48.4 kB
JavaScript
;
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