пятница, 17 мая 2013 г.

Пагинация в Oracle

Как известно, БД от Oracle не поддерживает инструкцию LIMIT в SQL-запросах. Поэтому на первых порах часто возникают вопросы, о том как реализовать пагинацию в Oracle. Тут на самом деле все просто. Достаточно использовать rownum, например вот так:
select *
from some_table
where <some_conditions>
  and rownum >= 1
  and rownum < 20

Казалось бы ВОТ ОНО. Но не тут то было. Как только возникает потребность реализовать пагинацию над некой агрегированной выборкой (выборка с использованием групповых функций), приходится выполнить ряд дополнительных телодвижений:
select tmp.*
from
  (select field1,
          count(field2) field2_cnt
          sum(field3) field3_sum
   from some_table
   where <some_conditions>
   group by field1) tmp
where rownum >= 1
  and rownum < 20
Что здесь происходит? Здесь сначала делается выборка по полям, удовлетворяющим условиям, выполняются групповые операции над ними, затем отсечку по rownum делаем уже над сгруппированными данными, таким образом падгинация работает, как и ожидалось. Вот такой вот небольшой хинт. Ну и всё это можно обернуть в некую хранимую функцию на pl/sql:

funсtion get_padgination_cursor(page in integer := 1) return sys_ref_cursor as
  cr sys_ref_cursor;
  records_per_page integer := 20;
  start_limit integer := records_per_page * (page - 1) + 1;
  stop_limit integer := start_limit + records_per_page;
begin
  open cr for
    select tmp.*
    from
      (select field1,
              count(field2) field2_cnt
              sum(field3) field3_sum
       from some_table
       where <some_conditions>
       group by field1) tmp
    where rownum >= start_limit
      and rownum < stop_limit;

  return cr;
end;

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

Авторизация в Redmine через ActiveDirectory с использованием ролей

Столкнулся недавно с, казалось бы, уже многократно пережеванной задачей - интеграцией Redmine и Active Directory, но с одни доп. условием - авторизация должна проходить только для пользователей из определенной группы в AD. Ну сказано - сделано. Поэтому, чтобы и самому не забыть, да и, вдруг, кому пригодиться, оставлю здесь пошаговую инструкцию.

Для ясности договоримся, что домен у нас зовется domain.local

Итак, первым делом, нам нужен служебный пользователь в AD с правами на чтение атрибутов всех пользователей домена (ну или отдельно взятой ОУшки). Сделать это несложно, пускай пользователя будут звать ldap_agent. Теперь в оснастке управления AD (пользователи и компьютеры) выбираем нужный домен/ОУшку, кликаем в меню Действия->Делегирование управления, в визарде всё понятно без слов, поэтому пропущу этот момент. Итак, двигаемся далее. Теперь займемся непосредственно Redmine'ом. Тут тоже все просто. Администрирование ->Авторизация с помощью LDAP. Там добавляем новый способ аутентификации или правим уже существующий (если таковой имеется). Переходим в форму настройки аутентификации. Там пишем следующее:
Имя: ActiveDirectory # любое имя, идентифицирующее текущий способ аутентификации Компьютер: dc.domain.local # имя (или IP) хоста, выполняющего роль контроллера домена Порт: 389 # порт, на котором висит сервис LDAP на контроллере домена (для ActiveDirectory по умолчанию 389) Учётная запись: domain\ldap_agent # учетная запись в домене, под которой будем коннектиться к контроллеру и аутентифицировать пользователя (данному пользователю должны быть выданы права на чтение всех атрибутов всех пользователей домена или ОУшки, для которой должна работать авторизация) Пароль: long_secret # пароль вышеуказанной учетной записи BaseDN: dc=domain, dc=local # базовые параметры домена (и/или ОУшки в этом случае в начале строке следует дописать еще примерно вот это: ou=ouName,...) Фильтр LDAP: (&(objectClass=user)(memberOf=cn=RedmineUsers, ou=LocDomainGroups, dc=domain, dc=local)) # Фильтр, позволяющий реализовать более гибкую систему авторизации, например, авторизовать пользователя только при наличии определенной роли. В качестве примера, пускаем только пользователей из группы ReadmineUsers, которая, в свою очередь, находится в ОУшке LocDomainGroups. Таймаут в секундах: # время ожидания ответа от контроллера - оставим пустым (и пусть весь мир подождет)))) Создание пользователя на лету: true # позволяет автоматически создавать пользователя при его первой успешной авторизации
В разделе формы с атрибутами настраиваем соответствие атрибутов пользователя в Redmine к атрибутам пользователя в AD:
Пользователь: sAMAccountName # наименование атрибута в LDAP, с которым будет сравниваться логин пользователя Имя: givenName # наименование атрибута в LDAP, из которого будет автоматически подтягиваться имя пользователя в Redmine Фамилия: sn # наименование атрибута в LDAP, из которого будет автоматически подтягиваться фамилия пользователя в Redmine email: mail # наименование атрибута в LDAP, из которого будет автоматически подтягиваться email пользователя в Redmine

Вот, собственно, и всё. Да, чуть не забыл. Этот способ был опробован на Redmine версии 2.1, в более ранних версиях не было возможности задавать дополнительные LDAP-фильтры