From 3fa0ac2a81a5f7590bb0be99128cbdb61619ff56 Mon Sep 17 00:00:00 2001 From: Robbie Antenesse Date: Wed, 22 May 2019 14:21:42 -0600 Subject: [PATCH] Sync words on load --- src/js/account/sync.js | 73 ++++++++++++++++++++++++++++++++------ src/php/api/Dictionary.php | 9 ++--- src/php/api/User.php | 5 ++- src/php/api/index.php | 10 ++++-- 4 files changed, 80 insertions(+), 17 deletions(-) diff --git a/src/js/account/sync.js b/src/js/account/sync.js index dac33fc..c682e86 100644 --- a/src/js/account/sync.js +++ b/src/js/account/sync.js @@ -1,6 +1,7 @@ import { addMessage } from "../utilities"; -import { saveDictionary } from "../dictionaryManagement"; +import { saveDictionary, clearDictionary } from "../dictionaryManagement"; import { request, saveToken } from "./helpers"; +import { renderAll } from "../render"; /* Outline for syncing login @@ -8,12 +9,12 @@ login (DONE!) ? no id -> upload dictionary -> make new dictionary current - ? mismatched id + (Canceled) ? mismatched id -> sync local dictionary (see 'same id' below) -> if no matching remote id, ignore (assume deleted) -> clear local dictionary -> insert downloaded dictionary - ? same id + (DONE!) ? same id -> compare detail last updated timestamp ? downloaded details are newer -> replace local details @@ -37,15 +38,27 @@ export function syncDictionary() { request({ action: 'get-current-dictionary', }, remote => { - console.log(remote); + // console.log(remote); + if (remote.details.externalId !== window.currentDictionary.externalId) { + clearDictionary(); + } const detailsSynced = syncDetails(remote.details); if (detailsSynced === false) { addMessage('Could not sync'); } else { detailsSynced.then(success => { + renderAll(); if (success) { - console.log('Do a word comparison!'); + syncWords(remote.words, remote.deletedWords).then(success => { + if (success) { + renderAll(); + } else { + console.error('word sync failed'); + } + }); + } else { + console.error('details sync failed'); } }); } @@ -91,7 +104,17 @@ export function uploadWholeDictionary(asNew = false) { } export function syncDetails(remoteDetails = false) { - if (remoteDetails === false || remoteDetails.lastUpdated < window.currentDictionary.lastUpdated) { + let direction; // This is if/else if tree the only way I can think to correctly prioritize this when to upload vs download. + if (remoteDetails === false) { + direction = 'up'; + } else if (!window.currentDictionary.hasOwnProperty('externalId')) { // If mismatched id, dictionary will be cleared, allowing it to be overwritten + direction = 'down'; + } else if (remoteDetails.lastUpdated < window.currentDictionary.lastUpdated) { + direction = 'up'; + } else if (remoteDetails.lastUpdated > window.currentDictionary.lastUpdated) { + direction = 'down'; + } + if (direction === 'up') { const details = Object.assign({}, window.currentDictionary); delete details.words; return request({ @@ -105,12 +128,12 @@ export function syncDetails(remoteDetails = false) { addMessage('Could not sync dictionary'); return false; }); - } else if (remoteDetails.lastUpdated > window.currentDictionary.lastUpdated) { + } else if (direction === 'down') { window.currentDictionary = Object.assign(window.currentDictionary, remoteDetails); saveDictionary(); } addMessage('Dictionary details synchronized'); - return Promise.resolve(); + return Promise.resolve(true); } export function syncWords(remoteWords, deletedWords) { @@ -121,14 +144,44 @@ export function syncWords(remoteWords, deletedWords) { } return true; }); - const newLocalWords = words.filter(word => { + const localWordsToUpload = words.filter(word => { + // Find words that don't exist in remote words after clearing deleted words const remote = remoteWords.find(remoteWord => remoteWord.id === word.wordId); return typeof remote === 'undefined'; }); + remoteWords.forEach(remoteWord => { const localWord = words.find(word => word.wordId === remoteWord.wordId); if (localWord) { - + if (localWord.lastUpdated < remoteWord.lastUpdated) { + localWord = remoteWord; + } else if (localWord.lastUpdated > remoteWord.lastUpdated) { + // Add more-recently-updated words to upload + localWordsToUpload.push(localWord); + } + } else { + // If word not found, add it to words + words.push(remoteWord); } }); + + window.currentDictionary.words = words; + saveDictionary(); + + if (localWordsToUpload.length > 0) { + return request({ + action: 'set-dictionary-words', + words, + }, successful => { + addMessage('Saved Words to Server'); + return successful; + }, error => { + console.error(error); + addMessage('Could not sync words'); + return false; + }); + } + + addMessage('Words synchronized'); + return Promise.resolve(true); } \ No newline at end of file diff --git a/src/php/api/Dictionary.php b/src/php/api/Dictionary.php index 0f73d63..dcfb7af 100644 --- a/src/php/api/Dictionary.php +++ b/src/php/api/Dictionary.php @@ -197,7 +197,6 @@ WHERE dictionary=$dictionary"; if ($results) { return array_map(function ($row) { return array( - 'id' => intval($row['word_id']), 'name' => $row['name'], 'pronunciation' => $row['pronunciation'], 'partOfSpeech' => $row['part_of_speech'], @@ -205,6 +204,7 @@ WHERE dictionary=$dictionary"; 'details' => $row['details'], 'lastUpdated' => is_null($row['last_updated']) ? null : intval($row['last_updated']), 'createdOn' => intval($row['created_on']), + 'wordId' => intval($row['word_id']), ); }, $results); } @@ -239,10 +239,10 @@ WHERE dictionary=$dictionary"; if ($most_recent_word_update < $last_updated) { $most_recent_word_update = $last_updated; } - $word_ids[] = $word['id']; + $word_ids[] = $word['wordId']; $query .= "(?, ?, ?, ?, ?, ?, ?, ?, ?), "; $params[] = $dictionary; - $params[] = $word['id']; + $params[] = $word['wordId']; $params[] = $word['name']; $params[] = $word['pronunciation']; $params[] = $word['partOfSpeech']; @@ -257,7 +257,8 @@ pronunciation=VALUES(pronunciation), part_of_speech=VALUES(part_of_speech), definition=VALUES(definition), details=VALUES(details), -last_updated=VALUES(last_updated)'; +last_updated=VALUES(last_updated), +created_on=VALUES(created_on)'; $results = $this->db->execute($query, $params); diff --git a/src/php/api/User.php b/src/php/api/User.php index 617c7dc..eb99e88 100644 --- a/src/php/api/User.php +++ b/src/php/api/User.php @@ -212,9 +212,12 @@ VALUES (?, ?, ?, ?, ?)'; $dictionary = $user_data->dictionary; $user = $user_data->id; $updated_words = $this->dictionary->setWords($user, $dictionary, $words); - if ($updated_words) { + if ($updated_words === true) { return true; } + return array( + 'error' => $updated_words, + ); } return false; } diff --git a/src/php/api/index.php b/src/php/api/index.php index e0ed336..09a812f 100644 --- a/src/php/api/index.php +++ b/src/php/api/index.php @@ -249,12 +249,18 @@ switch ($action) { if ($token !== false && isset($request['words'])) { $user = new User(); $update_words_success = $user->updateOrAddWordsToCurrentDictionary($token, $request['words']); - if ($update_words_success !== false) { + if ($update_words_success === true) { return Response::json(array( - 'data' => 'Updated successfully', + 'data' => $update_words_success, 'error' => false, ), 200); } + if (isset($update_words_success['error'])) { + return Response::json(array( + 'data' => $update_words_success['error'], + 'error' => true, + ), 500); + } return Response::json(array( 'data' => 'Could not set words: invalid token', 'error' => true,