25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

83 lines
2.3 KiB

  1. //
  2. // File.swift
  3. //
  4. //
  5. // Created by Michiel Carman on 9/26/24.
  6. //
  7. import Vapor
  8. import Fluent
  9. struct UserSignup: Content {
  10. let username: String
  11. let password: String
  12. }
  13. struct NewSession: Content {
  14. let token: String
  15. let user: User.Public
  16. }
  17. extension UserSignup: Validatable {
  18. static func validations(_ validations: inout Validations) {
  19. validations.add("username", as: String.self, is: !.empty)
  20. validations.add("password", as: String.self, is: .count(6...))
  21. }
  22. }
  23. struct UserController: RouteCollection {
  24. func boot(routes: RoutesBuilder) throws {
  25. let usersRoute = routes.grouped("users")
  26. usersRoute.post("signup", use: create)
  27. let tokenProtected = usersRoute.grouped(Token.authenticator())
  28. tokenProtected.get("me", use: getMyOwnUser)
  29. let passwordProtected = usersRoute.grouped(User.authenticator())
  30. passwordProtected.post("login", use: login)
  31. }
  32. fileprivate func create(req: Request) throws -> EventLoopFuture<NewSession> {
  33. try UserSignup.validate(content: req)
  34. let userSignup = try req.content.decode(UserSignup.self)
  35. let user = try User.create(from: userSignup)
  36. var token: Token!
  37. return checkIfUserExists(userSignup.username, req: req).flatMap { exists in
  38. guard !exists else {
  39. return req.eventLoop.future(error: UserError.usernameTaken)
  40. }
  41. return user.save(on: req.db)
  42. }.flatMap {
  43. guard let newToken = try? user.createToken(source: .signup) else {
  44. return req.eventLoop.future(error: Abort(.internalServerError))
  45. }
  46. token = newToken
  47. return token.save(on: req.db)
  48. }.flatMapThrowing {
  49. NewSession(token: token.value, user: try user.asPublic())
  50. }
  51. }
  52. fileprivate func login(req: Request) throws -> EventLoopFuture<NewSession> {
  53. let user = try req.auth.require(User.self)
  54. let token = try user.createToken(source: .login)
  55. return token.save(on: req.db).flatMapThrowing {
  56. NewSession(token: token.value, user: try user.asPublic())
  57. }
  58. }
  59. func getMyOwnUser(req: Request) throws -> User.Public {
  60. try req.auth.require(User.self).asPublic()
  61. }
  62. private func checkIfUserExists(_ username: String, req: Request) -> EventLoopFuture<Bool> {
  63. User.query(on: req.db)
  64. .filter(\.$username == username)
  65. .first()
  66. .map { $0 != nil }
  67. }
  68. }