I currently have three phoenix applications at work that share a common requirement, that requirement is that users must be invited to the system. Here is how I am currently doing the invitation system on one of the applications:
I have two schema’s: Invitation
and User
, and here’s what they look like:
schema "users" do
field :first_name, :string
field :last_name, :string
field :email, :string
field :password_hash, :string
field :password_reset_hash, :string
belongs_to :account, Aura.Account
many_to_many :permissions, Aura.Permission, join_through: Aura.UserPermission, on_replace: :delete
many_to_many :surgeons, Aura.Surgeon, join_through: Aura.UserSurgeon, on_replace: :delete
field :password, :string, virtual: true
field :password_confirmation, :string, virtual: true
timestamps()
end
schema "invitations" do
field :first_name, :string
field :last_name, :string
field :email, :string
field :token, :string
belongs_to :account, Aura.Account
many_to_many :permissions, Aura.Permission, join_through: Aura.InvitationPermission, on_replace: :delete
many_to_many :surgeons, Aura.Surgeon, join_through: Aura.InvitationSurgeon, on_replace: :delete
timestamps()
end
The Invitation
is a struct that holds information that is required to create a user. So it holds things like the first_name
, last_name
, permissions
, surgeons
, account
, etc… just like the User
.
A User
that has a permission to invite another User
interacts with the InvitationController
to create an Invitation
. When that Invitation
is created an email is sent to the newly invited user with a url that has a unique token that they can click to begin the creation of their User
. Once they click the link and enter a password all of the information from the Invitation
is used to create their User
and then the Invitation
is deleted.
So this implemention has:
-
User
struct -
Invitation
struct - Ecto migrations for the above structs
-
InvitationController
with:-
[:edit, :create_user]
actions that are not guarded behind authentication to allow a new user to view their invitation, enter a password and then create their user. -
[:index, :new, :create, :delete]
actions are behind authentication to allow authentication users to view, create, and delete invitations.
-
- Associated html templates and views that go along with the above controller actions
My goal is to be able to have something like this that I can drop into newly created phoenix applications.
Here’s a list of thoughts/questions I currently have:
-
Does it make sense to extract this functionality or just continue to write this funtionality in each phoenix application? Ultimately it’s just a couple ecto structs and a phoenix controller implementation.
-
If I was to extract this functionality, how would I handle the flow of information from the extracted module’s
Invitation
to the application’sUser
? Does the extracted module just allow the application to hand over what is considered theInvitation
andUser
? Because each application may have different data on a user. -
Does it make sense to even have the concept of an
Invitation
? I’ve been thinking that maybe when you invite a user, it just creates aUser
that can’t login or isn’t activated. -
Is it common or make sense to extract a phoenix controller out of the phoenix application and into its own module? This was my initial thought on how I would extract this funtionality. Basically extract the phoenix controller into the module, and allow the phoenix application that is implementing the module to use it in its router. I’m not sure how I would handle the flow of data related to #2 though.