Skip to content

Commit f70726b

Browse files
refactor: Extract security logic from auth service (#5635)
1 parent fe16b2a commit f70726b

File tree

6 files changed

+97
-71
lines changed

6 files changed

+97
-71
lines changed

site/src/i18n/en/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import appearanceSettings from "./appearanceSettings.json"
1717
import starterTemplatesPage from "./starterTemplatesPage.json"
1818
import starterTemplatePage from "./starterTemplatePage.json"
1919
import createTemplatePage from "./createTemplatePage.json"
20+
import userSettingsPage from "./userSettingsPage.json"
2021

2122
export const en = {
2223
common,
@@ -38,4 +39,5 @@ export const en = {
3839
starterTemplatesPage,
3940
starterTemplatePage,
4041
createTemplatePage,
42+
userSettingsPage,
4143
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"securityUpdateSuccessMessage": "Updated password."
3+
}

site/src/pages/UserSettingsPage/SecurityPage/SecurityPage.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import * as API from "../../../api/api"
33
import { GlobalSnackbar } from "../../../components/GlobalSnackbar/GlobalSnackbar"
44
import * as SecurityForm from "../../../components/SettingsSecurityForm/SettingsSecurityForm"
55
import { renderWithAuth } from "../../../testHelpers/renderHelpers"
6-
import * as AuthXService from "../../../xServices/auth/authXService"
76
import { SecurityPage } from "./SecurityPage"
87
import i18next from "i18next"
98

@@ -47,9 +46,10 @@ describe("SecurityPage", () => {
4746
const { user } = renderPage()
4847
await fillAndSubmitForm()
4948

50-
const successMessage = await screen.findByText(
51-
AuthXService.Language.successSecurityUpdate,
52-
)
49+
const expectedMessage = t("securityUpdateSuccessMessage", {
50+
ns: "userSettingsPage",
51+
})
52+
const successMessage = await screen.findByText(expectedMessage)
5353
expect(successMessage).toBeDefined()
5454
expect(API.updateUserPassword).toBeCalledTimes(1)
5555
expect(API.updateUserPassword).toBeCalledWith(user.id, newData)

site/src/pages/UserSettingsPage/SecurityPage/SecurityPage.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
1-
import { useActor } from "@xstate/react"
2-
import React, { useContext } from "react"
1+
import { useMachine } from "@xstate/react"
2+
import { useMe } from "hooks/useMe"
3+
import React from "react"
4+
import { userSecuritySettingsMachine } from "xServices/userSecuritySettings/userSecuritySettingsXService"
35
import { Section } from "../../../components/Section/Section"
46
import { SecurityForm } from "../../../components/SettingsSecurityForm/SettingsSecurityForm"
5-
import { XServiceContext } from "../../../xServices/StateContext"
67

78
export const Language = {
89
title: "Security",
910
}
1011

1112
export const SecurityPage: React.FC = () => {
12-
const xServices = useContext(XServiceContext)
13-
const [authState, authSend] = useActor(xServices.authXService)
14-
const { me, updateSecurityError } = authState.context
15-
16-
if (!me) {
17-
throw new Error("No current user found")
18-
}
13+
const me = useMe()
14+
const [securityState, securitySend] = useMachine(
15+
userSecuritySettingsMachine,
16+
{
17+
context: {
18+
userId: me.id,
19+
},
20+
},
21+
)
22+
const { error } = securityState.context
1923

2024
return (
2125
<Section title={Language.title}>
2226
<SecurityForm
23-
updateSecurityError={updateSecurityError}
24-
isLoading={authState.matches("signedIn.security.updatingSecurity")}
27+
updateSecurityError={error}
28+
isLoading={securityState.matches("updatingSecurity")}
2529
initialValues={{ old_password: "", password: "", confirm_password: "" }}
2630
onSubmit={(data) => {
27-
authSend({
31+
securitySend({
2832
type: "UPDATE_SECURITY",
2933
data,
3034
})

site/src/xServices/auth/authXService.ts

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { displaySuccess } from "../../components/GlobalSnackbar/utils"
55

66
export const Language = {
77
successProfileUpdate: "Updated settings.",
8-
successSecurityUpdate: "Updated password.",
98
successRegenerateSSHKey: "SSH Key regenerated successfully",
109
}
1110

@@ -80,7 +79,6 @@ export interface AuthContext {
8079
getMethodsError?: Error | unknown
8180
authError?: Error | unknown
8281
updateProfileError?: Error | unknown
83-
updateSecurityError?: Error | unknown
8482
me?: TypesGen.User
8583
methods?: TypesGen.AuthMethods
8684
permissions?: Permissions
@@ -95,7 +93,6 @@ export type AuthEvent =
9593
| { type: "SIGN_OUT" }
9694
| { type: "SIGN_IN"; email: string; password: string }
9795
| { type: "UPDATE_PROFILE"; data: TypesGen.UpdateUserProfileRequest }
98-
| { type: "UPDATE_SECURITY"; data: TypesGen.UpdateUserPasswordRequest }
9996
| { type: "GET_SSH_KEY" }
10097
| { type: "REGENERATE_SSH_KEY" }
10198
| { type: "CONFIRM_REGENERATE_SSH_KEY" }
@@ -385,41 +382,6 @@ export const authMachine =
385382
},
386383
},
387384
},
388-
security: {
389-
initial: "idle",
390-
states: {
391-
idle: {
392-
initial: "noError",
393-
states: {
394-
noError: {},
395-
error: {},
396-
},
397-
on: {
398-
UPDATE_SECURITY: {
399-
target: "updatingSecurity",
400-
},
401-
},
402-
},
403-
updatingSecurity: {
404-
entry: "clearUpdateSecurityError",
405-
invoke: {
406-
src: "updateSecurity",
407-
onDone: [
408-
{
409-
actions: "notifySuccessSecurityUpdate",
410-
target: "#authState.signedIn.security.idle.noError",
411-
},
412-
],
413-
onError: [
414-
{
415-
actions: "assignUpdateSecurityError",
416-
target: "#authState.signedIn.security.idle.error",
417-
},
418-
],
419-
},
420-
},
421-
},
422-
},
423385
},
424386
on: {
425387
SIGN_OUT: {
@@ -513,13 +475,6 @@ export const authMachine =
513475

514476
return API.updateProfile(context.me.id, event.data)
515477
},
516-
updateSecurity: async (context, event) => {
517-
if (!context.me) {
518-
throw new Error("No current user found")
519-
}
520-
521-
return API.updateUserPassword(context.me.id, event.data)
522-
},
523478
checkPermissions: async () => {
524479
return API.checkAuthorization({
525480
checks: permissionsToCheck,
@@ -572,15 +527,6 @@ export const authMachine =
572527
clearUpdateProfileError: assign({
573528
updateProfileError: (_) => undefined,
574529
}),
575-
clearUpdateSecurityError: assign({
576-
updateSecurityError: (_) => undefined,
577-
}),
578-
notifySuccessSecurityUpdate: () => {
579-
displaySuccess(Language.successSecurityUpdate)
580-
},
581-
assignUpdateSecurityError: assign({
582-
updateSecurityError: (_, event) => event.data,
583-
}),
584530
assignPermissions: assign({
585531
// Setting event.data as Permissions to be more stricted. So we know
586532
// what permissions we asked for.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { assign, createMachine } from "xstate"
2+
import * as API from "api/api"
3+
import { UpdateUserPasswordRequest } from "api/typesGenerated"
4+
import { displaySuccess } from "components/GlobalSnackbar/utils"
5+
import { t } from "i18next"
6+
7+
interface Context {
8+
userId: string
9+
error?: unknown
10+
}
11+
12+
type Events = { type: "UPDATE_SECURITY"; data: UpdateUserPasswordRequest }
13+
14+
export const userSecuritySettingsMachine = createMachine(
15+
{
16+
id: "userSecuritySettings",
17+
predictableActionArguments: true,
18+
schema: {
19+
context: {} as Context,
20+
events: {} as Events,
21+
},
22+
tsTypes: {} as import("./userSecuritySettingsXService.typegen").Typegen0,
23+
initial: "idle",
24+
states: {
25+
idle: {
26+
on: {
27+
UPDATE_SECURITY: {
28+
target: "updatingSecurity",
29+
},
30+
},
31+
},
32+
updatingSecurity: {
33+
entry: "clearError",
34+
invoke: {
35+
src: "updateSecurity",
36+
onDone: [
37+
{
38+
actions: "notifyUpdate",
39+
target: "idle",
40+
},
41+
],
42+
onError: [
43+
{
44+
actions: "assignError",
45+
target: "idle",
46+
},
47+
],
48+
},
49+
},
50+
},
51+
},
52+
{
53+
services: {
54+
updateSecurity: async ({ userId }, { data }) =>
55+
API.updateUserPassword(userId, data),
56+
},
57+
actions: {
58+
clearError: assign({
59+
error: (_) => undefined,
60+
}),
61+
notifyUpdate: () => {
62+
displaySuccess(
63+
t("securityUpdateSuccessMessage", { ns: "userSettingsPage" }),
64+
)
65+
},
66+
assignError: assign({
67+
error: (_, event) => event.data,
68+
}),
69+
},
70+
},
71+
)

0 commit comments

Comments
 (0)