Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2024-01-01 17:20:33 +08:00
commit f5a8533926
16 changed files with 149 additions and 101 deletions

View file

@ -1200,7 +1200,7 @@
"38": "Too many keywords mentioned [%d], adjust if necessary [Settings - Search - Backlink Mentions - Keyword Limit]",
"39": "Deleting index %s",
"40": "Inserting index %s",
"41": "Upload completed",
"41": "Upload completed [%d]",
"42": "The setting is complete, the application will be closed automatically, please restart later...",
"43": "The maximum storage capacity of cloud space [%s] has been exceeded, and data upload cannot continue",
"44": "Parse template failed: %s",

View file

@ -1200,7 +1200,7 @@
"38": "Demasiadas palabras clave mencionadas [%d], ajústelas si es necesario [Configuración - Búsqueda - Menciones de backlinks - Límite de palabras clave]",
"39": "Eliminando índice %s",
"40": "Insertando índice %s",
"41": "Carga completada",
"41": "Carga completada [%d]",
"42": "La configuración se ha completado, la aplicación se cerrará automáticamente, por favor reinicie más tarde...",
"43": "Se ha superado la capacidad máxima de almacenamiento del espacio en la nube [%s] y la carga de datos no puede continuar",
"44": "El proceso de análisis de la plantilla ha fallado: %s",

View file

@ -1200,7 +1200,7 @@
"38": "Trop de mots-clés mentionnés [%d], ajustez si nécessaire [Paramètres - Recherche - Mentions de backlink - Limite de mots-clés]",
"39": "Suppression de l'index %s",
"40": "Insertion de l'index %s",
"41": "Transfert complété",
"41": "Transfert complété [%d]",
"42": "Le paramétrage est terminé, l'application se fermera automatiquement, merci de redémarrer plus tard...",
"43": "La capacité de stockage maximale de l'espace cloud [%s] a été dépassée et le téléchargement des données ne peut pas continuer",
"44": "L'analyse du template a échoué : %s",

View file

@ -1200,7 +1200,7 @@
"38": "提及關鍵字數量 [%d] 過多,如有需要可以調整 [設置 - 搜索 - 反連提及 - 關鍵字數量限制]",
"39": "正在刪除索引 %s",
"40": "正在插入索引 %s",
"41": "上傳完畢",
"41": "上傳完畢 [%d]",
"42": "設置完成,即將自動關閉應用,請稍後重新啟動...",
"43": "已超過雲端空間最大存儲容量 [%s],無法繼續上傳資料",
"44": "範本解析失敗:%s",

View file

@ -1200,7 +1200,7 @@
"38": "提及关键字数量 [%d] 过多,如有需要可以调整 [设置 - 搜索 - 反链提及 - 关键字数量限制]",
"39": "正在删除索引 %s",
"40": "正在插入索引 %s",
"41": "上传完毕",
"41": "上传完毕 [%d]",
"42": "设置完成,即将自动关闭应用,请稍后重新启动...",
"43": "已超过云端空间最大存储容量 [%s],无法继续上传数据",
"44": "模板解析失败:%s",

View file

@ -35,6 +35,8 @@ Below are the detailed changes in this version.
* [Search and replace fails in some cases](https://github.com/siyuan-note/siyuan/issues/10016)
* [Reference jump is not located in read-only mode](https://github.com/siyuan-note/siyuan/issues/10028)
* [Converting PDF annotation ref to text fails after setting the appearance](https://github.com/siyuan-note/siyuan/issues/10029)
* [Pressing the scoring shortcut key immediately after `Alt+F` is invalid](https://github.com/siyuan-note/siyuan/issues/10020)
* [The images in the embed blocks are not uploaded to the community hosting](https://github.com/siyuan-note/siyuan/issues/10042)
### Development

View file

@ -35,6 +35,8 @@
* [某些情況下搜尋替換失效](https://github.com/siyuan-note/siyuan/issues/10016)
* [唯讀模式下引用跳轉後未定位瀏覽位置](https://github.com/siyuan-note/siyuan/issues/10028)
* [無法轉換外觀樣式的 PDF 註解引用為文字](https://github.com/siyuan-note/siyuan/issues/10029)
* [`Alt+F` 後快速按下評分快捷鍵失效](https://github.com/siyuan-note/siyuan/issues/10020)
* [在嵌入區塊中的圖片未能上傳社群](https://github.com/siyuan-note/siyuan/issues/10042)
### 開發者

View file

@ -35,6 +35,8 @@
* [某些情况下搜索替换失效](https://github.com/siyuan-note/siyuan/issues/10016)
* [只读模式下引用跳转后未定位浏览位置](https://github.com/siyuan-note/siyuan/issues/10028)
* [无法转换带外观样式的 PDF 注释引用为文本](https://github.com/siyuan-note/siyuan/issues/10029)
* [`Alt+F` 后快速按下评分快捷键失效](https://github.com/siyuan-note/siyuan/issues/10020)
* [在嵌入块中的图片未能上传社区](https://github.com/siyuan-note/siyuan/issues/10042)
### 开发者

View file

@ -17,6 +17,7 @@
package api
import (
"fmt"
"net/http"
"path/filepath"
"strings"
@ -257,14 +258,15 @@ func uploadCloud(c *gin.Context) {
}
rootID := arg["id"].(string)
err := model.UploadAssets2Cloud(rootID)
count, err := model.UploadAssets2Cloud(rootID)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
ret.Data = map[string]interface{}{"closeTimeout": 3000}
} else {
util.PushMsg(model.Conf.Language(41), 3000)
return
}
util.PushMsg(fmt.Sprintf(model.Conf.Language(41), count), 3000)
}
func insertLocalAssets(c *gin.Context) {

View file

@ -475,7 +475,7 @@ type ValueRollup struct {
Contents []*Value `json:"contents"`
}
func (r *ValueRollup) RenderContents(calc *RollupCalc) {
func (r *ValueRollup) RenderContents(calc *RollupCalc, destKey *Key) {
if nil == calc {
return
}
@ -531,103 +531,105 @@ func (r *ValueRollup) RenderContents(calc *RollupCalc) {
case CalcOperatorSum:
sum := 0.0
for _, v := range r.Contents {
if "" != v.String() {
n, _ := strconv.ParseFloat(v.String(), 64)
sum += n
if nil != v.Number {
sum += v.Number.Content
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(sum)}}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewFormattedValueNumber(sum, destKey.NumberFormat)}}
case CalcOperatorAverage:
sum := 0.0
count := 0
for _, v := range r.Contents {
if "" != v.String() {
n, _ := strconv.ParseFloat(v.String(), 64)
sum += n
if nil != v.Number {
sum += v.Number.Content
count++
}
}
if 0 < count {
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(sum / float64(count))}}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewFormattedValueNumber(sum/float64(count), destKey.NumberFormat)}}
}
case CalcOperatorMedian:
var numbers []float64
for _, v := range r.Contents {
if "" != v.String() {
n, _ := strconv.ParseFloat(v.String(), 64)
numbers = append(numbers, n)
if nil != v.Number {
numbers = append(numbers, v.Number.Content)
}
}
sort.Float64s(numbers)
if 0 < len(numbers) {
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(numbers[len(numbers)/2])}}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewFormattedValueNumber(numbers[len(numbers)/2], destKey.NumberFormat)}}
}
case CalcOperatorMin:
min := math.MaxFloat64
for _, v := range r.Contents {
if "" != v.String() {
n, _ := strconv.ParseFloat(v.String(), 64)
if n < min {
min = n
if nil != v.Number {
if v.Number.Content < min {
min = v.Number.Content
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(min)}}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewFormattedValueNumber(min, destKey.NumberFormat)}}
case CalcOperatorMax:
max := -math.MaxFloat64
for _, v := range r.Contents {
if "" != v.String() {
n, _ := strconv.ParseFloat(v.String(), 64)
if n > max {
max = n
if nil != v.Number {
if v.Number.Content > max {
max = v.Number.Content
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(max)}}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewFormattedValueNumber(max, destKey.NumberFormat)}}
case CalcOperatorRange:
min := math.MaxFloat64
max := -math.MaxFloat64
for _, v := range r.Contents {
if "" != v.String() {
n, _ := strconv.ParseFloat(v.String(), 64)
if n < min {
min = n
if nil != v.Number {
if v.Number.Content < min {
min = v.Number.Content
}
if n > max {
max = n
if v.Number.Content > max {
max = v.Number.Content
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(max - min)}}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewFormattedValueNumber(max-min, destKey.NumberFormat)}}
case CalcOperatorChecked:
countChecked := 0
for _, v := range r.Contents {
if "√" == v.String() {
countChecked++
if nil != v.Checkbox {
if v.Checkbox.Checked {
countChecked++
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(float64(countChecked))}}
case CalcOperatorUnchecked:
countUnchecked := 0
for _, v := range r.Contents {
if "√" != v.String() {
countUnchecked++
if nil != v.Checkbox {
if !v.Checkbox.Checked {
countUnchecked++
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(float64(countUnchecked))}}
case CalcOperatorPercentChecked:
countChecked := 0
for _, v := range r.Contents {
if "√" == v.String() {
countChecked++
if nil != v.Checkbox {
if v.Checkbox.Checked {
countChecked++
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(float64(countChecked * 100 / len(r.Contents)))}}
case CalcOperatorPercentUnchecked:
countUnchecked := 0
for _, v := range r.Contents {
if "√" != v.String() {
countUnchecked++
if nil != v.Checkbox {
if !v.Checkbox.Checked {
countUnchecked++
}
}
}
r.Contents = []*Value{{Type: KeyTypeNumber, Number: NewValueNumber(float64(countUnchecked * 100 / len(r.Contents)))}}

View file

@ -20,6 +20,7 @@ import (
"bytes"
"errors"
"fmt"
"github.com/88250/lute/editor"
"io"
"io/fs"
"mime"
@ -509,13 +510,25 @@ func GetAssetAbsPath(relativePath string) (ret string, err error) {
return "", errors.New(fmt.Sprintf(Conf.Language(12), relativePath))
}
func UploadAssets2Cloud(rootID string) (err error) {
func UploadAssets2Cloud(rootID string) (count int, err error) {
if !IsSubscriber() {
return
}
sqlAssets := sql.QueryRootBlockAssets(rootID)
err = uploadAssets2Cloud(sqlAssets, bizTypeUploadAssets)
tree, err := loadTreeByBlockID(rootID)
if nil != err {
return
}
assets := assetsLinkDestsInTree(tree)
embedAssets := assetsLinkDestsInQueryEmbedNodes(tree)
assets = append(assets, embedAssets...)
assets = gulu.Str.RemoveDuplicatedElem(assets)
err = uploadAssets2Cloud(assets, bizTypeUploadAssets)
if nil != err {
return
}
count = len(assets)
return
}
@ -525,17 +538,17 @@ const (
)
// uploadAssets2Cloud 将资源文件上传到云端图床。
func uploadAssets2Cloud(sqlAssets []*sql.Asset, bizType string) (err error) {
func uploadAssets2Cloud(assetPaths []string, bizType string) (err error) {
var uploadAbsAssets []string
for _, asset := range sqlAssets {
for _, assetPath := range assetPaths {
var absPath string
absPath, err = GetAssetAbsPath(asset.Path)
absPath, err = GetAssetAbsPath(assetPath)
if nil != err {
logging.LogWarnf("get asset [%s] abs path failed: %s", asset, err)
logging.LogWarnf("get asset [%s] abs path failed: %s", assetPath, err)
return
}
if "" == absPath {
logging.LogErrorf("not found asset [%s]", asset)
logging.LogErrorf("not found asset [%s]", assetPath)
continue
}
@ -1044,9 +1057,45 @@ func emojisInTree(tree *parse.Tree) (ret []string) {
return
}
func assetsLinkDestsInTree(tree *parse.Tree) (ret []string) {
func assetsLinkDestsInQueryEmbedNodes(tree *parse.Tree) (ret []string) {
// The images in the embed blocks are not uploaded to the community hosting https://github.com/siyuan-note/siyuan/issues/10042
ret = []string{}
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering || ast.NodeBlockQueryEmbedScript != n.Type {
return ast.WalkContinue
}
stmt := n.TokensStr()
stmt = html.UnescapeString(stmt)
stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
sqlBlocks := sql.SelectBlocksRawStmt(stmt, 1, Conf.Search.Limit)
for _, sqlBlock := range sqlBlocks {
subtree, _ := loadTreeByBlockID(sqlBlock.ID)
if nil == subtree {
continue
}
embedNode := treenode.GetNodeInTree(subtree, sqlBlock.ID)
if nil == embedNode {
continue
}
ret = append(ret, assetsLinkDestsInNode(embedNode)...)
}
return ast.WalkContinue
})
ret = gulu.Str.RemoveDuplicatedElem(ret)
return
}
func assetsLinkDestsInTree(tree *parse.Tree) (ret []string) {
ret = assetsLinkDestsInNode(tree.Root)
return
}
func assetsLinkDestsInNode(node *ast.Node) (ret []string) {
ret = []string{}
ast.Walk(node, func(n *ast.Node, entering bool) ast.WalkStatus {
// 修改以下代码时需要同时修改 database 构造行级元素实现,增加必要的类型
if !entering || (ast.NodeLinkDest != n.Type && ast.NodeHTMLBlock != n.Type && ast.NodeInlineHTML != n.Type &&
ast.NodeIFrame != n.Type && ast.NodeWidget != n.Type && ast.NodeAudio != n.Type && ast.NodeVideo != n.Type &&
@ -1103,7 +1152,7 @@ func assetsLinkDestsInTree(tree *parse.Tree) (ret []string) {
dest := strings.TrimSpace(string(src))
ret = append(ret, dest)
} else {
logging.LogWarnf("src is missing the closing double quote in tree [%s] ", tree.Box+tree.Path)
logging.LogWarnf("src is missing the closing double quote in tree [%s] ", node.Box+node.Path)
}
}
}

View file

@ -243,26 +243,22 @@ func GetBlockAttributeViewKeys(blockID string) (ret []*BlockAttributeViewKeys) {
relVal := attrView.GetValue(kv.Key.Rollup.RelationKeyID, kv.Values[0].BlockID)
if nil != relVal && nil != relVal.Relation {
destAv, _ := av.ParseAttributeView(relKey.Relation.AvID)
if nil != destAv {
destKey, _ := destAv.GetKey(kv.Key.Rollup.KeyID)
if nil != destAv && nil != destKey {
for _, bID := range relVal.Relation.BlockIDs {
destVal := destAv.GetValue(kv.Key.Rollup.KeyID, bID)
if nil == destVal {
destKey, _ := destAv.GetKey(kv.Key.Rollup.KeyID)
if nil == destKey {
continue
}
destVal = treenode.GetAttributeViewDefaultValue(ast.NewNodeID(), kv.Key.Rollup.KeyID, blockID, destKey.Type)
}
if av.KeyTypeNumber == destVal.Type {
destVal.Number.Format = kv.Key.NumberFormat
if av.KeyTypeNumber == destKey.Type {
destVal.Number.Format = destKey.NumberFormat
destVal.Number.FormatNumber()
}
kv.Values[0].Rollup.Contents = append(kv.Values[0].Rollup.Contents, destVal.Clone())
kv.Values[0].Rollup.RenderContents(kv.Key.Rollup.Calc)
}
kv.Values[0].Rollup.RenderContents(kv.Key.Rollup.Calc, destKey)
}
}
case av.KeyTypeRelation:
@ -817,25 +813,25 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *a
break
}
destKey, _ := destAv.GetKey(rollupKey.Rollup.KeyID)
if nil == destKey {
continue
}
for _, blockID := range relVal.Relation.BlockIDs {
destVal := destAv.GetValue(rollupKey.Rollup.KeyID, blockID)
if nil == destVal {
destKey, _ := destAv.GetKey(rollupKey.Rollup.KeyID)
if nil == destKey {
continue
}
destVal = treenode.GetAttributeViewDefaultValue(ast.NewNodeID(), rollupKey.Rollup.KeyID, blockID, destKey.Type)
}
if av.KeyTypeNumber == destVal.Type {
destVal.Number.Format = rollupKey.NumberFormat
if av.KeyTypeNumber == destKey.Type {
destVal.Number.Format = destKey.NumberFormat
destVal.Number.FormatNumber()
}
cell.Value.Rollup.Contents = append(cell.Value.Rollup.Contents, destVal.Clone())
}
cell.Value.Rollup.RenderContents(rollupKey.Rollup.Calc)
cell.Value.Rollup.RenderContents(rollupKey.Rollup.Calc, destKey)
case av.KeyTypeRelation: // 渲染关联列
relKey, _ := attrView.GetKey(cell.Value.KeyID)
if nil != relKey && nil != relKey.Relation {

View file

@ -780,12 +780,17 @@ func IsSubscriber() bool {
}
func IsPaidUser() bool {
// S3/WebDAV data sync and backup are available for a fee https://github.com/siyuan-note/siyuan/issues/8780
if IsSubscriber() {
return true
}
return nil != Conf.GetUser() // Sign in to use S3/WebDAV data sync https://github.com/siyuan-note/siyuan/issues/8779
// TODO S3/WebDAV data sync and backup are available for a fee https://github.com/siyuan-note/siyuan/issues/8780
// return nil != Conf.User && 1 == Conf.User.UserSiYuanOneTimePayStatus
u := Conf.GetUser()
if nil == u {
return false
}
return 1 == u.UserSiYuanOneTimePayStatus
}
const (

View file

@ -67,8 +67,11 @@ func Export2Liandi(id string) (err error) {
return errors.New(Conf.Language(204))
}
sqlAssets := sql.QueryRootBlockAssets(id)
err = uploadAssets2Cloud(sqlAssets, bizTypeExport2Liandi)
assets := assetsLinkDestsInTree(tree)
embedAssets := assetsLinkDestsInQueryEmbedNodes(tree)
assets = append(assets, embedAssets...)
assets = gulu.Str.RemoveDuplicatedElem(assets)
err = uploadAssets2Cloud(assets, bizTypeExport2Liandi)
if nil != err {
return
}

View file

@ -115,21 +115,6 @@ func QueryAssetByHash(hash string) (ret *Asset) {
return
}
func QueryRootBlockAssets(rootID string) (ret []*Asset) {
sqlStmt := "SELECT * FROM assets WHERE root_id = ?"
rows, err := query(sqlStmt, rootID)
if nil != err {
logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
return
}
defer rows.Close()
for rows.Next() {
asset := scanAssetRows(rows)
ret = append(ret, asset)
}
return
}
func scanAssetRows(rows *sql.Rows) (ret *Asset) {
var asset Asset
if err := rows.Scan(&asset.ID, &asset.BlockID, &asset.RootID, &asset.Box, &asset.DocPath, &asset.Path, &asset.Name, &asset.Title, &asset.Hash); nil != err {

View file

@ -774,25 +774,25 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *a
break
}
destKey, _ := destAv.GetKey(rollupKey.Rollup.KeyID)
if nil == destKey {
continue
}
for _, blockID := range relVal.Relation.BlockIDs {
destVal := destAv.GetValue(rollupKey.Rollup.KeyID, blockID)
if nil == destVal {
destKey, _ := destAv.GetKey(rollupKey.Rollup.KeyID)
if nil == destKey {
continue
}
destVal = GetAttributeViewDefaultValue(ast.NewNodeID(), rollupKey.Rollup.KeyID, blockID, destKey.Type)
}
if av.KeyTypeNumber == destVal.Type {
destVal.Number.Format = rollupKey.NumberFormat
if av.KeyTypeNumber == destKey.Type {
destVal.Number.Format = destKey.NumberFormat
destVal.Number.FormatNumber()
}
cell.Value.Rollup.Contents = append(cell.Value.Rollup.Contents, destVal.Clone())
}
cell.Value.Rollup.RenderContents(rollupKey.Rollup.Calc)
cell.Value.Rollup.RenderContents(rollupKey.Rollup.Calc, destKey)
case av.KeyTypeRelation: // 渲染关联列
relKey, _ := attrView.GetKey(cell.Value.KeyID)
if nil != relKey && nil != relKey.Relation {