Feat: enter room: login with link

This commit is contained in:
Grail Finder
2025-05-21 09:22:29 +03:00
parent 59cccbbe8e
commit ad8f1aaee2
6 changed files with 125 additions and 85 deletions

View File

@ -1,9 +1,13 @@
{{define "main"}} {{define "main"}}
<!-- user has no username -> login form --> Start of main temp
{{ if not . }} {{ if not . }}
login temp
{{template "login"}} {{template "login"}}
<!-- user has name but no room id => suggest to create room --> {{ else if ne .LinkLogin "" }}
got to linklogin
{{template "linklogin" .LinkLogin}}
{{ else if eq .State.RoomID "" }} {{ else if eq .State.RoomID "" }}
empty state roomid
<div id="hello-user"> <div id="hello-user">
<p>Hello {{.State.Username}}</p> <p>Hello {{.State.Username}}</p>
</div> </div>
@ -14,7 +18,7 @@
{{template "roomlist" .List}} {{template "roomlist" .List}}
</div> </div>
{{else}} {{else}}
<!-- instead of having room div; better to replace ancestor completely with room --> else
<div id="room"> <div id="room">
{{template "room" .}} {{template "room" .}}
</div> </div>

16
components/linklogin.html Normal file
View File

@ -0,0 +1,16 @@
{{define "linklogin"}}
<div id="logindiv">
You're about to join room#{{.}}; but first!
<form class="space-y-6" hx-post="/login" hx-target="#ancestor">
<label For="username" class="block text-sm font-medium leading-6 text-white-900">tell us your username</label>
<div class="mt-2">
<input id="username" name="username" hx-target="#login_notice" hx-swap="outerHTML" hx-post="/check/name" hx-trigger="input changed delay:400ms" autocomplete="username" required class="block w-full rounded-md border-0 bg-white py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 text-center"/>
<input type="hidden" name="room_id" value={{.}}>
</div>
<div id="login_notice">this name looks available</div>
<div>
<button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Sign in</button>
</div>
</form>
</div>
{{end}}

View File

@ -60,6 +60,7 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
abortWithError(w, msg) abortWithError(w, msg)
return return
} }
roomID := r.PostFormValue("room_id")
// make sure username does not exists // make sure username does not exists
cleanName := utils.RemoveSpacesFromStr(username) cleanName := utils.RemoveSpacesFromStr(username)
// login user // login user
@ -75,12 +76,29 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return
} }
// state := models.MakeTestState(cleanName)
// state.State.Username = cleanName
userstate := models.InitState(cleanName) userstate := models.InitState(cleanName)
fi := &models.FullInfo{ fi := &models.FullInfo{
State: userstate, State: userstate,
} }
// check if room_id provided and exists
if roomID != "" {
log.Debug("got room_id in login", "room_id", roomID)
room, err := getRoomByID(roomID)
if err != nil {
abortWithError(w, err.Error())
return
}
room.PlayerList = append(room.PlayerList, fi.State.Username)
fi.State.RoomID = room.ID
fi.Room = room
fi.List = nil
// save full info instead
if err := saveFullInfo(fi); err != nil {
abortWithError(w, err.Error())
return
}
} else {
log.Debug("no room_id in login")
fi.List = listPublicRooms() fi.List = listPublicRooms()
// save state to cache // save state to cache
if err := saveState(cleanName, userstate); err != nil { if err := saveState(cleanName, userstate); err != nil {
@ -89,6 +107,7 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return
} }
}
tmpl.ExecuteTemplate(w, "base", fi) tmpl.ExecuteTemplate(w, "base", fi)
} }

View File

@ -49,55 +49,52 @@ func HandleCreateRoom(w http.ResponseWriter, r *http.Request) {
tmpl.ExecuteTemplate(w, "base", fi) tmpl.ExecuteTemplate(w, "base", fi)
} }
func HandleRoomEnter(w http.ResponseWriter, r *http.Request) { // DEPRACATED: duplication of HandleJoinRoom
// parse payload // func HandleRoomEnter(w http.ResponseWriter, r *http.Request) {
roomID := r.URL.Query().Get("id") // // parse payload
if roomID == "" { // roomID := r.URL.Query().Get("id")
// error // if roomID == "" {
return // msg := "room id not provided"
} // log.Error(msg)
// create a room // abortWithError(w, msg)
room, err := getRoomByID(roomID) // return
if err != nil { // }
msg := "failed to find the room" // tmpl, err := template.ParseGlob("components/*.html")
log.Error(msg, "error", err, "room_id", roomID) // if err != nil {
abortWithError(w, msg) // abortWithError(w, err.Error())
return // return
} // }
ctx := context.WithValue(r.Context(), "current_room", room.ID) // // create a room
ctx, err = updateRoomInSession(ctx, room.ID) // room, err := getRoomByID(roomID)
if err != nil { // if err != nil {
msg := "failed to set current room to session" // msg := "failed to find the room"
log.Error(msg, "error", err) // log.Error(msg, "error", err, "room_id", roomID)
abortWithError(w, msg) // abortWithError(w, msg)
return // return
} // }
state, err := getStateByCtx(ctx) // state, err := getStateByCtx(r.Context())
if err != nil { // // INFO: if non-loggined user join: prompt to login
log.Error("failed to get state", "error", err) // if err != nil {
abortWithError(w, err.Error()) // log.Error("failed to get state", "error", err)
return // // abortWithError(w, err.Error())
} // tmpl.ExecuteTemplate(w, "login", nil)
state.RoomID = room.ID // return
// update state // }
if err := saveStateByCtx(ctx, state); err != nil { // state.RoomID = room.ID
log.Error("failed to update state", "error", err) // // update state
abortWithError(w, err.Error()) // if err := saveStateByCtx(r.Context(), state); err != nil {
return // log.Error("failed to update state", "error", err)
} // abortWithError(w, err.Error())
// send msg of created room // return
// h.Broker.Notifier <- broker.NotificationEvent{ // }
// EventName: models.MsgRoomListUpdate, // // send msg of created room
// Payload: fmt.Sprintf("%s created a room named %s", r.CreatorName, r.RoomName), // // h.Broker.Notifier <- broker.NotificationEvent{
// } // // EventName: models.MsgRoomListUpdate,
// return html // // Payload: fmt.Sprintf("%s created a room named %s", r.CreatorName, r.RoomName),
tmpl, err := template.ParseGlob("components/*.html") // // }
if err != nil { // // return html
abortWithError(w, err.Error()) // tmpl.ExecuteTemplate(w, "base", room)
return // }
}
tmpl.ExecuteTemplate(w, "base", room)
}
func HandleJoinTeam(w http.ResponseWriter, r *http.Request) { func HandleJoinTeam(w http.ResponseWriter, r *http.Request) {
r.ParseForm() r.ParseForm()
@ -239,11 +236,20 @@ func HandleJoinRoom(w http.ResponseWriter, r *http.Request) {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return
} }
fi, err := getFullInfoByCtx(r.Context()) tmpl, err := template.ParseGlob("components/*.html")
if err != nil { if err != nil {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return
} }
fi, err := getFullInfoByCtx(r.Context())
if err != nil {
// INFO: if non-loggined user join: prompt to login
fi = &models.FullInfo{}
fi.LinkLogin = roomID
tmpl.ExecuteTemplate(w, "base", fi)
// abortWithError(w, err.Error())
return
}
room.PlayerList = append(room.PlayerList, fi.State.Username) room.PlayerList = append(room.PlayerList, fi.State.Username)
fi.State.RoomID = room.ID fi.State.RoomID = room.ID
fi.Room = room fi.Room = room
@ -252,12 +258,6 @@ func HandleJoinRoom(w http.ResponseWriter, r *http.Request) {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return
} }
// return html
tmpl, err := template.ParseGlob("components/*.html")
if err != nil {
abortWithError(w, err.Error())
return
}
tmpl.ExecuteTemplate(w, "room", fi) tmpl.ExecuteTemplate(w, "room", fi)
} }

View File

@ -23,7 +23,7 @@ func ListenToRequests(port string) error {
mux.HandleFunc("GET /ping", handlers.HandlePing) mux.HandleFunc("GET /ping", handlers.HandlePing)
mux.HandleFunc("GET /", handlers.HandleHome) mux.HandleFunc("GET /", handlers.HandleHome)
mux.HandleFunc("POST /login", handlers.HandleFrontLogin) mux.HandleFunc("POST /login", handlers.HandleFrontLogin)
mux.HandleFunc("GET /room", handlers.HandleRoomEnter) // mux.HandleFunc("GET /room", handlers.HandleRoomEnter)
mux.HandleFunc("POST /join-team", handlers.HandleJoinTeam) mux.HandleFunc("POST /join-team", handlers.HandleJoinTeam)
mux.HandleFunc("GET /end-turn", handlers.HandleEndTurn) mux.HandleFunc("GET /end-turn", handlers.HandleEndTurn)
mux.HandleFunc("POST /room-create", handlers.HandleCreateRoom) mux.HandleFunc("POST /room-create", handlers.HandleCreateRoom)

View File

@ -245,6 +245,7 @@ type FullInfo struct {
State *UserState State *UserState
Room *Room Room *Room
List []*Room List []*Room
LinkLogin string // room_id
} }
func (f *FullInfo) ExitRoom() *Room { func (f *FullInfo) ExitRoom() *Room {