Skip to content

Commit 0446c60

Browse files
committed
Allow professors to request all nodegroups
1 parent a32650e commit 0446c60

9 files changed

Lines changed: 87 additions & 26 deletions

File tree

controller/workspace.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package controller
33
import (
44
"log/slog"
55
"net/http"
6-
"slices"
76
"strings"
87

98
"github.com/labstack/echo/v4"
@@ -81,7 +80,7 @@ func checkNodegroups(user *auth.User, nodegroup string) error {
8180
if !model.Nodegroup(nodegroup).Valid() {
8281
return echo.ErrBadRequest
8382
}
84-
if slices.Contains(user.Groups, nodegroup) {
83+
if model.Nodegroup(nodegroup).AvailableToGroups(user.Groups) {
8584
return nil
8685
}
8786
return echo.ErrForbidden

controller/workspace_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package controller
2+
3+
import (
4+
"testing"
5+
6+
"github.com/labstack/echo/v4"
7+
8+
"github.com/bacchus-snu/sgs/model"
9+
"github.com/bacchus-snu/sgs/pkg/auth"
10+
)
11+
12+
func TestCheckNodegroups(t *testing.T) {
13+
tests := map[string]struct {
14+
groups []string
15+
nodegroup string
16+
wantErr error
17+
}{
18+
"undergraduate user can request undergraduate": {
19+
groups: []string{string(model.NodegroupUndergraduate)},
20+
nodegroup: string(model.NodegroupUndergraduate),
21+
},
22+
"graduate user can request graduate": {
23+
groups: []string{string(model.NodegroupGraduate)},
24+
nodegroup: string(model.NodegroupGraduate),
25+
},
26+
"professor user can request undergraduate": {
27+
groups: []string{model.UserGroupProfessor},
28+
nodegroup: string(model.NodegroupUndergraduate),
29+
},
30+
"professor user can request graduate": {
31+
groups: []string{model.UserGroupProfessor},
32+
nodegroup: string(model.NodegroupGraduate),
33+
},
34+
"undergraduate user cannot request graduate": {
35+
groups: []string{string(model.NodegroupUndergraduate)},
36+
nodegroup: string(model.NodegroupGraduate),
37+
wantErr: echo.ErrForbidden,
38+
},
39+
"invalid nodegroup is rejected": {
40+
groups: []string{model.UserGroupProfessor},
41+
nodegroup: "invalid",
42+
wantErr: echo.ErrBadRequest,
43+
},
44+
}
45+
46+
for name, tt := range tests {
47+
t.Run(name, func(t *testing.T) {
48+
user := &auth.User{Groups: tt.groups}
49+
if gotErr := checkNodegroups(user, tt.nodegroup); gotErr != tt.wantErr {
50+
t.Fatalf("checkNodegroups() = %v; want %v", gotErr, tt.wantErr)
51+
}
52+
})
53+
}
54+
}

docs/en/src/usage/request-workspace.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[sgs-request]: https://sgs.snucse.org/request
55

66
> Before continuing, you must already have a [SNUCSE ID][id] account registered
7-
> in either the `undergraduate` or `graduate` groups.
7+
> in the `undergraduate`, `graduate`, or `professor` group.
88
99
To request a workspace, fill out the Workspace request form on the SGS
1010
[workspace management page][sgs-request].

docs/ko/src/usage/request-workspace.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[id]: https://id.snucse.org
44
[sgs-request]: https://sgs.snucse.org/request
55

6-
> 시작하기 전에 `undergraduate` 또는 `graduate` 그룹에 등록된 [스누씨 계정][id]이 필요합니다.
6+
> 시작하기 전에 `undergraduate`, `graduate`, 또는 `professor` 그룹에 등록된 [스누씨 계정][id]이 필요합니다.
77
88
워크스페이스를 신청하려면 SGS [워크스페이스 관리 페이지][sgs-request]에서 신청 양식을 작성하세요.
99

model/workspace.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package model
22

33
import (
44
"context"
5+
"slices"
56
)
67

78
// WorkspaceUser represents a user in a workspace with their acceptance status.
@@ -119,13 +120,13 @@ func (ws WorkspaceUpdate) Valid() bool {
119120
type Resource string
120121

121122
const (
122-
ResCPURequest Resource = "requests.cpu"
123-
ResCPULimit Resource = "limits.cpu"
124-
ResMemoryRequest Resource = "requests.memory"
125-
ResMemoryLimit Resource = "limits.memory"
126-
ResStorageRequest Resource = "requests.storage"
127-
ResGPURequest Resource = "requests.nvidia.com/gpu"
128-
ResGPUMemoryRequest Resource = "requests.nvidia.com/gpumem"
123+
ResCPURequest Resource = "requests.cpu"
124+
ResCPULimit Resource = "limits.cpu"
125+
ResMemoryRequest Resource = "requests.memory"
126+
ResMemoryLimit Resource = "limits.memory"
127+
ResStorageRequest Resource = "requests.storage"
128+
ResGPURequest Resource = "requests.nvidia.com/gpu"
129+
ResGPUMemoryRequest Resource = "requests.nvidia.com/gpumem"
129130
)
130131

131132
var Resources = []Resource{
@@ -149,6 +150,8 @@ type Nodegroup string
149150
const (
150151
NodegroupUndergraduate Nodegroup = "undergraduate"
151152
NodegroupGraduate Nodegroup = "graduate"
153+
154+
UserGroupProfessor = "professor"
152155
)
153156

154157
var Nodegroups = []Nodegroup{
@@ -164,6 +167,13 @@ func (n Nodegroup) Valid() bool {
164167
return false
165168
}
166169

170+
func (n Nodegroup) AvailableToGroups(groups []string) bool {
171+
if !n.Valid() {
172+
return false
173+
}
174+
return slices.Contains(groups, string(n)) || slices.Contains(groups, UserGroupProfessor)
175+
}
176+
167177
type WorkspaceService interface {
168178
// Accept user-provided fields only.
169179
CreateWorkspace(ctx context.Context, ws *Workspace, creatorEmail string) (*Workspace, error)

view/request.templ

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package view
22

33
import (
44
"github.com/bacchus-snu/sgs/model"
5-
"slices"
65
)
76

87
const reasonPlaceholder = `Protein Language Model을 활용해 Protein의 특성을 예측하는 연구를 진행하고 있습니다. GPU 1장에서 모델 fine-tuning과 evaulation을 진행하고자 합니다.
@@ -18,7 +17,7 @@ templ PageRequestForm() {
1817
<select id="nodegroup" name="nodegroup" required>
1918
<option value="">Select a nodegroup</option>
2019
for _, ng := range model.Nodegroups {
21-
if slices.Contains(ctxUser(ctx).Groups, string(ng)) {
20+
if ng.AvailableToGroups(ctxUser(ctx).Groups) {
2221
<option value={ string(ng) }>{ string(ng) }</option>
2322
}
2423
}

view/request_templ.go

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

view/workspace.templ

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ templ workspaceDetails(ws, newWS *model.Workspace) {
160160
<select id="nodegroup" name="nodegroup" required>
161161
<option value="">Select a nodegroup</option>
162162
for _, ng := range model.Nodegroups {
163-
if user := ctxUser(ctx); user.IsAdmin() || slices.Contains(user.Groups, string(ng)) {
163+
if user := ctxUser(ctx); user.IsAdmin() || ng.AvailableToGroups(user.Groups) {
164164
<option value={ string(ng) } selected?={ ng == newWS.Nodegroup }>{ string(ng) }</option>
165165
}
166166
}

view/workspace_templ.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)