@stevenkellner/team-conduct-api 1.0.31 → 1.0.33
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/lib/src/Firestore.d.ts +12 -3
- package/lib/src/Firestore.js +17 -8
- package/lib/src/FirestoreScheme.d.ts +3 -3
- package/lib/src/firebaseFunctionsContext.d.ts +6 -5
- package/lib/src/firebaseFunctionsContext.js +5 -4
- package/lib/src/functions/index.d.ts +4 -3
- package/lib/src/functions/index.js +4 -3
- package/lib/src/functions/invitation/getInvitation.d.ts +50 -0
- package/lib/src/functions/invitation/getInvitation.js +94 -0
- package/lib/src/functions/invitation/invite.d.ts +7 -0
- package/lib/src/functions/invitation/invite.js +25 -0
- package/lib/src/functions/invitation/register.d.ts +19 -0
- package/lib/src/functions/{userInvitation → invitation}/register.js +26 -19
- package/lib/src/functions/invitation/withdraw.d.ts +8 -0
- package/lib/src/functions/{userInvitation → invitation}/withdraw.js +6 -6
- package/lib/src/functions/user/kickout.js +8 -1
- package/lib/src/types/Invitation.d.ts +25 -0
- package/lib/src/types/Invitation.js +46 -0
- package/lib/src/types/index.d.ts +1 -1
- package/lib/src/types/index.js +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/Firestore.ts +22 -10
- package/src/FirestoreScheme.ts +3 -3
- package/src/firebaseFunctionsContext.ts +6 -5
- package/src/functions/index.ts +4 -3
- package/src/functions/invitation/getInvitation.ts +138 -0
- package/src/functions/invitation/invite.ts +32 -0
- package/src/functions/invitation/register.ts +69 -0
- package/src/functions/{userInvitation → invitation}/withdraw.ts +6 -6
- package/src/functions/user/kickout.ts +11 -2
- package/src/types/Invitation.ts +60 -0
- package/src/types/index.ts +1 -1
- package/lib/src/functions/userInvitation/invite.d.ts +0 -7
- package/lib/src/functions/userInvitation/invite.js +0 -23
- package/lib/src/functions/userInvitation/register.d.ts +0 -7
- package/lib/src/functions/userInvitation/withdraw.d.ts +0 -8
- package/lib/src/types/UserInvitation.d.ts +0 -25
- package/lib/src/types/UserInvitation.js +0 -42
- package/src/functions/userInvitation/invite.ts +0 -28
- package/src/functions/userInvitation/register.ts +0 -54
- package/src/types/UserInvitation.ts +0 -56
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stevenkellner/team-conduct-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"description": "Firebase API for Team Conduct",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Steven Kellner",
|
|
@@ -22,21 +22,21 @@
|
|
|
22
22
|
"release": "npm run rebuild && npm run lint && npm version patch && git push --follow-tags"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@stevenkellner/firebase-function": "^1.4.
|
|
26
|
-
"@stevenkellner/typescript-common-functionality": "^1.0.
|
|
25
|
+
"@stevenkellner/firebase-function": "^1.4.141",
|
|
26
|
+
"@stevenkellner/typescript-common-functionality": "^1.0.61"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@assertive-ts/core": "^2.1.0",
|
|
30
|
-
"@eslint/compat": "^1.
|
|
30
|
+
"@eslint/compat": "^1.3.1",
|
|
31
31
|
"@eslint/eslintrc": "^3.3.1",
|
|
32
|
-
"@eslint/js": "^9.
|
|
32
|
+
"@eslint/js": "^9.30.0",
|
|
33
33
|
"@types/mocha": "^10.0.10",
|
|
34
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
35
|
-
"@typescript-eslint/parser": "^8.
|
|
36
|
-
"eslint": "^9.
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
|
35
|
+
"@typescript-eslint/parser": "^8.35.0",
|
|
36
|
+
"eslint": "^9.30.0",
|
|
37
37
|
"eslint-config-google": "^0.14.0",
|
|
38
|
-
"eslint-plugin-import": "^2.
|
|
39
|
-
"mocha": "^11.
|
|
38
|
+
"eslint-plugin-import": "^2.32.0",
|
|
39
|
+
"mocha": "^11.7.1",
|
|
40
40
|
"ts-node": "^10.9.2",
|
|
41
41
|
"typescript": "^5.8.3"
|
|
42
42
|
}
|
package/src/Firestore.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { FirestoreDocument } from '@stevenkellner/firebase-function';
|
|
1
|
+
import { FirestoreCollection, FirestoreDocument } from '@stevenkellner/firebase-function';
|
|
2
2
|
import { FirestoreScheme } from './FirestoreScheme';
|
|
3
|
-
import { Fine, FineTemplate,
|
|
3
|
+
import { Fine, FineTemplate, Invitation, Person, User, Team } from './types';
|
|
4
4
|
import { FirebaseConfiguration } from './firebase';
|
|
5
5
|
|
|
6
6
|
export class Firestore {
|
|
@@ -31,33 +31,45 @@ export class Firestore {
|
|
|
31
31
|
.document(id.value);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
public
|
|
34
|
+
public invitation(id: Invitation.Id): FirestoreDocument<Invitation> {
|
|
35
35
|
return this.base
|
|
36
|
-
.collection('
|
|
36
|
+
.collection('invitations')
|
|
37
37
|
.document(id.value);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
public
|
|
40
|
+
public persons(teamId: Team.Id): FirestoreCollection<{ [x: string]: FirestoreDocument<Person, never>; }> {
|
|
41
41
|
return this.base
|
|
42
42
|
.collection('teams')
|
|
43
43
|
.document(teamId.guidString)
|
|
44
|
-
.collection('persons')
|
|
44
|
+
.collection('persons');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public person(teamId: Team.Id, id: Person.Id): FirestoreDocument<Person> {
|
|
48
|
+
return this.persons(teamId)
|
|
45
49
|
.document(id.guidString);
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
public
|
|
52
|
+
public fineTemplates(teamId: Team.Id): FirestoreCollection<{ [x: string]: FirestoreDocument<FineTemplate, never>; }> {
|
|
49
53
|
return this.base
|
|
50
54
|
.collection('teams')
|
|
51
55
|
.document(teamId.guidString)
|
|
52
|
-
.collection('fineTemplates')
|
|
56
|
+
.collection('fineTemplates');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public fineTemplate(teamId: Team.Id, id: FineTemplate.Id): FirestoreDocument<FineTemplate> {
|
|
60
|
+
return this.fineTemplates(teamId)
|
|
53
61
|
.document(id.guidString);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
public
|
|
64
|
+
public fines(teamId: Team.Id): FirestoreCollection<{ [x: string]: FirestoreDocument<Fine, never>; }> {
|
|
57
65
|
return this.base
|
|
58
66
|
.collection('teams')
|
|
59
67
|
.document(teamId.guidString)
|
|
60
|
-
.collection('fines')
|
|
68
|
+
.collection('fines');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public fine(teamId: Team.Id, id: Fine.Id): FirestoreDocument<Fine> {
|
|
72
|
+
return this.fines(teamId)
|
|
61
73
|
.document(id.guidString);
|
|
62
74
|
}
|
|
63
75
|
}
|
package/src/FirestoreScheme.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { FirestoreCollection, FirestoreDocument } from '@stevenkellner/firebase-function';
|
|
2
|
-
import { Fine, FineTemplate,
|
|
2
|
+
import { Fine, FineTemplate, Invitation, Person, Team, User } from './types';
|
|
3
3
|
|
|
4
4
|
export type FirestoreScheme = FirestoreDocument<never, {
|
|
5
5
|
users: FirestoreCollection<{
|
|
6
6
|
[UserId in string]: FirestoreDocument<User>
|
|
7
7
|
}>
|
|
8
|
-
|
|
9
|
-
[
|
|
8
|
+
invitations: FirestoreCollection<{
|
|
9
|
+
[InvitationId in string]: FirestoreDocument<Invitation>
|
|
10
10
|
}>
|
|
11
11
|
teams: FirestoreCollection<{
|
|
12
12
|
[TeamId in string]: FirestoreDocument<Team, {
|
|
@@ -2,7 +2,7 @@ import { FirebaseFunctionsContext } from '@stevenkellner/firebase-function';
|
|
|
2
2
|
import { TeamNewFunction,
|
|
3
3
|
UserKickoutFunction, UserLoginFunction, UserRoleEditFunction,
|
|
4
4
|
PaypalMeEditFunction, NotificationRegisterFunction, NotificationSubscribeFunction,
|
|
5
|
-
|
|
5
|
+
InvitationInviteFunction, InvitationWithdrawFunction, InvitationGetInvitationFunction, InvitationRegisterFunction,
|
|
6
6
|
PersonAddFunction, PersonDeleteFunction, PersonUpdateFunction,
|
|
7
7
|
FineTemplateAddFunction, FineTemplateDeleteFunction, FineTemplateUpdateFunction,
|
|
8
8
|
FineAddFunction, FineDeleteFunction, FineUpdateFunction
|
|
@@ -24,10 +24,11 @@ export const firebaseFunctionsContext = FirebaseFunctionsContext.build(builder =
|
|
|
24
24
|
register: builder.function(NotificationRegisterFunction),
|
|
25
25
|
subscribe: builder.function(NotificationSubscribeFunction)
|
|
26
26
|
},
|
|
27
|
-
|
|
28
|
-
invite: builder.function(
|
|
29
|
-
withdraw: builder.function(
|
|
30
|
-
|
|
27
|
+
invitation: {
|
|
28
|
+
invite: builder.function(InvitationInviteFunction),
|
|
29
|
+
withdraw: builder.function(InvitationWithdrawFunction),
|
|
30
|
+
getInvitation: builder.function(InvitationGetInvitationFunction),
|
|
31
|
+
register: builder.function(InvitationRegisterFunction)
|
|
31
32
|
},
|
|
32
33
|
person: {
|
|
33
34
|
add: builder.function(PersonAddFunction),
|
package/src/functions/index.ts
CHANGED
|
@@ -6,9 +6,10 @@ export * from './user/kickout';
|
|
|
6
6
|
export * from './paypalMe/edit';
|
|
7
7
|
export * from './notification/register';
|
|
8
8
|
export * from './notification/subscribe';
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
11
|
-
export * from './
|
|
9
|
+
export * from './invitation/invite';
|
|
10
|
+
export * from './invitation/withdraw';
|
|
11
|
+
export * from './invitation/getInvitation';
|
|
12
|
+
export * from './invitation/register';
|
|
12
13
|
export * from './person/add';
|
|
13
14
|
export * from './person/update';
|
|
14
15
|
export * from './person/delete';
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { FirebaseFunction, FunctionsError } from '@stevenkellner/firebase-function';
|
|
2
|
+
import { Invitation, Person, PersonPrivateProperties, Team } from '../../types';
|
|
3
|
+
import { Firestore } from '../../Firestore';
|
|
4
|
+
import { compactMap, Flattable, ITypeBuilder } from '@stevenkellner/typescript-common-functionality';
|
|
5
|
+
|
|
6
|
+
export class InvitationGetInvitationFunction extends FirebaseFunction<Invitation.Id, InvitationGetInvitationFunction.ReturnType> {
|
|
7
|
+
|
|
8
|
+
public parametersBuilder = Invitation.Id.builder;
|
|
9
|
+
|
|
10
|
+
public returnTypeBuilder = InvitationGetInvitationFunction.ReturnType.builder;
|
|
11
|
+
|
|
12
|
+
public async execute(invitationId: Invitation.Id): Promise<InvitationGetInvitationFunction.ReturnType> {
|
|
13
|
+
|
|
14
|
+
if (this.userId === null)
|
|
15
|
+
throw new FunctionsError('unauthenticated', 'User not authenticated');
|
|
16
|
+
|
|
17
|
+
const invitationSnapshot = await Firestore.shared.invitation(invitationId).snapshot();
|
|
18
|
+
if (!invitationSnapshot.exists)
|
|
19
|
+
throw new FunctionsError('not-found', 'Invitation not found');
|
|
20
|
+
const invitation = Invitation.builder.build(invitationSnapshot.data);
|
|
21
|
+
|
|
22
|
+
if (invitation.personId !== null)
|
|
23
|
+
return InvitationGetInvitationFunction.ReturnType.from(invitation.teamId, invitation.personId);
|
|
24
|
+
|
|
25
|
+
const personSnapshots = await Firestore.shared.persons(invitation.teamId).documentSnapshots();
|
|
26
|
+
const persons = compactMap(personSnapshots, personSnapshot => {
|
|
27
|
+
if (!personSnapshot.exists)
|
|
28
|
+
return null;
|
|
29
|
+
const person = Person.builder.build(personSnapshot.data);
|
|
30
|
+
return {
|
|
31
|
+
id: person.id,
|
|
32
|
+
properties: person.properties
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return InvitationGetInvitationFunction.ReturnType.from(invitation.teamId, persons);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export namespace InvitationGetInvitationFunction {
|
|
40
|
+
|
|
41
|
+
export type PersonIdOrPersons = {
|
|
42
|
+
personId: Person.Id;
|
|
43
|
+
} | {
|
|
44
|
+
persons: {
|
|
45
|
+
id: Person.Id,
|
|
46
|
+
properties: PersonPrivateProperties,
|
|
47
|
+
}[];
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export namespace PersonIdOrPersons {
|
|
51
|
+
|
|
52
|
+
export type Flatten = {
|
|
53
|
+
personId: Person.Id.Flatten,
|
|
54
|
+
} | {
|
|
55
|
+
persons: {
|
|
56
|
+
id: Person.Id.Flatten,
|
|
57
|
+
properties: PersonPrivateProperties.Flatten,
|
|
58
|
+
}[];
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class ReturnType implements Flattable<ReturnType.Flatten> {
|
|
63
|
+
|
|
64
|
+
private constructor(
|
|
65
|
+
public teamId: Team.Id,
|
|
66
|
+
private personIdOrPersons: PersonIdOrPersons
|
|
67
|
+
) {}
|
|
68
|
+
|
|
69
|
+
public static from(teamId: Team.Id, personId: Person.Id): ReturnType;
|
|
70
|
+
public static from(teamId: Team.Id, persons: { id: Person.Id, properties: PersonPrivateProperties }[]): ReturnType;
|
|
71
|
+
public static from(teamId: Team.Id, personIdOrPersons: Person.Id | { id: Person.Id, properties: PersonPrivateProperties }[]): ReturnType {
|
|
72
|
+
if (Array.isArray(personIdOrPersons)) {
|
|
73
|
+
return new ReturnType(teamId, {
|
|
74
|
+
persons: personIdOrPersons
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return new ReturnType(teamId, {
|
|
78
|
+
personId: personIdOrPersons
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public get personId(): Person.Id | null {
|
|
83
|
+
if (!('personId' in this.personIdOrPersons))
|
|
84
|
+
return null;
|
|
85
|
+
return this.personIdOrPersons.personId;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public get persons(): Person.Id[] | null {
|
|
89
|
+
if (!('persons' in this.personIdOrPersons))
|
|
90
|
+
return null;
|
|
91
|
+
return this.personIdOrPersons.persons.map(person => person.id);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public get flatten(): ReturnType.Flatten {
|
|
95
|
+
if ('personId' in this.personIdOrPersons) {
|
|
96
|
+
return {
|
|
97
|
+
teamId: this.teamId.flatten,
|
|
98
|
+
personId: this.personIdOrPersons.personId.flatten
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
teamId: this.teamId.flatten,
|
|
103
|
+
persons: this.personIdOrPersons.persons.map(person => ({
|
|
104
|
+
id: person.id.flatten,
|
|
105
|
+
properties: person.properties.flatten
|
|
106
|
+
}))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export namespace ReturnType {
|
|
112
|
+
|
|
113
|
+
export type Flatten = {
|
|
114
|
+
teamId: Team.Id.Flatten
|
|
115
|
+
} & InvitationGetInvitationFunction.PersonIdOrPersons.Flatten;
|
|
116
|
+
|
|
117
|
+
export class TypeBuilder implements ITypeBuilder<Flatten, ReturnType> {
|
|
118
|
+
|
|
119
|
+
public build(value: Flatten): ReturnType {
|
|
120
|
+
if ('personId' in value) {
|
|
121
|
+
return ReturnType.from(
|
|
122
|
+
Team.Id.builder.build(value.teamId),
|
|
123
|
+
Person.Id.builder.build(value.personId)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return ReturnType.from(
|
|
127
|
+
Team.Id.builder.build(value.teamId),
|
|
128
|
+
value.persons.map(person => ({
|
|
129
|
+
id: Person.Id.builder.build(person.id),
|
|
130
|
+
properties: PersonPrivateProperties.builder.build(person.properties)
|
|
131
|
+
}))
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const builder = new TypeBuilder();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FirebaseFunction, FunctionsError } from '@stevenkellner/firebase-function';
|
|
2
|
+
import { Invitation } from '../../types';
|
|
3
|
+
import { checkAuthentication } from '../../checkAuthentication';
|
|
4
|
+
import { Firestore } from '../../Firestore';
|
|
5
|
+
|
|
6
|
+
export class InvitationInviteFunction extends FirebaseFunction<Invitation, Invitation.Id> {
|
|
7
|
+
|
|
8
|
+
public parametersBuilder = Invitation.builder;
|
|
9
|
+
|
|
10
|
+
public returnTypeBuilder = Invitation.Id.builder;
|
|
11
|
+
|
|
12
|
+
public async execute(invitation: Invitation): Promise<Invitation.Id> {
|
|
13
|
+
|
|
14
|
+
await checkAuthentication(this.userId, invitation.teamId, 'team-manager');
|
|
15
|
+
|
|
16
|
+
if (invitation.personId !== null) {
|
|
17
|
+
|
|
18
|
+
const personSnapshot = await Firestore.shared.person(invitation.teamId, invitation.personId).snapshot();
|
|
19
|
+
if (!personSnapshot.exists)
|
|
20
|
+
throw new FunctionsError('not-found', 'Person not found');
|
|
21
|
+
|
|
22
|
+
if (personSnapshot.data.signInProperties !== null)
|
|
23
|
+
throw new FunctionsError('already-exists', 'Person already has an account');
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const invitationId = invitation.createId();
|
|
28
|
+
await Firestore.shared.invitation(invitationId).set(invitation);
|
|
29
|
+
|
|
30
|
+
return invitationId;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { FirebaseFunction, FunctionsError } from '@stevenkellner/firebase-function';
|
|
2
|
+
import { Person, PersonSignInProperties, Team, User, Invitation } from '../../types';
|
|
3
|
+
import { Firestore } from '../../Firestore';
|
|
4
|
+
import { Flattable, ObjectTypeBuilder, UtcDate } from '@stevenkellner/typescript-common-functionality';
|
|
5
|
+
|
|
6
|
+
export namespace InvitationRegisterFunction {
|
|
7
|
+
|
|
8
|
+
export type Parameters = {
|
|
9
|
+
teamId: Team.Id
|
|
10
|
+
personId: Person.Id
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class InvitationRegisterFunction extends FirebaseFunction<InvitationRegisterFunction.Parameters, User> {
|
|
15
|
+
|
|
16
|
+
public parametersBuilder = new ObjectTypeBuilder<Flattable.Flatten<InvitationRegisterFunction.Parameters>, InvitationRegisterFunction.Parameters>({
|
|
17
|
+
teamId: Team.Id.builder,
|
|
18
|
+
personId: Person.Id.builder
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
public returnTypeBuilder = User.builder;
|
|
22
|
+
|
|
23
|
+
public async execute(parameters: InvitationRegisterFunction.Parameters): Promise<User> {
|
|
24
|
+
|
|
25
|
+
if (this.userId === null)
|
|
26
|
+
throw new FunctionsError('unauthenticated', 'User not authenticated');
|
|
27
|
+
const userId = User.Id.builder.build(this.userId);
|
|
28
|
+
const user = await this.getUser(userId);
|
|
29
|
+
|
|
30
|
+
if (user.teams.has(parameters.teamId))
|
|
31
|
+
throw new FunctionsError('already-exists', 'User already in team');
|
|
32
|
+
|
|
33
|
+
const teamSnapshot = await Firestore.shared.team(parameters.teamId).snapshot();
|
|
34
|
+
if (!teamSnapshot.exists)
|
|
35
|
+
throw new FunctionsError('not-found', 'Team not found');
|
|
36
|
+
const team = Team.builder.build(teamSnapshot.data);
|
|
37
|
+
|
|
38
|
+
const personSnapshot = await Firestore.shared.person(parameters.teamId, parameters.personId).snapshot();
|
|
39
|
+
if (!personSnapshot.exists)
|
|
40
|
+
throw new FunctionsError('not-found', 'Person not found');
|
|
41
|
+
const person = Person.builder.build(personSnapshot.data);
|
|
42
|
+
|
|
43
|
+
if (person.signInProperties !== null)
|
|
44
|
+
throw new FunctionsError('already-exists', 'Person already registered');
|
|
45
|
+
|
|
46
|
+
await this.removeUserInvitation(parameters.teamId, parameters.personId);
|
|
47
|
+
|
|
48
|
+
user.teams.set(parameters.teamId, new User.TeamProperties(team.name, parameters.personId));
|
|
49
|
+
await Firestore.shared.user(userId).set(user);
|
|
50
|
+
|
|
51
|
+
person.signInProperties = new PersonSignInProperties(userId, UtcDate.now);
|
|
52
|
+
await Firestore.shared.person(parameters.teamId, parameters.personId).set(person);
|
|
53
|
+
|
|
54
|
+
return user;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private async getUser(userId: User.Id): Promise<User> {
|
|
58
|
+
const userSnapshot = await Firestore.shared.user(userId).snapshot();
|
|
59
|
+
if (userSnapshot.exists)
|
|
60
|
+
return User.builder.build(userSnapshot.data);
|
|
61
|
+
return new User(userId);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private async removeUserInvitation(teamId: Team.Id, personId: Person.Id) {
|
|
65
|
+
const invitation = new Invitation(teamId, personId);
|
|
66
|
+
const invitationId = invitation.createId();
|
|
67
|
+
await Firestore.shared.invitation(invitationId).remove();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { FirebaseFunction, FunctionsError } from '@stevenkellner/firebase-function';
|
|
2
|
-
import {
|
|
2
|
+
import { Invitation } from '../../types';
|
|
3
3
|
import { checkAuthentication } from '../../checkAuthentication';
|
|
4
4
|
import { Firestore } from '../../Firestore';
|
|
5
5
|
import { ValueTypeBuilder } from '@stevenkellner/typescript-common-functionality';
|
|
6
6
|
|
|
7
|
-
export class
|
|
7
|
+
export class InvitationWithdrawFunction extends FirebaseFunction<Invitation, void> {
|
|
8
8
|
|
|
9
|
-
public parametersBuilder =
|
|
9
|
+
public parametersBuilder = Invitation.builder;
|
|
10
10
|
|
|
11
11
|
public returnTypeBuilder = new ValueTypeBuilder<void>();
|
|
12
12
|
|
|
13
|
-
public async execute(invitation:
|
|
13
|
+
public async execute(invitation: Invitation): Promise<void> {
|
|
14
14
|
|
|
15
15
|
await checkAuthentication(this.userId, invitation.teamId, 'team-manager');
|
|
16
16
|
|
|
17
17
|
const invitationId = invitation.createId();
|
|
18
|
-
const invitationSnapshot = await Firestore.shared.
|
|
18
|
+
const invitationSnapshot = await Firestore.shared.invitation(invitationId).snapshot();
|
|
19
19
|
if (!invitationSnapshot.exists)
|
|
20
20
|
throw new FunctionsError('not-found', 'Invitation not found');
|
|
21
21
|
|
|
22
|
-
await Firestore.shared.
|
|
22
|
+
await Firestore.shared.invitation(invitationId).remove();
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FirebaseFunction, FunctionsError } from '@stevenkellner/firebase-function';
|
|
2
|
-
import { Team, User } from '../../types';
|
|
2
|
+
import { Person, Team, User } from '../../types';
|
|
3
3
|
import { Flattable, ObjectTypeBuilder, ValueTypeBuilder } from '@stevenkellner/typescript-common-functionality';
|
|
4
4
|
import { Firestore } from '../../Firestore';
|
|
5
5
|
import { checkAuthentication } from '../../checkAuthentication';
|
|
@@ -37,6 +37,15 @@ export class UserKickoutFunction extends FirebaseFunction<UserKickoutFunction.Pa
|
|
|
37
37
|
if (userTeamProperties === null)
|
|
38
38
|
throw new FunctionsError('not-found', 'User is not a member of the team.');
|
|
39
39
|
|
|
40
|
-
await Firestore.shared.person(parameters.teamId, userTeamProperties.personId).
|
|
40
|
+
const personSnapshot = await Firestore.shared.person(parameters.teamId, userTeamProperties.personId).snapshot();
|
|
41
|
+
if (!personSnapshot.exists)
|
|
42
|
+
throw new FunctionsError('not-found', 'Person not found.');
|
|
43
|
+
const person = Person.builder.build(personSnapshot.data);
|
|
44
|
+
|
|
45
|
+
person.signInProperties = null;
|
|
46
|
+
await Firestore.shared.person(parameters.teamId, userTeamProperties.personId).set(person);
|
|
47
|
+
|
|
48
|
+
user.teams.delete(parameters.teamId);
|
|
49
|
+
await Firestore.shared.user(parameters.userId).set(user);
|
|
41
50
|
}
|
|
42
51
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { BytesCoder, Flattable, ITypeBuilder, OptionalTypeBuilder, Sha512, Tagged, ValueTypeBuilder } from '@stevenkellner/typescript-common-functionality';
|
|
2
|
+
import { Team } from './Team';
|
|
3
|
+
import { Person } from './Person';
|
|
4
|
+
|
|
5
|
+
export class Invitation implements Flattable<Invitation.Flatten> {
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
public teamId: Team.Id,
|
|
9
|
+
public personId: Person.Id | null
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
public createId(): Invitation.Id {
|
|
13
|
+
const hasher = new Sha512();
|
|
14
|
+
const teamIdBytes = BytesCoder.fromUtf8(this.teamId.guidString);
|
|
15
|
+
let invitationBytes = teamIdBytes;
|
|
16
|
+
if (this.personId !== null) {
|
|
17
|
+
const personIdBytes = BytesCoder.fromUtf8(this.personId.guidString);
|
|
18
|
+
invitationBytes = new Uint8Array([...teamIdBytes, ...personIdBytes]);
|
|
19
|
+
}
|
|
20
|
+
const hashedInvitationBytes = hasher.hash(invitationBytes);
|
|
21
|
+
const rawId = BytesCoder.toHex(hashedInvitationBytes).slice(0, 12);
|
|
22
|
+
return new Tagged(rawId, 'invitation');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public get flatten(): Invitation.Flatten {
|
|
26
|
+
return {
|
|
27
|
+
teamId: this.teamId.flatten,
|
|
28
|
+
personId: this.personId !== null ? this.personId.flatten : null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export namespace Invitation {
|
|
34
|
+
|
|
35
|
+
export type Id = Tagged<string, 'invitation'>;
|
|
36
|
+
|
|
37
|
+
export namespace Id {
|
|
38
|
+
|
|
39
|
+
export type Flatten = string;
|
|
40
|
+
|
|
41
|
+
export const builder = Tagged.builder('invitation' as const, new ValueTypeBuilder<string>());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type Flatten = {
|
|
45
|
+
teamId: Team.Id.Flatten,
|
|
46
|
+
personId: Person.Id.Flatten | null
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export class TypeBuilder implements ITypeBuilder<Flatten, Invitation> {
|
|
50
|
+
|
|
51
|
+
public build(value: Flatten): Invitation {
|
|
52
|
+
return new Invitation(
|
|
53
|
+
Team.Id.builder.build(value.teamId),
|
|
54
|
+
new OptionalTypeBuilder(Person.Id.builder).build(value.personId)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const builder = new TypeBuilder();
|
|
60
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from './Fine';
|
|
|
3
3
|
export * from './FineAmount';
|
|
4
4
|
export * from './FineTemplate';
|
|
5
5
|
export * from './FineTemplateRepetition';
|
|
6
|
-
export * from './
|
|
6
|
+
export * from './Invitation';
|
|
7
7
|
export * from './Localization';
|
|
8
8
|
export * from './MoneyAmount';
|
|
9
9
|
export * from './NotificationProperties';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { FirebaseFunction } from '@stevenkellner/firebase-function';
|
|
2
|
-
import { UserInvitation } from '../../types';
|
|
3
|
-
export declare class UserInvitationInviteFunction extends FirebaseFunction<UserInvitation, UserInvitation.Id> {
|
|
4
|
-
parametersBuilder: UserInvitation.TypeBuilder;
|
|
5
|
-
returnTypeBuilder: import("@stevenkellner/typescript-common-functionality").Tagged.TypeBuilder<string, "userInvitation">;
|
|
6
|
-
execute(invitation: UserInvitation): Promise<UserInvitation.Id>;
|
|
7
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UserInvitationInviteFunction = void 0;
|
|
4
|
-
const firebase_function_1 = require("@stevenkellner/firebase-function");
|
|
5
|
-
const types_1 = require("../../types");
|
|
6
|
-
const checkAuthentication_1 = require("../../checkAuthentication");
|
|
7
|
-
const Firestore_1 = require("../../Firestore");
|
|
8
|
-
class UserInvitationInviteFunction extends firebase_function_1.FirebaseFunction {
|
|
9
|
-
parametersBuilder = types_1.UserInvitation.builder;
|
|
10
|
-
returnTypeBuilder = types_1.UserInvitation.Id.builder;
|
|
11
|
-
async execute(invitation) {
|
|
12
|
-
await (0, checkAuthentication_1.checkAuthentication)(this.userId, invitation.teamId, 'team-manager');
|
|
13
|
-
const personSnapshot = await Firestore_1.Firestore.shared.person(invitation.teamId, invitation.personId).snapshot();
|
|
14
|
-
if (!personSnapshot.exists)
|
|
15
|
-
throw new firebase_function_1.FunctionsError('not-found', 'Person not found');
|
|
16
|
-
if (personSnapshot.data.signInProperties !== null)
|
|
17
|
-
throw new firebase_function_1.FunctionsError('already-exists', 'Person already has an account');
|
|
18
|
-
const invitationId = invitation.createId();
|
|
19
|
-
await Firestore_1.Firestore.shared.userInvitation(invitationId).set(invitation);
|
|
20
|
-
return invitationId;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
exports.UserInvitationInviteFunction = UserInvitationInviteFunction;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { FirebaseFunction } from '@stevenkellner/firebase-function';
|
|
2
|
-
import { UserInvitation, User } from '../../types';
|
|
3
|
-
export declare class UserInvitationRegisterFunction extends FirebaseFunction<UserInvitation.Id, User> {
|
|
4
|
-
parametersBuilder: import("@stevenkellner/typescript-common-functionality").Tagged.TypeBuilder<string, "userInvitation">;
|
|
5
|
-
returnTypeBuilder: User.TypeBuilder;
|
|
6
|
-
execute(invitationId: UserInvitation.Id): Promise<User>;
|
|
7
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { FirebaseFunction } from '@stevenkellner/firebase-function';
|
|
2
|
-
import { UserInvitation } from '../../types';
|
|
3
|
-
import { ValueTypeBuilder } from '@stevenkellner/typescript-common-functionality';
|
|
4
|
-
export declare class UserInvitationWithdrawFunction extends FirebaseFunction<UserInvitation, void> {
|
|
5
|
-
parametersBuilder: UserInvitation.TypeBuilder;
|
|
6
|
-
returnTypeBuilder: ValueTypeBuilder<void>;
|
|
7
|
-
execute(invitation: UserInvitation): Promise<void>;
|
|
8
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Flattable, ITypeBuilder, Tagged } from '@stevenkellner/typescript-common-functionality';
|
|
2
|
-
import { Team } from './Team';
|
|
3
|
-
import { Person } from './Person';
|
|
4
|
-
export declare class UserInvitation implements Flattable<UserInvitation.Flatten> {
|
|
5
|
-
teamId: Team.Id;
|
|
6
|
-
personId: Person.Id;
|
|
7
|
-
constructor(teamId: Team.Id, personId: Person.Id);
|
|
8
|
-
createId(): UserInvitation.Id;
|
|
9
|
-
get flatten(): UserInvitation.Flatten;
|
|
10
|
-
}
|
|
11
|
-
export declare namespace UserInvitation {
|
|
12
|
-
type Id = Tagged<string, 'userInvitation'>;
|
|
13
|
-
namespace Id {
|
|
14
|
-
type Flatten = string;
|
|
15
|
-
const builder: Tagged.TypeBuilder<string, "userInvitation">;
|
|
16
|
-
}
|
|
17
|
-
type Flatten = {
|
|
18
|
-
teamId: Team.Id.Flatten;
|
|
19
|
-
personId: Person.Id.Flatten;
|
|
20
|
-
};
|
|
21
|
-
class TypeBuilder implements ITypeBuilder<Flatten, UserInvitation> {
|
|
22
|
-
build(value: Flatten): UserInvitation;
|
|
23
|
-
}
|
|
24
|
-
const builder: TypeBuilder;
|
|
25
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UserInvitation = void 0;
|
|
4
|
-
const typescript_common_functionality_1 = require("@stevenkellner/typescript-common-functionality");
|
|
5
|
-
const Team_1 = require("./Team");
|
|
6
|
-
const Person_1 = require("./Person");
|
|
7
|
-
class UserInvitation {
|
|
8
|
-
teamId;
|
|
9
|
-
personId;
|
|
10
|
-
constructor(teamId, personId) {
|
|
11
|
-
this.teamId = teamId;
|
|
12
|
-
this.personId = personId;
|
|
13
|
-
}
|
|
14
|
-
createId() {
|
|
15
|
-
const hasher = new typescript_common_functionality_1.Sha512();
|
|
16
|
-
const teamIdBytes = typescript_common_functionality_1.BytesCoder.fromUtf8(this.teamId.guidString);
|
|
17
|
-
const personIdBytes = typescript_common_functionality_1.BytesCoder.fromUtf8(this.personId.guidString);
|
|
18
|
-
const hashedInvitationBytes = hasher.hash(new Uint8Array([...teamIdBytes, ...personIdBytes]));
|
|
19
|
-
const rawId = typescript_common_functionality_1.BytesCoder.toHex(hashedInvitationBytes).slice(0, 12);
|
|
20
|
-
return new typescript_common_functionality_1.Tagged(rawId, 'userInvitation');
|
|
21
|
-
}
|
|
22
|
-
get flatten() {
|
|
23
|
-
return {
|
|
24
|
-
teamId: this.teamId.flatten,
|
|
25
|
-
personId: this.personId.flatten
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.UserInvitation = UserInvitation;
|
|
30
|
-
(function (UserInvitation) {
|
|
31
|
-
let Id;
|
|
32
|
-
(function (Id) {
|
|
33
|
-
Id.builder = typescript_common_functionality_1.Tagged.builder('userInvitation', new typescript_common_functionality_1.ValueTypeBuilder());
|
|
34
|
-
})(Id = UserInvitation.Id || (UserInvitation.Id = {}));
|
|
35
|
-
class TypeBuilder {
|
|
36
|
-
build(value) {
|
|
37
|
-
return new UserInvitation(Team_1.Team.Id.builder.build(value.teamId), Person_1.Person.Id.builder.build(value.personId));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
UserInvitation.TypeBuilder = TypeBuilder;
|
|
41
|
-
UserInvitation.builder = new TypeBuilder();
|
|
42
|
-
})(UserInvitation || (exports.UserInvitation = UserInvitation = {}));
|