Skip to content

Commit 5faa671

Browse files
committed
rm getProfile from protocol, use ProfileDetails
1 parent d4fd759 commit 5faa671

File tree

4 files changed

+74
-81
lines changed

4 files changed

+74
-81
lines changed

components/dashboard/src/user-settings/Account.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,20 @@ import isEmail from "validator/lib/isEmail";
1717
import { useToast } from "../components/toasts/Toasts";
1818
import { InputWithCopy } from "../components/InputWithCopy";
1919
import { InputField } from "../components/forms/InputField";
20-
import { getPrimaryEmail, getProfile, isOrganizationOwned } from "@gitpod/public-api-common/lib/user-utils";
20+
import { getPrimaryEmail, isOrganizationOwned } from "@gitpod/public-api-common/lib/user-utils";
2121
import { User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
22-
import { User as UserProtocol } from "@gitpod/gitpod-protocol";
22+
import { User as UserProtocol, ProfileDetails } from "@gitpod/gitpod-protocol";
2323
import { useUpdateCurrentUserMutation } from "../data/current-user/update-mutation";
2424

25+
type UserProfile = Pick<ProfileDetails, "emailAddress"> & Required<Pick<UserProtocol, "name" | "avatarUrl">>;
26+
function getProfile(user: User): UserProfile {
27+
return {
28+
name: user.name,
29+
avatarUrl: user.avatarUrl,
30+
emailAddress: getPrimaryEmail(user),
31+
};
32+
}
33+
2534
export default function Account() {
2635
const { user, setUser } = useContext(UserContext);
2736
const [modal, setModal] = useState(false);
@@ -43,17 +52,17 @@ export default function Account() {
4352
return;
4453
}
4554
if (canUpdateEmail) {
46-
if (profileState.email.trim() === "") {
55+
if (!profileState.emailAddress?.trim()) {
4756
setErrorMessage("Email must not be empty.");
4857
return;
4958
}
5059
// check valid email
51-
if (!isEmail(profileState.email.trim())) {
60+
if (!isEmail(profileState.emailAddress?.trim() || "")) {
5261
setErrorMessage("Please enter a valid email.");
5362
return;
5463
}
5564
} else {
56-
profileState.email = getPrimaryEmail(user) || "";
65+
profileState.emailAddress = getPrimaryEmail(user) || "";
5766
}
5867

5968
const updatedUser = await updateUser.mutateAsync({
@@ -78,7 +87,7 @@ export default function Account() {
7887
title="Delete Account"
7988
areYouSureText="You are about to permanently delete your account."
8089
buttonText="Delete Account"
81-
buttonDisabled={typedEmail !== original.email}
90+
buttonDisabled={typedEmail !== (original.emailAddress || "")}
8291
visible={modal}
8392
onClose={close}
8493
onConfirm={deleteAccount}
@@ -133,8 +142,8 @@ export default function Account() {
133142
}
134143

135144
function ProfileInformation(props: {
136-
profileState: UserProtocol.Profile;
137-
setProfileState: (newState: UserProtocol.Profile) => void;
145+
profileState: UserProfile;
146+
setProfileState: (newState: UserProfile) => void;
138147
errorMessage: string;
139148
emailIsReadonly?: boolean;
140149
user?: User;
@@ -161,10 +170,10 @@ function ProfileInformation(props: {
161170
/>
162171
<TextInputField
163172
label="Email"
164-
value={props.profileState.email}
173+
value={props.profileState.emailAddress || ""}
165174
disabled={props.emailIsReadonly}
166175
onChange={(val) => {
167-
props.setProfileState({ ...props.profileState, email: val });
176+
props.setProfileState({ ...props.profileState, emailAddress: val });
168177
}}
169178
/>
170179
{props.user && (
@@ -178,7 +187,7 @@ function ProfileInformation(props: {
178187
<Subheading>Avatar</Subheading>
179188
<img
180189
className="rounded-full w-24 h-24"
181-
src={props.profileState.avatarURL}
190+
src={props.profileState.avatarUrl}
182191
alt={props.profileState.name}
183192
/>
184193
</div>

components/gitpod-protocol/src/protocol.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -104,39 +104,6 @@ export namespace User {
104104
}
105105
user.additionalData.ideSettings = newIDESettings;
106106
}
107-
108-
// TODO: refactor where this is referenced so it's more clearly tied to just analytics-tracking
109-
// Let other places rely on the ProfileDetails type since that's what we store
110-
// This is the profile data we send to our Segment analytics tracking pipeline
111-
export interface Profile {
112-
name: string;
113-
email: string;
114-
company?: string;
115-
avatarURL?: string;
116-
jobRole?: string;
117-
jobRoleOther?: string;
118-
explorationReasons?: string[];
119-
signupGoals?: string[];
120-
signupGoalsOther?: string;
121-
onboardedTimestamp?: string;
122-
companySize?: string;
123-
}
124-
export namespace Profile {
125-
export function hasChanges(before: Profile, after: Profile) {
126-
return (
127-
before.name !== after.name ||
128-
before.email !== after.email ||
129-
before.company !== after.company ||
130-
before.avatarURL !== after.avatarURL ||
131-
before.jobRole !== after.jobRole ||
132-
before.jobRoleOther !== after.jobRoleOther ||
133-
// not checking explorationReasons or signupGoals atm as it's an array - need to check deep equality
134-
before.signupGoalsOther !== after.signupGoalsOther ||
135-
before.onboardedTimestamp !== after.onboardedTimestamp ||
136-
before.companySize !== after.companySize
137-
);
138-
}
139-
}
140107
}
141108

142109
export interface WorkspaceTimeoutSetting {

components/public-api/typescript-common/src/user-utils.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,3 @@ export function getName(user: User | UserProtocol): string | undefined {
7272
export function isOrganizationOwned(user: User | UserProtocol) {
7373
return !!user.organizationId;
7474
}
75-
76-
// FIXME(at) get rid of this Nth indirection to read attributes of User entity
77-
export function getProfile(user: User | UserProtocol): UserProtocol.Profile {
78-
const profile = UserProtocol.is(user) ? user.additionalData?.profile : user.profile;
79-
return {
80-
name: getName(user) || "",
81-
email: getPrimaryEmail(user) || "",
82-
company: profile?.companyName,
83-
avatarURL: user?.avatarUrl,
84-
jobRole: profile?.jobRole,
85-
jobRoleOther: profile?.jobRoleOther,
86-
explorationReasons: profile?.explorationReasons,
87-
signupGoals: profile?.signupGoals,
88-
signupGoalsOther: profile?.signupGoalsOther,
89-
companySize: profile?.companySize,
90-
onboardedTimestamp: profile?.onboardedTimestamp,
91-
};
92-
}

components/server/src/user/user-service.ts

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { CreateUserParams } from "./user-authentication";
2424
import { IAnalyticsWriter } from "@gitpod/gitpod-protocol/lib/analytics";
2525
import { TransactionalContext } from "@gitpod/gitpod-db/lib/typeorm/transactional-db-impl";
2626
import { RelationshipUpdater } from "../authorization/relationship-updater";
27-
import { getProfile } from "@gitpod/public-api-common/lib/user-utils";
27+
import { getName, getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";
2828

2929
@injectable()
3030
export class UserService {
@@ -106,7 +106,7 @@ export class UserService {
106106
await this.authorizer.checkPermissionOnUser(userId, "write_info", user.id);
107107

108108
//hang on to user profile before it's overwritten for analytics below
109-
const oldProfile = getProfile(user);
109+
const oldProfile = Profile.getProfile(user);
110110

111111
const allowedFields: (keyof User)[] = ["fullName", "additionalData"];
112112
for (const p of allowedFields) {
@@ -118,8 +118,8 @@ export class UserService {
118118
await this.userDb.updateUserPartial(user);
119119

120120
//track event and user profile if profile of partialUser changed
121-
const newProfile = getProfile(user);
122-
if (this.hasChanges(oldProfile, newProfile)) {
121+
const newProfile = Profile.getProfile(user);
122+
if (Profile.hasChanges(oldProfile, newProfile)) {
123123
this.analytics.track({
124124
userId: user.id,
125125
event: "profile_changed",
@@ -133,21 +133,6 @@ export class UserService {
133133
return user;
134134
}
135135

136-
private hasChanges(before: User.Profile, after: User.Profile) {
137-
return (
138-
before.name !== after.name ||
139-
before.email !== after.email ||
140-
before.company !== after.company ||
141-
before.avatarURL !== after.avatarURL ||
142-
before.jobRole !== after.jobRole ||
143-
before.jobRoleOther !== after.jobRoleOther ||
144-
// not checking explorationReasons or signupGoals atm as it's an array - need to check deep equality
145-
before.signupGoalsOther !== after.signupGoalsOther ||
146-
before.onboardedTimestamp !== after.onboardedTimestamp ||
147-
before.companySize !== after.companySize
148-
);
149-
}
150-
151136
async updateWorkspaceTimeoutSetting(
152137
userId: string,
153138
targetUserId: string,
@@ -328,3 +313,53 @@ export class UserService {
328313
log.info("User verified", { userId: user.id });
329314
}
330315
}
316+
317+
// TODO: refactor where this is referenced so it's more clearly tied to just analytics-tracking
318+
// Let other places rely on the ProfileDetails type since that's what we store
319+
// This is the profile data we send to our Segment analytics tracking pipeline
320+
interface Profile {
321+
name: string;
322+
email: string;
323+
company?: string;
324+
avatarURL?: string;
325+
jobRole?: string;
326+
jobRoleOther?: string;
327+
explorationReasons?: string[];
328+
signupGoals?: string[];
329+
signupGoalsOther?: string;
330+
onboardedTimestamp?: string;
331+
companySize?: string;
332+
}
333+
namespace Profile {
334+
export function hasChanges(before: Profile, after: Profile) {
335+
return (
336+
before.name !== after.name ||
337+
before.email !== after.email ||
338+
before.company !== after.company ||
339+
before.avatarURL !== after.avatarURL ||
340+
before.jobRole !== after.jobRole ||
341+
before.jobRoleOther !== after.jobRoleOther ||
342+
// not checking explorationReasons or signupGoals atm as it's an array - need to check deep equality
343+
before.signupGoalsOther !== after.signupGoalsOther ||
344+
before.onboardedTimestamp !== after.onboardedTimestamp ||
345+
before.companySize !== after.companySize
346+
);
347+
}
348+
349+
export function getProfile(user: User): Profile {
350+
const profile = user.additionalData?.profile;
351+
return {
352+
name: getName(user) || "",
353+
email: getPrimaryEmail(user) || "",
354+
company: profile?.companyName,
355+
avatarURL: user?.avatarUrl,
356+
jobRole: profile?.jobRole,
357+
jobRoleOther: profile?.jobRoleOther,
358+
explorationReasons: profile?.explorationReasons,
359+
signupGoals: profile?.signupGoals,
360+
signupGoalsOther: profile?.signupGoalsOther,
361+
companySize: profile?.companySize,
362+
onboardedTimestamp: profile?.onboardedTimestamp,
363+
};
364+
}
365+
}

0 commit comments

Comments
 (0)