backend token logic

This commit is contained in:
Iris Lightshard 2023-07-07 23:56:41 -06:00
parent f4513a28f7
commit 01fccb55f0
Signed by: nilix
GPG key ID: 3B7FBC22144E6398
11 changed files with 313 additions and 132 deletions

View file

@ -48,8 +48,7 @@ func apiGetTableData(next http.Handler, udb auth.UserStore, dbAdapter mongodb.Db
if dbAdapter.CheckTable(tableKey) {
mapUrl, _ := dbAdapter.GetMapImageUrl(tableKey)
auxMessage, _ := dbAdapter.GetAuxMessage(tableKey)
availableTokens, _ := dbAdapter.GetTokens(tableKey, true)
activeTokens, _ := dbAdapter.GetTokens(tableKey, false)
tokens, _ := dbAdapter.GetTokens(tableKey, true)
diceRolls, _ := dbAdapter.GetDiceRolls(tableKey)
AddContextValue(req, "tableData", models.Table{
@ -57,8 +56,7 @@ func apiGetTableData(next http.Handler, udb auth.UserStore, dbAdapter mongodb.Db
Passcode: tableKey.Passcode,
DiceRolls: diceRolls,
MapImageUrl: mapUrl,
Tokens: activeTokens,
AvailableTokens: availableTokens,
Tokens: tokens,
AuxMessage: auxMessage,
})
} else {

View file

@ -192,8 +192,7 @@ func (self *GameTableServer) getCurrentState(tableKey models.TableKey) []byte {
if self.dbAdapter.CheckTable(tableKey) {
mapUrl, _ := self.dbAdapter.GetMapImageUrl(tableKey)
auxMessage, _ := self.dbAdapter.GetAuxMessage(tableKey)
availableTokens, _ := self.dbAdapter.GetTokens(tableKey, true)
activeTokens, _ := self.dbAdapter.GetTokens(tableKey, false)
tokens, _ := self.dbAdapter.GetTokens(tableKey, false)
diceRolls, _ := self.dbAdapter.GetDiceRolls(tableKey)
table := models.Table{
@ -201,8 +200,7 @@ func (self *GameTableServer) getCurrentState(tableKey models.TableKey) []byte {
Passcode: tableKey.Passcode,
DiceRolls: diceRolls,
MapImageUrl: mapUrl,
Tokens: activeTokens,
AvailableTokens: availableTokens,
Tokens: tokens,
AuxMessage: auxMessage,
}
data, err := json.Marshal(table)
@ -223,8 +221,41 @@ func (self *GameTableServer) writeToDB(tableMsg *models.TableMessage) error {
return err
}
}
if tableMsg.Token != nil && tableMsg.Token.Id != nil {
t := *tableMsg.Token
exists, active := self.dbAdapter.CheckToken(key, *t.Id)
if exists {
if active {
if !t.Active {
err := self.dbAdapter.ActivateToken(key, *t.Id, false)
if err != nil {
return err
}
tableMsg.Token.X = nil
tableMsg.Token.Y = nil
} else if t.X != nil && t.Y != nil {
err := self.dbAdapter.MoveToken(key, t)
if err != nil {
return err
}
}
} else {
if t.Active {
err := self.dbAdapter.ActivateToken(key, *t.Id, true)
if err != nil {
return err
}
}
}
} else {
// respond to nonextant IDs as if they were destroyed
tableMsg.Token.X = nil
tableMsg.Token.Y = nil
tableMsg.Token.Active = false
}
}
// map image change, aux message, and token addition/removal require admin authorization
// map image change, aux message, and token creation/deletion require admin authorization
if tableMsg.Auth != nil {
authorized, _ := self.udb.ValidateToken(*tableMsg.Auth)
if authorized {
@ -240,6 +271,22 @@ func (self *GameTableServer) writeToDB(tableMsg *models.TableMessage) error {
return err
}
}
if tableMsg.Token != nil {
t := *tableMsg.Token
if t.Id == nil {
id, err := self.dbAdapter.CreateToken(key, t)
if err == nil {
*tableMsg.Token.Id = id
} else {
return err
}
} else {
if t.X == nil && t.Y == nil && !t.Active {
err := self.dbAdapter.DestroyToken(key, *t.Id)
return err
}
}
}
}
}
return nil

10
go.mod
View file

@ -3,7 +3,7 @@ module hacklab.nilfm.cc/felt
go 1.19
require (
go.mongodb.org/mongo-driver v1.11.0
go.mongodb.org/mongo-driver v1.12.0
golang.org/x/time v0.1.0
hacklab.nilfm.cc/quartzgun v0.3.0
nhooyr.io/websocket v1.8.7
@ -15,10 +15,10 @@ require (
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/text v0.7.0 // indirect
)

30
go.sum
View file

@ -55,6 +55,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -68,31 +69,60 @@ github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE=
go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE=
go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -18,11 +18,16 @@ type DiceRoll struct {
}
type Token struct {
Id string `json:"id"`
Id *string `json:"id" bson:"_id"`
Name string `json:"name"`
SpriteUri string `json:"spriteUrl"`
Sprite string `json:"sprite"`
W int `json:"w"`
H int `json:"h"`
OX int `json:"oX"`
OY int `json:"oY"`
X *int `json:"x"`
Y *int `json:"y"`
Active bool `json:"active"`
}
type Table struct {
@ -31,7 +36,6 @@ type Table struct {
MapImageUrl string `json:"mapImg"`
DiceRolls []DiceRoll `json:"diceRolls"`
Tokens []Token `json:"tokens"`
AvailableTokens []Token `json:"availableTokens"`
AuxMessage string `json:"auxMsg"`
}

View file

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"hacklab.nilfm.cc/felt/models"
@ -14,7 +15,9 @@ import (
const errNoCollection string = "collection not found: felt.%s"
const errNoDocument string = "document with name/id '%s' doesn't exist in collection: %s"
const errNotAString string = "document property is not a string: %s<key=%s>.%s"
const errNotAnArray string = "doccument property is not an array: %s<key=%s>.%s"
const errNotAnArray string = "document property is not an array: %s<key=%s>.%s"
const ErrNotFound string = "this token doesn't exist at this table; forget about it"
type DbAdapter interface {
Init(mongoUri string) error
@ -34,10 +37,12 @@ type DbAdapter interface {
SetAuxMessage(table models.TableKey, message string) error
GetAuxMessage(table models.TableKey) (string, error)
AddToken(table models.TableKey, token models.Token, active bool) error
RemoveToken(table models.TableKey, tokenId string, active bool) error
ModifyToken(table models.TableKey, token models.Token, active bool) error
GetTokens(table models.TableKey, active bool) ([]models.Token, error)
CheckToken(table models.TableKey, tokenId string) (bool, bool)
CreateToken(table models.TableKey, token models.Token) (string, error)
ActivateToken(table models.TableKey, tokenId string, active bool) error
MoveToken(table models.TableKey, token models.Token) error
DestroyToken(table models.TableKey, tokenId string) error
GetTokens(table models.TableKey, activeOnly bool) ([]models.Token, error)
}
type DbEngine struct {
@ -284,13 +289,37 @@ func (self *DbEngine) GetAuxMessage(table models.TableKey) (string, error) {
return "", errors.New(fmt.Sprintf(errNoCollection, "tables"))
}
func (self *DbEngine) AddToken(table models.TableKey, token models.Token, active bool) error {
func (self *DbEngine) CheckToken(table models.TableKey, tokenId string) (bool, bool) {
mongoId, err := primitive.ObjectIDFromHex(tokenId)
if err != nil {
return false, false
}
tables := self.db.Collection("tables")
if tables != nil {
tokenArrKey := "tokens"
if !active {
tokenArrKey = "availableTokens"
result := models.Table{}
err := tables.FindOne(self.mkCtx(10), bson.D{
{"name", table.Name},
{"passcode", table.Passcode},
{"tokens", bson.E{"_id", mongoId}},
}).Decode(&result)
if err != nil {
return false, false
} else {
active := false
for _, t := range result.Tokens {
if *t.Id == tokenId && t.Active {
active = true
}
}
return true, active
}
}
return false, false
}
func (self *DbEngine) CreateToken(table models.TableKey, token models.Token) (string, error) {
tables := self.db.Collection("tables")
if tables != nil {
var result models.Table
err := tables.FindOneAndUpdate(
self.mkCtx(10),
@ -299,7 +328,39 @@ func (self *DbEngine) AddToken(table models.TableKey, token models.Token, active
{"passcode", table.Passcode},
},
bson.D{
{"$push", bson.D{{tokenArrKey, token}}},
{"$push", bson.D{{"tokens", token}}},
},
).Decode(&result)
if err == nil {
newId := result.Tokens[len(result.Tokens)-1].Id
return *newId, nil
} else {
return "", err
}
}
return "", errors.New(fmt.Sprintf(errNoCollection, "tables"))
}
func (self *DbEngine) ActivateToken(table models.TableKey, tokenId string, active bool) error {
mongoId, err := primitive.ObjectIDFromHex(tokenId)
if err != nil {
return err
}
tables := self.db.Collection("tables")
if tables != nil {
var result models.Table
err := tables.FindOneAndUpdate(
self.mkCtx(10),
bson.D{
{"name", table.Name},
{"passcode", table.Passcode},
{"tokens", bson.E{"_id", mongoId}},
},
bson.D{
{"$set", bson.D{{"tokens.$", bson.D{
{"active", active},
}}}},
},
).Decode(&result)
return err
@ -307,48 +368,23 @@ func (self *DbEngine) AddToken(table models.TableKey, token models.Token, active
return errors.New(fmt.Sprintf(errNoCollection, "tables"))
}
func (self *DbEngine) RemoveToken(table models.TableKey, tokenId string, active bool) error {
tables := self.db.Collection("tables")
if tables != nil {
tokenArrKey := "tokens"
if !active {
tokenArrKey = "availableTokens"
}
var result models.Table
err := tables.FindOneAndUpdate(
self.mkCtx(10),
bson.D{
{"name", table.Name},
{"passcode", table.Passcode},
},
bson.D{
{"$pull", bson.D{{tokenArrKey, bson.D{{"_id", tokenId}}}}},
},
).Decode(&result)
func (self *DbEngine) MoveToken(table models.TableKey, token models.Token) error {
mongoId, err := primitive.ObjectIDFromHex(*token.Id)
if err != nil {
return err
}
return errors.New(fmt.Sprintf(errNoCollection, "tables"))
}
func (self *DbEngine) ModifyToken(table models.TableKey, token models.Token, active bool) error {
tables := self.db.Collection("tables")
if tables != nil {
tokenArrKey := "tokens"
if !active {
tokenArrKey = "availableTokens"
}
var result models.Table
err := tables.FindOneAndUpdate(
self.mkCtx(10),
bson.D{
{"name", table.Name},
{"passcode", table.Passcode},
{tokenArrKey, bson.E{"_id", token.Id}},
{"tokens", bson.E{"_id", mongoId}},
},
bson.D{
{"$set", bson.D{{tokenArrKey + ".$", bson.D{
{"name", token.Name},
{"spriteUri", token.SpriteUri},
{"$set", bson.D{{"tokens.$", bson.D{
{"x", token.X},
{"y", token.Y},
}}}},
@ -359,7 +395,30 @@ func (self *DbEngine) ModifyToken(table models.TableKey, token models.Token, act
return errors.New(fmt.Sprintf(errNoCollection, "tables"))
}
func (self *DbEngine) GetTokens(table models.TableKey, active bool) ([]models.Token, error) {
func (self *DbEngine) DestroyToken(table models.TableKey, tokenId string) error {
mongoId, err := primitive.ObjectIDFromHex(tokenId)
if err != nil {
return err
}
tables := self.db.Collection("tables")
if tables != nil {
var result models.Table
err := tables.FindOneAndUpdate(
self.mkCtx(10),
bson.D{
{"name", table.Name},
{"passcode", table.Passcode},
},
bson.D{
{"$pull", bson.D{{"tokens", bson.D{{"_id", mongoId}}}}},
},
).Decode(&result)
return err
}
return errors.New(fmt.Sprintf(errNoCollection, "tables"))
}
func (self *DbEngine) GetTokens(table models.TableKey, activeOnly bool) ([]models.Token, error) {
tables := self.db.Collection("tables")
if tables != nil {
var result models.Table
@ -370,11 +429,14 @@ func (self *DbEngine) GetTokens(table models.TableKey, active bool) ([]models.To
{"passcode", table.Passcode},
}).Decode(&result)
if err == nil {
if active {
return result.Tokens, nil
} else {
return result.AvailableTokens, nil
tokens := []models.Token{}
for _, t := range result.Tokens {
if !activeOnly || t.Active {
tokens = append(tokens, t)
}
}
return tokens, nil
} else {
return nil, errors.New(fmt.Sprintf(errNoDocument, table.Name, "tables"))
}

View file

@ -16,6 +16,7 @@ const tokenCY = document.getElementById("token_cy");
const previewZone = document.getElementById("tokenPreview_zone");
const tokenAspect = document.getElementById("tokenKeepAspect");
const aspectLockLabel = document.getElementById("aspectLockLabel");
const tokenZone = document.getElementById("tokenZone");
async function getTable(name, pass) {
try {
@ -41,8 +42,9 @@ async function getTable(name, pass) {
document.getElementById("input_table_name").value = name;
document.getElementById("input_table_pass").value = pass;
dial();
const table = await res.json()
infoHtml = "<a href='#' onclick='getTables()'>&larr; table list</a><br>";
infoHtml += `<textarea id='auxMsgZone'>${(await res.json()).auxMsg}</textarea><br><button onclick='publishAuxMsg()'>Set Status</button>`
infoHtml += `<textarea id='auxMsgZone'>${table.auxMsg}</textarea><br><button onclick='publishAuxMsg()'>Set Status</button>`
infoHtml += "<button onclick='destroyTable()'>Destroy Table</button><br/>";
infoHtml += "<input id='map_img_upload' type='file'/><button onclick='uploadMapImg()'>Upload Map</button><br/>"
if (mapImgs.ok) {
@ -70,18 +72,14 @@ async function getTable(name, pass) {
}
tokenListHTML += "</ul>";
fillSpriteDropdown(tokens);
redrawTokenMasterList();
} else {
tokenListHTML += "<label>Sprites couldn't be retrieved</label>"
}
spriteZone.innerHTML = tokenListHTML;
tokenWrapper.style.display = "inline";
// also, we have to fill and toggle the tokens window
} else {
console.log(res.status);
}
@ -90,6 +88,15 @@ async function getTable(name, pass) {
}
}
function redrawTokenMasterList() {
if (tokenZone) {
const headers = new Headers();
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
const res = await fetch(`/`
}
}
function fillSpriteDropdown(tokens) {
let options = "<option value=''>select</option>";
for (const t of tokens) {
@ -127,7 +134,6 @@ function toggleAspectLock() {
function scaleSpritePreview(source) {
if (mapImg && mapImg._image) {
console.log(mapImg);
const scaleFactor = mapImg._image.clientWidth / mapImg._image.naturalWidth;
const keepAspect = tokenAspect.checked;
const img = previewZone.children[0];
@ -162,19 +168,20 @@ function drawTokenOrigin() {
const img = previewZone.children[0];
const x = Number(tokenWidth.value) / Number(tokenCX.value);
const y = Number(tokenHeight.value) / Number(tokenCY.value);
const origin = {x: img.width/x, y: img.height/y};
const originImg = document.createElement("img");
originImg.src="/table/origin.png";
originImg.style.position = "absolute";
originImg.style.left = (origin.x - 2) + "px";
originImg.style.top = (origin.y - 2) + "px";
if (previewZone.children.length > 1) {
previewZone.replaceChild(originImg, previewZone.children[1]);
} else {
previewZone.appendChild(originImg);
}
}
function reinitializeSpritePreview() {
@ -206,24 +213,19 @@ function createToken() {
const img = tokenSpriteDropdown[tokenSpriteDropdown.selectedIndex].value;
const name = tokenName.value;
console.log("creating token");
if (!isNaN(w) && !isNaN(h) && !isNaN(oX) && !isNaN(oY) && img && name) {
console.log("all green");
const self = {
sz: [w, h],
m: L.marker(getCascadingPos(), {
icon: L.icon({
iconUrl: img,
iconSize: [w,h],
}),
title: name,
draggable: true,
autoPan: true
}),
};
// create on the frontend for testing
/*
const self = NewToken(w, h, oX, oY, img, name);
tokens.push(self);
self.m.addTo(map);
resizeMarkers();
*/
// really though we have to send it on the websocket and wait for it to come back
}
}
@ -236,10 +238,19 @@ function publishAuxMsg() {
}
function sendMapImg(url) {
console.log("sending " + url);
publish({mapImg: url, auth: adminToken.access_token});
}
function sendToken(t) {
publish({token: t, auth: adminToken.access_token});
}
function revokeToken(t) {
t.x = null;
t.y = null;
sendToken(t);
}
async function uploadMapImg() {
try {
var input = document.getElementById("map_img_upload");
@ -446,5 +457,9 @@ async function createTable() {
if (res.ok) {
getTables();
setTableCreateFormVisible(false);
} else if (res.status === 422) {
setErr('Table name and passcode must be only alphanumeric and underscores');
} else {
setErr('Error creating table');
}
}

View file

@ -88,7 +88,7 @@
<div id="adminWrapper_tokens">
<details id="admin_token_win" class="ui_win admin_win"><summary>tokens</summary>
<button onclick="setTokenCreateFormVisible(true)">New Token</button>
<form onsubmit="return false" id="createTokenForm">
<form onsubmit="return false" id="createTokenForm" style="display:none;">
<label>Sprite<select id="token_combobox" onchange="previewSprite(this)"></select></label><br/>
<label>Name<input id="token_name"/></label><br/>
@ -96,9 +96,9 @@
<label>Height<input type="number" id="token_height" min="1" max="9999" onchange="previewSprite(this)"/></label><br/>
<label>cX<input type="number" id="token_cx" min="0" max="9999" onchange="previewSprite(this)"/></label><br/>
<label>cY<input type="number" id="token_cy" min="0" max="9999" onchange="previewSprite(this)"/></label><br/>
<div id="tokenPreview_zone"></div>
<button type="submit" onclick="createToken()">Create</button>
<button onclick="setTokenCreateFormVisible(false)">Cancel</button>
<div id="tokenPreview_zone"></div>
</form>
<div id="tokenZone"></div>
</details><br/>

View file

@ -4,7 +4,9 @@ let tokens = [];
const worldBounds = [[180, -180],[-180, 180]];
function initializeMap(mapImgUrl) {
let init = false;
if (!map) {
init = true;
map = L.map('map', { minZoom: 0, maxZoom: 4, crs: L.CRS.Simple });
map.on("zoomend", ()=>{resizeMarkers();scaleSpritePreview();});
}
@ -14,7 +16,9 @@ function initializeMap(mapImgUrl) {
mapImg = L.imageOverlay(mapImgUrl, worldBounds);
mapImg.addTo(map);
map.setMaxBounds(worldBounds);
if (init) {
map.setView([0,0], 2);
}
while (tokens.some(t=>t)) {
tokens[0].m.removeFrom(map);
tokens.shift();
@ -39,6 +43,21 @@ function getCascadingPos() {
return topLeft;
}
function NewToken(w, h, oX, oY, img, name, x, y) {
return {
sz: [w, h],
m: L.marker((x && y) ? [y,x] : getCascadingPos(), {
icon: L.icon({
iconUrl: img,
iconSize: [w,h],
}),
title: name,
draggable: true,
autoPan: true
}),
};
}
function addToken(token) {
const self = { sz: token.sz, m: L.marker(token.pos, {
icon: L.icon({

View file

@ -19,15 +19,17 @@ function fmtLeading(n) {
}
function formatDice(r) {
console.log(r);
const date = new Date(r.timestamp)
const p = document.createElement("p");
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
p.innerHTML = `${date.getFullYear()}-${fmtLeading(month)}-${fmtLeading(day)} ${fmtLeading(hours)}:${fmtLeading(minutes)}:${fmtLeading(seconds)} ${r.player} rolled ${r.roll.length}d${r.faces} ${(r.note ? "(" + r.note + ")" : "")}<br>[${r.roll}] (total ${r.roll.reduce((a,c)=>a+c,0)})`;
return p;
}

View file

@ -147,6 +147,10 @@ pre {
color: var(--fg_color);
}
.ui_win ul {
max-height: 10em;
}
#admin_section {
text-align: right;
}