-
Notifications
You must be signed in to change notification settings - Fork 2
/
participant.go
69 lines (58 loc) · 2.43 KB
/
participant.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package service
import (
"context"
"errors"
"net/http"
"github.com/go-chi/render"
"github.com/France-ioi/AlgoreaBackend/app/auth"
"github.com/France-ioi/AlgoreaBackend/app/database"
)
type participantMiddlewareKey int
const ctxParticipant participantMiddlewareKey = iota
// GetStorer is an interface allowing to get a data store bound to the context of the given request.
type GetStorer interface {
GetStore(r *http.Request) *database.DataStore
}
// ParticipantMiddleware is a middleware retrieving a participant from the request content.
// The participant id is the `as_team_id` parameter value if it is given or the user's `group_id` otherwise.
// If `as_team_id` is given, it should be an id of a team and the user should be a member of this team, otherwise
// the 'forbidden' error is returned.
func ParticipantMiddleware(srv GetStorer) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := auth.UserFromContext(r.Context())
participantID, apiError := GetParticipantIDFromRequest(r, user, srv.GetStore(r))
if apiError != NoError {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = render.Render(w, r, apiError.httpResponse())
return
}
ctx := context.WithValue(r.Context(), ctxParticipant, participantID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// ParticipantIDFromContext retrieves a participant id set by the middleware from a context.
func ParticipantIDFromContext(ctx context.Context) int64 {
return ctx.Value(ctxParticipant).(int64)
}
// GetParticipantIDFromRequest returns `as_team_id` parameter value if it is given or the user's `group_id` otherwise.
// If `as_team_id` is given, it should be an id of a team and the user should be a member of this team, otherwise
// the 'forbidden' error is returned.
func GetParticipantIDFromRequest(httpReq *http.Request, user *database.User, store *database.DataStore) (int64, APIError) {
groupID := user.GroupID
var err error
if len(httpReq.URL.Query()["as_team_id"]) != 0 {
groupID, err = ResolveURLQueryGetInt64Field(httpReq, "as_team_id")
if err != nil {
return 0, ErrInvalidRequest(err)
}
var found bool
found, err = store.Groups().TeamGroupForUser(groupID, user).HasRows()
MustNotBeError(err)
if !found {
return 0, ErrForbidden(errors.New("can't use given as_team_id as a user's team"))
}
}
return groupID, NoError
}