summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikita Kostovsky <nikita@kostovsky.me>2025-06-23 22:03:49 +0200
committerNikita Kostovsky <nikita@kostovsky.me>2025-06-23 22:03:49 +0200
commit0915fc1494df1cd15fc9c09bbf622f137406c84c (patch)
treeef81d75f0e62143b1d072f6fd911eed9c5d2230f /src
parentc9fcceb74d861525b2defec8219374edb9c1455a (diff)
add User(login) constructor, fetch db data inside
Diffstat (limited to 'src')
-rw-r--r--src/atomchannel.cpp20
-rw-r--r--src/atomchannel.h4
-rw-r--r--src/constants.h3
-rw-r--r--src/main.cpp1
-rw-r--r--src/rsshit_db.cpp1
-rw-r--r--src/user.cpp95
-rw-r--r--src/user.h47
7 files changed, 134 insertions, 37 deletions
diff --git a/src/atomchannel.cpp b/src/atomchannel.cpp
index 6a7c87c..95f4f0d 100644
--- a/src/atomchannel.cpp
+++ b/src/atomchannel.cpp
@@ -81,8 +81,8 @@ AtomChannel::AtomChannel(QXmlStreamReader *xmlReader)
// TODO: move to a separate function, code is almost identical in all methods called `getDbId`
int AtomChannel::getDbId()
{
- if (id != rsshit::db::IdNotFound)
- return id;
+ if (m_id != rsshit::db::IdNotFound)
+ return m_id;
const auto db = rsshit::db::open();
@@ -122,8 +122,8 @@ int AtomChannel::getDbId()
// TODO: move to a separate function, code is almost identical in all methods called `createInDb`
int AtomChannel::createInDb()
{
- if (id != rsshit::db::IdNotFound)
- return id;
+ if (m_id != rsshit::db::IdNotFound)
+ return m_id;
const auto db = rsshit::db::open();
@@ -142,7 +142,9 @@ int AtomChannel::createInDb()
return rsshit::db::IdNotFound;
}
- return insertQ.lastInsertId().toInt();
+ m_id = insertQ.lastInsertId().toInt();
+
+ return m_id;
}
// TODO: can be moved to IDbObject
@@ -158,16 +160,16 @@ int AtomChannel::getOrInsertDbId()
QList<int> AtomChannel::syncDbItems()
{
- if (id == rsshit::db::IdNotFound)
- id = getOrInsertDbId();
+ if (m_id == rsshit::db::IdNotFound)
+ m_id = getOrInsertDbId();
- if (id == rsshit::db::IdNotFound)
+ if (m_id == rsshit::db::IdNotFound)
return {};
QList<int> result;
for (auto &item : items) {
- auto id = item.getOrInsertDbId(this->id);
+ auto id = item.getOrInsertDbId(this->m_id);
if (id != rsshit::db::IdNotFound)
result << id;
diff --git a/src/atomchannel.h b/src/atomchannel.h
index cde066b..7f7294a 100644
--- a/src/atomchannel.h
+++ b/src/atomchannel.h
@@ -49,9 +49,9 @@ public:
public:
/*!
- * \brief id - cache db id
+ * \brief m_id - cache db m_id
*/
- int id{0};
+ int m_id{0};
QString title;
/*!
diff --git a/src/constants.h b/src/constants.h
index c27b777..bd67eda 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -10,6 +10,9 @@ const QString feedsTableName{"feeds"};
const QString idTag{"id"};
const QString linkTag{"link"};
+const QString loginTag{"loging"};
+const QString passwordHashTag{"password_hash"};
+const QString saltTag{"salt"};
constexpr int IdNotFound{0};
diff --git a/src/main.cpp b/src/main.cpp
index 22029a9..2dab907 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -66,6 +66,7 @@ int main(int argc, char *argv[])
qDebug() << "verify password 321:" << user.verifyPassword("321");
qDebug() << "user.getDbId()" << user.getDbId();
qDebug() << "user.createInDb()" << user.createInDb();
+ qDebug() << "user.createInDb()" << user.createInDb();
qDebug() << "user.createInDb()" << user.getOrInsertDbId();
qDebug() << "user.createInDb()" << user.createInDb();
diff --git a/src/rsshit_db.cpp b/src/rsshit_db.cpp
index d5d2a2a..b690eaa 100644
--- a/src/rsshit_db.cpp
+++ b/src/rsshit_db.cpp
@@ -48,7 +48,6 @@ std::optional<QSqlDatabase> rsshit::db::open()
+ QFileInfo{rsshit::db::dbSqliteResourceFilename}.fileName()};
db.setDatabaseName(dbFilepath);
- qDebug() << "open" << dbFilepath;
if (!db.open()) {
qWarning() << "cannot open db:" << db.lastError().text();
diff --git a/src/user.cpp b/src/user.cpp
index 4667ebf..1c83921 100644
--- a/src/user.cpp
+++ b/src/user.cpp
@@ -25,19 +25,26 @@ QByteArray generateSalt()
// FIXME: use better password hashing algo
User::User(const QString &login, const QString &password)
- : login{login}
- , salt{rsshit::generateSalt()}
- , passwordHash{hashPassword(password)}
+ : m_login{login}
+ , m_salt{rsshit::generateSalt()}
+ , m_passwordHash{hashPassword(password)}
{
qDebug() << __func__ << "login:" << login;
- qDebug() << __func__ << "salt size:" << salt.size();
- qDebug() << __func__ << "passwordHash size:" << passwordHash.size();
+ qDebug() << __func__ << "salt size:" << m_salt.size();
+ qDebug() << __func__ << "passwordHash size:" << m_passwordHash.size();
}
+User::User(const QString &login)
+ : m_login{login}
+{
+ fetchFromDb();
+}
+
+// TODO: rename to `fetchFromDb` and fill all data?
int User::getDbId()
{
- if (id != rsshit::db::IdNotFound)
- return id;
+ if (m_id != rsshit::db::IdNotFound)
+ return m_id;
const auto db = rsshit::db::open();
@@ -45,7 +52,7 @@ int User::getDbId()
return rsshit::db::IdNotFound;
QSqlQuery selectQ{"select id from users where login=?"};
- selectQ.addBindValue(login);
+ selectQ.addBindValue(m_login);
if (!selectQ.exec()) {
qWarning() << "cannot exec query" << selectQ.lastQuery() << ":"
@@ -71,26 +78,78 @@ int User::getDbId()
return rsshit::db::IdNotFound;
}
+ if (m_id != result)
+ m_id = result;
+
return result;
}
+int User::fetchFromDb()
+{
+ const auto db = rsshit::db::open();
+
+ if (!db)
+ return rsshit::db::IdNotFound;
+
+ // ignore local `id` if exists, fetch all fields
+ QSqlQuery selectQ{"select id, login, salt, password_hash from users where login=?"};
+ selectQ.addBindValue(m_login);
+
+ if (!selectQ.exec()) {
+ qWarning() << "cannot exec query" << selectQ.lastQuery() << ":"
+ << selectQ.lastError().text();
+
+ return rsshit::db::IdNotFound;
+ }
+
+ if (!selectQ.next())
+ return rsshit::db::IdNotFound;
+
+ const auto idVariant = selectQ.value(rsshit::db::idTag);
+
+ if (!idVariant.isValid() || !idVariant.canConvert<int>())
+ return rsshit::db::IdNotFound;
+
+ bool ok{false};
+ m_id = idVariant.toInt(&ok);
+
+ if (!ok) {
+ qWarning() << "got invalid id from db:" << idVariant;
+
+ return rsshit::db::IdNotFound;
+ }
+
+ if (m_id == rsshit::db::IdNotFound)
+ return m_id;
+
+ m_salt = selectQ.value(rsshit::db::saltTag).toByteArray();
+ m_passwordHash = selectQ.value(rsshit::db::passwordHashTag).toByteArray();
+
+ return m_id;
+}
+
+bool User::existsInDb()
+{
+ return getDbId() != rsshit::db::IdNotFound;
+}
+
int User::createInDb()
{
- if (id != rsshit::db::IdNotFound)
- return id;
+ if (m_id != rsshit::db::IdNotFound)
+ return m_id;
const auto db = rsshit::db::open();
if (!db)
return rsshit::db::IdNotFound;
- if (login.isEmpty() || salt.isEmpty() || passwordHash.isEmpty())
+ if (m_login.isEmpty() || m_salt.isEmpty() || m_passwordHash.isEmpty())
return rsshit::db::IdNotFound;
QSqlQuery insertQ{"insert into users(login, salt, password_hash) values(?, ?, ?)"};
- insertQ.addBindValue(login);
- insertQ.addBindValue(salt);
- insertQ.addBindValue(passwordHash);
+ insertQ.addBindValue(m_login);
+ insertQ.addBindValue(m_salt);
+ insertQ.addBindValue(m_passwordHash);
if (!insertQ.exec()) {
qWarning() << "cannot exec query" << insertQ.lastQuery() << ":"
@@ -99,7 +158,9 @@ int User::createInDb()
return rsshit::db::IdNotFound;
}
- return insertQ.lastInsertId().toInt();
+ m_id = insertQ.lastInsertId().toInt();
+
+ return m_id;
}
int User::getOrInsertDbId()
@@ -114,10 +175,10 @@ int User::getOrInsertDbId()
bool User::verifyPassword(const QString &password)
{
- return hashPassword(password) == passwordHash;
+ return (!m_passwordHash.isEmpty()) && (hashPassword(password) == m_passwordHash);
}
QByteArray User::hashPassword(const QString &password)
{
- return QCryptographicHash::hash(salt + password.toUtf8(), QCryptographicHash::Sha256);
+ return QCryptographicHash::hash(m_salt + password.toUtf8(), QCryptographicHash::Sha256);
}
diff --git a/src/user.h b/src/user.h
index 6826ed4..b6c1633 100644
--- a/src/user.h
+++ b/src/user.h
@@ -14,22 +14,53 @@ public:
/*!
* \brief User - create user with given `login` and `password`. `salt` and
* `passwordHash` will be generated and stored instead of real `password`.
- * Will *not* be committed to db automatically.
+ * Will *not* be committed to db automatically. Should be used to create a
+ * new user
+ * \code
+ * User user{"admin", "123"};
+ * auto id = user.createInDb();
+ * if (id == rsshit::db::IdNotFound) // error
+ * ...
* \param login - max len is 32
* \param password - max len is 32
*/
explicit User(const QString &login, const QString &password);
+ /*!
+ * \brief User - create user with given `login` and try to fetch data from db
+ * automatically. Should be used for existing users
+ * \code
+ * User user{"admin"};
+ * if (user.getDbId() == rsshit::db::IdNotFound) // user not found
+ * ...
+ * if (!user.verifyPassword("123)) // wrong password
+ * ...
+ */
+ explicit User(const QString &login);
+
public:
/*!
* \brief getDbId - check if user with corresponding `link` exists in db
- * and return db id if any
+ * and return db id if any (fills `id` var as well)
* \return id on success, 0 otherwise
*/
int getDbId();
/*!
- * \brief createInDb - create user in db
+ * \brief fetchFromDb - fetch db user record with corresponding `login`
+ * \return existing `id` on success, 0 otherwise
+ */
+ int fetchFromDb();
+
+ /*!
+ * \brief existsInDb - helper function, checks if `this` has valid `id`, or
+ * db record with corresponding `login` exists (calls `getDbId` under the hood)
+ * \return true if exists, false otherwise
+ */
+ bool existsInDb();
+
+ /*!
+ * \brief createInDb - create user in db, fill `id`
* \return new user id on success, 0 otherwise
*/
int createInDb();
@@ -43,11 +74,11 @@ public:
bool verifyPassword(const QString &password);
-public:
- int id{0};
- QString login;
- QByteArray salt;
- QByteArray passwordHash;
+private:
+ int m_id{0};
+ QString m_login;
+ QByteArray m_salt;
+ QByteArray m_passwordHash;
private:
QByteArray hashPassword(const QString &password);