2024-01-02 08:29:18 +08:00
|
|
|
package store
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-01-03 08:31:59 +08:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
2024-01-02 08:29:18 +08:00
|
|
|
"strings"
|
|
|
|
|
2024-01-28 07:58:53 +08:00
|
|
|
"github.com/lithammer/shortuuid/v4"
|
2024-01-02 08:29:18 +08:00
|
|
|
"github.com/pkg/errors"
|
2024-01-03 08:31:59 +08:00
|
|
|
|
|
|
|
"github.com/usememos/memos/internal/log"
|
2024-01-02 08:29:18 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// MigrateResourceInternalPath migrates resource internal path from absolute path to relative path.
|
|
|
|
func (s *Store) MigrateResourceInternalPath(ctx context.Context) error {
|
|
|
|
resources, err := s.ListResources(ctx, &FindResource{})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to list resources")
|
|
|
|
}
|
|
|
|
|
2024-01-03 08:31:59 +08:00
|
|
|
dataPath := strings.ReplaceAll(s.Profile.Data, `\`, "/")
|
|
|
|
migrateStartTime := time.Now()
|
|
|
|
migratedCount := 0
|
2024-01-02 08:29:18 +08:00
|
|
|
for _, resource := range resources {
|
|
|
|
if resource.InternalPath == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-01-03 08:31:59 +08:00
|
|
|
internalPath := strings.ReplaceAll(resource.InternalPath, `\`, "/")
|
|
|
|
if !strings.HasPrefix(internalPath, dataPath) {
|
|
|
|
continue
|
2024-01-02 08:29:18 +08:00
|
|
|
}
|
2024-01-03 08:31:59 +08:00
|
|
|
|
|
|
|
internalPath = strings.TrimPrefix(internalPath, dataPath)
|
|
|
|
|
|
|
|
for os.IsPathSeparator(internalPath[0]) {
|
|
|
|
internalPath = internalPath[1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := s.UpdateResource(ctx, &UpdateResource{
|
|
|
|
ID: resource.ID,
|
|
|
|
InternalPath: &internalPath,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to update local resource path")
|
|
|
|
}
|
|
|
|
migratedCount++
|
2024-01-02 08:29:18 +08:00
|
|
|
}
|
|
|
|
|
2024-01-06 16:55:13 +08:00
|
|
|
if migratedCount > 0 && s.Profile.Mode == "prod" {
|
2024-01-03 08:31:59 +08:00
|
|
|
log.Info(fmt.Sprintf("migrated %d local resource paths in %s", migratedCount, time.Since(migrateStartTime)))
|
|
|
|
}
|
2024-01-02 08:29:18 +08:00
|
|
|
return nil
|
|
|
|
}
|
2024-01-28 07:58:53 +08:00
|
|
|
|
|
|
|
// MigrateResourceName migrates resource name from other format to short UUID.
|
|
|
|
func (s *Store) MigrateResourceName(ctx context.Context) error {
|
|
|
|
memos, err := s.ListMemos(ctx, &FindMemo{})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to list memos")
|
|
|
|
}
|
|
|
|
for _, memo := range memos {
|
|
|
|
if checkResourceName(memo.ResourceName) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
resourceName := shortuuid.New()
|
|
|
|
err := s.UpdateMemo(ctx, &UpdateMemo{
|
|
|
|
ID: memo.ID,
|
|
|
|
ResourceName: &resourceName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to update memo")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resources, err := s.ListResources(ctx, &FindResource{})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to list resources")
|
|
|
|
}
|
|
|
|
for _, resource := range resources {
|
|
|
|
if checkResourceName(resource.ResourceName) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
resourceName := shortuuid.New()
|
|
|
|
_, err := s.UpdateResource(ctx, &UpdateResource{
|
|
|
|
ID: resource.ID,
|
|
|
|
ResourceName: &resourceName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to update resource")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkResourceName(resourceName string) bool {
|
|
|
|
// 22 is the length of shortuuid.
|
|
|
|
if len(resourceName) != 22 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for _, c := range resourceName {
|
|
|
|
if c >= '0' && c <= '9' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if c >= 'a' && c <= 'z' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if c >= 'A' && c <= 'Z' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|