@sideline/domain 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/api/AgeThresholdApi.js +86 -0
- package/dist/cjs/api/AgeThresholdApi.js.map +1 -0
- package/dist/cjs/api/Auth.js +33 -2
- package/dist/cjs/api/Auth.js.map +1 -1
- package/dist/cjs/api/Invite.js +1 -2
- package/dist/cjs/api/Invite.js.map +1 -1
- package/dist/cjs/api/NotificationApi.js +42 -0
- package/dist/cjs/api/NotificationApi.js.map +1 -0
- package/dist/cjs/api/RoleApi.js +123 -0
- package/dist/cjs/api/RoleApi.js.map +1 -0
- package/dist/cjs/api/Roster.js +159 -0
- package/dist/cjs/api/Roster.js.map +1 -0
- package/dist/cjs/api/SubgroupApi.js +122 -0
- package/dist/cjs/api/SubgroupApi.js.map +1 -0
- package/dist/cjs/index.js +31 -1
- package/dist/cjs/models/AgeThresholdRule.js +21 -0
- package/dist/cjs/models/AgeThresholdRule.js.map +1 -0
- package/dist/cjs/models/DiscordRoleMapping.js +20 -0
- package/dist/cjs/models/DiscordRoleMapping.js.map +1 -0
- package/dist/cjs/models/MemberRole.js +15 -0
- package/dist/cjs/models/MemberRole.js.map +1 -0
- package/dist/cjs/models/Notification.js +24 -0
- package/dist/cjs/models/Notification.js.map +1 -0
- package/dist/cjs/models/Role.js +32 -0
- package/dist/cjs/models/Role.js.map +1 -0
- package/dist/cjs/models/RoleSyncEvent.js +28 -0
- package/dist/cjs/models/RoleSyncEvent.js.map +1 -0
- package/dist/cjs/models/RosterMemberModel.js +19 -0
- package/dist/cjs/models/RosterMemberModel.js.map +1 -0
- package/dist/cjs/models/RosterModel.js +19 -0
- package/dist/cjs/models/RosterModel.js.map +1 -0
- package/dist/cjs/models/SubgroupModel.js +18 -0
- package/dist/cjs/models/SubgroupModel.js.map +1 -0
- package/dist/cjs/models/TeamMember.js +2 -3
- package/dist/cjs/models/TeamMember.js.map +1 -1
- package/dist/cjs/rpc/RoleSyncRpc.js +66 -0
- package/dist/cjs/rpc/RoleSyncRpc.js.map +1 -0
- package/dist/dts/api/AgeThresholdApi.d.ts +119 -0
- package/dist/dts/api/AgeThresholdApi.d.ts.map +1 -0
- package/dist/dts/api/Auth.d.ts +60 -1
- package/dist/dts/api/Auth.d.ts.map +1 -1
- package/dist/dts/api/Invite.d.ts +7 -7
- package/dist/dts/api/Invite.d.ts.map +1 -1
- package/dist/dts/api/NotificationApi.d.ts +53 -0
- package/dist/dts/api/NotificationApi.d.ts.map +1 -0
- package/dist/dts/api/RoleApi.d.ts +138 -0
- package/dist/dts/api/RoleApi.d.ts.map +1 -0
- package/dist/dts/api/Roster.d.ts +225 -0
- package/dist/dts/api/Roster.d.ts.map +1 -0
- package/dist/dts/api/SubgroupApi.d.ts +140 -0
- package/dist/dts/api/SubgroupApi.d.ts.map +1 -0
- package/dist/dts/index.d.ts +15 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/models/AgeThresholdRule.d.ts +97 -0
- package/dist/dts/models/AgeThresholdRule.d.ts.map +1 -0
- package/dist/dts/models/DiscordRoleMapping.d.ts +84 -0
- package/dist/dts/models/DiscordRoleMapping.d.ts.map +1 -0
- package/dist/dts/models/MemberRole.d.ts +16 -0
- package/dist/dts/models/MemberRole.d.ts.map +1 -0
- package/dist/dts/models/Notification.d.ts +125 -0
- package/dist/dts/models/Notification.d.ts.map +1 -0
- package/dist/dts/models/Role.d.ts +102 -0
- package/dist/dts/models/Role.d.ts.map +1 -0
- package/dist/dts/models/RoleSyncEvent.d.ts +164 -0
- package/dist/dts/models/RoleSyncEvent.d.ts.map +1 -0
- package/dist/dts/models/RosterMemberModel.d.ts +71 -0
- package/dist/dts/models/RosterMemberModel.d.ts.map +1 -0
- package/dist/dts/models/RosterModel.d.ts +84 -0
- package/dist/dts/models/RosterModel.d.ts.map +1 -0
- package/dist/dts/models/SubgroupModel.d.ts +71 -0
- package/dist/dts/models/SubgroupModel.d.ts.map +1 -0
- package/dist/dts/models/TeamInvite.d.ts +4 -4
- package/dist/dts/models/TeamMember.d.ts +11 -13
- package/dist/dts/models/TeamMember.d.ts.map +1 -1
- package/dist/dts/rpc/RoleSyncRpc.d.ts +82 -0
- package/dist/dts/rpc/RoleSyncRpc.d.ts.map +1 -0
- package/dist/esm/api/AgeThresholdApi.js +72 -0
- package/dist/esm/api/AgeThresholdApi.js.map +1 -0
- package/dist/esm/api/Auth.js +28 -1
- package/dist/esm/api/Auth.js.map +1 -1
- package/dist/esm/api/Invite.js +1 -2
- package/dist/esm/api/Invite.js.map +1 -1
- package/dist/esm/api/NotificationApi.js +32 -0
- package/dist/esm/api/NotificationApi.js.map +1 -0
- package/dist/esm/api/RoleApi.js +106 -0
- package/dist/esm/api/RoleApi.js.map +1 -0
- package/dist/esm/api/Roster.js +142 -0
- package/dist/esm/api/Roster.js.map +1 -0
- package/dist/esm/api/SubgroupApi.js +106 -0
- package/dist/esm/api/SubgroupApi.js.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/models/AgeThresholdRule.js +14 -0
- package/dist/esm/models/AgeThresholdRule.js.map +1 -0
- package/dist/esm/models/DiscordRoleMapping.js +13 -0
- package/dist/esm/models/DiscordRoleMapping.js.map +1 -0
- package/dist/esm/models/MemberRole.js +8 -0
- package/dist/esm/models/MemberRole.js.map +1 -0
- package/dist/esm/models/Notification.js +17 -0
- package/dist/esm/models/Notification.js.map +1 -0
- package/dist/esm/models/Role.js +24 -0
- package/dist/esm/models/Role.js.map +1 -0
- package/dist/esm/models/RoleSyncEvent.js +21 -0
- package/dist/esm/models/RoleSyncEvent.js.map +1 -0
- package/dist/esm/models/RosterMemberModel.js +12 -0
- package/dist/esm/models/RosterMemberModel.js.map +1 -0
- package/dist/esm/models/RosterModel.js +12 -0
- package/dist/esm/models/RosterModel.js.map +1 -0
- package/dist/esm/models/SubgroupModel.js +11 -0
- package/dist/esm/models/SubgroupModel.js.map +1 -0
- package/dist/esm/models/TeamMember.js +1 -2
- package/dist/esm/models/TeamMember.js.map +1 -1
- package/dist/esm/rpc/RoleSyncRpc.js +57 -0
- package/dist/esm/rpc/RoleSyncRpc.js.map +1 -0
- package/package.json +2 -1
- package/src/api/AgeThresholdApi.ts +99 -0
- package/src/api/Auth.ts +52 -0
- package/src/api/Invite.ts +1 -2
- package/src/api/NotificationApi.ts +49 -0
- package/src/api/RoleApi.ts +130 -0
- package/src/api/Roster.ts +176 -0
- package/src/api/SubgroupApi.ts +146 -0
- package/src/index.ts +30 -0
- package/src/models/AgeThresholdRule.ts +16 -0
- package/src/models/DiscordRoleMapping.ts +15 -0
- package/src/models/MemberRole.ts +8 -0
- package/src/models/Notification.ts +26 -0
- package/src/models/Role.ts +53 -0
- package/src/models/RoleSyncEvent.ts +30 -0
- package/src/models/RosterMemberModel.ts +14 -0
- package/src/models/RosterModel.ts +14 -0
- package/src/models/SubgroupModel.ts +13 -0
- package/src/models/TeamMember.ts +1 -4
- package/src/rpc/RoleSyncRpc.ts +59 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from '@effect/platform';
|
|
2
|
+
import { Schema } from 'effect';
|
|
3
|
+
import { AuthMiddleware } from '~/api/Auth.js';
|
|
4
|
+
import { AgeThresholdRuleId } from '~/models/AgeThresholdRule.js';
|
|
5
|
+
import { RoleId } from '~/models/Role.js';
|
|
6
|
+
import { TeamId } from '~/models/Team.js';
|
|
7
|
+
import { TeamMemberId } from '~/models/TeamMember.js';
|
|
8
|
+
|
|
9
|
+
export class AgeThresholdInfo extends Schema.Class<AgeThresholdInfo>('AgeThresholdInfo')({
|
|
10
|
+
ruleId: AgeThresholdRuleId,
|
|
11
|
+
teamId: TeamId,
|
|
12
|
+
roleId: RoleId,
|
|
13
|
+
roleName: Schema.String,
|
|
14
|
+
minAge: Schema.NullOr(Schema.Number),
|
|
15
|
+
maxAge: Schema.NullOr(Schema.Number),
|
|
16
|
+
}) {}
|
|
17
|
+
|
|
18
|
+
export class AgeRoleChange extends Schema.Class<AgeRoleChange>('AgeRoleChange')({
|
|
19
|
+
memberId: TeamMemberId,
|
|
20
|
+
memberName: Schema.String,
|
|
21
|
+
roleId: RoleId,
|
|
22
|
+
roleName: Schema.String,
|
|
23
|
+
action: Schema.Literal('assigned', 'removed'),
|
|
24
|
+
}) {}
|
|
25
|
+
|
|
26
|
+
export class CreateAgeThresholdRequest extends Schema.Class<CreateAgeThresholdRequest>(
|
|
27
|
+
'CreateAgeThresholdRequest',
|
|
28
|
+
)({
|
|
29
|
+
roleId: RoleId,
|
|
30
|
+
minAge: Schema.NullOr(Schema.Number),
|
|
31
|
+
maxAge: Schema.NullOr(Schema.Number),
|
|
32
|
+
}) {}
|
|
33
|
+
|
|
34
|
+
export class UpdateAgeThresholdRequest extends Schema.Class<UpdateAgeThresholdRequest>(
|
|
35
|
+
'UpdateAgeThresholdRequest',
|
|
36
|
+
)({
|
|
37
|
+
minAge: Schema.NullOr(Schema.Number),
|
|
38
|
+
maxAge: Schema.NullOr(Schema.Number),
|
|
39
|
+
}) {}
|
|
40
|
+
|
|
41
|
+
export class Forbidden extends Schema.TaggedError<Forbidden>()(
|
|
42
|
+
'AgeThresholdForbidden',
|
|
43
|
+
{},
|
|
44
|
+
HttpApiSchema.annotations({ status: 403 }),
|
|
45
|
+
) {}
|
|
46
|
+
|
|
47
|
+
export class RuleNotFound extends Schema.TaggedError<RuleNotFound>()(
|
|
48
|
+
'AgeThresholdRuleNotFound',
|
|
49
|
+
{},
|
|
50
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
51
|
+
) {}
|
|
52
|
+
|
|
53
|
+
export class RoleNotFound extends Schema.TaggedError<RoleNotFound>()(
|
|
54
|
+
'AgeThresholdRoleNotFound',
|
|
55
|
+
{},
|
|
56
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
57
|
+
) {}
|
|
58
|
+
|
|
59
|
+
export class AgeThresholdApiGroup extends HttpApiGroup.make('ageThreshold')
|
|
60
|
+
.add(
|
|
61
|
+
HttpApiEndpoint.get('listAgeThresholds', '/teams/:teamId/age-thresholds')
|
|
62
|
+
.addSuccess(Schema.Array(AgeThresholdInfo))
|
|
63
|
+
.addError(Forbidden, { status: 403 })
|
|
64
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
65
|
+
.middleware(AuthMiddleware),
|
|
66
|
+
)
|
|
67
|
+
.add(
|
|
68
|
+
HttpApiEndpoint.post('createAgeThreshold', '/teams/:teamId/age-thresholds')
|
|
69
|
+
.addSuccess(AgeThresholdInfo, { status: 201 })
|
|
70
|
+
.addError(Forbidden, { status: 403 })
|
|
71
|
+
.addError(RoleNotFound, { status: 404 })
|
|
72
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
73
|
+
.setPayload(CreateAgeThresholdRequest)
|
|
74
|
+
.middleware(AuthMiddleware),
|
|
75
|
+
)
|
|
76
|
+
.add(
|
|
77
|
+
HttpApiEndpoint.patch('updateAgeThreshold', '/teams/:teamId/age-thresholds/:ruleId')
|
|
78
|
+
.addSuccess(AgeThresholdInfo)
|
|
79
|
+
.addError(Forbidden, { status: 403 })
|
|
80
|
+
.addError(RuleNotFound, { status: 404 })
|
|
81
|
+
.setPath(Schema.Struct({ teamId: TeamId, ruleId: AgeThresholdRuleId }))
|
|
82
|
+
.setPayload(UpdateAgeThresholdRequest)
|
|
83
|
+
.middleware(AuthMiddleware),
|
|
84
|
+
)
|
|
85
|
+
.add(
|
|
86
|
+
HttpApiEndpoint.del('deleteAgeThreshold', '/teams/:teamId/age-thresholds/:ruleId')
|
|
87
|
+
.addSuccess(Schema.Void)
|
|
88
|
+
.addError(Forbidden, { status: 403 })
|
|
89
|
+
.addError(RuleNotFound, { status: 404 })
|
|
90
|
+
.setPath(Schema.Struct({ teamId: TeamId, ruleId: AgeThresholdRuleId }))
|
|
91
|
+
.middleware(AuthMiddleware),
|
|
92
|
+
)
|
|
93
|
+
.add(
|
|
94
|
+
HttpApiEndpoint.post('evaluateAgeThresholds', '/teams/:teamId/age-thresholds/evaluate')
|
|
95
|
+
.addSuccess(Schema.Array(AgeRoleChange))
|
|
96
|
+
.addError(Forbidden, { status: 403 })
|
|
97
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
98
|
+
.middleware(AuthMiddleware),
|
|
99
|
+
) {}
|
package/src/api/Auth.ts
CHANGED
|
@@ -6,12 +6,21 @@ import {
|
|
|
6
6
|
HttpApiSecurity,
|
|
7
7
|
} from '@effect/platform';
|
|
8
8
|
import { Context, Schema } from 'effect';
|
|
9
|
+
import { Permission } from '~/models/Role.js';
|
|
10
|
+
import { TeamId } from '~/models/Team.js';
|
|
9
11
|
import { Gender, Locale, Position, Proficiency, UserId } from '~/models/User.js';
|
|
10
12
|
|
|
11
13
|
export { UserId } from '~/models/User.js';
|
|
12
14
|
|
|
13
15
|
export const MIN_AGE = 6;
|
|
14
16
|
|
|
17
|
+
export class UserTeam extends Schema.Class<UserTeam>('UserTeam')({
|
|
18
|
+
teamId: TeamId,
|
|
19
|
+
teamName: Schema.String,
|
|
20
|
+
roleNames: Schema.Array(Schema.String),
|
|
21
|
+
permissions: Schema.Array(Permission),
|
|
22
|
+
}) {}
|
|
23
|
+
|
|
15
24
|
export class CurrentUser extends Schema.Class<CurrentUser>('CurrentUser')({
|
|
16
25
|
id: UserId,
|
|
17
26
|
discordId: Schema.String,
|
|
@@ -31,6 +40,10 @@ export class UpdateLocaleRequest extends Schema.Class<UpdateLocaleRequest>('Upda
|
|
|
31
40
|
locale: Locale,
|
|
32
41
|
}) {}
|
|
33
42
|
|
|
43
|
+
export class CreateTeamRequest extends Schema.Class<CreateTeamRequest>('CreateTeamRequest')({
|
|
44
|
+
name: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(100)),
|
|
45
|
+
}) {}
|
|
46
|
+
|
|
34
47
|
export class CompleteProfileRequest extends Schema.Class<CompleteProfileRequest>(
|
|
35
48
|
'CompleteProfileRequest',
|
|
36
49
|
)({
|
|
@@ -50,6 +63,25 @@ export class CompleteProfileRequest extends Schema.Class<CompleteProfileRequest>
|
|
|
50
63
|
proficiency: Proficiency,
|
|
51
64
|
}) {}
|
|
52
65
|
|
|
66
|
+
export class UpdateProfileRequest extends Schema.Class<UpdateProfileRequest>(
|
|
67
|
+
'UpdateProfileRequest',
|
|
68
|
+
)({
|
|
69
|
+
name: Schema.NullOr(Schema.String),
|
|
70
|
+
birthYear: Schema.NullOr(
|
|
71
|
+
Schema.Number.pipe(
|
|
72
|
+
Schema.int(),
|
|
73
|
+
Schema.greaterThanOrEqualTo(1900),
|
|
74
|
+
Schema.filter((year) => year <= new Date().getFullYear() - MIN_AGE, {
|
|
75
|
+
message: () => `Birth year must be at most ${new Date().getFullYear() - MIN_AGE}`,
|
|
76
|
+
}),
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
gender: Schema.NullOr(Gender),
|
|
80
|
+
jerseyNumber: Schema.NullOr(Schema.Number.pipe(Schema.int(), Schema.between(0, 99))),
|
|
81
|
+
position: Schema.NullOr(Position),
|
|
82
|
+
proficiency: Schema.NullOr(Proficiency),
|
|
83
|
+
}) {}
|
|
84
|
+
|
|
53
85
|
export class Unauthorized extends Schema.TaggedError<Unauthorized>()(
|
|
54
86
|
'Unauthorized',
|
|
55
87
|
{},
|
|
@@ -101,4 +133,24 @@ export class AuthApiGroup extends HttpApiGroup.make('auth')
|
|
|
101
133
|
.setPayload(UpdateLocaleRequest)
|
|
102
134
|
.middleware(AuthMiddleware),
|
|
103
135
|
)
|
|
136
|
+
.add(
|
|
137
|
+
HttpApiEndpoint.patch('updateProfile', '/me')
|
|
138
|
+
.addSuccess(CurrentUser)
|
|
139
|
+
.addError(Unauthorized, { status: 401 })
|
|
140
|
+
.setPayload(UpdateProfileRequest)
|
|
141
|
+
.middleware(AuthMiddleware),
|
|
142
|
+
)
|
|
143
|
+
.add(
|
|
144
|
+
HttpApiEndpoint.get('myTeams', '/me/teams')
|
|
145
|
+
.addSuccess(Schema.Array(UserTeam))
|
|
146
|
+
.addError(Unauthorized, { status: 401 })
|
|
147
|
+
.middleware(AuthMiddleware),
|
|
148
|
+
)
|
|
149
|
+
.add(
|
|
150
|
+
HttpApiEndpoint.post('createTeam', '/me/teams')
|
|
151
|
+
.addSuccess(UserTeam)
|
|
152
|
+
.addError(Unauthorized, { status: 401 })
|
|
153
|
+
.setPayload(CreateTeamRequest)
|
|
154
|
+
.middleware(AuthMiddleware),
|
|
155
|
+
)
|
|
104
156
|
.prefix('/auth') {}
|
package/src/api/Invite.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from '@effect/platform';
|
|
|
2
2
|
import { Schema } from 'effect';
|
|
3
3
|
import { AuthMiddleware } from '~/api/Auth.js';
|
|
4
4
|
import { TeamId } from '~/models/Team.js';
|
|
5
|
-
import { TeamRole } from '~/models/TeamMember.js';
|
|
6
5
|
|
|
7
6
|
export class InviteInfo extends Schema.Class<InviteInfo>('InviteInfo')({
|
|
8
7
|
teamName: Schema.String,
|
|
@@ -12,7 +11,7 @@ export class InviteInfo extends Schema.Class<InviteInfo>('InviteInfo')({
|
|
|
12
11
|
|
|
13
12
|
export class JoinResult extends Schema.Class<JoinResult>('JoinResult')({
|
|
14
13
|
teamId: TeamId,
|
|
15
|
-
|
|
14
|
+
roleNames: Schema.Array(Schema.String),
|
|
16
15
|
isProfileComplete: Schema.Boolean,
|
|
17
16
|
}) {}
|
|
18
17
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from '@effect/platform';
|
|
2
|
+
import { Schema } from 'effect';
|
|
3
|
+
import { AuthMiddleware } from '~/api/Auth.js';
|
|
4
|
+
import { NotificationId, NotificationType } from '~/models/Notification.js';
|
|
5
|
+
import { TeamId } from '~/models/Team.js';
|
|
6
|
+
|
|
7
|
+
export class NotificationInfo extends Schema.Class<NotificationInfo>('NotificationInfo')({
|
|
8
|
+
notificationId: NotificationId,
|
|
9
|
+
teamId: TeamId,
|
|
10
|
+
type: NotificationType,
|
|
11
|
+
title: Schema.String,
|
|
12
|
+
body: Schema.String,
|
|
13
|
+
isRead: Schema.Boolean,
|
|
14
|
+
createdAt: Schema.String,
|
|
15
|
+
}) {}
|
|
16
|
+
|
|
17
|
+
export class Forbidden extends Schema.TaggedError<Forbidden>()(
|
|
18
|
+
'NotificationForbidden',
|
|
19
|
+
{},
|
|
20
|
+
HttpApiSchema.annotations({ status: 403 }),
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
export class NotificationNotFound extends Schema.TaggedError<NotificationNotFound>()(
|
|
24
|
+
'NotificationNotFound',
|
|
25
|
+
{},
|
|
26
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
27
|
+
) {}
|
|
28
|
+
|
|
29
|
+
export class NotificationApiGroup extends HttpApiGroup.make('notification')
|
|
30
|
+
.add(
|
|
31
|
+
HttpApiEndpoint.get('listNotifications', '/notifications')
|
|
32
|
+
.addSuccess(Schema.Array(NotificationInfo))
|
|
33
|
+
.addError(Forbidden, { status: 403 })
|
|
34
|
+
.middleware(AuthMiddleware),
|
|
35
|
+
)
|
|
36
|
+
.add(
|
|
37
|
+
HttpApiEndpoint.patch('markAsRead', '/notifications/:notificationId/read')
|
|
38
|
+
.addSuccess(Schema.Void)
|
|
39
|
+
.addError(Forbidden, { status: 403 })
|
|
40
|
+
.addError(NotificationNotFound, { status: 404 })
|
|
41
|
+
.setPath(Schema.Struct({ notificationId: NotificationId }))
|
|
42
|
+
.middleware(AuthMiddleware),
|
|
43
|
+
)
|
|
44
|
+
.add(
|
|
45
|
+
HttpApiEndpoint.post('markAllAsRead', '/notifications/read-all')
|
|
46
|
+
.addSuccess(Schema.Void)
|
|
47
|
+
.addError(Forbidden, { status: 403 })
|
|
48
|
+
.middleware(AuthMiddleware),
|
|
49
|
+
) {}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from '@effect/platform';
|
|
2
|
+
import { Schema } from 'effect';
|
|
3
|
+
import { AuthMiddleware } from '~/api/Auth.js';
|
|
4
|
+
import { Permission, RoleId } from '~/models/Role.js';
|
|
5
|
+
import { TeamId } from '~/models/Team.js';
|
|
6
|
+
import { TeamMemberId } from '~/models/TeamMember.js';
|
|
7
|
+
|
|
8
|
+
export class RoleInfo extends Schema.Class<RoleInfo>('RoleInfo')({
|
|
9
|
+
roleId: RoleId,
|
|
10
|
+
teamId: TeamId,
|
|
11
|
+
name: Schema.String,
|
|
12
|
+
isBuiltIn: Schema.Boolean,
|
|
13
|
+
permissionCount: Schema.Number,
|
|
14
|
+
}) {}
|
|
15
|
+
|
|
16
|
+
export class RoleDetail extends Schema.Class<RoleDetail>('RoleDetail')({
|
|
17
|
+
roleId: RoleId,
|
|
18
|
+
teamId: TeamId,
|
|
19
|
+
name: Schema.String,
|
|
20
|
+
isBuiltIn: Schema.Boolean,
|
|
21
|
+
permissions: Schema.Array(Permission),
|
|
22
|
+
}) {}
|
|
23
|
+
|
|
24
|
+
export class CreateRoleRequest extends Schema.Class<CreateRoleRequest>('CreateRoleRequest')({
|
|
25
|
+
name: Schema.NonEmptyString,
|
|
26
|
+
permissions: Schema.Array(Permission),
|
|
27
|
+
}) {}
|
|
28
|
+
|
|
29
|
+
export class UpdateRoleRequest extends Schema.Class<UpdateRoleRequest>('UpdateRoleRequest')({
|
|
30
|
+
name: Schema.NullOr(Schema.NonEmptyString),
|
|
31
|
+
permissions: Schema.NullOr(Schema.Array(Permission)),
|
|
32
|
+
}) {}
|
|
33
|
+
|
|
34
|
+
export class RoleNotFound extends Schema.TaggedError<RoleNotFound>()(
|
|
35
|
+
'RoleNotFound',
|
|
36
|
+
{},
|
|
37
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
38
|
+
) {}
|
|
39
|
+
|
|
40
|
+
export class Forbidden extends Schema.TaggedError<Forbidden>()(
|
|
41
|
+
'RoleForbidden',
|
|
42
|
+
{},
|
|
43
|
+
HttpApiSchema.annotations({ status: 403 }),
|
|
44
|
+
) {}
|
|
45
|
+
|
|
46
|
+
export class CannotModifyBuiltIn extends Schema.TaggedError<CannotModifyBuiltIn>()(
|
|
47
|
+
'CannotModifyBuiltIn',
|
|
48
|
+
{},
|
|
49
|
+
HttpApiSchema.annotations({ status: 400 }),
|
|
50
|
+
) {}
|
|
51
|
+
|
|
52
|
+
export class AssignRoleRequest extends Schema.Class<AssignRoleRequest>('AssignRoleRequest')({
|
|
53
|
+
roleId: RoleId,
|
|
54
|
+
}) {}
|
|
55
|
+
|
|
56
|
+
export class MemberNotFound extends Schema.TaggedError<MemberNotFound>()(
|
|
57
|
+
'MemberNotFound',
|
|
58
|
+
{},
|
|
59
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
60
|
+
) {}
|
|
61
|
+
|
|
62
|
+
export class RoleInUse extends Schema.TaggedError<RoleInUse>()(
|
|
63
|
+
'RoleInUse',
|
|
64
|
+
{},
|
|
65
|
+
HttpApiSchema.annotations({ status: 409 }),
|
|
66
|
+
) {}
|
|
67
|
+
|
|
68
|
+
export class RoleApiGroup extends HttpApiGroup.make('role')
|
|
69
|
+
.add(
|
|
70
|
+
HttpApiEndpoint.get('listRoles', '/teams/:teamId/roles')
|
|
71
|
+
.addSuccess(Schema.Array(RoleInfo))
|
|
72
|
+
.addError(Forbidden, { status: 403 })
|
|
73
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
74
|
+
.middleware(AuthMiddleware),
|
|
75
|
+
)
|
|
76
|
+
.add(
|
|
77
|
+
HttpApiEndpoint.post('createRole', '/teams/:teamId/roles')
|
|
78
|
+
.addSuccess(RoleDetail, { status: 201 })
|
|
79
|
+
.addError(Forbidden, { status: 403 })
|
|
80
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
81
|
+
.setPayload(CreateRoleRequest)
|
|
82
|
+
.middleware(AuthMiddleware),
|
|
83
|
+
)
|
|
84
|
+
.add(
|
|
85
|
+
HttpApiEndpoint.get('getRole', '/teams/:teamId/roles/:roleId')
|
|
86
|
+
.addSuccess(RoleDetail)
|
|
87
|
+
.addError(Forbidden, { status: 403 })
|
|
88
|
+
.addError(RoleNotFound, { status: 404 })
|
|
89
|
+
.setPath(Schema.Struct({ teamId: TeamId, roleId: RoleId }))
|
|
90
|
+
.middleware(AuthMiddleware),
|
|
91
|
+
)
|
|
92
|
+
.add(
|
|
93
|
+
HttpApiEndpoint.patch('updateRole', '/teams/:teamId/roles/:roleId')
|
|
94
|
+
.addSuccess(RoleDetail)
|
|
95
|
+
.addError(Forbidden, { status: 403 })
|
|
96
|
+
.addError(RoleNotFound, { status: 404 })
|
|
97
|
+
.addError(CannotModifyBuiltIn, { status: 400 })
|
|
98
|
+
.setPath(Schema.Struct({ teamId: TeamId, roleId: RoleId }))
|
|
99
|
+
.setPayload(UpdateRoleRequest)
|
|
100
|
+
.middleware(AuthMiddleware),
|
|
101
|
+
)
|
|
102
|
+
.add(
|
|
103
|
+
HttpApiEndpoint.del('deleteRole', '/teams/:teamId/roles/:roleId')
|
|
104
|
+
.addSuccess(Schema.Void)
|
|
105
|
+
.addError(Forbidden, { status: 403 })
|
|
106
|
+
.addError(RoleNotFound, { status: 404 })
|
|
107
|
+
.addError(CannotModifyBuiltIn, { status: 400 })
|
|
108
|
+
.addError(RoleInUse, { status: 409 })
|
|
109
|
+
.setPath(Schema.Struct({ teamId: TeamId, roleId: RoleId }))
|
|
110
|
+
.middleware(AuthMiddleware),
|
|
111
|
+
)
|
|
112
|
+
.add(
|
|
113
|
+
HttpApiEndpoint.post('assignRole', '/teams/:teamId/members/:memberId/roles')
|
|
114
|
+
.addSuccess(Schema.Void, { status: 204 })
|
|
115
|
+
.addError(Forbidden, { status: 403 })
|
|
116
|
+
.addError(MemberNotFound, { status: 404 })
|
|
117
|
+
.addError(RoleNotFound, { status: 404 })
|
|
118
|
+
.setPath(Schema.Struct({ teamId: TeamId, memberId: TeamMemberId }))
|
|
119
|
+
.setPayload(AssignRoleRequest)
|
|
120
|
+
.middleware(AuthMiddleware),
|
|
121
|
+
)
|
|
122
|
+
.add(
|
|
123
|
+
HttpApiEndpoint.del('unassignRole', '/teams/:teamId/members/:memberId/roles/:roleId')
|
|
124
|
+
.addSuccess(Schema.Void)
|
|
125
|
+
.addError(Forbidden, { status: 403 })
|
|
126
|
+
.addError(MemberNotFound, { status: 404 })
|
|
127
|
+
.addError(RoleNotFound, { status: 404 })
|
|
128
|
+
.setPath(Schema.Struct({ teamId: TeamId, memberId: TeamMemberId, roleId: RoleId }))
|
|
129
|
+
.middleware(AuthMiddleware),
|
|
130
|
+
) {}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from '@effect/platform';
|
|
2
|
+
import { Schema } from 'effect';
|
|
3
|
+
import { AuthMiddleware } from '~/api/Auth.js';
|
|
4
|
+
import { Permission } from '~/models/Role.js';
|
|
5
|
+
import { RosterId } from '~/models/RosterModel.js';
|
|
6
|
+
import { TeamId } from '~/models/Team.js';
|
|
7
|
+
import { TeamMemberId } from '~/models/TeamMember.js';
|
|
8
|
+
import { Gender, Position, Proficiency, UserId } from '~/models/User.js';
|
|
9
|
+
|
|
10
|
+
export class RosterPlayer extends Schema.Class<RosterPlayer>('RosterPlayer')({
|
|
11
|
+
memberId: TeamMemberId,
|
|
12
|
+
userId: UserId,
|
|
13
|
+
roleNames: Schema.Array(Schema.String),
|
|
14
|
+
permissions: Schema.Array(Permission),
|
|
15
|
+
name: Schema.NullOr(Schema.String),
|
|
16
|
+
birthYear: Schema.NullOr(Schema.Number),
|
|
17
|
+
gender: Schema.NullOr(Gender),
|
|
18
|
+
jerseyNumber: Schema.NullOr(Schema.Number),
|
|
19
|
+
position: Schema.NullOr(Position),
|
|
20
|
+
proficiency: Schema.NullOr(Proficiency),
|
|
21
|
+
discordUsername: Schema.String,
|
|
22
|
+
discordAvatar: Schema.NullOr(Schema.String),
|
|
23
|
+
}) {}
|
|
24
|
+
|
|
25
|
+
export class UpdatePlayerRequest extends Schema.Class<UpdatePlayerRequest>('UpdatePlayerRequest')({
|
|
26
|
+
name: Schema.NullOr(Schema.String),
|
|
27
|
+
birthYear: Schema.NullOr(Schema.Number),
|
|
28
|
+
gender: Schema.NullOr(Gender),
|
|
29
|
+
jerseyNumber: Schema.NullOr(Schema.Number),
|
|
30
|
+
position: Schema.NullOr(Position),
|
|
31
|
+
proficiency: Schema.NullOr(Proficiency),
|
|
32
|
+
}) {}
|
|
33
|
+
|
|
34
|
+
export class PlayerNotFound extends Schema.TaggedError<PlayerNotFound>()(
|
|
35
|
+
'PlayerNotFound',
|
|
36
|
+
{},
|
|
37
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
38
|
+
) {}
|
|
39
|
+
|
|
40
|
+
export class Forbidden extends Schema.TaggedError<Forbidden>()(
|
|
41
|
+
'Forbidden',
|
|
42
|
+
{},
|
|
43
|
+
HttpApiSchema.annotations({ status: 403 }),
|
|
44
|
+
) {}
|
|
45
|
+
|
|
46
|
+
export class RosterNotFound extends Schema.TaggedError<RosterNotFound>()(
|
|
47
|
+
'RosterNotFound',
|
|
48
|
+
{},
|
|
49
|
+
HttpApiSchema.annotations({ status: 404 }),
|
|
50
|
+
) {}
|
|
51
|
+
|
|
52
|
+
export class RosterInfo extends Schema.Class<RosterInfo>('RosterInfo')({
|
|
53
|
+
rosterId: RosterId,
|
|
54
|
+
teamId: TeamId,
|
|
55
|
+
name: Schema.String,
|
|
56
|
+
active: Schema.Boolean,
|
|
57
|
+
memberCount: Schema.Number,
|
|
58
|
+
createdAt: Schema.String,
|
|
59
|
+
}) {}
|
|
60
|
+
|
|
61
|
+
export class RosterDetail extends Schema.Class<RosterDetail>('RosterDetail')({
|
|
62
|
+
rosterId: RosterId,
|
|
63
|
+
teamId: TeamId,
|
|
64
|
+
name: Schema.String,
|
|
65
|
+
active: Schema.Boolean,
|
|
66
|
+
createdAt: Schema.String,
|
|
67
|
+
members: Schema.Array(RosterPlayer),
|
|
68
|
+
}) {}
|
|
69
|
+
|
|
70
|
+
export class CreateRosterRequest extends Schema.Class<CreateRosterRequest>('CreateRosterRequest')({
|
|
71
|
+
name: Schema.String,
|
|
72
|
+
}) {}
|
|
73
|
+
|
|
74
|
+
export class UpdateRosterRequest extends Schema.Class<UpdateRosterRequest>('UpdateRosterRequest')({
|
|
75
|
+
name: Schema.NullOr(Schema.String),
|
|
76
|
+
active: Schema.NullOr(Schema.Boolean),
|
|
77
|
+
}) {}
|
|
78
|
+
|
|
79
|
+
export class AddRosterMemberRequest extends Schema.Class<AddRosterMemberRequest>(
|
|
80
|
+
'AddRosterMemberRequest',
|
|
81
|
+
)({
|
|
82
|
+
memberId: TeamMemberId,
|
|
83
|
+
}) {}
|
|
84
|
+
|
|
85
|
+
export class RosterApiGroup extends HttpApiGroup.make('roster')
|
|
86
|
+
.add(
|
|
87
|
+
HttpApiEndpoint.get('listMembers', '/teams/:teamId/members')
|
|
88
|
+
.addSuccess(Schema.Array(RosterPlayer))
|
|
89
|
+
.addError(Forbidden, { status: 403 })
|
|
90
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
91
|
+
.middleware(AuthMiddleware),
|
|
92
|
+
)
|
|
93
|
+
.add(
|
|
94
|
+
HttpApiEndpoint.get('getMember', '/teams/:teamId/members/:memberId')
|
|
95
|
+
.addSuccess(RosterPlayer)
|
|
96
|
+
.addError(Forbidden, { status: 403 })
|
|
97
|
+
.addError(PlayerNotFound, { status: 404 })
|
|
98
|
+
.setPath(Schema.Struct({ teamId: TeamId, memberId: TeamMemberId }))
|
|
99
|
+
.middleware(AuthMiddleware),
|
|
100
|
+
)
|
|
101
|
+
.add(
|
|
102
|
+
HttpApiEndpoint.patch('updateMember', '/teams/:teamId/members/:memberId')
|
|
103
|
+
.addSuccess(RosterPlayer)
|
|
104
|
+
.addError(Forbidden, { status: 403 })
|
|
105
|
+
.addError(PlayerNotFound, { status: 404 })
|
|
106
|
+
.setPath(Schema.Struct({ teamId: TeamId, memberId: TeamMemberId }))
|
|
107
|
+
.setPayload(UpdatePlayerRequest)
|
|
108
|
+
.middleware(AuthMiddleware),
|
|
109
|
+
)
|
|
110
|
+
.add(
|
|
111
|
+
HttpApiEndpoint.del('deactivateMember', '/teams/:teamId/members/:memberId')
|
|
112
|
+
.addSuccess(Schema.Void)
|
|
113
|
+
.addError(Forbidden, { status: 403 })
|
|
114
|
+
.addError(PlayerNotFound, { status: 404 })
|
|
115
|
+
.setPath(Schema.Struct({ teamId: TeamId, memberId: TeamMemberId }))
|
|
116
|
+
.middleware(AuthMiddleware),
|
|
117
|
+
)
|
|
118
|
+
.add(
|
|
119
|
+
HttpApiEndpoint.get('listRosters', '/teams/:teamId/rosters')
|
|
120
|
+
.addSuccess(Schema.Array(RosterInfo))
|
|
121
|
+
.addError(Forbidden, { status: 403 })
|
|
122
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
123
|
+
.middleware(AuthMiddleware),
|
|
124
|
+
)
|
|
125
|
+
.add(
|
|
126
|
+
HttpApiEndpoint.post('createRoster', '/teams/:teamId/rosters')
|
|
127
|
+
.addSuccess(RosterInfo, { status: 201 })
|
|
128
|
+
.addError(Forbidden, { status: 403 })
|
|
129
|
+
.setPath(Schema.Struct({ teamId: TeamId }))
|
|
130
|
+
.setPayload(CreateRosterRequest)
|
|
131
|
+
.middleware(AuthMiddleware),
|
|
132
|
+
)
|
|
133
|
+
.add(
|
|
134
|
+
HttpApiEndpoint.get('getRoster', '/teams/:teamId/rosters/:rosterId')
|
|
135
|
+
.addSuccess(RosterDetail)
|
|
136
|
+
.addError(Forbidden, { status: 403 })
|
|
137
|
+
.addError(RosterNotFound, { status: 404 })
|
|
138
|
+
.setPath(Schema.Struct({ teamId: TeamId, rosterId: RosterId }))
|
|
139
|
+
.middleware(AuthMiddleware),
|
|
140
|
+
)
|
|
141
|
+
.add(
|
|
142
|
+
HttpApiEndpoint.patch('updateRoster', '/teams/:teamId/rosters/:rosterId')
|
|
143
|
+
.addSuccess(RosterInfo)
|
|
144
|
+
.addError(Forbidden, { status: 403 })
|
|
145
|
+
.addError(RosterNotFound, { status: 404 })
|
|
146
|
+
.setPath(Schema.Struct({ teamId: TeamId, rosterId: RosterId }))
|
|
147
|
+
.setPayload(UpdateRosterRequest)
|
|
148
|
+
.middleware(AuthMiddleware),
|
|
149
|
+
)
|
|
150
|
+
.add(
|
|
151
|
+
HttpApiEndpoint.del('deleteRoster', '/teams/:teamId/rosters/:rosterId')
|
|
152
|
+
.addSuccess(Schema.Void)
|
|
153
|
+
.addError(Forbidden, { status: 403 })
|
|
154
|
+
.addError(RosterNotFound, { status: 404 })
|
|
155
|
+
.setPath(Schema.Struct({ teamId: TeamId, rosterId: RosterId }))
|
|
156
|
+
.middleware(AuthMiddleware),
|
|
157
|
+
)
|
|
158
|
+
.add(
|
|
159
|
+
HttpApiEndpoint.post('addRosterMember', '/teams/:teamId/rosters/:rosterId/members')
|
|
160
|
+
.addSuccess(Schema.Void)
|
|
161
|
+
.addError(Forbidden, { status: 403 })
|
|
162
|
+
.addError(RosterNotFound, { status: 404 })
|
|
163
|
+
.addError(PlayerNotFound, { status: 404 })
|
|
164
|
+
.setPath(Schema.Struct({ teamId: TeamId, rosterId: RosterId }))
|
|
165
|
+
.setPayload(AddRosterMemberRequest)
|
|
166
|
+
.middleware(AuthMiddleware),
|
|
167
|
+
)
|
|
168
|
+
.add(
|
|
169
|
+
HttpApiEndpoint.del('removeRosterMember', '/teams/:teamId/rosters/:rosterId/members/:memberId')
|
|
170
|
+
.addSuccess(Schema.Void)
|
|
171
|
+
.addError(Forbidden, { status: 403 })
|
|
172
|
+
.addError(RosterNotFound, { status: 404 })
|
|
173
|
+
.addError(PlayerNotFound, { status: 404 })
|
|
174
|
+
.setPath(Schema.Struct({ teamId: TeamId, rosterId: RosterId, memberId: TeamMemberId }))
|
|
175
|
+
.middleware(AuthMiddleware),
|
|
176
|
+
) {}
|