Показаны сообщения с ярлыком JS. Показать все сообщения
Показаны сообщения с ярлыком JS. Показать все сообщения

вторник, 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);
        }
    });
};

четверг, 28 августа 2014 г.

SharePoint 2013. ClientPeoplePicker & Custom forms

Многие уже знают, что в SharePoint 2013 появился новый замечательный элемент управления для работы с данными типа "Пользователь". Выглядит он так:
И именно этот элемент управления, с возможность предлагать возможные значения, отображается во всех формах элементов списка по умолчанию. И это очень хорошо.
Проблемы возникают когда Вы создаете новую форму.
Напомню, что в формах по умолчанию, за генерацию полей отвечает ListFormWebPart. Но если Вы создаете новую форму, то функцию генерации html полей на себя берет DataFormWebPart. При этом каждое отдельное поле генерируется элементом управления FormField. Кастомизировать форму становиться намного легче. Но при этом вместо нового ClientPeoplePicker мы видим старый контрол, без автокомплита и с кнопками проверки пользователя и кнопки для открытия всплывающего окна для поиска пользователя:
Как я уже упомянул, каждое поле генерируется SharePoint:FormField. Я пытался найти возможность "попросить" его вывести именно новый ClientPeoplePicker, но тщетно.
Мы сами можем добавить новый контрол на страницу, для этого добавим на форму такой код:


После этого у нас появится прекрасно работающий ClientPeoplePicker. Вот только нужно его привязать к полю и делать это нужно самому. Я сделал это спрятав основной контрол, который без автокомплита, но только спрятал, с самой формы не убирал. Дальше, используя JavaScript, в методе PreSaveAction() перед сохранением формы брал данные из ClientPeoplePicker и вставлял их в старый PeoplePicker. Что бы мне было удобно работать, я использовал библиотеку SPSservices.
// Заполняем поля в PeoplePicker
var arrUserField = [];
$("#UserFieldCPP_TopSpan span span span[class='ms-entity-resolved']").each(function(index, elem){
    arrUserField.push($(this).text());
});
var strUserField = arrUserField.join(";");

$().SPServices.SPFindPeoplePicker({
 peoplePickerDisplayName: "Сотрудник",
 valueToSet: strUserField ,
 checkNames: true
});
Т.е. перед сохранение формы данные из ClientPeoplePicker копируются в обычный PeoplePicker.
Приведенный код подходит для формы создания элемента, для формы редактирования нам нужно из обычного PeoplePicker'а скопировать в ClientPeoplePicker. Используйте этот код:

// Заполняем поля в ClientPeoplePicker
var UserFieldPP = $().SPServices.SPFindPeoplePicker({
 peoplePickerDisplayName: "Сотрудник" 
});

var UserFieldPPPeopleList = UserFieldPP.currentValue.split(";");
UserFieldPPPeopleList.pop(); 
var picker = SPClientPeoplePicker.SPClientPeoplePickerDict["UserFieldCPP_TopSpan"]

for (i = 0; i < UserFieldPPPeopleList.length; i++) { 
    var name = UserFieldPPPeopleList[i];
 $("#UserFieldCPP_TopSpan_EditorInput").val(name);
 picker.AddUnresolvedUserFromEditor(true)
}
Теперь кастомные формы могут иметь ClientPeoplePicker привязанный к полю в списке.
Код работает в т.ч. для множественных значений. Так же, что бы приведенный выше код работал, ID у ClientPeoplePicker должно быть "UserFieldCPP".