Fixes disable branding for teams and users (#5913)

* Adding new nextauth object

* Use correct brand hidden values

* Move check to getprops instead of a function

* Update apps/web/components/booking/pages/AvailabilityPage.tsx

* Update apps/web/components/booking/pages/AvailabilityPage.tsx

* Update apps/web/pages/[user]/[type].tsx

Co-authored-by: Leo Giovanetti <hello@leog.me>

* Update apps/web/pages/api/auth/[...nextauth].tsx

Co-authored-by: Leo Giovanetti <hello@leog.me>

* Update apps/web/pages/api/auth/[...nextauth].tsx

Co-authored-by: Leo Giovanetti <hello@leog.me>

Co-authored-by: Leo Giovanetti <hello@leog.me>
This commit is contained in:
sean-brydon
2022-12-07 15:04:04 +00:00
committed by GitHub
co-authored by Leo Giovanetti
parent c3122c82e4
commit f4ed345a87
9 changed files with 57 additions and 10 deletions
@@ -442,7 +442,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
/>
</div>
</div>
{(!eventType.users[0] || !isBrandingHidden(eventType.users[0])) && !isEmbed && <PoweredByCal />}
{(!restProps.isBrandingHidden || isEmbed) && <PoweredByCal />}
</div>
</main>
</div>
+2 -4
View File
@@ -1,5 +1,3 @@
import { User } from "@prisma/client";
export function isBrandingHidden<TUser extends Pick<User, "hideBranding" | "plan">>(user: TUser) {
return user.hideBranding && user.plan !== "FREE";
export function isBrandingHidden(hideBrandingSetting: boolean, belongsToActiveTeam: boolean) {
return belongsToActiveTeam && hideBrandingSetting;
}
+16 -1
View File
@@ -10,8 +10,9 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent";
import prisma from "@calcom/prisma";
import { User } from "@calcom/prisma/client";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { EventTypeMetaDataSchema, teamMetadataSchema } from "@calcom/prisma/zod-utils";
import { isBrandingHidden } from "@lib/isBrandingHidden";
import { inferSSRProps } from "@lib/types/inferSSRProps";
import { EmbedProps } from "@lib/withEmbedSsr";
@@ -110,6 +111,11 @@ async function getUserPageProps(context: GetStaticPropsContext) {
},
],
},
teams: {
include: {
team: true,
},
},
},
});
@@ -150,6 +156,13 @@ async function getUserPageProps(context: GetStaticPropsContext) {
locations: privacyFilteredLocations(locations),
descriptionAsSafeHTML: eventType.description ? md.render(eventType.description) : null,
});
// Check if the user you are logging into has any active teams
const hasActiveTeam =
user.teams.filter((m) => {
const metadata = teamMetadataSchema.safeParse(m.team.metadata);
if (metadata.success && metadata.data?.subscriptionId) return false;
return true;
}).length > 0;
return {
props: {
@@ -167,6 +180,7 @@ async function getUserPageProps(context: GetStaticPropsContext) {
away: user?.away,
isDynamic: false,
trpcState: ssg.dehydrate(),
isBrandingHidden: isBrandingHidden(user.hideBranding, hasActiveTeam),
},
revalidate: 10, // seconds
};
@@ -262,6 +276,7 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
isDynamic: true,
away: false,
trpcState: ssg.dehydrate(),
isBrandingHidden: false, // I think we should always show branding for dynamic groups - saves us checking every single user
},
revalidate: 10, // seconds
};
+18
View File
@@ -20,6 +20,7 @@ import { defaultCookies } from "@calcom/lib/default-cookies";
import rateLimit from "@calcom/lib/rateLimit";
import { serverConfig } from "@calcom/lib/serverConfig";
import prisma from "@calcom/prisma";
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
import CalComAdapter from "@lib/auth/next-auth-custom-adapter";
import { randomString } from "@lib/random";
@@ -63,6 +64,11 @@ const providers: Provider[] = [
password: true,
twoFactorEnabled: true,
twoFactorSecret: true,
teams: {
include: {
team: true,
},
},
},
});
@@ -116,6 +122,13 @@ const providers: Provider[] = [
intervalInMs: 60 * 1000, // 1 minute
});
await limiter.check(10, user.email); // 10 requests per minute
// Check if the user you are logging into has any active teams
const hasActiveTeams =
user.teams.filter((m) => {
const metadata = teamMetadataSchema.safeParse(m.team.metadata);
if (metadata.success && metadata.data?.subscriptionId) return false;
return true;
}).length > 0;
// authentication success- but does it meet the minimum password requirements?
if (user.role === "ADMIN" && !isPasswordValid(credentials.password, false, true)) {
@@ -125,6 +138,7 @@ const providers: Provider[] = [
email: user.email,
name: user.name,
role: "USER",
belongsToActiveTeam: hasActiveTeams,
};
}
@@ -134,6 +148,7 @@ const providers: Provider[] = [
email: user.email,
name: user.name,
role: user.role,
belongsToActiveTeam: hasActiveTeams,
};
},
}),
@@ -272,6 +287,7 @@ export default NextAuth({
email: user.email,
role: user.role,
impersonatedByUID: user?.impersonatedByUID,
belongsToActiveTeam: user?.belongsToActiveTeam,
};
}
@@ -307,6 +323,7 @@ export default NextAuth({
email: existingUser.email,
role: existingUser.role,
impersonatedByUID: token.impersonatedByUID as number,
belongsToActiveTeam: token?.belongsToActiveTeam as boolean,
};
}
@@ -324,6 +341,7 @@ export default NextAuth({
username: token.username as string,
role: token.role as UserPermissionRole,
impersonatedByUID: token.impersonatedByUID as number,
belongsToActiveTeam: token?.belongsToActiveTeam as boolean,
},
};
return calendsoSession;
+1
View File
@@ -166,6 +166,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
previousPage: context.req.headers.referer ?? null,
booking,
users: [user.username],
isBrandingHidden: user.hideBranding,
},
};
};
@@ -1,3 +1,4 @@
import { useSession } from "next-auth/react";
import { Controller, useForm } from "react-hook-form";
import { APP_NAME } from "@calcom/lib/constants";
@@ -41,7 +42,7 @@ const SkeletonLoader = () => {
const AppearanceView = () => {
const { t } = useLocale();
const session = useSession();
const utils = trpc.useContext();
const { data: user, isLoading } = trpc.viewer.me.useQuery();
@@ -180,6 +181,7 @@ const AppearanceView = () => {
<div className="flex-none">
<Switch
id="hideBranding"
disabled={!session.data?.user.belongsToActiveTeam}
onCheckedChange={(checked) =>
formMethods.setValue("hideBranding", checked, { shouldDirty: true })
}
+2
View File
@@ -43,6 +43,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
name: true,
slug: true,
logo: true,
hideBranding: true,
eventTypes: {
where: {
slug: typeParam,
@@ -160,6 +161,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
previousPage: context.req.headers.referer ?? null,
booking,
trpcState: ssg.dehydrate(),
isBrandingHidden: team.hideBranding,
},
};
};
@@ -11,7 +11,8 @@ const teamIdschema = z.object({
const auditAndReturnNextUser = async (
impersonatedUser: Pick<User, "id" | "username" | "email" | "name" | "role">,
impersonatedByUID: number
impersonatedByUID: number,
hasTeam?: boolean
) => {
// Log impersonations for audit purposes
await prisma.impersonations.create({
@@ -36,6 +37,7 @@ const auditAndReturnNextUser = async (
name: impersonatedUser.name,
role: impersonatedUser.role,
impersonatedByUID,
belongsToActiveTeam: hasTeam,
};
return obj;
@@ -103,7 +105,11 @@ const ImpersonationProvider = CredentialsProvider({
if (impersonatedUser.disableImpersonation) {
throw new Error("This user has disabled Impersonation.");
}
return auditAndReturnNextUser(impersonatedUser, session?.user.id as number);
return auditAndReturnNextUser(
impersonatedUser,
session?.user.id as number,
impersonatedUser.teams.length > 0 // If the user has any teams, they belong to an active team and we can set the hasActiveTeam ctx to true
);
}
if (!teamId) throw new Error("You do not have permission to do this.");
@@ -137,7 +143,11 @@ const ImpersonationProvider = CredentialsProvider({
throw new Error("You do not have permission to do this.");
}
return auditAndReturnNextUser(impersonatedUser, session?.user.id as number);
return auditAndReturnNextUser(
impersonatedUser,
session?.user.id as number,
impersonatedUser.teams.length > 0 // If the user has any teams, they belong to an active team and we can set the hasActiveTeam ctx to true
);
},
});
+1
View File
@@ -14,6 +14,7 @@ declare module "next-auth" {
emailVerified?: PrismaUser["emailVerified"];
email_verified?: boolean;
impersonatedByUID?: number;
belongsToActiveTeam?: boolean;
username?: PrismaUser["username"];
role?: PrismaUser["role"];
}