Skip to content

Commit b78b893

Browse files
authored
Only show the password change section if the user has a password (#4100)
2 parents 1db0843 + dbcb051 commit b78b893

File tree

8 files changed

+34
-5
lines changed

8 files changed

+34
-5
lines changed

crates/handlers/src/graphql/model/users.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,16 @@ impl User {
705705
)
706706
.await
707707
}
708+
709+
/// Check if the user has a password set.
710+
async fn has_password(&self, ctx: &Context<'_>) -> Result<bool, async_graphql::Error> {
711+
let state = ctx.state();
712+
let mut repo = state.repository().await?;
713+
714+
let password = repo.user_password().active(&self.0).await?;
715+
716+
Ok(password.is_some())
717+
}
708718
}
709719

710720
/// A session in an application, either a compatibility or an OAuth 2.0 one

frontend/schema.graphql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,10 @@ type User implements Node {
20592059
"""
20602060
last: Int
20612061
): AppSessionConnection!
2062+
"""
2063+
Check if the user has a password set.
2064+
"""
2065+
hasPassword: Boolean!
20622066
}
20632067

20642068
"""

frontend/src/gql/gql.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type Documents = {
4242
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": typeof types.UserEmailListDocument,
4343
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n }\n": typeof types.UserEmailList_SiteConfigFragmentDoc,
4444
"\n fragment BrowserSessionsOverview_user on User {\n id\n\n browserSessions(first: 0, state: ACTIVE) {\n totalCount\n }\n }\n": typeof types.BrowserSessionsOverview_UserFragmentDoc,
45-
"\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": typeof types.UserProfileDocument,
45+
"\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n hasPassword\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": typeof types.UserProfileDocument,
4646
"\n query BrowserSessionList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n $lastActive: DateFilter\n ) {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n\n user {\n id\n\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n lastActive: $lastActive\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n }\n": typeof types.BrowserSessionListDocument,
4747
"\n query SessionsOverview {\n viewer {\n __typename\n\n ... on User {\n id\n ...BrowserSessionsOverview_user\n }\n }\n }\n": typeof types.SessionsOverviewDocument,
4848
"\n query AppSessionsList(\n $before: String\n $after: String\n $first: Int\n $last: Int\n $lastActive: DateFilter\n ) {\n viewer {\n __typename\n\n ... on User {\n id\n appSessions(\n before: $before\n after: $after\n first: $first\n last: $last\n lastActive: $lastActive\n state: ACTIVE\n ) {\n edges {\n cursor\n node {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n }\n }\n }\n }\n }\n": typeof types.AppSessionsListDocument,
@@ -91,7 +91,7 @@ const documents: Documents = {
9191
"\n query UserEmailList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n viewer {\n __typename\n ... on User {\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n": types.UserEmailListDocument,
9292
"\n fragment UserEmailList_siteConfig on SiteConfig {\n emailChangeAllowed\n }\n": types.UserEmailList_SiteConfigFragmentDoc,
9393
"\n fragment BrowserSessionsOverview_user on User {\n id\n\n browserSessions(first: 0, state: ACTIVE) {\n totalCount\n }\n }\n": types.BrowserSessionsOverview_UserFragmentDoc,
94-
"\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": types.UserProfileDocument,
94+
"\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n hasPassword\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": types.UserProfileDocument,
9595
"\n query BrowserSessionList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n $lastActive: DateFilter\n ) {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n\n user {\n id\n\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n lastActive: $lastActive\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n }\n": types.BrowserSessionListDocument,
9696
"\n query SessionsOverview {\n viewer {\n __typename\n\n ... on User {\n id\n ...BrowserSessionsOverview_user\n }\n }\n }\n": types.SessionsOverviewDocument,
9797
"\n query AppSessionsList(\n $before: String\n $after: String\n $first: Int\n $last: Int\n $lastActive: DateFilter\n ) {\n viewer {\n __typename\n\n ... on User {\n id\n appSessions(\n before: $before\n after: $after\n first: $first\n last: $last\n lastActive: $lastActive\n state: ACTIVE\n ) {\n edges {\n cursor\n node {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n }\n }\n }\n }\n }\n": types.AppSessionsListDocument,
@@ -224,7 +224,7 @@ export function graphql(source: "\n fragment BrowserSessionsOverview_user on Us
224224
/**
225225
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
226226
*/
227-
export function graphql(source: "\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n"): typeof import('./graphql').UserProfileDocument;
227+
export function graphql(source: "\n query UserProfile {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n user {\n hasPassword\n emails(first: 0) {\n totalCount\n }\n }\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n"): typeof import('./graphql').UserProfileDocument;
228228
/**
229229
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
230230
*/

frontend/src/gql/graphql.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,8 @@ export type User = Node & {
13381338
createdAt: Scalars['DateTime']['output'];
13391339
/** Get the list of emails, chronologically sorted */
13401340
emails: UserEmailConnection;
1341+
/** Check if the user has a password set. */
1342+
hasPassword: Scalars['Boolean']['output'];
13411343
/** ID of the object. */
13421344
id: Scalars['ID']['output'];
13431345
/** When the user was locked out. */
@@ -1687,7 +1689,7 @@ export type BrowserSessionsOverview_UserFragment = { __typename?: 'User', id: st
16871689
export type UserProfileQueryVariables = Exact<{ [key: string]: never; }>;
16881690

16891691

1690-
export type UserProfileQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number } } } | { __typename: 'Oauth2Session' }, siteConfig: (
1692+
export type UserProfileQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', hasPassword: boolean, emails: { __typename?: 'UserEmailConnection', totalCount: number } } } | { __typename: 'Oauth2Session' }, siteConfig: (
16911693
{ __typename?: 'SiteConfig', emailChangeAllowed: boolean, passwordLoginEnabled: boolean }
16921694
& { ' $fragmentRefs'?: { 'UserEmailList_SiteConfigFragment': UserEmailList_SiteConfigFragment;'UserEmail_SiteConfigFragment': UserEmail_SiteConfigFragment;'PasswordChange_SiteConfigFragment': PasswordChange_SiteConfigFragment } }
16931695
) };
@@ -2302,6 +2304,7 @@ export const UserProfileDocument = new TypedDocumentString(`
23022304
... on BrowserSession {
23032305
id
23042306
user {
2307+
hasPassword
23052308
emails(first: 0) {
23062309
totalCount
23072310
}

frontend/src/routes/_account.index.lazy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function Index(): React.ReactElement {
9494
</>
9595
)}
9696

97-
{siteConfig.passwordLoginEnabled && (
97+
{siteConfig.passwordLoginEnabled && viewerSession.user.hasPassword && (
9898
<>
9999
<Collapsible.Section
100100
defaultOpen

frontend/src/routes/_account.index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const QUERY = graphql(/* GraphQL */ `
1818
... on BrowserSession {
1919
id
2020
user {
21+
hasPassword
2122
emails(first: 0) {
2223
totalCount
2324
}

frontend/stories/routes/index.stories.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ const userProfileHandler = ({
3434
passwordLoginEnabled,
3535
passwordChangeAllowed,
3636
emailTotalCount,
37+
hasPassword,
3738
}: {
3839
emailChangeAllowed: boolean;
3940
passwordLoginEnabled: boolean;
4041
passwordChangeAllowed: boolean;
4142
emailTotalCount: number;
43+
hasPassword: boolean;
4244
}): GraphQLHandler =>
4345
mockUserProfileQuery(() =>
4446
HttpResponse.json({
@@ -47,6 +49,7 @@ const userProfileHandler = ({
4749
__typename: "BrowserSession",
4850
id: "session-id",
4951
user: {
52+
hasPassword,
5053
emails: {
5154
totalCount: emailTotalCount,
5255
},
@@ -130,6 +133,7 @@ export const MultipleEmails: Story = {
130133
passwordChangeAllowed: true,
131134
emailChangeAllowed: true,
132135
emailTotalCount: 3,
136+
hasPassword: true,
133137
}),
134138
threeEmailsHandler,
135139
],
@@ -147,6 +151,7 @@ export const NoEmails: Story = {
147151
passwordChangeAllowed: true,
148152
emailChangeAllowed: false,
149153
emailTotalCount: 0,
154+
hasPassword: true,
150155
}),
151156
],
152157
},
@@ -163,6 +168,7 @@ export const MultipleEmailsNoChange: Story = {
163168
passwordChangeAllowed: true,
164169
emailChangeAllowed: false,
165170
emailTotalCount: 3,
171+
hasPassword: true,
166172
}),
167173
threeEmailsHandler,
168174
],
@@ -180,6 +186,7 @@ export const NoEmailChange: Story = {
180186
passwordChangeAllowed: true,
181187
emailChangeAllowed: false,
182188
emailTotalCount: 1,
189+
hasPassword: true,
183190
}),
184191
],
185192
},
@@ -196,6 +203,7 @@ export const NoPasswordChange: Story = {
196203
passwordChangeAllowed: false,
197204
emailChangeAllowed: true,
198205
emailTotalCount: 1,
206+
hasPassword: true,
199207
}),
200208
],
201209
},
@@ -212,6 +220,7 @@ export const NoPasswordLogin: Story = {
212220
passwordChangeAllowed: false,
213221
emailChangeAllowed: true,
214222
emailTotalCount: 1,
223+
hasPassword: true,
215224
}),
216225
],
217226
},
@@ -228,6 +237,7 @@ export const NoPasswordNoEmailChange: Story = {
228237
passwordChangeAllowed: false,
229238
emailChangeAllowed: false,
230239
emailTotalCount: 0,
240+
hasPassword: false,
231241
}),
232242
],
233243
},

frontend/tests/mocks/handlers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export const handlers = [
9191
__typename: "BrowserSession",
9292
id: "browser-session-id",
9393
user: {
94+
hasPassword: true,
9495
emails: {
9596
totalCount: 1,
9697
},

0 commit comments

Comments
 (0)