javascript

Sharepoint List get list fields in console

On 20/02/2025


function getUrlParams() {
  const params = new URLSearchParams(window.location.search);
  const urlParams = {};
  for (const [key, value] of params.entries()) {
    urlParams[key] = value;
  }
  return urlParams;
}
async function getSharePointListFields(listId) {
  const apiUrl = `${_spPageContextInfo.webAbsoluteUrl}/_api/web/lists(guid'${listId}')/fields?$select=InternalName&$orderby=InternalName&$filter=Hidden eq false`;

  try {
    const response = await fetch(apiUrl, {
      method: 'GET',
      headers: {
        'Accept': 'application/json;odata=verbose',
        'Content-Type': 'application/json;odata=verbose',
      },
      credentials: 'include', // Include credentials for authenticated requests
    });

    if (!response.ok) {
      throw new Error('Network response was not ok');
    }

    const data = await response.json();
    return data.d.results;
  } catch (error) {
    console.error('Error fetching SharePoint list fields:', error);
    return [];
  }
}
// Usage
const urlParams = getUrlParams();
const listId = urlParams.List;
window.Fields = "";
if (listId) {
  getSharePointListFields(listId).then((fields) => {
    console.log('SharePoint List Fields:', fields);
    // Process the fields as needed
	fields.map((f) => {
	window.Fields += `${f.InternalName}\n`;
		
	});
    console.log(window.Fields);
  });
} else {
  console.error('List ID not found in URL parameters');
}


Understanding Regular Expressions RegEX Javascript

On 04/02/2025

Understanding Regular Expressions (RegEX) in JavaScript

Regular expressions (RegEX) in JavaScript are a powerful tool for searching and manipulating strings. They allow you to define complex search patterns and apply them to text strings. Here is a detailed explanation of how they work:

1. Creating a Regular Expression

In JavaScript, you can create a regular expression in two ways:

  • Literal: Using slashes /.
  • RegExp Object: Using the RegExp constructor.

Literal Example:

let regex = /pattern/;

RegExp Object Example:

let regex = new RegExp("pattern");

2. Using Regular Expressions

Regular expressions can be used with several string methods and RegExp object methods.

String Methods:

  • search(): Searches for a match and returns the index of the first occurrence.
  • match(): Searches for all matches and returns an array of results.
  • replace(): Replaces matches with another string.
  • split(): Splits a string into an array based on matches.

RegExp Object Methods:

  • test(): Checks if a string contains a match.
  • exec(): Searches for a match and returns an array of information about the match.

3. Practical Examples

Search for a Match:

let str = "Hello, world!"; let regex = /world/; let result = str.search(regex); // Returns 7

Find All Matches:

 


let str = "Hello, world! Hello, everyone!"; 
let regex = /Hello/g; // The 'g' flag means global, to find all occurrences 
let result = str.match(regex); // Returns ["Hello", "Hello"] 

 

Replace Matches:

let str = "Hello, world!"; let regex = /world/; let result = str.replace(regex, "universe"); // Returns "Hello, universe!"

Split a String:

let str = "one,two,three"; let regex = /,/; let result = str.split(regex); // Returns ["one", "two", "three"]

Test for a Match:

let str = "Hello, world!"; let regex = /world/; let result = regex.test(str); // Returns true

Use exec():

let str = "Hello, world!"; let regex = /world/; let result = regex.exec(str); // Returns ["world", index: 7, input: "Hello, world!", groups: undefined]

4. Flags

Regular expressions can include flags to modify their behavior:

  • i: Case-insensitive.
  • g: Global search (find all occurrences).
  • m: Multi-line mode (treat each line separately).
  • s: DotAll mode (the dot . matches newlines).
  • u: Unicode mode.
  • y: Sticky mode (search from the lastIndex position).

Example with Flags:

let regex = /hello/i; // Case-insensitive let result = regex.test("Hello"); // Returns true

5. Search Patterns

Regular expressions allow you to define complex patterns:

  • ^: Start of the string.
  • $: End of the string.
  • .: Any character except a newline.
  • \d: A digit.
  • \w: An alphanumeric character.
  • \s: A whitespace character.
  • *: Zero or more occurrences of the preceding pattern.
  • +: One or more occurrences of the preceding pattern.
  • ?: Zero or one occurrence of the preceding pattern.
  • {n}: Exactly n occurrences of the preceding pattern.
  • {n,m}: Between n and m occurrences of the preceding pattern.

Complex Pattern Example:

 


let regex = /^\d{3}-\d{2}-\d{4}$/; // Matches a US Social Security Number 
let result = regex.test("123-45-6789"); // Returns true 

 

Conclusion

Regular expressions in JavaScript are a powerful tool for manipulating strings. They allow you to define complex search patterns and apply them to text strings flexibly and efficiently. By mastering search patterns and associated methods, you can accomplish advanced text processing tasks.

SharePoint Get All Documents Permissions

On 13/12/2024

Get all RoleAssignments from a document library even more than 5000 elements

only when HasUniqueRoleAssignments == true

 


let currentSort = { column: null, direction: 'asc' }; // Store the current sort state

// Creates the style element
function createStyleElement(id, content) {
    var style = document.createElement("style");
    style.type = "text/css";
    style.id = id;
    style.innerHTML = content;

    if (style.styleSheet) {
        style.styleSheet.cssText = content;
    } else {
        let st = document.getElementById(id);
        if (st == undefined) {
            var head = document.head || document.getElementsByTagName("head")[i];
            head.appendChild(style);
        } else {
            st.innerHTML = content;
        }
    }
    return style;
}


// Function to filter the table based on dropdown selection
function filterTable(columnIndex, value) {
    let table, tr, td, i, select, selectedValue, txtValue;
    table = document.querySelector("table");
    tr = table.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
    select = table.getElementsByTagName("select")[columnIndex];
    //debugger;
    selectedValue = value;

    // Loop through all table rows and hide those that don't match the filter
    for (i = 0; i < tr.length; i++) {
        td = tr[i].getElementsByTagName("td")[columnIndex];
        if (td) {
            txtValue = td.textContent || td.innerText;
            if (selectedValue === "" || txtValue === selectedValue) {
                tr[i].style.display = "";
            } else {
                tr[i].style.display = "none";
            }
        }
    }
}
function sortTable(columnIndex, direction) {
    let table, rows, switching, i, x, y, shouldSwitch;
    table = document.querySelector("table");
    switching = true;
    let tbody = table.querySelector("tbody");

    // Set the current sort state
    currentSort.column = columnIndex;
    currentSort.direction = direction;

    while (switching) {
        switching = false;
        rows = tbody.rows;

        for (i = 0; i < rows.length - 1; i++) {
            shouldSwitch = false;
            x = rows[i].getElementsByTagName("td")[columnIndex];
            y = rows[i + 1].getElementsByTagName("td")[columnIndex];
            let isNumber = false;


            if (!isNaN(x.innerHTML)) {

                // Check if rows should switch based on ascending or descending order
                if (direction === 'asc') {
                    if (parseFloat(x.innerHTML) > parseFloat(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                } else if (direction === 'desc') {
                    if (parseFloat(x.innerHTML) < parseFloat(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
            else {
                // Check if rows should switch based on ascending or descending order
                if (direction === 'asc') {
                    if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                } else if (direction === 'desc') {
                    if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
        }
        if (shouldSwitch) {
            rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
            switching = true;
        }
    }
}
// Function to generate the table
function generateTableFromJson2(jsonArray, select, addHeaders = true) {
    const style = `
    table {
            width: 100%;
            border-collapse: collapse;
        }

        th, td {
            padding: 8px 12px;
            text-align: left;
            border: 1px solid #ddd;
        }

        tbody tr{
           max-height: 15px;
        }

        th {
            background-color: #f4f4f4;
            color: #000;
        }

        /* Scrollable table wrapper */
        .table-wrapper {
            max-height: 800px;
            overflow-y: auto;
            border: 1px solid #ddd;
        }
        /* Style for dropdowns in header */
        select {
            width: 100%;
            padding: 4px;
            margin-top: 5px;
        }

        /* Style for the sorting arrows */
        .sort-arrows {
            cursor: pointer;
            margin-left: 5px;
        }    
        `;
    createStyleElement("fdiStyle", style);

    // Create table element
    let table = document.createElement('table');

    // Create table header
    let header = table.createTHead();
    let headerRow = header.insertRow(0);

    // Get keys (headers) from the first object in the JSON array
    //let keys = Object.keys(jsonArray[0]);
    let keys = select.split(",");
    if (addHeaders) {
        keys.forEach((key, index) => {
            if (key !== "__metadata") {

                let th = document.createElement('th');
                th.innerHTML = key;

                // Create a dropdown (select) for filtering
                let select = document.createElement('select');

                select.addEventListener('change', function () {
                    const selectedValue = select.value;
                    filterTable(index, selectedValue);
                });

                // Populate dropdown with unique values from the JSON data
                let uniqueValues = [...new Set(jsonArray.map(item => item[key]))];

                // Add a default "All" option for no filter
                let optionAll = document.createElement('option');
                optionAll.value = "";
                optionAll.text = `All`;
                select.appendChild(optionAll);

                // Create an option for each unique value
                if (typeof (uniqueValues[0]) === typeof (1)) {
                    const pp = uniqueValues.sort((a, b) => {
                        if (a < b) {
                            return -1;
                        }
                        if (a > b) {
                            return 1;
                        }
                        return 0;
                    });
                    pp.forEach(value => {
                        let option = document.createElement('option');
                        option.value = value;
                        option.text = value;
                        select.appendChild(option);
                    });
                } else
                    uniqueValues.sort().forEach(value => {
                        let option = document.createElement('option');
                        option.value = value;
                        option.text = value;
                        select.appendChild(option);
                    });
                // Sort arrows for sorting the columns
                let upArrow = document.createElement('span');
                upArrow.innerHTML = '⬆️';
                upArrow.classList.add('sort-arrows');
                upArrow.onclick = () => sortTable(index, 'asc');

                let downArrow = document.createElement('span');
                downArrow.innerHTML = '⬇️';
                downArrow.classList.add('sort-arrows');
                downArrow.onclick = () => sortTable(index, 'desc');

                th.appendChild(select);  // Append the dropdown to the header
                th.appendChild(upArrow);  // Append the dropdown to the header
                th.appendChild(downArrow);  // Append the dropdown to the header
                headerRow.appendChild(th);
            }
        });
    }

    // Create table body and populate rows with data
    let tbody = document.createElement('tbody');
    jsonArray.forEach((item) => {
        let row = tbody.insertRow();
        keys = select.split(",");
        keys.forEach((key) => {
            let cell = row.insertCell();
            if (key !== "__metadata") {
                cell.setAttribute("nowrap", "nowrap");
                if (key === "RoleDefinitionBindings") {
                    cell.appendChild(generateTableFromJson2(item.RoleDefinitionBindings.results, "Name,Id", false));
                } else if (key.indexOf("/") > 0) {
                    cell.innerHTML = item[key.split("/")[0]][key.split("/")[1]]
                } else
                    cell.innerHTML = item[key];  // Insert each value from the JSON into the table cell
            }
        });
    });

    // Append the body to the table
    table.appendChild(tbody);


    return table;
}

function removeSlasches(select, datas) {
    const ret = [];
    const fields = select.split(',');
    for (let i = 0; i < datas.length; i++) {
        const toAdd = {};

        for (let j = 0; j < fields.length; j++) {
            if (fields[j].indexOf('/') > 0) {
                const splitted = fields[j].split('/');
                toAdd[splitted.join('')] = datas[i][splitted[0]][splitted[1]];
            } else
                toAdd[fields[j]] = datas[i][fields[j]];
        }
        ret.push(toAdd);
    }
    console.log("removeSlasches", ret);
    return ret;
}

async function GetPermissionsInFolder(siteUrl, listUrl1, query) {
    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    //get web relativeUrl
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const webServerRelativUrl = (await (await fetch(req, fetchOptions)).json()).d.ServerRelativeUrl;

    let query1 = "";
    if (`${query}`.trim() !== "") {
        query1 = `&$filter=${query}`;
        query = ` and ${query}`;
    }
    //get firstId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id asc`;
    console.log("req", req);
    const firstId = 0;//(await (await fetch(req, fetchOptions)).json()).d.results[0].Id;
    console.log("firstId", firstId);
    //get lastId
    //req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$filter=Id gt 170 and Id lt 533&$top=1&$orderby=Id desc`;
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id desc`;
    console.log("last", req);
    const lastId = (await (await fetch(req, fetchOptions)).json()).d.results[0].Id;
    console.log("lastId", lastId);


    let startId = firstId;
    let endId = firstId + 5000;
    var allItems = [];

    console.log(`startId ${startId} endId ${endId} lastId ${lastId}`)
    console.log("query", query);
    do {
        var select = "?$select=FileDirRef,RoleAssignments,HasUniqueRoleAssignments,Id,Title,FileLeafRef,Modified,Created";
        req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items${select}&$filter=Id ge ${startId} and Id lt ${endId}${query}&$orderby=Id asc&$top=5000`;
        console.log("req", req);
        // Send the asynchronous GET request to the REST API endpoint
        var respList1 = await fetch(req, fetchOptions);
        const items = (await respList1.json()).d.results;

        //get only items with unique permissions
        const withUniquePermissions = items.filter(user => user.HasUniqueRoleAssignments);

        console.log("withUniquePermissions", withUniquePermissions.length);
        allItems.push(...withUniquePermissions);
        startId += 5000;
        endId += 5000;
        console.log(`startId ${startId} endId ${endId} lastId ${lastId}`)
    }
    while (endId < lastId);

    return allItems;
}

async function batchFetchPermissions(siteUrl, itemIds, listUrl1) {
    const batchBoundary = "batch_" + new Date().getTime();
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };
    const webServerRelativUrl = (await (await fetch(`${siteUrl}/_api/web?$select=ServerRelativeUrl`, fetchOptions)).json()).d.ServerRelativeUrl;
    const batchBody = itemIds.map((item) => {
        return `
--${batchBoundary}
Content-Type: application/http
Content-Transfer-Encoding: binary

GET ${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items(${item.Id})/RoleAssignments?$expand=Member,RoleDefinitionBindings HTTP/1.1
`;
    }).join("\n") + `\n--${batchBoundary}--`;
    const digest = await GetDigestValue(siteUrl);//
    //console.log("digest", digest);
    const headers = {
        Accept: "application/json;odata=verbose",
        "X-RequestDigest": digest,
        "Content-Type": `multipart/mixed; boundary="${batchBoundary}"`,
    };

    console.log("itemIds", itemIds.length);
    const response = await fetch(`${siteUrl}/_api/$batch`, {
        method: "POST",
        headers,
        body: batchBody,
    });

    const text = await response.text(); // Parse response manually (multipart)
    return parseBatchResponse(text, itemIds);
}

async function GetDigestValue(siteUrl) {//
    const fetchOptions = {
        method: 'POST',
        headers: {
            'Accept': 'application/json;odata=verbose',
            'Content-type': 'application/json;odata=verbose'
        }
    };

    const response = await fetch(siteUrl + "/_api/contextinfo", fetchOptions);
    return (await response.json()).d.GetContextWebInformation.FormDigestValue;
}


function nodeParser2(xml) {

    var parser = new DOMParser();
    var doc = parser.parseFromString(xml, "application/xml");

    // Define a namespace resolver
    var nsResolver = function (prefix) {
        var ns = {
            'atom': 'http://www.w3.org/2005/Atom',
            'd': 'http://schemas.microsoft.com/ado/2007/08/dataservices',
            'm': 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
            'georss': 'http://www.georss.org/georss',
            'gml': 'http://www.opengis.net/gml'
        };
        return ns[prefix] || null;
    };

    // Use the namespace resolver in the XPath evaluation
    var result = doc.evaluate('/atom:feed/atom:entry', doc, nsResolver, XPathResult.ANY_TYPE, null);

    var entries = [];
    var entry = result.iterateNext();
    while (entry) {
        // Check if the entry contains a category with term="SP.User"
        var category = entry.getElementsByTagNameNS('http://www.w3.org/2005/Atom', 'category');
        let userName = "";
        let permissions = [];
        for (var i = 0; i < category.length; i++) {//
            if (category[i].getAttribute('term') === 'SP.User') {
                // Get the d:Email value
                let email = entry.getElementsByTagNameNS('http://schemas.microsoft.com/ado/2007/08/dataservices', 'Email');

                if (email.length > 0 && email[0].textContent.trim() !== "") {
                    userName = email[0].textContent;//
                } else {
                    email = entry.getElementsByTagNameNS('http://schemas.microsoft.com/ado/2007/08/dataservices', 'Title');
                    userName = email[0].textContent;//
                }
            }
            else if (category[i].getAttribute('term') === 'SP.Group') {
                // Get the d:Email value
                let email = entry.getElementsByTagNameNS('http://schemas.microsoft.com/ado/2007/08/dataservices', 'Email');

                if (email.length > 0 && email[0].textContent.trim() !== "") {
                    userName = email[0].textContent;//
                } else {
                    email = entry.getElementsByTagNameNS('http://schemas.microsoft.com/ado/2007/08/dataservices', 'Title');
                    userName = email[0].textContent;//
                }
            }
            else if (category[i].getAttribute('term') === 'SP.RoleDefinition') {
                var Name = entry.getElementsByTagNameNS('http://schemas.microsoft.com/ado/2007/08/dataservices', 'Name');
                if (Name.length > 0) {
                    permissions.push(Name[0].textContent);
                }
            }
        }

        if (userName === "") {
            debugger;
        }
        entries.push({
            "userName": userName,
            "permissions": permissions,
        });
        entry = result.iterateNext();
    }

    //console.log("entries:", entries);
    return entries;
}

// Helper to parse batch responses
function parseBatchResponse(responseText, itemIds) {
    //console.log("responseText", responseText);
    var results = [];
    const parts = responseText.split("--batchresponse");

    let i = 0;
    for (const part of parts) {
        if (part.includes("HTTP/1.1 200 OK")) {
            const xmlStart = part.indexOf("");
            if (xmlStart > -1 && xmlEnd > -1) {
                let xmlString = part.substring(xmlStart, xmlEnd + 8);
                results.push({
                    "item": itemIds[i],
                    "permissions": nodeParser2(xmlString)
                })
                i++;
            }
        }
    }

    return results;
}
function chunkArray(array, chunkSize) {
    let result = [];
    for (let i = 0; i < array.length; i += chunkSize) {
        // Utilise slice pour découper le tableau
        result.push(array.slice(i, i + chunkSize));
    }
    return result;
}


const siteUrl = _spPageContextInfo.webAbsoluteUrl || "https://test.sharepoint.com/sites/BIPvvvv";
const withUniquePermissions = await GetPermissionsInFolder(siteUrl, "Shared%20Documents", "");
//"startswith(FileDirRef, '/sites/BIPvvvv/Shared%20Documents/General/07%20-%20Release%201')"
console.log("withUniquePermissions", withUniquePermissions);
console.log("withUniquePermissions length", withUniquePermissions.length);

const permmissionItemsAll = [];
if (withUniquePermissions.length > 0) {
    const withUniquePermissionsCutted = chunkArray(withUniquePermissions, 30);
    for (let i = 0; i < withUniquePermissionsCutted.length; i++) {
        //debugger;
        const permmissionItems = await batchFetchPermissions(siteUrl, withUniquePermissionsCutted[i], "Shared%20Documents");
        permmissionItemsAll.push(...permmissionItems)

    }
    console.log("permmissionItems", permmissionItemsAll);
}

//FileDirRef,RoleAssignments,HasUniqueRoleAssignments,Id,Title,FileLeafRef,Modified,Created
const toDisplay = [];
let csv = "Id;Title;Modified;Created;UserPermission;Permissions;FileLeafRef;FileDirRef\n";
for (let i = 0; i < permmissionItemsAll.length; i++) {
    const permmissionItem = permmissionItemsAll[i];
    for (let j = 0; j < permmissionItem.permissions.length; j++) {
        for (let k = 0; k < permmissionItem.permissions[j].permissions.length; k++) {
            //debugger;
            const item = {
                "Id": permmissionItem.item.Id,
                "FileDirRef": permmissionItem.item.FileDirRef,
                "HasUniqueRoleAssignments": permmissionItem.item.HasUniqueRoleAssignments,
                "Title": permmissionItem.item.Title,
                "FileLeafRef": permmissionItem.item.FileLeafRef,
                "FileDirRef": permmissionItem.item.FileDirRef,
                "Modified": permmissionItem.item.Modified,
                "Created": permmissionItem.item.Created,
                "UserPermission": permmissionItem.permissions[j].userName,
                "Permissions": permmissionItem.permissions[j].permissions[k]
            }
            csv += `${item.Id};${item.Title};${item.Modified};${item.Created};${item.UserPermission};${item.Permissions};${item.FileLeafRef};${item.FileDirRef}` + "\n";
            toDisplay.push(item);
        }
    }
}

document.body.innerHTML = `<div id="tableContainer" class="table-wrapper"></div>`;

const table = generateTableFromJson2(toDisplay, "Id,Title,Modified,Created,UserPermission,Permissions,FileLeafRef,FileDirRef");

console.log("csv", csv);

// Append the table to the container

document.getElementById('tableContainer').appendChild(table);

navigator.clipboard.writeText(csv);

 

SharePoint Rest Get All Items In A folder even more than 5000

On 11/12/2024


async function GetPermissionsInFolder(siteUrl, listUrl1, query) {
    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    //get web relativeUrl
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const webServerRelativUrl = (await (await fetch(req, fetchOptions)).json()).d.ServerRelativeUrl;

    let query1 = "";
    if (`${query}`.trim() !== "") {
        query1 = `&$filter=${query}`;
        query = ` and ${query}`;
    }
    //get firstId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id asc`;
    console.log("req", req);
    const firstId = 0;//(await (await fetch(req, fetchOptions)).json()).d.results[0].Id;
    console.log("firstId", firstId);
    //get lastId
    //req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$filter=Id gt 170 and Id lt 533&$top=1&$orderby=Id desc`;
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id desc`;
    console.log("last", req);
    const lastId = (await (await fetch(req, fetchOptions)).json()).d.results[0].Id;
    console.log("lastId", lastId);


    let startId = firstId;
    let endId = firstId + 5000;
    var allItems = [];

    console.log(`startId ${startId} endId ${endId} lastId ${lastId}`)
    console.log("query", query);
    do {
        var select = "?$select=FileDirRef,RoleAssignments,HasUniqueRoleAssignments,Id,Title,FileLeafRef,Modified,Created";
        req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items${select}&$filter=Id ge ${startId} and Id lt ${endId}${query}&$orderby=Id asc&$top=5000`;
        console.log("req", req);
        // Send the asynchronous GET request to the REST API endpoint
        var respList1 = await fetch(req, fetchOptions);
        const items = (await respList1.json()).d.results;
        allItems.push(...items);
        startId += 5000;
        endId += 5000;
        console.log(`startId ${startId} endId ${endId} lastId ${lastId}`)
    }
    while (endId < lastId);

    return allItems;
}



const siteUrl = _spPageContextInfo.webAbsoluteUrl;
const items = await GetPermissionsInFolder(siteUrl, "Shared%20Documents", "");
console.log("items", items);
console.log("items length", items.length);


SharePoint Api Add ListItem

On 29/11/2024



const endpoint = `https://test.sharepoint.com/sites/fdiSandBox`;

const myHtttp = {
	getItemTypeForListName: async function (listTitle) {
		const fetchOptions = {
			method: 'GET',
			headers: {
				'Accept': 'application/json;odata=verbose',
				'Content-type': 'application/json;odata=verbose'
			}
		};
	
		const response = await fetch(endpoint + `/_api/web/lists/getbytitle('${listTitle}')/?$select=ListItemEntityTypeFullName`, fetchOptions);
		return response.json();
	},
	GetDisgestValue: async function () {//
		const fetchOptions = {
			method: 'POST',
			headers: {
				'Accept': 'application/json;odata=verbose',
				'Content-type': 'application/json;odata=verbose'
			}
		};
	
		const response = await fetch(endpoint + "/_api/contextinfo", fetchOptions);
		console.log(response);
		return response.json();
	}
}

const listItemEntityTypeFullName = (await myHtttp.getItemTypeForListName("test")).d.ListItemEntityTypeFullName;
const digest = (await myHtttp.GetDisgestValue()).d.GetContextWebInformation.FormDigestValue;
console.log(digest);

const toAdd = {
	__metadata: { type: listItemEntityTypeFullName },
	"Title": "test",
	"MyLookupId": 1
};
console.log("toAdd", toAdd);
// Fetch options with headers for authentication and response format
const fetchOptions = {
	method: 'POST',
	headers: {
		'Accept': 'application/json;odata=verbose',
		'Content-type': 'application/json;odata=verbose',
		'X-RequestDigest': digest
	},
	body: JSON.stringify(toAdd)
};

try {
	const response = await fetch(endpoint + `/_api/web/lists/getbytitle('test')/items`, fetchOptions);
	console.log("resp", response.json());
}
catch (e) {

	console.log(e);
}

SharePoint get by Rest List Role DefinitionBindings

On 28/10/2024


let currentSort = { column: null, direction: 'asc' }; // Store the current sort state

// Creates the style element
function createStyleElement(id, content) {
    var style = document.createElement("style");
    style.type = "text/css";
    style.id = id;
    style.innerHTML = content;

    if (style.styleSheet) {
        style.styleSheet.cssText = content;
    } else {
        let st = document.getElementById(id);
        if (st == undefined) {
            var head = document.head || document.getElementsByTagName("head")[i];
            head.appendChild(style);
        } else {
            st.innerHTML = content;
        }
    }
    return style;
}


// Function to filter the table based on dropdown selection
function filterTable(columnIndex, value) {
    let table, tr, td, i, select, selectedValue, txtValue;
    table = document.querySelector("table");
    tr = table.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
    select = table.getElementsByTagName("select")[columnIndex];
    //debugger;
    selectedValue = value;

    // Loop through all table rows and hide those that don't match the filter
    for (i = 0; i < tr.length; i++) {
        td = tr[i].getElementsByTagName("td")[columnIndex];
        if (td) {
            txtValue = td.textContent || td.innerText;
            if (selectedValue === "" || txtValue === selectedValue) {
                tr[i].style.display = "";
            } else {
                tr[i].style.display = "none";
            }
        }
    }
}
function sortTable(columnIndex, direction) {
    let table, rows, switching, i, x, y, shouldSwitch;
    table = document.querySelector("table");
    switching = true;
    let tbody = table.querySelector("tbody");

    // Set the current sort state
    currentSort.column = columnIndex;
    currentSort.direction = direction;

    while (switching) {
        switching = false;
        rows = tbody.rows;

        for (i = 0; i < rows.length - 1; i++) {
            shouldSwitch = false;
            x = rows[i].getElementsByTagName("td")[columnIndex];
            y = rows[i + 1].getElementsByTagName("td")[columnIndex];
            let isNumber = false;


            if (!isNaN(x.innerHTML)) {

                // Check if rows should switch based on ascending or descending order
                if (direction === 'asc') {
                    if (parseFloat(x.innerHTML) > parseFloat(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                } else if (direction === 'desc') {
                    if (parseFloat(x.innerHTML) < parseFloat(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
            else {
                // Check if rows should switch based on ascending or descending order
                if (direction === 'asc') {
                    if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                } else if (direction === 'desc') {
                    if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
        }
        if (shouldSwitch) {
            rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
            switching = true;
        }
    }
}
// Function to generate the table
function generateTableFromJson2(jsonArray, select, addHeaders = true) {
    const style = `
    table {
            width: 100%;
            border-collapse: collapse;
        }

        th, td {
            padding: 8px 12px;
            text-align: left;
            border: 1px solid #ddd;
        }

        tbody tr{
           max-height: 15px;
        }

        th {
            background-color: #f4f4f4;
            color: #000;
        }

        /* Scrollable table wrapper */
        .table-wrapper {
            max-height: 800px;
            overflow-y: auto;
            border: 1px solid #ddd;
        }
        /* Style for dropdowns in header */
        select {
            width: 100%;
            padding: 4px;
            margin-top: 5px;
        }

        /* Style for the sorting arrows */
        .sort-arrows {
            cursor: pointer;
            margin-left: 5px;
        }    
        `;
    createStyleElement("fdiStyle", style);





    // Create table element
    let table = document.createElement('table');

    // Create table header
    let header = table.createTHead();
    let headerRow = header.insertRow(0);

    // Get keys (headers) from the first object in the JSON array
    //let keys = Object.keys(jsonArray[0]);
    let keys = select.split(",");
    if (addHeaders) {
        keys.forEach((key, index) => {
            if (key !== "__metadata") {

                let th = document.createElement('th');
                th.innerHTML = key;

                // Create a dropdown (select) for filtering
                let select = document.createElement('select');

                select.addEventListener('change', function () {
                    const selectedValue = select.value;
                    filterTable(index, selectedValue);
                });

                // Populate dropdown with unique values from the JSON data
                let uniqueValues = [...new Set(jsonArray.map(item => item[key]))];

                // Add a default "All" option for no filter
                let optionAll = document.createElement('option');
                optionAll.value = "";
                optionAll.text = `All`;
                select.appendChild(optionAll);

                // Create an option for each unique value
                if (typeof (uniqueValues[0]) === typeof (1)) {
                    const pp = uniqueValues.sort((a, b) => {
                        if (a < b) {
                            return -1;
                        }
                        if (a > b) {
                            return 1;
                        }
                        return 0;
                    });
                    pp.forEach(value => {
                        let option = document.createElement('option');
                        option.value = value;
                        option.text = value;
                        select.appendChild(option);
                    });
                } else
                    uniqueValues.sort().forEach(value => {
                        let option = document.createElement('option');
                        option.value = value;
                        option.text = value;
                        select.appendChild(option);
                    });
                // Sort arrows for sorting the columns
                let upArrow = document.createElement('span');
                upArrow.innerHTML = '⬆️';
                upArrow.classList.add('sort-arrows');
                upArrow.onclick = () => sortTable(index, 'asc');

                let downArrow = document.createElement('span');
                downArrow.innerHTML = '⬇️';
                downArrow.classList.add('sort-arrows');
                downArrow.onclick = () => sortTable(index, 'desc');

                th.appendChild(select);  // Append the dropdown to the header
                th.appendChild(upArrow);  // Append the dropdown to the header
                th.appendChild(downArrow);  // Append the dropdown to the header
                headerRow.appendChild(th);
            }
        });
    }

    // Create table body and populate rows with data
    let tbody = document.createElement('tbody');
    jsonArray.forEach((item) => {
        let row = tbody.insertRow();
        keys = select.split(",");
        keys.forEach((key) => {
            let cell = row.insertCell();
            if (key !== "__metadata") {
                cell.setAttribute("nowrap", "nowrap");
                if (key === "RoleDefinitionBindings") {
                    cell.appendChild(generateTableFromJson2(item.RoleDefinitionBindings.results, "Name,Id", false));
                } else if (key.indexOf("/") > 0) {
                    cell.innerHTML = item[key.split("/")[0]][key.split("/")[1]]
                } else
                    cell.innerHTML = item[key];  // Insert each value from the JSON into the table cell
            }
        });
    });

    // Append the body to the table
    table.appendChild(tbody);


    return table;
}

function removeSlasches(select, datas) {
    const ret = [];
    const fields = select.split(',');
    for (let i = 0; i < datas.length; i++) {
        const toAdd = {};

        for (let j = 0; j < fields.length; j++) {
            if (fields[j].indexOf('/') > 0) {
                const splitted = fields[j].split('/');
                toAdd[splitted.join('')] = datas[i][splitted[0]][splitted[1]];
            } else
                toAdd[fields[j]] = datas[i][fields[j]];
        }
        ret.push(toAdd);
    }
    console.log("removeSlasches", ret);
    return ret;
}

// Function to get permissions for a SharePoint group
async function getSharePointPermissions(siteUrl, select) {

    // REST API endpoint to get group permissions
    const endpoint = `${siteUrl}`;

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
        throw new Error(`Error fetching permissions: ${response.statusText}`);
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();

    // Extract role assignments (permissions)
    const roleAssignments = data.d.results;
    console.log('roleAssignments', roleAssignments);
    console.log(JSON.stringify(roleAssignments));

    const D1 = removeSlasches(select, roleAssignments)
    const pattern2 = /\//g;
    console.log("json111", JSON.stringify(D1));
    const table = generateTableFromJson2(D1, select.replace(pattern2, ""));
    // Append the table to the container
    document.getElementById('tableContainer').appendChild(table);
}

// Usage example: Replace 'your-group-id' and 'your-site-url' with actual values
const select = "Member/Title,Member/Id,Member/LoginName,RoleDefinitionBindings";
let siteUrl = 'https://mySite.sharepoint.com/sites/Dev_wf';
siteUrl += `/_api/web/roleassignments/?$expand=RoleDefinitionBindings,Member&$select=${select}`; // Replace with the actual site URL
document.body.innerHTML = `<div id="tableContainer" class="table-wrapper"></div>`; await getSharePointPermissions(siteUrl, select); 

 

Permissions

Javascript how to Clear / Empty Browser Cache and Cookies

On 11/09/2024

Clear / Empty Browser Cache and Cookies

 


//clear bowser cache
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          return caches.delete(cacheName);
        })
      );
    })
  );
});
function deleteAllCookies() {
  const cookies = document.cookie.split(";");

  for (let i = 0; i < cookies.length; i++) {
    const cookie = cookies[i];
    const eqPos = cookie.indexOf("=");
    const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
    document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;";
  }
}

// Call the function to delete all cookies
deleteAllCookies();

 

Get User Permissions By Mail And Javascript

On 09/09/2024

Get User Permissions By Mail And Javascript

 


let siteUrl = "https://mayTenant.sharepoint.com/sites/test"

async function getUserPermissions(siteUrl, userMail) {

    // REST API endpoint to get group permissions
    const endpoint = `${siteUrl}/_api/web/siteusers?$filter=Email eq '${userMail}'&$select=Id`;
    //const endpoint = `${siteUrl}/_api/web/siteusers?$filter=Email eq '${userMail}'&$select=LoginName`;

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
        throw new Error(`Error fetching permissions: ${response.statusText}`);
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();
    console.log("data", data);

    if (data.d.results.length === 0) {
        console.log("user not found", userMail);
    } else {

        const userId = `${data.d.results[0].Id}`;
        for (const user in data.d.results) {

            console.log("user", userMail);
        }
        let ret = "";
        const endpoint2 = `${siteUrl}/_api/web//RoleAssignments/GetByPrincipalId(${userId})/RoleDefinitionBindings`;
        // Send the asynchronous GET request to the REST API endpoint
        const response2 = await fetch(endpoint2, fetchOptions);
        const data2 = await response2.json();
        console.log("data2", data2);
        for (let i = 0; i < data2.d.results.length; i++) {
            ret += `User ${data2.d.results[0].Name} : ${data2.d.results[0].Description}\r\n`;
        }

        //by groups
        const getGroupsEndPoint = `${siteUrl}/_api/web/GetUserById(${userId})/groups?$select=Id,Title`;
        const response3 = await fetch(getGroupsEndPoint, fetchOptions);
        const data3 = await response3.json();
        console.log("data3", data3);

        for (let i = 0; i < data3.d.results.length; i++) {
            //get group permissions
            const endpoint4 = `${siteUrl}/_api/web//RoleAssignments/GetByPrincipalId(${data3.d.results[i].Id})/RoleDefinitionBindings`;
            const response4 = await fetch(endpoint4, fetchOptions);
            const data4 = await response4.json();
            console.log("data4", data4);
            for (let j = 0; j < data4.d.results.length; j++) {
                ret += `Group ${data3.d.results[i].Title} Id ${data3.d.results[i].Id} : ${data4.d.results[j].Name} : ${data4.d.results[j].Description}. ` + "\r\n";
            }
        }

        return `${ret}.`;
    }
    return null;
}


await getUserPermissions(siteUrl, "test-ext@test.com");

Permissions to Check:

Here are some common permissions encoded in the High and Low values:

  • ViewListItems: 0x00000001
  • AddListItems: 0x00000002
  • EditListItems: 0x00000004
  • DeleteListItems: 0x00000008
  • OpenItems: 0x00000010
  • ViewVersions: 0x00000020
  • CancelCheckout: 0x00000040
  • ManagePermissions: 0x00010000
  • ManageWeb: 0x00040000

SharePoint List Users And Their Groups By JS to CSV

On 06/09/2024


let siteUrl = '';


async function getUsersGroups(siteUrl) {

    // REST API endpoint to get group permissions
    const endpoint = `${siteUrl}`;

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
        throw new Error(`Error fetching permissions: ${response.statusText}`);
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();
    console.log("data", data);
    let csv = "Title;Email;LoginName;Id;IsSiteAdmin;UserOnly;GroupTitle;GroupId;Owner;Description;AllowMembersEditMembership;AllowRequestToJoinLeave;AutoAcceptRequestToJoinLeave;GroupId;Limited\r\n";
    for (const user of data.d.results) {

        //debugger;
        if (user.Groups && user.Groups.results && user.Groups.results.length > 0) {
            csv += `${user.Title};${user.Email};${user.LoginName};${user.Id};${user.IsSiteAdmin};true;;;;;;;;;NoLimited\r\n`;
            for (const group of user.Groups.results) {
                let limited = "not"
                if (`${group.Title}`.indexOf("imited") > 0) {
                    limited = "Limited";
                }
                csv += `${user.Title};${user.Email};${user.LoginName};${user.Id};${user.IsSiteAdmin};group;${group.Title};${group.Id};${group.OwnerTitle};${group.Description};${group.AllowMembersEditMembership};${group.AllowRequestToJoinLeave};${group.AutoAcceptRequestToJoinLeave};${group.Id};${limited}\r\n`;
            }
        } else
            csv += `${user.Title};${user.Email};${user.LoginName};${user.Id};${user.IsSiteAdmin};noGroup;;;;;;;;;noGroup\r\n`;
    }
    console.log("csv", csv);
}

let query = `/_api/web/siteusers?$select=IsSiteAdmin,Email,Id,LoginName,Title&$expand=Groups`;
await getUsersGroups(siteUrl + query);

Get SharePoint Lists With JS

On 05/09/2024

Display Sharepoint lists in an html table, and in a csv text content

// The content of the stylesheet
const styleSheetContent = `
    .cadre-table-scroll {
  display: inline-block;
  height: 100em;
  overflow-y: scroll;
    overflow-x: auto;
    white-space: nowrap;
}
.table-scroll thead th {
  position: sticky;
  top: 0;
}
.table-scroll tfoot td {
  position: sticky;
  bottom: 0;
}
 .table-scroll tbody {
    display: table;
    width: 100%;
}
`;

// Creates the style element
function createStyleElement(id, content) {
    var style = document.createElement("style");
    style.type = "text/css";
    style.id = id;
    style.innerHTML = content;

    if (style.styleSheet) {
        style.styleSheet.cssText = content;
    } else {
        let st = document.getElementById(id);
        if (st == undefined) {
            var head = document.head || document.getElementsByTagName("head")[i];
            head.appendChild(style);
        } else {
            st.innerHTML = content;
        }
    }
    return style;
}


async function getSharePointLists(query) {

    const endpoint = `${query}`;

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
        throw new Error(`Error fetching permissions: ${response.statusText}`);
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();
    let csv = "Id;Title;RootFolderr;BaseTemplate;ContentTypesEnabled;Created;ItemCount;EnableMinorVersions;EnableModeration;EnableVersioning;LastItemModifiedDate;NoCrawl;Hidden\r\n";
    // Extract lists
    const lists = data.d.results;
    console.log("lists", lists);
    createStyleElement("fdiStyle", styleSheetContent);
    let html = `<table class="cadre-table-scroll"><thead><tr>
    <th>Id</th>
    <th>Title</th>
    <th>RootFolderr/ServerRelativeUrl</th>
    <th>BaseTemplate</th>
    <th>ContentTypesEnabled</th>
    <th>Created</th>
    <th>ItemCount</th>
    <th>EnableMinorVersions</th>
    <th>EnableModeration</th>
    <th>EnableVersioning</th>
    <th>LastItemModifiedDate</th>
    <th>NoCrawl</th>
    <th>Hidden</th></tr><thead><tbody>
`;
    for (let i = 0; i < lists.length; i++) {
        const responseList = await fetch(`${lists[i].__metadata.id}?$select=HasUniqueRoleAssignments`, fetchOptions);
        const data = await responseList.json();
        //console.log("responseList", data);
csv += `${lists[i].Id};${lists[i].Title};${lists[i].RootFolder.ServerRelativeUrl};${lists[i].BaseTemplate};${lists[i].ContentTypesEnabled};${lists[i].Created};${lists[i].ItemCount};${lists[i].EnableMinorVersions};${lists[i].EnableModeration};${lists[i].EnableVersioning};${lists[i].LastItemModifiedDate};${lists[i].NoCrawl};${lists[i].Hidden}`;
csv += `\r\n`;
        if (lists[i].Title === "DO_NOT_DELETE_SPLIST_SITECOLLECTION_AGGREGATED_CONTENTTYPES")
            continue;
        lists[i].HasUniqueRoleAssignments = data.d.HasUniqueRoleAssignments;
        html += `<tr>
    <td>${lists[i].Id}</td>
    <td>${lists[i].Title}</td>
    <td>${lists[i].RootFolder.ServerRelativeUrl}</td>
    <td>${lists[i].BaseTemplate}</td>
    <td>${lists[i].ContentTypesEnabled}</td>
    <td>${lists[i].Created}</td>
    <td>${lists[i].ItemCount}</td>
    <td>${lists[i].EnableMinorVersions}</td>
    <td>${lists[i].EnableModeration}</td>
    <td>${lists[i].EnableVersioning}</td>
    <td>${lists[i].LastItemModifiedDate}</td>
    <td>${lists[i].NoCrawl}</td>
    <td>${lists[i].Hidden}</td>
</tr>`;
    }
    html += "</tbody></table>"
    document.body.innerHTML = html;
    console.log("datas", csv);

}

let req = "/_api/web/lists?$select=Id,Title,RootFolder/ServerRelativeUrl,ItemCount,BaseTemplate,ContentTypesEnabled,Created,EnableMinorVersions,EnableModeration,EnableVersioning,LastItemModifiedDate,NoCrawl,Hidden&$expand=RootFolder&$OrderBy=Hidden,Title";
let siteUrl = ";


getSharePointLists(siteUrl + req);

Get SharePoint Web Permissions

On 05/09/2024

Gets sharepoint roleassignements and display page, and createcsv text

 


// The content of the stylesheet
const styleSheetContent = '
    .container {
        display: grid;
        row-gap: 10px;
        /* 20px gap between rows */
        column-gap: 10px;
        /* 10px gap between columns */
        grid-template-columns: 1fr 1fr 1fr 1fr;
        padding-bottom: 5px;
    }
    .container2 {
        display: grid;
        row-gap: 10px;
        /* 20px gap between rows */
        column-gap: 10px;
        /* 10px gap between columns */
        grid-template-columns: 1fr 1fr 1fr;
        padding-bottom: 5px;
    }

    .container .header {
        text-align: center;
        border: 1px solid black;
    }

    .container .data {
        border: 1px solid black;
    }
';

// Creates the style element
function createStyleElement(id, content) {
    var style = document.createElement("style");
    style.type = "text/css";
    style.id = id;
    style.innerHTML = content;

    if (style.styleSheet) {
        style.styleSheet.cssText = content;
    } else {
        let st = document.getElementById(id);
        if(st == undefined){
            var head = document.head || document.getElementsByTagName("head")[0];
            head.appendChild(style);
        } else {
            st.innerHTML = content;
        }
    }
    return style;
}



// Function to get permissions for a SharePoint group
async function getSharePointPermissions(siteUrl) {
  
    // REST API endpoint to get group permissions
    const endpoint = '${siteUrl}';

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
      method: 'GET',
      headers: {
        'Accept': 'application/json;odata=verbose'
      }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
      throw new Error('Error fetching permissions: ${response.statusText}');
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();
    
    // Extract role assignments (permissions)
    const roleAssignments = data.d.results;

    console.log('roleAssignments: ', data.d.results);
    createStyleElement("fdiStyle", styleSheetContent);
    let repportCSV = 'Title;LoginName;Id;Role_Name;Role_Description;Role;Id';
    repportCSV += "\r\n";
    document.body.innerHTML = '<div class="container">
    <div class="header">Title</div>
    <div class="header">LoginName</div>
    <div class="header">Id</div>
    <div class="header">Role
        <div class="container2">
            <div class="data">Name</div>
            <div class="data">Description</div>
            <div class="data">Id</div>
        </div>
    </div>
</div>';

    // Report permissions
    roleAssignments.forEach(roleAssignment => {
      const member = roleAssignment.Member;
      const roleBindings = roleAssignment.RoleDefinitionBindings.results;
      repportCSV+= '${member.Title};${member.LoginName};${member.Id}';
      let div = '      
<div class="container">
    <div class="data">${member.Title}</div>
    <div class="data">${member.LoginName}</div>
    <div class="data">${member.Id}</div>';
      roleBindings.forEach(role => {
        repportCSV+= ';${role.Name};${role.Description};${role.Id}';
        repportCSV += "\r\n";
        div += '
        <div class="container2">
            <div class="data">${role.Name}</div>
            <div class="data">${role.Description}</div>
            <div class="data">${role.Id}</div>
        </div>
        ';
        console.log(' - Role: ${role.Name}');
      });
      div += "
"; document.body.innerHTML += div; }); console.log("datas", repportCSV); } // Usage example: 'your-site-url' with actual values let siteUrl = ''; siteUrl += '/_api/web/roleassignments/?$expand=RoleDefinitionBindings,Member&$select=Member/Title,Member/Id,Member/LoginName'; // Replace with the actual site URL getSharePointPermissions(siteUrl);
In HTML

SFPX React From Css

On 05/09/2024

Introduction
Le développement de composants pour SharePoint Framework (SPFx) en utilisant React nécessite une attention particulière aux pratiques CSS pour garantir que vos interfaces sont responsives et adaptées à tous les types d'écrans, que ce soit sur mobile, tablette ou desktop. 

1. Principes de Base pour des CSS Responsives

1. Unité Relative :
   - Utilisez des unités relatives comme `%`, `em`, `rem`, `vh`, et `vw` pour les marges, les paddings, et les dimensions. Cela permet aux éléments de s’adapter dynamiquement à la taille de l'écran.

2. Media Queries :
   - Utilisez des media queries pour ajuster les styles en fonction de la taille de l'écran. Par exemple, pour les écrans de moins de 768px de largeur (taille de tablette), vous pouvez ajuster les layouts.
   css
   @media (max-width: 768px) {
       .container {
           flex-direction: column;
       }
   }
   

3. Flexbox :
   - Utilisez Flexbox pour créer des layouts flexibles qui peuvent s'adapter facilement aux différentes tailles d'écran. Flexbox est particulièrement utile pour les barres de navigation, les formulaires, et les mises en page de cartes.
   css


   .form-container {
       display: flex;
       flex-wrap: wrap;
   }

   .form-group {
       flex: 1 1 300px; /* Les groupes de formulaire s'ajustent avec un minimum de 300px */
       margin: 10px;
   }
   

4. Grid Layout :
   - Pour des mises en page plus complexes, comme des tableaux de données ou des calendriers, utilisez CSS Grid. Cela permet de contrôler avec précision la disposition des éléments sur la page.

2. Exemple de Formulaire Responsive

Voici un exemple de formulaire avec différents types d'entrées HTML, construit en React et avec une mise en page responsive.

HTML/JSX pour le Formulaire

jsx
import * as React from 'react';
import './Form.css';

const ResponsiveForm = () => {
    return (
        <form className="form-container">
            <div className="form-group">
                <label htmlFor="name">Nom:</label>
                <input type="text" id="name" name="name" placeholder="Votre nom" />
            </div>
            <div className="form-group">
                <label htmlFor="email">Email:</label>
                <input type="email" id="email" name="email" placeholder="Votre email" />
            </div>
            <div className="form-group">
                <label htmlFor="date">Date:</label>
                <input type="date" id="date" name="date" />
            </div>
            <div className="form-group">
                <label htmlFor="color">Couleur:</label>
                <input type="color" id="color" name="color" />
            </div>
            <div className="form-group">
                <label>Sexe:</label>
                <input type="radio" id="male" name="gender" value="male" />
                <label htmlFor="male">Homme</label>
                <input type="radio" id="female" name="gender" value="female" />
                <label htmlFor="female">Femme</label>
            </div>
            <div className="form-group">
                <label>Langues:</label>
                <input type="checkbox" id="english" name="language" value="english" />
                <label htmlFor="english">Anglais</label>
                <input type="checkbox" id="french" name="language" value="french" />
                <label htmlFor="french">Français</label>
            </div>
            <div className="form-group">
                <label htmlFor="people-picker">Personne:</label>
                <input type="text" id="people-picker" name="people-picker" placeholder="Sélectionner une personne" />
            </div>
            <div className="form-group">
                <button type="submit">Envoyer</button>
            </div>
        </form>
    );
};

export default ResponsiveForm;

CSS pour le Formulaire

css
.form-container {
    display: flex;
    flex-wrap: wrap;
    margin: 20px;
}

.form-group {
    flex: 1 1 300px;
    margin: 10px;
}

.form-group label {
    display: block;
    margin-bottom: 5px;
}

.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="date"],
.form-group input[type="color"],
.form-group input[type="radio"],
.form-group input[type="checkbox"] {
    width: 100%;
    padding: 8px;
    margin-bottom: 10px;
    box-sizing: border-box;
}

button[type="submit"] {
    background-color: #0078d4;
    color: white;
    padding: 10px 20px;
    border: none;
    cursor: pointer;
}

button[type="submit"]:hover {
    background-color: #005a9e;
}

@media (max-width: 768px) {
    .form-container {
        flex-direction: column;
    }
}

Rendu Visuel

L'utilisation de Flexbox ici permet aux groupes de formulaire de se réarranger dynamiquement en fonction de la largeur de l'écran. Sur des écrans larges, les groupes se placent côte à côte, tandis que sur les petits écrans (comme les mobiles), ils s'empilent verticalement.

3. Exemple de Grille Responsive avec les Jours de la Semaine

Voici un exemple de grille responsive affichant les jours de la semaine.

HTML/JSX pour la Grille

jsx
import * as React from 'react';
import './WeekGrid.css';

const WeekGrid = () => {
    return (
        <div className="week-grid">
            <div className="day">Lundi</div>
            <div className="day">Mardi</div>
            <div className="day">Mercredi</div>
            <div className="day">Jeudi</div>
            <div className="day">Vendredi</div>
            <div className="day">Samedi</div>
            <div className="day">Dimanche</div>
        </div>
    );
};

export default WeekGrid;

CSS pour la Grille

css
.week-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 10px;
    margin: 20px;
}

.day {
    background-color: #f4f4f4;
    padding: 20px;
    text-align: center;
    font-weight: bold;
    border: 1px solid #ddd;
}

@media (max-width: 768px) {
    .week-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 480px) {
    .week-grid {
        grid-template-columns: 1fr;
    }
}

Rendu Visuel

- Grille par Défaut : Les jours de la semaine sont affichés côte à côte sur des écrans larges, en 7 colonnes.
- Tablette : La grille passe à 2 colonnes, ce qui permet de voir deux jours par ligne.
- Mobile : La grille devient une seule colonne, chaque jour étant affiché dans une ligne distincte.

Conclusion

Les bonnes pratiques pour des CSS responsives dans le développement SPFx avec React incluent l'utilisation de Flexbox et CSS Grid pour créer des mises en page adaptatives, l'utilisation judicieuse des media queries, et la préférence pour des unités relatives pour la taille des éléments. Ces techniques permettent de créer des interfaces utilisateurs qui sont à la fois élégantes et fonctionnelles sur tous types de dispositifs.

In Tools

ToGrid

On 23/02/2024

In HTML

Inject Html In Page With Json Datas

On 31/10/2023

Display json datas in your existing html page to debug

 


class fdiRender {
    constructor(element_id) {
        if (element_id == undefined)
            this.TARGETELEMENTID = "fdiPopup";
        else
            this.TARGETELEMENTID = element_id;
        this.element = document.getElementById(this.TARGETELEMENTID);
        //debugger;
        if (this.element == null) {
            let body = document.getElementsByTagName("body")[0];
            body.insertAdjacentHTML("afterbegin", "<div id='" + this.TARGETELEMENTID + "'>coucou</div>");
            this.element = document.getElementById(this.TARGETELEMENTID);
        }

        /*beforebegin (before an element)
        afterbegin (first child)
        beforeend (last child)
        afterend (after an element)*/

        this.buildCss();
        this.render();
    }

    buildCss() {

        this.css = {};
        this.css.container = "width: 100%;margin-right: auto;margin-left: auto;";
        this.css.row = "display: flex;flex-wrap: wrap;margin-top: calc(0);margin-right: 0.75rem;margin-left: 0.75rem;";
        this.css.col = "flex: 0 0 auto;width: 50%;";
        this.css.colArray = "flex: 0 0 auto;";
        this.css.border = "border: 1px solid black;padding: 0.15rem;";
    }

    render(obj) {

        if (obj != undefined && obj != null) {

            let keys = Object.keys(obj)

            let html = [];
            html.push("<div style='" + this.css.container + "' id='" + this.TARGETELEMENTID + "'>");
            for (let i = 0; i < keys.length; i++) {
                //rows
                html.push("<div style='" + this.css.row + "'>");

                //columns
                if (typeof (obj[keys[i]]) != typeof ([])) {
                    html.push("<div style='" + this.css.col + "'>");
                    html.push("<div style='" + this.css.border + "'>" + keys[i] + "</div>");
                    html.push("</div>");
                    html.push("<div style='" + this.css.col + "'>");
                    html.push("<div style='" + this.css.border + "'>" + obj[keys[i]] + "</div>");
                    html.push("</div>");
                } else {
                    html.push("<div style='" + this.css.col + "'>");
                    html.push("<div style='" + this.css.border + "'>" + keys[i] + "</div>");
                    html.push("</div>");
                    const css = this.css.colArray + "width: " + 100 / keys.length + "%;"
                    html.push("<div style='" + this.css.col + "'>");
                    html.push(this.renderArray(obj[keys[i]], true));
                    html.push("</div>");
                }

                html.push("</div>");//end row
            }
            html.push("</div>");
            this.element.innerHTML = html.join("");
            return;
        }

        this.element.innerHTML = "<div style='" + this.css.container + "' id='" + this.TARGETELEMENTID + "'>yes</div>";
    }

    renderArray(obj, isChild, exportCSV) {

        if (obj != undefined && obj != null && obj.length != undefined && obj.length > 0) {

            let keys = Object.keys(obj[0]);
            let exportCSVSTR = "";

            let html = [];
            if (isChild == undefined)
                html.push("<div class='demo' style='" + this.css.container + "' id='" + this.TARGETELEMENTID + "'>");
            const css = this.css.colArray + "width: " + 100 / keys.length + "%;"
            html.push("<div class='demo2' style='" + this.css.row + "'>");
            for (let i = 0; i < keys.length; i++) {//columns
                html.push("<div style='" + css + "'>");
                html.push("<div style='" + this.css.border + "'>" + keys[i] + "</div>");
                html.push("</div>");
                if (exportCSV != undefined)
                    exportCSVSTR += keys[i] + exportCSV;
            }
            exportCSVSTR += "\r\n";
            html.push("</div>");//end row


            for (let j = 0; j < obj.length; j++) {//elements in array
                html.push("<div style='" + this.css.row + "'>");
                for (let i = 0; i < keys.length; i++) {//columns
                    if (typeof (obj[j][keys[i]]) != typeof ([])) {
                        html.push("<div style='" + css + "'>");
                        html.push("<div style='" + this.css.border + "'>" + obj[j][keys[i]] + "</div>");
                        html.push("</div>");
                        if (exportCSV != undefined)
                            exportCSVSTR += obj[j][keys[i]] + exportCSV;
                    } else {
                        html.push("<div style='" + css + "'>");
                        html.push(this.renderArray(obj[j][keys[i]], true));
                        html.push("</div>");
                        if (exportCSV != undefined)
                            exportCSVSTR += "array" + exportCSV;
                    }
                }
                exportCSVSTR += "\r\n";

                html.push("</div>");//end row
            }

            //end div
            if (isChild == undefined)
                html.push("</div>");
            if (isChild == undefined)
                this.element.innerHTML = html.join("");
            console.log(exportCSVSTR);
            return html.join("");
        }
        this.element.innerHTML = "<div style='" + this.css.container + "' id='" + this.TARGETELEMENTID + "'>yes</div>";
    }
}

function test() {
    let fdi = new fdiRender();
    let obj1 = {
        "name": "toto",
        "age": 23,
        "town": "fontenay sous bois",
        "pays": "france"
    }
    let arr2 = [];
    arr2.push(obj1);
    arr2.push(obj1);
    arr2.push(obj1);

    let obj = {
        "name": "tata popo",
        "age": 28,
        "town": "Selestat",
        "pays": "france",
        "monTableau": arr2,
        "department": "Alsace"
    }
    let arr = [];
    arr.push(obj);
    arr.push(obj);
    arr.push(obj);
    arr.push(obj);
    //fdi.render(obj);
    fdi.renderArray(arr, undefined, ";");

}

Table
In HTML

Inject CSS with javascript in html page

On 30/10/2023

How to inject css in your page with javascript

 


// The content of the stylesheet
const styleSheetContent = `
    .demo{
        background:red;
        color: yellow;
    }

    .demo2 {
        font-size: 1.2rem;
        color: black;
    }
`;

// Creates the style element
function createStyleElement(id, content) {
    var style = document.createElement("style");
    style.type = "text/css";
    style.id = id;
    style.innerHTML = content;

    if (style.styleSheet) {
        style.styleSheet.cssText = content;
    } else {
        let st = document.getElementById(id);
        if(st == undefined){
            var head = document.head || document.getElementsByTagName("head")[0];
            head.appendChild(style);
        } else {
            st.innerHTML = content;
        }
    }
    return style;
}

createStyleElement("fdiStyle", styleSheetContent);

 

Get SharePoint Audit Logs

On 05/04/2023

Create certification for azure app

    
        # Create certificate
        $mycert = New-SelfSignedCertificate -DnsName "myCertificate.org" -CertStoreLocation "cert:\CurrentUser\My" -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange
        
        $mypwd = ConvertTo-SecureString -String "myCertificatePsw" -Force -AsPlainText
        # Export certificate to .pfx file
        $mycert | Export-PfxCertificate -FilePath myCertificate.pfx -Password $mypwd
        
        # Export certificate to .cer file
        $mycert | Export-Certificate -FilePath myCertificate.cer  
    

Connect to site

    
        $url = "https://m365x6422vvvvd.sharepoint.com/";
        $appId = "868d7a0c-a3dc-45af-b4a7-f72a70f61a60";
        $thumbprint = "A17177BB0E8A465F6AD08B0CEAE2F369C46D6481";
        $tenantId = "3533ab30-c2f0-48fd-b4c5-f5dc6ca77ec3"

        Connect-PnPOnline  -Url $url -Tenant $tenantId -Thumbprint $thumbprint -ClientId $appId
    

Export audit

premission required

Office 365 Management APIs (3) :: ActivityFeed.Read

possible filters

  • FilePreviewed
  • FileAccessed
  • SignInEvent
  • FileModifiedExtended
  • FileUploaded
  • PageViewed
  • PagePrefetched
  • FileCheckedIn
  • FileModified
  • FolderCreated
  • ListUpdated
  • ListViewed
    
        $ele = Get-PnPUnifiedAuditLog -ContentType SharePoint -StartTime (Get-Date).AddDays(-2) -EndTime (Get-Date).AddDays(-1)

        $ele = Get-PnPUnifiedAuditLog -ContentType SharePoint

        $ele = Get-PnPUnifiedAuditLog -ContentType SharePoint | Where-Object {$_.Operation -eq "PageViewed"} | Select-Object CreationTime,Operation,Workload,UserId,ObjectId,SourceFileName,SiteUrl,SourceFileExtension,SourceRelativeUrl

        $ele | Export-Csv -Path "Audit_3.csv" -Encodin:UTF8 -NoTypeInformation -Delimiter ";"
    

with sharepoint search request

    
        kqlQuery = "ContentTypeId:0x0101009D1CB255DA76424F860D91F20E6C4118*";//news
        kqlQuery = "ContentTypeId:0x0101* language=fr ViewsLastMonths3=0";//documents
        kqlQuery = "ContentTypeId:0x0101* ViewsLifeTime=0";
        var seletvvv = "Title,ViewsLifeTimeUniqueUsers,ViewsLifeTime,language,Created,Size,Path,LastModifiedTime,ViewsLastMonths3,ViewsLastMonths3Unique,LastAnalyticsUpdateTime";

        &sortlist='Size:descending'
        &sortlist='ViewsLifeTime:descending'
    

How to resolve the 5000 item limit

On 24/01/2022


    var firstItems = listLocation.web.getList(listLocation.listUri).items.select('ID').top(1).orderBy('Id').get();
    var lastItems = listLocation.web.getList(listLocation.listUri).items.select('ID').top(1).orderBy('Id', false).get();
	const allMySites  = [];

    if (firstItems.length === 1 && lastItems.length === 1) {
      const firstId: number = firstItems[0].ID;
      const lastId: number = lastItems[0].ID;
      let startId = firstId;
      let endId = firstId + 5000;
      do {
        let mySites: ISite[] = await listLocation.web.getList(listLocation.listUri).items

          .select('ID', 'Title', 'Url')
          .filter(`Id ge ${startId} and Id lt ${endId} and ProprietairesPeople/Id eq ${userId}`)
          .expand('ProprietairesPeople')
          .orderBy('Title')
          .top(5000)
          .getAll(); 

          allMySites.push(...mySites);
          startId = startId + 5000;
          endId = endId + 5000;
      }
      while (endId < lastId);
    }
    return allMySites;


Add User To Group With Rest

On 20/09/2021

Add User To Sharepoint Group With Rest

 


var fdi = fdi || {};

fdi.post = function(request, data, urlWeb, retFunction, expecedcode=200, odata="verbose"){
    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/contextinfo?&select=FormDigestValue";
	var xhr = new XMLHttpRequest();
	xhr.open('POST', url, true);
	xhr.setRequestHeader("Accept", "application/json; odata=nometadata");
	xhr.onload = function () {
		if (xhr.status === 200) {
			console.log(url + " : success");
			var d = JSON.parse(xhr.responseText);
            console.dir(d.FormDigestValue);

            var viewXml =  "" +
                    "" +
                    "" +
                    "" +
                    "";
            
            var req = { "query" :{"__metadata": { "type": "SP.CamlQuery" }, "ViewXml": viewXml}};
            var xhrPOST = new XMLHttpRequest();
            var reqUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/sitegroups(5)/users";
            //debugger;
            xhrPOST.open('POST', reqUrl, true);
            xhrPOST.setRequestHeader("Accept", "application/json; odata=" + odata);
            xhrPOST.setRequestHeader("content-type", "application/json; odata=" + odata);
            xhrPOST.setRequestHeader("X-RequestDigest", d.FormDigestValue);

            console.log("onload");
            xhrPOST.onload = function () {
                
            console.log("onload ok");
                console.dir(JSON.parse(xhrPOST.responseText));
            }
			
			var metadata = {  
    __metadata: {  
        'type': 'SP.User'  
    },  
    LoginName: 'i:0#.f|membership|fred.ddiet@test.com'  
};  JSON.stringify(metadata)
            xhrPOST.send(JSON.stringify(metadata));
            console.log("sent");
		}
		else {
			console.log("error");
			console.log(xhr.status);
			console.dir(xhr);
			console.dir(xhr.responseText);			
		}
	};
    xhr.send();
};

fdi.post();

Get Sharepoint List Items Count

On 02/04/2021

Get Sharepoint list Items count


var xhr = new XMLHttpRequest();
console.clear();
var url = "https://mySiteUrl";
xhr.open('GET', url + "/_api/web/Lists/getbytitle('TheListName')?$select=ItemCount,Title");

xhr.setRequestHeader("Accept", "application/json; odata=verbose");
 
xhr.onload = function () {
	if (xhr.status === 200) {
		var kk = JSON.parse(xhr.responseText);
		console.dir(kk.d.Title + " Item Count : " + kk.d.ItemCount);
	}
	else {
		console.dir(xhr);
		alert('Request failed. Returned status of ' + xhr.status);
	}
};
xhr.send();

In your browser you must be your your site url, push key F12 paste above code in console, en push enter

Listitemscount

fr

Sharepoint Rest Caml Query

On 06/01/2021

Use Sharepoint REST api to do a caml query

 


fdi.post = function(request, data, urlWeb, retFunction, expecedcode=200, odata="verbose"){
    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/contextinfo?&select=FormDigestValue";
	var xhr = new XMLHttpRequest();
	xhr.open('POST', url, true);
	xhr.setRequestHeader("Accept", "application/json; odata=nometadata");
	xhr.onload = function (data) {
		if (xhr.status === 200) {
			console.log(url + " : success");
			var d = JSON.parse(xhr.responseText);
            console.dir(d.FormDigestValue);

            var viewXml =  "<View>" +
                    "<Query>" +
                    "<Where></Where>" +
                    "</Query>" +
                    "</View>";
            
            var req = { "query" :{"__metadata": { "type": "SP.CamlQuery" }, "ViewXml": viewXml}};
            var xhrPOST = new XMLHttpRequest();
            var reqUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('Catalogue Produits')/GetItems";
            debugger;
            xhrPOST.open('POST', reqUrl, true);
            xhrPOST.setRequestHeader("Accept", "application/json; odata=" + odata);
            xhrPOST.setRequestHeader("content-type", "application/json; odata=" + odata);
            xhrPOST.setRequestHeader("X-RequestDigest", d.FormDigestValue);

            console.log("onload");
            xhrPOST.onload = function () {
                
            console.log("onload ok");
                console.dir(JSON.parse(xhrPOST.responseText));
            }
            xhrPOST.send(JSON.stringify(req));
            console.log("sent");
		}
		else {
			console.log("error");
			console.log(xhr.status);
			console.dir(xhr);
			console.dir(xhr.responseText);			
		}
	};
    xhr.send();
};