defmodule Coherence.InvitationController do @moduledoc """ Handle invitation actions. Handle the following actions: * new - render the send invitation form. * create - generate and send the invitation token. * edit - render the form after user clicks the invitation email link. * create_user - create a new user database record * resend - resend an invitation token email """ use Coherence.Web, :controller alias Coherence.{Config, Invitation} require Logger use Timex import Ecto.Changeset plug Coherence.ValidateOption, :invitable plug :scrub_params, "user" when action in [:create_user] plug :layout_view @doc false def layout_view(conn, _) do conn |> put_layout({Coherence.LayoutView, "app.html"}) |> put_view(Coherence.InvitationView) end @doc """ Render the new invitation form. """ def new(conn, _params) do changeset = Invitation.changeset(%Invitation{}) render(conn, "new.html", changeset: changeset) end @doc """ Generate and send an invitation token. Creates a new invitation token, save it to the database and send the invitation email. """ def create(conn, %{"invitation" => invitation_params}) do repo = Config.repo user_schema = Config.user_schema email = invitation_params["email"] cs = Invitation.changeset(%Invitation{}, invitation_params) case repo.one from u in user_schema, where: u.email == ^email do nil -> token = random_string 48 url = router_helpers.invitation_url(conn, :edit, token) cs = put_change(cs, :token, token) case Config.repo.insert cs do {:ok, invitation} -> send_user_email :invitation, invitation, url conn |> put_flash(:info, "Invitation sent.") |> redirect(to: logged_out_url(conn)) {:error, changeset} -> {conn, changeset} = case repo.one from i in Invitation, where: i.email == ^email do nil -> {conn, changeset} invitation -> {assign(conn, :invitation, invitation), add_error(changeset, :email, "Invitation already sent.")} end render(conn, "new.html", changeset: changeset) end _ -> cs = cs |> add_error(:email, "User already has an account!") |> struct(action: true) conn |> render("new.html", changeset: cs) end end @doc """ Render the create user template. Sets the name and email address in the form based on what was entered when the invitation was sent. """ def edit(conn, params) do token = params["id"] where(Invitation, [u], u.token == ^token) |> Config.repo.one |> case do nil -> conn |> put_flash(:error, "Invalid invitation token.") |> redirect(to: logged_out_url(conn)) invite -> user_schema = Config.user_schema cs = user_schema.changeset(user_schema.__struct__, %{email: invite.email, name: invite.name}) conn |> render(:edit, changeset: cs, token: invite.token) end end @doc """ Create a new user action. Create a new user based from an invite token. """ def create_user(conn, params) do token = params["token"] repo = Config.repo user_schema = Config.user_schema where(Invitation, [u], u.token == ^token) |> repo.one |> case do nil -> conn |> put_flash(:error, "Invalid Invitation. Please contact the site administrator.") |> redirect(to: logged_out_url(conn)) invite -> changeset = user_schema.changeset(user_schema.__struct__, params["user"]) case repo.insert changeset do {:ok, user} -> repo.delete invite conn |> send_confirmation(user, user_schema) |> redirect(to: logged_out_url(conn)) {:error, changeset} -> render conn, "edit.html", changeset: changeset, token: token end end end @doc """ Resent an invitation Resent the invitation based on the invitation's id. """ def resend(conn, %{"id" => id}) do case Config.repo.get(Invitation, id) do nil -> conn |> put_flash(:error, "Can't find that token") invitation -> send_user_email :invitation, invitation, router_helpers.invitation_url(conn, :edit, invitation.token) put_flash conn, :info, "Invitation sent." end |> redirect(to: logged_out_url(conn)) end end