Skip to content

Instantly share code, notes, and snippets.

@koltyakov
Last active February 16, 2017 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koltyakov/16c790befab48b3f33f74117ab60df54 to your computer and use it in GitHub Desktop.
Save koltyakov/16c790befab48b3f33f74117ab60df54 to your computer and use it in GitHub Desktop.

Работа с 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