diff --git a/QtClient/JoplinQtClient/schema.sql b/QtClient/JoplinQtClient/schema.sql index 27a878bc6..aa660b99e 100755 --- a/QtClient/JoplinQtClient/schema.sql +++ b/QtClient/JoplinQtClient/schema.sql @@ -2,8 +2,7 @@ CREATE TABLE folders ( id TEXT PRIMARY KEY, title TEXT, created_time INT, - updated_time INT, - synced BOOLEAN DEFAULT 0 + updated_time INT ); CREATE TABLE notes ( @@ -24,23 +23,20 @@ CREATE TABLE notes ( todo_completed INT, source_application TEXT, application_data TEXT, - `order` INT, - synced BOOLEAN DEFAULT 0 + `order` INT ); CREATE TABLE tags ( id TEXT PRIMARY KEY, title TEXT, created_time INT, - updated_time INT, - synced BOOLEAN DEFAULT 0 + updated_time INT ); CREATE TABLE note_tags ( id INTEGER PRIMARY KEY, note_id TEXT, - tag_id TEXT, - synced BOOLEAN DEFAULT 0 + tag_id TEXT ); CREATE TABLE resources ( @@ -49,15 +45,13 @@ CREATE TABLE resources ( mime TEXT, filename TEXT, created_time INT, - updated_time INT, - synced BOOLEAN DEFAULT 0 + updated_time INT ); CREATE TABLE note_resources ( id INTEGER PRIMARY KEY, note_id TEXT, - resource_id TEXT, - synced BOOLEAN DEFAULT 0 + resource_id TEXT ); CREATE TABLE version ( diff --git a/debug_client/css/style.css b/debug_client/css/style.css new file mode 100755 index 000000000..1b94a7d39 --- /dev/null +++ b/debug_client/css/style.css @@ -0,0 +1,75 @@ +/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ +html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} +body{margin:0} +article,aside,footer,header,nav,section{display:block} +h1{font-size:2em;margin:.67em 0} +figcaption,figure,main{display:block} +figure{margin:1em 40px} +hr{box-sizing:content-box;height:0;overflow:visible} +pre{font-family:monospace,monospace;font-size:1em} +a{background-color:transparent;-webkit-text-decoration-skip:objects} +a:active,a:hover{outline-width:0} +abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} +b,strong{font-weight:inherit;font-weight:bolder} +code,kbd,samp{font-family:monospace,monospace;font-size:1em} +dfn{font-style:italic} +mark{background-color:#ff0;color:#000} +small{font-size:80%} +sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} +sub{bottom:-.25em} +sup{top:-.5em} +audio,video{display:inline-block} +audio:not([controls]){display:none;height:0} +img{border-style:none} +svg:not(:root){overflow:hidden} +button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0} +button,input{overflow:visible} +button,select{text-transform:none} +button,html [type="button"],/* 1 */ +[type="reset"],[type="submit"]{-webkit-appearance:button} +button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0} +button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText} +fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} +legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal} +progress{display:inline-block;vertical-align:baseline} +textarea{overflow:auto} +[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0} +[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto} +[type="search"]{-webkit-appearance:textfield;outline-offset:-2px} +[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none} +::-webkit-file-upload-button{-webkit-appearance:button;font:inherit} +details,/* 1 */ +menu{display:block} +summary{display:list-item} +canvas{display:inline-block} +template{display:none} +[hidden]{display:none} +/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ + +body { + padding: 1em; +} + +table { + border-spacing: 0; + border-collapse: collapse; +} + +td { + border: 1px #ccc solid; + padding: .3em; +} + +.form-group { + margin-bottom: 0.5em; +} + +.form-group label { + width: 200px; + display: inline-block; +} + +.form-group input { + width: 300px; + display: inline-block; +} diff --git a/debug_client/index.php b/debug_client/index.php new file mode 100755 index 000000000..fe577f0e9 --- /dev/null +++ b/debug_client/index.php @@ -0,0 +1,190 @@ + 'http://joplin.local', + 'clientId' => 'E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3', + ); + if (isset($config[$name])) return $config[$name]; + throw new Exception('Unknown config: ' . $name); +} + +function curlCmd($method, $url, $data) { + $cmd = array(); + $cmd[] = 'curl'; + if ($method != 'GET' && $method != 'POST') { + $cmd[] = '-X ' . $method; + } + if ($method != 'GET' && $method != 'DELETE') { + $cmd[] = "--data '" . http_build_query($data) . "'"; + } + $cmd[] = "'" . $url . "'"; + + return implode(' ', $cmd); +} + +function saveCurlCmd($cmd) { + $cmds = array(); + if (isset($_SESSION['curlCommands'])) $cmds = $_SESSION['curlCommands']; + $cmds[] = $cmd; + while (count($cmds) > 100) { + array_splice($cmds, 0, 1); + } + $_SESSION['curlCommands'] = $cmds; +} + +function execRequest($method, $path, $query = array(), $data = null) { + $url = config('baseUrl') . '/' . $path; + if (!empty($_SESSION['sessionId'])) { + $query['session'] = $_SESSION['sessionId']; + } + if (count($query)) $url .= '?' . http_build_query($query); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + if ($method != 'GET' && $method != 'POST') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + } + $response = curl_exec($ch); + curl_close($ch); + + $curlCmd = curlCmd($method, $url, $data); + saveCurlCmd($curlCmd); + + $output = json_decode($response, true); + if ($output === null) { + $msg = 'Cannot decode JSON: ' . $response . "\n\n" . $curlCmd; + die($msg); + } + + return $output; +} + +function renderView($name, $parameters = array()) { + $path = dirname(__FILE__) . '/views/' . $name . '.php'; + if (!file_exists($path)) throw new Exception('View not found: ' . $path); + + extract($parameters); + ob_start(); + include $path; + $content = ob_get_contents(); + ob_end_clean(); + return $content; +} + +function differentProperties($old, $new, $oldPrefix = '') { + $output = array(); + foreach ($old as $k1 => $v1) { + foreach ($new as $k2 => $v2) { + if ($k1 === $k2 && (string)$v1 !== (string)$v2) { + $output[$k1] = $v2; + } + } + } + return $output; +} + +function removePrefix($array, $prefix) { + $output = array(); + foreach ($array as $k => $v) { + if (strpos($k, $prefix) === 0) { + $k = substr($k, strlen($prefix)); + } + $output[$k] = $v; + } + return $output; +} + +function redirect($path) { + header('Location: ' . $path); + die(); +} + +initialize(); + +$session = execRequest('POST', 'sessions', null, array( + 'email' => 'laurent@cozic.net', + 'password' => '12345678', + 'client_id' => config('clientId'), +)); + +$_SESSION['sessionId'] = $session['id']; + +$action = isset($_GET['action']) ? $_GET['action'] : 'folders'; + +if (isset($_POST['create_folder'])) $action = 'create_folder'; +if (isset($_POST['delete_folder'])) $action = 'delete_folder'; +if (isset($_POST['update_folder'])) $action = 'update_folder'; + +$pageParams = array( + 'title' => ucfirst($action), + 'contentHtml' => '', +); + +switch ($action) { + + case 'folders': + + $folders = execRequest('GET', 'folders'); + $pageParams['contentHtml'] = renderView('folders', array('folders' => $folders)); + break; + + case 'folder': + + $folder = execRequest('GET', 'folders/' . $_GET['folder_id']); + $pageParams['contentHtml'] = renderView('folder', array('folder' => $folder)); + break; + + case 'notes': + + $notes = execRequest('GET', 'folders/' . $_GET['folder_id'] . '/notes'); + $pageParams['contentHtml'] = renderView('notes', array('notes' => $notes)); + break; + + case 'create_folder': + + $data = array('title' => $_POST['folder_title']); + $folder = execRequest('POST', 'folders', null, $data); + redirect('/'); + break; + + case 'delete_folder': + + $folder = execRequest('DELETE', 'folders/' . $_POST['folder_id']); + redirect('/'); + break; + + case 'update_folder': + + $oldFolder = json_decode($_POST['original_folder'], true); + $newFolder = removePrefix($_POST, 'folder_'); + $diff = differentProperties($oldFolder, $newFolder); + if (count($diff)) { + execRequest('PATCH', 'folders/' . $_POST['folder_id'], null, $diff); + } + redirect('/'); + break; + +} + +echo renderView('page', $pageParams); + +echo '
';
+$curlCommands = isset($_SESSION['curlCommands']) ? $_SESSION['curlCommands'] : array();
+for ($i = count($curlCommands) - 1; $i >= 0; $i--) {
+	$cmd = $curlCommands[$i];
+	echo $cmd . "\n";
+}
+echo '
'; \ No newline at end of file diff --git a/debug_client/views/folder.php b/debug_client/views/folder.php new file mode 100755 index 000000000..973f6e003 --- /dev/null +++ b/debug_client/views/folder.php @@ -0,0 +1,10 @@ +
+ $v): ?> +
+ + +
+ + + +
\ No newline at end of file diff --git a/debug_client/views/folders.php b/debug_client/views/folders.php new file mode 100755 index 000000000..796fe1362 --- /dev/null +++ b/debug_client/views/folders.php @@ -0,0 +1,29 @@ + + + + + + + + + +
Title
+ + + View notes + +
+ + +
+
+ +
+ +
+
+ + +
+ +
\ No newline at end of file diff --git a/debug_client/views/notes.php b/debug_client/views/notes.php new file mode 100755 index 000000000..157859458 --- /dev/null +++ b/debug_client/views/notes.php @@ -0,0 +1,6 @@ + + + + + +
Title
\ No newline at end of file diff --git a/debug_client/views/page.php b/debug_client/views/page.php new file mode 100755 index 000000000..d83ba6817 --- /dev/null +++ b/debug_client/views/page.php @@ -0,0 +1,12 @@ + + + +<?php echo htmlentities($title); ?> + + + + Home +

+ + + \ No newline at end of file