Reset Password (#1)

Implements reset password routes, views, and tests.

Reviewed-on: #1
This commit is contained in:
2025-01-27 14:07:37 +00:00
parent 1f2bb900ca
commit 9478fae371
16 changed files with 250 additions and 7 deletions

View File

@@ -65,6 +65,27 @@ struct UserApiRouteTests {
#expect(route == .user(.index))
}
@Test
func resetPassword() throws {
let id = UUID(0)
let json = """
{
\"password\": \"super-secret\",
\"confirmPassword\": \"super-secret\"
}
"""
var request = URLRequestData(
method: "PATCH",
path: "/api/v1/users/\(id)/reset-password",
body: .init(json.utf8)
)
let route = try router.parse(&request)
#expect(route == .user(.resetPassword(
id: id,
request: .init(password: "super-secret", confirmPassword: "super-secret")
)))
}
@Test
func update() throws {
let id = UUID(0)

View File

@@ -101,6 +101,25 @@ struct ViewControllerTests {
}
}
@Test
func resetPasswordViews() async throws {
try await withSnapshotTesting(record: record) {
try await withDependencies {
$0.dateFormatter = .mock
$0.database.users = .mock
$0.viewController = .liveValue
} operation: {
@Dependency(\.viewController) var viewController
var htmlString = try await viewController.render(.resetPassword(.index(id: UUID(0))))
assertSnapshot(of: htmlString, as: .html)
htmlString = try await viewController.render(.resetPassword(.submit(id: UUID(0), request: .mock)))
assertSnapshot(of: htmlString, as: .html)
}
}
}
@Test
func userViews() async throws {
try await withSnapshotTesting(record: record) {
@@ -240,6 +259,7 @@ extension DatabaseClient.Users {
get: { _ in User.mock },
login: { _ in User.Token.mock },
logout: { _ in },
resetPassword: { _, _ in },
token: { _ in User.Token.mock },
update: { _, _ in User.mock }
)
@@ -407,3 +427,9 @@ extension PurchaseOrder.Create {
)
}
}
extension User.ResetPassword {
static var mock: Self {
.init(password: "super-secret", confirmPassword: "super-secret")
}
}

View File

@@ -0,0 +1,16 @@
<div id="float" class="float" style="display: block;">
<div class="btn-row">
<button class="btn-close" onclick="toggleContent('float');">x</button>
</div>
<form id="user-form" class="user-form" hx-patch="/reset-password/00000000-0000-0000-0000-000000000000" hx-push-url="false" hx-target="#float" hx-swap="outerHTML" hx-on::after-request="if(event.detail.successful) this.reset();">
<div class="row">
<input type="password" id="password" name="password" placeholder="Password" required>
</div>
<div class="row">
<input type="password" id="confirmPassword" name="confirmPassword" placeholder="Confirm Password" required>
</div>
<div class="row">
<button type="submit" class="btn-primary">Reset</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,19 @@
<div id="float" class="float" style="display: block;">
<div class="btn-row">
<button class="btn-close" onclick="toggleContent('float'); window.location.href='/users';">x</button>
</div>
<form hx-post="/users/00000000-0000-0000-0000-000000000000" hx-swap="outerHTML" hx-target="#user-00000000-0000-0000-0000-000000000000" hx-on::after-request="toggleContent('float');">
<div class="row">
<label for="username" class="col-2"><span class="label">Username:</span></label>
<input class="col-4" type="text" id="username" name="username" value="test" required>
Email:<label for="email" class="col-2"><span class="label"></span></label>
<input class="col-4" type="email" id="email" name="email" value="test@example.com" required>
</div>
<div class="row"><span class="label col-2">Created:</span><span class="date col-4">01/31/2025</span><span class="label col-2">Updated:</span><span class="date col-4">01/31/2025</span></div>
<div class="btn-row user-buttons">
<button type="submit" class="btn-secondary">Update</button>
<button class="danger" hx-delete="/api/v1/users/00000000-0000-0000-0000-000000000000" hx-trigger="click" hx-swap="outerHTML" hx-target="#user-00000000-0000-0000-0000-000000000000" hx-confirm="Are you sure you want to delete this user?" hx-on::after-request="toggleContent('float'); window.location.href='/users';">Delete</button>
<button class="btn-primary" hx-target="#float" hx-get="/reset-password/00000000-0000-0000-0000-000000000000" hx-trigger="click">Reset Password</button>
</div>
</form>
</div>

View File

@@ -13,6 +13,7 @@
<div class="btn-row user-buttons">
<button type="submit" class="btn-secondary">Update</button>
<button class="danger" hx-delete="/api/v1/users/00000000-0000-0000-0000-000000000000" hx-trigger="click" hx-swap="outerHTML" hx-target="#user-00000000-0000-0000-0000-000000000000" hx-confirm="Are you sure you want to delete this user?" hx-on::after-request="toggleContent('float'); window.location.href='/users';">Delete</button>
<button class="btn-primary" hx-target="#float" hx-get="/reset-password/00000000-0000-0000-0000-000000000000" hx-trigger="click">Reset Password</button>
</div>
</form>
</div>