Merge branch 'master' into stable

This commit is contained in:
azivner 2017-11-29 20:30:56 -05:00
commit d019d0a690
18 changed files with 210 additions and 217 deletions

27
app.js
View File

@ -9,6 +9,7 @@ const session = require('express-session');
const FileStore = require('session-file-store')(session);
const os = require('os');
const sessionSecret = require('./services/session_secret');
const utils = require('./services/utils');
require('./services/ping_job');
@ -71,4 +72,30 @@ require('./services/sync');
// triggers backup timer
require('./services/backup');
if (utils.isElectron()) {
const ipcMain = require('electron').ipcMain;
ipcMain.on('server-request', (event, arg) => {
const req = {};
req.url = arg.url;
req.method = arg.method;
req.body = arg.data;
req.headers = {};
const res = {};
res.setHeader = function() {
};
res.send = function(obj) {
event.sender.send('server-response', {
requestId: arg.requestId,
body: obj
});
};
return app._router.handle(req, res, () => {});
});
}
module.exports = app;

View File

@ -30,16 +30,9 @@ const editTreePrefix = (function() {
formEl.submit(() => {
const prefix = treePrefixInputEl.val();
$.ajax({
url: baseApiUrl + 'tree/' + noteTreeId + '/setPrefix',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({
prefix: prefix
}),
success: () => noteTree.setPrefix(noteTreeId, prefix),
error: () => showError("Error setting prefix.")
});
server.put('tree/' + noteTreeId + '/setPrefix', {
prefix: prefix
}).then(() => noteTree.setPrefix(noteTreeId, prefix));
dialogEl.dialog("close");

View File

@ -13,11 +13,7 @@ const eventLog = (function() {
height: 700
});
const result = await $.ajax({
url: baseApiUrl + 'event-log',
type: 'GET',
error: () => showError("Error getting event log.")
});
const result = await server.get('event-log');
listEl.html('');

View File

@ -24,11 +24,7 @@ const noteHistory = (function() {
listEl.empty();
contentEl.empty();
historyItems = await $.ajax({
url: baseApiUrl + 'notes-history/' + noteId,
type: 'GET',
error: () => showError("Error getting note history.")
});
historyItems = await server.get('notes-history/' + noteId);
for (const item of historyItems) {
const dateModified = getDateFromTS(item.date_modified_to);

View File

@ -12,11 +12,7 @@ const recentChanges = (function() {
height: 700
});
const result = await $.ajax({
url: baseApiUrl + 'recent-changes/',
type: 'GET',
error: () => showError("Error getting recent changes.")
});
const result = await server.get('recent-changes/');
dialogEl.html('');

View File

@ -10,38 +10,26 @@ const recentNotes = (function() {
const noteDetailEl = $('#note-detail');
let list = [];
$.ajax({
url: baseApiUrl + 'recent-notes',
type: 'GET',
error: () => showError("Error getting recent notes.")
}).then(result => {
server.get('recent-notes').then(result => {
list = result.map(r => r.note_tree_id);
});
function addRecentNote(notePath) {
setTimeout(() => {
setTimeout(async () => {
// we include the note into recent list only if the user stayed on the note at least 5 seconds
if (notePath && notePath === noteTree.getCurrentNotePath()) {
$.ajax({
url: baseApiUrl + 'recent-notes/' + encodeURIComponent(notePath),
type: 'PUT',
error: () => showError("Error setting recent notes.")
}).then(result => {
list = result.map(r => r.note_path);
});
const result = await server.put('recent-notes/' + encodeURIComponent(notePath));
list = result.map(r => r.note_path);
}
}, 1500);
}
// FIXME: this should be probably just refresh upon deletion, not explicit delete
function removeRecentNote(notePathIdToRemove) {
$.ajax({
url: baseApiUrl + 'recent-notes/' + encodeURIComponent(notePathIdToRemove),
type: 'DELETE',
error: () => showError("Error removing note from recent notes.")
}).then(result => {
list = result.map(r => r.note_path);
});
async function removeRecentNote(notePathIdToRemove) {
const result = server.remove('recent-notes/' + encodeURIComponent(notePathIdToRemove));
list = result.map(r => r.note_path);
}
function showDialog() {

View File

@ -13,11 +13,7 @@ const settings = (function() {
async function showDialog() {
glob.activeDialog = dialogEl;
const settings = await $.ajax({
url: baseApiUrl + 'settings',
type: 'GET',
error: () => showError("Error getting settings.")
});
const settings = await server.get('settings');
dialogEl.dialog({
modal: true,
@ -33,20 +29,13 @@ const settings = (function() {
}
}
function saveSettings(settingName, settingValue) {
return $.ajax({
url: baseApiUrl + 'settings',
type: 'POST',
data: JSON.stringify({
name: settingName,
value: settingValue
}),
contentType: "application/json",
success: () => {
showMessage("Settings change have been saved.");
},
error: () => alert("Error occurred during saving settings change.")
async function saveSettings(settingName, settingValue) {
await server.post('settings', {
name: settingName,
value: settingValue
});
showMessage("Settings change have been saved.");
}
return {
@ -79,26 +68,19 @@ settings.addModule((function() {
return false;
}
$.ajax({
url: baseApiUrl + 'password/change',
type: 'POST',
data: JSON.stringify({
'current_password': oldPassword,
'new_password': newPassword1
}),
contentType: "application/json",
success: result => {
if (result.success) {
alert("Password has been changed. Trilium will be reloaded after you press OK.");
server.post('password/change', {
'current_password': oldPassword,
'new_password': newPassword1
}).then(result => {
if (result.success) {
alert("Password has been changed. Trilium will be reloaded after you press OK.");
// password changed so current protected session is invalid and needs to be cleared
protected_session.resetProtectedSession();
}
else {
showError(result.message);
}
},
error: () => showError("Error occurred during changing password.")
// password changed so current protected session is invalid and needs to be cleared
protected_session.resetProtectedSession();
}
else {
showError(result.message);
}
});
return false;
@ -159,7 +141,7 @@ settings.addModule((async function () {
const buildDateEl = $("#build-date");
const buildRevisionEl = $("#build-revision");
const appInfo = await $.get(baseApiUrl + 'app-info');
const appInfo = await server.get('app-info');
appVersionEl.html(appInfo.app_version);
dbVersionEl.html(appInfo.db_version);

View File

@ -129,14 +129,4 @@ function showAppIfHidden() {
// Kick off the CSS transition
loaderDiv.style.opacity = 0.0;
}
}
function initAjax() {
$.ajaxSetup({
headers: {
'x-protected-session-id': typeof protected_session !== 'undefined' ? protected_session.getProtectedSessionId() : null
}
});
}
initAjax();
}

View File

@ -17,29 +17,28 @@ $(document).ready(() => {
});
});
$("#run-migration").click(() => {
$("#run-migration").click(async () => {
$("#run-migration").prop("disabled", true);
$("#migration-result").show();
$.ajax({
const result = await $.ajax({
url: baseApiUrl + 'migration',
type: 'POST',
success: result => {
for (const migration of result.migrations) {
const row = $('<tr>')
.append($('<td>').html(migration.db_version))
.append($('<td>').html(migration.name))
.append($('<td>').html(migration.success ? 'Yes' : 'No'))
.append($('<td>').html(migration.success ? 'N/A' : migration.error));
if (!migration.success) {
row.addClass("danger");
}
$("#migration-table").append(row);
}
},
error: () => showError("Migration failed with unknown error")
});
for (const migration of result.migrations) {
const row = $('<tr>')
.append($('<td>').html(migration.db_version))
.append($('<td>').html(migration.name))
.append($('<td>').html(migration.success ? 'Yes' : 'No'))
.append($('<td>').html(migration.success ? 'N/A' : migration.error));
if (!migration.success) {
row.addClass("danger");
}
$("#migration-table").append(row);
}
});

View File

@ -93,15 +93,7 @@ const noteEditor = (function() {
}
async function saveNoteToServer(note) {
await $.ajax({
url: baseApiUrl + 'notes/' + note.detail.note_id,
type: 'PUT',
data: JSON.stringify(note),
contentType: "application/json",
error: () => {
showError("Error saving the note!");
}
});
await server.put('notes/' + note.detail.note_id, note);
isNoteChanged = false;
@ -130,7 +122,7 @@ const noteEditor = (function() {
}
async function loadNoteToEditor(noteId) {
currentNote = await $.get(baseApiUrl + 'notes/' + noteId);
currentNote = await server.get('notes/' + noteId);
if (isNewNoteCreated) {
isNewNoteCreated = false;
@ -167,7 +159,7 @@ const noteEditor = (function() {
}
async function loadNote(noteId) {
return await $.get(baseApiUrl + 'notes/' + noteId);
return await server.get('notes/' + noteId);
}
$(document).ready(() => {

View File

@ -307,15 +307,10 @@ const noteTree = (function() {
return path.reverse().join('/');
}
function setExpandedToServer(noteTreeId, isExpanded) {
async function setExpandedToServer(noteTreeId, isExpanded) {
const expandedNum = isExpanded ? 1 : 0;
$.ajax({
url: baseApiUrl + 'notes/' + noteTreeId + '/expanded/' + expandedNum,
type: 'PUT',
contentType: "application/json",
success: result => {}
});
await server.put('notes/' + noteTreeId + '/expanded/' + expandedNum);
}
function setCurrentNotePathToHash(node) {
@ -479,7 +474,7 @@ const noteTree = (function() {
}
function loadTree() {
return $.get(baseApiUrl + 'tree').then(resp => {
return server.get('tree').then(resp => {
startNoteTreeId = resp.start_note_tree_id;
treeLoadTime = resp.tree_load_time;
@ -574,16 +569,11 @@ const noteTree = (function() {
const newNoteName = "new note";
const result = await $.ajax({
url: baseApiUrl + 'notes/' + parentNoteId + '/children' ,
type: 'POST',
data: JSON.stringify({
note_title: newNoteName,
target: target,
target_note_tree_id: node.data.note_tree_id,
is_protected: isProtected
}),
contentType: "application/json"
const result = await server.post('notes/' + parentNoteId + '/children', {
note_title: newNoteName,
target: target,
target_note_tree_id: node.data.note_tree_id,
is_protected: isProtected
});
const newNode = {

View File

@ -10,11 +10,7 @@ const protected_session = (function() {
let protectedSessionTimeout = null;
let protectedSessionId = null;
$.ajax({
url: baseApiUrl + 'settings/all',
type: 'GET',
error: () => showError("Error getting protected session settings.")
}).then(settings => {
server.get('settings/all').then(settings => {
protectedSessionTimeout = settings.protected_session_timeout;
});
@ -61,7 +57,7 @@ const protected_session = (function() {
}
protectedSessionId = response.protectedSessionId;
initAjax();
server.initAjax();
dialogEl.dialog("close");
@ -88,14 +84,8 @@ const protected_session = (function() {
}
async function enterProtectedSession(password) {
return await $.ajax({
url: baseApiUrl + 'login/protected',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
password: password
}),
error: () => showError("Error entering protected session.")
return await server.post('login/protected', {
password: password
});
}
@ -106,7 +96,7 @@ const protected_session = (function() {
function resetProtectedSession() {
protectedSessionId = null;
initAjax();
server.initAjax();
// most secure solution - guarantees nothing remained in memory
// since this expires because user doesn't use the app, it shouldn't be disruptive
@ -154,12 +144,7 @@ const protected_session = (function() {
async function protectSubTree(noteId, protect) {
await ensureProtectedSession(true, true);
await $.ajax({
url: baseApiUrl + 'tree/' + noteId + "/protectSubTree/" + (protect ? 1 : 0),
type: 'PUT',
contentType: 'application/json',
error: () => showError("Request to un/protect sub tree has failed.")
});
await server.put('tree/' + noteId + "/protectSubTree/" + (protect ? 1 : 0));
showMessage("Request to un/protect sub tree has finished successfully");

View File

@ -43,7 +43,7 @@ const searchTree = (function() {
}
if (e && e.which === $.ui.keyCode.ENTER) {
$.get(baseApiUrl + 'notes?search=' + searchText).then(resp => {
server.get('notes?search=' + searchText).then(resp => {
// Pass a string to perform case insensitive matching
getTree().filterBranches(node => {
return resp.includes(node.data.note_id);

View File

@ -0,0 +1,84 @@
const server = (function() {
function initAjax() {
$.ajaxSetup({
headers: {
'x-protected-session-id': typeof protected_session !== 'undefined' ? protected_session.getProtectedSessionId() : null
}
});
}
async function get(url) {
return await call('GET', url);
}
async function post(url, data) {
return await call('POST', url, data);
}
async function put(url, data) {
return await call('PUT', url, data);
}
async function remove(url) {
return await call('DELETE', url);
}
let i = 1;
const reqResolves = {};
async function call(method, url, data) {
if (isElectron()) {
const ipc = require('electron').ipcRenderer;
const requestId = i++;
return new Promise((resolve, reject) => {
reqResolves[requestId] = resolve;
ipc.send('server-request', {
requestId: requestId,
method: method,
url: "/" + baseApiUrl + url,
data: data
});
});
}
else {
return await ajax(url, method, data);
}
}
if (isElectron()) {
const ipc = require('electron').ipcRenderer;
ipc.on('server-response', (event, arg) => {
reqResolves[arg.requestId](arg.body);
});
}
async function ajax(url, method, data) {
const options = {
url: baseApiUrl + url,
type: method
};
if (data) {
options.data = JSON.stringify(data);
options.contentType = "application/json";
}
return await $.ajax(options).catch(e => {
showError("Error when calling " + method + " " + url + ": " + e);
});
}
initAjax();
return {
get,
post,
put,
remove,
initAjax
}
})();

View File

@ -1,21 +1,16 @@
"use strict";
function syncNow() {
$.ajax({
url: baseApiUrl + 'sync/now',
type: 'POST',
success: result => {
if (result.success) {
showMessage("Sync finished successfully.");
}
else {
if (result.message.length > 50) {
result.message = result.message.substr(0, 50);
}
async function syncNow() {
const result = await server.post('sync/now');
showError("Sync failed: " + result.message);
}
},
error: () => showError("Sync failed for unknown reason.")
});
if (result.success) {
showMessage("Sync finished successfully.");
}
else {
if (result.message.length > 50) {
result.message = result.message.substr(0, 50);
}
showError("Sync failed: " + result.message);
}
}

View File

@ -2,11 +2,7 @@
const treeChanges = (function() {
async function moveBeforeNode(node, beforeNode, changeInPath = true) {
await $.ajax({
url: baseApiUrl + 'notes/' + node.data.note_tree_id + '/moveBefore/' + beforeNode.data.note_tree_id,
type: 'PUT',
contentType: "application/json"
});
await server.put('notes/' + node.data.note_tree_id + '/moveBefore/' + beforeNode.data.note_tree_id);
node.moveTo(beforeNode, 'before');
@ -18,11 +14,7 @@ const treeChanges = (function() {
}
async function moveAfterNode(node, afterNode, changeInPath = true) {
await $.ajax({
url: baseApiUrl + 'notes/' + node.data.note_tree_id + '/moveAfter/' + afterNode.data.note_tree_id,
type: 'PUT',
contentType: "application/json"
});
await server.put('notes/' + node.data.note_tree_id + '/moveAfter/' + afterNode.data.note_tree_id);
node.moveTo(afterNode, 'after');
@ -35,11 +27,7 @@ const treeChanges = (function() {
// beware that first arg is noteId and second is noteTreeId!
async function cloneNoteAfter(noteId, afterNoteTreeId) {
const resp = await $.ajax({
url: baseApiUrl + 'notes/' + noteId + '/cloneAfter/' + afterNoteTreeId,
type: 'PUT',
error: () => showError("Error cloning note.")
});
const resp = await server.put('notes/' + noteId + '/cloneAfter/' + afterNoteTreeId);
if (!resp.success) {
alert(resp.message);
@ -50,11 +38,7 @@ const treeChanges = (function() {
}
async function moveToNode(node, toNode) {
await $.ajax({
url: baseApiUrl + 'notes/' + node.data.note_tree_id + '/moveTo/' + toNode.data.note_id,
type: 'PUT',
contentType: "application/json"
});
await server.put('notes/' + node.data.note_tree_id + '/moveTo/' + toNode.data.note_id);
node.moveTo(toNode);
@ -69,11 +53,7 @@ const treeChanges = (function() {
}
async function cloneNoteTo(childNoteId, parentNoteId) {
const resp = await $.ajax({
url: baseApiUrl + 'notes/' + childNoteId + '/cloneTo/' + parentNoteId,
type: 'PUT',
error: () => showError("Error cloning note.")
});
const resp = await server.put('notes/' + childNoteId + '/cloneTo/' + parentNoteId);
if (!resp.success) {
alert(resp.message);
@ -88,10 +68,7 @@ const treeChanges = (function() {
return;
}
await $.ajax({
url: baseApiUrl + 'notes/' + node.data.note_tree_id,
type: 'DELETE'
});
await server.remove('notes/' + node.data.note_tree_id);
if (node.getParent() !== null && node.getParent().getChildren().length <= 1) {
node.getParent().folder = false;
@ -118,11 +95,7 @@ const treeChanges = (function() {
return;
}
await $.ajax({
url: baseApiUrl + 'notes/' + node.data.note_tree_id + '/moveAfter/' + node.getParent().data.note_tree_id,
type: 'PUT',
contentType: "application/json",
});
await server.put('notes/' + node.data.note_tree_id + '/moveAfter/' + node.getParent().data.note_tree_id);
if (node.getParent() !== null && node.getParent().getChildren().length <= 1) {
node.getParent().folder = false;

View File

@ -105,6 +105,12 @@ async function getLastSyncedPull() {
return parseInt(await options.getOption('last_synced_pull'));
}
async function setLastSyncedPull(syncId) {
await sql.doInTransaction(async () => {
await options.setOption('last_synced_pull', syncId);
});
}
async function pullSync(syncContext) {
const lastSyncedPull = await getLastSyncedPull();
@ -118,6 +124,8 @@ async function pullSync(syncContext) {
if (source_id.isLocalSourceId(sync.source_id)) {
log.info("Skipping " + sync.entity_name + " " + sync.entity_id + " because it has local source id.");
await setLastSyncedPull(sync.id);
continue;
}
@ -149,9 +157,7 @@ async function pullSync(syncContext) {
throw new Error("Unrecognized entity type " + sync.entity_name);
}
await sql.doInTransaction(async () => {
await options.setOption('last_synced_pull', sync.id);
});
await setLastSyncedPull(sync.id);
}
log.info("Finished pull");

View File

@ -302,6 +302,7 @@
<link href="stylesheets/style.css" rel="stylesheet">
<script src="javascripts/init.js"></script>
<script src="javascripts/server.js"></script>
<!-- Tree scripts -->
<script src="javascripts/note_tree.js"></script>