From eabfc850684c6ea26a61b5af2f01043652391d1b Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 9 Dec 2024 09:27:32 -0300 Subject: [PATCH] in progress --- app/activeproject.cpp | 66 ++++------------- app/activeproject.h | 13 +--- app/qml/project/MMProjectController.qml | 2 +- core/merginapi.cpp | 95 +++++++++++++++++++++++++ core/merginapi.h | 42 ++++++----- 5 files changed, 138 insertions(+), 80 deletions(-) diff --git a/app/activeproject.cpp b/app/activeproject.cpp index d51e64174..ba65999fc 100644 --- a/app/activeproject.cpp +++ b/app/activeproject.cpp @@ -76,6 +76,17 @@ ActiveProject::ActiveProject( AppSettings &appSettings setAutosyncEnabled( mAppSettings.autosyncAllowed() ); QObject::connect( &mAppSettings, &AppSettings::autosyncAllowedChanged, this, &ActiveProject::setAutosyncEnabled ); + + QObject::connect( + mMerginApi, + &MerginApi::projectMetadataRoleUpdated, + this, [this]( const QString & projectFullName, const QString & role ) + { + if ( projectFullName == this->projectFullName() ) + { + setProjectRole( role ); + } + } ); } ActiveProject::~ActiveProject() = default; @@ -103,7 +114,7 @@ bool ActiveProject::load( const QString &filePath ) bool ActiveProject::forceLoad( const QString &filePath, bool force ) { // update user's role each time a project is opened, following #3174 - updateProjectMetadata(); + mMerginApi->updateProjectMetadataRole( projectFullName() ); CoreUtils::log( QStringLiteral( "Project loading" ), filePath + " " + ( force ? "true" : "false" ) ); @@ -559,56 +570,9 @@ bool ActiveProject::positionTrackingSupported() const return mQgsProject->readBoolEntry( QStringLiteral( "Mergin" ), QStringLiteral( "PositionTracking/Enabled" ), false ); } -bool ActiveProject::updateProjectMetadata() -{ - if ( !mMerginApi ) - { - return false; - } - - QNetworkReply *reply = mMerginApi->getProjectInfo( projectFullName() ); - if ( !reply ) - { - restoreCachedRole(); - return false; - } - - reply->request().setAttribute( static_cast( mMerginApi->AttrProjectFullName ), projectFullName() ); - - connect( reply, &QNetworkReply::finished, this, &ActiveProject::updateProjectMetadataReplyFinished ); - - return true; -} - -void ActiveProject::updateProjectMetadataReplyFinished() -{ - QNetworkReply *r = qobject_cast( sender() ); - Q_ASSERT( r ); - - QString projectFullName = r->request().attribute( static_cast( mMerginApi->AttrProjectFullName ) ).toString(); - - if ( r->error() == QNetworkReply::NoError ) - { - QByteArray data = r->readAll(); - - MerginProjectMetadata serverProject = MerginProjectMetadata::fromJson( data ); - QString role = serverProject.role; - setProjectRole( role ); - } - else - { - restoreCachedRole(); - } - - r->deleteLater(); -} - -void ActiveProject::restoreCachedRole() -{ - MerginProjectMetadata cachedProjectMetadata = MerginProjectMetadata::fromCachedJson( mLocalProject.projectDir + "/" + mMerginApi->sMetadataFile ); - QString role = cachedProjectMetadata.role; - setProjectRole( role ); -} +// read cached role from metadata -> get reply -> update if changed +// metadataRoleFetchFinishedSignal -> (data) +// store role in app settings or update only role in cached json or nothing :) QString ActiveProject::projectRole() const { diff --git a/app/activeproject.h b/app/activeproject.h index bec9a8b4f..d7ff185eb 100644 --- a/app/activeproject.h +++ b/app/activeproject.h @@ -22,7 +22,7 @@ #include "localprojectsmanager.h" #include "autosynccontroller.h" #include "inputmapsettings.h" -#include "../core/merginapi.h" +#include "merginapi.h" /** * \brief The ActiveProject class can load a QGIS project and holds its data. @@ -128,17 +128,6 @@ class ActiveProject: public QObject void setProjectRole( const QString &role ); - /** - * Restores cached project role in metadata - */ - void restoreCachedRole(); - - /** - * Creates a network request to fetch latest project information and define user role in this project - */ - Q_INVOKABLE bool updateProjectMetadata(); - void updateProjectMetadataReplyFinished(); - signals: void qgsProjectChanged(); void localProjectChanged( LocalProject project ); diff --git a/app/qml/project/MMProjectController.qml b/app/qml/project/MMProjectController.qml index 47d34033d..a0b8283bb 100644 --- a/app/qml/project/MMProjectController.qml +++ b/app/qml/project/MMProjectController.qml @@ -51,7 +51,7 @@ Item { // just hide the panel - project already loaded hidePanel() // update user's role in project ( in case user has changed ) - __activeProject.updateProjectMetadata() + __merginApi.updateProjectMetadataRole( __activeProject.projectFullName() ) } else { diff --git a/core/merginapi.cpp b/core/merginapi.cpp index ab5e4a618..801f511e1 100644 --- a/core/merginapi.cpp +++ b/core/merginapi.cpp @@ -3449,6 +3449,45 @@ bool MerginApi::writeData( const QByteArray &data, const QString &path ) return true; } +bool MerginApi::updateCachedProjectRole( const QString &projectFullName, const QString &newRole ) +{ + LocalProject project = mLocalProjects.projectFromMerginName( projectFullName ); + if ( !project.isValid() ) + { + return false; + } + + QString metadataPath = project.projectDir + "/" + sMetadataFile; + + QFile file( metadataPath ); + if ( !file.open( QIODevice::ReadOnly ) ) + { + return false; + } + + QByteArray data = file.readAll(); + file.close(); + + QJsonDocument doc = QJsonDocument::fromJson( data ); + if ( !doc.isObject() ) + { + return false; + } + + QJsonObject obj = doc.object(); + obj["role"] = newRole; + doc.setObject( obj ); + + if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) + { + return false; + } + + bool success = ( file.write( doc.toJson() ) != -1 ); + file.close(); + + return success; +} void MerginApi::createPathIfNotExists( const QString &filePath ) { @@ -3945,3 +3984,59 @@ DownloadQueueItem::DownloadQueueItem( const QString &fp, qint64 s, int v, qint64 tempFileName = CoreUtils::uuidWithoutBraces( QUuid::createUuid() ); } +void MerginApi::updateProjectMetadataRole( const QString &projectFullName ) +{ + if ( projectFullName.isEmpty() ) + { + return; + } + + QString projectDir = mLocalProjects.projectFromMerginName( projectFullName ).projectDir; + MerginProjectMetadata cachedProjectMetadata = MerginProjectMetadata::fromCachedJson( projectDir + "/" + sMetadataFile ); + QString cachedRole = cachedProjectMetadata.role; + + QNetworkReply *reply = getProjectInfo( projectFullName ); + if ( !reply ) + { + emit projectMetadataRoleUpdated( projectFullName, cachedRole ); + return; + } + + reply->request().setAttribute( static_cast( AttrProjectFullName ), projectFullName ); + reply->request().setAttribute( static_cast( AttrCachedRole ), cachedRole ); + connect( reply, &QNetworkReply::finished, this, &MerginApi::updateProjectMetadataRoleReplyFinished ); +} + +void MerginApi::updateProjectMetadataRoleReplyFinished() +{ + QNetworkReply *r = qobject_cast( sender() ); + Q_ASSERT( r ); + + QString projectFullName = r->request().attribute( static_cast( AttrProjectFullName ) ).toString(); + QString cachedRole = r->request().attribute( static_cast( AttrCachedRole ) ).toString(); + + if ( r->error() == QNetworkReply::NoError ) + { + QByteArray data = r->readAll(); + MerginProjectMetadata serverProject = MerginProjectMetadata::fromJson( data ); + QString role = serverProject.role; + + if ( role != cachedRole ) + { + if ( updateCachedProjectRole( projectFullName, role ) ) + { + emit projectMetadataRoleUpdated( projectFullName, role ); + } + else + { + CoreUtils::log( "metadata", QString( "Failed to update cached role for project %1" ).arg( projectFullName ) ); + } + } + } + else + { + emit projectMetadataRoleUpdated( projectFullName, cachedRole ); + } + + r->deleteLater(); +} diff --git a/core/merginapi.h b/core/merginapi.h index 9fc47ac64..baa229e49 100644 --- a/core/merginapi.h +++ b/core/merginapi.h @@ -573,23 +573,10 @@ class MerginApi: public QObject */ bool apiSupportsWorkspaces(); - /** Creates a request to get project details (list of project files). - */ - QNetworkReply *getProjectInfo( const QString &projectFullName, bool withAuth = true ); - - enum CustomAttribute - { - AttrProjectFullName = QNetworkRequest::User, - AttrTempFileName = QNetworkRequest::User + 1, - AttrWorkspaceName = QNetworkRequest::User + 2, - AttrAcceptFlag = QNetworkRequest::User + 3, - }; - /** - * Extracts detail (message) of an error json. If its not json or detail cannot be parsed, the whole data are return; - * \param data Data received from mergin server on a request failed. - */ - QString extractServerErrorMsg( const QByteArray &data ); + * Updates project metadata role by fetching latest information from server. + */ + Q_INVOKABLE void updateProjectMetadataRole( const QString &projectFullName ); signals: void apiSupportsSubscriptionsChanged(); @@ -668,6 +655,7 @@ class MerginApi: public QObject void apiSupportsWorkspacesChanged(); void serverWasUpgraded(); + void projectMetadataRoleUpdated( const QString &projectFullName, const QString &role ); private slots: void listProjectsReplyFinished( QString requestId ); @@ -762,11 +750,20 @@ class MerginApi: public QObject */ QVariant extractServerErrorValue( const QByteArray &data, const QString &key ); /** + * Extracts detail (message) of an error json. If its not json or detail cannot be parsed, the whole data are return; + * \param data Data received from mergin server on a request failed. + */ + QString extractServerErrorMsg( const QByteArray &data ); + /** * Returns a temporary project path. * \param projectFullName */ QString getTempProjectDir( const QString &projectFullName ); + /** Creates a request to get project details (list of project files). + */ + QNetworkReply *getProjectInfo( const QString &projectFullName, bool withAuth = true ); + //! Called when pull of project data has finished to finalize things and emit sync finished signal void finalizeProjectPull( const QString &projectFullName ); @@ -798,6 +795,10 @@ class MerginApi: public QObject bool projectFileHasBeenUpdated( const ProjectDiff &diff ); + void updateProjectMetadataRoleReplyFinished(); + + bool updateCachedProjectRole( const QString &projectFullName, const QString &newRole ); + QNetworkAccessManager mManager; QString mApiRoot; LocalProjectsManager &mLocalProjects; @@ -808,6 +809,15 @@ class MerginApi: public QObject MerginSubscriptionInfo *mSubscriptionInfo; //owned by this (qml grouped-properties) MerginUserAuth *mUserAuth; //owned by this (qml grouped-properties) + enum CustomAttribute + { + AttrProjectFullName = QNetworkRequest::User, + AttrTempFileName = QNetworkRequest::User + 1, + AttrWorkspaceName = QNetworkRequest::User + 2, + AttrAcceptFlag = QNetworkRequest::User + 3, + AttrCachedRole = QNetworkRequest::User + 4 + }; + Transactions mTransactionalStatus; //projectFullname -> transactionStatus static const QSet sIgnoreExtensions; static const QSet sIgnoreImageExtensions;