From 1e30ca20e798138f9814b36e1c279373a9fc307c Mon Sep 17 00:00:00 2001 From: "E. Kozlovskaya" Date: Mon, 4 Jan 2021 22:14:24 +0700 Subject: [PATCH] Add registration dialog and bare-minimum auth --- iFacility/db/database.cpp | 4 +- iFacility/iFacility.pro | 11 +- iFacility/loginwindow.cpp | 54 +++- iFacility/loginwindow.h | 19 +- iFacility/loginwindow.ui | 102 +++++++- iFacility/main.cpp | 8 +- iFacility/objects/user.cpp | 33 ++- iFacility/objects/user.h | 12 +- iFacility/registrationdialog.cpp | 98 +++++++ iFacility/registrationdialog.h | 37 +++ iFacility/registrationdialog.ui | 240 ++++++++++++++++++ .../viewmodels/userprofessionviewmodel.cpp | 56 ++++ .../viewmodels/userprofessionviewmodel.h | 25 ++ 13 files changed, 658 insertions(+), 41 deletions(-) create mode 100644 iFacility/registrationdialog.cpp create mode 100644 iFacility/registrationdialog.h create mode 100644 iFacility/registrationdialog.ui create mode 100644 iFacility/viewmodels/userprofessionviewmodel.cpp create mode 100644 iFacility/viewmodels/userprofessionviewmodel.h diff --git a/iFacility/db/database.cpp b/iFacility/db/database.cpp index 5e796c9..de2c35a 100644 --- a/iFacility/db/database.cpp +++ b/iFacility/db/database.cpp @@ -99,7 +99,7 @@ bool Database::removeProfession(PID pid) { void Database::save() { QFile f(Database::mFilename); - f.open(QIODevice::ReadOnly); + f.open(QIODevice::WriteOnly); QDataStream stream(&f); stream << mProfessions << mUsers; f.close(); @@ -112,7 +112,7 @@ void Database::load() { mUsers.clear(); mProfessions.clear(); QFile f(Database::mFilename); - f.open(QIODevice::WriteOnly); + f.open(QIODevice::ReadOnly); QDataStream stream(&f); stream >> mProfessions >> mUsers; f.close(); diff --git a/iFacility/iFacility.pro b/iFacility/iFacility.pro index b909493..59fc8ac 100644 --- a/iFacility/iFacility.pro +++ b/iFacility/iFacility.pro @@ -14,17 +14,22 @@ SOURCES += \ objects/profession.cpp \ objects/user.cpp \ objects/userprofession.cpp \ - db/database.cpp + db/database.cpp \ + registrationdialog.cpp \ + viewmodels/userprofessionviewmodel.cpp HEADERS += \ loginwindow.h \ objects/profession.h \ objects/user.h \ objects/userprofession.h \ - db/database.h + db/database.h \ + registrationdialog.h \ + viewmodels/userprofessionviewmodel.h FORMS += \ - loginwindow.ui + loginwindow.ui \ + registrationdialog.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin diff --git a/iFacility/loginwindow.cpp b/iFacility/loginwindow.cpp index 0be7301..c6eeb1c 100644 --- a/iFacility/loginwindow.cpp +++ b/iFacility/loginwindow.cpp @@ -1,15 +1,57 @@ #include "loginwindow.h" #include "ui_loginwindow.h" -LoginWindow::LoginWindow(QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::LoginWindow) -{ +LoginWindow::LoginWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::LoginWindow) { ui->setupUi(this); + + checkForFirstRun(); } -LoginWindow::~LoginWindow() -{ +LoginWindow::~LoginWindow() { delete ui; } +void LoginWindow::checkForFirstRun() { + auto admins = Database::instance()->getUsersByType(UserType::ADMINISTRATOR); + if (admins.isEmpty()) { + QMessageBox::information(this, "Info", "No administrators found. " + "Starting registration process."); + User *user = new User(); + RegistrationDialog rd(this); + rd.setEditMode(false); + rd.setUser(user); + rd.lockUserType(UserType::ADMINISTRATOR); + rd.setWindowTitle("New administrator"); + if (rd.exec() != RegistrationDialog::Accepted) { + QMessageBox::critical(this, "Error", "System cannot work without administrator " + "profile.\nPlease, restart application."); + return; + } + + Database::instance()->addUser(*user); + QMessageBox::information(this, "Info", "Now you can login as administrator."); + } +} + +void LoginWindow::doLogin() { + QString login = ui->login->text().trimmed(); + QString password = ui->password->text().trimmed(); + auto user = Database::instance()->getUser(login); + if (user == nullptr || !user->checkPassword(password)) { + QMessageBox::critical(this, "Error", "Wrong pair login/password"); + return; + } + + QMessageBox::information(this, "Info", "Success"); + // TODO: Open valid window +} + +void LoginWindow::validateForm() { + if (ui->login->text().trimmed().isEmpty() || ui->password->text().trimmed().isEmpty()) { + QMessageBox::critical(this, "Error", "Fields should not be empty"); + return; + } + + doLogin(); +} + diff --git a/iFacility/loginwindow.h b/iFacility/loginwindow.h index 976d90c..0542915 100644 --- a/iFacility/loginwindow.h +++ b/iFacility/loginwindow.h @@ -2,20 +2,31 @@ #define LOGINWINDOW_H #include +#include + +#include "objects/user.h" +#include "db/database.h" + +#include "registrationdialog.h" QT_BEGIN_NAMESPACE namespace Ui { class LoginWindow; } QT_END_NAMESPACE -class LoginWindow : public QMainWindow -{ +class LoginWindow : public QMainWindow { +private: Q_OBJECT + Ui::LoginWindow *ui; + + void checkForFirstRun(); + void doLogin(); + public: LoginWindow(QWidget *parent = nullptr); ~LoginWindow(); -private: - Ui::LoginWindow *ui; +public slots: + void validateForm(); }; #endif // LOGINWINDOW_H diff --git a/iFacility/loginwindow.ui b/iFacility/loginwindow.ui index eca3e11..d22b0c5 100644 --- a/iFacility/loginwindow.ui +++ b/iFacility/loginwindow.ui @@ -6,17 +6,107 @@ 0 0 - 800 - 600 + 520 + 169 + + + 520 + 169 + + + + + 520 + 169 + + LoginWindow - - - + + + + + + Login: + + + + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Log in + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + - + + + btnLogIn + clicked() + LoginWindow + validateForm() + + + 292 + 132 + + + 475 + 171 + + + + + + validateForm() + diff --git a/iFacility/main.cpp b/iFacility/main.cpp index 9c05408..ac28405 100644 --- a/iFacility/main.cpp +++ b/iFacility/main.cpp @@ -1,12 +1,18 @@ +#include #include "loginwindow.h" -#include +#include "db/database.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); + Database::instance()->load(); + LoginWindow w; w.show(); + QObject::connect(&a, &QApplication::aboutToQuit, []() { + Database::instance()->save(); + }); return a.exec(); } diff --git a/iFacility/objects/user.cpp b/iFacility/objects/user.cpp index 2e1bb05..9fc427f 100644 --- a/iFacility/objects/user.cpp +++ b/iFacility/objects/user.cpp @@ -37,17 +37,17 @@ PID User::getCurrentProfession() const { return mCurrentProfession; } -User User::createUser(QString login, QString password, UserType userType, - QString firstName, QString secondName, QString patronymic) { - User u; +User* User::createUser(QString login, QString password, UserType userType, + QString firstName, QString secondName, QString patronymic) { + User *u = new User(); - u.mUID = QUuid::createUuid(); - u.mLogin = login; - u.mPassword = password; - u.mUserType = userType; - u.mFirstName = firstName; - u.mSecondName = secondName; - u.mPatronymic = patronymic; + u->mUID = QUuid::createUuid(); + u->mLogin = login; + u->mPassword = password; + u->mUserType = userType; + u->mFirstName = firstName; + u->mSecondName = secondName; + u->mPatronymic = patronymic; return u; } @@ -62,15 +62,20 @@ bool User::hasProfession(PID pid) { return false; } -bool User::addProfession(const Profession &p, ProfRank rank) { - if (hasProfession(p.pID())) { +bool User::addProfession(PID pid, ProfRank rank) { + if (hasProfession(pid)) { return false; } if (mProfessions.size() >= 4) { - mProfessions.remove(0); + if (mCurrentProfession == mProfessions[0].getProfession()) { + mProfessions.remove(1); + } + else { + mProfessions.remove(0); + } } - UserProfession up(p.pID(), rank); + UserProfession up(pid, rank); mProfessions.push_back(up); return true; diff --git a/iFacility/objects/user.h b/iFacility/objects/user.h index 63b05a5..d17b241 100644 --- a/iFacility/objects/user.h +++ b/iFacility/objects/user.h @@ -13,9 +13,9 @@ typedef QUuid UID; typedef QVector ProfessionsList; enum class UserType { - ADMINISTRATOR, - DISPATCHER, - WORKER + ADMINISTRATOR = 0, + DISPATCHER = 1, + WORKER = 2 }; class User { @@ -30,6 +30,8 @@ private: ProfessionsList mProfessions; PID mCurrentProfession = 0; + friend class RegistrationDialog; + public: User() = default; @@ -43,11 +45,11 @@ public: ProfessionsList getProfessions() const; PID getCurrentProfession() const; - static User createUser(QString login, QString password, UserType userType, + static User* createUser(QString login, QString password, UserType userType, QString firstName, QString secondName, QString patronymic); bool hasProfession(PID pid); - bool addProfession(const Profession &p, ProfRank rank); + bool addProfession(PID pid, ProfRank rank); bool setCurrentProfession(PID pid); void removeProfession(PID pid); diff --git a/iFacility/registrationdialog.cpp b/iFacility/registrationdialog.cpp new file mode 100644 index 0000000..facfcf4 --- /dev/null +++ b/iFacility/registrationdialog.cpp @@ -0,0 +1,98 @@ +#include "registrationdialog.h" +#include "ui_registrationdialog.h" + +RegistrationDialog::RegistrationDialog(QWidget *parent) : + QDialog(parent), ui(new Ui::RegistrationDialog) { + ui->setupUi(this); + + upvm = new UserProfessionViewModel(this); + ui->userProfessions->setModel(upvm); +} + +RegistrationDialog::~RegistrationDialog() { + delete ui; + + delete upvm; +} + +void RegistrationDialog::lockUserType(UserType type) { + ui->userGroup->setCurrentIndex((int)type); + ui->userGroup->setEnabled(false); +} + +void RegistrationDialog::setUser(User *usr) { + user = usr; + + if (mEditMode) { + ui->firstName->setText(user->firstName()); + ui->secondName->setText(user->secondName()); + ui->patronymic->setText(user->patronymic()); + ui->login->setText(user->getLogin()); + ui->login->setEnabled(false); + ui->password->setText(user->mPassword); + ui->password->setEnabled(usr->getUserType() == UserType::ADMINISTRATOR); + ui->userGroup->setCurrentIndex((int)user->getUserType()); + ui->userGroup->setEnabled(false); + upvm->setProfessionsList(user->getProfessions()); + } +} + +void RegistrationDialog::setEditMode(bool editMode) { + mEditMode = editMode; +} + +void RegistrationDialog::accept() { + QString fname = ui->firstName->text().trimmed(); + QString sname = ui->secondName->text().trimmed(); + QString patr = ui->patronymic->text().trimmed(); + QString login = ui->login->text().trimmed(); + QString pass = ui->password->text().trimmed(); + UserType type = (UserType)ui->userGroup->currentIndex(); + if (fname.isEmpty() || sname.isEmpty() || patr.isEmpty() + || login.isEmpty() || pass.isEmpty()) { + QMessageBox::critical(this, "Error", "Check field data correctness"); + return; + } + if (mEditMode) { + QMessageBox::information(this, "Info", "Please note: login nor pasword cannot be " + "changed. Your changes will be omited."); + user->mPassword = pass; + user->mFirstName = fname; + user->mSecondName = sname; + user->mPatronymic = patr; + } + else { + auto u = User::createUser(login, pass, type, fname, sname, patr); + std::swap(*user, *u); + delete u; + } + + QDialog::accept(); +} + +void RegistrationDialog::addNewProfession() { + QStringList professions; + foreach (auto prof, Database::instance()->professions()) { + professions << prof.title() + "|" + prof.pID().toString(); + } + if (professions.isEmpty()) { + QMessageBox::critical(this, "Error", "No professions found"); + return; + } + bool ok; + QString p = QInputDialog::getItem(this, "Choose profession", "Profession title", + professions, 0, false, &ok); + if (ok) { + PID pid = p.split("|").last(); + int r = QInputDialog::getInt(this, "Profession rank", "", 1, 1, 2e5, 1, &ok); + if (ok) { + user->addProfession(pid, r); + return; + } + } + QMessageBox::critical(this, "Error", "Aborted by user or selected non-existant profession"); +} + +void RegistrationDialog::removeOldProfession() { + +} diff --git a/iFacility/registrationdialog.h b/iFacility/registrationdialog.h new file mode 100644 index 0000000..7166bf5 --- /dev/null +++ b/iFacility/registrationdialog.h @@ -0,0 +1,37 @@ +#ifndef REGISTRATIONDIALOG_H +#define REGISTRATIONDIALOG_H + +#include +#include +#include + +#include "objects/user.h" +#include "viewmodels/userprofessionviewmodel.h" + +namespace Ui { class RegistrationDialog; } + +class RegistrationDialog : public QDialog { +private: + Q_OBJECT + + Ui::RegistrationDialog *ui; + UserProfessionViewModel *upvm; + User *user = nullptr; + bool mEditMode = false; + +public: + explicit RegistrationDialog(QWidget *parent = nullptr); + ~RegistrationDialog(); + + void lockUserType(UserType type); + void setUser(User *usr); + void setEditMode(bool editMode); + +public slots: + void accept() Q_DECL_OVERRIDE; + + void addNewProfession(); + void removeOldProfession(); +}; + +#endif // REGISTRATIONDIALOG_H diff --git a/iFacility/registrationdialog.ui b/iFacility/registrationdialog.ui new file mode 100644 index 0000000..140de4e --- /dev/null +++ b/iFacility/registrationdialog.ui @@ -0,0 +1,240 @@ + + + RegistrationDialog + + + + 0 + 0 + 648 + 436 + + + + + 648 + 436 + + + + + 648 + 436 + + + + Dialog + + + + + + Full name + + + + + + First name + + + + + + + Second name + + + + + + + Patronymic + + + + + + + + + + Login data + + + + + + Login + + + + + + + QLineEdit::Password + + + Password + + + + + + + + + + User type + + + + + + + Administrator + + + + + Dispatcher + + + + + Worker + + + + + + + + + + + Professions + + + + + + + + + + 0 + 0 + + + + Add + + + + + + + + 0 + 0 + + + + Remove + + + + + + + + + + + 630 + 23 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + RegistrationDialog + accept() + + + 257 + 426 + + + 157 + 274 + + + + + buttonBox + rejected() + RegistrationDialog + reject() + + + 325 + 426 + + + 286 + 274 + + + + + btnAddProfession + clicked() + RegistrationDialog + addNewProfession() + + + 587 + 245 + + + 520 + 184 + + + + + btnRemoveProfession + clicked() + RegistrationDialog + removeOldProfession() + + + 600 + 363 + + + 279 + 184 + + + + + + addNewProfession() + removeOldProfession() + + diff --git a/iFacility/viewmodels/userprofessionviewmodel.cpp b/iFacility/viewmodels/userprofessionviewmodel.cpp new file mode 100644 index 0000000..6ac951d --- /dev/null +++ b/iFacility/viewmodels/userprofessionviewmodel.cpp @@ -0,0 +1,56 @@ +#include "userprofessionviewmodel.h" + +UserProfessionViewModel::UserProfessionViewModel(QObject *parent) : QAbstractTableModel(parent) { + +} + +int UserProfessionViewModel::rowCount(const QModelIndex &/*parent*/) const { + return mProfList.length(); +} + +int UserProfessionViewModel::columnCount(const QModelIndex &/*parent*/) const { + return 3; +} + +QVariant UserProfessionViewModel::headerData(int section, + Qt::Orientation orientation, int role) const { + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + switch (section) { + case 0: + return QString("Profession"); + case 1: + return QString("Date of acquirement"); + case 2: + return QString("Rank"); + } + } + return QVariant(); +} + +QVariant UserProfessionViewModel::data(const QModelIndex &index, int role) const { + if (role == Qt::DisplayRole) { + auto item = mProfList[index.row()]; + auto prof = Database::instance()->getProfession(item.getProfession()); + + int col = index.column(); + switch (col) { + case 0: + return prof == nullptr? "ERROR:UNKNOWN" : prof->title(); + case 1: + return item.getAcquiredDate(); + case 2: + return item.getRank(); + } + + return "UNKNOWN FIELD"; + } + + return QVariant(); +} + +void UserProfessionViewModel::setProfessionsList(const ProfessionsList &profList) { + beginResetModel(); + mProfList.clear(); + mProfList += profList; + endResetModel(); +} diff --git a/iFacility/viewmodels/userprofessionviewmodel.h b/iFacility/viewmodels/userprofessionviewmodel.h new file mode 100644 index 0000000..355beab --- /dev/null +++ b/iFacility/viewmodels/userprofessionviewmodel.h @@ -0,0 +1,25 @@ +#ifndef USERPROFESSIONVIEWMODEL_H +#define USERPROFESSIONVIEWMODEL_H + +#include + +#include "../objects/user.h" +#include "../db/database.h" + +class UserProfessionViewModel : public QAbstractTableModel { +private: + Q_OBJECT + + ProfessionsList mProfList; + +public: + UserProfessionViewModel(QObject *parent); + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + void setProfessionsList(const ProfessionsList &profList); +}; + +#endif // USERPROFESSIONVIEWMODEL_H