diff --git a/go.mod b/go.mod index f5ec84e1f..f03faaa54 100644 --- a/go.mod +++ b/go.mod @@ -178,6 +178,7 @@ require ( google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + mvdan.cc/xurls/v2 v2.5.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index adbc6af42..1d5ac6a7f 100644 --- a/go.sum +++ b/go.sum @@ -757,6 +757,8 @@ modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE= modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= +mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= +mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/pkg/migration/20240114224713.go b/pkg/migration/20240114224713.go new file mode 100644 index 000000000..45ff861a6 --- /dev/null +++ b/pkg/migration/20240114224713.go @@ -0,0 +1,105 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public Licensee as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public Licensee for more details. +// +// You should have received a copy of the GNU Affero General Public Licensee +// along with this program. If not, see . + +package migration + +import ( + "strings" + + "mvdan.cc/xurls/v2" + "src.techknowlogick.com/xormigrate" + "xorm.io/xorm" +) + +func convertLinksToHTMLElements(input string) (output string) { + + links := xurls.Strict().FindAllString(input, -1) + + if len(links) == 0 { + return input + } + + unique := make(map[string]bool) + for _, link := range links { + unique[link] = true + } + + for link := range unique { + + if strings.Contains(input, `href="`+link) { + continue + } + + input = strings.ReplaceAll(input, link, ``+link+``) + } + + return input +} + +func convertDescriptionToLinks(tx *xorm.Engine, table string, column string) (err error) { + items := []map[string]interface{}{} + err = tx.Table(table). + Select("id, " + column). + Find(&items) + if err != nil { + return + } + + for _, task := range items { + if task[column] == "" || task[column] == "

" { + continue + } + + task[column] = convertLinksToHTMLElements(task[column].(string)) + _, err = tx.Where("id = ?", task["id"]). + Table(table). + Cols(column). + Update(task) + if err != nil { + return + } + } + + return +} + +func init() { + migrations = append(migrations, &xormigrate.Migration{ + ID: "20240114224713", + Description: "Convert all non-html links to html a href", + Migrate: func(tx *xorm.Engine) (err error) { + + for _, table := range []string{ + "tasks", + "labels", + "projects", + "saved_filters", + "teams", + } { + err = convertDescriptionToLinks(tx, table, "description") + if err != nil { + return + } + } + + err = convertDescriptionToLinks(tx, "task_comments", "comment") + return + }, + Rollback: func(tx *xorm.Engine) error { + return nil + }, + }) +}