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

воскресенье, 9 декабря 2012 г.

CAML-запросы с расширенной фильтрацией по пользователям и группам

Давно забытое старое!
Речь сегодня пойдёт об использовании тега Membership в CAML-запросах.
Этого тега нет ни в CAML Builder ни в CAML Designer, поэтому не все знают о его существовании.
Тем не менее, на MSDN присутствует описание этого тега, хоть и без примеров.
Итак, запрос с использованием этого тега может выглядеть так:
<Where>
  <Membership Type='CurrentUserGroups'>
    <FieldRef Name='Person' />
  </Membership>
</Where>

Тег Membership содержит атрибут Type, указывающий тип фильтрации:
  • SPWeb.AllUsers – Выбор элементов, содержащих в указанном поле пользователя
  • SPWeb.Groups - Выбор элементов, содержащих в указанном поле группу
  • SPWeb.Users - Выбор элементов, содержащих в указанном поле пользователя, не содержащегося в группе 
  • CurrentUserGroups - Выбор элементов, содержащих в указанном поле группу, в которую входит текущий пользователь
  • SPGroup - Выбор элементов, содержащих в указанном поле указанную группу; группа (ID) указывается отдельным атрибутом тега Membership: ID=’1’

Пример.
Допустим имеем такой список:
image

Тестовое (консольное) приложение:
static void Main(string[] args)
{
    var values = new Dictionary<string, int>
        {
            {"SPWeb.AllUsers", 7},
            {"SPWeb.Groups", 7},
            {"SPWeb.Users", 7},
            {"CurrentUserGroups", 7},
            {"SPGroup", 1073741823}
        };

    foreach (var value in values)
        RunQuery(value.Key, value.Value);

    Console.WriteLine();
    Console.WriteLine("Completed!");
    Console.ReadKey(true);
}

static void RunQuery(string membership, int userId)
{
    using (var site = new SPSite("http://x33/", GetUserToken(userId)))
    {
        using (var web = site.OpenWeb())
        {
            var list = web.Lists["CAMLTest"];

            var query = new SPQuery {Query = string.Format("<Where><Membership Type='{0}' ID='4'><FieldRef Name='Person' /></Membership></Where>", membership)};
            var items = list.GetItems(query);

            Console.WriteLine("Current user: {0}; Membership type: {1}; Items count: {2}", web.CurrentUser.Name, membership, items.Count);
            items.Cast<SPListItem>().ToList().ForEach(li => Console.WriteLine("ID - {0}; Title - {1}; Person - {2}", li.ID, li.Title, li["Person"]));
            Console.WriteLine("----------");
            Console.WriteLine();
        }
    }
}

static SPUserToken GetUserToken(int userId)
{
    using (var site = new SPSite("http://x33/"))
    {
        using (var web = site.OpenWeb())
        {
            return web.SiteUsers.GetByID(userId).UserToken;
        }
    }
}

Результат работы приложения:
image

Наиболее интересный тип фильтрации: CurrentUserGroups.
Допустим в списке у нас проставлены группы. С помощью данного запроса мы можем выбрать все элементы, которые содержат группу текущего пользователя, т.е. элементы, доступные участником тех же групп, что и для текущего пользователя! (аналог фильтрации по аудиториям)

понедельник, 27 июня 2011 г.

Проверка принадлежности текущего пользователя к аудитории для элемента навигации SharePoint

Допустим, имеется набор элементов навигации SPNavigationNodeCollection (например, web.Navigation.TopNavigationBar или web.Navigation.QuickLaunch).
Необходимо выбрать из них элементы в соответствии с установленной для них аудиторией относительно текущего пользователя.


Для данной задачи я создал следующий класс:

public static class AudienceHelper
{
    public static bool UserInAudience(this SPNavigationNode navigationNode)
    {
        //Необходимые нам данные об аудитории находятся в свойстве элемента
        if (navigationNode.Properties["Audience"] == null)
            return true;

        var audiencesLine = navigationNode.Properties["Audience"].ToString();

        /*
         * В качестве значения для аудитории может быть установлено значение одного из трёх типов:
         * Аудитории SharePoint
         * Группы безопасности
         * Группы SharePoint
         *
         * Информация об аудитории представляет собой строку вида "MyAudience;;MySecurityGroup;;MySPGroup"
         * Значения между ";;" могут отсутствовать, либо быть набором из нескольких значений разделённых ","
         * Для примера,
         * аудитория SharePoint задаётся значением "MyAudience;;;;",
         * две группы SharePoint - значением ";;;;MySPGroup1,MySPGroup2"
         */

        var audiencesList = audiencesLine.Split(new[] { ";;" }, StringSplitOptions.None).ToList();
        if (string.IsNullOrEmpty(audiencesLine) || audiencesList.Count < 3)
            return true;

        /* Для проверки наличия текущего пользователя в аудитории необходим объект AudienceLoader
         * из библиотеки Microsoft.Office.Server*/
        var audienceLoader = AudienceLoader.GetAudienceLoader();

        #region Global audience

        if (!string.IsNullOrEmpty(audiencesList[0]))
        {
            var audiences = audiencesList[0].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (audiences.Any(audienceLoader.IsUserMemberOfGlobalAudience))
                return true;
        }

        #endregion

        #region
Security group

        if (!string.IsNullOrEmpty(audiencesList[1]))
        {
            var audiences = audiencesList[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (audiences.Any(audienceLoader.IsUserMemberOfDL))
                return true;
        }

        #endregion

        #region
SharePoint group

        if (!string.IsNullOrEmpty(audiencesList[2]))
        {
            var audiences = audiencesList[2].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (audiences.Any(audienceLoader.IsUserMemberOfSharePointGroup))
                return true;
        }

        #endregion

        //Если пользователь не содержится не в одном из типов аудиторий возвращаем False
        return false;
    }
}


Теперь можем перебрать все элементы:
foreach (var navItem in web.Navigation.TopNavigationBar.Cast<SPNavigationNode>().Where(nn => nn.IsVisible && nn.UserInAudience()))
{
    //Действия с элементом   
}