Skip to content

Commit

Permalink
Merge branch 'main' into refactor_allow_managed_event_tests_parallel_…
Browse files Browse the repository at this point in the history
…runs
  • Loading branch information
zomars committed Aug 15, 2024
2 parents 9ebbc03 + cd311f0 commit 61889ab
Show file tree
Hide file tree
Showing 102 changed files with 2,497 additions and 839 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/e2e-app-store.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,5 @@ jobs:
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: app-store-results
path: test-results
name: blob-report-app-store
path: blob-report
4 changes: 2 additions & 2 deletions .github/workflows/e2e-embed-react.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,5 @@ jobs:
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: embed-react-results
path: test-results
name: blob-report-embed-react
path: blob-report
4 changes: 2 additions & 2 deletions .github/workflows/e2e-embed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,5 @@ jobs:
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: embed-core-results
path: test-results
name: blob-report-embed-core
path: blob-report
2 changes: 1 addition & 1 deletion .github/workflows/pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ jobs:
if: github.event.review.state == 'approved'
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.READY_FOR_E2E_PAT }}
labels: 'ready-for-e2e'
8 changes: 4 additions & 4 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,19 @@ jobs:

merge-reports:
name: Merge reports
if: ${{ !cancelled() }}
needs: [e2e]
if: ${{ !cancelled() && needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [changes, check-label, e2e, e2e-embed, e2e-embed-react, e2e-app-store]
uses: ./.github/workflows/merge-reports.yml
secrets: inherit

publish-report:
name: Publish HTML report
if: ${{ !cancelled() }}
if: ${{ !cancelled() && needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
permissions:
contents: write
issues: write
pull-requests: write
needs: [merge-reports]
needs: [changes, check-label, merge-reports]
uses: ./.github/workflows/publish-report.yml
secrets: inherit

Expand Down
28 changes: 26 additions & 2 deletions apps/api/v2/src/ee/me/me.controller.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import { User } from "@prisma/client";
import { User, Team } from "@prisma/client";
import * as request from "supertest";
import { OrganizationRepositoryFixture } from "test/fixtures/repository/organization.repository.fixture";
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withApiAuth } from "test/utils/withApiAuth";
Expand All @@ -25,9 +27,11 @@ describe("Me Endpoints", () => {

let userRepositoryFixture: UserRepositoryFixture;
let schedulesRepositoryFixture: SchedulesRepositoryFixture;

let profilesRepositoryFixture: ProfileRepositoryFixture;
let organizationsRepositoryFixture: OrganizationRepositoryFixture;
const userEmail = "me-controller-e2e@api.com";
let user: User;
let org: Team;

beforeAll(async () => {
const moduleRef = await withApiAuth(
Expand All @@ -43,13 +47,30 @@ describe("Me Endpoints", () => {
.compile();

userRepositoryFixture = new UserRepositoryFixture(moduleRef);
organizationsRepositoryFixture = new OrganizationRepositoryFixture(moduleRef);
profilesRepositoryFixture = new ProfileRepositoryFixture(moduleRef);

schedulesRepositoryFixture = new SchedulesRepositoryFixture(moduleRef);

user = await userRepositoryFixture.create({
email: userEmail,
username: userEmail,
});

org = await organizationsRepositoryFixture.create({
name: "Test org team",
isOrganization: true,
isPlatform: true,
});

await profilesRepositoryFixture.create({
uid: "asd-asd",
username: userEmail,
user: { connect: { id: user.id } },
organization: { connect: { id: org.id } },
movedFromUser: { connect: { id: user.id } },
});

app = moduleRef.createNestApplication();
bootstrap(app as NestExpressApplication);

Expand All @@ -75,6 +96,8 @@ describe("Me Endpoints", () => {
expect(responseBody.data.defaultScheduleId).toEqual(user.defaultScheduleId);
expect(responseBody.data.weekStart).toEqual(user.weekStart);
expect(responseBody.data.timeZone).toEqual(user.timeZone);
expect(responseBody.data.organization?.isPlatform).toEqual(true);
expect(responseBody.data.organization?.id).toEqual(org.id);
});
});

Expand Down Expand Up @@ -138,6 +161,7 @@ describe("Me Endpoints", () => {

afterAll(async () => {
await userRepositoryFixture.deleteByEmail(user.email);
await organizationsRepositoryFixture.delete(org.id);
await app.close();
});
});
Expand Down
15 changes: 13 additions & 2 deletions apps/api/v2/src/ee/me/me.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,19 @@ export class MeController {
@Get("/")
@Permissions([PROFILE_READ])
async getMe(@GetUser() user: UserWithProfile): Promise<GetMeOutput> {
const me = userSchemaResponse.parse(user);

const organization = user?.movedToProfile?.organization;
const me = userSchemaResponse.parse(
organization
? {
...user,
organizationId: organization.id,
organization: {
id: organization.id,
isPlatform: organization.isPlatform,
},
}
: user
);
return {
status: SUCCESS_STATUS,
data: me,
Expand Down
13 changes: 12 additions & 1 deletion apps/api/v2/src/ee/me/outputs/me.output.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { IsInt, IsEmail, IsOptional, IsString } from "class-validator";
import { Type } from "class-transformer";
import { IsInt, IsEmail, IsOptional, IsString, ValidateNested } from "class-validator";

export class MeOrgOutput {
isPlatform!: boolean;

id!: number;
}
export class MeOutput {
@IsInt()
id!: number;
Expand All @@ -25,4 +31,9 @@ export class MeOutput {

@IsInt()
organizationId!: number | null;

@IsOptional()
@ValidateNested()
@Type(() => MeOrgOutput)
organization?: MeOrgOutput;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TokensRepository } from "@/modules/tokens/tokens.repository";
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Reflector } from "@nestjs/core";
import { getToken } from "next-auth/jwt";

import { hasPermissions } from "@calcom/platform-utils";

Expand All @@ -24,6 +25,12 @@ export class PermissionsGuard implements CanActivate {

const request = context.switchToHttp().getRequest();
const authString = request.get("Authorization")?.replace("Bearer ", "");
const nextAuthSecret = this.config.get("next.authSecret", { infer: true });
const nextAuthToken = await getToken({ req: request, secret: nextAuthSecret });

if (nextAuthToken) {
return true;
}

if (!authString) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Injectable, InternalServerErrorException, UnauthorizedException } from
import { ConfigService } from "@nestjs/config";
import { PassportStrategy } from "@nestjs/passport";
import type { Request } from "express";
import { getToken } from "next-auth/jwt";

import { INVALID_ACCESS_TOKEN, X_CAL_CLIENT_ID, X_CAL_SECRET_KEY } from "@calcom/platform-constants";

Expand Down Expand Up @@ -45,6 +46,13 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
return await this.authenticateBearerToken(bearerToken, requestOrigin);
}

const nextAuthSecret = this.config.get("next.authSecret", { infer: true });
const nextAuthToken = await getToken({ req: request, secret: nextAuthSecret });

if (nextAuthToken) {
return await this.authenticateNextAuth(nextAuthToken);
}

throw new UnauthorizedException(
"No authentication method provided. Either pass an API key as 'Bearer' header or OAuth client credentials as 'x-cal-secret-key' and 'x-cal-client-id' headers"
);
Expand All @@ -58,6 +66,11 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
}
}

async authenticateNextAuth(token: { email?: string | null }) {
const user = await this.nextAuthStrategy(token);
return this.success(user);
}

async authenticateOAuthClient(oAuthClientId: string, oAuthClientSecret: string) {
const user = await this.oAuthClientStrategy(oAuthClientId, oAuthClientSecret);
return this.success(user);
Expand Down Expand Up @@ -163,4 +176,17 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
const user: UserWithProfile | null = await this.userRepository.findByIdWithProfile(ownerId);
return user;
}

async nextAuthStrategy(token: { email?: string | null }) {
if (!token.email) {
throw new UnauthorizedException("Email not found in the authentication token.");
}

const user = await this.userRepository.findByEmailWithProfile(token.email);
if (!user) {
throw new UnauthorizedException("User associated with the authentication token email not found.");
}

return user;
}
}
13 changes: 9 additions & 4 deletions apps/api/v2/src/modules/users/users.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { CreateManagedUserInput } from "@/modules/users/inputs/create-managed-user.input";
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
import { Injectable } from "@nestjs/common";
import type { Profile, User } from "@prisma/client";
import type { Profile, User, Team } from "@prisma/client";

export type UserWithProfile = User & {
movedToProfile?: Profile | null;
movedToProfile?: (Profile & { organization: Pick<Team, "isPlatform" | "id" | "slug" | "name"> }) | null;
};

@Injectable()
Expand Down Expand Up @@ -67,12 +67,15 @@ export class UsersRepository {
}

async findByIdWithProfile(userId: number): Promise<UserWithProfile | null> {
console.log("findByIdWithProfile");
return this.dbRead.prisma.user.findUnique({
where: {
id: userId,
},
include: {
movedToProfile: true,
movedToProfile: {
include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } },
},
},
});
}
Expand Down Expand Up @@ -126,7 +129,9 @@ export class UsersRepository {
email,
},
include: {
movedToProfile: true,
movedToProfile: {
include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } },
},
},
});
}
Expand Down
Loading

0 comments on commit 61889ab

Please sign in to comment.