Skip to content

Commit

Permalink
Add last_updated filter to GET /v1/apps (#367)
Browse files Browse the repository at this point in the history
* Add last_updated filter to /v1/apps
* Add updated_at to app JSON object
* Update App timestamp every new rating
  • Loading branch information
tomkonidas authored Sep 16, 2024
1 parent 332b0d9 commit 7d2c15c
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 11 deletions.
14 changes: 13 additions & 1 deletion lib/plexus/apps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ defmodule Plexus.Apps do
|> Repo.one!()
end

@spec fetch_app(String.t()) :: {:ok, App.t()} | {:error, :not_found}
def fetch_app(package) do
case Repo.get(App, package) do
%App{} = app -> {:ok, app}
nil -> {:error, :not_found}
end
end

@spec create_app(%{
optional(:icon_url) => String.t(),
package: String.t(),
Expand All @@ -63,8 +71,9 @@ defmodule Plexus.Apps do
end

@spec update_app(App.t(), %{
optional(:updated_at) => DateTime.t(),
optional(:icon_url) => String.t(),
name: String.t()
optional(:name) => String.t()
}) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
def update_app(%App{} = app, params) do
app
Expand Down Expand Up @@ -126,6 +135,9 @@ defmodule Plexus.Apps do
{_, ""}, query ->
query

{:updated_at_greater_than_or_equal_to, dt}, query ->
from q in query, where: q.updated_at >= ^dt

{:search_term, search_term}, query ->
pattern = "%#{search_term}%"

Expand Down
14 changes: 9 additions & 5 deletions lib/plexus/ratings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Plexus.Ratings do
"""
import Ecto.Query

alias Plexus.Apps
alias Plexus.PaginationHelpers
alias Plexus.QueryHelpers
alias Plexus.Repo
Expand Down Expand Up @@ -55,11 +56,14 @@ defmodule Plexus.Ratings do
installation_source: String.t(),
rating_type: atom(),
score: pos_integer()
}) :: {:ok, Rating.t()} | {:error, Ecto.Changeset.t()}
def create_rating(params) do
%Rating{}
|> Rating.changeset(params)
|> Repo.insert()
}) :: {:ok, Rating.t()} | {:error, :not_found} | {:error, Ecto.Changeset.t()}
def create_rating(%{app_package: app_package} = params) do
Repo.transact(fn ->
with {:ok, app} <- Apps.fetch_app(app_package),
{:ok, _app} <- Apps.update_app(app, %{updated_at: DateTime.utc_now()}) do
Repo.insert(Rating.changeset(%Rating{}, params))
end
end)
|> broadcast(:app_rating_updated)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/plexus/schemas/app.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule Plexus.Schemas.App do
@spec changeset(App.t(), map()) :: Ecto.Changeset.t()
def changeset(%App{} = app, params) do
app
|> cast(params, [:package, :name, :icon_url])
|> cast(params, [:package, :name, :icon_url, :updated_at])
|> validate_required([:package, :name])
|> unique_constraint(:package, name: :apps_pkey)
end
Expand Down
21 changes: 20 additions & 1 deletion lib/plexus_web/controllers/api/v1/app_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ defmodule PlexusWeb.API.V1.AppController do
page: [in: :query, description: "Page number", type: :integer, example: 1],
limit: [in: :query, description: "Max results per page", type: :integer, example: 25],
scores: [in: :query, description: "Include scores", type: :boolean, example: true],
q: [in: :query, description: "Search query", type: :string, example: "Signal"]
q: [in: :query, description: "Search query", type: :string, example: "Signal"],
last_updated: [
in: :query,
description: "Apps that have updates after or on your datetime. Using RFC 3339",
type: %OpenApiSpex.Schema{type: :string, format: "date-time"},
example:
DateTime.utc_now()
|> DateTime.add(-7, :day)
|> DateTime.truncate(:second)
|> DateTime.to_iso8601(:extended)
]
],
responses: [
ok: {"Applications", "application/json", AppsResponse}
Expand Down Expand Up @@ -77,6 +87,15 @@ defmodule PlexusWeb.API.V1.AppController do
{"scores", "true"}, acc ->
Keyword.put(acc, :scores, true)

{"last_updated", last_updated}, acc ->
case DateTime.from_iso8601(last_updated) do
{:ok, last_updated_dt, _utc_offset} ->
Keyword.put(acc, :updated_at_greater_than_or_equal_to, last_updated_dt)

_ ->
acc
end

{"page", page}, acc ->
case Integer.parse(page) do
{value, _remainder} ->
Expand Down
3 changes: 2 additions & 1 deletion lib/plexus_web/controllers/api/v1/app_json.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ defmodule PlexusWeb.API.V1.AppJSON do
%{
package: app.package,
name: app.name,
icon_url: app.icon_url
icon_url: app.icon_url,
updated_at: DateTime.truncate(app.updated_at, :second)
}
|> merge_scores(app.scores)
end
Expand Down
1 change: 1 addition & 0 deletions lib/plexus_web/controllers/api/v1/schemas/app.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ defmodule PlexusWeb.API.V1.Schemas.App do
example: %{
"name" => "Signal",
"package" => "org.thoughtcrime.securesms",
"updated_at" => "2024-04-30T22:41:19Z",
"scores" => %{
"native" => %{
"rating_type" => "native",
Expand Down
1 change: 1 addition & 0 deletions lib/plexus_web/controllers/api/v1/schemas/app_response.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule PlexusWeb.API.V1.Schemas.AppResponse do
%{
"name" => "Signal",
"package" => "org.thoughtcrime.securesms",
"updated_at" => "2024-04-30T22:41:19Z",
"scores" => %{
"native" => %{
"rating_type" => "native",
Expand Down
1 change: 1 addition & 0 deletions lib/plexus_web/controllers/api/v1/schemas/apps_response.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ defmodule PlexusWeb.API.V1.Schemas.AppsResponse do
%{
"name" => "Signal",
"package" => "org.thoughtcrime.securesms",
"updated_at" => "2024-04-30T22:41:19Z",
"scores" => %{
"native" => %{
"rating_type" => "native",
Expand Down
4 changes: 2 additions & 2 deletions test/plexus/ratings_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule Plexus.RatingsTest do
alias Plexus.Schemas.Rating

@invalid_attrs %{
app_package: nil,
app_package: "",
app_build_number: nil,
app_version: nil,
rating_type: nil,
Expand Down Expand Up @@ -65,7 +65,7 @@ defmodule Plexus.RatingsTest do
end

test "invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Ratings.create_rating(@invalid_attrs)
assert {:error, _reason} = Ratings.create_rating(@invalid_attrs)
end
end
end

0 comments on commit 7d2c15c

Please sign in to comment.