Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

Работа с API службы профилей пользователей SharePoint с помощью Node.js

Данная статья является логическим продолжением предыдущей публикации, где разбиралось, как работать со службой управляемых метаданных (MMD). Статья приоткрывает проблематику работы с SharePoint API средствами Node.js, а именно - работу с API очень популярного сервиса SharePoint - службами профилей пользователей (UPS).

REST интерфейс для UPS будет поинтереснее аналогичного для MMD, как минимум он есть. Разделы UPS API PeopleManager и ProfileLoader позволяют довольно много чего. Однако, как всегда, не обошлось без того, что чего-то да и не хватает, не все возможности CSOM UPS присустствуют в его аналоге на REST. Большинство методов предназначены для работы с собственным профилем и большинство свойств только на чтение.

В нашем же сценарии мы собираемся создать механизм по записи свойств в произвольные профили. Так же, как и в случае с MMD, будут задействованы SOAP службы и CSOM/JSOM интерфейс для того, чтобы расширить возможности кода на Node.js. Такой сценарий имеет место быть, если у нас есть сторонний источник данных с данными пользователей и нам надо синхронизировать эти свойства с профилями, при этом по какой-то неведомой причине условие - использовать только JavaScript для задачи, запускаемой по расписанию.

SOAP

Дедушка SOAP API в SharePoint прячется по ссылке /_vti_bin/UserProfileService.asmx. Сервис, на самом деле, довольно большой и в нем порядка 40 методов. Ну что, весьма не дурно.

Для записи свойств нас интересует следующий метод - ModifyUserPropertyByAccountName. Он позволяет писать одиночные и мультизначения в свойства заданного профиля.

Так же, как и в случае с MMD, для обеспечения коммуникации с SharePoint задействуем sp-request и node-sp-auth. Привет Сергею Сергееву, автору данных чудесных библиотек!

Взглянем на ModifyUserPropertyByAccountName. SOAP пакет выглядит следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ModifyUserPropertyByAccountName
   xmlns="http://microsoft.com/webservices/SharePointPortalServer/UserProfileService">
            <accountName>{{ accountName }}</accountName>
            <newData>
                {{#newData}}
                <PropertyData>
                    <IsPrivacyChanged>{{ isPrivacyChanged }}</IsPrivacyChanged>
                    <IsValueChanged>{{ isValueChanged }}</IsValueChanged>
                    <Name>{{ name }}</Name>
                    <Privacy>{{ privacy }}</Privacy>
                    <Values>
                        {{#values}}
                        <ValueData>
                            <Value xsi:type="xsd:string">{{ this }}</Value>
                        </ValueData>
                        {{/values}}
                    </Values>
                </PropertyData>
                {{/newData}}
            </newData>
        </ModifyUserPropertyByAccountName>
    </soap:Body>
</soap:Envelope>

Динамически подставляемые параметры:

  • accountName - логин пользователя (i:0#.f|membership|user.name@contoso.com)
  • newData - массив свойств
    • name - имя свойства
    • values - значение(я) свойства

После того, как XML безобразие обернуто в человеческий вид, работать с методом можно так:

let Screwdriver = require('sp-scredriver');  
let context = require('./path_to_private_settings');  
let screw = new Screwdriver(context);

let data = {
    baseUrl: context.siteUrl,
    accountName: config.ups.accountName,
    newData: [{
        isPrivacyChanged: false,
        isValueChanged: true,
        privacy: 'NotSet',
        name: 'SPS-Birthday',
        values: [ '10.03' ]
    }, {
        isPrivacyChanged: false,
        isValueChanged: true,
        privacy: 'NotSet',
        name: 'SPS-Department',
        values: [ 'Administration' ]
    }]
};

screw.ups.modifyUserPropertyByAccountName(data)
    .then(response => {
        console.log('Response:', response.body);
    })
    .catch(err => console.log('Error:', err.message));

Все есть на GitHub

На этом с SOAP составляющей все. Я на самом деле, жутко не люблю SOAP. Получается дружба по принуждению, к счастью, помимо мыльца есть и альтернатива с client.svc.

CSOM/JSOM

В CSOM API присутствуют два метода по записи свойств setSingleValueProfileProperty и setMultiValuedProfileProperty, их-то и будем оборачивать в библиотеку. В предыдущей статье описано более подробно, в этом контексте не буду повторяться, упомяну лишь, что нужно реализовать требуемую функциональность в JSOM и посмотреть отправляемый на client.svc пакет в fiddler.

// JSOM вариант
var clientContext = new SP.ClientContext.get_current();
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);

peopleManager.setMultiValuedProfileProperty(
   `i:0#.f|membership|${_spPageContextInfo.userLoginName}`, 
   'SPS-Skills', 
   [ 'Git', 'Node.js', 'JavaScript', 'SharePoint' ]
);

clientContext.executeQueryAsync(
    () => console.log('Done'), 
    (sender, args) => console.log('Error:', args.get_message())
);

При перехвате fiddler'ом получаем пакет:

<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="15.0.0.0" ApplicationName="Javascript Library">
    <Actions>
        <ObjectPath Id="82" ObjectPathId="81" />
        <Method Name="SetMultiValuedProfileProperty" Id="83" ObjectPathId="81">
            <Parameters>
                <Parameter Type="String">{{ accountName }}</Parameter>
                <Parameter Type="String">{{ propertyName }}</Parameter>
                <Parameter Type="Array">
                    {{#propertyValues}}
                    <Object Type="String">{{ this }}</Object>
                    {{/propertyValues}}
                </Parameter>
            </Parameters>
        </Method>
    </Actions>
    <ObjectPaths>
        <Constructor Id="81" TypeId="{cf560d69-0fdb-4489-a216-b6b47adf8ef8}" />
    </ObjectPaths>
</Request>

Где:

  • accountName - опять же логин (i:0#.f|membership|user.name@contoso.com)
  • propertyName - наименование свойства
  • propertyValues - массив значений свойства

После обертки в библиотеку на Node.js, уже не надо думать о пакетах, а использовать следующий вызов:

let Screwdriver = require('sp-scredriver');  
let context = require('./path_to_private_settings');  
let screw = new Screwdriver(context);

let data = {
    baseUrl: context.siteUrl,
    accountName: config.ups.accountName,
    propertyName: 'SPS-Skills',
    propertyValues: [ 'Git', 'Node.js', 'JavaScript', 'SharePoint' ]
};

screw.ups.setMultiValuedProfileProperty(data)
    .then(response => {
        console.log('Response:', JSON.parse(response.body));
    })
    .catch(err => console.log('Error:', err.message));

setSingleValueProfileProperty практически идентичен, только проще.

Все исходники можно посмотреть на GitHub. Как уже говорил раньше, sp-screwdriver - библиотека не для "продакшена", а пример, отражающий то, как можно реализовать сценарии программного взаимодействия с SharePoint в Node.js, когда это вдруг стало жизненно необходимо, либо Вы фанат технологии, как я.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.