+
+ @spec valid_invite?(UserInviteToken.t()) :: boolean()
+ def valid_invite?(%{invite_type: "one_time"} = invite) do
+ not invite.used
+ end
+
+ def valid_invite?(%{invite_type: "date_limited"} = invite) do
+ not_overdue_date?(invite) and not invite.used
+ end
+
+ def valid_invite?(%{invite_type: "reusable"} = invite) do
+ invite.uses < invite.max_use and not invite.used
+ end
+
+ def valid_invite?(%{invite_type: "reusable_date_limited"} = invite) do
+ not_overdue_date?(invite) and invite.uses < invite.max_use and not invite.used
+ end
+
+ defp not_overdue_date?(%{expires_at: expires_at}) do
+ Date.compare(Date.utc_today(), expires_at) in [:lt, :eq]
+ end
+
+ @spec update_usage!(UserInviteToken.t()) :: nil | UserInviteToken.t() | no_return()
+ def update_usage!(%{invite_type: "date_limited"}), do: nil
+
+ def update_usage!(%{invite_type: "one_time"} = invite),
+ do: update_invite!(invite, %{used: true})
+
+ def update_usage!(%{invite_type: invite_type} = invite)
+ when invite_type == "reusable" or invite_type == "reusable_date_limited" do
+ changes = %{
+ uses: invite.uses + 1
+ }
+
+ changes =
+ if changes.uses >= invite.max_use do
+ Map.put(changes, :used, true)
+ else
+ changes
+ end
+
+ update_invite!(invite, changes)
+ end