вторник, 30 июня 2015 г.

SharePoint. Как послать email используя JavaScript


У меня возникла необходимость послать email сообщение c формы элемента, сделав это асинхронно из JavaScript. В JSOM я не нашел такой возможности.

Способ № 1
Первое что пришло в голову - сделать на C# веб-часть, которая будет брать данные из url и отсылать почту, код выглядит достаточно коротким:

using (var oSite = new SPSite(SPContext.Current.Web.Url))
using (var oWeb = oSite.OpenWeb(SPContext.Current.Web.ServerRelativeUrl))
{
    string to, subject, body;
    to = Page.Request.QueryString["to"];
    subject = Page.Request.QueryString["subject"];
    body = Page.Request.QueryString["body"];
                
    var headers = new StringDictionary
        {
            {"to", to},
            {"subject", subject},
            {"content-type", "text/html"}
        };
        SPUtility.SendEmail(oWeb, headers, body);
}


Теперь нам необходимо вызвать серверной код GET запросом, код на JavaScript & jQuery будет выглядеть так:

// Отсылаем уведомление
function  SendMail(to, subject, body) {
    $.ajax({
        url: '/SitePages/SendMail.aspx',
        type: 'GET',
        data: { to: to, subject: subject, body: body },
        contentType: 'application/json; charset=utf-8',
        success: function  (response) {
            console.log("success send email to secretary");
        },
        error: function  () {
            console.log("error");
        }
    });
}


Недостаток этого решения в самом решении. Нужно создавать и разворачивать веб-часть, SPUtility недоступен в Sandbox решениях. Возможны прочие причины не использовать серверный код.

Способ № 2
Есть другой пусть. Как известно, мы можем слать письма используя рабочий процесс, так же мы знаем о возможности создавать элементы списка используя JSOM. Т.е. можем создать JavaScript'ом элемент списка, на создании которого запуститься рабочий процесс и отошлет письмо. Чтобы у рабочего процесса была информация куда, с какой темой и что слать - создадим соответствующие поля в списке. Наш элемент списка  должен  иметь 3 столбца:
  • Кому
  • Тема
  • Тело
Итак, у нас будет функция которая будет написана на JavaScript и использовать JSOM для создания элемента в списке:

// Создаем элемент списка
function CreateEmailListItem(emailListTitle, to, subject, body) {
    var clientContext = new SP.ClientContext.get_current();
    var oList = clientContext.get_web().get_lists().getByTitle(emailListTitle);
    var itemCreateInfo = new SP.ListItemCreationInformation();
    this.oListItem = oList.addItem(itemCreateInfo);

    oListItem.set_item('To', to);
    oListItem.set_item('Subject', subject);
    oListItem.set_item('Body', body);
    oListItem.update();
    clientContext.load(oListItem);

    clientContext.executeQueryAsync(function.createDelegate(this, this.onQuerySucceededEmailListItem), function.createDelegate(this, this.onQueryFailedEmailListItem));
}

function onQuerySucceededEmailListItem() {
    console.log('(Успех. Элемент списка создан.)Item created: ' + oListItem.get_id());
}

function onQueryFailedEmailListItem(sender, args) {
    console.log('Request failed. (Ошибка. Элемент списка не создан.)' + args.get_message() + '\n' + args.get_stackTrace());
}

После создания элемента будет срабатывать рабочий процесс отсылающий письмо. Для этого нам нужно одно действие рабочего процесса:



В редакторе необходимо настроить действие:


Для начала заполним отправителя:


Аналогично необходимо заполнить поля "Тема" и "Тело":


Теперь действие рабочего процесса заполнено:

 Необходимо опубликовать рабочий процесс и обязательно отметить пункт "Автоматически запускать рабочий процесс при создании элемента":
 Теперь попробуем вызвать нашу JavaScript функцию:

CreateEmailListItem('emailList', 'Ulmaskulov_ar@Borets.ru', 'subject', 'body')

После выполнения функции в списке можно увидеть созданный элемент:
После создания выполнится рабочий процесс и отправит письмо. Это решает проблему.

P. S. Не забудьте разобраться с правами на список, иначе пользователи смогут читать сообщения отправленные не им.
Рекомендую перейти в настройки списка: Параметры -> Дополнительные параметры -> Разрешения на уровне элементов -> Доступ на чтение и отметить "Чтение элементов, созданных пользователем". Выглядит это так:


Способ № 3
После публикации ссылки на пост в фейсбуке, в комментариях, мне подсказали еще один способ. Вероятно, это самый удобный из всех возможных. Спасибо Denis Molodtsov и Иван Горбадей.
Суть способа заключается в отправке запроса к SharePoint REST API.
Код выглядит так:

function SendEmail(from, to, body, subject) {
    var siteurl = _spPageContextInfo.webServerRelativeUrl;
    var urlTemplate = siteurl + "/_api/SP.Utilities.Utility.SendEmail";
    $.ajax({
        contentType: 'application/json',
        url: urlTemplate,
        type: "POST",
        data: JSON.stringify({
            'properties': {
                '__metadata': { 'type': 'SP.Utilities.EmailProperties' },
                'From': from,
                'To': { 'results': [to] },
                'Body': body,
                'Subject': subject
            }
        }
        ),
        headers: {
            "Accept": "application/json;odata=verbose",
            "content-type": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        },
        success: function(data) {
            alert("Email sent");
        },
        error: function(err) {
            alert(err.responseText);
        }
    });
};

понедельник, 1 июня 2015 г.

SharePoint. Error: Cannot complete the copy or merge operation because the database schema versions are different


Ошибка возникла при попытке перенести коллекцию сайтов в другую базу данных контента.
Как это делать можно узнать по ссылке. Если кратко, то необходимо выполнить следующий PowerShell коммандлет:

Move-SPSite <http://ServerName/SiteName> -DestinationDatabase <DestinationContentDb>

Что бы исправить ошибку необходима одинаковая схема БД контента источника и цели, т.е. куда переноситься коллекция. Еще проще говоря, БД контента должны иметь идентичную схему, что бы была возможность переноса коллекций сайтов между ними.
Как могло получиться, что схемы разные? Скорее всего после обновления. Новая БД контента создается по новой схеме, а старая работает в диапазоне совместимости.

В моём случае необходимо было обновить схему БД источника.
На картинке видно, что БД контента (WSS_Content), откуда мне необходимо перенести коллекцию сайтов - требует обновления, в отличии от БД контента в которую будет перемещена коллекция (WSS_Content_SSTD):

Что бы точно узнать версии схем - клик по имени базы, на отдельной странице будут написаны подробные сведения о БД:



Для обновления БД контента необходимо выполнить PowerShell скрипт:

Upgrade-SPContentDatabase <DB Name>

Подробности о коммандлете можно прочитать здесь.
Так же, если необходимо, обновите все остальные не БД контента, делается это другим коммандлетом:

(Get-SPDatabase <DB_id> ).Provision();

После обновления БД контента Вы увидите следующее:


Теперь ошибка о разности схем исчезнет и можно выполнить перенос коллекции сайтов.