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 model
18
19import (
20 "strings"
21 "time"
22 "unicode/utf8"
23
24 "github.com/88250/gulu"
25 "github.com/88250/lute/ast"
26 "github.com/siyuan-note/siyuan/kernel/av"
27 "github.com/siyuan-note/siyuan/kernel/filesys"
28 "github.com/siyuan-note/siyuan/kernel/treenode"
29 "github.com/siyuan-note/siyuan/kernel/util"
30)
31
32func checkAttrView(attrView *av.AttributeView, view *av.View) {
33 // 字段删除以后需要删除设置的过滤和排序
34 tmpFilters := []*av.ViewFilter{}
35 for _, f := range view.Filters {
36 if k, _ := attrView.GetKey(f.Column); nil != k {
37 tmpFilters = append(tmpFilters, f)
38 }
39 }
40 changed := len(tmpFilters) != len(view.Filters)
41 view.Filters = tmpFilters
42
43 tmpSorts := []*av.ViewSort{}
44 for _, s := range view.Sorts {
45 if k, _ := attrView.GetKey(s.Column); nil != k {
46 tmpSorts = append(tmpSorts, s)
47 }
48 }
49 if !changed {
50 changed = len(tmpSorts) != len(view.Sorts)
51 }
52 view.Sorts = tmpSorts
53
54 // 字段删除以后需要删除设置的分组
55 if nil != view.Group {
56 if k, _ := attrView.GetKey(view.Group.Field); nil == k {
57 view.Group = nil
58 }
59 }
60
61 // 订正视图类型
62 for i, v := range attrView.Views {
63 if av.LayoutTypeGallery == v.LayoutType && nil == v.Gallery {
64 // 切换为卡片视图时可能没有初始化卡片实例 https://github.com/siyuan-note/siyuan/issues/15122
65 if nil != v.Table {
66 v.LayoutType = av.LayoutTypeTable
67 changed = true
68 } else {
69 attrView.Views = append(attrView.Views[:i], attrView.Views[i+1:]...)
70 changed = true
71 }
72 }
73 }
74
75 now := util.CurrentTimeMillis()
76
77 // 订正字段类型
78 for _, kv := range attrView.KeyValues {
79 for _, v := range kv.Values {
80 if v.Type != kv.Key.Type {
81 v.Type = kv.Key.Type
82 if av.KeyTypeBlock == v.Type && nil == v.Block {
83 v.Block = &av.ValueBlock{}
84 if nil != v.Text {
85 v.Block.Content = v.Text.Content
86 }
87 if "" == v.BlockID {
88 v.BlockID = ast.NewNodeID()
89 }
90 createdStr := v.BlockID[:len("20060102150405")]
91 created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local)
92 if nil == parseErr {
93 v.Block.Created = created.UnixMilli()
94 } else {
95 v.Block.Created = now
96 }
97 v.Block.Updated = v.Block.Created
98 }
99 changed = true
100 }
101 }
102 }
103
104 attrView.Name = strings.ReplaceAll(attrView.Name, "\n", " ")
105 // 截断超长的数据库标题 Limit the database title to 512 characters https://github.com/siyuan-note/siyuan/issues/15459
106 if 512 < utf8.RuneCountInString(attrView.Name) {
107 attrView.Name = gulu.Str.SubStr(attrView.Name, 512)
108 changed = true
109 }
110
111 if changed {
112 av.SaveAttributeView(attrView)
113 }
114}
115
116func upgradeAttributeViewSpec(attrView *av.AttributeView) {
117 currentSpec := attrView.Spec
118
119 upgradeAttributeViewSpec1(attrView)
120 av.UpgradeSpec(attrView)
121
122 newSpec := attrView.Spec
123 if currentSpec != newSpec {
124 av.SaveAttributeView(attrView)
125 }
126}
127
128func upgradeAttributeViewSpec1(attrView *av.AttributeView) {
129 if 1 <= attrView.Spec {
130 return
131 }
132
133 var blockIDs []string
134 idBlocks := map[string]*av.Value{}
135 for _, kv := range attrView.KeyValues {
136 switch kv.Key.Type {
137 case av.KeyTypeBlock:
138 for _, v := range kv.Values {
139 if !v.IsDetached {
140 blockIDs = append(blockIDs, v.BlockID)
141 idBlocks[v.BlockID] = v
142 }
143 }
144 }
145 }
146 blockIDs = gulu.Str.RemoveDuplicatedElem(blockIDs)
147
148 trees := filesys.LoadTrees(blockIDs)
149 for _, id := range blockIDs {
150 tree := trees[id]
151 if nil == tree {
152 continue
153 }
154
155 node := treenode.GetNodeInTree(tree, id)
156 if nil == node {
157 continue
158 }
159
160 if block := idBlocks[id].Block; nil != block {
161 block.Icon = node.IALAttr("icon")
162 }
163 }
164}