chore: removed gravatar (#11153)
parent
7143923ea4
commit
3f0380617a
|
@ -98,14 +98,7 @@ const UserProfile = () => {
|
|||
return (
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="flex flex-row items-center justify-start rtl:justify-end">
|
||||
{user && (
|
||||
<Avatar
|
||||
alt={user.username || "user avatar"}
|
||||
gravatarFallbackMd5={user.emailMd5}
|
||||
size="lg"
|
||||
imageSrc={imageSrc}
|
||||
/>
|
||||
)}
|
||||
{user && <Avatar alt={user.username || "user avatar"} size="lg" imageSrc={imageSrc} />}
|
||||
<input
|
||||
ref={avatarRef}
|
||||
type="hidden"
|
||||
|
|
|
@ -32,7 +32,7 @@ function getCspPolicy(nonce: string) {
|
|||
IS_PRODUCTION ? (useNonStrictPolicy ? "'unsafe-inline'" : "") : "'unsafe-inline'"
|
||||
} app.cal.com;
|
||||
font-src 'self';
|
||||
img-src 'self' ${WEBAPP_URL} https://www.gravatar.com https://img.youtube.com https://eu.ui-avatars.com/api/ data:;
|
||||
img-src 'self' ${WEBAPP_URL} https://img.youtube.com https://eu.ui-avatars.com/api/ data:;
|
||||
connect-src 'self'
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import crypto from "crypto";
|
||||
|
||||
export const defaultAvatarSrc = function ({ email, md5 }: { md5?: string; email?: string }) {
|
||||
if (!email && !md5) return "";
|
||||
|
||||
if (email && !md5) {
|
||||
md5 = crypto.createHash("md5").update(email).digest("hex");
|
||||
}
|
||||
|
||||
return `https://www.gravatar.com/avatar/${md5}?s=160&d=mp&r=PG`;
|
||||
};
|
|
@ -1,13 +1,11 @@
|
|||
import crypto from "crypto";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getSlugOrRequestedSlug, orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { AVATAR_FALLBACK } from "@calcom/lib/constants";
|
||||
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { defaultAvatarSrc } from "@lib/profile";
|
||||
|
||||
const querySchema = z
|
||||
.object({
|
||||
username: z.string(),
|
||||
|
@ -75,12 +73,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
res.setHeader("x-cal-org", identity.org);
|
||||
}
|
||||
res.writeHead(302, {
|
||||
Location: defaultAvatarSrc({
|
||||
md5: crypto
|
||||
.createHash("md5")
|
||||
.update(identity?.email || "guest@example.com")
|
||||
.digest("hex"),
|
||||
}),
|
||||
Location: AVATAR_FALLBACK,
|
||||
});
|
||||
|
||||
return res.end();
|
||||
|
|
|
@ -406,7 +406,7 @@ const ProfileForm = ({
|
|||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
<Avatar alt="" imageSrc={value} gravatarFallbackMd5="fallback" size="lg" />
|
||||
<Avatar alt="" imageSrc={value} size="lg" />
|
||||
<div className="ms-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg width="32" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><rect width="32" height="32" rx="16" fill="#E5E7EB"/><path d="M16 21.333A6.667 6.667 0 1 0 16 8a6.667 6.667 0 0 0 0 13.333Z" fill="#1F2937"/><path d="M26.667 32a10.667 10.667 0 1 0-21.334 0" fill="#1F2937"/><path d="M16 21.333A6.667 6.667 0 1 0 16 8a6.667 6.667 0 0 0 0 13.333Zm0 0A10.667 10.667 0 0 1 26.667 32M16 21.333A10.666 10.666 0 0 0 5.333 32" stroke="#1F2937" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></g><defs><clipPath id="a"><rect width="32" height="32" rx="16" fill="#fff"/></clipPath></defs></svg>
|
After Width: | Height: | Size: 635 B |
|
@ -1093,7 +1093,7 @@
|
|||
"or_lowercase": "or",
|
||||
"nevermind": "Nevermind",
|
||||
"go_to": "Go to: ",
|
||||
"invite_link_make": "<li>Go to<a>Make Invite Link</a> and install Cal.com appp</li>",
|
||||
"invite_link_make": "<li>Go to<a>Make Invite Link</a> and install Cal.com app</li>",
|
||||
"zapier_invite_link": "Zapier Invite Link",
|
||||
"meeting_url_provided_after_confirmed": "A Meeting URL will be created once the event is confirmed.",
|
||||
"dynamically_display_attendee_or_organizer": "Dynamically display the name of your attendee for you, or your name if it's viewed by your attendee",
|
||||
|
|
|
@ -80,7 +80,6 @@ function UserToInviteItem({
|
|||
alt="Users avatar"
|
||||
asChild
|
||||
imageSrc={`${bookerUrl}/${member.user.username}/avatar.png`}
|
||||
gravatarFallbackMd5="hash"
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${member.user.id}`}
|
||||
|
|
|
@ -241,12 +241,7 @@ const PendingMemberItem = (props: { member: TeamMember; index: number; teamId: n
|
|||
)}
|
||||
data-testid="pending-member-item">
|
||||
<div className="flex space-x-2 rtl:space-x-reverse">
|
||||
<Avatar
|
||||
gravatarFallbackMd5="teamMember"
|
||||
size="mdLg"
|
||||
imageSrc={bookerUrl + "/" + member.username + "/avatar.png"}
|
||||
alt="owner-avatar"
|
||||
/>
|
||||
<Avatar size="mdLg" imageSrc={bookerUrl + "/" + member.username + "/avatar.png"} alt="owner-avatar" />
|
||||
<div>
|
||||
<div className="flex space-x-1">
|
||||
<p>{member.name || member.email || t("team_member")}</p>
|
||||
|
|
|
@ -119,7 +119,7 @@ export const UserForm = ({
|
|||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
<Avatar alt="" imageSrc={value} gravatarFallbackMd5="fallback" size="lg" />
|
||||
<Avatar alt="" imageSrc={value} size="lg" />
|
||||
<div className="ml-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
|
|
|
@ -134,7 +134,6 @@ function UsersTableBare() {
|
|||
<Avatar
|
||||
size="md"
|
||||
alt={`Avatar of ${user.username || "Nameless"}`}
|
||||
gravatarFallbackMd5=""
|
||||
imageSrc={`${WEBAPP_URL}/${user.username}/avatar.png?orgId=${user.organizationId}`}
|
||||
/>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { defaultAvatarSrc } from "@calcom/lib/defaultAvatarImage";
|
||||
import { AVATAR_FALLBACK } from "@calcom/lib/constants";
|
||||
import { _UserModel as User } from "@calcom/prisma/zod";
|
||||
import type { inferRouterOutputs } from "@calcom/trpc";
|
||||
import { TRPCError } from "@calcom/trpc";
|
||||
|
@ -39,7 +39,7 @@ export function getAvatarUrlFromUser(user: {
|
|||
username: string | null;
|
||||
email: string;
|
||||
}) {
|
||||
if (!user.avatar || !user.username) return defaultAvatarSrc({ email: user.email });
|
||||
if (!user.avatar || !user.username) return AVATAR_FALLBACK;
|
||||
return `${WEBAPP_URL}/${user.username}/avatar.png`;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,6 @@ const Filter = (props: {
|
|||
imageSrc={userAvatar || ""}
|
||||
size="sm"
|
||||
alt={`${user} Avatar`}
|
||||
gravatarFallbackMd5="fallback"
|
||||
className="self-center"
|
||||
asChild
|
||||
/>
|
||||
|
@ -172,7 +171,6 @@ const Filter = (props: {
|
|||
imageSrc={profile.image || ""}
|
||||
size="sm"
|
||||
alt={`${profile.slug} Avatar`}
|
||||
gravatarFallbackMd5="fallback"
|
||||
className="self-center"
|
||||
asChild
|
||||
/>
|
||||
|
|
|
@ -24,7 +24,6 @@ export const TotalBookingUsersTable = ({
|
|||
imageSrc={item.user.avatar}
|
||||
title={item.user.name || ""}
|
||||
className="m-2"
|
||||
gravatarFallbackMd5={item.emailMd5}
|
||||
/>
|
||||
<p className="text-default mx-0 my-auto">
|
||||
<strong>{item.user.name}</strong>
|
||||
|
|
|
@ -76,12 +76,7 @@ export function AvailabilitySliderTable() {
|
|||
const { username, email, timeZone } = row.original;
|
||||
return (
|
||||
<div className="max-w-64 flex flex-shrink-0 items-center gap-2 overflow-hidden">
|
||||
<Avatar
|
||||
size="sm"
|
||||
alt={username || email}
|
||||
imageSrc={"/" + username + "/avatar.png"}
|
||||
gravatarFallbackMd5="fallback"
|
||||
/>
|
||||
<Avatar size="sm" alt={username || email} imageSrc={"/" + username + "/avatar.png"} />
|
||||
<div className="">
|
||||
<div className="text-emphasis max-w-64 truncate text-sm font-medium" title={email}>
|
||||
{username || "No username"}
|
||||
|
|
|
@ -93,12 +93,7 @@ export function EditForm({
|
|||
});
|
||||
}}>
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
<Avatar
|
||||
size="lg"
|
||||
alt={`${selectedUser?.name} avatar`}
|
||||
imageSrc={avatarUrl}
|
||||
gravatarFallbackMd5="fallback"
|
||||
/>
|
||||
<Avatar size="lg" alt={`${selectedUser?.name} avatar`} imageSrc={avatarUrl} />
|
||||
<div className="space-between flex flex-col leading-none">
|
||||
<span className="text-emphasis text-lg font-semibold">{selectedUser?.name ?? "Nameless User"}</span>
|
||||
<p className="subtle text-sm font-normal">
|
||||
|
|
|
@ -46,7 +46,6 @@ export function EditUserSheet({ state, dispatch }: { state: State; dispatch: Dis
|
|||
className="h-[36px] w-[36px]"
|
||||
alt={`${loadedUser?.name} avatar`}
|
||||
imageSrc={avatarURL}
|
||||
gravatarFallbackMd5="fallback"
|
||||
/>
|
||||
<div className="space-between flex flex-col leading-none">
|
||||
<Skeleton loading={isLoading} as="p" waitForTranslation={false}>
|
||||
|
|
|
@ -163,12 +163,7 @@ export function UserListTable() {
|
|||
const { username, email } = row.original;
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar
|
||||
size="sm"
|
||||
alt={username || email}
|
||||
imageSrc={domain + "/" + username + "/avatar.png"}
|
||||
gravatarFallbackMd5="fallback"
|
||||
/>
|
||||
<Avatar size="sm" alt={username || email} imageSrc={domain + "/" + username + "/avatar.png"} />
|
||||
<div className="">
|
||||
<div className="text-emphasis text-sm font-medium leading-none">
|
||||
{username || "No username"}
|
||||
|
|
|
@ -58,6 +58,7 @@ export const HOSTED_CAL_FEATURES = process.env.NEXT_PUBLIC_HOSTED_CAL_FEATURES |
|
|||
export const NEXT_PUBLIC_BASE_URL = process.env.NEXT_PUBLIC_WEBAPP_URL || `https://${process.env.VERCEL_URL}`;
|
||||
export const LOGO = "/calcom-logo-white-word.svg";
|
||||
export const LOGO_ICON = "/cal-com-icon-white.svg";
|
||||
export const AVATAR_FALLBACK = "/avatar.svg";
|
||||
export const FAVICON_16 = "/favicon-16x16.png";
|
||||
export const FAVICON_32 = "/favicon-32x32.png";
|
||||
export const APPLE_TOUCH_ICON = "/apple-touch-icon.png";
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { defaultAvatarSrc, getPlaceholderAvatar } from "./defaultAvatarImage";
|
||||
|
||||
describe("Default Avatar Image tests", () => {
|
||||
describe("fn: defaultAvatarSrc", () => {
|
||||
it("should return a gravatar URL when an email is provided", () => {
|
||||
const email = "john@example.com";
|
||||
const result = defaultAvatarSrc({ email });
|
||||
|
||||
expect(result).toEqual(
|
||||
"https://www.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=160&d=mp&r=PG"
|
||||
);
|
||||
});
|
||||
|
||||
it("should return a gravatar URL when an MD5 hash is provided", () => {
|
||||
const md5 = "my-md5-hash";
|
||||
const result = defaultAvatarSrc({ md5 });
|
||||
|
||||
expect(result).toEqual("https://www.gravatar.com/avatar/my-md5-hash?s=160&d=mp&r=PG");
|
||||
});
|
||||
|
||||
it("should return a gravatar URL using the MD5 hash when an email and MD5 hash are provided", () => {
|
||||
const email = "john@example.com";
|
||||
const md5 = "my-md5-hash";
|
||||
|
||||
const result = defaultAvatarSrc({ email, md5 });
|
||||
|
||||
expect(result).toEqual("https://www.gravatar.com/avatar/my-md5-hash?s=160&d=mp&r=PG");
|
||||
});
|
||||
|
||||
it("should return an empty string when neither an email or MD5 hash is provided", () => {
|
||||
const result = defaultAvatarSrc({});
|
||||
|
||||
expect(result).toEqual("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("fn: getPlaceholderAvatar", () => {
|
||||
it("should return the avatar URL when one is provided", () => {
|
||||
const avatar = "https://example.com/avatar.png";
|
||||
const name = "John Doe";
|
||||
|
||||
const result = getPlaceholderAvatar(avatar, name);
|
||||
|
||||
expect(result).toEqual(avatar);
|
||||
});
|
||||
|
||||
it("should return a placeholder avatar URL when no avatar is provided", () => {
|
||||
const name = "John Doe";
|
||||
|
||||
const result = getPlaceholderAvatar(null, name);
|
||||
|
||||
expect(result).toEqual(
|
||||
"https://eu.ui-avatars.com/api/?background=fff&color=f9f9f9&bold=true&background=000000&name=John%20Doe"
|
||||
);
|
||||
});
|
||||
|
||||
it("should return a placeholder avatar URL when no avatar is provided and no name is provided", () => {
|
||||
const result = getPlaceholderAvatar(null, null);
|
||||
|
||||
expect(result).toEqual(
|
||||
"https://eu.ui-avatars.com/api/?background=fff&color=f9f9f9&bold=true&background=000000&name="
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,19 +1,3 @@
|
|||
import md5Parser from "md5";
|
||||
|
||||
/**
|
||||
* Provided either an email or an MD5 hash, return the URL for the Gravatar
|
||||
* image aborting early if neither is provided.
|
||||
*/
|
||||
export const defaultAvatarSrc = function ({ email, md5 }: { md5?: string; email?: string }) {
|
||||
if (!email && !md5) return "";
|
||||
|
||||
if (email && !md5) {
|
||||
md5 = md5Parser(email);
|
||||
}
|
||||
|
||||
return `https://www.gravatar.com/avatar/${md5}?s=160&d=mp&r=PG`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an avatar URL and a name, return the appropriate avatar URL. In the
|
||||
* event that no avatar URL is provided, return a placeholder avatar URL from
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|||
import Link from "next/link";
|
||||
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { defaultAvatarSrc } from "@calcom/lib/defaultAvatarImage";
|
||||
import { AVATAR_FALLBACK } from "@calcom/lib/constants";
|
||||
|
||||
import type { Maybe } from "@trpc/server";
|
||||
|
||||
|
@ -17,7 +17,6 @@ export type AvatarProps = {
|
|||
title?: string;
|
||||
alt: string;
|
||||
href?: string;
|
||||
gravatarFallbackMd5?: string;
|
||||
fallback?: React.ReactNode;
|
||||
accepted?: boolean;
|
||||
asChild?: boolean; // Added to ignore the outer span on the fallback component - messes up styling
|
||||
|
@ -35,7 +34,7 @@ const sizesPropsBySize = {
|
|||
} as const;
|
||||
|
||||
export function Avatar(props: AvatarProps) {
|
||||
const { imageSrc, gravatarFallbackMd5, size = "md", alt, title, href } = props;
|
||||
const { imageSrc, size = "md", alt, title, href } = props;
|
||||
const rootClass = classNames("aspect-square rounded-full", sizesPropsBySize[size]);
|
||||
let avatar = (
|
||||
<AvatarPrimitive.Root
|
||||
|
@ -55,15 +54,7 @@ export function Avatar(props: AvatarProps) {
|
|||
asChild={props.asChild}
|
||||
className="flex h-full items-center justify-center">
|
||||
<>
|
||||
{props.fallback ? (
|
||||
props.fallback
|
||||
) : (
|
||||
<img
|
||||
src={defaultAvatarSrc({ md5: gravatarFallbackMd5 ?? "fallback" })}
|
||||
alt={alt}
|
||||
className={rootClass}
|
||||
/>
|
||||
)}
|
||||
{props.fallback ? props.fallback : <img src={AVATAR_FALLBACK} alt={alt} className={rootClass} />}
|
||||
</>
|
||||
</AvatarPrimitive.Fallback>
|
||||
{props.accepted && (
|
||||
|
|
|
@ -29,10 +29,10 @@ Avatar group can be composed differently based on the number of user profile.
|
|||
|
||||
<Examples title="Avatar style">
|
||||
<Example title="Small">
|
||||
<Avatar size="sm" alt="Avatar Story" gravatarFallbackMd5="Ui@CAL.com" />
|
||||
<Avatar size="sm" alt="Avatar Story" />
|
||||
</Example>
|
||||
<Example title="Large">
|
||||
<Avatar size="lg" alt="Avatar Story" gravatarFallbackMd5="Ui@CAL.com" />
|
||||
<Avatar size="lg" alt="Avatar Story" />
|
||||
</Example>
|
||||
</Examples>
|
||||
|
||||
|
@ -146,7 +146,6 @@ Avatar group can be composed differently based on the number of user profile.
|
|||
args={{
|
||||
size: "sm",
|
||||
alt: "Avatar Story",
|
||||
gravatarFallbackMd5: "Ui@CAL.com",
|
||||
}}
|
||||
argTypes={{
|
||||
size: {
|
||||
|
@ -156,12 +155,11 @@ Avatar group can be composed differently based on the number of user profile.
|
|||
},
|
||||
},
|
||||
alt: { control: "text" },
|
||||
gravatarFallbackMd5: { control: "text" },
|
||||
}}>
|
||||
{({ size, alt, gravatarFallbackMd5 }) => (
|
||||
{({ size, alt }) => (
|
||||
<VariantsTable titles={["Default"]} columnMinWidth={150}>
|
||||
<VariantRow variant={size}>
|
||||
<Avatar size={size} alt={alt} gravatarFallbackMd5={gravatarFallbackMd5} />
|
||||
<Avatar size={size} alt={alt} />
|
||||
</VariantRow>
|
||||
</VariantsTable>
|
||||
)}
|
||||
|
|
Loading…
Reference in New Issue