Reset Password (#1)
Implements reset password routes, views, and tests. Reviewed-on: #1
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user