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

alkem-io / server / #7980

11 Aug 2024 06:30AM UTC coverage: 13.774%. First build
#7980

Pull #4388

travis-ci

Pull Request #4388: Feature account-spaces: Direct linkage to account for user + organization

79 of 4128 branches covered (1.91%)

Branch coverage included in aggregate %.

4 of 34 new or added lines in 7 files covered. (11.76%)

1914 of 10341 relevant lines covered (18.51%)

3.02 hits per line

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

11.11
/src/services/infrastructure/contributor-lookup/contributor.lookup.service.ts
1
import { EntityManager, FindOneOptions, In } from 'typeorm';
25✔
2
import { isUUID } from 'class-validator';
25✔
3
import { InjectEntityManager } from '@nestjs/typeorm';
25✔
4
import { Inject, LoggerService } from '@nestjs/common';
25✔
5
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
25✔
6
import { User } from '@domain/community/user/user.entity';
25✔
7
import { IContributor } from '@domain/community/contributor/contributor.interface';
8
import {
9
  EntityNotFoundException,
25✔
10
  RelationshipNotFoundException,
11
} from '@common/exceptions';
12
import { AuthorizationCredential, LogContext } from '@common/enums';
13
import { Credential, CredentialsSearchInput, ICredential } from '@domain/agent';
25✔
14
import { VirtualContributor } from '@domain/community/virtual-contributor/virtual.contributor.entity';
25✔
15
import { Organization } from '@domain/community/organization/organization.entity';
25✔
16
import { RoleSetContributorType } from '@common/enums/role.set.contributor.type';
25✔
17
import { InvalidUUID } from '@common/exceptions/invalid.uuid';
25✔
18
import { UserLookupService } from '@domain/community/user-lookup/user.lookup.service';
25✔
19

20
export class ContributorLookupService {
21
  constructor(
25✔
22
    private userLookupService: UserLookupService,
23
    @InjectEntityManager('default')
24
    private entityManager: EntityManager,
×
25
    @Inject(WINSTON_MODULE_NEST_PROVIDER)
26
    private readonly logger: LoggerService
×
27
  ) {}
28

29
  // TODO: this may be heavy, is there a better way to do this?
30
  // Note: this logic should be reworked when the Account relationship to User / Organization is resolved
31
  public async getContributorsManagedByUser(
32
    userID: string
33
  ): Promise<IContributor[]> {
×
34
    const contributorsManagedByUser: IContributor[] = [];
35
    const user = await this.userLookupService.getUserOrFail(userID, {
36
      relations: {
37
        agent: true,
38
      },
39
    });
40
    if (!user.agent) {
×
41
      throw new EntityNotFoundException(
42
        `User with id ${userID} could not load the agent`,
43
        LogContext.COMMUNITY
44
      );
45
    }
46

×
47
    // Obviously this user managed itself :)
48
    contributorsManagedByUser.push(user);
49

50
    // Get all the organizations managed by the User
51
    const organizationOwnerCredentials =
52
      await this.getCredentialsByTypeHeldByAgent(user.agent.id, [
×
53
        AuthorizationCredential.ORGANIZATION_OWNER,
×
54
        AuthorizationCredential.ORGANIZATION_ADMIN,
55
      ]);
56
    const organizationsIDs = organizationOwnerCredentials.map(
57
      credential => credential.resourceID
58
    );
×
59
    const organizations = await this.entityManager.find(Organization, {
60
      where: {
61
        id: In(organizationsIDs),
62
      },
63
      relations: {
64
        agent: true,
65
      },
×
66
    });
×
67
    if (organizations.length > 0) {
×
68
      contributorsManagedByUser.push(...organizations);
69
    }
70

71
    // Get all the Accounts from the User directly or via Organizations the user manages
72
    const accountIDs: string[] = [];
×
73

74
    accountIDs.push(user.accountID);
75

76
    for (const organization of organizations) {
77
      accountIDs.push(organization.accountID);
78
    }
79

×
80
    // Finally, get all the virtual contributors managed by the accounts
81
    for (const accountID of accountIDs) {
82
      const virtualContributors =
83
        await this.getVirtualContributorsManagedByAccount(accountID);
×
84
      contributorsManagedByUser.push(...virtualContributors);
85
    }
86

87
    return contributorsManagedByUser;
×
88
  }
89

90
  private async getVirtualContributorsManagedByAccount(
91
    accountID: string
92
  ): Promise<IContributor[]> {
93
    const virtualContributors = await this.entityManager.find(
94
      VirtualContributor,
×
95
      {
96
        where: {
97
          account: {
98
            id: accountID,
×
99
          },
100
        },
101
      }
×
102
    );
×
103
    return virtualContributors;
104
  }
105

106
  public getContributorType(contributor: IContributor) {
×
107
    if (contributor instanceof User) return RoleSetContributorType.USER;
108
    if (contributor instanceof Organization)
109
      return RoleSetContributorType.ORGANIZATION;
110
    if (contributor instanceof VirtualContributor)
111
      return RoleSetContributorType.VIRTUAL;
112
    throw new RelationshipNotFoundException(
113
      `Unable to determine contributor type for ${contributor.id}`,
114
      LogContext.COMMUNITY
×
115
    );
116
  }
×
117

118
  async contributorsWithCredentials(
×
119
    credentialCriteria: CredentialsSearchInput,
×
120
    limit?: number
121
  ): Promise<IContributor[]> {
122
    const credResourceID = credentialCriteria.resourceID || '';
123

×
124
    const userContributors: IContributor[] = await this.entityManager.find(
125
      User,
126
      {
127
        where: {
128
          agent: {
129
            credentials: {
130
              type: credentialCriteria.type,
×
131
              resourceID: credResourceID,
132
            },
133
          },
134
        },
×
135
        relations: {
×
136
          agent: {
137
            credentials: true,
138
          },
139
        },
×
140
        take: limit,
141
      }
142
    );
143
    const organizationContributors = await this.entityManager.find(
144
      Organization,
145
      {
146
        where: {
147
          agent: {
×
148
            credentials: {
×
149
              type: credentialCriteria.type,
150
              resourceID: credResourceID,
151
            },
152
          },
153
        },
×
154
        relations: {
×
155
          agent: {
156
            credentials: true,
157
          },
158
        },
159
        take: limit,
160
      }
161
    );
×
162

163
    const vcContributors = await this.entityManager.find(VirtualContributor, {
164
      where: {
165
        agent: {
×
166
          credentials: {
167
            type: credentialCriteria.type,
168
            resourceID: credResourceID,
169
          },
×
170
        },
×
171
      },
172
      relations: {
×
173
        agent: {
174
          credentials: true,
175
        },
176
      },
177
      take: limit,
178
    });
179

180
    return userContributors
×
181
      .concat(organizationContributors)
×
182
      .concat(vcContributors);
183
  }
184

185
  async getContributorByUUID(
×
186
    contributorID: string,
NEW
187
    options?: FindOneOptions<IContributor>
×
188
  ): Promise<IContributor | null> {
189
    if (!isUUID(contributorID)) {
×
NEW
190
      throw new InvalidUUID('Invalid UUID provided!', LogContext.COMMUNITY, {
×
191
        provided: contributorID,
192
      });
193
    }
194
    let contributor: IContributor | null = await this.entityManager.findOne(
×
195
      User,
196
      {
×
197
        ...options,
×
198
        where: { ...options?.where, id: contributorID },
199
      }
200
    );
×
201
    if (!contributor) {
202
      contributor = await this.entityManager.findOne(Organization, {
203
        ...options,
204
        where: { ...options?.where, id: contributorID },
205
      });
206
    }
×
207
    if (!contributor) {
208
      contributor = await this.entityManager.findOne(VirtualContributor, {
209
        ...options,
210
        where: { ...options?.where, id: contributorID },
211
      });
212
    }
213

214
    return contributor;
215
  }
216

×
217
  async getContributorByUuidOrFail(
218
    contributorID: string,
219
    options?: FindOneOptions<IContributor>
220
  ): Promise<IContributor | never> {
×
221
    const contributor = await this.getContributorByUUID(contributorID, options);
×
222
    if (!contributor)
×
223
      throw new EntityNotFoundException(
×
224
        `Unable to find Contributor with ID: ${contributorID}`,
×
225
        LogContext.COMMUNITY
×
226
      );
227
    return contributor;
228
  }
229

230
  private async getCredentialsByTypeHeldByAgent(
231
    agentID: string,
232
    credentialTypes: AuthorizationCredential[]
233
  ): Promise<ICredential[]> {
234
    const hostedAccountCredentials = await this.entityManager.find(Credential, {
235
      where: {
×
236
        type: In(credentialTypes),
237
        agent: {
×
238
          id: agentID,
239
        },
240
      },
241
    });
242

243
    return hostedAccountCredentials;
244
  }
245
}
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