1
0
mirror of https://github.com/altlinux/admc.git synced 2025-02-10 05:57:24 +03:00

add rename dialog

custom extra attribute edits for users and groups
remove rename_user/group from adldap
print untranslated/unreworded ldap error by default
This commit is contained in:
Dmitry Degtyarev 2020-08-13 13:50:59 +04:00
parent 8af5db2ace
commit 4e2f7c8687
11 changed files with 205 additions and 134 deletions

View File

@ -72,6 +72,7 @@ set(ADMC_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/general_tab.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/address_tab.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/object_tab.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rename_dialog.cpp
)
set(TS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/translations)

View File

@ -780,90 +780,6 @@ int ad_rename(LDAP *ld, const char *dn, const char *new_rdn) {
return result;
}
int ad_rename_user(LDAP *ld, const char *dn, const char *new_name) {
int result = AD_SUCCESS;
char* new_rdn = NULL;
char* domain = NULL;
char* upn = NULL;
const int result_replace_name = ad_attribute_replace(ld, dn, "sAMAccountName", new_name);
if (result_replace_name != AD_SUCCESS) {
// Failed to change sAMAccountName
result = result_replace_name;
goto end;
}
// Construct userPrincipalName
const int result_dn2domain = dn2domain(dn, &domain);
if (result_dn2domain != AD_SUCCESS) {
result = result_dn2domain;
goto end;
}
upn = malloc(strlen(new_name) + strlen(domain) + 2);
sprintf(upn, "%s@%s", new_name, domain);
const int result_replace_upn = ad_attribute_replace(ld, dn, "userPrincipalName", upn);
if (result_replace_upn != AD_SUCCESS) {
// Failed to change userPrincipalName
result = result_replace_upn;
goto end;
}
new_rdn = malloc(strlen(new_name) + 4);
sprintf(new_rdn, "cn=%s", new_name);
const int result_rename = ad_rename(ld, dn, new_rdn);
if (result_rename != AD_SUCCESS) {
result = result_rename;
goto end;
}
end:
{
free(domain);
free(upn);
free(new_rdn);
return result;
}
}
int ad_rename_group(LDAP *ld, const char *dn, const char *new_name) {
int result = AD_SUCCESS;
char *new_rdn = NULL;
const int result_replace = ad_attribute_replace(ld, dn, "sAMAccountName", new_name);
if (result_replace != AD_SUCCESS) {
// Failed to change sAMAccountName
result = result_replace;
goto end;
}
new_rdn = malloc(strlen(new_name) + 4);
sprintf(new_rdn, "cn=%s", new_name);
const int result_rename = ldap_rename_s(ld, dn, new_rdn, NULL, 1, NULL, NULL);
if (result_rename != LDAP_SUCCESS) {
result = AD_LDAP_ERROR;
goto end;
}
end:
{
free(new_rdn);
return result;
}
}
int ad_move_user(LDAP *ld, const char *current_dn, const char *new_container) {
int result = AD_SUCCESS;

View File

@ -116,14 +116,6 @@ int AdConnection::rename(const char *dn, const char *new_name) {
return ad_rename(ldap_connection, dn, new_name);
}
int AdConnection::rename_user(const char *dn, const char *new_username) {
return ad_rename_user(ldap_connection, dn, new_username);
}
int AdConnection::rename_group(const char *dn, const char *new_name) {
return ad_rename_group(ldap_connection, dn, new_name);
}
int AdConnection::move(const char *current_dn, const char *new_container) {
return ad_move(ldap_connection, current_dn, new_container);
}

View File

@ -175,23 +175,10 @@ int ad_attribute_delete(LDAP *ld, const char *dn, const char *attribute, const c
/**
* Rename object
* Use specialized functions to rename users and groups
* Returns AD_SUCCESS, AD_LDAP_ERROR
*/
int ad_rename(LDAP *ld, const char *dn, const char *new_rdn);
/**
* Rename user and update related attributes
* Returns AD_SUCCESS, AD_LDAP_ERROR, AD_INVALID_DN
*/
int ad_rename_user(LDAP *ld, const char *dn, const char *new_name);
/**
* Rename group and update related attributes
* Returns AD_SUCCESS, AD_LDAP_ERROR
*/
int ad_rename_group(LDAP *ld, const char *dn, const char *new_name);
/**
* Move object
* Use ad_move_user() for user objects

View File

@ -51,8 +51,6 @@ public:
int attribute_delete(const char *dn, const char *attribute, const char *value);
int get_all_attributes(const char *dn, char ****attributes);
int rename(const char *dn, const char *new_name);
int rename_user(const char *dn, const char *new_username);
int rename_group(const char *dn, const char *new_name);
int move(const char *current_dn, const char *new_container);
int move_user(const char *current_dn, const char *new_container);
int create_group(const char *group_name, const char *dn);

View File

@ -521,19 +521,10 @@ AdResult AdInterface::object_rename(const QString &dn, const QString &new_name)
const QByteArray dn_array = dn.toLatin1();
const char *dn_cstr = dn_array.constData();
const QByteArray new_name_array = new_name.toLatin1();
const char *new_name_cstr = new_name_array.constData();
const QByteArray new_rdn_array = new_rdn.toLatin1();
const char *new_rdn_cstr = new_rdn_array.constData();
int result = AD_ERROR;
if (is_user(dn)) {
result = connection->rename_user(dn_cstr, new_name_cstr);
} else if (is_group(dn)) {
result = connection->rename_group(dn_cstr, new_name_cstr);
} else {
result = connection->rename(dn_cstr, new_rdn_cstr);
}
int result = connection->rename(dn_cstr, new_rdn_cstr);
const QString old_name = extract_name_from_dn(dn);
@ -956,7 +947,11 @@ QString AdInterface::default_error_string(int ad_result) const {
case LDAP_CONSTRAINT_VIOLATION: return tr("Constraint violation");
case LDAP_UNWILLING_TO_PERFORM: return tr("Server is unwilling to perform");
case LDAP_ALREADY_EXISTS: return tr("Already exists");
default: return tr("Unknown LDAP error");
default: {
char *ldap_err = ldap_err2string(ldap_result);
const QString ldap_err_qstr(ldap_err);
return QString(tr("LDAP error: %1")).arg(ldap_err_qstr);
}
}
} else {
switch (ad_result) {

View File

@ -37,15 +37,16 @@
#define ISO8601_FORMAT_STRING "yyyyMMddhhmmss.zZ"
#define ATTRIBUTE_USER_ACCOUNT_CONTROL "userAccountControl"
#define ATTRIBUTE_USER_PRINCIPAL_NAME "userPrincipalName"
#define ATTRIBUTE_LOCKOUT_TIME "lockoutTime"
#define ATTRIBUTE_ACCOUNT_EXPIRES "accountExpires"
#define ATTRIBUTE_PWD_LAST_SET "pwdLastSet"
#define ATTRIBUTE_NAME "name"
#define ATTRIBUTE_INITIALS "initials"
#define ATTRIBUTE_SAMACCOUNT_NAME "sAMAccountName"
#define ATTRIBUTE_DISPLAY_NAME "displayName"
#define ATTRIBUTE_DESCRIPTION "description"
#define ATTRIBUTE_GIVEN_NAME "givenName"
#define ATTRIBUTE_INITIALS "initials"
#define ATTRIBUTE_USER_PRINCIPAL_NAME "userPrincipalName"
#define ATTRIBUTE_MAIL "mail"
#define ATTRIBUTE_OFFICE "physicalDeliveryOfficeName"
#define ATTRIBUTE_SN "sn"

View File

@ -21,6 +21,7 @@
#include "ad_interface.h"
#include "confirmation_dialog.h"
#include "move_dialog.h"
#include "rename_dialog.h"
#include "utils.h"
#include "password_dialog.h"
#include "settings.h"
@ -82,7 +83,8 @@ void ObjectContextMenu::open(const QPoint &global_pos, const QString &dn, const
delete_object(dn);
});
addAction(tr("Rename"), [this, dn]() {
rename(dn);
auto rename_dialog = new RenameDialog(dn, this);
rename_dialog->open();
});
QMenu *submenu_new = addMenu("New");
@ -186,18 +188,6 @@ void ObjectContextMenu::new_object_dialog(const QString &parent_dn, NewObjectTyp
}
}
void ObjectContextMenu::rename(const QString &dn) {
// Get new name from input box
QString dialog_title = tr("Rename");
QString input_label = tr("New name:");
bool ok;
QString new_name = QInputDialog::getText(this, dialog_title, input_label, QLineEdit::Normal, "", &ok);
if (ok && !new_name.isEmpty()) {
AdInterface::instance()->object_rename(dn, new_name);
}
}
void ObjectContextMenu::edit_policy(const QString &dn) {
// Start policy edit process
const auto process = new QProcess(this);

View File

@ -46,7 +46,6 @@ private:
void open(const QPoint &global_pos, const QString &dn, const QString &parent_dn);
void delete_object(const QString &dn);
void new_object_dialog(const QString &parent_dn, NewObjectType type);
void rename(const QString &dn);
void edit_policy(const QString &dn);
};

138
src/rename_dialog.cpp Normal file
View File

@ -0,0 +1,138 @@
/*
* 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 "rename_dialog.h"
#include "ad_interface.h"
#include <QDialog>
#include <QLineEdit>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QList>
RenameDialog::RenameDialog(const QString &target_arg, QWidget *parent)
: QDialog(parent)
{
target = target_arg;
setAttribute(Qt::WA_DeleteOnClose);
resize(600, 600);
const QString name = AdInterface::instance()->attribute_get(target, ATTRIBUTE_NAME);
const auto title_label = new QLabel(QString(tr("Renaming \"%1\":")).arg(name), this);
const auto ok_button = new QPushButton(tr("OK"), this);
connect(
ok_button, &QAbstractButton::clicked,
this, &QDialog::accept);
const auto cancel_button = new QPushButton(tr("Cancel"), this);
connect(
cancel_button, &QAbstractButton::clicked,
this, &QDialog::reject);
label_layout = new QVBoxLayout();
edit_layout = new QVBoxLayout();
const auto attributes_layout = new QHBoxLayout();
attributes_layout->insertLayout(-1, label_layout);
attributes_layout->insertLayout(-1, edit_layout);
const auto top_layout = new QGridLayout(this);
top_layout->addWidget(title_label, 0, 0);
top_layout->addLayout(attributes_layout, 1, 0);
top_layout->addWidget(cancel_button, 2, 0, Qt::AlignLeft);
top_layout->addWidget(ok_button, 2, 2, Qt::AlignRight);
name_edit = {
"",
nullptr
};
add_attribute_edit(ATTRIBUTE_NAME, tr("Name:"));
// Add extra name-related attribute edits for users/groups
const bool is_user = AdInterface::instance()->is_user(target);
const bool is_group = AdInterface::instance()->is_group(target);
if (is_user) {
add_attribute_edit(ATTRIBUTE_GIVEN_NAME, tr("First name:"));
add_attribute_edit(ATTRIBUTE_SN, tr("Last name:"));
add_attribute_edit(ATTRIBUTE_DISPLAY_NAME, tr("Display name:"));
add_attribute_edit(ATTRIBUTE_USER_PRINCIPAL_NAME, tr("Logon name:"));
add_attribute_edit(ATTRIBUTE_SAMACCOUNT_NAME, tr("Logon name (pre-2000):"));
} if (is_group) {
add_attribute_edit(ATTRIBUTE_SAMACCOUNT_NAME, tr("Logon name (pre-2000):"));
}
connect(
this, &QDialog::accepted,
this, &RenameDialog::on_accepted);
}
void RenameDialog::on_accepted() {
auto push_changes_from_attribute_edit =
[this](const AttributeEdit &e) {
const QString attribute = e.attribute;
const QLineEdit *edit = e.edit;
const QString current_value = AdInterface::instance()->attribute_get(target, attribute);
const QString new_value = edit->text();
const bool changed = (new_value != current_value);
if (changed) {
if (attribute == ATTRIBUTE_NAME) {
AdInterface::instance()->object_rename(target, new_value);
} else {
AdInterface::instance()->attribute_replace(target, attribute, new_value);
}
}
};
// NOTE: change name last so that other attribute changes can complete on old DN
for (auto e : edits) {
push_changes_from_attribute_edit(e);
}
if (name_edit.edit != nullptr) {
push_changes_from_attribute_edit(name_edit);
}
}
void RenameDialog::add_attribute_edit(const QString &attribute, const QString &label_text) {
const auto label = new QLabel(label_text);
auto edit = new QLineEdit();
label_layout->addWidget(label);
edit_layout->addWidget(edit);
const QString current_value = AdInterface::instance()->attribute_get(target, attribute);
edit->setText(current_value);
AttributeEdit attribute_edit = {
QString(attribute),
edit
};
if (attribute == ATTRIBUTE_NAME) {
name_edit = attribute_edit;
} else {
edits.append(attribute_edit);
}
}

54
src/rename_dialog.h Normal file
View File

@ -0,0 +1,54 @@
/*
* 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 RENAME_DIALOG_H
#define RENAME_DIALOG_H
#include <QString>
#include <QDialog>
#include <QList>
class QLineEdit;
class QVBoxLayout;
class RenameDialog final : public QDialog {
Q_OBJECT
public:
RenameDialog(const QString &target_arg, QWidget *parent);
private slots:
void on_accepted();
private:
struct AttributeEdit {
QString attribute;
QLineEdit *edit;
};
QString target;
QVBoxLayout *label_layout;
QVBoxLayout *edit_layout;
AttributeEdit name_edit;
QList<AttributeEdit> edits;
void add_attribute_edit(const QString &attribute, const QString &label_text);
};
#endif /* RENAME_DIALOG_H */