Skip to content

Commit fd02f3f

Browse files
committed
Improve game redirects
1 parent 388bd3f commit fd02f3f

File tree

10 files changed

+216
-6
lines changed

10 files changed

+216
-6
lines changed

database/postgresdal.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1445,7 +1445,16 @@ func (d *postgresDAL) GetGameRedirects(dbs PGDBSession) ([]*types.GameRedirect,
14451445
}
14461446

14471447
func (d *postgresDAL) AddGameRedirect(dbs PGDBSession, srcId string, destId string) error {
1448-
// Validate dest id first
1448+
// Validate source id is not a live game
1449+
srcGame, err := d.GetGame(dbs, srcId)
1450+
if err != nil && err != pgx.ErrNoRows {
1451+
return err
1452+
}
1453+
if srcGame != nil && !srcGame.Deleted {
1454+
return fmt.Errorf("Source game is a live game")
1455+
}
1456+
1457+
// Validate dest id is a live game
14491458
game, err := d.GetGame(dbs, destId)
14501459

14511460
if err != nil {

service/siteservice.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,7 +3654,7 @@ func (s *SiteService) UnfreezeGame(ctx context.Context, gameId string, uid int64
36543654
return err
36553655
}
36563656

3657-
func (s *SiteService) GetGameRedirects(ctx context.Context) ([]*types.GameRedirect, error) {
3657+
func (s *SiteService) GetGameRedirectsPageData(ctx context.Context) (*types.GameRedirectsPageData, error) {
36583658
dbs, err := s.pgdal.NewSession(ctx)
36593659
if err != nil {
36603660
utils.LogCtx(ctx).Error(err)
@@ -3666,7 +3666,40 @@ func (s *SiteService) GetGameRedirects(ctx context.Context) ([]*types.GameRedire
36663666
utils.LogCtx(ctx).Error(err)
36673667
return nil, dberr(err)
36683668
}
3669-
return redirects, nil
3669+
3670+
bpd, err := s.GetBasePageData(ctx)
3671+
if err != nil {
3672+
return nil, err
3673+
}
3674+
3675+
pageData := &types.GameRedirectsPageData{
3676+
BasePageData: *bpd,
3677+
GameRedirects: redirects,
3678+
}
3679+
3680+
return pageData, nil
3681+
}
3682+
3683+
func (s *SiteService) AddNewGameRedirect(ctx context.Context, srcId string, destId string) error {
3684+
dbs, err := s.pgdal.NewSession(ctx)
3685+
if err != nil {
3686+
utils.LogCtx(ctx).Error(err)
3687+
return dberr(err)
3688+
}
3689+
3690+
err = s.pgdal.AddGameRedirect(dbs, srcId, destId)
3691+
if err != nil {
3692+
utils.LogCtx(ctx).Error(err)
3693+
return dberr(err)
3694+
}
3695+
3696+
err = dbs.Commit()
3697+
if err != nil {
3698+
utils.LogCtx(ctx).Error(err)
3699+
return dberr(err)
3700+
}
3701+
3702+
return nil
36703703
}
36713704

36723705
// NukeSessionTable nukes the session table

static/styles.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,3 +764,8 @@ video {
764764
.session-field-name {
765765
font-weight: bold;
766766
}
767+
768+
.monospaced {
769+
font-family: monospace;
770+
font-size: 1.25em;
771+
}

templates/game-redirects.gohtml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{{define "main"}}
2+
<div class="content">
3+
<script>
4+
function onAddNewRedirect() {
5+
const s = document.getElementById("source").value;
6+
const d = document.getElementById("dest").value;
7+
if (s && d) {
8+
fetch("/api/game-redirects", {
9+
method: "POST",
10+
body: JSON.stringify({
11+
sourceId: s,
12+
destId: d,
13+
})
14+
})
15+
.then(res => {
16+
if (res.ok) {
17+
window.location.reload();
18+
} else {
19+
alert(`ERROR: ${res.status} - ${res.text()}`);
20+
}
21+
})
22+
.catch(err => {
23+
alert(err);
24+
})
25+
}
26+
}
27+
</script>
28+
29+
<h1>Game Redirects</h1>
30+
{{if isFreezer .UserRoles}}
31+
<div>
32+
<label>Source</label>
33+
<input id="source" type="text"></input>
34+
<label>Destination</label>
35+
<input id="dest" type="text"></input>
36+
<button onclick="onAddNewRedirect()">Add New Redirect</button>
37+
</div>
38+
<br>
39+
{{end}}
40+
41+
<table class="pure-table pure-table-striped submissions-table monospaced">
42+
<thead>
43+
<tr>
44+
<th>Source</th>
45+
<th>Destination</th>
46+
</tr>
47+
</thead>
48+
<tbody>
49+
{{range .GameRedirects}}
50+
<tr>
51+
<td>{{.SourceId}}</td>
52+
<td>{{.DestId}}</td>
53+
</tr>
54+
{{end}}
55+
</tbody>
56+
</table>
57+
</div>
58+
{{end}}

transport/handlers.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,13 +1178,36 @@ func (a *App) HandleUnfreezeGame(w http.ResponseWriter, r *http.Request) {
11781178
func (a *App) HandleGameRedirects(w http.ResponseWriter, r *http.Request) {
11791179
ctx := r.Context()
11801180

1181-
data, err := a.Service.GetGameRedirects(ctx)
1181+
pageData, err := a.Service.GetGameRedirectsPageData(ctx)
11821182
if err != nil {
11831183
writeError(ctx, w, err)
11841184
return
11851185
}
11861186

1187-
writeResponse(ctx, w, data, http.StatusOK)
1187+
if utils.RequestType(ctx) == constants.RequestJSON {
1188+
if r.Method == http.MethodGet {
1189+
writeResponse(ctx, w, pageData.GameRedirects, http.StatusOK)
1190+
return
1191+
} else {
1192+
// POST
1193+
var requestBody types.AddGameRedirectRequest
1194+
err = json.NewDecoder(r.Body).Decode(&requestBody)
1195+
if err != nil {
1196+
writeResponse(ctx, w, err, http.StatusBadRequest)
1197+
return
1198+
}
1199+
err := a.Service.AddNewGameRedirect(ctx, requestBody.SourceId, requestBody.DestId)
1200+
if err != nil {
1201+
writeError(ctx, w, err)
1202+
return
1203+
}
1204+
writeResponse(ctx, w, "success", http.StatusOK)
1205+
return
1206+
}
1207+
}
1208+
1209+
a.RenderTemplates(ctx, w, r, pageData,
1210+
"templates/game-redirects.gohtml")
11881211
}
11891212

11901213
func (a *App) HandleSubmissionsPage(w http.ResponseWriter, r *http.Request) {

transport/middlewares.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,61 @@ func (a *App) AdminPassAuth(next func(http.ResponseWriter, *http.Request)) func(
8787
}
8888
}
8989

90+
// Loads user info into the context without any page authorization requirements
91+
func (a *App) OpenMux(next func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
92+
return func(w http.ResponseWriter, r *http.Request) {
93+
ctx := r.Context()
94+
95+
secret := ""
96+
authHeader := r.Header.Get("Authorization")
97+
if authHeader != "" {
98+
checkAuth := func() *string {
99+
// try bearer token
100+
// split the header at the space character
101+
authHeaderParts := strings.Split(authHeader, " ")
102+
if len(authHeaderParts) != 2 || authHeaderParts[0] != "Bearer" {
103+
return nil
104+
}
105+
decodedBytes, err := base64.StdEncoding.DecodeString(authHeaderParts[1])
106+
if err != nil {
107+
return nil
108+
}
109+
var tokenMap map[string]string
110+
err = json.Unmarshal(decodedBytes, &tokenMap)
111+
if err != nil {
112+
return nil
113+
}
114+
token, err := service.ParseAuthToken(tokenMap)
115+
if err != nil {
116+
return nil
117+
}
118+
return &token.Secret
119+
}
120+
found := checkAuth()
121+
if found != nil {
122+
secret = *found
123+
}
124+
} else {
125+
// try cookie
126+
found, err := a.GetSecretFromCookie(ctx, r)
127+
if err == nil {
128+
secret = found
129+
}
130+
}
131+
132+
if secret != "" {
133+
authInfo, ok, err := a.Service.GetSessionAuthInfo(ctx, secret)
134+
if ok && err == nil {
135+
r = r.WithContext(context.WithValue(ctx, utils.CtxKeys.UserID, authInfo.UID))
136+
r = r.WithContext(context.WithValue(r.Context(), utils.CtxKeys.Scope, authInfo.Scope))
137+
}
138+
}
139+
140+
next(w, r)
141+
return
142+
}
143+
}
144+
90145
// UserAuthMux takes many authorization middlewares and accepts if any of them does not return error
91146
func (a *App) UserAuthMux(next func(http.ResponseWriter, *http.Request), authorizers ...func(*http.Request, int64) (bool, error)) func(http.ResponseWriter, *http.Request) {
92147
return func(w http.ResponseWriter, r *http.Request) {

transport/router.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,27 @@ func (a *App) handleRequests(l *logrus.Entry, srv *http.Server, router *mux.Rout
435435

436436
////////////////////////
437437

438+
f = a.OpenMux(a.HandleGameRedirects)
439+
440+
router.Handle(
441+
"/web/game-redirects",
442+
http.HandlerFunc(a.RequestWeb(f, true))).
443+
Methods("GET")
444+
438445
router.Handle(
439446
"/api/game-redirects",
440-
http.HandlerFunc(a.RequestJSON(a.HandleGameRedirects, true))).
447+
http.HandlerFunc(a.RequestJSON(f, true))).
441448
Methods("GET")
442449

450+
f = a.UserAuthMux(
451+
a.RequestScope(a.HandleGameRedirects, types.AuthScopeRedirectEdit),
452+
muxAny(isFreezer))
453+
454+
router.Handle(
455+
"/api/game-redirects",
456+
http.HandlerFunc(a.RequestJSON(f, true))).
457+
Methods("POST")
458+
443459
////////////////////////
444460

445461
f = a.UserAuthMux(

types/auth.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const (
7777
AuthScopeGameRead = "game:read"
7878
AuthScopeGameEdit = "game:edit"
7979
AuthScopeHashCheck = "hash-check"
80+
AuthScopeRedirectEdit = "redirect:edit"
8081
)
8182

8283
type ClientApplication struct {

types/pagedata.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ type GameDataIndexPageData struct {
9090
Index *GameDataIndex
9191
}
9292

93+
type GameRedirectsPageData struct {
94+
BasePageData
95+
GameRedirects []*GameRedirect
96+
}
97+
9398
type SubmissionsPageData struct {
9499
BasePageData
95100
Submissions []*ExtendedSubmission

types/types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,3 +945,8 @@ type ActivityEventsFilter struct {
945945
From int64 `schema:"from"`
946946
To int64 `schema:"to"`
947947
}
948+
949+
type AddGameRedirectRequest struct {
950+
SourceId string `json:"sourceId"`
951+
DestId string `json:"destId"`
952+
}

0 commit comments

Comments
 (0)