chore: removed gravatar (#11153)

pull/10873/head
Peer Richelsen 2023-09-05 19:56:02 +02:00 committed by GitHub
parent 7143923ea4
commit 3f0380617a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 22 additions and 165 deletions

View File

@ -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"

View File

@ -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'
`;
}

View File

@ -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`;
};

View File

@ -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();

View File

@ -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"

View File

@ -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

View File

@ -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",

View File

@ -80,7 +80,6 @@ function UserToInviteItem({
alt="Users avatar"
asChild
imageSrc={`${bookerUrl}/${member.user.username}/avatar.png`}
gravatarFallbackMd5="hash"
/>
<label
htmlFor={`${member.user.id}`}

View File

@ -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>

View File

@ -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"

View File

@ -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}`}
/>

View File

@ -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`;
}

View File

@ -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
/>

View File

@ -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>

View File

@ -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"}

View File

@ -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">

View File

@ -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}>

View File

@ -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"}

View File

@ -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";

View File

@ -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="
);
});
});
});

View File

@ -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

View File

@ -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 && (

View File

@ -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>
)}