• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

teableio / teable / 8421671885

25 Mar 2024 02:23PM UTC coverage: 79.959% (+53.9%) from 26.087%
8421671885

Pull #496

github

web-flow
Merge f587f00fb into 9313e45fb
Pull Request #496: fix: unexpected link convert

3265 of 3865 branches covered (84.48%)

63 of 63 new or added lines in 4 files covered. (100.0%)

762 existing lines in 27 files now uncovered.

25183 of 31495 relevant lines covered (79.96%)

1188.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.03
/apps/nestjs-backend/src/features/collaborator/collaborator.service.ts
1
import { BadRequestException, Injectable } from '@nestjs/common';
2✔
2
import type { SpaceRole } from '@teable/core';
2✔
3
import { PrismaService } from '@teable/db-main-prisma';
2✔
4
import type {
2✔
5
  ListBaseCollaboratorVo,
2✔
6
  ListSpaceCollaboratorVo,
2✔
7
  UpdateSpaceCollaborateRo,
2✔
8
} from '@teable/openapi';
2✔
9
import { Knex } from 'knex';
2✔
10
import { isDate } from 'lodash';
2✔
11
import { InjectModel } from 'nest-knexjs';
2✔
12
import { ClsService } from 'nestjs-cls';
2✔
13
import type { IClsStore } from '../../types/cls';
2✔
14
import { getFullStorageUrl } from '../../utils/full-storage-url';
2✔
15

2✔
16
@Injectable()
2✔
17
export class CollaboratorService {
2✔
18
  constructor(
64✔
19
    private readonly prismaService: PrismaService,
64✔
20
    private readonly cls: ClsService<IClsStore>,
64✔
21
    @InjectModel('CUSTOM_KNEX') private readonly knex: Knex
64✔
22
  ) {}
64✔
23

64✔
24
  async createSpaceCollaborator(userId: string, spaceId: string, role: SpaceRole) {
64✔
25
    const currentUserId = this.cls.get('user.id');
19✔
26
    const exist = await this.prismaService
19✔
27
      .txClient()
19✔
28
      .collaborator.count({ where: { userId, spaceId, deletedTime: null } });
19✔
29
    if (exist) {
19!
UNCOV
30
      throw new BadRequestException('has already existed in space');
×
UNCOV
31
    }
×
32
    return await this.prismaService.txClient().collaborator.create({
19✔
33
      data: {
19✔
34
        spaceId,
19✔
35
        roleName: role,
19✔
36
        userId,
19✔
37
        createdBy: currentUserId,
19✔
38
      },
19✔
39
    });
19✔
40
  }
19✔
41

64✔
42
  async deleteBySpaceId(spaceId: string) {
64✔
43
    return await this.prismaService.txClient().collaborator.updateMany({
15✔
44
      where: {
15✔
45
        spaceId,
15✔
46
      },
15✔
47
      data: {
15✔
48
        deletedTime: new Date().toISOString(),
15✔
49
      },
15✔
50
    });
15✔
51
  }
15✔
52

64✔
53
  async getListByBase(baseId: string): Promise<ListBaseCollaboratorVo> {
64✔
54
    const base = await this.prismaService
×
55
      .txClient()
×
56
      .base.findUniqueOrThrow({ select: { spaceId: true }, where: { id: baseId } });
×
57

×
58
    return await this.getCollaborators({ spaceId: base.spaceId, baseId });
×
59
  }
×
60

64✔
61
  async getBaseCollabsWithPrimary(tableId: string) {
64✔
62
    const { baseId } = await this.prismaService.txClient().tableMeta.findUniqueOrThrow({
×
63
      select: { baseId: true },
×
64
      where: { id: tableId },
×
65
    });
×
66

×
67
    const baseCollabs = await this.getListByBase(baseId);
×
68
    return baseCollabs.map(({ userId, userName, email }) => ({
×
69
      id: userId,
×
70
      name: userName,
×
71
      email,
×
72
    }));
×
73
  }
×
74

64✔
75
  async getListBySpace(spaceId: string): Promise<ListSpaceCollaboratorVo> {
64✔
76
    return await this.getCollaborators({ spaceId });
8✔
77
  }
8✔
78

64✔
79
  private async getCollaborators(params: {
64✔
80
    spaceId: string;
8✔
81
    baseId?: string;
8✔
82
  }): Promise<ListSpaceCollaboratorVo | ListBaseCollaboratorVo> {
8✔
83
    const { spaceId, baseId } = params;
8✔
84
    const getCollaboratorsSql = this.knex
8✔
85
      .select({
8✔
86
        userId: 'u.id',
8✔
87
        userName: 'u.name',
8✔
88
        email: 'u.email',
8✔
89
        avatar: 'u.avatar',
8✔
90
        role: 'c.role_name',
8✔
91
        createdTime: 'c.created_time',
8✔
92
      })
8✔
93
      .from(this.knex.ref('collaborator').as('c'))
8✔
94
      .join(this.knex.ref('users').as('u'), (clause) => {
8✔
95
        clause.on('c.user_id', 'u.id').andOnNull('c.deleted_time').andOnNull('u.deleted_time');
8✔
96
      })
8✔
97
      .where((builder) => {
8✔
98
        builder.where('c.space_id', spaceId);
8✔
99
        if (baseId) {
8!
100
          builder.orWhere('c.base_id', baseId);
×
101
        } else {
8✔
102
          builder.whereNull('c.base_id');
8✔
103
        }
8✔
104
      });
8✔
105

8✔
106
    const collaborators = await this.prismaService
8✔
107
      .txClient()
8✔
108
      .$queryRawUnsafe<
8✔
109
        ListSpaceCollaboratorVo | ListBaseCollaboratorVo
8✔
110
      >(getCollaboratorsSql.toQuery());
8✔
111

8✔
112
    return collaborators.map((collaborator) => {
8✔
113
      if (isDate(collaborator.createdTime)) {
12✔
114
        collaborator.createdTime = collaborator.createdTime.toISOString();
12✔
115
      }
12✔
116
      if (collaborator.avatar) {
12✔
117
        collaborator.avatar = getFullStorageUrl(collaborator.avatar);
4✔
118
      }
4✔
119
      return collaborator;
12✔
120
    });
12✔
121
  }
8✔
122

64✔
123
  async deleteCollaborator(spaceId: string, userId: string) {
64✔
124
    return await this.prismaService.txClient().collaborator.updateMany({
×
125
      where: {
×
126
        spaceId,
×
127
        userId,
×
128
      },
×
129
      data: {
×
130
        deletedTime: new Date().toISOString(),
×
131
      },
×
132
    });
×
133
  }
×
134

64✔
135
  async updateCollaborator(spaceId: string, updateCollaborator: UpdateSpaceCollaborateRo) {
64✔
136
    const currentUserId = this.cls.get('user.id');
×
137
    const { userId, role } = updateCollaborator;
×
138
    return await this.prismaService.txClient().collaborator.updateMany({
×
139
      where: {
×
140
        spaceId,
×
141
        userId,
×
142
      },
×
143
      data: {
×
144
        roleName: role,
×
145
        lastModifiedBy: currentUserId,
×
146
      },
×
147
    });
×
148
  }
×
149

64✔
150
  async getCollaboratorsBaseAndSpaceArray(userId: string) {
64✔
151
    const collaborators = await this.prismaService.txClient().collaborator.findMany({
9✔
152
      where: {
9✔
153
        userId,
9✔
154
        deletedTime: null,
9✔
155
      },
9✔
156
      select: {
9✔
157
        roleName: true,
9✔
158
        baseId: true,
9✔
159
        spaceId: true,
9✔
160
      },
9✔
161
    });
9✔
162
    const roleMap: Record<string, SpaceRole> = {};
9✔
163
    const baseIds = new Set<string>();
9✔
164
    const spaceIds = new Set<string>();
9✔
165
    collaborators.forEach(({ baseId, spaceId, roleName }) => {
9✔
166
      if (baseId) {
18!
167
        baseIds.add(baseId);
×
168
        roleMap[baseId] = roleName as SpaceRole;
×
169
      }
×
170
      if (spaceId) {
18✔
171
        spaceIds.add(spaceId);
18✔
172
        roleMap[spaceId] = roleName as SpaceRole;
18✔
173
      }
18✔
174
    });
18✔
175
    return {
9✔
176
      baseIds: Array.from(baseIds),
9✔
177
      spaceIds: Array.from(spaceIds),
9✔
178
      roleMap: roleMap,
9✔
179
    };
9✔
180
  }
9✔
181
}
64✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc