Skip to content

Commit 75f8944

Browse files
committed
use api for saving & tidy
1 parent 840d3d4 commit 75f8944

File tree

4 files changed

+92
-45
lines changed

4 files changed

+92
-45
lines changed

src/note_mark/static/script.js

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,20 +107,56 @@ function do_note_autosave(api_url) {
107107
})
108108
.then(response => {
109109
if (response.ok) {
110-
return response.text();
110+
return response.json();
111111
}
112112
throw new Error("auto-save error!");
113113
})
114-
.then(updated_at => {
115-
document.getElementById("edit-note-updated_at").value = updated_at;
116-
add_flash("note has been auto-saved");
114+
.then(json_data => {
115+
if (json_data.conflict === true) {
116+
add_flash("note could not be auto-saved as conflict was detected", "error");
117+
}
118+
else {
119+
document.getElementById("edit-note-updated_at").value = json_data.updated_at;
120+
add_flash("note has been auto-saved");
121+
}
117122
})
118123
.catch((error) => {
119124
console.error(error);
120125
add_flash("note could not be auto-saved", "error");
121126
});
122127
}
123128

129+
function do_note_save(api_url) {
130+
if (typeof auto_save_timeout === "number") {
131+
// clear the auto-save timeout
132+
window.clearTimeout(auto_save_timeout);
133+
}
134+
const form_data = new FormData(document.getElementById("form-edit-note"));
135+
fetch(api_url, {
136+
body: form_data,
137+
method: "patch"
138+
})
139+
.then(response => {
140+
if (response.ok) {
141+
return response.json();
142+
}
143+
throw new Error("save error!");
144+
})
145+
.then(json_data => {
146+
document.getElementById("edit-note-updated_at").value = json_data.updated_at;
147+
if (json_data.conflict === true) {
148+
add_flash("note has been saved, but conflict was detected so made a backup file");
149+
}
150+
else {
151+
add_flash("note has been saved");
152+
}
153+
})
154+
.catch((error) => {
155+
console.error(error);
156+
add_flash("note could not be saved", "error");
157+
});
158+
}
159+
124160
/**
125161
* replace old element content with new
126162
* from requested html fragment
@@ -187,14 +223,6 @@ function handle_note_content_change(api_url) {
187223
load_fragment_to_elem(note_elem, api_url).catch(console.error);
188224
}
189225

190-
/**
191-
* handle showing the user that
192-
* their edit page is out of date
193-
*/
194-
function handle_note_content_change_edit() {
195-
add_flash("note has been edited elsewhere!");
196-
}
197-
198226
/**
199227
* handles updating the note prefix on a notes page
200228
* @param {string} api_url - api url the get the new note prefix

src/note_mark/templates/personal-home/note/edit.jinja2

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
<a class="button" href="{{ url_for('personal_home.rename_note', notebook_uuid=note.notebook_id, note_uuid=note.uuid) }}">Rename</a>
99
<button onclick="ask_before_get(`{{ url_for('personal_home.delete_note', notebook_uuid=note.notebook_id, note_uuid=note.uuid)}}`)">Delete</button>
1010
</div>
11-
<form class="container" id="form-edit-note" action="" method="post">
11+
<form class="container" id="form-edit-note" action="" method="post" onsubmit="return false;">
1212
<div class="control-bar" id="edit-toolbox">
13-
<button type="submit">Save</button>
13+
<button type="submit" onclick="do_note_save(`{{ url_for('api.note_save', notebook_uuid=note.notebook_id, note_uuid=note.uuid) }}`)">Save</button>
1414
{% include "/shared/includes/edit-toolbox.jinja2" %}
1515
</div>
1616
<textarea name="content" id="edit-note-content" placeholder="enter content..." autofocus="true">{{ content }}</textarea>
@@ -20,9 +20,6 @@
2020
<script>
2121
add_auto_save_handle("{{ url_for('api.note_auto_save', notebook_uuid=note.notebook_id, note_uuid=note.uuid) }}");
2222
listen_for_ws_updates(`{{ url_for('api.note_update_ws', notebook_uuid=note.notebook_id, note_uuid=note.uuid, token=get_ws_token()) }}`);
23-
window.addEventListener(
24-
get_ws_event_type(WS_MESSAGE_CATEGORY.NOTE_CONTENT_CHANGE),
25-
_event => { handle_note_content_change_edit() });
2623
window.addEventListener(
2724
get_ws_event_type(WS_MESSAGE_CATEGORY.NOTE_PREFIX_CHANGE),
2825
_event => { handle_note_prefix_change("") });

src/note_mark/views/api.py

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22
from uuid import UUID
33

4-
from quart import Blueprint, jsonify, make_response, render_template, request
4+
from quart import Blueprint, json, jsonify, make_response, render_template, request
55
from quart_auth import current_user
66
from tortoise.exceptions import DoesNotExist
77

@@ -197,18 +197,59 @@ async def note_auto_save(notebook_uuid, note_uuid):
197197
updated_content = (await request.form)["content"]
198198
updated_at = (await request.form)["updated_at"]
199199
updated_at = datetime_input_type(updated_at, "%Y-%m-%d %H:%M:%S.%f%z")
200-
201200
if updated_at < note.updated_at:
202201
# conflict was detected
203-
return "note conflict detected", 400
202+
return jsonify(updated_at=None, conflict=True)
204203

205204
# no conflict detected
206205
await write_note_file_md(notebook_uuid, note_uuid, updated_content)
207206
await note.save() # mark the note updated
208207
await get_ws_handler().broadcast_message(
209208
make_message(MessageCategory.NOTE_CONTENT_CHANGE),
210209
notebook_uuid, note_uuid)
211-
return str(note.updated_at)
210+
return jsonify(updated_at=str(note.updated_at), conflict=False)
211+
212+
except DoesNotExist:
213+
return "notebook does not exist, or you don't have access to it", 404
214+
except ValueError:
215+
return "invalid notebook/user/note", 404
216+
except KeyError:
217+
return "missing required params", 400
218+
219+
220+
@blueprint.route("/notebook/<notebook_uuid>/notes/<note_uuid>/save", methods=["PATCH"])
221+
@api_login_required
222+
async def note_save(notebook_uuid, note_uuid):
223+
try:
224+
notebook_uuid = UUID(notebook_uuid)
225+
note_uuid = UUID(note_uuid)
226+
owner_id = UUID(current_user.auth_id)
227+
await crud.check_user_notebook_access(
228+
owner_id,
229+
notebook_uuid,
230+
("write", "owner"))
231+
note = await crud.get_note(note_uuid)
232+
233+
updated_content = (await request.form)["content"]
234+
updated_at = (await request.form)["updated_at"]
235+
updated_at = datetime_input_type(updated_at, "%Y-%m-%d %H:%M:%S.%f%z")
236+
237+
conflict = False
238+
if updated_at < note.updated_at:
239+
# conflict was detected
240+
conflict = True
241+
conflict_dt = note.updated_at.strftime("%Y-%m-%d %H:%M:%S")
242+
note_backup = await crud.create_note(notebook_uuid, note.prefix + conflict_dt)
243+
conflict_data = await read_note_file_md(notebook_uuid, note_uuid)
244+
await write_note_file_md(notebook_uuid, note_backup.uuid, conflict_data)
245+
246+
await write_note_file_md(notebook_uuid, note_uuid, updated_content)
247+
await note.save() # mark the note updated
248+
249+
await get_ws_handler().broadcast_message(
250+
make_message(MessageCategory.NOTE_CONTENT_CHANGE),
251+
notebook_uuid, note_uuid)
252+
return jsonify(updated_at=str(note.updated_at), conflict=conflict)
212253

213254
except DoesNotExist:
214255
return "notebook does not exist, or you don't have access to it", 404

src/note_mark/views/personal_home.py

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -269,37 +269,18 @@ async def rename_note(notebook_uuid, note_uuid):
269269
return redirect(url_for(".index"))
270270

271271

272-
@blueprint.route("/notebook/<notebook_uuid>/notes/<note_uuid>/edit", methods=["GET", "POST"])
272+
@blueprint.route("/notebook/<notebook_uuid>/notes/<note_uuid>/edit")
273273
@login_required
274274
async def edit_note(notebook_uuid, note_uuid):
275275
try:
276276
notebook_uuid = UUID(notebook_uuid)
277277
note_uuid = UUID(note_uuid)
278278
owner_id = UUID(current_user.auth_id)
279-
await crud.check_user_notebook_access(owner_id, notebook_uuid, ("write", "owner"))
279+
await crud.check_user_notebook_access(
280+
owner_id,
281+
notebook_uuid,
282+
("write", "owner"))
280283
note = await crud.get_note(note_uuid)
281-
if request.method == "POST":
282-
updated_content = (await request.form)["content"]
283-
updated_at = (await request.form)["updated_at"]
284-
updated_at = datetime_input_type(updated_at, "%Y-%m-%d %H:%M:%S.%f%z")
285-
if updated_at < note.updated_at:
286-
# conflict was detected
287-
conflict_dt = note.updated_at.strftime("%Y-%m-%d %H:%M:%S")
288-
note_backup = await crud.create_note(notebook_uuid, note.prefix + conflict_dt)
289-
conflict_data = await read_note_file_md(notebook_uuid, note_uuid)
290-
await write_note_file_md(notebook_uuid, note_backup.uuid, conflict_data)
291-
await write_note_file_md(notebook_uuid, note_uuid, updated_content)
292-
await note.save() # mark the note updated
293-
await flash("note saved, but conflict was detected", "ok")
294-
else:
295-
# no conflict detected
296-
await write_note_file_md(notebook_uuid, note_uuid, updated_content)
297-
await note.save() # mark the note updated
298-
await flash("note saved", "ok")
299-
await get_ws_handler().broadcast_message(
300-
make_message(MessageCategory.NOTE_CONTENT_CHANGE),
301-
notebook_uuid, note_uuid)
302-
303284
content = await read_note_file_md(notebook_uuid, note_uuid)
304285
return await render_template(
305286
"/personal-home/note/edit.jinja2",

0 commit comments

Comments
 (0)