Skip to content

Commit 34d3b2b

Browse files
authored
Merge pull request #44 from import-ai/refactor/roots
refactor(namespaces): refactor resource roots
2 parents d8218c2 + 1eb7e27 commit 34d3b2b

File tree

11 files changed

+159
-142
lines changed

11 files changed

+159
-142
lines changed

src/auth/auth.service.ts

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -80,63 +80,47 @@ export class AuthService {
8080
password_repeat: string;
8181
},
8282
) {
83+
let payload: any;
8384
try {
84-
const payload = this.jwtService.verify(token);
85-
const account = await this.userService.findByEmail(payload.email);
86-
if (account) {
87-
throw new BadRequestException(
88-
'The email is already registered. Please log in directly.',
89-
);
90-
}
91-
return await this.dataSource.transaction(async (manager) => {
92-
const user = await this.userService.create(
93-
{
94-
email: payload.email,
95-
username: data.username,
96-
password: data.password,
97-
password_repeat: data.password_repeat,
98-
},
99-
manager,
100-
);
101-
102-
// Invited user
103-
if (payload.role && payload.namespace) {
104-
const namespace = await this.namespaceService.get(
105-
payload.namespace,
106-
manager,
107-
);
108-
const field = payload.role === 'owner' ? 'owner_id' : 'collaborators';
109-
if (namespace[field].includes(user.id)) {
110-
return;
111-
}
112-
namespace[field].push(user.id);
113-
await this.namespaceService.update(
114-
payload.namespace,
115-
{
116-
[field]: namespace[field],
117-
},
118-
manager,
119-
);
120-
}
121-
122-
await this.namespaceService.createAndInit(
123-
user.id,
124-
`${user.username}'s Namespace`,
125-
manager,
126-
);
127-
return {
128-
id: user.id,
129-
username: user.username,
130-
access_token: this.jwtService.sign({
131-
sub: user.id,
132-
email: user.email,
133-
}),
134-
};
135-
});
85+
payload = this.jwtService.verify(token);
13686
} catch (e) {
13787
console.log(e);
13888
throw new UnauthorizedException('Invalid or expired token.');
13989
}
90+
const account = await this.userService.findByEmail(payload.email);
91+
if (account) {
92+
throw new BadRequestException(
93+
'The email is already registered. Please log in directly.',
94+
);
95+
}
96+
return await this.dataSource.transaction(async (manager) => {
97+
const user = await this.userService.create(
98+
{
99+
email: payload.email,
100+
username: data.username,
101+
password: data.password,
102+
password_repeat: data.password_repeat,
103+
},
104+
manager,
105+
);
106+
let namespaceId = payload.namespace;
107+
if (!namespaceId) {
108+
const namespace = await this.namespaceService.createNamespace(
109+
`${user.username}'s Namespace`,
110+
manager,
111+
);
112+
namespaceId = namespace.id;
113+
}
114+
await this.namespaceService.addMember(namespaceId, user.id, manager);
115+
return {
116+
id: user.id,
117+
username: user.username,
118+
access_token: this.jwtService.sign({
119+
sub: user.id,
120+
email: user.email,
121+
}),
122+
};
123+
});
140124
}
141125

142126
async signUpWithoutConfirm(createUser: CreateUserDto) {

src/namespaces/entities/namespace.entity.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import {
1111
BeforeInsert,
1212
} from 'typeorm';
1313

14+
export enum SpaceType {
15+
PRIVATE = 'private',
16+
TEAMSPACE = 'teamspace',
17+
}
18+
1419
@Entity('namespaces')
1520
@Index(['name'], { unique: true, where: '"deleted_at" IS NULL' })
1621
export class Namespace extends Base {

src/namespaces/namespaces.controller.ts

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import {
88
Patch,
99
Delete,
1010
Controller,
11+
Query,
1112
} from '@nestjs/common';
13+
import { SpaceType } from './entities/namespace.entity';
1214

1315
@Controller('api/v1/namespaces')
1416
export class NamespacesController {
@@ -19,28 +21,47 @@ export class NamespacesController {
1921
return await this.namespacesService.listNamespaces(req.user.id);
2022
}
2123

22-
@Get(':id')
23-
async get(@Param('id') id: string) {
24-
return await this.namespacesService.get(id);
24+
@Get(':namespaceId')
25+
async get(@Param('namespaceId') namespaceId: string) {
26+
return await this.namespacesService.get(namespaceId);
2527
}
2628

27-
@Get(':id/members')
28-
async listMembers(@Req() req, @Param('id') namespaceId: string) {
29+
@Get(':namespaceId/members')
30+
async listMembers(@Req() req, @Param('namespaceId') namespaceId: string) {
2931
return await this.namespacesService.listMembers(namespaceId);
3032
}
3133

34+
@Get(':namespaceId/root')
35+
async getRoot(
36+
@Param('namespaceId') namespaceId: string,
37+
@Query('space_type') spaceType: SpaceType,
38+
@Req() req,
39+
) {
40+
return await this.namespacesService.getRoot(
41+
namespaceId,
42+
spaceType,
43+
req.user.id,
44+
);
45+
}
46+
3247
@Post()
3348
async create(@Req() req, @Body('name') name: string) {
34-
return await this.namespacesService.create(req.user.id, name);
49+
return await this.namespacesService.createNamespaceAndMember(
50+
req.user.id,
51+
name,
52+
);
3553
}
3654

37-
@Patch(':id')
38-
async update(@Param('id') id: string, @Body('name') name: string) {
39-
return await this.namespacesService.update(id, { name });
55+
@Patch(':namespaceId')
56+
async update(
57+
@Param('namespaceId') namespaceId: string,
58+
@Body('name') name: string,
59+
) {
60+
return await this.namespacesService.update(namespaceId, { name });
4061
}
4162

42-
@Delete(':id')
43-
async delete(@Param('id') id: string) {
44-
return await this.namespacesService.delete(id);
63+
@Delete(':namespaceId')
64+
async delete(@Param('namespaceId') namespaceId: string) {
65+
return await this.namespacesService.delete(namespaceId);
4566
}
4667
}

src/namespaces/namespaces.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import { NamespacesService } from 'src/namespaces/namespaces.service';
55
import { NamespacesController } from 'src/namespaces/namespaces.controller';
66
import { Namespace } from './entities/namespace.entity';
77
import { NamespaceMember } from './entities/namespace-member.entity';
8+
import { ResourcesModule } from 'src/resources/resources.module';
89

910
@Module({
1011
exports: [NamespacesService],
1112
providers: [NamespacesService],
1213
controllers: [NamespacesController],
1314
imports: [
1415
UserModule,
16+
ResourcesModule,
1517
TypeOrmModule.forFeature([Namespace]),
1618
TypeOrmModule.forFeature([NamespaceMember]),
1719
],

src/namespaces/namespaces.service.ts

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import each from 'src/utils/each';
2-
import { ArrayContains, DataSource, EntityManager, Repository } from 'typeorm';
2+
import { DataSource, EntityManager, IsNull, Repository } from 'typeorm';
33
import { InjectRepository } from '@nestjs/typeorm';
44
import { UpdateNamespaceDto } from './dto/update-namespace.dto';
55
import {
@@ -8,9 +8,10 @@ import {
88
NotFoundException,
99
} from '@nestjs/common';
1010
import { Resource } from 'src/resources/resources.entity';
11-
import { Namespace } from './entities/namespace.entity';
11+
import { Namespace, SpaceType } from './entities/namespace.entity';
1212
import { NamespaceMember } from './entities/namespace-member.entity';
1313
import { NamespaceMemberDto } from './dto/namespace-member.dto';
14+
import { ResourcesService } from 'src/resources/resources.service';
1415

1516
@Injectable()
1617
export class NamespacesService {
@@ -22,6 +23,8 @@ export class NamespacesService {
2223
private namespaceMemberRepository: Repository<NamespaceMember>,
2324

2425
private readonly dataSource: DataSource,
26+
27+
private readonly resourceService: ResourcesService,
2528
) {}
2629

2730
async getTeamspaceRoot(namespaceId: string): Promise<Resource> {
@@ -55,9 +58,14 @@ export class NamespacesService {
5558
return namespace;
5659
}
5760

58-
async create(ownerId: string, name: string): Promise<Namespace> {
61+
async createNamespaceAndMember(
62+
ownerId: string,
63+
name: string,
64+
): Promise<Namespace> {
5965
return await this.dataSource.transaction(async (manager) => {
60-
return await this.createAndInit(ownerId, name, manager);
66+
const namespace = await this.createNamespace(name, manager);
67+
await this.addMember(namespace.id, ownerId, manager);
68+
return namespace;
6169
});
6270
}
6371

@@ -66,28 +74,22 @@ export class NamespacesService {
6674
name: string,
6775
manager: EntityManager,
6876
): Promise<Namespace> {
69-
const namespace = await manager.save(
70-
manager.create(Namespace, {
71-
name,
72-
}),
73-
);
74-
const privateRoot = await manager.save(
75-
manager.create(Resource, {
76-
resourceType: 'folder',
77-
parent: null,
78-
namespace: { id: namespace.id },
79-
user: { id: ownerId },
80-
}),
81-
);
82-
const publicRoot = await manager.save(
83-
manager.create(Resource, {
84-
resourceType: 'folder',
85-
parent: null,
86-
namespace: { id: namespace.id },
87-
user: { id: ownerId },
88-
}),
77+
const namespace = await this.createNamespace(name, manager);
78+
await this.addMember(namespace.id, ownerId, manager);
79+
return namespace;
80+
}
81+
82+
async createNamespace(
83+
name: string,
84+
manager: EntityManager,
85+
): Promise<Namespace> {
86+
const namespace = await manager.save(manager.create(Namespace, { name }));
87+
const publicRoot = await this.resourceService.createFolder(
88+
namespace.id,
89+
null,
90+
null,
91+
manager,
8992
);
90-
await this.addMember(namespace.id, ownerId, privateRoot.id, manager);
9193
await manager.update(Namespace, namespace.id, {
9294
rootResource: { id: publicRoot.id },
9395
});
@@ -116,20 +118,28 @@ export class NamespacesService {
116118
await this.namespaceRepository.softDelete(id);
117119
}
118120

119-
async addMember(
120-
namespaceId: string,
121-
userId: string,
122-
privateRootId: string,
123-
manager?: EntityManager,
124-
) {
125-
const repo = manager
126-
? manager.getRepository(NamespaceMember)
127-
: this.namespaceMemberRepository;
128-
await repo.save(
129-
repo.create({
121+
async addMember(namespaceId: string, userId: string, manager: EntityManager) {
122+
const count = await manager.count(NamespaceMember, {
123+
where: {
124+
namespace: { id: namespaceId },
125+
user: { id: userId },
126+
deletedAt: IsNull(),
127+
},
128+
});
129+
if (count > 0) {
130+
return;
131+
}
132+
const privateRoot = await this.resourceService.createFolder(
133+
namespaceId,
134+
null,
135+
userId,
136+
manager,
137+
);
138+
await manager.save(
139+
manager.create(NamespaceMember, {
130140
namespace: { id: namespaceId },
131141
user: { id: userId },
132-
rootResource: { id: privateRootId },
142+
rootResource: { id: privateRoot.id },
133143
}),
134144
);
135145
}
@@ -167,4 +177,19 @@ export class NamespacesService {
167177
return { email: member.user.email, role: member.role };
168178
});
169179
}
180+
181+
async getRoot(namespace: string, spaceType: SpaceType, userId: string) {
182+
let resource: Resource | null;
183+
if (spaceType === SpaceType.TEAMSPACE) {
184+
resource = await this.getTeamspaceRoot(namespace);
185+
} else {
186+
resource = await this.getPrivateRoot(userId, namespace);
187+
}
188+
const children = await this.resourceService.query({
189+
namespaceId: namespace,
190+
spaceType,
191+
parentId: resource.id,
192+
});
193+
return { ...resource, parentId: '0', spaceType, children };
194+
}
170195
}

src/resources/resources.controller.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import {
1515
UploadedFile,
1616
UseInterceptors,
1717
} from '@nestjs/common';
18-
import { SpaceType } from './resources.entity';
1918
import { FileInterceptor } from '@nestjs/platform-express';
2019
import { Response } from 'express';
20+
import { SpaceType } from 'src/namespaces/entities/namespace.entity';
2121

2222
export async function fileResponse(
2323
resourceId: string,
@@ -47,19 +47,6 @@ export class ResourcesController {
4747
return await this.resourcesService.create(req.user, data);
4848
}
4949

50-
@Get('root')
51-
async getRoot(
52-
@Query('namespace_id') namespaceId: string,
53-
@Query('space_type') spaceType: SpaceType,
54-
@Req() req,
55-
) {
56-
return await this.resourcesService.getRoot(
57-
namespaceId,
58-
spaceType,
59-
req.user.id,
60-
);
61-
}
62-
6350
@Get('query')
6451
async query(
6552
@Query('namespace') namespaceId: string,

src/resources/resources.entity.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import {
1212
import { Namespace } from 'src/namespaces/entities/namespace.entity';
1313
import { PermissionLevel } from 'src/permissions/permission-level.enum';
1414

15-
export enum SpaceType {
16-
PRIVATE = 'private',
17-
TEAMSPACE = 'teamspace',
18-
}
19-
2015
export enum ResourceType {
2116
DOC = 'doc',
2217
LINK = 'link',

0 commit comments

Comments
 (0)