Files
hnh-map/internal/app/migrations.go
Nikolay Tatarinov 8f769543f4 Refactor frontend components and enhance API integration
- Updated frontend-nuxt.mdc to specify usage of composables for API calls.
- Added new AuthCard and ConfirmModal components for improved UI consistency.
- Introduced UserAvatar component for user profile display, replacing previous Gravatar implementation.
- Implemented useFormSubmit composable for handling form submissions with loading and error states.
- Enhanced vitest.config.ts to include coverage reporting for composables and components.
- Removed deprecated useAdminApi and useAuth composables to streamline API interactions.
- Updated login and setup pages to utilize new components and composables for better user experience.
2026-03-04 00:14:05 +03:00

205 lines
4.7 KiB
Go

package app
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/andyleap/hnh-map/internal/app/store"
"go.etcd.io/bbolt"
)
var migrations = []func(tx *bbolt.Tx) error{
func(tx *bbolt.Tx) error {
if tx.Bucket(store.BucketMarkers) != nil {
return tx.DeleteBucket(store.BucketMarkers)
}
return nil
},
func(tx *bbolt.Tx) error {
grids, err := tx.CreateBucketIfNotExists(store.BucketGrids)
if err != nil {
return err
}
tiles, err := tx.CreateBucketIfNotExists(store.BucketTiles)
if err != nil {
return err
}
zoom, err := tiles.CreateBucketIfNotExists([]byte(strconv.Itoa(0)))
if err != nil {
return err
}
return grids.ForEach(func(k, v []byte) error {
g := GridData{}
err := json.Unmarshal(v, &g)
if err != nil {
return err
}
td := &TileData{
Coord: g.Coord,
Zoom: 0,
File: fmt.Sprintf("0/%s", g.Coord.Name()),
Cache: time.Now().UnixNano(),
}
raw, err := json.Marshal(td)
if err != nil {
return err
}
return zoom.Put([]byte(g.Coord.Name()), raw)
})
},
func(tx *bbolt.Tx) error {
b, err := tx.CreateBucketIfNotExists(store.BucketConfig)
if err != nil {
return err
}
return b.Put([]byte("title"), []byte("HnH Automapper Server"))
},
func(tx *bbolt.Tx) error {
// No-op: markers deletion already in migration 0
return nil
},
func(tx *bbolt.Tx) error {
if tx.Bucket(store.BucketTiles) != nil {
allTiles := map[string]map[string]TileData{}
tiles := tx.Bucket(store.BucketTiles)
err := tiles.ForEach(func(k, v []byte) error {
zoom := tiles.Bucket(k)
zoomTiles := map[string]TileData{}
allTiles[string(k)] = zoomTiles
return zoom.ForEach(func(tk, tv []byte) error {
td := TileData{}
if err := json.Unmarshal(tv, &td); err != nil {
return err
}
zoomTiles[string(tk)] = td
return nil
})
})
if err != nil {
return err
}
err = tx.DeleteBucket(store.BucketTiles)
if err != nil {
return err
}
tiles, err = tx.CreateBucket(store.BucketTiles)
if err != nil {
return err
}
maptiles, err := tiles.CreateBucket([]byte("0"))
if err != nil {
return err
}
for k, v := range allTiles {
zoom, err := maptiles.CreateBucket([]byte(k))
if err != nil {
return err
}
for tk, tv := range v {
raw, _ := json.Marshal(tv)
err = zoom.Put([]byte(strings.TrimSuffix(tk, ".png")), raw)
if err != nil {
return err
}
}
}
err = tiles.SetSequence(1)
if err != nil {
return err
}
}
return nil
},
func(tx *bbolt.Tx) error {
// No-op: markers deletion already in migration 0
return nil
},
func(tx *bbolt.Tx) error {
highest := uint64(0)
maps, err := tx.CreateBucketIfNotExists(store.BucketMaps)
if err != nil {
return err
}
grids, err := tx.CreateBucketIfNotExists(store.BucketGrids)
if err != nil {
return err
}
mapsFound := map[int]struct{}{}
err = grids.ForEach(func(k, v []byte) error {
gd := GridData{}
err := json.Unmarshal(v, &gd)
if err != nil {
return err
}
if _, ok := mapsFound[gd.Map]; !ok {
mapsFound[gd.Map] = struct{}{}
if uint64(gd.Map) > highest {
highest = uint64(gd.Map)
}
mi := MapInfo{
ID: gd.Map,
Name: strconv.Itoa(gd.Map),
Hidden: false,
}
raw, _ := json.Marshal(mi)
return maps.Put([]byte(strconv.Itoa(gd.Map)), raw)
}
return nil
})
if err != nil {
return err
}
return maps.SetSequence(highest + 1)
},
func(tx *bbolt.Tx) error {
users := tx.Bucket(store.BucketUsers)
if users == nil {
return nil
}
return users.ForEach(func(k, v []byte) error {
u := User{}
if err := json.Unmarshal(v, &u); err != nil {
return err
}
if u.Auths.Has(AUTH_MAP) && !u.Auths.Has(AUTH_MARKERS) {
u.Auths = append(u.Auths, AUTH_MARKERS)
raw, err := json.Marshal(u)
if err != nil {
return err
}
users.Put(k, raw)
}
return nil
})
},
func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(store.BucketOAuthStates)
return err
},
}
// RunMigrations runs all pending migrations on the database.
func RunMigrations(db *bbolt.DB) error {
return db.Update(func(tx *bbolt.Tx) error {
b, err := tx.CreateBucketIfNotExists(store.BucketConfig)
if err != nil {
return err
}
vraw := b.Get([]byte("version"))
v, _ := strconv.Atoi(string(vraw))
if v < len(migrations) {
for _, f := range migrations[v:] {
if err := f(tx); err != nil {
return err
}
}
}
return b.Put([]byte("version"), []byte(strconv.Itoa(len(migrations))))
})
}