Skip to content

Commit

Permalink
Moar Zulip integrations
Browse files Browse the repository at this point in the history
- Track users in Zulip
- Use Zulip URLs a discussion links
  • Loading branch information
jerodsanto committed Oct 3, 2024
1 parent 1d191e5 commit b4459bc
Show file tree
Hide file tree
Showing 16 changed files with 87 additions and 60 deletions.
2 changes: 1 addition & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ config :changelog, Oban,
timezone: "US/Central",
crontab: [
# 3am daily
{"00 3 * * *", Changelog.ObanWorkers.SlackImporter},
{"00 3 * * *", Changelog.ObanWorkers.ZulipImporter},
# 3:30am daily
{"30 3 * * *", Changelog.ObanWorkers.Bouncer},
# 4am daily
Expand Down
27 changes: 27 additions & 0 deletions lib/changelog/oban_workers/zulip_importer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Changelog.ObanWorkers.ZulipImporter do
use Oban.Worker, queue: :scheduled

alias Changelog.{Person, Repo}
alias Changelog.Zulip.Client

@impl Oban.Worker
def perform(_job) do
case Client.get_users() do
%{"ok" => true, "members" => members} ->
for %{"user_id" => id, "email" => email} <- members do
import_member_id(id, email)
end

:ok
%{"ok" => false} ->
:ok
end
end

def import_member_id(id, email) do
Person
|> Person.not_in_zulip()
|> Person.with_email(email)
|> Repo.update_all(set: [zulip_id: "#{id}"])
end
end
8 changes: 4 additions & 4 deletions lib/changelog/schema/person.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ defmodule Changelog.Person do
field :mastodon_handle, :string
field :twitter_handle, :string
field :slack_id, :string
field :zulip_id, :string
field :website, :string
field :bio, :string
field :location, :string
Expand Down Expand Up @@ -118,6 +119,9 @@ defmodule Changelog.Person do
def in_slack(query \\ __MODULE__), do: from(q in query, where: not is_nil(q.slack_id))
def not_in_slack(query \\ __MODULE__), do: from(q in query, where: is_nil(q.slack_id))

def in_zulip(query \\ __MODULE__), do: from(q in query, where: not is_nil(q.zulip_id))
def not_in_zulip(query \\ __MODULE__), do: from(q in query, where: is_nil(q.zulip_id))

def joined(query \\ __MODULE__), do: from(a in query, where: not is_nil(a.joined_at))
def never_confirmed(query \\ __MODULE__), do: from(q in query, where: is_nil(q.joined_at))
def never_signed_in(query \\ __MODULE__), do: from(q in query, where: is_nil(q.signed_in_at))
Expand Down Expand Up @@ -288,10 +292,6 @@ defmodule Changelog.Person do
})
end

def slack_changes(person, slack_id) do
change(person, %{slack_id: slack_id})
end

def refresh_auth_token(person, expires_in \\ 60 * 24) do
auth_token = Base.encode16(:crypto.strong_rand_bytes(8))
expires_at = Timex.add(Timex.now(), Timex.Duration.from_minutes(expires_in))
Expand Down
5 changes: 4 additions & 1 deletion lib/changelog/schema/podcast/podcast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ defmodule Changelog.Podcast do
field :riverside_url, :string
field :youtube_url, :string
field :clips_url, :string
field :zulip_url, :string

field :download_count, :float
field :reach_count, :integer
Expand Down Expand Up @@ -89,6 +90,7 @@ defmodule Changelog.Podcast do
spotify_url: "https://open.spotify.com/show/0S1h5K7jm2YvOcM7y1ZMXY",
youtube_url: "https://www.youtube.com/changelog",
clips_url: "https://www.youtube.com/playlist?list=PLCzseuA9sYreJ1p9RXR6Z667mrMyHXAeH",
zulip_url: "https://changelog.zulipchat.com",
cover: true,
active_hosts: [],
retired_hosts: []
Expand All @@ -114,6 +116,7 @@ defmodule Changelog.Podcast do
spotify_url: "https://open.spotify.com/show/5bBki72YeKSLUqyD94qsuJ",
youtube_url: "https://www.youtube.com/playlist?list=PLCzseuA9sYrf9nHWFF1dQsk-X5cghL6UH",
clips_url: "https://www.youtube.com/playlist?list=PLCzseuA9sYreumc6MQV7C8FiRuaMczhjK",
zulip_url: "https://changelog.zulipchat.com",
cover: true,
active_hosts: Person.with_ids([1, 2]) |> Person.newest_first() |> Repo.all()
}
Expand Down Expand Up @@ -144,7 +147,7 @@ defmodule Changelog.Podcast do
podcast
|> cast(
attrs,
~w(name slug status vanity_domain schedule_note welcome description extended_description keywords mastodon_handle mastodon_token twitter_handle apple_url spotify_url riverside_url youtube_url clips_url recorded_live partner position)a
~w(name slug status vanity_domain schedule_note welcome description extended_description keywords mastodon_handle mastodon_token twitter_handle apple_url spotify_url riverside_url youtube_url clips_url zulip_url recorded_live partner position)a
)
|> validate_required([:name, :slug, :status])
|> validate_format(:vanity_domain, Regexp.http(), message: Regexp.http_message())
Expand Down
8 changes: 8 additions & 0 deletions lib/changelog/zulip/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ defmodule Changelog.Zulip.Client do
|> handle()
end

def get_users do
headers = with_bot_headers()

"/users"
|> get(headers)
|> handle()
end

def post_invite(email) do
params = ~s(invitee_emails=#{email}&stream_ids=[]&include_realm_default_subscriptions=true)
headers = with_admin_headers()
Expand Down
1 change: 1 addition & 0 deletions lib/changelog_web/controllers/admin/page_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ defmodule ChangelogWeb.Admin.PageController do
%{
today: Repo.count(Person.joined_today()),
slack: Repo.count(Person.in_slack()),
zulip: Repo.count(Person.in_zulip()),
spam: Repo.count(Person.spammy()),
total: Repo.count(Person.joined())
}
Expand Down
9 changes: 0 additions & 9 deletions lib/changelog_web/controllers/admin/person_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,9 @@ defmodule ChangelogWeb.Admin.PersonController do
flash =
case Slack.Client.invite(person.email) do
%{"ok" => true} ->
set_slack_id_to_pending(person)
"success"

%{"ok" => false, "error" => "already_in_team"} ->
set_slack_id_to_pending(person)
"success"

_else ->
Expand Down Expand Up @@ -273,13 +271,6 @@ defmodule ChangelogWeb.Admin.PersonController do
end
end

defp set_slack_id_to_pending(person = %{slack_id: id}) when not is_nil(id), do: person

defp set_slack_id_to_pending(person) do
{:ok, person} = Repo.update(Person.slack_changes(person, "pending"))
person
end

defp handle_welcome_email(person, params) do
case Map.get(params, "welcome") do
"generic" -> handle_generic_welcome_email(person)
Expand Down
43 changes: 5 additions & 38 deletions lib/changelog_web/controllers/home/home_controller.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule ChangelogWeb.HomeController do
use ChangelogWeb, :controller

alias Changelog.{Fastly, NewsItem, Person, Podcast, Slack, StringKit, Subscription, Zulip}
alias Changelog.{Fastly, NewsItem, Person, Podcast, StringKit, Subscription, Zulip}

plug(RequireUser, "except from email links" when action not in [:opt_out])
plug :preload_current_user_extras
Expand Down Expand Up @@ -86,41 +86,21 @@ defmodule ChangelogWeb.HomeController do
send_resp(conn, 200, "")
end

def slack(conn = %{assigns: %{current_user: me}}, _params) do
{updated_user, flash} =
case Slack.Client.invite(me.email) do
%{"ok" => true} ->
{set_slack_id(me), "Invite sent! Check your email 🎯"}

%{"ok" => false, "error" => "already_in_team"} ->
{set_slack_id(me), "You're on the team! We'll see you in there ✊"}

%{"ok" => false, "error" => error} ->
{me, "Hmm, Slack is saying '#{error}' 🤔"}
end

conn
|> assign(:current_user, updated_user)
|> put_flash(:success, flash)
|> redirect(to: ~p"/~")
end

def zulip(conn = %{assigns: %{current_user: me}}, _params) do
{updated_user, flash} = case Zulip.user_id(me) do
flash = case Zulip.user_id(me) do
{:ok, _id} ->
{me, "Your email already has an account. We'll see you in there! 💬"}
"Your email already has an account. We'll see you in there! 💬"
{:error, nil} ->
case Zulip.invite(me) do
%{"ok" => true} ->
{set_zulip_id(me), "Invite sent! Check your email 🎯"}
"Invite sent! Check your email 🎯"

%{"ok" => false, "msg" => error} ->
{me, "Hmm, Zulip is saying '#{error}' 🤔"}
"Hmm, Zulip is saying '#{error}' 🤔"
end
end

conn
|> assign(:current_user, updated_user)
|> put_flash(:success, flash)
|> redirect(to: ~p"/~")
end
Expand Down Expand Up @@ -171,19 +151,6 @@ defmodule ChangelogWeb.HomeController do
render(conn, :opted_out)
end

defp set_slack_id(person) do
if person.slack_id do
person
else
{:ok, person} = Repo.update(Person.slack_changes(person, "pending"))
person
end
end

defp set_zulip_id(person) do
person
end

defp preload_current_user_extras(conn = %{assigns: %{current_user: me}}, _) do
me =
me
Expand Down
4 changes: 4 additions & 0 deletions lib/changelog_web/templates/admin/page/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
<td>Members in Slack</td>
<td><%= @members[:slack] |> SharedHelpers.comma_separated() %></td>
</tr>
<tr>
<td>Members in Zulip</td>
<td><%= @members[:zulip] |> SharedHelpers.comma_separated() %></td>
</tr>
<tr>
<td>Total members</td>
<td><%= @members[:total] |> SharedHelpers.comma_separated() %></td>
Expand Down
2 changes: 1 addition & 1 deletion lib/changelog_web/templates/admin/person/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<%= if Policies.Admin.Person.edit(@current_user, @person) do %>
<%= AdminHelpers.icon_link("edit", to: ~p"/admin/people/#{@person}/edit?next=#{next}", title: "Edit") %>
<% end %>
<%= AdminHelpers.icon_link("slack", to: ~p"/admin/people/#{@person}/slack", title: "Invite to Slack", method: :post, data: [confirm: "Are you sure?"]) %>
<%= AdminHelpers.icon_link("zulip", to: ~p"/admin/people/#{@person}/zulip", title: "Invite to Zulip", method: :post, data: [confirm: "Are you sure?"]) %>
<%= if Policies.Admin.Person.masq(@current_user, @person) do %>
<%= AdminHelpers.icon_link("user secret", to: ~p"/admin/people/#{@person}/masq", title: "Masquarade", method: :post, data: [confirm: "Do you want to use the site as this user?"]) %>
<% end %>
Expand Down
6 changes: 6 additions & 0 deletions lib/changelog_web/templates/admin/podcast/_form.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@
<%= AdminHelpers.error_message(f, :clips_url) %>
</div>

<div class={"field #{AdminHelpers.error_class(f, :zulip_url)}"}>
<%= label(f, :zulip_url, "Zulip URL") %>
<%= text_input(f, :zulip_url) %>
<%= AdminHelpers.error_message(f, :zulip_url) %>
</div>

<div class="ui hidden divider"></div>
<div class="ui equal width stackable grid">
<%= if !AdminHelpers.is_persisted(f.data) do %>
Expand Down
4 changes: 3 additions & 1 deletion lib/changelog_web/templates/episode/_item.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@

<footer class="news_item-footer">
<span class="news_item-footer-item">
<%= link("Discuss", to: ~p"/#{@episode.podcast.slug}/#{@episode.slug}/discuss") %>
<%= if @episode.podcast.zulip_url do %>
<%= link("Discuss", to: @episode.podcast.zulip_url) %>
<% end %>
&bull; <%= link("Share",
title: "Share this episode",
to: {:javascript, "void(0);"},
Expand Down
4 changes: 2 additions & 2 deletions lib/changelog_web/templates/episode/_play_bar.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
class: "toolbar_item toolbar_item--button playbar playbar_play") %>
<% end %>

<%= if @item do %>
<%= if @episode.podcast.zulip_url do %>
<%= link("Discuss",
title: "Discuss this episode",
to: Routes.news_item_path(@conn, :show, NewsItem.slug(@item)),
to: @episode.podcast.zulip_url,
class: "toolbar_item toolbar_item--button playbar_discuss") %>
<% end %>

Expand Down
1 change: 0 additions & 1 deletion lib/changelog_web/views/episode_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ defmodule ChangelogWeb.EpisodeView do
Github,
HtmlKit,
ListKit,
NewsItem,
Podcast,
Subscription,
StringKit,
Expand Down
10 changes: 8 additions & 2 deletions lib/changelog_web/views/feed_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ defmodule ChangelogWeb.FeedView do
def discussion_link(nil), do: ""

def discussion_link(episode = %Episode{}) do
url(~p"/#{episode.podcast.slug}/#{episode.slug}/discuss") |> discussion_link()
link = if episode.podcast.zulip_url do
episode.podcast.zulip_url
else
url(~p"/#{episode.podcast.slug}/#{episode.slug}/discuss")
end

discussion_link(link)
end

def discussion_link(post = %Post{}), do: discussion_link(post.news_item)
Expand All @@ -18,7 +24,7 @@ defmodule ChangelogWeb.FeedView do

def discussion_link(url) when is_binary(url) do
content_tag(:p) do
content_tag(:a, "Leave us a comment", href: url)
content_tag(:a, "Join the discussion", href: url)
end
|> safe_to_string()
end
Expand Down
13 changes: 13 additions & 0 deletions priv/repo/migrations/20241003201027_add_zulip_fields.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Changelog.Repo.Migrations.AddZulipFields do
use Ecto.Migration

def change do
alter table(:people) do
add :zulip_id, :string
end

alter table(:podcasts) do
add :zulip_url, :string
end
end
end

0 comments on commit b4459bc

Please sign in to comment.