Skip to content
Snippets Groups Projects
Commit 477f4f66 authored by Emmanuel Lepage Vallee's avatar Emmanuel Lepage Vallee Committed by Guillaume Roguez
Browse files

account: Add a state machine for the credentials

Refs #68972

(cherry picked from commit d100b1af)
parent 92aaabdf
No related branches found
No related tags found
No related merge requests found
...@@ -1651,7 +1651,6 @@ void AccountPrivate::save() ...@@ -1651,7 +1651,6 @@ void AccountPrivate::save()
q_ptr->codecModel()->save(); q_ptr->codecModel()->save();
q_ptr->setId(currentId.toLatin1()); q_ptr->setId(currentId.toLatin1());
q_ptr->credentialModel()->save();
} //New account } //New account
else { //Existing account else { //Existing account
MapStringString tmp; MapStringString tmp;
...@@ -1668,6 +1667,9 @@ void AccountPrivate::save() ...@@ -1668,6 +1667,9 @@ void AccountPrivate::save()
} }
} }
//Save the credentials if they changed
q_ptr->credentialModel() << CredentialModel::EditAction::SAVE;
if (!q_ptr->id().isEmpty()) { if (!q_ptr->id().isEmpty()) {
Account* acc = AccountModel::instance()->getById(q_ptr->id()); Account* acc = AccountModel::instance()->getById(q_ptr->id());
qDebug() << "Adding the new account to the account list (" << q_ptr->id() << ")"; qDebug() << "Adding the new account to the account list (" << q_ptr->id() << ")";
...@@ -1727,7 +1729,7 @@ void AccountPrivate::reload() ...@@ -1727,7 +1729,7 @@ void AccountPrivate::reload()
//If the credential model is loaded, then update it //If the credential model is loaded, then update it
if (m_pCredentials) if (m_pCredentials)
m_pCredentials->reload(); m_pCredentials << CredentialModel::EditAction::RELOAD;
emit q_ptr->changed(q_ptr); emit q_ptr->changed(q_ptr);
//The registration state is cached, update that cache //The registration state is cached, update that cache
......
...@@ -23,39 +23,68 @@ ...@@ -23,39 +23,68 @@
//Ring //Ring
#include <account.h> #include <account.h>
#include <private/matrixutils.h>
//Dring //Dring
#include "dbus/configurationmanager.h" #include "dbus/configurationmanager.h"
#include <account_const.h> #include <account_const.h>
typedef void (CredentialModelPrivate::*CredModelFct)();
class CredentialModelPrivate class CredentialModelPrivate
{ {
public: public:
///@struct CredentialData store credential information ///@struct CredentialData store credential information
struct CredentialData2 { struct CredentialData {
QString name ; QString name ;
QString password; QString password;
QString realm ; QString realm ;
}; };
//Attributes //Attributes
QList<CredentialData2*> m_lCredentials; QList<CredentialData*> m_lCredentials;
Account* m_pAccount ; Account* m_pAccount ;
CredentialModel::EditState m_EditState ;
CredentialModel* q_ptr ;
static Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> m_mStateMachine;
//Callbacks
void clear ();
void save ();
void reload ();
void nothing();
void modify ();
//Helper
inline void performAction(const CredentialModel::EditAction action);
}; };
#define CMP &CredentialModelPrivate
Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> CredentialModelPrivate::m_mStateMachine ={{
/* SAVE MODIFY RELOAD CLEAR */
/* LOADING */ {{ CMP::nothing, CMP::nothing, CMP::reload, CMP::nothing }},
/* READY */ {{ CMP::nothing, CMP::modify , CMP::reload, CMP::clear }},
/* MODIFIED */ {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }},
/* OUTDATED */ {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }},
}};
#undef CMP
///Constructor ///Constructor
CredentialModel::CredentialModel(Account* acc) : QAbstractListModel(acc), CredentialModel::CredentialModel(Account* acc) : QAbstractListModel(acc),
d_ptr(new CredentialModelPrivate()) d_ptr(new CredentialModelPrivate())
{ {
Q_ASSERT(acc); Q_ASSERT(acc);
d_ptr->m_EditState = CredentialModel::EditState::LOADING;
d_ptr->m_pAccount = acc; d_ptr->m_pAccount = acc;
d_ptr->q_ptr = this;
QHash<int, QByteArray> roles = roleNames(); QHash<int, QByteArray> roles = roleNames();
reload(); this << EditAction::RELOAD;
d_ptr->m_EditState = CredentialModel::EditState::READY;
} }
CredentialModel::~CredentialModel() CredentialModel::~CredentialModel()
{ {
foreach (CredentialModelPrivate::CredentialData2* data, d_ptr->m_lCredentials) { foreach (CredentialModelPrivate::CredentialData* data, d_ptr->m_lCredentials) {
delete data; delete data;
} }
} }
...@@ -119,16 +148,21 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in ...@@ -119,16 +148,21 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in
if (idx.column() == 0 && role == CredentialModel::Role::NAME) { if (idx.column() == 0 && role == CredentialModel::Role::NAME) {
d_ptr->m_lCredentials[idx.row()]->name = value.toString(); d_ptr->m_lCredentials[idx.row()]->name = value.toString();
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
this << EditAction::MODIFY;
return true; return true;
} }
else if (idx.column() == 0 && role == CredentialModel::Role::PASSWORD) { else if (idx.column() == 0 && role == CredentialModel::Role::PASSWORD) {
if (d_ptr->m_lCredentials[idx.row()]->password != value.toString()) {
d_ptr->m_lCredentials[idx.row()]->password = value.toString(); d_ptr->m_lCredentials[idx.row()]->password = value.toString();
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
this << EditAction::MODIFY;
return true; return true;
} }
}
else if (idx.column() == 0 && role == CredentialModel::Role::REALM) { else if (idx.column() == 0 && role == CredentialModel::Role::REALM) {
d_ptr->m_lCredentials[idx.row()]->realm = value.toString(); d_ptr->m_lCredentials[idx.row()]->realm = value.toString();
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
this << EditAction::MODIFY;
return true; return true;
} }
return false; return false;
...@@ -138,7 +172,7 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in ...@@ -138,7 +172,7 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in
QModelIndex CredentialModel::addCredentials() QModelIndex CredentialModel::addCredentials()
{ {
beginInsertRows(QModelIndex(), d_ptr->m_lCredentials.size()-1, d_ptr->m_lCredentials.size()-1); beginInsertRows(QModelIndex(), d_ptr->m_lCredentials.size()-1, d_ptr->m_lCredentials.size()-1);
d_ptr->m_lCredentials << new CredentialModelPrivate::CredentialData2; d_ptr->m_lCredentials << new CredentialModelPrivate::CredentialData;
endInsertRows(); endInsertRows();
emit dataChanged(index(d_ptr->m_lCredentials.size()-1,0), index(d_ptr->m_lCredentials.size()-1,0)); emit dataChanged(index(d_ptr->m_lCredentials.size()-1,0), index(d_ptr->m_lCredentials.size()-1,0));
return index(d_ptr->m_lCredentials.size()-1,0); return index(d_ptr->m_lCredentials.size()-1,0);
...@@ -159,52 +193,92 @@ void CredentialModel::removeCredentials(const QModelIndex& idx) ...@@ -159,52 +193,92 @@ void CredentialModel::removeCredentials(const QModelIndex& idx)
} }
///Remove everything ///Remove everything
void CredentialModel::clear() void CredentialModelPrivate::clear()
{ {
foreach(CredentialModelPrivate::CredentialData2* data2, d_ptr->m_lCredentials) { foreach(CredentialModelPrivate::CredentialData* data2, m_lCredentials) {
delete data2; delete data2;
} }
d_ptr->m_lCredentials.clear(); m_lCredentials.clear();
m_EditState = CredentialModel::EditState::READY;
} }
///Save all credentials ///Save all credentials
void CredentialModel::save() void CredentialModelPrivate::save()
{ {
ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance(); ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
VectorMapStringString toReturn; VectorMapStringString toReturn;
for (int i=0; i < rowCount();i++) { for (int i=0; i < q_ptr->rowCount();i++) {
const QModelIndex& idx = index(i,0); const QModelIndex& idx = q_ptr->index(i,0);
MapStringString credentialData; MapStringString credentialData;
QString user = data(idx,CredentialModel::Role::NAME).toString(); QString user = q_ptr->data(idx,CredentialModel::Role::NAME).toString();
QString realm = data(idx,CredentialModel::Role::REALM).toString(); QString realm = q_ptr->data(idx,CredentialModel::Role::REALM).toString();
if (user.isEmpty()) { if (user.isEmpty()) {
user = d_ptr->m_pAccount->username(); user = m_pAccount->username();
setData(idx,user,CredentialModel::Role::NAME); q_ptr->setData(idx,user,CredentialModel::Role::NAME);
} }
if (realm.isEmpty()) { if (realm.isEmpty()) {
realm = '*'; realm = '*';
setData(idx,realm,CredentialModel::Role::REALM); q_ptr->setData(idx,realm,CredentialModel::Role::REALM);
} }
credentialData[ DRing::Account::ConfProperties::USERNAME ] = user; credentialData[ DRing::Account::ConfProperties::USERNAME ] = user;
credentialData[ DRing::Account::ConfProperties::PASSWORD ] = data(idx,CredentialModel::Role::PASSWORD).toString(); credentialData[ DRing::Account::ConfProperties::PASSWORD ] = q_ptr->data(idx,CredentialModel::Role::PASSWORD).toString();
credentialData[ DRing::Account::ConfProperties::REALM ] = realm; credentialData[ DRing::Account::ConfProperties::REALM ] = realm;
toReturn << credentialData; toReturn << credentialData;
} }
configurationManager.setCredentials(d_ptr->m_pAccount->id(),toReturn); configurationManager.setCredentials(m_pAccount->id(),toReturn);
m_EditState = CredentialModel::EditState::READY;
} }
///Reload credentials from DBUS ///Reload credentials from DBUS
void CredentialModel::reload() void CredentialModelPrivate::reload()
{ {
if (!d_ptr->m_pAccount->isNew()) { if (!m_pAccount->isNew()) {
clear(); clear();
m_EditState = CredentialModel::EditState::LOADING;
ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance(); ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
const VectorMapStringString credentials = configurationManager.getCredentials(d_ptr->m_pAccount->id()); const VectorMapStringString credentials = configurationManager.getCredentials(m_pAccount->id());
for (int i=0; i < credentials.size(); i++) { for (int i=0; i < credentials.size(); i++) {
const QModelIndex& idx = addCredentials(); const QModelIndex& idx = q_ptr->addCredentials();
setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME ); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME );
setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD);
setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM ],CredentialModel::Role::REALM ); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM ],CredentialModel::Role::REALM );
}
} }
m_EditState = CredentialModel::EditState::READY;
}
void CredentialModelPrivate::nothing()
{
//nothing
}
void CredentialModelPrivate::modify()
{
m_EditState = CredentialModel::EditState::MODIFIED;
m_pAccount << Account::EditAction::MODIFY;
} }
void CredentialModelPrivate::performAction(const CredentialModel::EditAction action)
{
(this->*(m_mStateMachine[m_EditState][action]))();//FIXME don't use integer cast
}
/// anAccount << Call::EditAction::SAVE
CredentialModel* CredentialModel::operator<<(CredentialModel::EditAction& action)
{
performAction(action);
return this;
}
CredentialModel* operator<<(CredentialModel* a, CredentialModel::EditAction action)
{
return (!a)?nullptr : (*a) << action;
}
///Change the current edition state
bool CredentialModel::performAction(const CredentialModel::EditAction action)
{
CredentialModel::EditState curState = d_ptr->m_EditState;
d_ptr->performAction(action);
return curState != d_ptr->m_EditState;
} }
...@@ -40,6 +40,24 @@ public: ...@@ -40,6 +40,24 @@ public:
REALM = 102, REALM = 102,
}; };
/// @enum CredentialModel::Action Manage a CredentialModel lifecycle
enum class EditAction {
SAVE = 0, /*!< Save the model, if there is a conflict, use "ours" */
MODIFY = 1, /*!< Notify the state machine that the data has changed */
RELOAD = 2, /*!< Reload from the daemon, if there is a conflict, use "their" */
CLEAR = 3, /*!< Remove all credentials */
COUNT__
};
/// @enum CredentialModel::EditState track the changes from both clients and daemon
enum class EditState {
LOADING = 0, /*!< The credentials are being loaded, they are not ready yet */
READY = 1, /*!< Both side are synchronised */
MODIFIED = 2, /*!< Our version differ from the remote one */
OUTDATED = 3, /*!< The remote version differ from ours */
COUNT__
};
//Constructor //Constructor
explicit CredentialModel(Account* acc); explicit CredentialModel(Account* acc);
virtual ~CredentialModel(); virtual ~CredentialModel();
...@@ -54,13 +72,20 @@ public: ...@@ -54,13 +72,20 @@ public:
//Mutator //Mutator
QModelIndex addCredentials(); QModelIndex addCredentials();
void removeCredentials(const QModelIndex& idx); void removeCredentials(const QModelIndex& idx);
void clear (); bool performAction(CredentialModel::EditAction action);
void save ();
void reload(); //Getter
CredentialModel::EditState editState() const;
//Operator
CredentialModel* operator<<(CredentialModel::EditAction& action);
private: private:
QScopedPointer<CredentialModelPrivate> d_ptr; QScopedPointer<CredentialModelPrivate> d_ptr;
Q_DECLARE_PRIVATE(CredentialModel)
}; };
Q_DECLARE_METATYPE(CredentialModel*) Q_DECLARE_METATYPE(CredentialModel*)
CredentialModel* operator<<(CredentialModel* a, CredentialModel::EditAction action);
#endif #endif
...@@ -116,6 +116,17 @@ private: ...@@ -116,6 +116,17 @@ private:
static QMap<A, Row> m_hReverseMapping; static QMap<A, Row> m_hReverseMapping;
}; };
/**
* Create a matrix type with 2 enum class dimensions M[I,J] = V
* ^ ^ ^
* | | |
* Rows <--- | |
* Columns <----- |
* Value <----------
*/
template<class Row, class Column, typename Value>
using Matrix2D = Matrix1D<Row, Matrix1D<Column, Value>>;
/** /**
* A matrix with no value * A matrix with no value
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment