UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

1,080 lines 48.8 kB
import { jsonClone } from "../../exports-index"; import { PushNoDuplicate, firstOrNull, makeUniqueArray, toHash } from "../../helpers/collections.base"; import { jsonStringify } from "../../helpers/json"; import { NormalizeListName, SPBasePermissions, SchemaJsonToXml, SchemaXmlToJson, extendFieldInfos } from "../../helpers/sharepoint"; import { normalizeGuid } from "../../helpers/strings"; import { SafeIfElse, isBoolean, isNotEmptyArray, isNullOrEmptyArray, isNullOrEmptyString, isNullOrUndefined, isNumber, isPromise, isString, isValidGuid } from "../../helpers/typecheckers"; import { makeServerRelativeUrl, normalizeUrl } from "../../helpers/url"; import { contentTypes, jsonTypes } from "../../types/rest.types"; import { SPBasePermissionKind } from "../../types/sharepoint.types"; import { ConsoleLogger } from "../consolelogger"; import { GetJson, GetJsonSync, longLocalCache, shortLocalCache } from "../rest"; import { GetRestBaseUrl, GetSiteUrl, LIST_EXPAND, LIST_SELECT } from "./common"; import { __fixGetListItemsResults } from "./listutils/common"; import { GetContentTypes, GetContentTypesSync, GetListsSync } from "./web"; const logger = ConsoleLogger.get("SharePoint.Rest.List"); /** returns /_api/web/lists/getById() or /_api/web/lists/getByTitle() */ export function GetListRestUrl(siteUrl, listIdOrTitle) { siteUrl = GetSiteUrl(siteUrl); let listId = GetListId(siteUrl, listIdOrTitle); let listPart = isValidGuid(listId) ? `getById('${normalizeGuid(listId)}')` : `getByTitle('${encodeURIComponent(listIdOrTitle)}')`; return GetRestBaseUrl(siteUrl) + `/web/lists/${listPart}`; } export function GetListId(siteUrl, listIdOrTitle) { if (isNullOrEmptyString(listIdOrTitle)) return null; if (isValidGuid(listIdOrTitle)) return listIdOrTitle; //Issue 7508 //When translation is enabled, and user changes list title but he is not on the same language as the site //he translates the list, but not changing its title //so REST api /lists/getByTitle will not work //instead, we need to get the list id from the web's lists collection. let lists = GetListsSync(siteUrl); var lower = listIdOrTitle.toLowerCase(); var list = firstOrNull(lists, l => l.Title.toLowerCase() === lower); return list && list.Id || null; } /** get the list ID from a list page, such as a list view or an item form */ export function GetListIdFromPageSync(siteUrl, listPageUrl) { let url = `${GetRestBaseUrl(siteUrl)}/web/getlist('${makeServerRelativeUrl(listPageUrl.split('?')[0].split('#')[0])}')?$select=id`; let response = GetJsonSync(url, null, { ...longLocalCache, jsonMetadata: jsonTypes.nometadata }); if (!isNullOrUndefined(response) && response.success) { let listId = response.result.Id; return normalizeGuid(listId); } return null; } /** ensures the site assets library exists and return its info. on errors - it will return null. */ export function EnsureAssetLibrary(siteUrl) { siteUrl = GetSiteUrl(siteUrl); let url = GetRestBaseUrl(siteUrl) + "/web/lists/EnsureSiteAssetsLibrary?$select=ID,RootFolder/Name,RootFolder/ServerRelativeUrl,RootFolder/Exists&$expand=RootFolder"; return GetJson(url, null, { method: "POST", spWebUrl: siteUrl, ...longLocalCache }).then(result => { if (result && result.d) { return { Id: result.d.Id, Name: result.d.RootFolder.Name, ServerRelativeUrl: result.d.RootFolder.ServerRelativeUrl }; } else return null; }).catch(() => null); } /** ensures the site pages library exists and return its info. on errors - it will return null. */ export async function EnsureSitePagesLibrary(siteUrl) { let url = `${GetRestBaseUrl(siteUrl)}/web/lists/EnsureSitePagesLibrary` + `?$select=ID,RootFolder/Name,RootFolder/ServerRelativeUrl,RootFolder/Exists&$expand=RootFolder`; let response = await GetJson(url, null, { method: "POST", jsonMetadata: jsonTypes.nometadata, includeDigestInPost: true, ...longLocalCache }); if (!isNullOrUndefined(response) && !isNullOrUndefined(response.RootFolder)) { return { Id: response.Id, Name: response.RootFolder.Name, ServerRelativeUrl: response.RootFolder.ServerRelativeUrl }; } return null; } export function GetSiteAssetLibrary(siteUrl, sync) { let reqUrl = `${GetRestBaseUrl(siteUrl)}/web/lists?` //Issue 1492: isSiteAssetsLibrary eq true does not work for reader users. //+ `$filter=isSiteAssetsLibrary eq true&$select=ID,RootFolder/Name,RootFolder/ServerRelativeUrl,RootFolder/Exists` + `$filter=EntityTypeName%20eq%20%27SiteAssets%27&$select=ID,RootFolder/Name,RootFolder/ServerRelativeUrl,RootFolder/Exists` + `&$expand=RootFolder`; let caller = sync ? GetJsonSync : GetJson; let result = caller(reqUrl, null, { ...longLocalCache, jsonMetadata: jsonTypes.nometadata }); let transform = (v) => { if (isNotEmptyArray(v && v.value)) { let assetLibrary = v.value[0]; return { Id: assetLibrary.Id, Name: assetLibrary.RootFolder.Name, ServerRelativeUrl: assetLibrary.RootFolder.ServerRelativeUrl }; } return null; }; if (isPromise(result)) return result.then(r => transform(r), () => null); else return result.success ? transform(result.result) : null; } /** Return the list Title */ export function GetListTitle(siteUrl, listIdOrTitle) { siteUrl = GetSiteUrl(siteUrl); return GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/Title`, null, { allowCache: true }) .then(r => { return r.d.Title; }) .catch(() => null); } /** Return the list */ export function GetList(siteUrlOrId, listIdOrTitle, options, refreshCache = false) { let siteUrl = GetSiteUrl(siteUrlOrId); if (isNullOrEmptyString(listIdOrTitle)) { return null; } return GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `?$select=${LIST_SELECT}&$expand=${LIST_EXPAND}`, null, { allowCache: true }) .then(async (r) => { let list = r.d; if (options) { let promises = []; if (options.includeViews) { promises.push(GetListViews(siteUrl, listIdOrTitle, options.viewOptions, refreshCache).then((r) => { list.Views = r; })); } if (options.includeContentTypes) { promises.push(GetListContentTypes(siteUrl, listIdOrTitle, null, refreshCache).then((r) => { list.ContentTypes = r; })); } if (options.includeRootFolder) { promises.push(GetListRootFolder(siteUrl, listIdOrTitle).then((r) => { list.RootFolder = r; })); } if (options.includeEventReceivers) { promises.push(GetListEventReceivers(siteUrl, listIdOrTitle, refreshCache).then((r) => { list.EventReceivers = r; })); } if (promises.length > 0) { await Promise.all(promises); } } if (list.EffectiveBasePermissions && (isString(list.EffectiveBasePermissions.High) || isString(list.EffectiveBasePermissions.Low))) { list.EffectiveBasePermissions = { High: Number(list.EffectiveBasePermissions.High), Low: Number(list.EffectiveBasePermissions.Low) }; } return list; }) .catch(() => null); } /** Return the list */ export function GetListSync(siteUrl, listIdOrTitle) { siteUrl = GetSiteUrl(siteUrl); if (isNullOrEmptyString(listIdOrTitle)) return null; let result = GetJsonSync(GetListRestUrl(siteUrl, listIdOrTitle) + `?$select=${LIST_SELECT}&$expand=${LIST_EXPAND}`, null, shortLocalCache); if (result && result.success) { let list = result.result.d; if (list.EffectiveBasePermissions && (isString(list.EffectiveBasePermissions.High) || isString(list.EffectiveBasePermissions.Low))) { list.EffectiveBasePermissions = { High: Number(list.EffectiveBasePermissions.High), Low: Number(list.EffectiveBasePermissions.Low) }; } return list; } else return null; } export function GetListNameSync(webUrl, listIdOrTitle) { let list = GetListSync(webUrl, listIdOrTitle); return NormalizeListName({ EntityTypeName: list.EntityTypeName, BaseType: list.BaseType }); } export async function GetListName(webUrl, listIdOrTitle) { let list = await GetList(webUrl, listIdOrTitle); return NormalizeListName({ EntityTypeName: list.EntityTypeName, BaseType: list.BaseType }); } export function GetListRootFolder(siteUrlOrId, listIdOrTitle) { let siteUrl = GetSiteUrl(siteUrlOrId); return GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/RootFolder?$Select=Name,ServerRelativeUrl`, null, longLocalCache) .then(r => { return r.d; }) .catch(() => null); } export function GetListRootFolderSync(siteUrlOrId, listIdOrTitle) { let siteUrl = GetSiteUrl(siteUrlOrId); let result = GetJsonSync(GetListRestUrl(siteUrl, listIdOrTitle) + `/RootFolder?$Select=Name,ServerRelativeUrl`, null, longLocalCache); return SafeIfElse(() => result.result.d, null); } export function GetListField(siteUrlOrId, listIdOrTitle, fieldIdOrName, refreshCache) { let siteUrl = GetSiteUrl(siteUrlOrId); var url = GetListRestUrl(siteUrl, listIdOrTitle) + `/fields`; if (isValidGuid(fieldIdOrName)) { url += `('${normalizeGuid(fieldIdOrName)}')`; } else { url += `/getbyinternalnameortitle(@u)?@u='${encodeURIComponent(fieldIdOrName)}'`; } let result = GetJson(url, null, { allowCache: refreshCache !== true }) .then(r => { return r.d; }) .catch(() => null); return result; } function _getListFieldsRequestUrl(siteUrl, listIdOrTitle) { return GetListRestUrl(siteUrl, listIdOrTitle) + `/fields`; } /** Gets ID, Title, ContentType Author, Editor, Created and Modified fields */ export function GetStandardListFields(siteUrlOrId, listIdOrTitle, refreshCache) { let fieldNames = ["ID", "Title", "ContentType", "Author", "Editor", "Created", "Modified"]; return GetListFields(siteUrlOrId, listIdOrTitle, { refreshCache: refreshCache, fieldNames: fieldNames }); } function _processGetListFields(fields, fieldNames) { if (isNullOrEmptyArray(fields)) { return fields; } let extendedFields = extendFieldInfos(fields); if (!isNullOrEmptyArray(fieldNames)) { return extendedFields.filter((extendedField) => { return fieldNames.includes(extendedField.InternalName); }); } return extendedFields; } export function GetListFields(siteUrlOrId, listIdOrTitle, options = {}) { let siteUrl = GetSiteUrl(siteUrlOrId); let url = _getListFieldsRequestUrl(siteUrl, listIdOrTitle); let restOptions = { allowCache: options.refreshCache !== true, jsonMetadata: jsonTypes.nometadata }; return GetJson(url, null, restOptions) .then((result) => { return _processGetListFields(result.value, options.fieldNames); }).catch(() => { return null; }); } export function GetListFieldsSync(siteUrlOrId, listIdOrTitle, options = {}) { let siteUrl = GetSiteUrl(siteUrlOrId); let url = _getListFieldsRequestUrl(siteUrl, listIdOrTitle); let restOptions = { allowCache: options.refreshCache !== true, jsonMetadata: jsonTypes.nometadata }; let result = GetJsonSync(url, null, restOptions); if (result.success && !isNullOrUndefined(result.result)) { return _processGetListFields(result.result.value, options.fieldNames); } return null; } export async function GetListFieldsAsHash(siteUrlOrId, listIdOrTitle, refreshCache) { let siteUrl = GetSiteUrl(siteUrlOrId); let fields = await GetListFields(siteUrl, listIdOrTitle, { refreshCache: refreshCache }); let hash = {}; if (isNotEmptyArray(fields)) { hash = toHash(fields, f => f.InternalName); } return hash; } export function GetListFieldsAsHashSync(siteUrlOrId, listIdOrTitle, refreshCache) { let siteUrl = GetSiteUrl(siteUrlOrId); let fields = GetListFieldsSync(siteUrl, listIdOrTitle, { refreshCache: refreshCache }); let hash = {}; if (isNotEmptyArray(fields)) { fields.forEach(f => { hash[f.InternalName] = f; }); } return hash; } export function GetListWorkflows(siteUrl, listIdOrTitle, refreshCache) { siteUrl = GetSiteUrl(siteUrl); return GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/workflowAssociations`, null, { allowCache: refreshCache !== true }) .then(r => { if (r && r.d && isNotEmptyArray(r.d.results)) { r.d.results.forEach(wf => { wf.BaseId = normalizeGuid(wf.BaseId); wf.Id = normalizeGuid(wf.Id); wf.ListId = normalizeGuid(wf.ListId); wf.WebId = normalizeGuid(wf.WebId); }); return r.d.results; } else return []; }) .catch(() => []); } export async function GetListEffectiveBasePermissions(siteUrlOrId, listIdOrTitle) { let siteUrl = GetSiteUrl(siteUrlOrId); let response = await GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/EffectiveBasePermissions`, null, { ...shortLocalCache }); return response.d.EffectiveBasePermissions; } export function GetListEffectiveBasePermissionsSync(siteUrlOrId, listIdOrTitle) { let siteUrl = GetSiteUrl(siteUrlOrId); let response = GetJsonSync(GetListRestUrl(siteUrl, listIdOrTitle) + `/EffectiveBasePermissions`, null, { ...shortLocalCache }); return response.result.d.EffectiveBasePermissions; } export function UserHasManagePermissions(siteUrlOrId, listIdOrTitle) { return GetListEffectiveBasePermissions(siteUrlOrId, listIdOrTitle).then((effectiveBasePermissions) => { return new SPBasePermissions(effectiveBasePermissions).has(SPBasePermissionKind.ManageLists); }).catch(() => null); } export function UserHasEditPermissions(siteUrlOrId, listIdOrTitle) { return UserHasPermissions(siteUrlOrId, listIdOrTitle, SPBasePermissionKind.EditListItems); } export function UserHasPermissions(siteUrlOrId, listIdOrTitle, permissionKind) { return GetListEffectiveBasePermissions(siteUrlOrId, listIdOrTitle).then((effectiveBasePermissions) => { return new SPBasePermissions(effectiveBasePermissions).has(permissionKind); }).catch(() => null); } export function UserHasPermissionsSync(siteUrlOrId, listIdOrTitle, permissionKind) { let effectiveBasePermissions = GetListEffectiveBasePermissionsSync(siteUrlOrId, listIdOrTitle); return new SPBasePermissions(effectiveBasePermissions).has(permissionKind); } /** create a new column and try to add it to default view. Send either Title and Type, or SchemaXml. Create with SchemaXml also adds to all content types */ export async function CreateField(siteUrl, listIdOrTitle, options) { siteUrl = GetSiteUrl(siteUrl); let finish = async (result) => { if (!result) { return null; } let internalName = result.InternalName; //we need to clear and reload the list fields cache, so call it and return our field from that collection. let fields = await GetListFields(siteUrl, listIdOrTitle, { refreshCache: true }); try { if (options.SkipAddToDefaultView !== true) { //try to add it to default view, don't wait for it GetListViews(siteUrl, listIdOrTitle).then(views => { let defaultView = firstOrNull(views, v => v.DefaultView); if (defaultView) GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/views('${defaultView.Id}')/ViewFields/addViewField('${internalName}')`, null, { method: "POST", spWebUrl: siteUrl }); }); } } catch (e) { } return firstOrNull(fields, f => f.InternalName === internalName); }; if (!isNullOrEmptyString(options.SchemaXml)) { try { let updateObject = { 'parameters': { '__metadata': { 'type': 'SP.XmlSchemaFieldCreationInformation' }, 'SchemaXml': options.SchemaXml, 'Options': options.SchemaXmlSpecificInternalName !== true ? 4 : //SP.AddFieldOptions.addToAllContentTypes 4 | 8 //SP.AddFieldOptions.addToAllContentTypes | addFieldInternalNameHint } }; let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/fields/createFieldAsXml`; let newFieldResult = await GetJson(url, JSON.stringify(updateObject)); if (!isNullOrUndefined(newFieldResult) && !isNullOrUndefined(newFieldResult.d)) { if ((!isNullOrEmptyString(options.Title) && options.Title !== newFieldResult.d.Title) || (isBoolean(options.Indexed) && options.Indexed !== newFieldResult.d.Indexed)) { let updatedField = await UpdateField(siteUrl, listIdOrTitle, newFieldResult.d.InternalName, { Title: options.Title, Indexed: options.Indexed === true }); return finish(updatedField); } } return finish(newFieldResult && newFieldResult.d); } catch { } return null; } else if (!isNullOrEmptyString(options.Title) && !isNullOrUndefined(options.Type)) { let updateObject = { '__metadata': { 'type': 'SP.Field' }, 'Title': options.Title, 'FieldTypeKind': options.Type, 'Required': options.Required === true, 'Indexed': options.Indexed === true }; if (!isNullOrEmptyString(options.ClientSideComponentId)) { updateObject.ClientSideComponentId = options.ClientSideComponentId; } if (!isNullOrEmptyString(options.ClientSideComponentProperties)) { updateObject.ClientSideComponentProperties = options.ClientSideComponentProperties; } if (!isNullOrEmptyString(options.JSLink)) { updateObject.JSLink = options.JSLink; } try { let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/fields`; let newFieldResult = await GetJson(url, JSON.stringify(updateObject)); return finish(newFieldResult && newFieldResult.d); } catch { } return null; } else { console.error("You must send either SchemaXml or Title and Type"); return null; } } /** Update field SchemaXml OR Title, only 1 update at a time supported. */ export async function UpdateField(siteUrlOrId, listIdOrTitle, fieldInternalName, options) { let siteUrl = GetSiteUrl(siteUrlOrId); let finish = async () => { //we need to clear and reload the list fields cache, so call it and return our field from that collection. let fields = await GetListFields(siteUrl, listIdOrTitle, { refreshCache: true }); return firstOrNull(fields, f => f.InternalName === fieldInternalName); }; let fields = await GetListFieldsAsHash(siteUrl, listIdOrTitle, true); let thisField = fields[fieldInternalName]; //updates can either be SchemaXml, or others. Cannot be both. let updates = { '__metadata': { 'type': 'SP.Field' } }; if (!isNullOrEmptyString(options.SchemaXml)) { updates.SchemaXml = options.SchemaXml; } else { //cannot send schema updates with other updates. if (!isNullOrEmptyString(options.Title)) { updates.Title = options.Title; } if (!isNullOrEmptyString(options.FieldType)) { updates.TypeAsString = options.FieldType; } if (isBoolean(options.Required)) { updates.Required = options.Required === true; } if (isBoolean(options.Indexed)) { updates.Indexed = options.Indexed === true; } if (!isNullOrEmptyArray(options.Choices)) { let choiceType = options.FieldType || thisField.TypeAsString; if (choiceType === "Choice" || choiceType === "MultiChoice") { updates["__metadata"]["type"] = choiceType === "Choice" ? "SP.FieldChoice" : "SP.FieldMultiChoice"; updates.Choices = { "results": options.Choices }; } else { logger.warn("Can only update 'Choices' property on 'Choice' and 'MultiChoice' field types."); } } if (isBoolean(options.Hidden)) { //this requries the CanToggleHidden to be in the schema... if not - we will need to add it before we can update this. let fields = await GetListFieldsAsHash(siteUrl, listIdOrTitle, false); let thisField = fields[fieldInternalName]; if (thisField.Hidden !== options.Hidden) { if (thisField) { if (thisField.SchemaJson.Attributes.CanToggleHidden !== "TRUE") { await UpdateField(siteUrl, listIdOrTitle, fieldInternalName, { SchemaXml: thisField.SchemaXml.replace("<Field ", `<Field CanToggleHidden="TRUE" `) }); } } updates.Hidden = options.Hidden === true; } } if (!isNullOrEmptyString(options.ClientSideComponentId)) updates.ClientSideComponentId = options.ClientSideComponentId; if (!isNullOrEmptyString(options.ClientSideComponentProperties)) updates.ClientSideComponentProperties = options.ClientSideComponentProperties; if (!isNullOrEmptyString(options.JSLink)) updates.JSLink = options.JSLink; } if (Object.keys(updates).length > 1) { return GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/fields/getbyinternalnameortitle('${fieldInternalName}')`, JSON.stringify(updates), { xHttpMethod: "MERGE" }) .then(r => { return finish(); }) .catch(() => null); } else { console.error("You must send an option to update"); return null; } } export async function ChangeTextFieldMode(siteUrlOrId, listIdOrTitle, textMode, currentField) { const newSchema = jsonClone(currentField.SchemaJson); const currentSchemaAttributes = newSchema.Attributes; switch (textMode) { case "singleline": let shouldIntermediateUpdate = false; if (currentSchemaAttributes.RichText === 'TRUE') { currentSchemaAttributes.RichText = 'FALSE'; shouldIntermediateUpdate = true; } ; if (currentSchemaAttributes.RichTextMode === 'FullHTML') { currentSchemaAttributes.RichTextMode = 'Compatible'; shouldIntermediateUpdate = true; } ; if (shouldIntermediateUpdate) { const intermediateSchema = SchemaJsonToXml(newSchema); const intermediateUpdatedField = await UpdateField(siteUrlOrId, listIdOrTitle, currentField.InternalName, { SchemaXml: intermediateSchema }); // Early exit if intermediate change failed. if (isNullOrUndefined(intermediateUpdatedField)) return false; } ; // Actual type update. currentSchemaAttributes.Type = 'Text'; delete currentSchemaAttributes.RichTextMode; delete currentSchemaAttributes.RichText; break; case "multiline": currentSchemaAttributes.Type = 'Note'; currentSchemaAttributes.RichText = 'FALSE'; currentSchemaAttributes.RichTextMode = 'Compatible'; break; case "html": currentSchemaAttributes.Type = 'Note'; currentSchemaAttributes.RichText = 'TRUE'; currentSchemaAttributes.RichTextMode = 'FullHTML'; break; } const updatedSchema = SchemaJsonToXml(newSchema); const fieldUpdated = await UpdateField(siteUrlOrId, listIdOrTitle, currentField.InternalName, { SchemaXml: updatedSchema }); // If object is null or undefined then request has failed. return !isNullOrUndefined(fieldUpdated); } export async function ChangeDatetimeFieldMode(siteUrlOrId, listIdOrTitle, includeTime, currentField) { const dateTimeFormat = 'DateTime'; const dateOnlyFormat = 'DateOnly'; const newSchema = jsonClone(currentField.SchemaJson); const fieldAttributes = newSchema.Attributes; let needUpdate = false; if (includeTime && fieldAttributes.Format === dateOnlyFormat) { needUpdate = true; fieldAttributes.Format = dateTimeFormat; } else if (!includeTime && fieldAttributes.Format === dateTimeFormat) { needUpdate = true; fieldAttributes.Format = dateOnlyFormat; } if (needUpdate) { const updatedSchema = SchemaJsonToXml(newSchema); const updateResponse = await UpdateField(siteUrlOrId, listIdOrTitle, currentField.InternalName, { SchemaXml: updatedSchema }); return !isNullOrUndefined(updateResponse); } // If an already existing format was chosen. return true; } export async function DeleteField(siteUrl, listIdOrTitle, fieldInternalName, options) { siteUrl = GetSiteUrl(siteUrl); // let finish = async () => { // //we need to clear and reload the list fields cache, so call it and return our field from that collection. // let fields = await GetListFields(siteUrl, listIdOrTitle, { refreshCache: true }); // return firstOrNull(fields, f => f.InternalName === fieldInternalName); // }; if (options && options.DeleteHiddenField) await UpdateField(siteUrl, listIdOrTitle, fieldInternalName, { Hidden: false }); return GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `/fields/getbyinternalnameortitle('${fieldInternalName}')`, null, { method: "POST", xHttpMethod: "DELETE" }) .then(r => true) .catch((e) => false); } export function GetListViews(siteUrl, listIdOrTitle, options, refreshCache = false) { siteUrl = GetSiteUrl(siteUrl); let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/views?$select=Title,Id,ServerRelativeUrl,RowLimit,Paged,ViewQuery,ListViewXml,PersonalView,MobileView,MobileDefaultView,Hidden,DefaultView,ReadOnlyView${options && options.includeViewFields ? "&$expand=ViewFields" : ""}`; return GetJson(url, null, { allowCache: refreshCache !== true, jsonMetadata: jsonTypes.nometadata }) .then(r => { let views = r.value; if (isNotEmptyArray(views)) { views.forEach(v => { v.Id = normalizeGuid(v.Id); if (options && options.includeViewFields) { v.ViewFields = v.ViewFields && v.ViewFields["Items"] && v.ViewFields["Items"] || []; } }); } return views; }) .catch(() => null); } export function GetListViewsSync(siteUrl, listIdOrTitle, options, refreshCache = false) { siteUrl = GetSiteUrl(siteUrl); let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/views?$select=Title,Id,ServerRelativeUrl,RowLimit,Paged,ViewQuery,ListViewXml,PersonalView,MobileView,MobileDefaultView,Hidden,DefaultView,ReadOnlyView${options && options.includeViewFields ? "&$expand=ViewFields" : ""}`; let response = GetJsonSync(url, null, { allowCache: refreshCache !== true, jsonMetadata: jsonTypes.nometadata }); if (response.success) { let views = response && response.result && response.result.value; if (isNotEmptyArray(views)) { views.forEach(v => { v.Id = normalizeGuid(v.Id); }); } return views; } return null; } export async function AddViewFieldToListView(siteUrl, listIdOrTitle, viewId, viewField) { return _addOrRemoveViewField(siteUrl, listIdOrTitle, viewId, viewField, "addviewfield"); } export async function RemoveViewFieldFromListView(siteUrl, listIdOrTitle, viewId, viewField) { return _addOrRemoveViewField(siteUrl, listIdOrTitle, viewId, viewField, "removeviewfield"); } async function _addOrRemoveViewField(siteUrl, listIdOrTitle, viewId, viewField, action) { siteUrl = GetSiteUrl(siteUrl); if (isNullOrEmptyString(viewField) || !isValidGuid(viewId)) { return false; } let views = await GetListViews(siteUrl, listIdOrTitle, { includeViewFields: true }); if (isNullOrEmptyArray(views)) { return false; } let view = views.filter((view) => { return normalizeGuid(view.Id) === normalizeGuid(viewId); })[0]; if (isNullOrUndefined(view)) { return false; } let hasField = view.ViewFields.includes(viewField); if (action === "addviewfield" && hasField === true) { return true; } if (action === "removeviewfield" && hasField === false) { return true; } try { let url = GetListRestUrl(siteUrl, listIdOrTitle) + `/views('${normalizeGuid(view.Id)}')/viewfields/${action}('${viewField}')`; let result = await GetJson(url, null, { method: "POST" }); if (result && result["odata.null"] === true) { return true; } } catch { } return false; } export function GetListContentTypes(siteUrl, listIdOrTitle, options, refreshCache = false) { return GetContentTypes(siteUrl, { ...(options || {}), listIdOrTitle: listIdOrTitle }, refreshCache); } export function GetListContentTypesSync(siteUrl, listIdOrTitle, options, refreshCache = false) { return GetContentTypesSync(siteUrl, { ...(options || {}), listIdOrTitle: listIdOrTitle }, refreshCache); } /** generic version. for the KWIZ forms version that supports action id call GetListFormUrlAppsWeb instead */ export function GetListFormUrl(siteUrl, listId, pageType, params) { siteUrl = GetSiteUrl(siteUrl); if (!isValidGuid(listId)) console.error('GetListFormUrl requires a list id'); let url = `${normalizeUrl(siteUrl)}/_layouts/15/listform.aspx?PageType=${pageType}&ListId=${encodeURIComponent(listId)}`; if (params) { if (!isNullOrEmptyString(params.contentTypeId)) url += `&ContentTypeId=${encodeURIComponent(params.contentTypeId)}`; if (!isNullOrEmptyString(params.itemId)) url += `&ID=${encodeURIComponent(params.itemId)}`; if (!isNullOrEmptyString(params.rootFolder)) url += `&RootFolder=${encodeURIComponent(params.rootFolder)}`; } return url; } export function GetFieldSchemaSync(siteUrl, listIdOrTitle, fieldInternalName, refreshCache) { siteUrl = GetSiteUrl(siteUrl); //ISSUE: 1516 - The get schema request will fail if the field doesn't exist in the list, so we load the fields and ensure the field //exists before requesting the schema. let fields = GetListFieldsSync(siteUrl, listIdOrTitle, { refreshCache: refreshCache, fieldNames: [fieldInternalName] }); if (isNullOrEmptyArray(fields)) { return null; } let field = fields[0]; return SchemaXmlToJson(field.SchemaXml); // let url = GetListRestUrl(siteUrl, listIdOrTitle) + `/fields/getByInternalNameOrTitle('${fieldInternalName}')?$select=SchemaXml`; // let result = GetJsonSync<{ d: { SchemaXml: string; }; }>( // url, // null, // { // ...shortLocalCache, // forceCacheUpdate: refreshCache === true // }); // if (result && result.success) { // return SchemaXmlToJson(result.result.d.SchemaXml); // } // return null; //#endregion } export async function GetFieldSchema(siteUrl, listIdOrTitle, fieldInternalName, refreshCache) { siteUrl = GetSiteUrl(siteUrl); //ISSUE: 1516 - The get schema request will fail if the field doesn't exist in the list, so we load the fields and ensure the field //exists before requesting the schema let fields = await GetListFields(siteUrl, listIdOrTitle, { refreshCache: refreshCache, fieldNames: [fieldInternalName] }); if (isNullOrEmptyArray(fields)) { return null; } let field = fields[0]; return SchemaXmlToJson(field.SchemaXml); } export async function GetListItems(siteUrl, listIdOrTitle, options) { let info = _GetListItemsInfo(siteUrl, listIdOrTitle, options); let items = []; do { let resultItems = []; let next = null; if (info.noMetadata) { let requestResult = (await GetJson(info.requestUrl, null, { allowCache: options.refreshCache !== true, jsonMetadata: options.jsonMetadata })); resultItems = requestResult.value; next = requestResult["odata.nextLink"]; } else { let requestResult = (await GetJson(info.requestUrl, null, { allowCache: options.refreshCache !== true })); resultItems = requestResult.d.results; next = requestResult.d.__next; } if (isNotEmptyArray(resultItems)) items.push(...resultItems); if (info.totalNumberOfItemsToGet > items.length) info.requestUrl = next; else info.requestUrl = null; } while (!isNullOrEmptyString(info.requestUrl)); return __fixGetListItemsResults(siteUrl, listIdOrTitle, items, options.foldersBehaviour, info.expandedLookupFields); } export function GetListItemsSync(siteUrl, listIdOrTitle, options) { let info = _GetListItemsInfo(siteUrl, listIdOrTitle, options); let items = []; do { let resultItems = []; let next = null; if (info.noMetadata) { let requestResult = GetJsonSync(info.requestUrl, null, { allowCache: true }); if (requestResult.success) { resultItems = requestResult.result.value; next = requestResult.result["odata.nextLink"]; } } else { let requestResult = GetJsonSync(info.requestUrl, null, { allowCache: true }); if (requestResult.success) { resultItems = requestResult.result.d.results; next = requestResult.result.d.__next; } } if (isNotEmptyArray(resultItems)) items.push(...resultItems); if (info.totalNumberOfItemsToGet > items.length) info.requestUrl = next; else info.requestUrl = null; } while (!isNullOrEmptyString(info.requestUrl)); return __fixGetListItemsResults(siteUrl, listIdOrTitle, items, options.foldersBehaviour, info.expandedLookupFields); } function _GetListItemsInfo(siteUrl, listIdOrTitle, options) { siteUrl = GetSiteUrl(siteUrl); let url = GetListRestUrl(siteUrl, listIdOrTitle) + `/items`; let queryParams = []; //Issue 8189 expand lookup fields let columns = []; let expand = []; let expandedLookupFields = []; options.columns.forEach(c => { if (isString(c)) columns.push(c); else { let internalName = c.InternalName; //Issue 828, 336 if (internalName.startsWith("_")) internalName = `OData_${internalName}`; let isLookupField = c.TypeAsString === "Lookup" || c.TypeAsString === "LookupMulti"; let isUserField = c.TypeAsString === "User" || c.TypeAsString === "UserMulti"; if (isLookupField || isUserField) { //ISSUE: 1519 - Added lookupField property to able to retrieve value of the additional lookup field key let lookupField = c.LookupField; if (!isNullOrEmptyString(lookupField) && isLookupField) { columns.push(`${internalName}/${lookupField}`); } //we want to expand it columns.push(`${internalName}/Title`); columns.push(`${internalName}/Id`); expand.push(internalName); expandedLookupFields.push(c); } else columns.push(internalName); } }); if (isNotEmptyArray(options.expand)) { expand.push(...options.expand); } //add the ones we need PushNoDuplicate(columns, "Id"); PushNoDuplicate(columns, "FileRef"); PushNoDuplicate(columns, "FileSystemObjectType"); queryParams.push(`$select=${encodeURIComponent(makeUniqueArray(columns).join(','))}`); if (isNotEmptyArray(expand)) queryParams.push(`$expand=${encodeURIComponent(makeUniqueArray(expand).join(','))}`); let batchSize = 2000; let limit = options.rowLimit >= 0 && options.rowLimit < batchSize ? options.rowLimit : batchSize; let totalNumberOfItemsToGet = !isNumber(options.rowLimit) || options.rowLimit < 1 ? 99999 : options.rowLimit > batchSize ? options.rowLimit : limit; if (!isNullOrEmptyString(options.$filter)) queryParams.push(`$filter=${options.$filter}`); queryParams.push(`$top=${limit}`); let requestUrl = url + (queryParams.length > 0 ? '?' + queryParams.join('&') : ''); let noMetadata = options.jsonMetadata === jsonTypes.nometadata; return { requestUrl, noMetadata, totalNumberOfItemsToGet, expandedLookupFields }; } /** Find an item by id, even if it is nested in a sub-folder */ export function FindListItemById(items, itemId) { for (let i = 0; i < items.length; i++) { let current = items[i]; if (current.Id === itemId) return current; else if (isNotEmptyArray(current.__Items)) //folder? look inside { let nestedResult = FindListItemById(current.__Items, itemId); if (!isNullOrUndefined(nestedResult)) return nestedResult; } } //not found return null; } function _getListEventReceiversRequestUrl(siteUrl, listIdOrTitle) { return GetListRestUrl(siteUrl, listIdOrTitle) + `/EventReceivers`; } export async function GetListEventReceivers(siteUrl, listIdOrTitle, refreshCache) { try { let url = _getListEventReceiversRequestUrl(siteUrl, listIdOrTitle); let response = await GetJson(url, null, { allowCache: refreshCache !== true, jsonMetadata: jsonTypes.nometadata }); return !isNullOrUndefined(response) ? response.value : null; } catch { } return null; } export async function AddListEventReceiver(siteUrl, listIdOrTitle, eventReceiverDefinition) { let newEventReceiver = { ReceiverAssembly: "", ReceiverClass: "", ...eventReceiverDefinition }; try { let url = _getListEventReceiversRequestUrl(siteUrl, listIdOrTitle); let response = await GetJson(url, JSON.stringify(newEventReceiver), { method: "POST", includeDigestInPost: true, jsonMetadata: jsonTypes.nometadata, headers: { "content-type": contentTypes.json } }); return !isNullOrUndefined(response) && isValidGuid(response.ReceiverId) ? response : null; } catch { } return null; } export async function DeleteListEventReceiver(siteUrl, listIdOrTitle, eventReceiverId) { try { let url = `${_getListEventReceiversRequestUrl(siteUrl, listIdOrTitle)}('${normalizeGuid(eventReceiverId)}')/deleteObject`; let response = await GetJson(url, null, { method: "POST", includeDigestInPost: true, jsonMetadata: jsonTypes.nometadata }); return !isNullOrUndefined(response) && response["odata.null"] === true; } catch { } return false; } export function GetListLastItemModifiedDate(siteUrl, listIdOrTitle, options) { siteUrl = GetSiteUrl(siteUrl); let endPoint = options && options.userChangesOnly ? 'LastItemUserModifiedDate' : 'LastItemModifiedDate'; let sync = options && options.sync ? true : false; let caller = sync ? GetJsonSync : GetJson; let result = caller(GetListRestUrl(siteUrl, listIdOrTitle) + `/${endPoint}`, null, { allowCache: true, //in memory only jsonMetadata: jsonTypes.nometadata, forceCacheUpdate: options && options.refreshCache === true || false }); if (isPromise(result)) return result.then(r => r.value, () => null); else return result.success ? result.result.value : null; } export async function ReloadListLastModified(siteUrl, listIdOrTitle) { await GetListLastItemModifiedDate(siteUrl, listIdOrTitle, { refreshCache: true }); //make sure we do it for both title and id, we don't know how the other callers may use this in their API if (!isValidGuid(listIdOrTitle)) { try { var listId = GetListId(siteUrl, listIdOrTitle); await GetListLastItemModifiedDate(siteUrl, listId, { refreshCache: true }); } catch (e) { } } else { try { var listTitle = await GetListTitle(siteUrl, listIdOrTitle); await GetListLastItemModifiedDate(siteUrl, listTitle, { refreshCache: true }); } catch (e) { } } } export async function ListHasUniquePermissions(siteUrl, listIdOrTitle) { let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/?$select=hasuniqueroleassignments`; let has = await GetJson(url, undefined, { allowCache: false, jsonMetadata: jsonTypes.nometadata }); return has.HasUniqueRoleAssignments === true; } export async function RestoreListPermissionInheritance(siteUrl, listIdOrTitle) { let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/ResetRoleInheritance`; await GetJson(url, undefined, { method: "POST", allowCache: false, jsonMetadata: jsonTypes.nometadata, spWebUrl: siteUrl }); } export async function BreakListPermissionInheritance(siteUrl, listIdOrTitle, clear = true) { let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/breakroleinheritance(copyRoleAssignments=${clear ? 'false' : 'true'}, clearSubscopes=true)`; await GetJson(url, undefined, { method: "POST", allowCache: false, jsonMetadata: jsonTypes.nometadata, spWebUrl: siteUrl }); } export async function AssignListPermission(siteUrl, listIdOrTitle, principalId, roleId) { let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/roleassignments/addroleassignment(principalid=${principalId},roleDefId=${roleId})`; await GetJson(url, undefined, { method: "POST", allowCache: false, jsonMetadata: jsonTypes.nometadata, spWebUrl: siteUrl }); } export async function RemoveListPermission(siteUrl, listIdOrTitle, principalId, roleId) { let url = `${GetListRestUrl(siteUrl, listIdOrTitle)}/roleassignments/removeroleassignment(principalid=${principalId},roleDefId=${roleId})`; await GetJson(url, undefined, { method: "POST", allowCache: false, jsonMetadata: jsonTypes.nometadata, spWebUrl: siteUrl }); } export async function CreateList(siteUrl, info) { let url = `${GetRestBaseUrl(siteUrl)}/web/lists`; const body = { __metadata: { type: 'SP.List' }, AllowContentTypes: false, ContentTypesEnabled: false, BaseTemplate: info.template, BaseType: info.type, Description: info.description, Title: info.title }; let newList = (await GetJson(url, jsonStringify(body))).d; normalizeGuid(newList.Id); return newList; } export async function SearchList(siteUrl, listIdOrTitle, query) { let listId = GetListId(siteUrl, listIdOrTitle); let url = `${GetRestBaseUrl(siteUrl)}/search/query?querytext='(${query}*)'&querytemplate='{searchTerms} (NormListID:${listId})'`; try { const result = await GetJson(url, null, { jsonMetadata: jsonTypes.nometadata }); logger.json(result.PrimaryQueryResult.RelevantResults, `search ${query}`); let rows = result.PrimaryQueryResult.RelevantResults.Table.Rows; const mapped = []; rows.forEach(r => { try { const rowValues = {}; r.Cells.forEach(cell => { rowValues[cell.Key] = cell.ValueType === "Edm.Int64" || cell.ValueType === "Edm.Double" ? parseInt(cell.Value, 10) : cell.ValueType === "Edm.DateTime" ? new Date(cell.Value) : cell.ValueType === "Null" ? "" : cell.Value; }); let resultPath = isNullOrEmptyString(rowValues.Path) ? "" : rowValues.Path.toLowerCase(); let indexOfId = resultPath.toLowerCase().indexOf("id="); let itemId = indexOfId >= 0 ? parseInt(resultPath.slice(indexOfId + 3)) : -1; if (itemId >= 0) rowValues.$itemId = itemId; mapped.push(rowValues); } catch (e) { return null; } }); return mapped; } catch (e) { logger.error(e); } return []; } export async function UpdateListExperience(siteUrl, listId, experience) { try { let url = GetListRestUrl(siteUrl, listId); let data = { "ListExperienceOptions": experience }; let result = await GetJson(url, JSON.stringify(data), { xHttpMethod: "MERGE", jsonMetadata: jsonTypes.nometadata }); return isNullOrEmptyString(result); } catch (e) { logger.error(e); } return false; } export async function GetListVersionSettings(siteUrlOrId, listIdOrTitle, options) { let siteUrl = GetSiteUrl(siteUrlOrId); if (isNullOrEmptyString(listIdOrTitle)) return null; try { const result = await GetJson(GetListRestUrl(siteUrl, listIdOrTitle) + `?$select=EnableMinorVersions,EnableVersioning,DraftVersionVisibility,MajorWithMinorVersionsLimit,MajorVersionLimit,EnableModeration`, null, { allowCache: options && options.refreshCache ? false : true, jsonMetadata: jsonTypes.nometadata }); return result; } catch { const result_1 = null; return result_1; } } export async function SetListVersionSettings(siteUrlOrId, listIdOrTitle, options) { let siteUrl = GetSiteUrl(siteUrlOrId); if (isNullOrEmptyString(listIdOrTitle)) return null; try { function updateProp(prop) { return GetJson(GetListRestUrl(siteUrl, listIdOrTitle), jsonStringify(prop), { method: "POST", spWebUrl: siteUrl, xHttpMethod: "MERGE", jsonMetadata: jsonTypes.nometadata }); } const currentValues = await GetListVersionSettings(siteUrlOrId, listIdOrTitle, { refreshCache: true }); //replace undefined props with current values const newSettings = { ...currentValues, ...options.newSettings }; //need to do some of the changes one by one... if (newSettings.EnableMinorVersions) { if (!currentValues.EnableMinorVersions) await updateProp({ EnableMinorVersions: true }); if (!isNullOrUndefined(newSettings.DraftVersionVisibility)) { if (currentValues.DraftVersionVisibility !== newSettings.DraftVersionVisibility) await updateProp({ DraftVersionVisibility: newSettings.DraftVersionVisibility }); } } else { if (currentValues.EnableMinorVersions) { await updateProp({ EnableMinorVersions: false }); } } if (newSettings.EnableMinorVersions && newSettings.EnableModeration) { if (!currentValues.EnableModeration) await updateProp({ EnableModeration: true }); } else { if (currentValues.EnableModeration) { await updateProp({ EnableModeration: false }); } } return await GetListVersionSettings(siteUrlOrId, listIdOrTitle, { refreshCache: true }); } catch { const result = null; return result; } } //# sourceMappingURL=list.js.map