Skip to content

Commit e3e81c0

Browse files
committed
Initial gallery implementation
By appending `/gallery`, you can view the list of all past drawings from the lobby. The link will work after the lobby dies, if the data is still in your session storage. We try to avoid sending requests multiple times by caching.
1 parent c5651bd commit e3e81c0

File tree

12 files changed

+457
-31
lines changed

12 files changed

+457
-31
lines changed

internal/api/http.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ func (handler *V1Handler) SetupRoutes(rootPath string, router chi.Router) {
1919
router.Get(routePrefix+"/lobby", handler.getLobbies)
2020
router.Post(routePrefix+"/lobby", handler.postLobby)
2121

22+
router.Get(routePrefix+"/lobby/{lobby_id}/gallery", handler.getGallery)
23+
2224
router.Patch(routePrefix+"/lobby/{lobby_id}", handler.patchLobby)
2325
// The websocket is shared between the public API and the official client
2426
router.Get(routePrefix+"/lobby/{lobby_id}/ws", handler.websocketUpgrade)

internal/api/v1.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ type LobbyEntry struct {
5151
CustomWords bool `json:"customWords"`
5252
}
5353

54+
//easyjson:json
55+
type Gallery []game.GalleryDrawing
56+
57+
func (handler *V1Handler) getGallery(writer http.ResponseWriter, request *http.Request) {
58+
lobby := state.GetLobby(chi.URLParam(request, "lobby_id"))
59+
if lobby == nil {
60+
http.Error(writer, ErrLobbyNotExistent.Error(), http.StatusNotFound)
61+
return
62+
}
63+
64+
// FIXME Synchronise access to lobby.Drawings.
65+
// The drawings should also be available in an unstarted game.
66+
67+
if started, _, err := easyjson.MarshalToHTTPResponseWriter(Gallery(lobby.Drawings), writer); err != nil {
68+
if !started {
69+
http.Error(writer, err.Error(), http.StatusInternalServerError)
70+
}
71+
return
72+
}
73+
}
74+
5475
func (handler *V1Handler) getLobbies(writer http.ResponseWriter, _ *http.Request) {
5576
// REMARK: If paging is ever implemented, we might want to maintain order
5677
// when deleting lobbies from state in the state package.

internal/api/v1_easyjson.go

Lines changed: 159 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/frontend/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,5 +197,5 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
197197
// We only add the lobby if we could do all necessary pre-steps successfully.
198198
state.AddLobby(lobby)
199199

200-
http.Redirect(writer, request, handler.basePageConfig.RootPath+"/ssrEnterLobby/"+lobby.LobbyID, http.StatusFound)
200+
http.Redirect(writer, request, handler.basePageConfig.RootPath+"/lobby/"+lobby.LobbyID, http.StatusFound)
201201
}

internal/frontend/gallery.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package frontend
2+
3+
import (
4+
"log"
5+
"net/http"
6+
"strings"
7+
8+
"github.com/go-chi/chi/v5"
9+
"github.com/scribble-rs/scribble.rs/internal/translations"
10+
)
11+
12+
type galleryPageData struct {
13+
*BasePageConfig
14+
15+
LobbyID string
16+
Translation translations.Translation
17+
Locale string
18+
}
19+
20+
func (handler *SSRHandler) ssrGallery(writer http.ResponseWriter, request *http.Request) {
21+
userAgent := strings.ToLower(request.UserAgent())
22+
if !isHumanAgent(userAgent) {
23+
// FIXME Handle robots
24+
return
25+
}
26+
27+
lobbyId := chi.URLParam(request, "lobby_id")
28+
translation, locale := determineTranslation(request)
29+
pageData := &galleryPageData{
30+
BasePageConfig: handler.basePageConfig,
31+
LobbyID: lobbyId,
32+
Translation: translation,
33+
Locale: locale,
34+
}
35+
36+
// If the pagedata isn't initialized, it means the synchronized block has exited.
37+
// In this case we don't want to template the lobby, since an error has occurred
38+
// and probably already has been handled.
39+
if err := pageTemplates.ExecuteTemplate(writer, "gallery-page", pageData); err != nil {
40+
log.Printf("Error templating lobby: %s\n", err)
41+
}
42+
}

internal/frontend/http.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
"html/template"
77
"net/http"
88
"path"
9+
"strings"
910

1011
"github.com/go-chi/chi/v5"
1112
"github.com/scribble-rs/scribble.rs/internal/translations"
13+
"golang.org/x/text/language"
1214
)
1315

1416
var (
@@ -61,8 +63,9 @@ func (handler *SSRHandler) SetupRoutes(router chi.Router) {
6163
}),
6264
).ServeHTTP,
6365
)
64-
router.Get("/"+path.Join(handler.cfg.RootPath, "ssrEnterLobby/{lobby_id}"), handler.ssrEnterLobby)
65-
router.Post("/"+path.Join(handler.cfg.RootPath, "ssrCreateLobby"), handler.ssrCreateLobby)
66+
router.Get("/"+path.Join(handler.cfg.RootPath, "lobby/{lobby_id}/gallery"), handler.ssrGallery)
67+
router.Get("/"+path.Join(handler.cfg.RootPath, "lobby/{lobby_id}"), handler.ssrEnterLobby)
68+
router.Post("/"+path.Join(handler.cfg.RootPath, "create_lobby"), handler.ssrCreateLobby)
6669
}
6770

6871
// errorPageData represents the data that error.html requires to be displayed.
@@ -86,3 +89,33 @@ func (handler *SSRHandler) userFacingError(w http.ResponseWriter, errorMessage s
8689
panic(err)
8790
}
8891
}
92+
93+
func determineTranslation(r *http.Request) (translations.Translation, string) {
94+
languageTags, _, err := language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
95+
if err == nil {
96+
for _, languageTag := range languageTags {
97+
fullLanguageIdentifier := languageTag.String()
98+
fullLanguageIdentifierLowercased := strings.ToLower(fullLanguageIdentifier)
99+
translation := translations.GetLanguage(fullLanguageIdentifierLowercased)
100+
if translation != nil {
101+
return translation, fullLanguageIdentifierLowercased
102+
}
103+
104+
baseLanguageIdentifier, _ := languageTag.Base()
105+
baseLanguageIdentifierLowercased := strings.ToLower(baseLanguageIdentifier.String())
106+
translation = translations.GetLanguage(baseLanguageIdentifierLowercased)
107+
if translation != nil {
108+
return translation, baseLanguageIdentifierLowercased
109+
}
110+
}
111+
}
112+
113+
return translations.DefaultTranslation, "en-us"
114+
}
115+
116+
func isHumanAgent(userAgent string) bool {
117+
return strings.Contains(userAgent, "gecko") ||
118+
strings.Contains(userAgent, "chrome") ||
119+
strings.Contains(userAgent, "opera") ||
120+
strings.Contains(userAgent, "safari")
121+
}

internal/frontend/lobby.go

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/scribble-rs/scribble.rs/internal/api"
1010
"github.com/scribble-rs/scribble.rs/internal/state"
1111
"github.com/scribble-rs/scribble.rs/internal/translations"
12-
"golang.org/x/text/language"
1312
)
1413

1514
type lobbyPageData struct {
@@ -34,7 +33,7 @@ func (handler *SSRHandler) ssrEnterLobby(writer http.ResponseWriter, request *ht
3433
}
3534

3635
userAgent := strings.ToLower(request.UserAgent())
37-
if !(strings.Contains(userAgent, "gecko") || strings.Contains(userAgent, "chrome") || strings.Contains(userAgent, "opera") || strings.Contains(userAgent, "safari")) {
36+
if !isHumanAgent(userAgent) {
3837
err := pageTemplates.ExecuteTemplate(writer, "robot-page", &robotPageData{
3938
BasePageConfig: handler.basePageConfig,
4039
LobbyData: api.CreateLobbyData(lobby),
@@ -91,26 +90,3 @@ func (handler *SSRHandler) ssrEnterLobby(writer http.ResponseWriter, request *ht
9190
}
9291
}
9392
}
94-
95-
func determineTranslation(r *http.Request) (translations.Translation, string) {
96-
languageTags, _, err := language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
97-
if err == nil {
98-
for _, languageTag := range languageTags {
99-
fullLanguageIdentifier := languageTag.String()
100-
fullLanguageIdentifierLowercased := strings.ToLower(fullLanguageIdentifier)
101-
translation := translations.GetLanguage(fullLanguageIdentifierLowercased)
102-
if translation != nil {
103-
return translation, fullLanguageIdentifierLowercased
104-
}
105-
106-
baseLanguageIdentifier, _ := languageTag.Base()
107-
baseLanguageIdentifierLowercased := strings.ToLower(baseLanguageIdentifier.String())
108-
translation = translations.GetLanguage(baseLanguageIdentifierLowercased)
109-
if translation != nil {
110-
return translation, baseLanguageIdentifierLowercased
111-
}
112-
}
113-
}
114-
115-
return translations.DefaultTranslation, "en-us"
116-
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
.app {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 0.5rem;
5+
padding: 1rem;
6+
box-sizing: border-box;
7+
height: 100%;
8+
}
9+
10+
#drawing-board {
11+
border-radius: var(--component-border-radius);
12+
min-height: 0;
13+
max-width: 100%;
14+
margin-left: auto;
15+
margin-right: auto;
16+
}
17+
18+
.top-bar {
19+
display: flex;
20+
flex-direction: row;
21+
justify-content: space-between;
22+
padding: 0.5rem;
23+
background-color: var(--component-base-color);
24+
border-radius: var(--component-border-radius);
25+
}
26+
27+
#word {
28+
font-size: 2rem;
29+
}
30+
31+
.prev,
32+
.next {
33+
font-size: 2rem;
34+
border: 1px solid black;
35+
}
36+
37+
.prev {}
38+
39+
.next {}

0 commit comments

Comments
 (0)