mirror of
https://github.com/altlinux/admc.git
synced 2025-03-28 18:50:45 +03:00
commit
87f54264a3
@ -35,6 +35,7 @@ add_executable(admc
|
||||
utils.cpp
|
||||
settings.cpp
|
||||
policy_model.cpp
|
||||
policy_results_widget.cpp
|
||||
|
||||
move_dialog.cpp
|
||||
rename_dialog.cpp
|
||||
|
@ -36,10 +36,12 @@
|
||||
#include "find_dialog.h"
|
||||
#include "password_dialog.h"
|
||||
#include "rename_policy_dialog.h"
|
||||
#include "select_dialog.h"
|
||||
#include "console_widget/console_widget.h"
|
||||
#include "console_widget/results_view.h"
|
||||
#include "editors/multi_editor.h"
|
||||
#include "gplink.h"
|
||||
#include "policy_results_widget.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QAbstractItemView>
|
||||
@ -70,6 +72,7 @@ CentralWidget::CentralWidget()
|
||||
object_actions = new ObjectActions(this);
|
||||
|
||||
create_policy_action = new QAction(tr("New policy"), this);
|
||||
auto add_link_action = new QAction(tr("Add link"), this);
|
||||
auto rename_policy_action = new QAction(tr("Rename"), this);
|
||||
auto delete_policy_action = new QAction(tr("Delete"), this);
|
||||
|
||||
@ -80,6 +83,7 @@ CentralWidget::CentralWidget()
|
||||
// NOTE: add policy actions to this list so that they
|
||||
// are processed
|
||||
policy_actions = {
|
||||
add_link_action,
|
||||
rename_policy_action,
|
||||
delete_policy_action,
|
||||
};
|
||||
@ -103,6 +107,9 @@ CentralWidget::CentralWidget()
|
||||
policies_results->detail_view()->header()->setDefaultSectionSize(200);
|
||||
policies_results_id = console_widget->register_results(policies_results, policy_model_header_labels(), policy_model_default_columns());
|
||||
|
||||
policy_results_widget = new PolicyResultsWidget();
|
||||
policy_links_results_id = console_widget->register_results(policy_results_widget);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
@ -179,6 +186,9 @@ CentralWidget::CentralWidget()
|
||||
connect(
|
||||
create_policy_action, &QAction::triggered,
|
||||
this, &CentralWidget::create_policy);
|
||||
connect(
|
||||
add_link_action, &QAction::triggered,
|
||||
this, &CentralWidget::add_link);
|
||||
connect(
|
||||
rename_policy_action, &QAction::triggered,
|
||||
this, &CentralWidget::rename_policy);
|
||||
@ -188,7 +198,7 @@ CentralWidget::CentralWidget()
|
||||
|
||||
connect(
|
||||
console_widget, &ConsoleWidget::current_scope_item_changed,
|
||||
this, &CentralWidget::update_description_bar);
|
||||
this, &CentralWidget::on_current_scope_changed);
|
||||
connect(
|
||||
console_widget, &ConsoleWidget::results_count_changed,
|
||||
this, &CentralWidget::update_description_bar);
|
||||
@ -255,7 +265,7 @@ void CentralWidget::go_online(AdInterface &ad) {
|
||||
for (const AdObject &object : search_results.values()) {
|
||||
QStandardItem *scope_item;
|
||||
QList<QStandardItem *> results_row;
|
||||
console_widget->add_buddy_scope_and_results(policies_results_id, ScopeNodeType_Static, policies_item->index(), &scope_item, &results_row);
|
||||
console_widget->add_buddy_scope_and_results(policy_links_results_id, ScopeNodeType_Static, policies_item->index(), &scope_item, &results_row);
|
||||
|
||||
setup_policy_scope_item(scope_item, object);
|
||||
setup_policy_results_row(results_row, object);
|
||||
@ -473,6 +483,62 @@ void CentralWidget::create_policy() {
|
||||
// unfinished)
|
||||
}
|
||||
|
||||
void CentralWidget::add_link() {
|
||||
const QList<QModelIndex> selected = console_widget->get_selected_items();
|
||||
if (selected.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = new SelectDialog({CLASS_OU}, SelectDialogMultiSelection_Yes, this);
|
||||
|
||||
QObject::connect(
|
||||
dialog, &SelectDialog::accepted,
|
||||
[=]() {
|
||||
AdInterface ad;
|
||||
if (ad_failed(ad)) {
|
||||
return;
|
||||
}
|
||||
|
||||
show_busy_indicator();
|
||||
|
||||
const QList<QString> gpos =
|
||||
[selected]() {
|
||||
QList<QString> out;
|
||||
|
||||
for (const QModelIndex &index : selected) {
|
||||
const QString gpo = index.data(PolicyRole_DN).toString();
|
||||
out.append(gpo);
|
||||
}
|
||||
|
||||
return out;
|
||||
}();
|
||||
|
||||
const QList<QString> ou_list = dialog->get_selected();
|
||||
|
||||
for (const QString &ou_dn : ou_list) {
|
||||
const QHash<QString, AdObject> results = ad.search(QString(), {ATTRIBUTE_GPLINK}, SearchScope_Object, ou_dn);
|
||||
const AdObject ou_object = results[ou_dn];
|
||||
const QString gplink_string = ou_object.get_string(ATTRIBUTE_GPLINK);
|
||||
Gplink gplink = Gplink(gplink_string);
|
||||
|
||||
for (const QString &gpo : gpos) {
|
||||
gplink.add(gpo);
|
||||
}
|
||||
|
||||
ad.attribute_replace_string(ou_dn, ATTRIBUTE_GPLINK, gplink.to_string());
|
||||
}
|
||||
|
||||
const QModelIndex current_scope = console_widget->get_current_scope_item();
|
||||
policy_results_widget->update(current_scope);
|
||||
|
||||
hide_busy_indicator();
|
||||
|
||||
STATUS()->display_ad_messages(ad, this);
|
||||
});
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void CentralWidget::rename_policy() {
|
||||
const QList<QModelIndex> indexes = console_widget->get_selected_items();
|
||||
if (indexes.size() != 1) {
|
||||
@ -612,6 +678,13 @@ void CentralWidget::on_items_dropped(const QList<QModelIndex> &dropped_list, con
|
||||
STATUS()->display_ad_messages(ad, nullptr);
|
||||
}
|
||||
|
||||
void CentralWidget::on_current_scope_changed() {
|
||||
const QModelIndex current_scope = console_widget->get_current_scope_item();
|
||||
policy_results_widget->update(current_scope);
|
||||
|
||||
update_description_bar();
|
||||
}
|
||||
|
||||
void CentralWidget::refresh_head() {
|
||||
show_busy_indicator();
|
||||
|
||||
|
@ -43,6 +43,7 @@ class AdInterface;
|
||||
class ConsoleWidget;
|
||||
class ResultsView;
|
||||
class ObjectActions;
|
||||
class PolicyResultsWidget;
|
||||
template <typename T> class QList;
|
||||
|
||||
enum ItemType {
|
||||
@ -89,6 +90,7 @@ private slots:
|
||||
void edit_upn_suffixes();
|
||||
|
||||
void create_policy();
|
||||
void add_link();
|
||||
void rename_policy();
|
||||
void delete_policy();
|
||||
|
||||
@ -97,12 +99,16 @@ private slots:
|
||||
void on_items_can_drop(const QList<QModelIndex> &dropped, const QModelIndex &target, bool *ok);
|
||||
void on_items_dropped(const QList<QModelIndex> &dropped, const QModelIndex &target);
|
||||
|
||||
void on_current_scope_changed();
|
||||
|
||||
private:
|
||||
int object_results_id;
|
||||
int policies_results_id;
|
||||
int policy_links_results_id;
|
||||
QPersistentModelIndex scope_head_index;
|
||||
QPersistentModelIndex policies_index;
|
||||
FilterDialog *filter_dialog;
|
||||
PolicyResultsWidget *policy_results_widget;
|
||||
|
||||
ObjectActions *object_actions;
|
||||
|
||||
|
@ -356,6 +356,9 @@ int ConsoleWidget::register_results(QWidget *widget, ResultsView *view, const QL
|
||||
connect(
|
||||
view, &ResultsView::context_menu,
|
||||
d, &ConsoleWidgetPrivate::on_context_menu);
|
||||
connect(
|
||||
view, &ResultsView::selection_changed,
|
||||
d, &ConsoleWidgetPrivate::on_selection_changed);
|
||||
|
||||
// Hide non-default results view columns. Note that
|
||||
// at creation, view header doesnt have any
|
||||
@ -374,10 +377,6 @@ int ConsoleWidget::register_results(QWidget *widget, ResultsView *view, const QL
|
||||
});
|
||||
}
|
||||
|
||||
connect(
|
||||
view, &ResultsView::selection_changed,
|
||||
d, &ConsoleWidgetPrivate::on_selection_changed);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
281
src/admc/policy_results_widget.cpp
Normal file
281
src/admc/policy_results_widget.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* ADMC - AD Management Center
|
||||
*
|
||||
* Copyright (C) 2020 BaseALT Ltd.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "policy_results_widget.h"
|
||||
|
||||
#include "adldap.h"
|
||||
#include "console_widget/console_widget.h"
|
||||
#include "central_widget.h"
|
||||
#include "policy_model.h"
|
||||
#include "utils.h"
|
||||
#include "gplink.h"
|
||||
#include "status.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QTreeView>
|
||||
#include <QDebug>
|
||||
#include <QTreeView>
|
||||
#include <QStandardItemModel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QHeaderView>
|
||||
|
||||
enum PolicyResultsColumn {
|
||||
PolicyResultsColumn_Name,
|
||||
PolicyResultsColumn_Enforced,
|
||||
PolicyResultsColumn_Disabled,
|
||||
PolicyResultsColumn_Path,
|
||||
|
||||
PolicyResultsColumn_COUNT,
|
||||
};
|
||||
|
||||
enum PolicyResultsRole {
|
||||
PolicyResultsRole_DN = Qt::UserRole,
|
||||
PolicyResultsRole_GplinkString = Qt::UserRole + 1,
|
||||
|
||||
PolicyResultsRole_COUNT,
|
||||
};
|
||||
|
||||
const QSet<PolicyResultsColumn> option_columns = {
|
||||
PolicyResultsColumn_Disabled,
|
||||
PolicyResultsColumn_Enforced
|
||||
};
|
||||
|
||||
const QHash<PolicyResultsColumn, GplinkOption> column_to_option = {
|
||||
{PolicyResultsColumn_Disabled, GplinkOption_Disabled},
|
||||
{PolicyResultsColumn_Enforced, GplinkOption_Enforced}
|
||||
};
|
||||
|
||||
// TODO: need to sync this with changes done through group
|
||||
// policy tab (just call load after properties is closed?)
|
||||
|
||||
PolicyResultsWidget::PolicyResultsWidget() {
|
||||
auto delete_link_action = new QAction(tr("Delete link"), this);
|
||||
|
||||
context_menu = new QMenu(this);
|
||||
context_menu->addAction(delete_link_action);
|
||||
|
||||
view = new QTreeView(this);
|
||||
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
view->setAllColumnsShowFocus(true);
|
||||
view->setSortingEnabled(true);
|
||||
view->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
|
||||
model = new QStandardItemModel(0, PolicyResultsColumn_COUNT, this);
|
||||
set_horizontal_header_labels_from_map(model, {
|
||||
{PolicyResultsColumn_Name, tr("Location")},
|
||||
{PolicyResultsColumn_Enforced, tr("Enforced")},
|
||||
{PolicyResultsColumn_Disabled, tr("Disabled")},
|
||||
{PolicyResultsColumn_Path, tr("Path")},
|
||||
});
|
||||
|
||||
view->setModel(model);
|
||||
|
||||
view->header()->resizeSection(0, 300);
|
||||
view->header()->resizeSection(1, 100);
|
||||
view->header()->resizeSection(2, 100);
|
||||
view->header()->resizeSection(3, 500);
|
||||
|
||||
const auto layout = new QVBoxLayout();
|
||||
setLayout(layout);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(view);
|
||||
|
||||
connect(
|
||||
model, &QStandardItemModel::itemChanged,
|
||||
this, &PolicyResultsWidget::on_item_changed);
|
||||
connect(
|
||||
view, &QWidget::customContextMenuRequested,
|
||||
this, &PolicyResultsWidget::open_context_menu);
|
||||
connect(
|
||||
delete_link_action, &QAction::triggered,
|
||||
this, &PolicyResultsWidget::delete_link);
|
||||
}
|
||||
|
||||
void PolicyResultsWidget::update(const QModelIndex &scope_index) {
|
||||
const ItemType type = (ItemType) scope_index.data(ConsoleRole_Type).toInt();
|
||||
if (type != ItemType_Policy) {
|
||||
return;
|
||||
}
|
||||
|
||||
AdInterface ad;
|
||||
if (ad_failed(ad)) {
|
||||
return;
|
||||
}
|
||||
|
||||
model->removeRows(0, model->rowCount());
|
||||
|
||||
gpo = scope_index.data(PolicyRole_DN).toString();
|
||||
|
||||
const QList<QString> search_attributes = {ATTRIBUTE_NAME, ATTRIBUTE_GPLINK};
|
||||
const QString filter = filter_CONDITION(Condition_Contains, ATTRIBUTE_GPLINK, gpo);
|
||||
const QHash<QString, AdObject> search_results = ad.search(filter, search_attributes, SearchScope_All);
|
||||
|
||||
for (const AdObject &object : search_results.values()) {
|
||||
const QList<QStandardItem *> row = make_item_row(PolicyResultsColumn_COUNT);
|
||||
|
||||
const QString dn = object.get_dn();
|
||||
const QString name = dn_get_name(dn);
|
||||
row[PolicyResultsColumn_Name]->setText(name);
|
||||
|
||||
row[PolicyResultsColumn_Path]->setText(dn_get_parent_canonical(dn));
|
||||
|
||||
const QString gplink_string = object.get_string(ATTRIBUTE_GPLINK);
|
||||
const Gplink gplink = Gplink(gplink_string);
|
||||
|
||||
const Qt::CheckState enforced_checkstate =
|
||||
[&]() {
|
||||
const bool is_enforced = gplink.get_option(dn, GplinkOption_Enforced);
|
||||
if (is_enforced) {
|
||||
return Qt::Checked;
|
||||
} else {
|
||||
return Qt::Unchecked;
|
||||
}
|
||||
}();
|
||||
row[PolicyResultsColumn_Enforced]->setCheckable(true);
|
||||
row[PolicyResultsColumn_Enforced]->setCheckState(enforced_checkstate);
|
||||
|
||||
for (const auto column : option_columns) {
|
||||
QStandardItem *item = row[column];
|
||||
item->setCheckable(true);
|
||||
|
||||
const Qt::CheckState checkstate =
|
||||
[=]() {
|
||||
const GplinkOption option = column_to_option[column];
|
||||
const bool option_is_set = gplink.get_option(dn, option);
|
||||
if (option_is_set) {
|
||||
return Qt::Checked;
|
||||
} else {
|
||||
return Qt::Unchecked;
|
||||
}
|
||||
}();
|
||||
item->setCheckState(checkstate);
|
||||
}
|
||||
|
||||
row[0]->setData(dn, PolicyResultsRole_DN);
|
||||
row[0]->setData(gplink_string, PolicyResultsRole_GplinkString);
|
||||
row[0]->setIcon(QIcon::fromTheme("folder-documents"));
|
||||
|
||||
model->appendRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyResultsWidget::on_item_changed(QStandardItem *item) {
|
||||
const PolicyResultsColumn column = (PolicyResultsColumn) item->column();
|
||||
if (!option_columns.contains(column)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QModelIndex this_index = item->index();
|
||||
const QModelIndex index = this_index.siblingAtColumn(0);
|
||||
const QString dn = index.data(PolicyResultsRole_DN).toString();
|
||||
const GplinkOption option = column_to_option[column];
|
||||
const bool is_checked = (item->checkState() == Qt::Checked);
|
||||
|
||||
const QString gplink_string = index.data(PolicyResultsRole_GplinkString).toString();
|
||||
Gplink gplink = Gplink(gplink_string);
|
||||
gplink.set_option(gpo, option, is_checked);
|
||||
const QString updated_gplink_string = gplink.to_string();
|
||||
|
||||
const bool gplink_didnt_change = gplink.equals(gplink_string);
|
||||
if (gplink_didnt_change) {
|
||||
return;
|
||||
}
|
||||
|
||||
AdInterface ad;
|
||||
if (ad_failed(ad)) {
|
||||
return;
|
||||
}
|
||||
|
||||
show_busy_indicator();
|
||||
|
||||
const bool success = ad.attribute_replace_string(dn, ATTRIBUTE_GPLINK, updated_gplink_string);
|
||||
|
||||
if (success) {
|
||||
model->setData(index, updated_gplink_string, PolicyResultsRole_GplinkString);
|
||||
} else {
|
||||
const Qt::CheckState undo_check_state =
|
||||
[&]() {
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
return Qt::Unchecked;
|
||||
} else {
|
||||
return Qt::Checked;
|
||||
}
|
||||
}();
|
||||
item->setCheckState(undo_check_state);
|
||||
}
|
||||
|
||||
STATUS()->display_ad_messages(ad, this);
|
||||
|
||||
hide_busy_indicator();
|
||||
}
|
||||
|
||||
void PolicyResultsWidget::open_context_menu(const QPoint &pos) {
|
||||
const QModelIndex index = view->indexAt(pos);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPoint global_pos = view->mapToGlobal(pos);
|
||||
context_menu->popup(global_pos);
|
||||
}
|
||||
|
||||
void PolicyResultsWidget::delete_link() {
|
||||
AdInterface ad;
|
||||
if (ad_failed(ad)) {
|
||||
return;
|
||||
}
|
||||
|
||||
show_busy_indicator();
|
||||
|
||||
|
||||
const QList<QModelIndex> selected = view->selectionModel()->selectedRows();
|
||||
|
||||
QList<QPersistentModelIndex> removed_indexes;
|
||||
|
||||
for (const QModelIndex &index : selected) {
|
||||
const QString dn = index.data(PolicyResultsRole_DN).toString();
|
||||
|
||||
const QString gplink_string = index.data(PolicyResultsRole_GplinkString).toString();
|
||||
Gplink gplink = Gplink(gplink_string);
|
||||
gplink.remove(gpo);
|
||||
const QString updated_gplink_string = gplink.to_string();
|
||||
|
||||
const bool gplink_didnt_change = gplink.equals(gplink_string);
|
||||
if (gplink_didnt_change) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool success = ad.attribute_replace_string(dn, ATTRIBUTE_GPLINK, updated_gplink_string);
|
||||
|
||||
if (success) {
|
||||
removed_indexes.append(QPersistentModelIndex(index));
|
||||
}
|
||||
}
|
||||
|
||||
for (const QPersistentModelIndex &index : removed_indexes) {
|
||||
model->removeRow(index.row());
|
||||
}
|
||||
|
||||
STATUS()->display_ad_messages(ad, this);
|
||||
|
||||
hide_busy_indicator();
|
||||
}
|
57
src/admc/policy_results_widget.h
Normal file
57
src/admc/policy_results_widget.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* ADMC - AD Management Center
|
||||
*
|
||||
* Copyright (C) 2020 BaseALT Ltd.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef POLICY_RESULTS_WIDGET_H
|
||||
#define POLICY_RESULTS_WIDGET_H
|
||||
|
||||
/**
|
||||
* Displays OU's linked to currently selected policy.
|
||||
*/
|
||||
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
|
||||
class QModelIndex;
|
||||
class QTreeView;
|
||||
class QStandardItemModel;
|
||||
class QStandardItem;
|
||||
class QMenu;
|
||||
|
||||
class PolicyResultsWidget final : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PolicyResultsWidget();
|
||||
|
||||
// Loads links for this policy. Nothing is done if given
|
||||
// index is not a policy.
|
||||
void update(const QModelIndex &scope_index);
|
||||
|
||||
private:
|
||||
QTreeView *view;
|
||||
QStandardItemModel *model;
|
||||
QString gpo;
|
||||
QMenu *context_menu;
|
||||
|
||||
void on_item_changed(QStandardItem *item);
|
||||
void open_context_menu(const QPoint &pos);
|
||||
void delete_link();
|
||||
};
|
||||
|
||||
#endif /* POLICY_RESULTS_WIDGET_H */
|
@ -41,6 +41,7 @@ set(TEST_SOURCES
|
||||
${PROJECT_SOURCE_DIR}/src/admc/utils.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/admc/settings.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/admc/policy_model.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/admc/policy_results_widget.cpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/src/admc/move_dialog.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/admc/rename_dialog.cpp
|
||||
|
Loading…
x
Reference in New Issue
Block a user