How to realize extra operations with Invitable View Source
List invitations sent by the current user
We first need to add a route for that, so in your router, add the following:
# lib/your_app_web/router.ex
resources "/invitations", YourAppWeb.InvitationController, only: ~W[index]a
(I voluntarily don't use get "/invitations", YourAppWeb.InvitationController
to have easier to add other actions)
Next, in one of your contexts or a new one, add a function to get the invitations of a user:
defmodule YourApp.Accounts do
import Ecto.Query
alias YourApp.Repo
import Haytni.InvitablePlugin.QueryHelpers
# ...
@spec list_invitations(user :: YourApp.user) :: [Haytni.InvitablePlugin.invitation]
def list_invitations(user = %YourApp.User{}) do
user
|> invitations_from_user()
|> preload([:accepter])
|> order_by([desc: :sent_at])
|> Repo.all()
end
end
So this way, you can easily add any filter (accepted or not, expired or not and so on) as pagination at any time.
Finaly, we'll have to write this controller and index action:
# lib/your_app_web/controllers/invitation_controller.ex
defmodule YourAppWeb.InvitationController do
use YourAppWeb, :controller
def index(conn, _params) do
if current_user = conn.assigns[:current_user] do
conn
|> assign(:invitations, Accounts.list_invitations(current_user))
|> render(:index)
else
{:error, :forbidden} # to be handled by an Action Fallback
end
end
end
If you need a starting point for the corresponding template, here it is:
# lib/your_app_web/templates/invitation/index.html.heex
<%= if Enum.any?(@invitations) do %>
<table>
<thead>
<tr>
<th><%= dgettext("myapp", "Sent at") %></th>
<th><%= dgettext("myapp", "Sent to") %></th>
<th><%= dgettext("myapp", "Accepted at") %></th>
<th><%= dgettext("myapp", "Accepted by") %></th>
<th></th>
</tr>
</thead>
<tbody>
<%= for invitation <- @invitations do %>
<tr>
<td><%= invitation.sent_at %></td>
<td><%= invitation.sent_to %></td>
<td><%= if is_nil(invitation.accepted_at), do: "-", else: invitation.accepted_at %></td>
<td><%= if is_nil(invitation.accepted_by), do: "-", else: invitation.accepter.name %></td>
<td><%= if is_nil(invitation.accepted_by), do: link(dgettext("myapp", "Revoke"), to: Routes.invitation_path(@conn, :delete, invitation), method: :delete) %></td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p><%= dgettext("myapp", "You have not send any invitation for now.") %></p>
<% end %>
<p>
<%= link dgettext("myapp", "Do you have a friend you want to invite?"), to: Routes.haytni_user_invitation_path(@conn, :new) %>
</p>
## Delete a non-accepted invitation
First, in your router, add a delete route:
# lib/your_app_web/router.ex
resources "/invitations", YourAppWeb.InvitationController, only: ~W[delete]a
Then, in one of your contexts or a new one, write a revoke_invitation like this one:
defmodule YourApp.Accounts do
import Ecto.Query
alias YourApp.Repo
import Haytni.InvitablePlugin.QueryHelpers
# ...
@spec revoke_invitation(user :: YourApp.User, id :: any) :: boolean
def revoke_invitation(user = %YourApp.User{}, id)
when not is_nil(id)
do
{count, nil} =
user
|> invitations_from_user()
|> and_where_not_accepted()
|> and_where_id_equals(id)
|> Repo.delete_all()
1 == count
end
end
Lastly, write the delete action of your invitation controller based on this model:
# lib/your_app_web/controllers/invitation_controller.ex
defmodule YourAppWeb.InvitationController do
use YourAppWeb, :controller
def delete(conn, %{"id" => invitation_id}) do
if current_user = conn.assigns[:current_user] do
Haytni.InvitablePlugin.revoke_invitation(current_user, invitation_id)
conn
|> put_flash(:info, "Invitation has been successfully revoked")
|> redirect(to: "/")
|> halt()
else
{:error, :forbidden} # to be handled by an Action Fallback
end
end
end