mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-06-27 22:36:00 +00:00
Improve LocalStorage related APIs (#17482)
* 🎨 Improve LocalStorage related APIs * 🎨 Improve LocalStorage related APIs --------- Co-authored-by: D <845765@qq.com>
This commit is contained in:
@@ -142,6 +142,19 @@ export class App {
|
||||
window.siyuan.storage[data.data.key] = data.data.val;
|
||||
}
|
||||
break;
|
||||
case "setLocalStorageVals":
|
||||
Object.keys(data.data.keyVals).forEach((k) => {
|
||||
window.siyuan.storage[k] = data.data.keyVals[k];
|
||||
});
|
||||
break;
|
||||
case "removeLocalStorageVal":
|
||||
delete window.siyuan.storage[data.data.key];
|
||||
break;
|
||||
case "removeLocalStorageVals":
|
||||
data.data.keys.forEach((k: string) => {
|
||||
delete window.siyuan.storage[k];
|
||||
});
|
||||
break;
|
||||
case "rename":
|
||||
getAllTabs().forEach((tab) => {
|
||||
if (tab.headElement) {
|
||||
|
||||
@@ -357,22 +357,26 @@ export const copyTab = (app: App, tab: Tab) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getRootID = (item: Tab) => {
|
||||
const pushRootID = (rootIDs: string[], item: Tab) => {
|
||||
let id;
|
||||
if (item.model instanceof Editor) {
|
||||
return item.model.editor.protyle.block.rootID;
|
||||
id = item.model.editor.protyle.block.rootID;
|
||||
} else if (!item.model) {
|
||||
const initTab = item.headElement.getAttribute("data-initdata");
|
||||
if (initTab) {
|
||||
try {
|
||||
const initTabData = JSON.parse(initTab);
|
||||
if (initTabData && initTabData.instance === "Editor" && initTabData.rootId) {
|
||||
return initTabData.rootId;
|
||||
id = initTabData.rootId;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse tab init data:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (id) {
|
||||
rootIDs.push(id);
|
||||
}
|
||||
};
|
||||
|
||||
export const closeTabByType = (tab: Tab, type: "closeOthers" | "closeAll" | "other", tabs?: Tab[]) => {
|
||||
@@ -381,7 +385,7 @@ export const closeTabByType = (tab: Tab, type: "closeOthers" | "closeAll" | "oth
|
||||
for (let index = 0; index < tab.parent.children.length; index++) {
|
||||
const item = tab.parent.children[index];
|
||||
if (item.id !== tab.id && !item.headElement.classList.contains("item--pin")) {
|
||||
rootIDs.push(getRootID(item));
|
||||
pushRootID(rootIDs, item);
|
||||
item.parent.removeTab(item.id, true, false);
|
||||
index--;
|
||||
}
|
||||
@@ -390,7 +394,7 @@ export const closeTabByType = (tab: Tab, type: "closeOthers" | "closeAll" | "oth
|
||||
for (let index = 0; index < tab.parent.children.length; index++) {
|
||||
const item = tab.parent.children[index];
|
||||
if (!item.headElement.classList.contains("item--pin")) {
|
||||
rootIDs.push(getRootID(item));
|
||||
pushRootID(rootIDs, item);
|
||||
item.parent.removeTab(item.id, true);
|
||||
index--;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,22 @@ export const onMessage = (app: App, data: IWebSocketData) => {
|
||||
case "readonly":
|
||||
window.siyuan.config.editor.readOnly = data.data;
|
||||
break;
|
||||
case "setLocalStorageVal":
|
||||
window.siyuan.storage[data.data.key] = data.data.val;
|
||||
break;
|
||||
case "setLocalStorageVals":
|
||||
Object.keys(data.data.keyVals).forEach((k) => {
|
||||
window.siyuan.storage[k] = data.data.keyVals[k];
|
||||
});
|
||||
break;
|
||||
case "removeLocalStorageVal":
|
||||
delete window.siyuan.storage[data.data.key];
|
||||
break;
|
||||
case "removeLocalStorageVals":
|
||||
data.data.keys.forEach((k: string) => {
|
||||
delete window.siyuan.storage[k];
|
||||
});
|
||||
break;
|
||||
case"progress":
|
||||
progressLoading(data);
|
||||
break;
|
||||
|
||||
@@ -20,6 +20,10 @@ export const updateHotkeyTip = compatibility.updateHotkeyTip;
|
||||
export const getLocalStorage = compatibility.getLocalStorage;
|
||||
export const setStorageVal = compatibility.setStorageVal;
|
||||
|
||||
export const getStorageVal = (key: string): any => {
|
||||
return window.siyuan.storage?.[key] ?? null; // 不存在时与接口响应一致使用 null
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} [options.timeoutType="defalut"] 仅在 Windows 和 Linux 有效,"default" 表示使用默认的超时机制,"never" 表示通知将一直显示,直到用户手动关闭它。
|
||||
* @returns 通知 id
|
||||
|
||||
@@ -101,6 +101,19 @@ class App {
|
||||
window.siyuan.storage[data.data.key] = data.data.val;
|
||||
}
|
||||
break;
|
||||
case "setLocalStorageVals":
|
||||
Object.keys(data.data.keyVals).forEach((k) => {
|
||||
window.siyuan.storage[k] = data.data.keyVals[k];
|
||||
});
|
||||
break;
|
||||
case "removeLocalStorageVal":
|
||||
delete window.siyuan.storage[data.data.key];
|
||||
break;
|
||||
case "removeLocalStorageVals":
|
||||
data.data.keys.forEach((k: string) => {
|
||||
delete window.siyuan.storage[k];
|
||||
});
|
||||
break;
|
||||
case "rename":
|
||||
getAllTabs().forEach((tab) => {
|
||||
if (tab.headElement) {
|
||||
|
||||
@@ -82,17 +82,21 @@ func ServeAPI(ginServer *gin.Engine) {
|
||||
|
||||
ginServer.Handle("POST", "/api/storage/setLocalStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, deprecated) // TODO 请使用 /api/storage/setLocalStorageVal,该端点将于 2026 年 12 月 1 日后删除
|
||||
ginServer.Handle("POST", "/api/storage/getLocalStorage", model.CheckAuth, getLocalStorage)
|
||||
ginServer.Handle("POST", "/api/storage/getLocalStorageVal", model.CheckAuth, getLocalStorageVal)
|
||||
ginServer.Handle("POST", "/api/storage/getLocalStorageVals", model.CheckAuth, getLocalStorageVals)
|
||||
ginServer.Handle("POST", "/api/storage/setLocalStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setLocalStorage, deprecated) // TODO 请使用 /api/storage/setLocalStorageVal,该端点计划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/issues/16664#issuecomment-3694774305
|
||||
ginServer.Handle("POST", "/api/storage/setLocalStorageVal", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setLocalStorageVal)
|
||||
ginServer.Handle("POST", "/api/storage/setLocalStorageVals", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setLocalStorageVals)
|
||||
ginServer.Handle("POST", "/api/storage/removeLocalStorageVal", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeLocalStorageVal)
|
||||
ginServer.Handle("POST", "/api/storage/removeLocalStorageVals", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeLocalStorageVals)
|
||||
ginServer.Handle("POST", "/api/storage/setCriterion", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setCriterion)
|
||||
ginServer.Handle("POST", "/api/storage/getCriteria", model.CheckAuth, getCriteria)
|
||||
ginServer.Handle("POST", "/api/storage/setCriterion", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setCriterion)
|
||||
ginServer.Handle("POST", "/api/storage/removeCriterion", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeCriterion)
|
||||
ginServer.Handle("POST", "/api/storage/getRecentDocs", model.CheckAuth, getRecentDocs)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocOpenTime", model.CheckAuth, updateRecentDocOpenTime)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocViewTime", model.CheckAuth, updateRecentDocViewTime)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocCloseTime", model.CheckAuth, updateRecentDocCloseTime)
|
||||
ginServer.Handle("POST", "/api/storage/batchUpdateRecentDocCloseTime", model.CheckAuth, batchUpdateRecentDocCloseTime)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocOpenTime", model.CheckAuth, updateRecentDocOpenTime)
|
||||
|
||||
ginServer.Handle("POST", "/api/storage/getOutlineStorage", model.CheckAuth, getOutlineStorage)
|
||||
ginServer.Handle("POST", "/api/storage/setOutlineStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setOutlineStorage)
|
||||
ginServer.Handle("POST", "/api/storage/removeOutlineStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeOutlineStorage)
|
||||
|
||||
@@ -60,7 +60,11 @@ func removeCriterion(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
name := arg["name"].(string)
|
||||
var name string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("name", &name, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
err := model.RemoveCriterion(name)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -78,7 +82,12 @@ func setCriterion(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
param, err := gulu.JSON.MarshalJSON(arg["criterion"])
|
||||
var criterionRaw any
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("criterion", &criterionRaw, true, false)) {
|
||||
return
|
||||
}
|
||||
|
||||
param, err := gulu.JSON.MarshalJSON(criterionRaw)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
@@ -117,10 +126,29 @@ func removeLocalStorageVals(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var keysArg []any
|
||||
var app string
|
||||
if !util.ParseJsonArgs(arg, ret,
|
||||
util.BindJsonArg("keys", &keysArg, true, true),
|
||||
util.BindJsonArg("app", &app, false, false),
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
var keys []string
|
||||
keysArg := arg["keys"].([]any)
|
||||
for _, key := range keysArg {
|
||||
keys = append(keys, key.(string))
|
||||
ks, elemOk := key.(string)
|
||||
if !elemOk {
|
||||
ret.Code = -1
|
||||
ret.Msg = "Field [keys]: each element should be of type [String]"
|
||||
return
|
||||
}
|
||||
if ks == "" {
|
||||
ret.Code = -1
|
||||
ret.Msg = "Field [keys]: each element must not be empty"
|
||||
return
|
||||
}
|
||||
keys = append(keys, ks)
|
||||
}
|
||||
|
||||
err := model.RemoveLocalStorageVals(keys)
|
||||
@@ -130,13 +158,43 @@ func removeLocalStorageVals(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
app := arg["app"].(string)
|
||||
evt := util.NewCmdResult("removeLocalStorageVals", 0, util.PushModeBroadcastMainExcludeSelfApp)
|
||||
evt.AppId = app
|
||||
evt.Data = map[string]any{"keys": keys}
|
||||
util.PushEvent(evt)
|
||||
}
|
||||
|
||||
func removeLocalStorageVal(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var key string
|
||||
var app string
|
||||
if !util.ParseJsonArgs(arg, ret,
|
||||
util.BindJsonArg("key", &key, true, true),
|
||||
util.BindJsonArg("app", &app, false, false),
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
err := model.RemoveLocalStorageVals([]string{key})
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
evt := util.NewCmdResult("removeLocalStorageVal", 0, util.PushModeBroadcastMainExcludeSelfApp)
|
||||
evt.AppId = app
|
||||
evt.Data = map[string]any{"key": key}
|
||||
util.PushEvent(evt)
|
||||
}
|
||||
|
||||
func setLocalStorageVal(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
@@ -146,22 +204,60 @@ func setLocalStorageVal(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
key := arg["key"].(string)
|
||||
val := arg["val"].(any)
|
||||
err := model.SetLocalStorageVal(key, val)
|
||||
var key string
|
||||
var app string
|
||||
if !util.ParseJsonArgs(arg, ret,
|
||||
util.BindJsonArg("key", &key, true, true),
|
||||
util.BindJsonArg("app", &app, false, false),
|
||||
) {
|
||||
return
|
||||
}
|
||||
val := arg["val"]
|
||||
|
||||
setKeyVals, err := model.SetLocalStorageVals(map[string]any{key: val})
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
app := arg["app"].(string)
|
||||
evt := util.NewCmdResult("setLocalStorageVal", 0, util.PushModeBroadcastMainExcludeSelfApp)
|
||||
evt.AppId = app
|
||||
evt.Data = map[string]any{"key": key, "val": val}
|
||||
evt.Data = map[string]any{"key": key, "val": setKeyVals[key]}
|
||||
util.PushEvent(evt)
|
||||
}
|
||||
|
||||
func setLocalStorageVals(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var keyVals map[string]any
|
||||
var app string
|
||||
if !util.ParseJsonArgs(arg, ret,
|
||||
util.BindJsonArg("keyVals", &keyVals, true, true),
|
||||
util.BindJsonArg("app", &app, false, false),
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
setKeyVals, err := model.SetLocalStorageVals(keyVals)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
evtSet := util.NewCmdResult("setLocalStorageVals", 0, util.PushModeBroadcastMainExcludeSelfApp)
|
||||
evtSet.AppId = app
|
||||
evtSet.Data = map[string]any{"keyVals": setKeyVals}
|
||||
util.PushEvent(evtSet)
|
||||
}
|
||||
|
||||
func setLocalStorage(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
@@ -171,7 +267,11 @@ func setLocalStorage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
val := arg["val"].(any)
|
||||
var val map[string]any
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("val", &val, true, false)) {
|
||||
return
|
||||
}
|
||||
|
||||
err := model.SetLocalStorage(val)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -192,6 +292,70 @@ func getLocalStorage(c *gin.Context) {
|
||||
ret.Data = data
|
||||
}
|
||||
|
||||
func getLocalStorageVal(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var key string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("key", &key, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
data := model.GetLocalStorage()
|
||||
if model.IsReadOnlyRoleContext(c) {
|
||||
publishAccess := model.GetPublishAccess()
|
||||
data = model.FilterLocalStorageByPublishAccess(publishAccess, data)
|
||||
}
|
||||
ret.Data = data[key]
|
||||
}
|
||||
|
||||
func getLocalStorageVals(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var keysArg []any
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keys", &keysArg, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for _, key := range keysArg {
|
||||
ks, elemOk := key.(string)
|
||||
if !elemOk {
|
||||
ret.Code = -1
|
||||
ret.Msg = "Field [keys]: each element should be of type [String]"
|
||||
return
|
||||
}
|
||||
if ks == "" {
|
||||
ret.Code = -1
|
||||
ret.Msg = "Field [keys]: each element must not be empty"
|
||||
return
|
||||
}
|
||||
keys = append(keys, ks)
|
||||
}
|
||||
|
||||
data := model.GetLocalStorage()
|
||||
if model.IsReadOnlyRoleContext(c) {
|
||||
publishAccess := model.GetPublishAccess()
|
||||
data = model.FilterLocalStorageByPublishAccess(publishAccess, data)
|
||||
}
|
||||
out := map[string]any{}
|
||||
for _, k := range keys {
|
||||
out[k] = data[k]
|
||||
}
|
||||
ret.Data = out
|
||||
}
|
||||
|
||||
func getOutlineStorage(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
@@ -201,7 +365,11 @@ func getOutlineStorage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
docID := arg["docID"].(string)
|
||||
var docID string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("docID", &docID, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := model.GetOutlineStorage(docID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -220,8 +388,15 @@ func setOutlineStorage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
docID := arg["docID"].(string)
|
||||
val := arg["val"].(any)
|
||||
var docID string
|
||||
var val map[string]any
|
||||
if !util.ParseJsonArgs(arg, ret,
|
||||
util.BindJsonArg("docID", &docID, true, true),
|
||||
util.BindJsonArg("val", &val, true, false),
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
err := model.SetOutlineStorage(docID, val)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -239,7 +414,11 @@ func removeOutlineStorage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
docID := arg["docID"].(string)
|
||||
var docID string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("docID", &docID, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
err := model.RemoveOutlineStorage(docID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -257,11 +436,11 @@ func updateRecentDocViewTime(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if nil == arg["rootID"] {
|
||||
var rootID string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("rootID", &rootID, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
rootID := arg["rootID"].(string)
|
||||
err := model.UpdateRecentDocViewTime(rootID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -279,11 +458,11 @@ func updateRecentDocOpenTime(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if nil == arg["rootID"] {
|
||||
var rootID string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("rootID", &rootID, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
rootID := arg["rootID"].(string)
|
||||
err := model.UpdateRecentDocOpenTime(rootID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
@@ -301,8 +480,8 @@ func updateRecentDocCloseTime(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
rootID, ok := arg["rootID"].(string)
|
||||
if !ok || rootID == "" {
|
||||
var rootID string
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("rootID", &rootID, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -323,10 +502,25 @@ func batchUpdateRecentDocCloseTime(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
rootIDsArg := arg["rootIDs"].([]any)
|
||||
var rootIDsArg []any
|
||||
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("rootIDs", &rootIDsArg, true, true)) {
|
||||
return
|
||||
}
|
||||
|
||||
var rootIDs []string
|
||||
for _, id := range rootIDsArg {
|
||||
rootIDs = append(rootIDs, id.(string))
|
||||
str, elemOk := id.(string)
|
||||
if !elemOk {
|
||||
ret.Code = -1
|
||||
ret.Msg = "Field [rootIDs]: each element should be of type [String]"
|
||||
return
|
||||
}
|
||||
if str == "" {
|
||||
ret.Code = -1
|
||||
ret.Msg = "Field [rootIDs]: each element must not be empty"
|
||||
return
|
||||
}
|
||||
rootIDs = append(rootIDs, str)
|
||||
}
|
||||
|
||||
err := model.BatchUpdateRecentDocCloseTime(rootIDs)
|
||||
|
||||
@@ -18,6 +18,7 @@ package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -646,16 +647,25 @@ func RemoveLocalStorageVals(keys []string) (err error) {
|
||||
return setLocalStorage(localStorage)
|
||||
}
|
||||
|
||||
func SetLocalStorageVal(key string, val any) (err error) {
|
||||
func SetLocalStorageVals(keyVals map[string]any) (setKeyVals map[string]any, err error) {
|
||||
localStorageLock.Lock()
|
||||
defer localStorageLock.Unlock()
|
||||
|
||||
setKeyVals = make(map[string]any, len(keyVals))
|
||||
localStorage := getLocalStorage()
|
||||
localStorage[key] = val
|
||||
return setLocalStorage(localStorage)
|
||||
for k, v := range keyVals {
|
||||
if v == nil {
|
||||
err = fmt.Errorf("local storage value for key [%s] must not be empty", k)
|
||||
return
|
||||
}
|
||||
localStorage[k] = v
|
||||
setKeyVals[k] = v
|
||||
}
|
||||
err = setLocalStorage(localStorage)
|
||||
return
|
||||
}
|
||||
|
||||
func SetLocalStorage(val any) (err error) {
|
||||
func SetLocalStorage(val map[string]any) (err error) {
|
||||
localStorageLock.Lock()
|
||||
defer localStorageLock.Unlock()
|
||||
return setLocalStorage(val)
|
||||
@@ -667,7 +677,7 @@ func GetLocalStorage() (ret map[string]any) {
|
||||
return getLocalStorage()
|
||||
}
|
||||
|
||||
func setLocalStorage(val any) (err error) {
|
||||
func setLocalStorage(val map[string]any) (err error) {
|
||||
dirPath := filepath.Join(util.DataDir, "storage")
|
||||
if err = os.MkdirAll(dirPath, 0755); err != nil {
|
||||
logging.LogErrorf("create storage [local] dir failed: %s", err)
|
||||
@@ -731,17 +741,13 @@ func GetOutlineStorage(docID string) (ret map[string]any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func SetOutlineStorage(docID string, val any) (err error) {
|
||||
func SetOutlineStorage(docID string, val map[string]any) (err error) {
|
||||
outlineStorageLock.Lock()
|
||||
defer outlineStorageLock.Unlock()
|
||||
|
||||
outlineDoc := &OutlineDoc{
|
||||
DocID: docID,
|
||||
Data: make(map[string]any),
|
||||
}
|
||||
|
||||
if valMap, ok := val.(map[string]any); ok {
|
||||
outlineDoc.Data = valMap
|
||||
Data: val,
|
||||
}
|
||||
|
||||
outlineDocs, err := getOutlineDocs()
|
||||
|
||||
@@ -222,7 +222,7 @@ func JsonArg(c *gin.Context, result *gulu.Result) (arg map[string]any, ok bool)
|
||||
|
||||
// ParseJsonArg 使用泛型从 JSON 参数中提取指定键的值。
|
||||
// - 如果 required 为 true 但参数缺失,则会在 ret.Msg 中说明需要传入的键
|
||||
// - 如果 rejectEmpty 为 true 但参数值为空,则会在 ret.Msg 中说明该键必须不为空
|
||||
// - 如果 rejectEmpty 为 true 但参数值为空,则会在 ret.Msg 中说明该键必须不为空(字符串去空白后、空数组、无任何键的对象)
|
||||
// - 如果参数存在但类型不匹配,则会在 ret.Msg 中说明该键期望的类型
|
||||
// - 返回值 ok 为 false 时,表示提取失败、类型不匹配或不满足非空约束
|
||||
func ParseJsonArg[T any](key string, arg map[string]any, ret *gulu.Result, required, rejectEmpty bool) (value T, ok bool) {
|
||||
@@ -274,6 +274,8 @@ func ParseJsonArg[T any](key string, arg map[string]any, ret *gulu.Result, requi
|
||||
}
|
||||
case []any:
|
||||
bad = len(x) == 0
|
||||
case map[string]any:
|
||||
bad = len(x) == 0
|
||||
}
|
||||
if bad {
|
||||
ret.Code = -1
|
||||
|
||||
Reference in New Issue
Block a user