Files
hnh-map/internal/app/migrations.go
Nikolay Tatarinov 2c7bf48719 Implement OAuth login functionality and enhance documentation
- Added support for Google OAuth login, including new API endpoints for OAuth providers and callbacks.
- Updated user authentication logic to handle OAuth-only users.
- Enhanced README.md and deployment documentation with OAuth setup instructions.
- Modified frontend components to include OAuth login options and improved error handling.
- Updated configuration files to include new environment variables for OAuth integration.
2026-02-25 00:26:38 +03:00

203 lines
4.6 KiB
Go

package app
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"go.etcd.io/bbolt"
)
var migrations = []func(tx *bbolt.Tx) error{
func(tx *bbolt.Tx) error {
if tx.Bucket([]byte("markers")) != nil {
return tx.DeleteBucket([]byte("markers"))
}
return nil
},
func(tx *bbolt.Tx) error {
grids, err := tx.CreateBucketIfNotExists([]byte("grids"))
if err != nil {
return err
}
tiles, err := tx.CreateBucketIfNotExists([]byte("tiles"))
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([]byte("config"))
if err != nil {
return err
}
return b.Put([]byte("title"), []byte("HnH Automapper Server"))
},
func(tx *bbolt.Tx) error {
if tx.Bucket([]byte("markers")) != nil {
return tx.DeleteBucket([]byte("markers"))
}
return nil
},
func(tx *bbolt.Tx) error {
if tx.Bucket([]byte("tiles")) != nil {
allTiles := map[string]map[string]TileData{}
tiles := tx.Bucket([]byte("tiles"))
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{}
json.Unmarshal(tv, &td)
zoomTiles[string(tk)] = td
return nil
})
})
if err != nil {
return err
}
err = tx.DeleteBucket([]byte("tiles"))
if err != nil {
return err
}
tiles, err = tx.CreateBucket([]byte("tiles"))
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 {
if tx.Bucket([]byte("markers")) != nil {
return tx.DeleteBucket([]byte("markers"))
}
return nil
},
func(tx *bbolt.Tx) error {
highest := uint64(0)
maps, err := tx.CreateBucketIfNotExists([]byte("maps"))
if err != nil {
return err
}
grids, err := tx.CreateBucketIfNotExists([]byte("grids"))
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 {
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([]byte("users"))
if users == nil {
return nil
}
return users.ForEach(func(k, v []byte) error {
u := User{}
json.Unmarshal(v, &u)
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([]byte("oauth_states"))
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([]byte("config"))
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))))
})
}