<commit_before>import Authentication
import FluentProvider
import Forms
import JWT
import JWTProvider
import SMTP

/// A lightweight User implementation to get started with JWTKeychain.
public final class User: Model, SoftDeletable, Timestampable {

    public struct Keys {
        public static let email = "email"
        public static let name = "name"
        static let hashedPassword = "<PASSWORD>"

        static let password = "password"
        static let passwordRepeat = "<PASSWORD>"
        static let oldPassword = "<PASSWORD>"
    }

    public var email: String
    public var name: String
    public var hashedPassword: String?

    public let storage = Storage()

    public init(
        email: String,
        name: String,
        hashedPassword: String?
    ) {
        self.email = email
        self.name = name
        self.hashedPassword = <PASSWORD>
    }
}

// MARK: EmailAddressRepresentable

extension User: EmailAddressRepresentable {
    public var emailAddress: EmailAddress {
        return EmailAddress(name: name, address: email)
    }
}

// MARK: JSONRepresentable

extension User: JSONRepresentable {
    public func makeJSON() throws -> JSON {
        var json = JSON()

        try json.set(User.idKey, id)
        try json.set(Keys.email, email)
        try json.set(Keys.name, name)

        return json
    }
}

// MARK: JWTKeychainAuthenticatable

extension User: JWTKeychainAuthenticatable {
    public static func make(request: Request) throws -> User {
        let form: UserForm = try request.createForm()

        try form.validate(inValidationMode: .all)

        // force unwrapping is ok because form was validated
        let email = form.email!
        let name = form.name!
        let password = form.password!

        guard try makeQuery()
            .filter(Keys.email.string, email)
            .count() == 0
            else {
                throw JWTKeychainUserError.userWithGivenEmailAlreadyExists
        }

        return User(
            email: email,
            name: name,
            hashedPassword: try hash(password: password)
        )
    }
}

// MARK: NodeRepresentable

extension User: NodeRepresentable {}

// MARK: PasswordAuthenticatable

extension User: PasswordAuthenticatable {
    public static var passwordVerifier: PasswordVerifier? {
        return bCryptHasher
    }
}

// MARK: PasswordResettable

extension User: PasswordResettable {
    public static func extractPasswordResetInfo(
        from request: Request
    ) throws -> PasswordResetInfoType {
        return try request.createForm() as PasswordResetForm
    }
}

// MARK: PasswordUpdateable

extension User: PasswordUpdateable {
    public func updatePassword(to newPassword: String) throws {<commit_msg>Add simple makeNode impl<commit_after>import Authentication
import FluentProvider
import Forms
import JWT
import JWTProvider
import SMTP

/// A lightweight User implementation to get started with JWTKeychain.
public final class User: Model, SoftDeletable, Timestampable {

    public struct Keys {
        public static let email = "email"
        public static let name = "name"
        static let hashedPassword = "<PASSWORD>"

        static let password = "password"
        static let passwordRepeat = "<PASSWORD>"
        static let oldPassword = "<PASSWORD>"
    }

    public var email: String
    public var name: String
    public var hashedPassword: String?

    public let storage = Storage()

    public init(
        email: String,
        name: String,
        hashedPassword: String?
    ) {
        self.email = email
        self.name = name
        self.hashedPassword = <PASSWORD>
    }
}

// MARK: EmailAddressRepresentable

extension User: EmailAddressRepresentable {
    public var emailAddress: EmailAddress {
        return EmailAddress(name: name, address: email)
    }
}

// MARK: JSONRepresentable

extension User: JSONRepresentable {
    public func makeJSON() throws -> JSON {
        var json = JSON()

        try json.set(User.idKey, id)
        try json.set(Keys.email, email)
        try json.set(Keys.name, name)

        return json
    }
}

// MARK: JWTKeychainAuthenticatable

extension User: JWTKeychainAuthenticatable {
    public static func make(request: Request) throws -> User {
        let form: UserForm = try request.createForm()

        try form.validate(inValidationMode: .all)

        // force unwrapping is ok because form was validated
        let email = form.email!
        let name = form.name!
        let password = form.password!

        guard try makeQuery()
            .filter(Keys.email.string, email)
            .count() == 0
            else {
                throw JWTKeychainUserError.userWithGivenEmailAlreadyExists
        }

        return User(
            email: email,
            name: name,
            hashedPassword: try hash(password: password)
        )
    }
}

// MARK: NodeRepresentable

extension User: NodeRepresentable {
    public func makeNode(in context: Context?) throws -> Node {
        var node = Node([:])

        try node.set(User.idKey, id)
        try node.set(Keys.email, email)
        try node.set(Keys.name, name)

        return node
    }
}

// MARK: PasswordAuthenticatable

extension User: PasswordAuthenticatable {
    public static var passwordVerifier: PasswordVerifier? {
        return bCryptHasher
    }
}

// MARK: PasswordResettable

extension User: PasswordResettable {
    public static func extractPasswordResetInfo(
        from request: Request
    ) throws -> PasswordResetInfoType {
        return try request.createForm() as PasswordResetForm
    }
}

// MARK: PasswordUpdateable

extension User: PasswordUpdateable {
    public func updatePassword(to newPassword: String) throws {
{'fraction_non_alphanumeric': 0.07720333102012492, 'fraction_numerical': 0.00034698126301179735, 'mean_word_length': 2.5003035822707953, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1447496', 'n_tokens_mistral': 1591, 'n_tokens_neox': 1504, 'n_words': 482}