Skip to content

Commit

Permalink
[admin] Add ability to accept News submissions with feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
jerodsanto committed Jan 16, 2024
1 parent 30e063e commit 8a5e72e
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 23 deletions.
12 changes: 12 additions & 0 deletions lib/changelog/notifier.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ defmodule Changelog.Notifier do
deliver_podcast_subscription_emails(episode)
end

def notify(item = %NewsItem{status: :accepted}) do
if StringKit.present?(item.message) do
item
|> NewsItem.preload_all()
|> deliver_submitter_accepted_email()
end
end

def notify(item = %NewsItem{status: :declined}) do
if StringKit.present?(item.message) do
item
Expand Down Expand Up @@ -212,6 +220,10 @@ defmodule Changelog.Notifier do
end
end

defp deliver_submitter_accepted_email(item) do
MailDeliverer.enqueue("submitted_news_accepted", %{"item" => item.id})
end

defp deliver_submitter_decline_email(item) do
MailDeliverer.enqueue("submitted_news_declined", %{"item" => item.id})
end
Expand Down
8 changes: 8 additions & 0 deletions lib/changelog/oban_workers/mail_deliverer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ defmodule Changelog.ObanWorkers.MailDeliverer do
|> Mailer.deliver_now()
end

def submitted_news_accepted(%{"item" => id}) do
NewsItem
|> Repo.get(id)
|> NewsItem.preload_all()
|> Email.submitted_news_accepted()
|> Mailer.deliver_now()
end

def submitted_news_declined(%{"item" => id}) do
NewsItem
|> Repo.get(id)
Expand Down
6 changes: 3 additions & 3 deletions lib/changelog/policies/admin/news/news_item.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ defmodule Changelog.Policies.Admin.NewsItem do
use Changelog.Policies.Default

def create(actor), do: is_admin(actor) || is_editor(actor)
def accept(actor), do: is_admin(actor)
def index(actor), do: is_admin(actor) || is_editor(actor)
def accept(actor, _item), do: is_admin(actor)
def update(actor, item), do: is_admin(actor) || is_logger(actor, item)
def move(actor, _), do: is_admin(actor)
def decline(actor, _), do: is_admin(actor)
def move(actor, _item), do: is_admin(actor)
def decline(actor, _item), do: is_admin(actor)
def unpublish(actor, item), do: is_admin(actor) || is_logger(actor, item)

def delete(actor, item = %{status: status}) do
Expand Down
25 changes: 18 additions & 7 deletions lib/changelog/schema/news/news_item.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ defmodule Changelog.NewsItem do
def feed_only(query \\ __MODULE__), do: from(q in query, where: q.feed_only)
def non_feed_only(query \\ __MODULE__), do: from(q in query, where: not q.feed_only)

def accepted(query \\ __MODULE__), do: from(q in query, where: q.status == ^:accepted)
def declined(query \\ __MODULE__), do: from(q in query, where: q.status == ^:declined)
def drafted(query \\ __MODULE__), do: from(q in query, where: q.status == ^:draft)

Expand Down Expand Up @@ -203,6 +204,7 @@ defmodule Changelog.NewsItem do
case item.type do
:audio -> get_episode_object(item.object_id)
:post -> get_post_object(item.object_id)
:link -> get_news_object(item.object_id)
_else -> nil
end

Expand All @@ -222,8 +224,7 @@ defmodule Changelog.NewsItem do
load_object(item, episode)
end

defp get_episode_object(object_id) when is_nil(object_id), do: nil

defp get_episode_object(nil), do: nil
defp get_episode_object(object_id) do
[_podcast_id, episode_id] = String.split(object_id, ":")

Expand All @@ -234,8 +235,13 @@ defmodule Changelog.NewsItem do
|> Repo.get(episode_id)
end

defp get_post_object(object_id) when is_nil(object_id), do: nil
# items that link to news objects are actually the same as items
# that link to episode objects, but we differentiate them because
# they are not audio, they are merely links that have been accepted
# and included in a news episode/email
defp get_news_object(object_id), do: get_episode_object(object_id)

defp get_post_object(nil), do: nil
defp get_post_object(object_id) do
[_, slug] = String.split(object_id, ":")

Expand Down Expand Up @@ -310,11 +316,16 @@ defmodule Changelog.NewsItem do
|> Repo.preload(:topics)
end

def accept!(item), do: item |> change(%{status: :accepted}) |> Repo.update!()
def accept!(item, ""), do: accept!(item)

def accept!(item, message),
do: item |> change(%{status: :accepted, message: message}) |> Repo.update!()
def accept!(item, object_id), do: accept!(item, object_id, "")

def accept!(item, object_id, message) do
item
|> change(%{status: :accepted})
|> change(%{message: message})
|> change(%{object_id: "news:#{object_id}"})
|> Repo.update!()
end

def decline!(item), do: item |> change(%{status: :declined}) |> Repo.update!()
def decline!(item, ""), do: decline!(item)
Expand Down
16 changes: 11 additions & 5 deletions lib/changelog_web/controllers/admin/episode_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,22 @@ defmodule ChangelogWeb.Admin.EpisodeController do
end

defp assign_submitted(conn, podcast) do
submitted = if Podcast.is_news(podcast) do
NewsItem.submitted()
{submitted, news_episodes} = if Podcast.is_news(podcast) do
{NewsItem.submitted()
|> NewsItem.newest_first(:inserted_at)
|> NewsItem.preload_all()
|> Repo.all()
|> Repo.all(),
Episode.with_podcast_slug("news")
|> Episode.newest_first(:recorded_at)
|> Episode.limit(20)
|> Repo.all()}
else
[]
{[], []}
end

assign(conn, :submitted, submitted)
conn
|> assign(:submitted, submitted)
|> assign(:news_episodes, news_episodes)
end

def performance(conn, %{"ids" => ids}, podcast) do
Expand Down
13 changes: 13 additions & 0 deletions lib/changelog_web/controllers/admin/mailer_preview_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,19 @@ defmodule ChangelogWeb.Admin.MailerPreviewController do
Email.authored_news_published(item)
end

def submitted_news_accepted_email(_person) do
item =
NewsItem
|> NewsItem.accepted()
|> NewsItem.with_object()
|> NewsItem.newest_first()
|> NewsItem.limit(1)
|> NewsItem.preload_all()
|> Repo.one()

Email.submitted_news_accepted(item)
end

def submitted_news_declined_email(_person) do
item =
NewsItem
Expand Down
6 changes: 4 additions & 2 deletions lib/changelog_web/controllers/admin/news_item_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ defmodule ChangelogWeb.Admin.NewsItemController do
Notifier
}

plug :assign_item when action in [:edit, :update, :move, :decline, :move, :unpublish, :delete]
plug :assign_item when action in [:accept, :edit, :update, :move, :decline, :move, :unpublish, :delete]
plug Authorize, [Policies.Admin.NewsItem, :item]
plug :scrub_params, "news_item" when action in [:create, :update]
plug :detect_quick_form when action in [:new, :create]
Expand Down Expand Up @@ -155,7 +155,9 @@ defmodule ChangelogWeb.Admin.NewsItemController do

def accept(conn = %{assigns: %{item: item}}, params) do
message = Map.get(params, "message", "")
item = NewsItem.accept!(item, message)
object_id = Map.get(params, "object", nil)

item = NewsItem.accept!(item, object_id, message)
Task.start_link(fn -> Notifier.notify(item) end)

conn
Expand Down
13 changes: 13 additions & 0 deletions lib/changelog_web/email.ex
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,19 @@ defmodule ChangelogWeb.Email do
|> render(:submitted_news_published)
end

def submitted_news_accepted(item) do
item = NewsItem.load_object(item)

styled_email()
|> put_header("X-CMail-GroupName", "Accepted News")
|> to(item.submitter)
|> subject("Your submission to Changelog News")
|> assign(:person, item.submitter)
|> assign(:item, item)
|> assign(:news, item.object)
|> render(:submitted_news_accepted)
end

def submitted_news_declined(item) do
styled_email()
|> put_header("X-CMail-GroupName", "Declined News")
Expand Down
12 changes: 10 additions & 2 deletions lib/changelog_web/templates/admin/news_item/_accept_modal.html.eex
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
<div id="<%= @modal_id %>" class="ui small accept modal">
<i class="close icon"></i>
<div class="header">
Accept with message: <em><%= @item.headline %></em>
Accepting: <em><%= @item.headline %></em>
</div>
<div class="content">
<%= form_tag Routes.admin_news_item_path(@conn, :accept, @item, next: "back"), id: @form_id, class: "ui small form" do %>
<div class="field">
<label>Featured in:</label>
<select name="object" class="ui fluid selection dropdown">
<%= for news <- @news_episodes do %>
<option value="<%= news.id %>">#<%= news.slug %>: <%= news.title %></option>
<% end %>
</select>
</div>
<div class="field">
<div class="ui">
<textarea name="message" placeholder="Personal note, sent by email to submitter"></textarea>
<textarea name="message" placeholder="Personal note, sent by email to submitter. Leave blank to accept silently."></textarea>
</div>
</div>
<% end %>
Expand Down
7 changes: 3 additions & 4 deletions lib/changelog_web/templates/admin/news_item/_table.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,12 @@
<% end %>
<%= if Policies.Admin.NewsItem.edit(@current_user, item), do: AdminHelpers.icon_link("edit", to: ~p"/admin/news/items/#{item}/edit") %>
<%= if @status == :submitted do %>
<%= AdminHelpers.icon_link("thumbs up", to: ~p"/admin/news/items/#{item}/accept?next=back", title: "Accept silently", method: :delete, data: [confirm: "Decline this item?"]) %>
<%= AdminHelpers.modal_icon_button(
ChangelogWeb.Admin.NewsItemView,
"file text",
"Accept with message",
"thumbs up",
"Accept",
"accept",
%{item: item, conn: @conn},
Map.merge(assigns, %{item: item}),
item.id
) %>
<%= AdminHelpers.icon_link("thumbs down", to: ~p"/admin/news/items/#{item}/decline?next=back", title: "Decline silently", method: :delete, data: [confirm: "Decline this item?"]) %>
Expand Down
18 changes: 18 additions & 0 deletions lib/changelog_web/templates/email/submitted_news_accepted.html.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<tr>
<td class="content-block" itemprop="handler" itemscope itemtype="http://schema.org/HttpActionHandler">
<p><%= greeting(@person) %></p>

<p>Your <%= link("submission", to: @item.url) %> was <strong>accepted</strong>! It is included in Changelog News #<%= @news.slug %>:</p>

<ul>
<li><%= link("Audio here", to: url(~p"/news/#{@news.slug}")) %></li>
<li><%= link("Email here", to: url(~p"/news/#{@news.slug}/email")) %></li>
</ul>

<p>In addition, here is a message from the editor:</p>

<p><blockquote><%= @item.message |> SharedHelpers.md_to_html() |> raw() %></blockquote></p>

<p>💚, Logbot</p>
</td>
</tr>
19 changes: 19 additions & 0 deletions lib/changelog_web/templates/email/submitted_news_accepted.text.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<%= greeting(@person) %>


Your submission was accepted! It is included in Changelog News #<%= @news.slug %>:

Audio link: url(~p"/news/#{@news.slug}")
Email link: url(~p"/news/#{@news.slug}/email")

In addition, here is a message from the editor:

---

<%= @item.message %>

---

If there's more to say or our message requested a response, feel free to reply.

💚, Logbot
26 changes: 26 additions & 0 deletions test/changelog/notifier_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,32 @@ defmodule Changelog.NotifierTest do
assert_no_emails_delivered()
end

test "when submitter has news item accepted with message" do
person = insert(:person, settings: %{email_on_submitted_news: true})
item = insert(:news_item, submitter: person)
news = insert(:podcast, slug: "news")
ep = insert(:published_episode, podcast: news)
item = NewsItem.accept!(item, ep.id, "accepted reason")
Notifier.notify(item)

assert %{success: 1, failure: 0} = Oban.drain_queue(queue: :email)

assert_delivered_email(Email.submitted_news_accepted(item))
end

test "when submitter has news item accepted sans message" do
person = insert(:person, settings: %{email_on_submitted_news: true})
item = insert(:news_item, submitter: person)
news = insert(:podcast, slug: "news")
ep = insert(:published_episode, podcast: news)
item = NewsItem.accept!(item, ep.id, "")
Notifier.notify(item)

assert %{success: 0, failure: 0} = Oban.drain_queue(queue: :email)

assert_no_emails_delivered()
end

test "when submitter and author are same person, notifications enabled" do
person = insert(:person, settings: %{email_on_submitted_news: true})
item = insert(:news_item, submitter: person, author: person)
Expand Down

0 comments on commit 8a5e72e

Please sign in to comment.