Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ config :algora, AlgoraWeb.Endpoint,

config :algora, Oban,
repo: Algora.Repo,
queues: [event_consumers: 1, comment_consumers: 1]
queues: [
event_consumers: 1,
comment_consumers: 1,
github_og_image: 5
]

# Configures the mailer
#
Expand Down
50 changes: 50 additions & 0 deletions lib/algora/workspace/jobs/update_repository_og_image.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
defmodule Algora.Workspace.Jobs.UpdateRepositoryOgImage do
@moduledoc false
use Oban.Worker, queue: :github_og_image

alias Algora.Repo
alias Algora.Workspace.Repository

require Logger

@impl Oban.Worker
def perform(%Oban.Job{args: %{"repository_id" => repository_id}}) do
repository =
Repository
|> Repo.get(repository_id)
|> Repo.preload(:user)

case repository do
nil -> {:error, :not_found}
repository -> update_og_image(repository)
end
end

defp update_og_image(repository) do
repo_owner = repository.user.provider_login
repo_name = repository.name
object = "repositories/#{repo_owner}/#{repo_name}/og.png"

req = Finch.build(:get, repository.og_image_url)

with {:ok, %Finch.Response{body: body}} <- Finch.request(req, Algora.Finch),
{:ok, _} <- Algora.S3.upload(body, object, content_type: "image/png"),
url = Algora.S3.bucket_url() <> "/" <> object,
{:ok, updated_repository} <- update_repository_url(repository, url) do
{:ok, updated_repository}
else
error ->
Logger.error("Failed to fetch/upload image for #{repo_owner}/#{repo_name}: #{inspect(error)}")
error
end
end

defp update_repository_url(repository, url) do
repository
|> Ecto.Changeset.change(%{
og_image_url: url,
og_image_updated_at: DateTime.utc_now()
})
|> Repo.update()
end
end
28 changes: 21 additions & 7 deletions lib/algora/workspace/schemas/repository.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,45 @@ defmodule Algora.Workspace.Repository do

@derive {Inspect, except: [:provider_meta]}
typed_schema "repositories" do
field :provider, :string
field :provider_id, :string
field :provider_meta, :map
field :provider, :string, null: false
field :provider_id, :string, null: false
field :provider_meta, :map, null: false

field :name, :string
field :url, :string
field :name, :string, null: false
field :url, :string, null: false
field :description, :string
field :og_image_url, :string, null: false
field :og_image_updated_at, :utc_datetime_usec

has_many :tickets, Algora.Workspace.Ticket
belongs_to :user, Algora.Accounts.User
belongs_to :user, Algora.Accounts.User, null: false

timestamps()
end

defp og_image_base_url, do: "https://opengraph.githubassets.com"

def has_default_og_image?(%Repository{} = repository),
do: String.starts_with?(repository.og_image_url, og_image_base_url())

def default_og_image_url(repo_owner, repo_name), do: "#{og_image_base_url()}/0/#{repo_owner}/#{repo_name}"

def github_changeset(meta, user) do
params = %{
provider_id: to_string(meta["id"]),
name: meta["name"],
description: meta["description"],
og_image_url: default_og_image_url(meta["owner"]["login"], meta["name"]),
og_image_updated_at: DateTime.utc_now(),
url: meta["html_url"],
user_id: user.id
}

%Repository{provider: "github", provider_meta: meta}
|> cast(params, [:provider_id, :name, :url, :user_id])
|> cast(params, [:provider_id, :name, :url, :description, :og_image_url, :og_image_updated_at, :user_id])
|> generate_id()
|> validate_required([:provider_id, :name, :url, :user_id])
|> foreign_key_constraint(:user_id)
|> unique_constraint([:provider, :provider_id])
end
end
31 changes: 28 additions & 3 deletions lib/algora/workspace/workspace.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule Algora.Workspace do
alias Algora.Github
alias Algora.Repo
alias Algora.Workspace.Installation
alias Algora.Workspace.Jobs
alias Algora.Workspace.Repository
alias Algora.Workspace.Ticket

Expand Down Expand Up @@ -49,10 +50,34 @@ defmodule Algora.Workspace do
where: u.provider_login == ^owner
)

case Repo.one(repository_query) do
%Repository{} = repository -> {:ok, repository}
nil -> create_repository_from_github(token, owner, repo)
res =
case Repo.one(repository_query) do
%Repository{} = repository -> {:ok, repository}
nil -> create_repository_from_github(token, owner, repo)
end

case res do
{:ok, repository} -> maybe_schedule_og_image_update(repository)
error -> error
end

res
end

defp maybe_schedule_og_image_update(%Repository{} = repository) do
one_day_ago = DateTime.add(DateTime.utc_now(), -1, :day)

needs_update? =
Repository.has_default_og_image?(repository) ||
(repository.og_image_updated_at && DateTime.before?(repository.og_image_updated_at, one_day_ago))

if needs_update? do
%{repository_id: repository.id}
|> Jobs.UpdateRepositoryOgImage.new()
|> Oban.insert()
end

:ok
end

def create_repository_from_github(token, owner, repo) do
Expand Down
23 changes: 23 additions & 0 deletions priv/repo/migrations/20250105152749_add_repo_fields.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Algora.Repo.Migrations.AddRepoFields do
use Ecto.Migration

def change do
alter table(:repositories) do
add :description, :text
add :og_image_url, :string
add :og_image_updated_at, :utc_datetime_usec
end

# Backfill existing repositories with default values
execute """
UPDATE repositories
SET og_image_url = REPLACE(url, 'https://github.com', 'https://opengraph.githubassets.com/0')
WHERE og_image_url IS NULL
"""

# Make columns non-nullable after backfill
alter table(:repositories) do
modify :og_image_url, :string, null: false
end
end
end
Loading