Вторник, 26 января 2021 19:00

Обработка результатов поиска в LDAP. Работа с LDAP в Qt5. Часть 3.

Россия
Оцените материал
(0 голосов)

В прошлой части мы рассмотрели поиск в каталоге LDAP.

Сегодня мы рассмотрим обработку результатов поиска и создадим класс-хранилище для нашей информации.

В этой статье мы будем использовать проект из предыдущей части.

Модернизируем метод search

Сперва улучшим метод search, добавив возможность сохранять атрибуты с множеством значений.

Внесем изменения в заголовочный файл qldap.h изменив объявления типов:

typedef QStringList QLdapEntryValues;
typedef QHash<QString,QLdapEntryValues> QLdapEntry;
typedef QList<QLdapEntry> QLdapEntryList;

 Внесем изменения в сам метод, в результате он примет вид:

int QLdap::search(QString baseDN, QString filter, QLdapEntryList *searchResults, const QString codePage)
{
    QTextCodec *codec = QTextCodec::codecForName(codePage.toUtf8());

    timeval	*timeout = new timeval();
    timeout->tv_sec = 100;

    LDAPMessage *searchResultMsg;

    int result  = ldap_search_ext_s( this->ldp,
                     (char*)baseDN.toStdString().c_str(),
                     LDAP_SCOPE_SUBTREE,
                     (char*)filter.toStdString().c_str(),
                     nullptr,
                     0,
                     nullptr,
                     nullptr,
                     nullptr,
                     LDAP_NO_LIMIT,
                     &searchResultMsg
                   );
    qDebug() << "Search result = " << ldap_err2string(result);

    if ( result != LDAP_SUCCESS )
    {
        qDebug() << "ldap_parse_result() error: " << ldap_err2string(result);
    }


    result = ldap_count_entries( this->ldp, searchResultMsg);
    qDebug() << "Search results count = " << result;

    result = ldap_count_references( this->ldp, searchResultMsg);
    qDebug() << "Search results ref = " << result;


    LDAPMessage *msg;

    QLdapEntryList results;


    for ( msg = ldap_first_message( this->ldp, searchResultMsg ); msg != NULL; msg = ldap_next_message( this->ldp, msg ) )
    {
        int msgtype = ldap_msgtype( msg );
        //qDebug() << "Type" << msgtype;

        switch( msgtype ) {

            //This is a search result data
            case LDAP_RES_SEARCH_RESULT:
            {

                char *matched_msg = NULL;
                int errcodep = 0;
                char *error_msg = NULL;
                char **refs;
                LDAPControl **serverctrls;

                int aresult = ldap_parse_result( this->ldp,
                                                msg,
                                                &errcodep,
                                                nullptr,
                                                &error_msg,
                                                nullptr,
                                                nullptr,
                                                0 );
                if ( aresult != LDAP_SUCCESS )
                {
                    qDebug() << "ldap_parse_result() error: " << ldap_err2string(aresult);
                }

                if ( errcodep != LDAP_SUCCESS )
                {
                    qDebug() << "ldap_parse_result() error: " << error_msg;
                }

                if (error_msg)
                {
                      ldap_memfree(error_msg);
                      return errcodep;
                }


                break;
            }

            //This is a data item of search
            case LDAP_RES_SEARCH_ENTRY:
            {
                BerElement *ber;
                char *a;

                QLdapEntry entry;

                for ( a = ldap_first_attribute( this->ldp, msg, &ber );
                      a != NULL;
                      a = ldap_next_attribute( this->ldp, msg, ber ) ) {



                    struct berval **values;
                    struct berval value;

                    //qDebug() << a;

                    if (( values = ldap_get_values_len( this->ldp, msg, a )) != NULL ) {

                        QLdapEntryValues attrvalues = QLdapEntryValues();

                        for ( int i = 0; values[ i ] != NULL; i++ ) {
                            value = *values[i];

                            QByteArray buf = value.bv_val;


                            QString text;
                            if (codePage.compare("utf-8") == 0) {
                                text = buf;
                            } else {
                                text  = codec->toUnicode(buf);
                            }


                            attrvalues.append(text);


//                            qDebug() << a << ":" << text;
                        }

                        entry.insert(a,attrvalues);
                        ldap_value_free_len( values );
                    }

                    ldap_memfree( a );
                }
                searchResults->append(entry);
                break;
            }
        }
    }

    ldap_msgfree(searchResultMsg);
    ldap_msgfree(msg);
    return LDAP_SUCCESS;
}

Обработка результатов поиска

Добавим в конструктор главной формы код:

     for( auto e = searchResults->begin(); e != searchResults->end(); ++e)
     {
         qDebug() << e->find("displayName").value() << e->find("title").value() << e->find("objectClass").value();
     }

Здесь мы используем итератор, для того чтобы пройти по всем элементам списка.

Запустим: 

("Павлова Ясмина Всеволодовна") ("Директор") ("top", "person", "organizationalPerson", "user")
("Калинина Виктория Леоновна") ("Заместитель директора") ("top", "person", "organizationalPerson", "user")
("Смирнов Арсений Владимирович") ("Заместитель директора") ("top", "person", "organizationalPerson", "user")
("Лебедева Валерия Адамовна") ("Секретарь") ("top", "person", "organizationalPerson", "user")
("Ильинская Ева Матвеевна") ("Главный бухгалтер") ("top", "person", "organizationalPerson", "user")
Вывод сокаращен.

Таким образом вы можете получить необходимые значения из поиска.

Так же вы можете обратиться к любому результату поиска по его индексу:

     QLdapEntry a = searchResults->at(0);
     qDebug() << a.find("displayName").value() << a.find("title").value() << a.find("objectClass").value();

Запустим 

("Павлова Ясмина Всеволодовна") ("Директор") ("top", "person", "organizationalPerson", "user")

Добавляем класс для пользователей

Создадим новый класс – QLdapUser

Заголовок:

#ifndef QLDAPUSER_H
#define QLDAPUSER_H

#include <QString>
#include "qldap.h"



class QLdapUser
{
public:
    QLdapUser();

    QLdapUser(QLdapEntry *user);

    QString getDisplayName() const;

    QString getGivenName() const;

    QString getInitials() const;

    QString getOfficePhone() const;

    QString getDepartment() const;

    QString getTitle() const;

    QString getUserPrincipalName() const;

    QString getCellPhone() const;

    QString getSamAccountName() const;

    QString getPath() const;

    QString getEmail() const;

    QString getStreetAddress() const;

    QString getOffice() const;

    QString getCompany() const;

    QString getFax() const;

    QString getUserValue(QString key) const;

    QString toString() const;
private:

    QLdapEntry *user;
};
#endif // QLDAPUSER_H

Реализация:

#include "qldapuser.h"
#include <QDebug>

QLdapUser::QLdapUser()
{

}

QLdapUser::QLdapUser(QLdapEntry *user)
{
    this->user = user;
}

QString QLdapUser::getUserValue(QString key) const
{
        return (*this->user)[key].join(",");
}

QString QLdapUser::getDisplayName() const
{
    return this->getUserValue("displayName");
}


QString QLdapUser::getInitials() const
{
    return this->getUserValue("initials");
}


QString QLdapUser::getOfficePhone() const
{
    return this->getUserValue("otherTelephone");
}

QString QLdapUser::getDepartment() const
{
    return this->getUserValue("department");
}


QString QLdapUser::getTitle() const
{
    return this->getUserValue("title");
}

QString QLdapUser::getUserPrincipalName() const
{
    return this->getUserValue("userPrincipalName");
}


QString QLdapUser::getCellPhone() const
{
    return this->getUserValue("mobile");
}

QString QLdapUser::getSamAccountName() const
{
    return this->getUserValue("sAMAccountName");
}


QString QLdapUser::getPath() const
{
    return this->getUserValue("distinguishedName");
}

QString QLdapUser::getEmail() const
{
    return this->getUserValue("mail");
}

QString QLdapUser::getStreetAddress() const
{
    return this->getUserValue("streetAddress");
}

QString QLdapUser::getOffice() const
{
    return this->getUserValue("physicalDeliveryOfficeName");
}

QString QLdapUser::getCompany() const
{
    return this->getUserValue("company");
}

QString QLdapUser::getFax() const
{
    return this->getUserValue("facsimileTelephoneNumber");
}

В прошлых статьях мы рассматривали класс – CountryFlag, в полях которого сохраняли всю необходимую информацию. На этот раз у нас все данные уже загружены в память и нет смысла создавать еще одну копию в памяти, поэтому вместо данных, мы сохраняем в поле класса указатель:

QLdapEntry *user;

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

QString QLdapUser::getDisplayName() const
{
    return this->getUserValue("displayName");
}

Эти методы просто возвращают значения из QLdapEntry который на самом деле QHash<QString,QLdapEntryValues>.

Использование класса QLdapUser

Добавим в конструктор главной формы код:

    QLdapUser *user = new QLdapUser(&a);

    qDebug() << user->getDisplayName();
    qDebug() << user->getCompany();

Запустим:

"Павлова Ясмина Всеволодовна"
"Altunin Soft"

Отладка класса

Добавим несколько методов, которые упростят нам отладку программы.

toString() 

Добавим метод toString() 

QString QLdapUser::toString() const
{
    QString s;
    QTextStream out(&s);

    out << "QLdapUser( "
        << "displayName: " << this->getDisplayName() << ","
        << "initials: " << this->getInitials() << ","
        << "officePhone: " << this->getOfficePhone() << ","
        << "department: " << this->getDepartment() << ","
        << "title: " << this->getTitle() << ","
        << "userPrincipalName: " << this->getUserPrincipalName() << ","
        << "cellPhone: " << this->getCellPhone() << ","
        << "samAccountName: " << this->getSamAccountName() << ","
        << "path: " << this->getPath() << ","
        << "email: " << this->getEmail() << ","
        << "streetAddress: " << this->getStreetAddress() << ","
        << "office: " << this->getOffice() << ","
        << "company: " << this->getCompany() << ","
        << "fax: " << this->getFax() << ""
        << " )"
        ;
    return s;
}

Оператор <<

Перегрузим оператор << для отладки с помощью qDebug(), подробнее эту тему мы рассматривали в  этой  статье. 

Добавим в qldapuser.h вне определения класса, строки:

QDebug operator<<(QDebug debug, const QLdapUser &user);
QDebug operator<<(QDebug debug, const QLdapUser *user);

Добавим реализацию:

QDebug operator<<(QDebug debug, const QLdapUser &user)
{
    QDebugStateSaver saver(debug);

    debug.nospace() << "QLdapUser( "
        << "displayName: " << user.getDisplayName() << ", "
        << "initials: " << user.getInitials() << ", "
        << "officePhone: " << user.getOfficePhone() << ", "
        << "department: " << user.getDepartment() << ", "
        << "title: " << user.getTitle() << ", "
        << "userPrincipalName: " << user.getUserPrincipalName() << ", "
        << "cellPhone: " << user.getCellPhone() << ", "
        << "samAccountName: " << user.getSamAccountName() << ", "
        << "path: " << user.getPath() << ", "
        << "email: " << user.getEmail() << ", "
        << "streetAddress: " << user.getStreetAddress() << ", "
        << "office: " << user.getOffice() << ", "
        << "company: " << user.getCompany() << ", "
        << "fax: " << user.getFax() << ""
        << " )";
    return debug;
}

 

QDebug operator<<(QDebug debug, const QLdapUser *user)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << *user;
    return debug;
}

Добавим в конструктор главной формы строки:

     qDebug() << user->toString();
     qDebug() << user;

Запустим:

"QLdapUser( displayName: Павлова Ясмина Всеволодовна,initials: В.,officePhone: 100,department: Руководство,title: Директор,userPrincipalName: PavlovaJAV,cellPhone: +7(495)853-91-88,samAccountName: PavlovaJAV,path: CN=PavlovaJAV,OU=ruk,OU=Company,DC=altuninvv,DC=local,email: Этот адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.,streetAddress: Ленина 1,office: 101,company: Altunin Soft,fax:  )"

QLdapUser( displayName: "Павлова Ясмина Всеволодовна",initials: "В.",officePhone: "100",department: "Руководство",title: "Директор",userPrincipalName: "PavlovaJAV",cellPhone: "+7(495)853-91-88",samAccountName: "PavlovaJAV",path: "CN=PavlovaJAV,OU=ruk,OU=Company,DC=altuninvv,DC=local",email: "Этот адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.",streetAddress: "Ленина 1",office: "101",company: "Altunin Soft",fax: "" )

Как видите - второй вариант более информативен.

Заключение

Сегодня мы рассмотрели обработку результатов поиска в каталоге LDAP.

Доработали метод поиска и добавили поддержку атрибутов с несколькими значениями.

Создали класс-хранилище для хранения информации о пользователях.

Добавили конструктор для заполнения класса данными из QLdapEntry.

Добавили метод toString()

Перегрузили оператор << для облегчения отладки c помощью qDebug().

В следующих статьях мы расширим возможности поиска и рассмотрим создание модели на основе результатов поиска.

Исходный код проекта вы моежете найти на Github.

Прочитано 179 раз Последнее изменение Четверг, 28 января 2021 19:12