@kwiz/common
Version:
KWIZ common utilities and helpers for M365 platform
1,080 lines • 48.8 kB
JavaScript
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