From 6305c7bedabd5376e5711e5c8c5c0f8f8e0caf5f Mon Sep 17 00:00:00 2001 From: Settel Date: Tue, 12 Apr 2022 14:16:03 +0200 Subject: [PATCH] feat: user last logged in/created --- client/nuxt.config.js | 5 ++- .../components/admin/AdminTileGameinfo.vue | 4 ++ .../src/components/admin/AdminTilePlayers.vue | 18 ++++++-- client/src/plugins/formatter.js | 27 +++++++++++ server/src/application/getGameInfo.go | 2 + server/src/application/syncHandler.go | 3 ++ server/src/game/game.go | 6 ++- server/src/game/getGameInfo.go | 15 ++++--- server/src/game/player.go | 16 ++++--- server/src/game/struct.go | 21 ++++++--- server/src/user/struct.go | 28 +++++++----- server/src/user/user.go | 45 +++++++++++++------ 12 files changed, 141 insertions(+), 49 deletions(-) create mode 100644 client/src/plugins/formatter.js diff --git a/client/nuxt.config.js b/client/nuxt.config.js index b1dc13d..21abfbe 100644 --- a/client/nuxt.config.js +++ b/client/nuxt.config.js @@ -22,7 +22,10 @@ export default { ], components: true, modules: ['@nuxtjs/axios'], - plugins: [{ src: '~/plugins/engine', mode: 'client' }], + plugins: [ + { src: '~/plugins/engine', mode: 'client' }, + { src: '~/plugins/formatter', mode: 'client' }, + ], axios: { proxy: true }, publicRuntimeConfig: { serverBaseUrl: '/', diff --git a/client/src/components/admin/AdminTileGameinfo.vue b/client/src/components/admin/AdminTileGameinfo.vue index 060919d..6527544 100644 --- a/client/src/components/admin/AdminTileGameinfo.vue +++ b/client/src/components/admin/AdminTileGameinfo.vue @@ -6,6 +6,10 @@ {{ gameinfo.name }}
+ + Created: + {{ $formatter.date(gameinfo.created) }} + # Players: {{ players.length }} diff --git a/client/src/components/admin/AdminTilePlayers.vue b/client/src/components/admin/AdminTilePlayers.vue index bb573ea..3a3f808 100644 --- a/client/src/components/admin/AdminTilePlayers.vue +++ b/client/src/components/admin/AdminTilePlayers.vue @@ -22,10 +22,10 @@ v-for="player in players" :key="player.id" > - {{ player.name }} + {{ player.name }}{{ player.role === 'gamemaster' ? ' 👑' : '' }} {{ player.numQuotes }} {{ player.score }} - {{ player.isPlaying ? (player.isIdle ? 'idle' : 'active') : '-'}} + {{ getPlayerStatus(player) }} @@ -55,7 +55,19 @@ export default { this.$emit('reload') this.isReloading = true setTimeout(() => { this.isReloading = false }, 500) - } + }, + getPlayerStatus(player) { + if (player.isPlaying && !player.isIdle) { + return 'active' + } else { + if (player.lastLoggedIn) { + return this.$formatter.datetime(player.lastLoggedIn) + } else if (player.isPlaying) { + return 'idle' + } + } + return '-' + }, }, } diff --git a/client/src/plugins/formatter.js b/client/src/plugins/formatter.js new file mode 100644 index 0000000..e63d837 --- /dev/null +++ b/client/src/plugins/formatter.js @@ -0,0 +1,27 @@ +export default (context, inject) => { + const leftPad2Digits = (val) => val < 10 ? '0' + val : '' + val + + const date = (time) => { + if (!time) return + + const d = new Date(time * 1000) + return `${1900 + d.getYear()}-` + + `${leftPad2Digits(d.getMonth() + 1)}-` + + `${leftPad2Digits(d.getDate())}` + } + + const datetime = (time) => { + if (!time) return + + const d = new Date(time * 1000) + return `${date(time)}, ` + + `${leftPad2Digits(d.getHours())}:` + + `${leftPad2Digits(d.getMinutes())}:` + + `${leftPad2Digits(d.getSeconds())}` + } + + inject('formatter', { + date, + datetime, + }) +} diff --git a/server/src/application/getGameInfo.go b/server/src/application/getGameInfo.go index b4a6243..1dfee15 100644 --- a/server/src/application/getGameInfo.go +++ b/server/src/application/getGameInfo.go @@ -31,6 +31,8 @@ func (app *Application) GetGameInfo(usr *user.User, w http.ResponseWriter, r *ht return } else { gameInfo.Players[i].AuthCode = playerUser.GetAuthCode() + gameInfo.Players[i].Created = playerUser.GetCreated() + gameInfo.Players[i].LastLoggedIn = playerUser.GetLastLoggedIn() } } diff --git a/server/src/application/syncHandler.go b/server/src/application/syncHandler.go index d7f20b1..471f483 100644 --- a/server/src/application/syncHandler.go +++ b/server/src/application/syncHandler.go @@ -21,6 +21,9 @@ func (app *Application) SyncHandler(usr *user.User, w http.ResponseWriter, r *ht return } + usr.UpdateHeartbeat() + usr.SaveUser() + app.updatePlayerIsConnected(usr) eng := gm.GetEngine() eng.SyncHandler(w, r) diff --git a/server/src/game/game.go b/server/src/game/game.go index e2b8724..150ce6e 100644 --- a/server/src/game/game.go +++ b/server/src/game/game.go @@ -6,6 +6,7 @@ import ( "os" "sirlab.de/go/knowyt/engine" "sirlab.de/go/knowyt/quote" + "time" ) func NewGameFromFile(id, fileName string) (*Game, error) { @@ -22,6 +23,7 @@ func NewGameFromFile(id, fileName string) (*Game, error) { id: id, filename: fileName, name: gmJson.Name, + created: gmJson.Created, eng: engine.NewEngine(), players: make(map[string]playerInfo, 0), state: STATE_IDLE, @@ -40,6 +42,7 @@ func NewGame(id, fileName, name string) (*Game, error) { eng: engine.NewEngine(), players: make(map[string]playerInfo, 0), state: STATE_IDLE, + created: time.Now().Unix(), quotes: make(map[string]*quote.Quote, 0), } @@ -51,7 +54,8 @@ func (gm *Game) SaveGame() error { defer gm.mu.Unlock() gmJson := GameJson{ - Name: gm.name, + Name: gm.name, + Created: gm.created, } if jsonBytes, err := json.Marshal(gmJson); err != nil { return err diff --git a/server/src/game/getGameInfo.go b/server/src/game/getGameInfo.go index 4281fb2..f9d25a0 100644 --- a/server/src/game/getGameInfo.go +++ b/server/src/game/getGameInfo.go @@ -18,6 +18,7 @@ func (gm *Game) initGameInfoJson() *GameInfoJson { gameInfo := GameInfoJson{ Name: gm.name, + Created: gm.created, State: gm.state, Players: make([]PlayerInfoJson, 0), NumQuotesLeft: numQuotesLeft, @@ -26,12 +27,14 @@ func (gm *Game) initGameInfoJson() *GameInfoJson { for _, player := range gm.players { gameInfo.Players = append(gameInfo.Players, PlayerInfoJson{ - Id: player.id, - Name: player.name, - Score: player.score, - IsPlaying: player.isPlaying, - IsIdle: player.isIdle, - Role: player.role, + Id: player.id, + Name: player.name, + Created: player.created, + LastLoggedIn: player.lastLoggedIn, + Score: player.score, + IsPlaying: player.isPlaying, + IsIdle: player.isIdle, + Role: player.role, }) } diff --git a/server/src/game/player.go b/server/src/game/player.go index 1330c87..1deaaf5 100644 --- a/server/src/game/player.go +++ b/server/src/game/player.go @@ -62,12 +62,14 @@ func (gm *Game) AddPlayer(usr *user.User) { } gm.players[usrId] = playerInfo{ - id: usrId, - name: usr.GetName(), - isPlaying: false, - isIdle: true, - score: 0, - role: usr.GetRole(), + id: usrId, + name: usr.GetName(), + created: usr.GetCreated(), + lastLoggedIn: usr.GetLastLoggedIn(), + isPlaying: false, + isIdle: true, + score: 0, + role: usr.GetRole(), } } @@ -83,6 +85,8 @@ func (gm *Game) UpdatePlayer(usr *user.User) { } player.name = usr.GetName() + player.created = usr.GetCreated() + player.lastLoggedIn = usr.GetLastLoggedIn() gm.players[usrId] = player } diff --git a/server/src/game/struct.go b/server/src/game/struct.go index a8d1549..396d39d 100644 --- a/server/src/game/struct.go +++ b/server/src/game/struct.go @@ -30,12 +30,14 @@ const ( ) type playerInfo struct { - id string - name string - isPlaying bool - isIdle bool - score int - role string + id string + name string + created int64 + lastLoggedIn int64 + isPlaying bool + isIdle bool + score int + role string } type Source struct { @@ -60,6 +62,7 @@ type Game struct { id string filename string name string + created int64 players map[string]playerInfo eng *engine.Engine state string @@ -69,7 +72,8 @@ type Game struct { } type GameJson struct { - Name string `json:"name"` + Name string `json:"name"` + Created int64 `json:"created"` } type Quote struct { @@ -84,6 +88,8 @@ type QuotesInfo struct { type PlayerInfoJson struct { Id string `json:"id"` Name string `json:"name"` + Created int64 `json:"created"` + LastLoggedIn int64 `json:"lastLoggedIn"` Score int `json:"score"` IsPlaying bool `json:"isPlaying"` IsIdle bool `json:"isIdle"` @@ -94,6 +100,7 @@ type PlayerInfoJson struct { type GameInfoJson struct { Name string `json:"name"` + Created int64 `json:"created"` State string `json:"state"` Players []PlayerInfoJson `json:"players"` NumQuotesLeft int `json:"numQuotesLeft"` diff --git a/server/src/user/struct.go b/server/src/user/struct.go index 55e42b8..a88d602 100644 --- a/server/src/user/struct.go +++ b/server/src/user/struct.go @@ -11,21 +11,25 @@ const ( ) type User struct { - mu sync.Mutex - id string - filename string - authcode string - name string - role string - gameId string - cameo *User + mu sync.Mutex + id string + filename string + authcode string + name string + role string + gameId string + created int64 + lastLoggedIn int64 + cameo *User } type UserJson struct { - Authcode string `json:"authcode"` - Name string `json:"name"` - Role string `json:"role"` - GameId string `json:"game"` + Authcode string `json:"authcode"` + Name string `json:"name"` + Role string `json:"role"` + GameId string `json:"game"` + Created int64 `json:"created"` + LastLoggedIn int64 `json:"lastLoggedIn"` } type UserinfoJson struct { diff --git a/server/src/user/user.go b/server/src/user/user.go index 9be7d25..3548e31 100644 --- a/server/src/user/user.go +++ b/server/src/user/user.go @@ -6,6 +6,7 @@ import ( "os" "path" "strings" + "time" ) func NewUserFromFile(fileName string) (*User, error) { @@ -22,12 +23,14 @@ func NewUserFromFile(fileName string) (*User, error) { _, fileNameShort := path.Split(fileName) id := strings.TrimSuffix(fileNameShort, ".json") return &User{ - id: id, - name: userJson.Name, - filename: fileName, - role: userJson.Role, - authcode: userJson.Authcode, - gameId: userJson.GameId, + id: id, + name: userJson.Name, + filename: fileName, + role: userJson.Role, + authcode: userJson.Authcode, + gameId: userJson.GameId, + lastLoggedIn: userJson.LastLoggedIn, + created: userJson.Created, }, nil } } @@ -36,9 +39,11 @@ func CreateUser(fileName, gameId string) *User { _, fileNameShort := path.Split(fileName) id := strings.TrimSuffix(fileNameShort, ".json") return &User{ - id: id, - filename: fileName, - gameId: gameId, + id: id, + filename: fileName, + gameId: gameId, + lastLoggedIn: 0, + created: time.Now().Unix(), } } @@ -47,10 +52,12 @@ func (usr *User) SaveUser() error { defer usr.mu.Unlock() userJson := UserJson{ - Name: usr.name, - Authcode: usr.authcode, - Role: usr.role, - GameId: usr.gameId, + Name: usr.name, + Authcode: usr.authcode, + Role: usr.role, + GameId: usr.gameId, + Created: usr.created, + LastLoggedIn: usr.lastLoggedIn, } if jsonBytes, err := json.Marshal(userJson); err != nil { return err @@ -153,3 +160,15 @@ func (usr *User) GetCameo() *User { return usr.cameo } + +func (usr *User) GetCreated() int64 { + return usr.created +} + +func (usr *User) GetLastLoggedIn() int64 { + return usr.lastLoggedIn +} + +func (usr *User) UpdateHeartbeat() { + usr.lastLoggedIn = time.Now().Unix() +}