A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package api
18
19import (
20 "net/http"
21
22 "github.com/88250/gulu"
23 "github.com/gin-gonic/gin"
24 "github.com/siyuan-note/siyuan/kernel/av"
25 "github.com/siyuan-note/siyuan/kernel/model"
26 "github.com/siyuan-note/siyuan/kernel/treenode"
27 "github.com/siyuan-note/siyuan/kernel/util"
28)
29
30func getAttributeViewItemIDsByBoundIDs(c *gin.Context) {
31 ret := gulu.Ret.NewResult()
32 defer c.JSON(http.StatusOK, ret)
33
34 arg, ok := util.JsonArg(c, ret)
35 if !ok {
36 return
37 }
38
39 avID := arg["avID"].(string)
40 blockIDsArg := arg["blockIDs"].([]interface{})
41 var blockIDs []string
42 for _, v := range blockIDsArg {
43 blockIDs = append(blockIDs, v.(string))
44 }
45
46 ret.Data = model.GetAttributeViewItemIDs(avID, blockIDs)
47}
48
49func getAttributeViewBoundBlockIDsByItemIDs(c *gin.Context) {
50 ret := gulu.Ret.NewResult()
51 defer c.JSON(http.StatusOK, ret)
52
53 arg, ok := util.JsonArg(c, ret)
54 if !ok {
55 return
56 }
57
58 avID := arg["avID"].(string)
59 itemIDsArg := arg["itemIDs"].([]interface{})
60 var itemIDs []string
61 for _, v := range itemIDsArg {
62 itemIDs = append(itemIDs, v.(string))
63 }
64
65 ret.Data = model.GetAttributeViewBoundBlockIDs(avID, itemIDs)
66}
67
68// getAttributeViewAddingBlockDefaultValues 用于获取添加块时的默认值。
69// 存在过滤或分组条件时,添加块时需要填充默认值到过滤字段或分组字段中,前端需要调用该接口来获取这些默认值以便填充。
70func getAttributeViewAddingBlockDefaultValues(c *gin.Context) {
71 ret := gulu.Ret.NewResult()
72 defer c.JSON(http.StatusOK, ret)
73
74 arg, ok := util.JsonArg(c, ret)
75 if !ok {
76 return
77 }
78
79 avID := arg["avID"].(string)
80 var viewID string
81 if viewIDArg := arg["viewID"]; nil != viewIDArg {
82 viewID = viewIDArg.(string)
83 }
84 var groupID string
85 if groupIDArg := arg["groupID"]; nil != groupIDArg {
86 groupID = groupIDArg.(string)
87 }
88 var previousID string
89 if nil != arg["previousID"] {
90 previousID = arg["previousID"].(string)
91 }
92 var addingBlockID string
93 if nil != arg["addingBlockID"] {
94 addingBlockID = arg["addingBlockID"].(string)
95 }
96
97 values := model.GetAttrViewAddingBlockDefaultValues(avID, viewID, groupID, previousID, addingBlockID)
98 if 1 > len(values) {
99 values = nil
100 }
101 ret.Data = map[string]interface{}{
102 "values": values,
103 }
104}
105
106func batchReplaceAttributeViewBlocks(c *gin.Context) {
107 // Add kernel API `/api/av/batchReplaceAttributeViewBlocks` https://github.com/siyuan-note/siyuan/issues/15313
108 ret := gulu.Ret.NewResult()
109 defer c.JSON(http.StatusOK, ret)
110
111 arg, ok := util.JsonArg(c, ret)
112 if !ok {
113 return
114 }
115
116 avID := arg["avID"].(string)
117 isDetached := arg["isDetached"].(bool)
118 oldNewArg := arg["oldNew"].([]interface{})
119 var oldNew []map[string]string
120 for _, v := range oldNewArg {
121 for o, n := range v.(map[string]interface{}) {
122 oldNew = append(oldNew, map[string]string{o: n.(string)})
123 }
124 }
125
126 err := model.BatchReplaceAttributeViewBlocks(avID, isDetached, oldNew)
127 if err != nil {
128 ret.Code = -1
129 ret.Msg = err.Error()
130 return
131 }
132
133 model.ReloadAttrView(avID)
134}
135
136func setAttrViewGroup(c *gin.Context) {
137 ret := gulu.Ret.NewResult()
138 arg, ok := util.JsonArg(c, ret)
139 if !ok {
140 c.JSON(http.StatusOK, ret)
141 return
142 }
143
144 avID := arg["avID"].(string)
145 blockID := arg["blockID"].(string)
146 groupArg := arg["group"].(map[string]interface{})
147
148 data, err := gulu.JSON.MarshalJSON(groupArg)
149 if nil != err {
150 ret.Code = -1
151 ret.Msg = err.Error()
152 c.JSON(http.StatusOK, ret)
153 return
154 }
155 group := &av.ViewGroup{}
156 if err = gulu.JSON.UnmarshalJSON(data, group); nil != err {
157 ret.Code = -1
158 ret.Msg = err.Error()
159 c.JSON(http.StatusOK, ret)
160 return
161 }
162
163 err = model.SetAttributeViewGroup(avID, blockID, group)
164 if err != nil {
165 ret.Code = -1
166 ret.Msg = err.Error()
167
168 c.JSON(http.StatusOK, ret)
169 return
170 }
171
172 ret = renderAttrView(blockID, avID, "", "", 1, -1, nil)
173 c.JSON(http.StatusOK, ret)
174}
175
176func changeAttrViewLayout(c *gin.Context) {
177 ret := gulu.Ret.NewResult()
178 arg, ok := util.JsonArg(c, ret)
179 if !ok {
180 c.JSON(http.StatusOK, ret)
181 return
182 }
183
184 blockID := arg["blockID"].(string)
185 avID := arg["avID"].(string)
186 layoutType := arg["layoutType"].(string)
187 err := model.ChangeAttrViewLayout(blockID, avID, av.LayoutType(layoutType))
188 if err != nil {
189 ret.Code = -1
190 ret.Msg = err.Error()
191 c.JSON(http.StatusOK, ret)
192 return
193 }
194
195 ret = renderAttrView(blockID, avID, "", "", 1, -1, nil)
196 c.JSON(http.StatusOK, ret)
197}
198
199func duplicateAttributeViewBlock(c *gin.Context) {
200 ret := gulu.Ret.NewResult()
201 defer c.JSON(http.StatusOK, ret)
202
203 arg, ok := util.JsonArg(c, ret)
204 if !ok {
205 return
206 }
207 avID := arg["avID"].(string)
208
209 newAvID, newBlockID, err := model.DuplicateDatabaseBlock(avID)
210 if err != nil {
211 ret.Code = -1
212 ret.Msg = err.Error()
213 return
214 }
215
216 ret.Data = map[string]interface{}{
217 "avID": newAvID,
218 "blockID": newBlockID,
219 }
220}
221
222func getAttributeViewKeysByAvID(c *gin.Context) {
223 ret := gulu.Ret.NewResult()
224 defer c.JSON(http.StatusOK, ret)
225
226 arg, ok := util.JsonArg(c, ret)
227 if !ok {
228 return
229 }
230 avID := arg["avID"].(string)
231 ret.Data = model.GetAttributeViewKeysByID(avID)
232}
233
234func getAttributeViewKeysByID(c *gin.Context) {
235 ret := gulu.Ret.NewResult()
236 defer c.JSON(http.StatusOK, ret)
237
238 arg, ok := util.JsonArg(c, ret)
239 if !ok {
240 return
241 }
242 avID := arg["avID"].(string)
243 keyIDsArg := arg["keyIDs"].([]interface{})
244 var keyIDs []string
245 for _, v := range keyIDsArg {
246 keyIDs = append(keyIDs, v.(string))
247 }
248 ret.Data = model.GetAttributeViewKeysByID(avID, keyIDs...)
249}
250
251func getMirrorDatabaseBlocks(c *gin.Context) {
252 ret := gulu.Ret.NewResult()
253 defer c.JSON(http.StatusOK, ret)
254
255 arg, ok := util.JsonArg(c, ret)
256 if !ok {
257 return
258 }
259
260 avID := arg["avID"].(string)
261 blockIDs := treenode.GetMirrorAttrViewBlockIDs(avID)
262 var retRefDefs []model.RefDefs
263 for _, blockID := range blockIDs {
264 retRefDefs = append(retRefDefs, model.RefDefs{RefID: blockID, DefIDs: []string{}})
265 }
266 if 1 > len(retRefDefs) {
267 retRefDefs = []model.RefDefs{}
268 }
269
270 ret.Data = map[string]any{
271 "refDefs": retRefDefs,
272 }
273}
274
275func setDatabaseBlockView(c *gin.Context) {
276 ret := gulu.Ret.NewResult()
277 defer c.JSON(http.StatusOK, ret)
278
279 arg, ok := util.JsonArg(c, ret)
280 if !ok {
281 return
282 }
283
284 blockID := arg["id"].(string)
285 viewID := arg["viewID"].(string)
286 avID := arg["avID"].(string)
287
288 err := model.SetDatabaseBlockView(blockID, avID, viewID)
289 if err != nil {
290 ret.Code = -1
291 ret.Msg = err.Error()
292 return
293 }
294}
295
296func getAttributeViewPrimaryKeyValues(c *gin.Context) {
297 ret := gulu.Ret.NewResult()
298 defer c.JSON(http.StatusOK, ret)
299
300 arg, ok := util.JsonArg(c, ret)
301 if !ok {
302 return
303 }
304
305 id := arg["id"].(string)
306 page := 1
307 pageArg := arg["page"]
308 if nil != pageArg {
309 page = int(pageArg.(float64))
310 }
311
312 pageSize := -1
313 pageSizeArg := arg["pageSize"]
314 if nil != pageSizeArg {
315 pageSize = int(pageSizeArg.(float64))
316 }
317
318 keyword := ""
319 if keywordArg := arg["keyword"]; nil != keywordArg {
320 keyword = keywordArg.(string)
321 }
322 attributeViewName, databaseBlockIDs, rows, err := model.GetAttributeViewPrimaryKeyValues(id, keyword, page, pageSize)
323 if err != nil {
324 ret.Code = -1
325 ret.Msg = err.Error()
326 return
327 }
328
329 ret.Data = map[string]interface{}{
330 "name": attributeViewName,
331 "blockIDs": databaseBlockIDs,
332 "rows": rows,
333 }
334}
335
336func appendAttributeViewDetachedBlocksWithValues(c *gin.Context) {
337 // Add an internal kernel API `/api/av/appendAttributeViewDetachedBlocksWithValues` https://github.com/siyuan-note/siyuan/issues/11608
338
339 ret := gulu.Ret.NewResult()
340 defer c.JSON(http.StatusOK, ret)
341
342 arg, _ := util.JsonArg(c, ret)
343 if nil == arg {
344 return
345 }
346
347 avID := arg["avID"].(string)
348 var values [][]*av.Value
349 for _, blocksVals := range arg["blocksValues"].([]interface{}) {
350 vals := blocksVals.([]interface{})
351 var rowValues []*av.Value
352 for _, val := range vals {
353 data, marshalErr := gulu.JSON.MarshalJSON(val)
354 if nil != marshalErr {
355 ret.Code = -1
356 ret.Msg = marshalErr.Error()
357 return
358 }
359 value := av.Value{}
360 if unmarshalErr := gulu.JSON.UnmarshalJSON(data, &value); nil != unmarshalErr {
361 ret.Code = -1
362 ret.Msg = unmarshalErr.Error()
363 return
364 }
365 rowValues = append(rowValues, &value)
366 }
367 values = append(values, rowValues)
368 }
369
370 err := model.AppendAttributeViewDetachedBlocksWithValues(avID, values)
371 if err != nil {
372 ret.Code = -1
373 ret.Msg = err.Error()
374 return
375 }
376}
377
378func addAttributeViewBlocks(c *gin.Context) {
379 ret := gulu.Ret.NewResult()
380 defer c.JSON(http.StatusOK, ret)
381
382 arg, _ := util.JsonArg(c, ret)
383 if nil == arg {
384 return
385 }
386
387 avID := arg["avID"].(string)
388 var blockID string
389 if blockIDArg := arg["blockID"]; nil != blockIDArg {
390 blockID = blockIDArg.(string)
391 }
392 var viewID string
393 if viewIDArg := arg["viewID"]; nil != viewIDArg {
394 viewID = viewIDArg.(string)
395 }
396 var groupID string
397 if groupIDArg := arg["groupID"]; nil != groupIDArg {
398 groupID = groupIDArg.(string)
399 }
400 var previousID string
401 if nil != arg["previousID"] {
402 previousID = arg["previousID"].(string)
403 }
404
405 var srcs []map[string]interface{}
406 for _, v := range arg["srcs"].([]interface{}) {
407 src := v.(map[string]interface{})
408 srcs = append(srcs, src)
409 }
410
411 var ignoreDefaultFill bool
412 if nil != arg["ignoreDefaultFill"] {
413 ignoreDefaultFill = arg["ignoreDefaultFill"].(bool)
414 }
415
416 err := model.AddAttributeViewBlock(nil, srcs, avID, blockID, viewID, groupID, previousID, ignoreDefaultFill, map[string]interface{}{})
417 if err != nil {
418 ret.Code = -1
419 ret.Msg = err.Error()
420 return
421 }
422
423 model.ReloadAttrView(avID)
424}
425
426func removeAttributeViewBlocks(c *gin.Context) {
427 ret := gulu.Ret.NewResult()
428 defer c.JSON(http.StatusOK, ret)
429
430 arg, _ := util.JsonArg(c, ret)
431 if nil == arg {
432 return
433 }
434
435 avID := arg["avID"].(string)
436 var srcIDs []string
437 for _, v := range arg["srcIDs"].([]interface{}) {
438 srcIDs = append(srcIDs, v.(string))
439 }
440
441 err := model.RemoveAttributeViewBlock(srcIDs, avID)
442 if err != nil {
443 ret.Code = -1
444 ret.Msg = err.Error()
445 return
446 }
447
448 model.ReloadAttrView(avID)
449}
450
451func addAttributeViewKey(c *gin.Context) {
452 ret := gulu.Ret.NewResult()
453 defer c.JSON(http.StatusOK, ret)
454
455 arg, _ := util.JsonArg(c, ret)
456 if nil == arg {
457 return
458 }
459
460 avID := arg["avID"].(string)
461 keyID := arg["keyID"].(string)
462 keyName := arg["keyName"].(string)
463 keyType := arg["keyType"].(string)
464 keyIcon := arg["keyIcon"].(string)
465 previousKeyID := arg["previousKeyID"].(string)
466
467 err := model.AddAttributeViewKey(avID, keyID, keyName, keyType, keyIcon, previousKeyID)
468 if err != nil {
469 ret.Code = -1
470 ret.Msg = err.Error()
471 return
472 }
473
474 model.ReloadAttrView(avID)
475}
476
477func removeAttributeViewKey(c *gin.Context) {
478 ret := gulu.Ret.NewResult()
479 defer c.JSON(http.StatusOK, ret)
480
481 arg, _ := util.JsonArg(c, ret)
482 if nil == arg {
483 return
484 }
485
486 avID := arg["avID"].(string)
487 keyID := arg["keyID"].(string)
488 removeRelationDest := false
489 if nil != arg["removeRelationDest"] {
490 removeRelationDest = arg["removeRelationDest"].(bool)
491 }
492
493 err := model.RemoveAttributeViewKey(avID, keyID, removeRelationDest)
494 if err != nil {
495 ret.Code = -1
496 ret.Msg = err.Error()
497 return
498 }
499
500 model.ReloadAttrView(avID)
501}
502
503func sortAttributeViewViewKey(c *gin.Context) {
504 ret := gulu.Ret.NewResult()
505 defer c.JSON(http.StatusOK, ret)
506
507 arg, ok := util.JsonArg(c, ret)
508 if !ok {
509 return
510 }
511
512 avID := arg["avID"].(string)
513 viewID := ""
514 if viewIDArg := arg["viewID"]; nil != viewIDArg {
515 viewID = viewIDArg.(string)
516 }
517 keyID := arg["keyID"].(string)
518 previousKeyID := arg["previousKeyID"].(string)
519
520 err := model.SortAttributeViewViewKey(avID, viewID, keyID, previousKeyID)
521 if err != nil {
522 ret.Code = -1
523 ret.Msg = err.Error()
524 return
525 }
526
527 model.ReloadAttrView(avID)
528}
529
530func sortAttributeViewKey(c *gin.Context) {
531 ret := gulu.Ret.NewResult()
532 defer c.JSON(http.StatusOK, ret)
533
534 arg, ok := util.JsonArg(c, ret)
535 if !ok {
536 return
537 }
538
539 avID := arg["avID"].(string)
540 keyID := arg["keyID"].(string)
541 previousKeyID := arg["previousKeyID"].(string)
542
543 err := model.SortAttributeViewKey(avID, keyID, previousKeyID)
544 if err != nil {
545 ret.Code = -1
546 ret.Msg = err.Error()
547 return
548 }
549
550 model.ReloadAttrView(avID)
551}
552
553func getAttributeViewFilterSort(c *gin.Context) {
554 ret := gulu.Ret.NewResult()
555 defer c.JSON(http.StatusOK, ret)
556
557 arg, _ := util.JsonArg(c, ret)
558 if nil == arg {
559 return
560 }
561
562 avID := arg["id"].(string)
563 blockID := arg["blockID"].(string)
564
565 filters, sorts := model.GetAttributeViewFilterSort(avID, blockID)
566 ret.Data = map[string]interface{}{
567 "filters": filters,
568 "sorts": sorts,
569 }
570}
571
572func searchAttributeViewNonRelationKey(c *gin.Context) {
573 ret := gulu.Ret.NewResult()
574 defer c.JSON(http.StatusOK, ret)
575
576 arg, _ := util.JsonArg(c, ret)
577 if nil == arg {
578 return
579 }
580
581 avID := arg["avID"].(string)
582 keyword := arg["keyword"].(string)
583
584 nonRelationKeys := model.SearchAttributeViewNonRelationKey(avID, keyword)
585 ret.Data = map[string]interface{}{
586 "keys": nonRelationKeys,
587 }
588}
589
590func searchAttributeViewRollupDestKeys(c *gin.Context) {
591 ret := gulu.Ret.NewResult()
592 defer c.JSON(http.StatusOK, ret)
593
594 arg, _ := util.JsonArg(c, ret)
595 if nil == arg {
596 return
597 }
598
599 avID := arg["avID"].(string)
600 keyword := arg["keyword"].(string)
601
602 rollupDestKeys := model.SearchAttributeViewRollupDestKeys(avID, keyword)
603 ret.Data = map[string]interface{}{
604 "keys": rollupDestKeys,
605 }
606}
607
608func searchAttributeViewRelationKey(c *gin.Context) {
609 ret := gulu.Ret.NewResult()
610 defer c.JSON(http.StatusOK, ret)
611
612 arg, _ := util.JsonArg(c, ret)
613 if nil == arg {
614 return
615 }
616
617 avID := arg["avID"].(string)
618 keyword := arg["keyword"].(string)
619
620 relationKeys := model.SearchAttributeViewRelationKey(avID, keyword)
621 ret.Data = map[string]interface{}{
622 "keys": relationKeys,
623 }
624}
625
626func getAttributeView(c *gin.Context) {
627 ret := gulu.Ret.NewResult()
628 defer c.JSON(http.StatusOK, ret)
629
630 arg, _ := util.JsonArg(c, ret)
631 if nil == arg {
632 return
633 }
634
635 id := arg["id"].(string)
636 ret.Data = map[string]interface{}{
637 "av": model.GetAttributeView(id),
638 }
639}
640
641func searchAttributeView(c *gin.Context) {
642 ret := gulu.Ret.NewResult()
643 defer c.JSON(http.StatusOK, ret)
644
645 arg, _ := util.JsonArg(c, ret)
646 if nil == arg {
647 return
648 }
649
650 keyword := arg["keyword"].(string)
651 var excludes []string
652 if nil != arg["excludes"] {
653 for _, e := range arg["excludes"].([]interface{}) {
654 excludes = append(excludes, e.(string))
655 }
656 }
657 results := model.SearchAttributeView(keyword, excludes)
658 ret.Data = map[string]interface{}{
659 "results": results,
660 }
661}
662
663func renderSnapshotAttributeView(c *gin.Context) {
664 ret := gulu.Ret.NewResult()
665 defer c.JSON(http.StatusOK, ret)
666
667 arg, ok := util.JsonArg(c, ret)
668 if !ok {
669 return
670 }
671
672 index := arg["snapshot"].(string)
673 id := arg["id"].(string)
674 view, attrView, err := model.RenderRepoSnapshotAttributeView(index, id)
675 if err != nil {
676 ret.Code = -1
677 ret.Msg = err.Error()
678 return
679 }
680
681 var views []map[string]interface{}
682 for _, v := range attrView.Views {
683 view := map[string]interface{}{
684 "id": v.ID,
685 "icon": v.Icon,
686 "name": v.Name,
687 "hideAttrViewName": v.HideAttrViewName,
688 "type": v.LayoutType,
689 }
690
691 views = append(views, view)
692 }
693
694 ret.Data = map[string]interface{}{
695 "name": attrView.Name,
696 "id": attrView.ID,
697 "viewType": view.GetType(),
698 "viewID": view.GetID(),
699 "views": views,
700 "view": view,
701 "isMirror": av.IsMirror(attrView.ID),
702 }
703}
704
705func renderHistoryAttributeView(c *gin.Context) {
706 ret := gulu.Ret.NewResult()
707 defer c.JSON(http.StatusOK, ret)
708
709 arg, ok := util.JsonArg(c, ret)
710 if !ok {
711 return
712 }
713
714 id := arg["id"].(string)
715 created := arg["created"].(string)
716 blockIDArg := arg["blockID"]
717 var blockID string
718 if nil != blockIDArg {
719 blockID = blockIDArg.(string)
720 }
721 viewIDArg := arg["viewID"]
722 var viewID string
723 if nil != viewIDArg {
724 viewID = viewIDArg.(string)
725 }
726 page := 1
727 pageArg := arg["page"]
728 if nil != pageArg {
729 page = int(pageArg.(float64))
730 }
731
732 pageSize := -1
733 pageSizeArg := arg["pageSize"]
734 if nil != pageSizeArg {
735 pageSize = int(pageSizeArg.(float64))
736 }
737
738 query := ""
739 queryArg := arg["query"]
740 if nil != queryArg {
741 query = queryArg.(string)
742 }
743
744 groupPaging := map[string]interface{}{}
745 groupPagingArg := arg["groupPaging"]
746 if nil != groupPagingArg {
747 groupPaging = groupPagingArg.(map[string]interface{})
748 }
749
750 view, attrView, err := model.RenderHistoryAttributeView(blockID, id, viewID, query, page, pageSize, groupPaging, created)
751 if err != nil {
752 ret.Code = -1
753 ret.Msg = err.Error()
754 return
755 }
756
757 var views []map[string]interface{}
758 for _, v := range attrView.Views {
759 view := map[string]interface{}{
760 "id": v.ID,
761 "icon": v.Icon,
762 "name": v.Name,
763 "hideAttrViewName": v.HideAttrViewName,
764 "type": v.LayoutType,
765 }
766
767 views = append(views, view)
768 }
769
770 ret.Data = map[string]interface{}{
771 "name": attrView.Name,
772 "id": attrView.ID,
773 "viewType": view.GetType(),
774 "viewID": view.GetID(),
775 "views": views,
776 "view": view,
777 "isMirror": av.IsMirror(attrView.ID),
778 }
779}
780
781func renderAttributeView(c *gin.Context) {
782 ret := gulu.Ret.NewResult()
783 arg, ok := util.JsonArg(c, ret)
784 if !ok {
785 c.JSON(http.StatusOK, ret)
786 return
787 }
788
789 id := arg["id"].(string)
790 blockIDArg := arg["blockID"]
791 var blockID string
792 if nil != blockIDArg {
793 blockID = blockIDArg.(string)
794 }
795 viewIDArg := arg["viewID"]
796 var viewID string
797 if nil != viewIDArg {
798 viewID = viewIDArg.(string)
799 }
800 page := 1
801 pageArg := arg["page"]
802 if nil != pageArg {
803 page = int(pageArg.(float64))
804 }
805
806 pageSize := -1
807 pageSizeArg := arg["pageSize"]
808 if nil != pageSizeArg {
809 pageSize = int(pageSizeArg.(float64))
810 }
811
812 query := ""
813 queryArg := arg["query"]
814 if nil != queryArg {
815 query = queryArg.(string)
816 }
817
818 groupPaging := map[string]interface{}{}
819 groupPagingArg := arg["groupPaging"]
820 if nil != groupPagingArg {
821 groupPaging = groupPagingArg.(map[string]interface{})
822 }
823
824 ret = renderAttrView(blockID, id, viewID, query, page, pageSize, groupPaging)
825 c.JSON(http.StatusOK, ret)
826}
827
828func renderAttrView(blockID, avID, viewID, query string, page, pageSize int, groupPaging map[string]interface{}) (ret *gulu.Result) {
829 ret = gulu.Ret.NewResult()
830 view, attrView, err := model.RenderAttributeView(blockID, avID, viewID, query, page, pageSize, groupPaging)
831 if err != nil {
832 ret.Code = -1
833 ret.Msg = err.Error()
834 return
835 }
836
837 var views []map[string]interface{}
838 for _, v := range attrView.Views {
839 view := map[string]interface{}{
840 "id": v.ID,
841 "icon": v.Icon,
842 "name": v.Name,
843 "desc": v.Desc,
844 "hideAttrViewName": v.HideAttrViewName,
845 "type": v.LayoutType,
846 "pageSize": v.PageSize,
847 }
848
849 views = append(views, view)
850 }
851
852 ret.Data = map[string]interface{}{
853 "name": attrView.Name,
854 "id": attrView.ID,
855 "viewType": view.GetType(),
856 "viewID": view.GetID(),
857 "views": views,
858 "view": view,
859 "isMirror": av.IsMirror(attrView.ID),
860 }
861 return
862}
863
864func getCurrentAttrViewImages(c *gin.Context) {
865 ret := gulu.Ret.NewResult()
866 defer c.JSON(http.StatusOK, ret)
867
868 arg, ok := util.JsonArg(c, ret)
869 if !ok {
870 return
871 }
872
873 id := arg["id"].(string)
874 viewIDArg := arg["viewID"]
875 var viewID string
876 if nil != viewIDArg {
877 viewID = viewIDArg.(string)
878 }
879
880 query := ""
881 queryArg := arg["query"]
882 if nil != queryArg {
883 query = queryArg.(string)
884 }
885
886 images, err := model.GetCurrentAttributeViewImages(id, viewID, query)
887 if err != nil {
888 ret.Code = -1
889 ret.Msg = err.Error()
890 return
891 }
892 ret.Data = images
893}
894
895func getAttributeViewKeys(c *gin.Context) {
896 ret := gulu.Ret.NewResult()
897 defer c.JSON(http.StatusOK, ret)
898
899 arg, ok := util.JsonArg(c, ret)
900 if !ok {
901 return
902 }
903
904 id := arg["id"].(string)
905 blockAttributeViewKeys := model.GetBlockAttributeViewKeys(id)
906 ret.Data = blockAttributeViewKeys
907}
908
909func setAttributeViewBlockAttr(c *gin.Context) {
910 ret := gulu.Ret.NewResult()
911 defer c.JSON(http.StatusOK, ret)
912
913 arg, ok := util.JsonArg(c, ret)
914 if !ok {
915 return
916 }
917
918 avID := arg["avID"].(string)
919 keyID := arg["keyID"].(string)
920 var itemID string
921 if _, ok := arg["itemID"]; ok {
922 itemID = arg["itemID"].(string)
923 } else if _, ok := arg["rowID"]; ok {
924 // TODO 划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/issues/15708#issuecomment-3239694546
925 itemID = arg["rowID"].(string)
926 }
927 value := arg["value"].(interface{})
928 updatedVal, err := model.UpdateAttributeViewCell(nil, avID, keyID, itemID, value)
929 if err != nil {
930 ret.Code = -1
931 ret.Msg = err.Error()
932 return
933 }
934
935 ret.Data = map[string]interface{}{
936 "value": updatedVal,
937 }
938
939 model.ReloadAttrView(avID)
940}
941
942func batchSetAttributeViewBlockAttrs(c *gin.Context) {
943 // Add kernel API `/api/av/batchSetAttributeViewBlockAttrs` https://github.com/siyuan-note/siyuan/issues/15310
944 ret := gulu.Ret.NewResult()
945 defer c.JSON(http.StatusOK, ret)
946
947 arg, ok := util.JsonArg(c, ret)
948 if !ok {
949 return
950 }
951
952 avID := arg["avID"].(string)
953 values := arg["values"].([]interface{})
954 err := model.BatchUpdateAttributeViewCells(nil, avID, values)
955 if err != nil {
956 ret.Code = -1
957 ret.Msg = err.Error()
958 return
959 }
960
961 model.ReloadAttrView(avID)
962}