-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6c6fc85
commit 09dd85f
Showing
11 changed files
with
3,853 additions
and
2 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
Sources/VernissageServer/Migrations/CreateDisposableEmails.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// | ||
// https://mczachurski.dev | ||
// Copyright © 2023 Marcin Czachurski and the repository contributors. | ||
// Licensed under the Apache License 2.0. | ||
// | ||
|
||
import Vapor | ||
import Fluent | ||
import SQLKit | ||
|
||
extension DisposableEmail { | ||
struct CreateDisposableEmails: AsyncMigration { | ||
func prepare(on database: Database) async throws { | ||
try await database | ||
.schema(DisposableEmail.schema) | ||
.field(.id, .int64, .identifier(auto: false)) | ||
.field("domain", .string, .required) | ||
.field("domainNormalized", .string, .required) | ||
.field("createdAt", .datetime) | ||
.field("updatedAt", .datetime) | ||
.unique(on: "domain") | ||
.create() | ||
|
||
if let sqlDatabase = database as? SQLDatabase { | ||
try await sqlDatabase | ||
.create(index: "domainNormalizedIndex") | ||
.on(DisposableEmail.schema) | ||
.column("domainNormalized") | ||
.run() | ||
} | ||
} | ||
|
||
func revert(on database: Database) async throws { | ||
try await database.schema(DisposableEmail.schema).delete() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// | ||
// https://mczachurski.dev | ||
// Copyright © 2023 Marcin Czachurski and the repository contributors. | ||
// Licensed under the Apache License 2.0. | ||
// | ||
|
||
import Fluent | ||
import Vapor | ||
import Frostflake | ||
|
||
/// Information about disposabled domains. That kind of domains cannot be used during registration process. | ||
final class DisposableEmail: Model { | ||
static let schema: String = "DisposableEmails" | ||
|
||
@ID(custom: .id, generatedBy: .user) | ||
var id: Int64? | ||
|
||
@Field(key: "domain") | ||
var domain: String | ||
|
||
@Field(key: "domainNormalized") | ||
var domainNormalized: String | ||
|
||
@Timestamp(key: "createdAt", on: .create) | ||
var createdAt: Date? | ||
|
||
@Timestamp(key: "updatedAt", on: .update) | ||
var updatedAt: Date? | ||
|
||
init() { | ||
self.id = .init(bitPattern: Frostflake.generate()) | ||
} | ||
|
||
convenience init(id: Int64? = nil, domain: String) { | ||
self.init() | ||
|
||
self.domain = domain | ||
self.domainNormalized = domain.uppercased() | ||
} | ||
} | ||
|
||
/// Allows `DisposableEmail` to be encoded to and decoded from HTTP messages. | ||
extension DisposableEmail: Content { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,4 +86,24 @@ final class ChangeEmailActionTests: CustomTestCase { | |
XCTAssertEqual(errorResponse.status, HTTPResponseStatus.badRequest, "Response http status code should be bad request (400).") | ||
XCTAssertEqual(errorResponse.error.code, "emailIsAlreadyConnected", "Error code should be equal 'emailIsAlreadyConnected'.") | ||
} | ||
|
||
func testEmailShouldNotBeChangedWhenIsDisposabledEmail() async throws { | ||
|
||
// Arrange. | ||
_ = try await DisposableEmail.create(domain: "10minutes.org") | ||
_ = try await User.create(userName: "kevinkrock") | ||
let changeEmailDto = ChangeEmailDto(email: "[email protected]", redirectBaseUrl: "http://localhost:8080/") | ||
|
||
// Act. | ||
let errorResponse = try SharedApplication.application().getErrorResponse( | ||
as: .user(userName: "kevinkrock", password: "p@ssword"), | ||
to: "/account/email", | ||
method: .PUT, | ||
data: changeEmailDto | ||
) | ||
|
||
// Assert. | ||
XCTAssertEqual(errorResponse.status, HTTPResponseStatus.badRequest, "Response http status code should be bad request (400).") | ||
XCTAssertEqual(errorResponse.error.code, "disposableEmailCannotBeUsed", "Error code should be equal 'disposableEmailCannotBeUsed'.") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -634,4 +634,29 @@ final class RegisterActionTests: CustomTestCase { | |
XCTAssertEqual(errorResponse.status, HTTPResponseStatus.forbidden, "Response http status code should be forbidden (403).") | ||
XCTAssertEqual(errorResponse.error.code, "invitationTokenHasBeenUsed", "Error code should be equal 'invitationTokenHasBeenUsed'.") | ||
} | ||
|
||
func testUserShouldNotBeCreatedWhenRegisteringWithDisposableEmail() async throws { | ||
|
||
// Arrange. | ||
_ = try await DisposableEmail.create(domain: "10minutes.net") | ||
|
||
let registerUserDto = RegisterUserDto(userName: "robingobis", | ||
email: "[email protected]", | ||
password: "p@ssword", | ||
redirectBaseUrl: "http://localhost:4200", | ||
agreement: true, | ||
name: "Robin Gobis", | ||
securityToken: "123") | ||
|
||
// Act. | ||
let errorResponse = try SharedApplication.application().getErrorResponse( | ||
to: "/register", | ||
method: .POST, | ||
data: registerUserDto | ||
) | ||
|
||
// Assert. | ||
XCTAssertEqual(errorResponse.status, HTTPResponseStatus.badRequest, "Response http status code should be bad request (400).") | ||
XCTAssertEqual(errorResponse.error.code, "disposableEmailCannotBeUsed", "Error code should be equal 'disposableEmailCannotBeUsed'.") | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
Tests/VernissageServerTests/Helpers/Extensions/DisposableEmail.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// https://mczachurski.dev | ||
// Copyright © 2023 Marcin Czachurski and the repository contributors. | ||
// Licensed under the Apache License 2.0. | ||
// | ||
|
||
@testable import VernissageServer | ||
import XCTVapor | ||
import Fluent | ||
|
||
extension VernissageServer.DisposableEmail { | ||
static func get(domain: String) async throws -> VernissageServer.DisposableEmail? { | ||
return try await VernissageServer.DisposableEmail.query(on: SharedApplication.application().db) | ||
.filter(\.$domainNormalized == domain.uppercased()) | ||
.first() | ||
} | ||
|
||
static func create(domain: String) async throws -> DisposableEmail { | ||
let disposableEmail = DisposableEmail(domain: domain) | ||
_ = try await disposableEmail.save(on: SharedApplication.application().db) | ||
return disposableEmail | ||
} | ||
} |