fix: update tempOrgRediret on updating org slug (#25838)
* fix: update tempOrgRediret on updating s lug * Update packages/trpc/server/routers/viewer/organizations/adminUpdate.handler.ts Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * refactor * fix --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
cubic-dev-ai[bot]
parent
176aeaafd8
commit
b20b52a1f8
@@ -0,0 +1,146 @@
|
||||
import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains";
|
||||
import type { OrganizationRepository } from "@calcom/features/ee/organizations/repositories/OrganizationRepository";
|
||||
import { TeamRepository } from "@calcom/features/ee/teams/repositories/TeamRepository";
|
||||
import { renameDomain } from "@calcom/lib/domainManager/organization";
|
||||
import { getMetadataHelpers } from "@calcom/lib/getMetadataHelpers";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import type { Prisma, PrismaClient } from "@calcom/prisma/client";
|
||||
import { teamMetadataStrictSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { TAdminUpdate } from "@calcom/trpc/server/routers/viewer/organizations/adminUpdate.schema";
|
||||
|
||||
type AdminOrganizationUpdateServiceDeps = {
|
||||
prismaClient: PrismaClient;
|
||||
organizationRepository: OrganizationRepository;
|
||||
};
|
||||
|
||||
export class AdminOrganizationUpdateService {
|
||||
constructor(private readonly deps: AdminOrganizationUpdateServiceDeps) {}
|
||||
|
||||
async updateOrganization(input: TAdminUpdate) {
|
||||
const { id, organizationSettings, ...restInput } = input;
|
||||
const { organizationRepository } = this.deps;
|
||||
|
||||
const existingOrg = await organizationRepository.findByIdIncludeOrganizationSettings({ id });
|
||||
|
||||
if (!existingOrg) {
|
||||
throw new HttpError({
|
||||
message: "Organization not found",
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const { mergeMetadata } = getMetadataHelpers(
|
||||
teamMetadataStrictSchema.unwrap(),
|
||||
existingOrg.metadata || {}
|
||||
);
|
||||
|
||||
const data: Prisma.TeamUpdateArgs["data"] = restInput;
|
||||
const oldSlug = existingOrg.slug;
|
||||
const newSlug = restInput.slug;
|
||||
|
||||
if (newSlug) {
|
||||
await throwIfSlugConflicts({
|
||||
id,
|
||||
slug: newSlug,
|
||||
teamRepository: new TeamRepository(this.deps.prismaClient),
|
||||
});
|
||||
const isSlugChanged = newSlug !== oldSlug;
|
||||
if (isSlugChanged) {
|
||||
// If slug is changed, we need to rename the domain first
|
||||
// If renaming fails, we don't want to update the new slug in DB
|
||||
await renameDomain(oldSlug, newSlug);
|
||||
}
|
||||
data.slug = newSlug;
|
||||
data.metadata = mergeMetadata({
|
||||
// If we save slug, we don't need the requestedSlug anymore
|
||||
requestedSlug: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
const updatedOrganization = await this.deps.prismaClient.$transaction(async (tx) => {
|
||||
const updatedOrganization = await tx.team.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
|
||||
// Update all TempOrgRedirect records that point to the old org URL to use the new org URL
|
||||
if (newSlug && oldSlug && newSlug !== oldSlug) {
|
||||
const oldOrgUrlPrefix = getOrgFullOrigin(oldSlug);
|
||||
const newOrgUrlPrefix = getOrgFullOrigin(newSlug);
|
||||
|
||||
const redirectsToUpdate = await tx.tempOrgRedirect.findMany({
|
||||
where: {
|
||||
toUrl: {
|
||||
startsWith: oldOrgUrlPrefix,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
toUrl: true,
|
||||
},
|
||||
});
|
||||
|
||||
for (const redirect of redirectsToUpdate) {
|
||||
const newToUrl = redirect.toUrl.replace(oldOrgUrlPrefix, newOrgUrlPrefix);
|
||||
await tx.tempOrgRedirect.update({
|
||||
where: {
|
||||
id: redirect.id,
|
||||
},
|
||||
data: {
|
||||
toUrl: newToUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (organizationSettings || existingOrg.organizationSettings) {
|
||||
await tx.organizationSettings.update({
|
||||
where: {
|
||||
organizationId: updatedOrganization.id,
|
||||
},
|
||||
data: {
|
||||
isOrganizationConfigured:
|
||||
organizationSettings?.isOrganizationConfigured ||
|
||||
existingOrg.organizationSettings?.isOrganizationConfigured,
|
||||
isOrganizationVerified:
|
||||
organizationSettings?.isOrganizationVerified ||
|
||||
existingOrg.organizationSettings?.isOrganizationVerified,
|
||||
isAdminReviewed: organizationSettings?.isAdminReviewed,
|
||||
orgAutoAcceptEmail:
|
||||
organizationSettings?.orgAutoAcceptEmail ||
|
||||
existingOrg.organizationSettings?.orgAutoAcceptEmail,
|
||||
isAdminAPIEnabled: !!(
|
||||
organizationSettings?.isAdminAPIEnabled ?? existingOrg.organizationSettings?.isAdminAPIEnabled
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
return updatedOrganization;
|
||||
});
|
||||
|
||||
return updatedOrganization;
|
||||
}
|
||||
}
|
||||
|
||||
async function throwIfSlugConflicts({
|
||||
id,
|
||||
slug,
|
||||
teamRepository,
|
||||
}: {
|
||||
id: number;
|
||||
slug: string;
|
||||
teamRepository: TeamRepository;
|
||||
}) {
|
||||
const isSlugAvailable = await teamRepository.isSlugAvailableForUpdate({
|
||||
slug,
|
||||
teamId: id,
|
||||
parentId: null,
|
||||
});
|
||||
|
||||
if (!isSlugAvailable) {
|
||||
throw new HttpError({
|
||||
message: "Organization or a Team with same slug already exists",
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { createAProfileForAnExistingUser } from "@calcom/features/profile/lib/cr
|
||||
import { UserRepository } from "@calcom/features/users/repositories/UserRepository";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import type { teamMetadataStrictSchema } from "@calcom/prisma/zod-utils";
|
||||
@@ -227,6 +227,7 @@ export class OrganizationRepository {
|
||||
},
|
||||
select: {
|
||||
...orgSelect,
|
||||
metadata: true,
|
||||
organizationSettings: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { renameDomain } from "@calcom/lib/domainManager/organization";
|
||||
import { getMetadataHelpers } from "@calcom/lib/getMetadataHelpers";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { getOrganizationRepository } from "@calcom/features/ee/organizations/di/OrganizationRepository.container";
|
||||
import { AdminOrganizationUpdateService } from "@calcom/features/ee/organizations/lib/service/AdminOrganizationUpdateService";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { teamMetadataStrictSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import type { TrpcSessionUser } from "../../../types";
|
||||
import type { TAdminUpdate } from "./adminUpdate.schema";
|
||||
@@ -16,103 +13,13 @@ type AdminUpdateOptions = {
|
||||
};
|
||||
|
||||
export const adminUpdateHandler = async ({ input }: AdminUpdateOptions) => {
|
||||
const { id, organizationSettings, ...restInput } = input;
|
||||
const existingOrg = await prisma.team.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
include: {
|
||||
organizationSettings: true,
|
||||
},
|
||||
const organizationRepository = getOrganizationRepository();
|
||||
const adminOrganizationUpdateService = new AdminOrganizationUpdateService({
|
||||
prismaClient: prisma,
|
||||
organizationRepository,
|
||||
});
|
||||
|
||||
if (!existingOrg) {
|
||||
throw new HttpError({
|
||||
message: "Organization not found",
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const { mergeMetadata } = getMetadataHelpers(teamMetadataStrictSchema.unwrap(), existingOrg.metadata || {});
|
||||
|
||||
const data: Prisma.TeamUpdateArgs["data"] = restInput;
|
||||
|
||||
if (restInput.slug) {
|
||||
await throwIfSlugConflicts({ id, slug: restInput.slug });
|
||||
const isSlugChanged = restInput.slug !== existingOrg.slug;
|
||||
if (isSlugChanged) {
|
||||
// If slug is changed, we need to rename the domain first
|
||||
// If renaming fails, we don't want to update the new slug in DB
|
||||
await renameDomain(existingOrg.slug, restInput.slug);
|
||||
}
|
||||
data.slug = input.slug;
|
||||
data.metadata = mergeMetadata({
|
||||
// If we save slug, we don't need the requestedSlug anymore
|
||||
requestedSlug: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
const updatedOrganization = await prisma.$transaction(async (tx) => {
|
||||
const updatedOrganization = await tx.team.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
|
||||
if (organizationSettings || existingOrg.organizationSettings) {
|
||||
await tx.organizationSettings.update({
|
||||
where: {
|
||||
organizationId: updatedOrganization.id,
|
||||
},
|
||||
data: {
|
||||
isOrganizationConfigured:
|
||||
organizationSettings?.isOrganizationConfigured ||
|
||||
existingOrg.organizationSettings?.isOrganizationConfigured,
|
||||
isOrganizationVerified:
|
||||
organizationSettings?.isOrganizationVerified ||
|
||||
existingOrg.organizationSettings?.isOrganizationVerified,
|
||||
isAdminReviewed: organizationSettings?.isAdminReviewed,
|
||||
orgAutoAcceptEmail:
|
||||
organizationSettings?.orgAutoAcceptEmail || existingOrg.organizationSettings?.orgAutoAcceptEmail,
|
||||
isAdminAPIEnabled: !!(
|
||||
organizationSettings?.isAdminAPIEnabled ?? existingOrg.organizationSettings?.isAdminAPIEnabled
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
return updatedOrganization;
|
||||
});
|
||||
|
||||
return updatedOrganization;
|
||||
return adminOrganizationUpdateService.updateOrganization(input);
|
||||
};
|
||||
|
||||
export default adminUpdateHandler;
|
||||
|
||||
async function throwIfSlugConflicts({ id, slug }: { id: number; slug: string }) {
|
||||
const organizationsWithSameSlug = await prisma.team.findMany({
|
||||
where: {
|
||||
slug: slug,
|
||||
parentId: null,
|
||||
},
|
||||
});
|
||||
|
||||
if (organizationsWithSameSlug.length > 1) {
|
||||
throw new HttpError({
|
||||
message: "There can only be one organization with a given slug",
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const foundOrg = organizationsWithSameSlug[0];
|
||||
if (!foundOrg) {
|
||||
// No org with same slug found - So, no conflict.
|
||||
return;
|
||||
}
|
||||
|
||||
// If foundOrg isn't same as the org being edited
|
||||
if (foundOrg.id !== id) {
|
||||
throw new HttpError({
|
||||
message: "Organization or a Team with same slug already exists",
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user