Handle switching API domain

pull/41/head
Laurent Cozic 2017-01-11 15:18:56 +01:00
parent ad3c59577e
commit 603d5e1370
17 changed files with 162 additions and 62 deletions

View File

@ -85,4 +85,19 @@ Item {
onClicked: root.loginButtonClicked()
}
Connections {
target: apiBaseUrlTF
onAccepted: root.loginButtonClicked()
}
Connections {
target: emailTF
onAccepted: root.loginButtonClicked()
}
Connections {
target: passwordTF
onAccepted: root.loginButtonClicked()
}
}

View File

@ -31,6 +31,7 @@ Application::Application(int &argc, char **argv) :
qDebug() << "Config dir:" << paths::configDir();
qDebug() << "Database file:" << paths::databaseFile();
qDebug() << "SSL:" << QSslSocket::sslLibraryBuildVersionString() << QSslSocket::sslLibraryVersionNumber();
jop::db().initialize(paths::databaseFile());
@ -152,9 +153,21 @@ void Application::dispatcher_loginClicked(const QString &apiBaseUrl, const QStri
qDebug() << apiBaseUrl << email << password;
dispatcher().emitLoginStarted();
QString newBaseUrl = filters::apiBaseUrl(apiBaseUrl);
Settings settings;
if (newBaseUrl != settings.value("api.baseUrl").toString()) {
// TODO: add confirmation dialog
qDebug() << "Base URL has changed from" << settings.value("api.baseUrl").toString() << "to" << newBaseUrl;
BaseModel::deleteAll(jop::FoldersTable);
BaseModel::deleteAll(jop::ChangesTable);
settings.remove("lastRevId");
settings.setValue("clientId", uuid::createUuid());
}
settings.setValue("user.email", filters::email(email));
settings.setValue("api.baseUrl", filters::apiBaseUrl(apiBaseUrl));
settings.setValue("api.baseUrl", newBaseUrl);
api_.setBaseUrl(apiBaseUrl);
@ -168,6 +181,9 @@ void Application::dispatcher_logoutClicked() {
Settings settings;
settings.setValue("session.id", "");
api_.setSessionId("");
synchronizer_.setSessionId("");
view_.showPage("login");
}

View File

@ -131,13 +131,13 @@ bool Database::commit() {
}
bool Database::execQuery(QSqlQuery &query) {
qDebug().noquote() << "SQL:" << query.lastQuery();
// qDebug().noquote() << "SQL:" << query.lastQuery();
QMapIterator<QString, QVariant> i(query.boundValues());
while (i.hasNext()) {
i.next();
qDebug().noquote() << "SQL:" << i.key() << "=" << i.value().toString();
}
// QMapIterator<QString, QVariant> i(query.boundValues());
// while (i.hasNext()) {
// i.next();
// qDebug().noquote() << "SQL:" << i.key() << "=" << i.value().toString();
// }
return query.exec();
}

View File

@ -16,6 +16,10 @@ void Dispatcher::emitFolderDeleted(const QString &folderId) {
emit folderDeleted(folderId);
}
void Dispatcher::emitAllFoldersDeleted() {
emit allFoldersDeleted();
}
void Dispatcher::emitLoginClicked(const QString &apiBaseUrl, const QString &email, const QString &password) {
emit loginClicked(apiBaseUrl, email, password);
}

View File

@ -18,6 +18,7 @@ public slots:
void emitFolderCreated(const QString& folderId);
void emitFolderUpdated(const QString& folderId);
void emitFolderDeleted(const QString& folderId);
void emitAllFoldersDeleted();
void emitLoginClicked(const QString& domain, const QString& email, const QString &password);
void emitLogoutClicked();
void emitLoginStarted();
@ -29,6 +30,7 @@ signals:
void folderCreated(const QString& folderId);
void folderUpdated(const QString& folderId);
void folderDeleted(const QString& folderId);
void allFoldersDeleted();
void loginClicked(const QString& domain, const QString& email, const QString& password);
void logoutClicked();
void loginStarted();

View File

@ -246,6 +246,16 @@ bool BaseModel::isValidFieldName(Table table, const QString &name) {
return false;
}
void BaseModel::deleteAll(Table table) {
QString tableName = BaseModel::tableName(table);
jop::db().execQuery("DELETE FROM " + tableName);
BaseModel::cache_.clear();
if (table == jop::FoldersTable) {
dispatcher().emitAllFoldersDeleted();
}
}
// When loading a QSqlQuery, all the values are cleared and replaced by those
// from the QSqlQuery. All the fields are marked as NOT changed as it's assumed
// the object is already in the database (since loaded from there).

View File

@ -57,6 +57,7 @@ public:
static bool hasField(jop::Table table, const QString& name);
static QStringList tableFieldNames(Table table);
static bool isValidFieldName(Table table, const QString& name);
static void deleteAll(Table table);
void loadSqlQuery(const QSqlQuery& query);
void loadJsonObject(const QJsonObject& jsonObject);

View File

@ -10,6 +10,7 @@ FolderModel::FolderModel(Database &database) : QAbstractListModel(), db_(databas
connect(&dispatcher(), SIGNAL(folderCreated(QString)), this, SLOT(dispatcher_folderCreated(QString)));
connect(&dispatcher(), SIGNAL(folderUpdated(QString)), this, SLOT(dispatcher_folderUpdated(QString)));
connect(&dispatcher(), SIGNAL(folderDeleted(QString)), this, SLOT(dispatcher_folderDeleted(QString)));
connect(&dispatcher(), SIGNAL(allFoldersDeleted()), this, SLOT(dispatcher_allFoldersDeleted()));
}
int FolderModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent);
@ -208,3 +209,10 @@ void FolderModel::dispatcher_folderDeleted(const QString &folderId) {
beginRemoveRows(QModelIndex(), index, index);
endRemoveRows();
}
void FolderModel::dispatcher_allFoldersDeleted() {
qDebug() << "FolderModel All folders deleted";
cache_.clear();
beginResetModel();
endResetModel();
}

View File

@ -57,6 +57,7 @@ public slots:
void dispatcher_folderCreated(const QString& folderId);
void dispatcher_folderUpdated(const QString& folderId);
void dispatcher_folderDeleted(const QString& folderId);
void dispatcher_allFoldersDeleted();
};

View File

@ -209,7 +209,13 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
qDebug() << "WebApi: done" << category << action << arg1 << arg2;
// TODO: check for error
QString error = "";
if (response.contains("error")) {
error = response.value("error").toString();
qCritical().noquote() << "Sync error:" << error;
// Each action might handle errors differently so let it proceed below
}
// =============================================================================================
// HANDLE UPLOAD RESPONSE
@ -218,22 +224,24 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
if (state_ == UploadingChanges) {
uploadsRemaining_--;
qDebug() << "Synced folder" << arg1;
if (error == "") {
qDebug() << "Synced folder" << arg1;
if (action == "putFolder") {
Change::disposeByItemId(arg1);
}
if (action == "putFolder") {
Change::disposeByItemId(arg1);
}
if (action == "patchFolder") {
Change::disposeByItemId(arg1);
}
if (action == "patchFolder") {
Change::disposeByItemId(arg1);
}
if (action == "deleteFolder") {
Change::disposeByItemId(arg1);
}
if (action == "deleteFolder") {
Change::disposeByItemId(arg1);
}
if (uploadsRemaining_ < 0) {
qWarning() << "Mismatch on operations done:" << uploadsRemaining_;
if (uploadsRemaining_ < 0) {
qWarning() << "Mismatch on operations done:" << uploadsRemaining_;
}
}
checkNextState();
@ -243,48 +251,51 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
// =============================================================================================
} else if (state_ == DownloadingChanges) {
if (action == "getSynchronizer") {
QJsonArray items = response["items"].toArray();
QString maxRevId = "";
foreach (QJsonValue it, items) {
QJsonObject obj = it.toObject();
QString itemId = obj["item_id"].toString();
QString itemType = obj["item_type"].toString();
QString operationType = obj["type"].toString();
QString revId = obj["id"].toString();
QJsonObject item = obj["item"].toObject();
if (error != "") {
checkNextState();
} else {
if (action == "getSynchronizer") {
QJsonArray items = response["items"].toArray();
QString maxRevId = "";
foreach (QJsonValue it, items) {
QJsonObject obj = it.toObject();
QString itemId = obj["item_id"].toString();
QString itemType = obj["item_type"].toString();
QString operationType = obj["type"].toString();
QString revId = obj["id"].toString();
QJsonObject item = obj["item"].toObject();
if (itemType == "folder") {
if (operationType == "create") {
Folder folder;
folder.loadJsonObject(item);
folder.save(false);
if (itemType == "folder") {
if (operationType == "create") {
Folder folder;
folder.loadJsonObject(item);
folder.save(false);
}
if (operationType == "update") {
Folder folder;
folder.load(itemId);
folder.patchJsonObject(item);
folder.save(false);
}
if (operationType == "delete") {
Folder folder;
folder.load(itemId);
folder.dispose();
}
}
if (operationType == "update") {
Folder folder;
folder.load(itemId);
folder.patchJsonObject(item);
folder.save(false);
}
if (operationType == "delete") {
Folder folder;
folder.load(itemId);
folder.dispose();
}
if (revId > maxRevId) maxRevId = revId;
}
if (revId > maxRevId) maxRevId = revId;
if (maxRevId != "") {
Settings settings;
settings.setValue("lastRevId", maxRevId);
}
checkNextState();
}
if (maxRevId != "") {
Settings settings;
settings.setValue("lastRevId", maxRevId);
}
checkNextState();
}
} else {
qCritical() << "Invalid category" << category;

View File

@ -140,8 +140,9 @@ void WebApi::request_finished(QNetworkReply *reply) {
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(responseBodyBA, &err);
if (err.error != QJsonParseError::NoError) {
qWarning() << "Could not parse JSON:" << err.errorString();
qWarning().noquote() << QString(responseBodyBA);
QString errorMessage = "Could not parse JSON: " + err.errorString() + "\n" + QString(responseBodyBA);
qWarning().noquote() << errorMessage;
response["error"] = errorMessage;
} else {
response = doc.object();
if (response.contains("error") && !response["error"].isNull()) {

Binary file not shown.

View File

@ -48,7 +48,7 @@ function saveCurlCmd($cmd) {
function execRequest($method, $path, $query = array(), $data = null) {
$url = config('baseUrl') . '/' . $path;
if (!empty($_SESSION['sessionId'])) {
if (!empty($_SESSION['sessionId']) && !isset($query['session'])) {
$query['session'] = $_SESSION['sessionId'];
}
if (count($query)) $url .= '?' . http_build_query($query);
@ -133,7 +133,8 @@ if (isset($_POST['delete_folder'])) $action = 'delete_folder';
if (isset($_POST['update_folder'])) $action = 'update_folder';
$pageParams = array(
'title' => ucfirst($action),
'pageTitle' => parse_url(config('baseUrl'), PHP_URL_HOST) . ' - ' . ucfirst($action),
'headerTitle' => ucfirst($action),
'contentHtml' => '',
'baseUrl' => config('baseUrl'),
);
@ -153,6 +154,17 @@ switch ($action) {
$pageParams['contentHtml'] = renderView('folder', array('folder' => $folder));
break;
case 'changes':
$session = execRequest('POST', 'sessions', null, array(
'email' => 'laurent@cozic.net',
'password' => '12345678',
'client_id' => 'ABCDABCDABCDABCDABCDABCDABCDABCD',
));
$changes = execRequest('GET', 'synchronizer', array('session' => $session['id']));
$pageParams['contentHtml'] = renderView('changes', array('changes' => $changes));
break;
case 'notes':
$notes = execRequest('GET', 'folders/' . $_GET['folder_id'] . '/notes');

18
debug_client/views/changes.php Executable file
View File

@ -0,0 +1,18 @@
<table>
<tr>
<th>ID</th>
<th>Type</th>
<th>Item type</th>
<th>Item ID</th>
<th>Item</th>
</tr>
<?php for ($i = count($changes['items']) - 1; $i >= 0; $i--): $it = $changes['items'][$i]; $t = $it['type']; ?>
<tr>
<td><?php echo htmlentities($it['id']); ?></td>
<td><?php echo htmlentities($it['type']); ?></td>
<td><?php echo htmlentities($it['item_type']); ?></td>
<td><?php echo htmlentities($it['item_id']); ?></td>
<td><?php echo htmlentities($t == 'update' ? json_encode($it['item']) : ''); ?></td>
</tr>
<?php endfor; ?>
</table>

View File

@ -1,12 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title><?php echo htmlentities($title); ?></title>
<title><?php echo htmlentities($pageTitle); ?></title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
</head>
<body>
<a href="/">Home</a>
<h1><?php echo htmlentities($title); ?></h1>
<a href="/?action=changes">Changes</a>
<h1><?php echo htmlentities($headerTitle); ?></h1>
<?php echo $contentHtml; ?>
<hr/>
<div class="debug">