@datalayer/core
Version:
[](https://datalayer.io)
1,348 lines • 114 kB
JavaScript
/*
* Copyright (c) 2023-2025 Datalayer, Inc.
* Distributed under the terms of the Modified BSD License.
*/
/************************************
*
* DEPRECATED - use useCache instead.
*
***********************************/
import { URLExt } from '@jupyterlab/coreutils';
import { BOOTSTRAP_USER_ONBOARDING, LinkedInUser, asContact, asDatasource, asInbound, asInvite, asOrganization, asOutbound, asPage, asSecret, asSpace, asSurvey, asTeam, asToken, asUsage, asUser, } from '../models';
import { useCoreStore, useIAMStore } from '../state';
import { asDisplayName, namesAsInitials, asArray } from '../utils';
import { IAMProvidersSpecs } from '../models';
import { newUserMock } from './../mocks';
import { useDatalayer } from './useDatalayer';
import { useAuthorization } from './useAuthorization';
import { useUploadForm } from './useUpload';
import { OUTPUTSHOT_PLACEHOLDER_DEFAULT_SVG } from './assets';
const CONTACTS_BY_HANDLE = new Map();
const CONTACTS_BY_ID = new Map();
const COURSES_BY_ID = new Map();
const COURSES_ENROLLMENTS_BY_ID = new Map();
const COURSES_INSTRUCTORS_BY_ID = new Map();
const DATASOURCES_BY_ID = new Map();
const INBOUNDS_BY_HANDLE = new Map();
const INBOUNDS_BY_ID = new Map();
const INVITES_BY_TOKEN = new Map();
const ORGANISATIONS_BY_HANDLE = new Map();
const ORGANISATIONS_BY_ID = new Map();
const ORGANISATIONS_FOR_USER_BY_ID = new Map();
const OUTBOUNDS_BY_ID = new Map();
const PAGES_BY_ID = new Map();
const PUBLIC_COURSES_BY_ID = new Map();
const PUBLIC_ITEMS_BY_ID = new Map();
const SCHOOLS_BY_ID = new Map();
const SECRETS_BY_ID = new Map();
const SPACES_BY_HANDLE_BY_ORGANISATION_HANDLE = new Map();
const SPACES_BY_ID_BY_ORGANISATION_ID = new Map();
const SPACES_FOR_USER_BY_HANDLE = new Map();
const SPACES_FOR_USER_BY_ID = new Map();
const SPACE_ASSIGNMENTS_BY_ID = new Map();
const SPACE_CELLS_BY_ID = new Map();
const SPACE_DATASETS_BY_ID = new Map();
const SPACE_DOCUMENTS_BY_ID = new Map();
const SPACE_ENVIRONMENTS_BY_ID = new Map();
const SPACE_EXERCISES_BY_ID = new Map();
const SPACE_ITEMS_CACHE = new Map();
const SPACE_LESSONS_BY_ID = new Map();
const SPACE_NOTEBOOKS_BY_ID = new Map();
const STUDENTS_BY_ID = new Map();
const STUDENT_ASSIGNMENTS_BY_ID = new Map();
const TEAMS_BY_HANDLE = new Map();
const TEAMS_BY_ID = new Map();
const TEAMS_BY_ORGANIZATION_BY_ID = new Map();
const TOKENS_BY_ID = new Map();
const USERS_BY_HANDLE = new Map();
const USERS_BY_ID = new Map();
const DEFAULT_SEARCH_OPTS = {
q: '*',
types: ['page'],
max: 3,
public: true,
};
/**
* Callbacks to Datalayer service.
*
* It assumes to be used within a {@link Router} component. If not
* you must set the options `loginRoute` to `null` (raise an error _Unauthorized_
* instead of redirecting to the login page).
*
* @deprecated use useCache instead.
*/
export const useCache0 = ({ loginRoute = '/login' } = {}) => {
const coreStore = useCoreStore();
const { configuration } = coreStore;
const { user } = useIAMStore();
const { requestDatalayer } = useDatalayer({ loginRoute });
const { checkIsOrganizationMember } = useAuthorization();
// Hook for notebook upload/creation
const { isLoading: notebookUploadLoading, uploadAndSubmit: uploadNotebook, progress: notebookUploadProgress, reset: resetNotebookUpload, } = useUploadForm(`${coreStore.configuration.spacerRunUrl}/api/spacer/v1/notebooks`);
// Caches -------------------------------------------------------------------
const clearAllCaches = () => {
CONTACTS_BY_HANDLE.clear();
CONTACTS_BY_ID.clear();
COURSES_BY_ID.clear();
COURSES_ENROLLMENTS_BY_ID.clear();
COURSES_INSTRUCTORS_BY_ID.clear();
DATASOURCES_BY_ID.clear();
INBOUNDS_BY_HANDLE.clear();
INBOUNDS_BY_ID.clear();
INVITES_BY_TOKEN.clear();
ORGANISATIONS_BY_HANDLE.clear();
ORGANISATIONS_BY_ID.clear();
ORGANISATIONS_FOR_USER_BY_ID.clear();
PAGES_BY_ID.clear();
OUTBOUNDS_BY_ID.clear();
PUBLIC_COURSES_BY_ID.clear();
PUBLIC_ITEMS_BY_ID.clear();
SCHOOLS_BY_ID.clear();
SECRETS_BY_ID.clear();
SPACES_BY_HANDLE_BY_ORGANISATION_HANDLE.clear();
SPACES_BY_ID_BY_ORGANISATION_ID.clear();
SPACES_FOR_USER_BY_HANDLE.clear();
SPACES_FOR_USER_BY_ID.clear();
SPACE_ASSIGNMENTS_BY_ID.clear();
SPACE_CELLS_BY_ID.clear();
SPACE_DATASETS_BY_ID.clear();
SPACE_DOCUMENTS_BY_ID.clear();
SPACE_ENVIRONMENTS_BY_ID.clear();
SPACE_EXERCISES_BY_ID.clear();
SPACE_ITEMS_CACHE.clear();
SPACE_LESSONS_BY_ID.clear();
SPACE_NOTEBOOKS_BY_ID.clear();
STUDENTS_BY_ID.clear();
STUDENT_ASSIGNMENTS_BY_ID.clear();
TOKENS_BY_ID.clear();
USERS_BY_HANDLE.clear();
USERS_BY_ID.clear();
};
const clearCachedItems = () => {
PUBLIC_ITEMS_BY_ID.clear();
SPACE_ASSIGNMENTS_BY_ID.clear();
SPACE_DATASETS_BY_ID.clear();
SPACE_DOCUMENTS_BY_ID.clear();
SPACE_ENVIRONMENTS_BY_ID.clear();
SPACE_EXERCISES_BY_ID.clear();
SPACE_ITEMS_CACHE.clear();
SPACE_ITEMS_CACHE.clear();
SPACE_LESSONS_BY_ID.clear();
SPACE_NOTEBOOKS_BY_ID.clear();
SPACE_CELLS_BY_ID.clear();
SPACE_CELLS_BY_ID.clear();
};
// Authentication ------------------------------------------------------------------
const login = (handle, password) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/login`,
method: 'POST',
body: {
handle,
password,
},
});
};
const logout = () => {
clearAllCaches();
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/logout`,
method: 'GET',
});
};
// Join ------------------------------------------------------------------
const requestJoin = (handle, email, firstName, lastName, password, passwordConfirm) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/join/request`,
method: 'POST',
body: {
handle,
email,
firstName,
lastName,
password,
passwordConfirm,
},
});
};
const requestJoinToken = (handle, email, firstName, lastName, password, passwordConfirm) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/join/request/token`,
method: 'POST',
body: {
handle,
email,
firstName,
lastName,
password,
passwordConfirm,
},
});
};
const joinWithInvite = (formValues, token) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/join/invites/token`,
method: 'POST',
body: {
...formValues,
token,
},
});
};
const confirmJoinWithToken = (userHandle, token) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/join/users/${userHandle}/tokens/${token}`,
method: 'GET',
});
};
// Password ------------------------------------------------------------------
const changePassword = (handle, password, passwordConfirm) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/password`,
method: 'PUT',
body: {
handle,
password,
passwordConfirm,
},
});
};
const createTokenForPasswordChange = (handle, password, passwordConfirm) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/password/token`,
method: 'POST',
body: {
handle,
password,
passwordConfirm,
},
});
};
const confirmPassworkWithToken = (userHandle, token) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/password/confirm/users/${userHandle}/tokens/${token}`,
method: 'PUT',
});
};
// OAuth2 -------------------------------------------------------------------
const getOAuth2AuthorizationURL = async (queryArgs) => {
return requestDatalayer({
url: URLExt.join(configuration.iamRunUrl, 'api/iam/v1/oauth2/authz/url') +
URLExt.objectToQueryString(queryArgs),
notifyOnError: false,
});
};
const getOAuth2AuthorizationLinkURL = async (queryArgs) => {
return requestDatalayer({
url: URLExt.join(configuration.iamRunUrl, 'api/iam/v1/oauth2/authz/url/link') + URLExt.objectToQueryString(queryArgs),
});
};
// IAM Providers ------------------------------------------------------------
const getGitHubProfile = async (accessToken) => {
return fetch(IAMProvidersSpecs.GitHub.userInfoURL, {
method: 'GET',
headers: {
Accept: 'application/vnd.github+json',
Authorization: `Bearer ${accessToken}`,
'X-GitHub-Api-Version': '2022-11-28',
},
}).then(resp => resp.json());
};
/*
* CORS is not supported @see https://github.com/linkedin-developers/linkedin-api-js-client
*/
const getLinkedinProfile = async (accessToken) => {
return proxyGET(IAMProvidersSpecs.LinkedIn.userInfoURL, accessToken).then(resp => {
return new LinkedInUser(resp.response);
});
};
const postLinkedinShare = async (linkedinUser, postText, accessToken) => {
const POST_SHARE_REQUEST = {
author: linkedinUser.getUrn(),
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: postText,
},
shareMediaCategory: 'NONE',
},
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
},
};
return proxyPOST(IAMProvidersSpecs.LinkedIn.postShareURL, POST_SHARE_REQUEST, accessToken);
};
const postLinkedinShareWithUpload = async (linkedinUser, postText, uploadObject, accessToken) => {
const REGISTER_UPLOAD_REQUEST = {
registerUploadRequest: {
recipes: ['urn:li:digitalmediaRecipe:feedshare-image'],
owner: linkedinUser.getUrn(),
serviceRelationships: [
{
relationshipType: 'OWNER',
identifier: 'urn:li:userGeneratedContent',
},
],
},
};
return proxyPOST(IAMProvidersSpecs.LinkedIn.registerUploadURL, REGISTER_UPLOAD_REQUEST, accessToken).then(registerUploadReponse => {
/*
{
"value": {
"uploadMechanism": {
"com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest": {
"headers": {},
"uploadUrl": "https://api.linkedin.com/mediaUpload/C5522AQGTYER3k3ByHQ/feedshare-uploadedImage/0?ca=vector_feedshare&cn=uploads&m=AQJbrN86Zm265gAAAWemyz2pxPSgONtBiZdchrgG872QltnfYjnMdb2j3A&app=1953784&sync=0&v=beta&ut=2H-IhpbfXrRow1"
}
},
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:C5522AQGTYER3k3ByHQ,urn:li:digitalmediaMediaArtifactClass:feedshare-uploadedImage)",
"asset": "urn:li:digitalmediaAsset:C5522AQGTYER3k3ByHQ"
}
}
*/
const asset = registerUploadReponse.response.value.asset;
const uploadURL = registerUploadReponse.response.value.uploadMechanism['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest'].uploadUrl;
const UPLOAD_OBJECT_REQUEST = {
uploadURL: uploadURL,
content: uploadObject,
userURN: linkedinUser.getUrn(),
};
return proxyPUT(uploadURL, UPLOAD_OBJECT_REQUEST, accessToken).then(resp => {
const share = {
author: linkedinUser.getUrn(),
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: postText,
},
shareMediaCategory: 'IMAGE',
media: [
{
status: 'READY',
description: {
text: 'Datalayer Notebook',
},
media: asset,
title: {
text: 'Datalayer Notebook',
},
},
],
},
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',
},
};
return proxyPOST(IAMProvidersSpecs.LinkedIn.postShareURL, share, accessToken);
});
});
};
// Proxy -------------------------------------------------------------------
const proxyGET = async (url, token) => {
return requestDatalayer({
url: URLExt.join(configuration.iamRunUrl, 'api/iam/v1/proxy/request'),
method: 'POST',
body: {
request_method: 'GET',
request_url: url,
request_token: token,
},
});
};
const proxyPOST = async (url, body, token) => {
return requestDatalayer({
url: URLExt.join(configuration.iamRunUrl, 'api/iam/v1/proxy/request'),
method: 'POST',
body: {
request_method: 'POST',
request_url: url,
request_token: token,
request_body: body,
},
});
};
const proxyPUT = async (url, body, token) => {
return requestDatalayer({
url: URLExt.join(configuration.iamRunUrl, 'api/iam/v1/proxy/request'),
method: 'POST',
body: {
request_method: 'PUT',
request_url: url,
request_token: token,
request_body: body,
},
});
};
// Waiting List -------------------------------------------------------------
const registerToWaitingList = (formData) => {
requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/waitinglist/register`,
method: 'POST',
body: {
firstName: formData.firstName,
lastName: formData.lastName,
email: formData.email,
affiliation: formData.affiliation || '',
},
})
.then(resp => {
// Special case, make the error very explicit to the user...
if (!resp.success) {
alert('Sorry, something has gone wrong... Please send an email to eric@datalayer.io to register to the waiting list.');
}
})
.catch(err => {
// Special case, make the error very explicit to the user...
console.error(err);
alert('Sorry, something has gone wrong... Please send an email to eric@datalayer.io to register to the waiting list.');
});
};
// Profile ------------------------------------------------------------------
const getMe = async (token) => {
const resp = await requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/me`,
method: 'GET',
token,
});
const me = resp.me;
if (me) {
const user = asUser(me);
return user;
}
return null;
};
const updateMe = (email, firstName, lastName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/me`,
method: 'PUT',
body: {
email,
firstName,
lastName,
},
});
};
const whoami = () => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/whoami`,
method: 'GET',
});
};
const requestEmailUpdate = email => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/me/email`,
method: 'PUT',
body: {
email,
},
});
};
const confirmEmailUpdate = token => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/me/email`,
method: 'POST',
body: {
token,
},
});
};
// Onboarding ---------------------------------------------------------------
const updateUserOnboarding = (onboarding) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/onboardings`,
method: 'PUT',
body: {
onboarding,
},
});
};
// Settings -----------------------------------------------------------------
const updateUserSettings = (userId, settings) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/users/${userId}/settings`,
method: 'PUT',
body: {
aiagents_url_s: settings.aiAgentsUrl,
can_invite_b: settings.canInvite || false,
},
});
};
// Pages ------------------------------------------------------------------
const toPage = (s) => {
if (s) {
const page = asPage(s);
PAGES_BY_ID.set(s.uid, page);
return page;
}
};
const createPage = (page) => {
return requestDatalayer({
url: `${configuration.libraryRunUrl}/api/library/v1/pages`,
method: 'POST',
body: { ...page },
}).then(resp => {
if (resp.success) {
if (resp.page) {
const pageId = resp.page.uid;
PAGES_BY_ID.set(pageId, {
...page,
id: pageId,
});
}
}
return resp;
});
};
const updatePage = (page) => {
return requestDatalayer({
url: `${configuration.libraryRunUrl}/api/library/v1/pages/${page.id}`,
method: 'PUT',
body: {
name: page.name,
description: page.description,
tags: page.tags,
},
}).then(resp => {
if (resp.success) {
if (resp.page) {
toPage(resp.page);
}
}
return resp;
});
};
const deletePage = (page) => {
return requestDatalayer({
url: `${configuration.libraryRunUrl}/api/library/v1/pages/${page.id}`,
method: 'DELETE',
});
};
const getPage = (pageId) => PAGES_BY_ID.get(pageId);
const clearCachedPages = () => PAGES_BY_ID.clear();
const refreshPage = (pageId) => {
return requestDatalayer({
url: `${configuration.libraryRunUrl}/api/library/v1/pages/${pageId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
if (resp.page) {
toPage(resp.page);
}
}
return resp;
});
};
const getPages = () => {
return Array.from(PAGES_BY_ID.values());
};
const refreshPages = () => {
return requestDatalayer({
url: `${configuration.libraryRunUrl}/api/library/v1/pages`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const pages = resp.pages;
if (pages) {
PAGES_BY_ID.clear();
pages.forEach(page => {
toPage(page);
});
}
}
return resp;
});
};
// Datasources ------------------------------------------------------------------
const toDatasource = (s) => {
if (s) {
const datasource = asDatasource(s);
DATASOURCES_BY_ID.set(s.uid, datasource);
return datasource;
}
};
const createDatasource = (datasource) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/datasources`,
method: 'POST',
body: { ...datasource },
}).then(resp => {
if (resp.success) {
if (resp.datasource) {
toDatasource(resp.datasource);
}
}
return resp;
});
};
const updateDatasource = (datasource) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/datasources/${datasource.id}`,
method: 'PUT',
body: { ...datasource },
}).then(resp => {
if (resp.success) {
if (resp.datasource) {
toDatasource(resp.datasource);
}
}
return resp;
});
};
const getDatasource = (datasourceId) => DATASOURCES_BY_ID.get(datasourceId);
const clearCachedDatasources = () => DATASOURCES_BY_ID.clear();
const refreshDatasource = (datasourceId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/datasources/${datasourceId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
if (resp.datasource) {
toDatasource(resp.datasource);
}
}
return resp;
});
};
const getDatasources = () => {
return Array.from(DATASOURCES_BY_ID.values());
};
const refreshDatasources = () => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/datasources`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const datasources = resp.datasources;
if (datasources) {
SECRETS_BY_ID.clear();
datasources.forEach(datasource => {
toDatasource(datasource);
});
}
}
return resp;
});
};
// Secrets ------------------------------------------------------------------
const toSecret = (s) => {
if (s) {
const secret = asSecret(s);
SECRETS_BY_ID.set(s.uid, secret);
return secret;
}
};
const createSecret = (secret) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/secrets`,
method: 'POST',
body: { ...secret },
}).then(resp => {
if (resp.success) {
if (resp.secret) {
toSecret(resp.secret);
}
}
return resp;
});
};
const updateSecret = (secret) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/secrets/${secret.id}`,
method: 'PUT',
body: { ...secret },
}).then(resp => {
if (resp.success) {
if (resp.secret) {
toSecret(resp.secret);
}
}
return resp;
});
};
const deleteSecret = (secret) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/secrets/${secret.id}`,
method: 'DELETE',
});
};
const getSecret = (secretId) => SECRETS_BY_ID.get(secretId);
const clearCachedSecrets = () => SECRETS_BY_ID.clear();
const refreshSecret = (secretId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/secrets/${secretId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
if (resp.secret) {
toSecret(resp.secret);
}
}
return resp;
});
};
const getSecrets = () => {
return Array.from(SECRETS_BY_ID.values());
};
const refreshSecrets = () => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/secrets`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const secrets = resp.secrets;
if (secrets) {
SECRETS_BY_ID.clear();
secrets.forEach(secret => {
toSecret(secret);
});
}
}
return resp;
});
};
// Tokens ------------------------------------------------------------------
const toToken = (s) => {
if (s) {
const token = asToken(s);
TOKENS_BY_ID.set(s.uid, token);
return token;
}
};
const createToken = (token) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/tokens`,
method: 'POST',
body: {
...token,
expirationDate: token.expirationDate.getTime(),
},
}).then(resp => {
if (resp.success) {
if (resp.token) {
toToken(resp.token);
}
}
return resp;
});
};
const updateToken = (token) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/tokens/${token.id}`,
method: 'PUT',
body: { ...token },
}).then(resp => {
if (resp.success) {
if (resp.token) {
toToken(resp.token);
}
}
return resp;
});
};
const getToken = (tokenId) => TOKENS_BY_ID.get(tokenId);
const clearCachedTokens = () => TOKENS_BY_ID.clear();
const refreshToken = (tokenId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/tokens/${tokenId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
if (resp.token) {
toToken(resp.token);
}
}
return resp;
});
};
const getTokens = () => {
return Array.from(TOKENS_BY_ID.values());
};
const refreshTokens = () => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/tokens`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const tokens = resp.tokens;
if (tokens) {
TOKENS_BY_ID.clear();
tokens.forEach(token => {
toToken(token);
});
}
}
return resp;
});
};
// Layout -------------------------------------------------------------------
const refreshLayout = (accountHandle, spaceHandle, user) => {
return requestDatalayer({
url: `${configuration.spacerRunUrl}/api/spacer/v1/layouts/accounts/${accountHandle}${spaceHandle !== undefined ? '/spaces/' + spaceHandle : ''}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
if (resp.user) {
toUser(resp.user);
}
let organization = undefined;
if (resp.organization) {
organization = toOrganization(resp.organization);
if (user && checkIsOrganizationMember(user, organization)) {
ORGANISATIONS_FOR_USER_BY_ID.set(organization.id, organization);
}
}
if (resp.space) {
const space = toSpace(resp.space);
if (organization) {
let osById = SPACES_BY_ID_BY_ORGANISATION_ID.get(organization.id);
if (!osById) {
osById = new Map();
SPACES_BY_ID_BY_ORGANISATION_ID.set(organization.id, osById);
}
osById.set(space.id, space);
let osByHandle = SPACES_BY_HANDLE_BY_ORGANISATION_HANDLE.get(organization.handle);
if (!osByHandle) {
osByHandle = new Map();
SPACES_BY_HANDLE_BY_ORGANISATION_HANDLE.set(organization.handle, osByHandle);
}
osByHandle.set(space.handle, space);
}
else {
SPACES_FOR_USER_BY_HANDLE.set(space.handle, space);
SPACES_FOR_USER_BY_ID.set(space.id, space);
}
}
}
return resp;
});
};
// Invites -------------------------------------------------------------------
const requestInvite = (firstName, lastName, email, socialUrl) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/invites/request`,
method: 'POST',
body: {
first_name: firstName,
last_name: lastName,
email: email,
social_url: socialUrl,
},
});
};
const sendInvite = (invite) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/invites`,
method: 'POST',
body: {
email: invite.to.email,
firstName: invite.to.firstName,
lastName: invite.to.lastName,
message: invite.message,
brand: invite.brand,
},
});
};
const getInvite = (token) => INVITES_BY_TOKEN.get(token);
const clearCachedInvites = () => INVITES_BY_TOKEN.clear();
const refreshInvite = (token) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/invites/tokens/${token}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const i = resp.invite;
if (i) {
const invite = asInvite(i);
if (invite.token) {
INVITES_BY_TOKEN.set(invite.token, invite);
}
}
}
return resp;
});
};
const getInvites = () => {
return Array.from(INVITES_BY_TOKEN.values());
};
const refreshInvites = (accountId) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/invites/users/${accountId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
resp.invites.forEach(i => {
const invite = asInvite(i);
if (invite.token) {
INVITES_BY_TOKEN.set(invite.token, invite);
}
});
}
return resp;
});
};
const putInvite = (token) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/invites/tokens/${token}`,
method: 'PUT',
});
};
// Accounts -------------------------------------------------------------------
const refreshAccount = (accountHandle) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/accounts/${accountHandle}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
if (resp.user) {
toUser(resp.user);
}
if (resp.organization) {
toOrganization(resp.organization);
}
}
return resp;
});
};
// Contacts ---------------------------------------------------------------------
const toContact = (c) => {
if (c) {
const contact = asContact(c);
CONTACTS_BY_ID.set(contact.id, contact);
CONTACTS_BY_HANDLE.set(contact.handle, contact);
return contact;
}
};
const getContactById = (contactId) => CONTACTS_BY_ID.get(contactId);
const getContactByHandle = (contactHandle) => CONTACTS_BY_HANDLE.get(contactHandle);
const createContact = (contact) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts`,
method: 'POST',
body: {
contact,
},
}).then(resp => {
if (resp.success) {
toContact(resp.contact);
}
return resp;
});
};
const updateContact = (contactId, contact) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}`,
method: 'PUT',
body: {
contact,
},
}).then(resp => {
if (resp.success) {
toContact(resp.contact);
}
return resp;
});
};
const refreshContact = (contactId) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
toContact(resp.contact);
}
return resp;
});
};
const searchContacts = (query) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/search`,
method: 'POST',
body: {
query,
},
}).then(resp => {
if (resp.success) {
const contacts = resp.contacts.map(contact => toContact(contact));
resp.contacts = contacts;
}
return resp;
});
};
const assignTagToContact = (contactId, tagName) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}/tags/${tagName}`,
method: 'POST',
});
};
const unassignTagFromContact = (contactId, tagName) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}/tags/${tagName}`,
method: 'DELETE',
});
};
const deleteContact = (contactId) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}`,
method: 'DELETE',
});
};
const sendInviteToContact = (contact, message) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/invites`,
method: 'POST',
body: {
contactId: contact.id,
message,
},
});
};
// Contacts Enrich ----------------------------------------------------------
const enrichContactEmail = (contactId, useDomain) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}/enrich/email?useDomain=${useDomain}`,
method: 'GET',
});
};
const enrichContactLinkedin = contactId => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contactId}/enrich/linkedin`,
method: 'GET',
});
};
const sendLinkedinConnectionRequest = (contact, message) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/contacts/${contact.id}/connect/linkedin`,
method: 'POST',
body: {
message,
},
}).then(resp => {
if (resp.success) {
toContact(resp.contact);
}
return resp;
});
};
// Contacts Links -----------------------------------------------------------
const linkUserWithContact = (userId, contactId) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/users/${userId}/contacts/${contactId}/link`,
method: 'POST',
});
};
const unlinkUserFromContact = (userId, contactId) => {
return requestDatalayer({
url: `${configuration.growthRunUrl}/api/growth/v1/users/${userId}/contacts/${contactId}/link`,
method: 'DELETE',
});
};
// Users --------------------------------------------------------------------
const toUser = (u) => {
if (u) {
const user = asUser(u);
USERS_BY_ID.set(user.id, user);
USERS_BY_HANDLE.set(user.handle, user);
return user;
}
};
const getUser = (id) => USERS_BY_ID.get(id);
const getUserByHandle = (handle) => USERS_BY_HANDLE.get(handle);
const refreshUser = (userId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/users/${userId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
toUser(resp.user);
}
return resp;
});
};
const searchUsers = (namingPattern) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/users/search`,
method: 'POST',
body: {
namingPattern,
},
}).then(resp => {
if (resp.success) {
const users = resp.users.map(user => toUser(user));
resp.users = users;
}
return resp;
});
};
// User Roles ---------------------------------------------------------------
const assignRoleToUser = (userId, roleName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/users/${userId}/roles/${roleName}`,
method: 'POST',
});
};
const unassignRoleFromUser = (userId, roleName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/users/${userId}/roles/${roleName}`,
method: 'DELETE',
});
};
// Organizations -------------------------------------------------------------------
const toOrganization = (org) => {
const organization = asOrganization(org);
ORGANISATIONS_BY_ID.set(organization.id, organization);
ORGANISATIONS_BY_HANDLE.set(organization.handle, organization);
return organization;
};
const createOrganization = (organization) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations`,
method: 'POST',
body: {
handle: organization.handle,
name: organization.name,
description: organization.description,
},
}).then(resp => {
const organization = toOrganization(resp.organization);
ORGANISATIONS_FOR_USER_BY_ID.set(organization.id, organization);
return resp;
});
};
const getOrganizationById = (organizationId) => ORGANISATIONS_BY_ID.get(organizationId);
const getOrganizationByHandle = (organizationHandle) => ORGANISATIONS_BY_HANDLE.get(organizationHandle);
const clearCachedOrganizations = () => {
ORGANISATIONS_BY_HANDLE.clear();
ORGANISATIONS_BY_ID.clear();
ORGANISATIONS_FOR_USER_BY_ID.clear();
};
const refreshOrganization = (user, organizationId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organizationId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const org = resp.organization;
if (org) {
const organization = toOrganization(org);
if (checkIsOrganizationMember(user, organization)) {
ORGANISATIONS_FOR_USER_BY_ID.set(organizationId, organization);
}
}
}
return resp;
});
};
const updateOrganization = (organization) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organization.id}`,
method: 'PUT',
body: {
name: organization.name,
description: organization.description,
},
}).then(resp => {
if (resp.success) {
const org = getOrganizationById(organization.id);
if (org) {
org.name = organization.name;
org.description = organization.description;
}
}
return resp;
});
};
const getUserOrganizations = () => Array.from(ORGANISATIONS_FOR_USER_BY_ID.values());
const getUserOrganizationById = (organizationId) => ORGANISATIONS_FOR_USER_BY_ID.get(organizationId);
const refreshUserOrganizations = (user) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations`,
method: 'GET',
}).then(resp => {
if (resp.success) {
resp.organizations.forEach(org => {
const organization = toOrganization(org);
if (checkIsOrganizationMember(user, organization)) {
ORGANISATIONS_FOR_USER_BY_ID.set(organization.id, organization);
}
});
}
return resp;
});
};
const addMemberToOrganization = (organizationId, userId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organizationId}/members/${userId}`,
method: 'POST',
});
};
const removeMemberFromOrganization = (organizationId, userId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organizationId}/members/${userId}`,
method: 'DELETE',
});
};
const addRoleToOrganizationMember = (organizationId, userId, roleName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organizationId}/members/${userId}/roles/${roleName}`,
method: 'POST',
});
};
const removeRoleFromOrganizationMember = (organizationId, userId, roleName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organizationId}/members/${userId}/roles/${roleName}`,
method: 'DELETE',
});
};
// Teams -------------------------------------------------------------------
const toTeam = (org, organizationId) => {
const team = asTeam(org, organizationId);
TEAMS_BY_ID.set(team.id, team);
TEAMS_BY_HANDLE.set(team.handle, team);
return team;
};
const createTeam = (team, organization) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams`,
method: 'POST',
body: {
handle: team.handle,
name: team.name,
description: team.description,
organizationId: organization.id,
},
}).then(resp => {
const team = toTeam(resp.team, organization.id);
TEAMS_BY_HANDLE.set(team.handle, team);
TEAMS_BY_ID.set(team.id, team);
return resp;
});
};
const getTeamById = (teamId) => TEAMS_BY_ID.get(teamId);
const getTeamByHandle = (teamHandle) => TEAMS_BY_HANDLE.get(teamHandle);
const clearCachedTeams = () => {
TEAMS_BY_HANDLE.clear();
TEAMS_BY_ID.clear();
};
const refreshTeam = (teamId, organizationId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams/${teamId}`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const t = resp.team;
if (t) {
const team = toTeam(t, organizationId);
TEAMS_BY_HANDLE.set(team.handle, team);
TEAMS_BY_ID.set(team.id, team);
}
}
return resp;
});
};
const updateTeam = (team) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams/${team.id}`,
method: 'PUT',
body: {
name: team.name,
description: team.description,
},
}).then(resp => {
if (resp.success) {
const t = resp.team;
if (t) {
const tt = toTeam(t, team.organization.id);
TEAMS_BY_HANDLE.set(team.handle, tt);
TEAMS_BY_ID.set(team.id, tt);
}
}
return resp;
});
};
const getTeamsByOrganizationId = (organizationId) => TEAMS_BY_ORGANIZATION_BY_ID.get(organizationId);
const refreshTeams = (organizationId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/${organizationId}/teams`,
method: 'GET',
}).then(resp => {
if (resp.success) {
const teams = resp.teams.map(t => {
const team = toTeam(t, organizationId);
TEAMS_BY_HANDLE.set(team.handle, team);
TEAMS_BY_ID.set(team.id, team);
return team;
});
TEAMS_BY_ORGANIZATION_BY_ID.set(organizationId, teams);
}
return resp;
});
};
const addMemberToTeam = (teamId, userId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams/${teamId}/members/${userId}`,
method: 'POST',
});
};
const removeMemberFromTeam = (teamId, userId) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams/${teamId}/members/${userId}`,
method: 'DELETE',
});
};
const addRoleToTeamMember = (teamId, userId, roleName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams/${teamId}/members/${userId}/roles/${roleName}`,
method: 'POST',
});
};
const removeRoleFromTeamMember = (teamId, userId, roleName) => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/teams/${teamId}/members/${userId}/roles/${roleName}`,
method: 'DELETE',
});
};
// Schools -------------------------------------------------------------------
const getSchools = () => {
return Array.from(SCHOOLS_BY_ID.values());
};
const refreshSchools = () => {
return requestDatalayer({
url: `${configuration.iamRunUrl}/api/iam/v1/organizations/schools`,
method: 'GET',
}).then(resp => {
if (resp.success) {
resp.orgs.forEach(s => {
const dean = undefined;
const students = new Array();
const members = new Array();
const courses = new Array();
const school = {
id: s.uid,
type: 'school',
handle: s.handle_s,
name: s.name_t,
description: s.description_t,
dean,
members,
students,
courses,
public: s.public_b,
creationDate: new Date(s.creation_ts_dt),
setMembers(members) {
this.members = members;
},
};
SCHOOLS_BY_ID.set(school.id, school);
});
}
return resp;
});
};
// Spaces -------------------------------------------------------------------
const toSpace = (spc) => {
const space = asSpace(spc);
r