-
-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add fetching of update notifications from GitHub
- Loading branch information
Showing
16 changed files
with
285 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
defmodule Keila.Instance do | ||
alias __MODULE__.Instance | ||
alias __MODULE__.Release | ||
|
||
use Keila.Repo | ||
require Logger | ||
|
||
@moduledoc """ | ||
This module provides easier access to the properties of the current Keila instance. | ||
""" | ||
|
||
@doc """ | ||
Returns the `Instance` struct that is persisted in the database. | ||
If it doesn't exist, creates a new `Instance` and returns it. | ||
""" | ||
@spec get_instance() :: Instance.t() | ||
def get_instance() do | ||
case Repo.one(Instance) do | ||
nil -> Repo.insert!(%Instance{}) | ||
instance -> instance | ||
end | ||
end | ||
|
||
@doc """ | ||
Returns the version of the current Keila instance as a string. | ||
""" | ||
@spec current_version() :: String.t() | ||
def current_version() do | ||
Application.spec(:keila, :vsn) |> to_string() | ||
end | ||
|
||
@doc """ | ||
Returns `true` if the update check has been enabled for the current instance. | ||
""" | ||
@spec update_checks_enabled? :: boolean() | ||
def update_checks_enabled? do | ||
Application.get_env(:keila, :update_checks_enabled, true) | ||
end | ||
|
||
@doc """ | ||
Returns `true` if updates are available. | ||
""" | ||
@spec updates_available? :: boolean() | ||
def updates_available? do | ||
update_checks_enabled?() && | ||
Repo.exists?( | ||
from i in Instance, where: fragment("jsonb_array_length(?) > 0", i.available_updates) | ||
) | ||
end | ||
|
||
@doc """ | ||
Fetches updates from the Keila GitHub update releases. | ||
""" | ||
@release_url "https://api.github.com/repos/pentacent/keila/releases" | ||
@spec fetch_updates() :: [__MODULE__.Release.t()] | ||
def fetch_updates() do | ||
with {:ok, response} <- HTTPoison.get(@release_url, recv_timeout: 5_000), | ||
{:ok, release_attrs} when is_list(release_attrs) <- Jason.decode(response.body) do | ||
current_version = current_version() |> Version.parse!() | ||
|
||
release_attrs | ||
|> Enum.map(fn %{"tag_name" => version, "published_at" => published_at, "body" => changelog} -> | ||
%{version: version, published_at: published_at, changelog: changelog} | ||
end) | ||
|> Enum.map(&Release.new!/1) | ||
|> Enum.filter(fn %{version: version} -> | ||
version |> Version.parse!() |> Version.compare(current_version) == :gt | ||
end) | ||
else | ||
other -> | ||
Logger.info("Unable to fetch updates. Got: #{inspect(other)}") | ||
[] | ||
end | ||
end | ||
|
||
def get_available_updates() do | ||
if update_checks_enabled?() do | ||
Repo.one(from i in Instance, select: i.available_updates) | ||
else | ||
[] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
defmodule Keila.Instance.Instance do | ||
use Keila.Schema | ||
|
||
schema "instance" do | ||
embeds_many :available_updates, Keila.Instance.Release, on_replace: :delete | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
defmodule Keila.Instance.Release do | ||
use Keila.Schema | ||
|
||
embedded_schema do | ||
field :version, :string | ||
field :published_at, :utc_datetime | ||
field :changelog, :string | ||
end | ||
|
||
def changeset(struct \\ %__MODULE__{}, params) do | ||
struct | ||
|> cast(params, [:version, :published_at, :changelog]) | ||
|> validate_required([:version, :published_at, :changelog]) | ||
|> validate_change(:version, fn :version, version -> | ||
case Version.parse(version) do | ||
{:ok, _} -> [] | ||
_ -> [version: "invalid version format"] | ||
end | ||
end) | ||
end | ||
|
||
def new!(params) do | ||
params |> changeset() |> Ecto.Changeset.apply_action!(:insert) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
defmodule Keila.Instance.UpdateCronWorker do | ||
use Oban.Worker, | ||
queue: :periodic, | ||
unique: [ | ||
period: :infinity, | ||
states: [:available, :scheduled, :executing] | ||
] | ||
|
||
use Keila.Repo | ||
alias Keila.Instance | ||
|
||
@impl true | ||
def perform(_job) do | ||
if Instance.update_checks_enabled?() do | ||
releases = Instance.fetch_updates() | ||
|
||
Instance.get_instance() | ||
|> change() | ||
|> put_embed(:available_updates, releases) | ||
|> Repo.update() | ||
else | ||
:ok | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
defmodule KeilaWeb.InstanceAdminController do | ||
use KeilaWeb, :controller | ||
|
||
alias Keila.Instance | ||
|
||
plug :authorize | ||
|
||
def show(conn, _) do | ||
update_checks_enabled? = Instance.update_checks_enabled?() | ||
available_updates = Instance.get_available_updates() | ||
current_version = Instance.current_version() | ||
|
||
host = | ||
Routes.project_url(conn, :index) | ||
|> String.replace(~r"https?://", "") | ||
|> String.replace("/", "") | ||
|
||
conn | ||
|> assign(:update_checks_enabled?, update_checks_enabled?) | ||
|> assign(:available_updates, available_updates) | ||
|> assign(:current_version, current_version) | ||
|> assign(:host, host) | ||
|> render("show.html") | ||
end | ||
|
||
defp authorize(conn, _) do | ||
case conn.assigns.is_admin? do | ||
true -> conn | ||
false -> conn |> put_status(404) |> halt() | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
defmodule KeilaWeb.InstanceInfoPlug do | ||
@behaviour Plug | ||
import Plug.Conn | ||
|
||
@impl true | ||
def call(conn, _opts) do | ||
if conn.assigns[:is_admin?] do | ||
updates_available? = Keila.Instance.updates_available?() | ||
|
||
conn | ||
|> assign(:instance_updates_available?, updates_available?) | ||
else | ||
conn | ||
end | ||
end | ||
|
||
@impl true | ||
def init(opts), do: opts | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<div class="container flex py-8 sm:py-11 mb-4"> | ||
<div class="flex-grow gap-4 flex flex-col sm:flex-row sm:items-center"> | ||
<h1 class="text-2xl sm:text-3xl text-gray-100"> | ||
<%= dgettext("admin", "You are currently running Keila %{version} on %{host}.", | ||
version: @current_version, | ||
host: @host | ||
) %> | ||
</h1> | ||
</div> | ||
</div> | ||
|
||
<div class="container mb-4"> | ||
<%= if @update_checks_enabled? do %> | ||
<%= if Enum.any?(@available_updates) do %> | ||
<div class="flex gap-4 items-center text-3xl max-w-xl"> | ||
<div class="flex size-16"> | ||
<%= render_icon(:newspaper) %> | ||
</div> | ||
There are updates available for your Keila instance! | ||
</div> | ||
<br /><br /> | ||
<%= for release <- @available_updates do %> | ||
<div class="mb-4 max-w-prose"> | ||
<p class="p-4 italic bg-gray-700"> | ||
<%= local_datetime_tag(release.published_at) %> | ||
</p> | ||
<div class="bg-gray-800 p-4 prose prose-lg prose-invert"> | ||
<%= raw(Earmark.as_html!(release.changelog)) %> | ||
</div> | ||
</div> | ||
<% end %> | ||
<% else %> | ||
<div class="flex gap-4 items-center text-3xl max-w-xl"> | ||
<div class="flex size-16"> | ||
<%= render_icon(:check_circle) %> | ||
</div> | ||
You seem to be running the most recent version of Keila! | ||
</div> | ||
<br /> | ||
<% end %> | ||
<% else %> | ||
<p>Update checks are disabled.</p> | ||
<% end %> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
defmodule KeilaWeb.InstanceAdminView do | ||
use KeilaWeb, :view | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
defmodule Keila.Repo.Migrations.CreateInstance do | ||
use Ecto.Migration | ||
|
||
def change do | ||
create table("instance") do | ||
add :available_updates, :jsonb, default: "[]" | ||
end | ||
|
||
execute "CREATE UNIQUE INDEX instance_singleton ON instance ((true));", "" | ||
execute "INSERT INTO instance DEFAULT VALUES;", "" | ||
end | ||
end |