Add userdata endpoints

Change nodetemplates to userdata
This commit is contained in:
pythongosssss 2023-12-03 11:56:43 +00:00
parent 50c8bc4ac9
commit a3148e6642
3 changed files with 103 additions and 16 deletions

View File

@ -102,3 +102,34 @@ class UserManager():
user_id = self.add_user(username) user_id = self.add_user(username)
return web.json_response(user_id) return web.json_response(user_id)
@routes.get("/userdata/{file}")
async def getuserdata(request):
file = request.match_info.get("file", None)
if not file:
return web.Response(status=400)
path = self.get_request_user_filepath(request, file)
if not path:
return web.Response(status=403)
if not os.path.exists(path):
return web.Response(status=404)
return web.FileResponse(path)
@routes.post("/userdata/{file}")
async def post_userdata(request):
file = request.match_info.get("file", None)
if not file:
return web.Response(status=400)
path = self.get_request_user_filepath(request, file)
if not path:
return web.Response(status=403)
body = await request.read()
with open(path, "wb") as f:
f.write(body)
return web.Response(status=200)

View File

@ -1,4 +1,5 @@
import { app } from "../../scripts/app.js"; import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { ComfyDialog, $el } from "../../scripts/ui.js"; import { ComfyDialog, $el } from "../../scripts/ui.js";
import { GroupNodeConfig, GroupNodeHandler } from "./groupNode.js"; import { GroupNodeConfig, GroupNodeHandler } from "./groupNode.js";
@ -20,16 +21,20 @@ import { GroupNodeConfig, GroupNodeHandler } from "./groupNode.js";
// Open the manage dialog and Drag and drop elements using the "Name:" label as handle // Open the manage dialog and Drag and drop elements using the "Name:" label as handle
const id = "Comfy.NodeTemplates"; const id = "Comfy.NodeTemplates";
const file = "comfy.templates.json";
class ManageTemplates extends ComfyDialog { class ManageTemplates extends ComfyDialog {
constructor() { constructor() {
super(); super();
this.load().then((v) => {
this.templates = v;
});
this.element.classList.add("comfy-manage-templates"); this.element.classList.add("comfy-manage-templates");
this.templates = this.load();
this.draggedEl = null; this.draggedEl = null;
this.saveVisualCue = null; this.saveVisualCue = null;
this.emptyImg = new Image(); this.emptyImg = new Image();
this.emptyImg.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; this.emptyImg.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
this.importInput = $el("input", { this.importInput = $el("input", {
type: "file", type: "file",
@ -67,17 +72,36 @@ class ManageTemplates extends ComfyDialog {
return btns; return btns;
} }
load() { async load() {
const templates = localStorage.getItem(id); let templates;
if (templates) { if (app.isNewUserSession) {
return JSON.parse(templates); // New user so migrate existing templates
const json = localStorage.getItem(id);
if (json) {
templates = JSON.parse(json);
}
await api.storeUserData(file, json, { stringify: false });
} else { } else {
return []; const res = await api.getUserData(file);
if (res.status === 200) {
templates = await res.json();
} else if (res.status !== 404) {
console.error(res.status + " " + res.statusText);
}
} }
return templates ?? [];
} }
store() { async store() {
localStorage.setItem(id, JSON.stringify(this.templates)); const templates = JSON.stringify(this.templates, undefined, 4);
localStorage.setItem(id, templates); // Backwards compatibility
try {
await api.storeUserData(file, templates, { stringify: false });
} catch (error) {
console.error(error);
alert(error.message);
}
} }
async importAll() { async importAll() {
@ -85,14 +109,14 @@ class ManageTemplates extends ComfyDialog {
if (file.type === "application/json" || file.name.endsWith(".json")) { if (file.type === "application/json" || file.name.endsWith(".json")) {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = async () => { reader.onload = async () => {
var importFile = JSON.parse(reader.result); const importFile = JSON.parse(reader.result);
if (importFile && importFile?.templates) { if (importFile?.templates) {
for (const template of importFile.templates) { for (const template of importFile.templates) {
if (template?.name && template?.data) { if (template?.name && template?.data) {
this.templates.push(template); this.templates.push(template);
} }
} }
this.store(); await this.store();
} }
}; };
await reader.readAsText(file); await reader.readAsText(file);
@ -159,7 +183,7 @@ class ManageTemplates extends ComfyDialog {
e.currentTarget.style.border = "1px dashed transparent"; e.currentTarget.style.border = "1px dashed transparent";
e.currentTarget.removeAttribute("draggable"); e.currentTarget.removeAttribute("draggable");
// rearrange the elements in the localStorage // rearrange the elements
this.element.querySelectorAll('.tempateManagerRow').forEach((el,i) => { this.element.querySelectorAll('.tempateManagerRow').forEach((el,i) => {
var prev_i = el.dataset.id; var prev_i = el.dataset.id;

View File

@ -324,8 +324,8 @@ class ComfyApi extends EventTarget {
} }
/** /**
* Gets a list of all setting values for the current user * Gets all setting values for the current user
* @returns { Promise<string, unknown> } * @returns { Promise<string, unknown> } A dictionary of id -> value
*/ */
async getSettings() { async getSettings() {
return (await this.fetchApi("/settings")).json(); return (await this.fetchApi("/settings")).json();
@ -333,7 +333,8 @@ class ComfyApi extends EventTarget {
/** /**
* Gets a setting for the current user * Gets a setting for the current user
* @returns { Promise<unknown> } * @param { string } id The id of the setting to fetch
* @returns { Promise<unknown> } The setting value
*/ */
async getSetting(id) { async getSetting(id) {
return (await this.fetchApi(`/settings/${encodeURIComponent(id)}`)).json(); return (await this.fetchApi(`/settings/${encodeURIComponent(id)}`)).json();
@ -341,6 +342,7 @@ class ComfyApi extends EventTarget {
/** /**
* Stores a dictionary of settings for the current user * Stores a dictionary of settings for the current user
* @param { Record<string, unknown> } settings Dictionary of setting id -> value to save
* @returns { Promise<void> } * @returns { Promise<void> }
*/ */
async storeSettings(settings) { async storeSettings(settings) {
@ -352,6 +354,8 @@ class ComfyApi extends EventTarget {
/** /**
* Stores a setting for the current user * Stores a setting for the current user
* @param { string } id The id of the setting to update
* @param { unknown } value The value of the setting
* @returns { Promise<void> } * @returns { Promise<void> }
*/ */
async storeSetting(id, value) { async storeSetting(id, value) {
@ -360,6 +364,34 @@ class ComfyApi extends EventTarget {
body: JSON.stringify(value) body: JSON.stringify(value)
}); });
} }
/**
* Gets a user data file for the current user
* @param { string } file The name of the userdata file to load
* @param { RequestInit } [options]
* @returns { Promise<unknown> } The fetch response object
*/
async getUserData(file, options) {
return this.fetchApi(`/userdata/${encodeURIComponent(file)}`, options);
}
/**
* Stores a user data file for the current user
* @param { string } file The name of the userdata file to save
* @param { unknown } data The data to save to the file
* @param { RequestInit & { stringify?: boolean, throwOnError?: boolean } } [options]
* @returns { Promise<void> }
*/
async storeUserData(file, data, options = { stringify: true, throwOnError: true }) {
const resp = await this.fetchApi(`/userdata/${encodeURIComponent(file)}`, {
method: "POST",
body: options?.stringify ? JSON.stringify(data) : data,
...options,
});
if (resp.status !== 200) {
throw new Error(`Error storing user data file '${file}': ${resp.status} ${(await resp).statusText}`);
}
}
} }
export const api = new ComfyApi(); export const api = new ComfyApi();