Yu-Gi-Oh! Deck Building and Card Inventory Management web interface written in Common Lisp, utilizing HTMX.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
4.1KB

  1. #|
  2. src/models/user.lisp
  3. # User Interaction Backend
  4. ## Create a superuser
  5. (create-superuser name email password)
  6. ## Create a normal user
  7. (bookshops.models::create-user "Joe Blogg" "JoeBlogg@example.com" "i<3books")
  8. ## Give him rights
  9. (add-role user :admin)
  10. Bootstrap roles: see database.lisp bootstrap-base-roles.
  11. # More Information
  12. - <https://github.com/fukamachi/can>
  13. |#
  14. (in-package #:cl-deck-builder2.models.user)
  15. (defclass user (has-secure-password)
  16. ((name :accessor name-of
  17. :col-type :text
  18. :initarg :name)
  19. (email :accessor user-email-of
  20. :col-type :text
  21. :initarg :email))
  22. (:unique-keys email)
  23. ;; (:primary-key email)
  24. (:metaclass registered-table-class)
  25. (:documentation "The USER class encapsulates information about the users of The Deck Builder: name, email, password, password salt, user roles."))
  26. (defclass role ()
  27. ((name ;;:col-type :text
  28. :col-type (:varchar 64)
  29. :initarg :role
  30. :inflate (alexandria:compose #'alexandria:make-keyword #'string-upcase)
  31. :deflate #'string-downcase
  32. :accessor name-of))
  33. (:documentation "The ROLE class encapsulates information about the roles of actions a user may perform, e.g. :ADMIN, :USER, :BANNED.")
  34. (:metaclass registered-table-class)
  35. (:primary-key name)
  36. (:auto-pk nil)
  37. (:record-timestamps nil))
  38. (defclass user-role ()
  39. ((user :col-type user
  40. :initarg :user
  41. :accessor user-role-user)
  42. (role :col-type role
  43. :initarg :role
  44. :accessor user-role-role))
  45. (:metaclass registered-table-class)
  46. (:primary-key user role)
  47. (:auto-pk nil)
  48. (:record-timestamps nil))
  49. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  50. (defun create-user (name email password)
  51. "Create a USER object with NAME, EMAIL, and PASSWORD fields. Will automatically be synced to db via CREATE-DAO. Password hashing provided by MITO-AUTH."
  52. (create-dao 'user :name name
  53. :email email
  54. :password password))
  55. (defun find-user (email)
  56. "Find a user by EMAIL."
  57. (find-dao 'user :email email))
  58. ;; (defun create-superuser (name email password)
  59. ;; "Create a USER with the ADMIN role."
  60. ;; (let ((user (create-user name email password)))
  61. ;; (add-role user :admin)))
  62. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  63. ;; TODO Role Viewer / Editor
  64. (defun create-role (name)
  65. "Create a ROLE called NAME. If the ROLE exists, return that, instead."
  66. (with-connection (db)
  67. (with-transaction
  68. (or (mito:find-dao 'role :name name)
  69. (mito:create-dao 'role :name name)))))
  70. (defun %find-role-from-keyword (role-name)
  71. "Return a role object from a keyword and throw an error if an associated role cannot be found"
  72. (let ((role (find-dao 'role :name role-name)))
  73. (assert role (role) "There is no role named ~a" role-name)
  74. role))
  75. (defgeneric add-role (user role)
  76. (:documentation "Add the given role to this user. ROLE is either a role object or a symbol. An example role is ':admin`.")
  77. (:method ((user user) (role role))
  78. (or (find-dao 'user-role :user user :role role)
  79. (create-dao 'user-role :user user :role role)))
  80. (:method ((user user) (role-name symbol))
  81. (let ((role (%find-role-from-keyword role-name)))
  82. (add-role user role))))
  83. ;; Retrieving roles from "user-role" table
  84. (defmethod user-roles-of ((user user))
  85. (with-connection (db)
  86. (with-transaction
  87. (mapcar #'user-role-role
  88. (mito:retrieve-dao 'user-role :user user)))))
  89. (defgeneric user-has-role (user role)
  90. (:documentation "Given a USER and a ROLE, return T if ROLE is a MEMBER of USER-ROLES for USER, NIL otherwise.")
  91. (:method ((user user) (role role))
  92. (member (name-of role) (user-roles-of user) :key #'name-of))
  93. (:method ((user user) (role-name symbol))
  94. (let ((role (%find-role-from-keyword role-name)))
  95. (user-has-role user role))))
  96. (defmethod user-admin-p ((user user))
  97. "Is USER an admin? Return T if so. NIL otherwise."
  98. (user-has-role user :admin))
  99. (defmethod user-verified-p ((user user))
  100. "Is USER in the VERIFIED role? Return T if so. NIL otherwise."
  101. (user-has-role user :verified))