Saturday 14 May 2016

Рассылка почтовых сообщений с помощью JavaScript REST API в SharePoint

Выполнить передачу почтового сообщения с помощью метода SendEmail на стороне клиента легко. В сети имеются масса примеров, о том как это сделать.
О проблемах исполнения этого метода тоже немало написано. Например частой ошибкой является - недействительный адрес электронной почты пользователя SharePoint. Даже, если достоверно известно, что пользователь имеет подтвержденный электронный адрес и у него достаточно высокий уровень доступа к материалам сайта, при отправке почты ему могут возникнуть проблемы. 
Лично я обнаружив, что нельзя довериться способу передачи почты с помощью методов sharepoint rest api, решил подстраховаться и написать в рамках собственного web service метод передачи почты пользователю SharePoint.
Конечно, если в вашей ферме SharePoint не работает собственное решение методов web service, то писать и развертывать его в ферме  только лишь для указанных целей, не стоит :). У меня же уже имелся в ферме собственный web service, в рамках которого выполнялись несколько десятков методов, поэтому добавить туда еще один метод - не проблема.

Итак, что я сделал:

sendEmailфункция javascript. она выполняет простую работу - передает почтовое сообщение пользователю (или группе пользователям). Если возникают проблемы, то функция обращается к моему методу на сервере (обратите внимание на функцию GetReturnAjax). Там, за "кулисами" работает метод SetItemSPSendEmailItem. Как правило с ним проблем не бывает :).

function sendEmail(from, to, body, subject, containerId, gridId, urlPanel, mparam) {        
    var urlTemplate = _spPageContextInfo.webAbsoluteUrl + 
"/_api/SP.Utilities.Utility.SendEmail";
    var container = $('#' + containerId);
    $.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()
        },
        beforeSend: function () {
            if (container.length) {
                container.prepend($('<p />').addClass('loading-aj-dialog'))
            }
        },
        success: function (data) {
            container.find('p.loading-aj-dialog').remove();
            GetReturnAjax(urlPanel, JSON.stringify(mparam), false,
                function (data) {
                    container.find('p.loading-aj-dialog').remove();
                    alert(subject + " передано успешно.");
            }, containerId);
        },
        error: function (err) {
            container.find('p.loading-aj-dialog').remove();
            console.log(JSON.stringify(err));
            var mparam2 = { "subject": subject,"body": body, "to": to };
            //если ошибка, то пытаемся передать сообщение через собственную службу
            GetReturnAjax(urlPanel, JSON.stringify(mparam2), false,
                function (data) {
                    container.find('p.loading-aj-dialog').remove();
                    alert(subject + " передано успешно.");
                }, containerId);
        }
    });
}
Метод на сервере на тот случай, если на клиенте будут проблемы.        
        [WebMethod]
        [System.Web.Script.Services.ScriptMethod ( UseHttpGet = false, ResponseFormat = ResponseFormat.Json )]
        public m_message SetItemSPSendEmailItem ( string subject,
            string body, string to )
        {
            m_message retur = new m_message { title = "", type = 2 };
            string error = "";
            using ( SPSite site = new SPSite ( this.GetUrlSite ) )
            {
                using ( SPWeb web = site.OpenWeb ( ) )
                {
                    try
                    {                                                
                        if ( !string.IsNullOrEmpty ( subject ) && 
                             !string.IsNullOrEmpty ( body ) && 
                             !string.IsNullOrEmpty ( to ) )
                        {
                            SPUtility.SendEmail ( web, truefalse, to, subject, body );
                        }
                    }
                    catch ( Exception ex )
                    {
                        error = ex.ToString ( );
                        retur.title = error;
                    }
                    finally
                    {
                        if ( web != null )
                            web.Dispose ( );
                    }
                }
            }
            return retur;
        }
Ну, вот, на сегодня, пожалуй все.

Tuesday 26 April 2016

Подробней о технической стороне решения "Работа с проектами документов". Часть 1

Прошлый мой материал имеет краткое описание форм решения "Работа с проектами документов" для SharePoint 2013. Здесь же, как я и обещал ранее, будет описание технической стороны этого проекта.
Следует сразу же оговориться, что данный проект целесообразно было бы сделать в рамках приложения для SharePoint 2013. Здесь же следует описание проекта, который состоит из нескольких изолированный решений Sharepoint 2013 и решений для фермы Sharepoint 2013.

Изолированные решения:

  1. Библиотека документов "Работа с проектами документов"
  2. Настраиваемый список "Участники согласования документов"
  3. Настраиваемый список "mListSP" (Таблица связи)
  4. Список "Обсуждение проектов документов"
  5. Пользовательское действие (CustomAction) 

Решения для фермы

  1. Библиотека. Методы для выполнения на стороне сервера Веб сервисов (WCF and SOAP). Методы этого решения выполняют задачи, которые было сложно сделать в рамках существующих в sharepoint 2013 rest api. Именно сложно, а невозможно. Лично я рекомендую использовать в своих работах методы sharepoint 2013 rest api. Но, к сожалению, сам не всегда следую собственным рекомендациям :). 
  2. Библиотека. Методы для контроля обработчиков событий. Расширение класса SPItemEventReceiver. Методы решения контролируют события - создания, редактирования и удаления строк в библиотеках и списках.
  3. Библиотека. Методы для выполнения заданий по исследованию содержимого проекта. Расширение класса SPJobDefinition
Это первая часть материалов. Далее планируется раскрывать каждую техническую часть подробней. Там же будут выложены ссылки на исходный материал.

Организация процесса согласования проектов документов. Решение для SharePoint 2013.

Поставлена задача написать для Sharepoint 2013 решение которое будет организовывать процесс согласования проектов документов.
При этом, главным условием было наличие в решении двух видов согласования: 
  1. Параллельный
  2. Последовательный
Кроме этого решение должно позволять:
  1. Регулировать уровень доступа к проекту документа индивидуально для каждого документа.
  2. Назначать каждому проекту документа (далее по тексту - Проект) тип согласования индивидуально.
  3. Создавать для каждого Проекта свой индивидуальный список согласующих лиц и предусмотреть возможность для автора Проекта редактировать этот список на любом этапе процесса согласования. Доступ к редакторам списка должен иметь только инициатор процесса согласования. Все остальные пользователи сайта SharePoint, включая участников согласования и администраторов сайта могут видеть только не редактируемый список согласующих лиц.
  4. Предусмотреть систему оповещения авторов Проектов, а так же участников процесса согласования о любых значимых событиях процесса согласования по почте.
  5. Предусмотреть возможность обсуждения Проектов участниками согласования в отдельном решении SharePoint (далее по тексту - Решение по обсуждению Проектов). При этом Решение по обсуждению Проектов должно быть интегрировано в единую систему оповещения о событиях процесса согласования.
  6. Исключить возможность редактирования документов после согласования.  
В итоге получаем единое решение SharePoint 2013, состоящее из
  1. Модернизированная библиотека документов "Проекты документов". Библиотека будет содержать документы.
  2. Настраиваемый список "Список согласующих лиц". Список будет хранить участников согласования.
  3. Настраиваемый список "Связи участников согласования с проектами документов". Список будет хранить информацию о связях библиотеки документов со списком участников согласования. Между библиотекой документов и списком мы организуем отношения "Много ко Многим". Например у конкретного документа будет множество участников согласования, которые принимали по нему решение и наоборот - у одного участника согласования будет множество документов, по которым он принимал решение. 
  4. CustomAction. Для меню проекта.

Некоторые формы решения:

1. Редактор библиотеки документов:


2. Представление библиотеки документов


3. Редактор списка Участников согласования документов 


4. Представление участников согласования

5. Представление списка связей участников согласования документов и документов

6. Редактор связи библиотеки документов и списка участников согласования

7. Форма обсуждения проектов документов


8. Форма на финише согласования документов. Возможность распечатать список согласовавших проект документа

В следующих постах будут раскрыты детали проекта поэтапно. Следите за обновление материалов :)