Skip to content

Commit 7d2c15c

Browse files
authored
Add last_updated filter to GET /v1/apps (#367)
* Add last_updated filter to /v1/apps * Add updated_at to app JSON object * Update App timestamp every new rating
1 parent 332b0d9 commit 7d2c15c

File tree

9 files changed

+50
-11
lines changed

9 files changed

+50
-11
lines changed

lib/plexus/apps.ex

+13-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ defmodule Plexus.Apps do
5050
|> Repo.one!()
5151
end
5252

53+
@spec fetch_app(String.t()) :: {:ok, App.t()} | {:error, :not_found}
54+
def fetch_app(package) do
55+
case Repo.get(App, package) do
56+
%App{} = app -> {:ok, app}
57+
nil -> {:error, :not_found}
58+
end
59+
end
60+
5361
@spec create_app(%{
5462
optional(:icon_url) => String.t(),
5563
package: String.t(),
@@ -63,8 +71,9 @@ defmodule Plexus.Apps do
6371
end
6472

6573
@spec update_app(App.t(), %{
74+
optional(:updated_at) => DateTime.t(),
6675
optional(:icon_url) => String.t(),
67-
name: String.t()
76+
optional(:name) => String.t()
6877
}) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
6978
def update_app(%App{} = app, params) do
7079
app
@@ -126,6 +135,9 @@ defmodule Plexus.Apps do
126135
{_, ""}, query ->
127136
query
128137

138+
{:updated_at_greater_than_or_equal_to, dt}, query ->
139+
from q in query, where: q.updated_at >= ^dt
140+
129141
{:search_term, search_term}, query ->
130142
pattern = "%#{search_term}%"
131143

lib/plexus/ratings.ex

+9-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ defmodule Plexus.Ratings do
44
"""
55
import Ecto.Query
66

7+
alias Plexus.Apps
78
alias Plexus.PaginationHelpers
89
alias Plexus.QueryHelpers
910
alias Plexus.Repo
@@ -55,11 +56,14 @@ defmodule Plexus.Ratings do
5556
installation_source: String.t(),
5657
rating_type: atom(),
5758
score: pos_integer()
58-
}) :: {:ok, Rating.t()} | {:error, Ecto.Changeset.t()}
59-
def create_rating(params) do
60-
%Rating{}
61-
|> Rating.changeset(params)
62-
|> Repo.insert()
59+
}) :: {:ok, Rating.t()} | {:error, :not_found} | {:error, Ecto.Changeset.t()}
60+
def create_rating(%{app_package: app_package} = params) do
61+
Repo.transact(fn ->
62+
with {:ok, app} <- Apps.fetch_app(app_package),
63+
{:ok, _app} <- Apps.update_app(app, %{updated_at: DateTime.utc_now()}) do
64+
Repo.insert(Rating.changeset(%Rating{}, params))
65+
end
66+
end)
6367
|> broadcast(:app_rating_updated)
6468
end
6569

lib/plexus/schemas/app.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule Plexus.Schemas.App do
2020
@spec changeset(App.t(), map()) :: Ecto.Changeset.t()
2121
def changeset(%App{} = app, params) do
2222
app
23-
|> cast(params, [:package, :name, :icon_url])
23+
|> cast(params, [:package, :name, :icon_url, :updated_at])
2424
|> validate_required([:package, :name])
2525
|> unique_constraint(:package, name: :apps_pkey)
2626
end

lib/plexus_web/controllers/api/v1/app_controller.ex

+20-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ defmodule PlexusWeb.API.V1.AppController do
1717
page: [in: :query, description: "Page number", type: :integer, example: 1],
1818
limit: [in: :query, description: "Max results per page", type: :integer, example: 25],
1919
scores: [in: :query, description: "Include scores", type: :boolean, example: true],
20-
q: [in: :query, description: "Search query", type: :string, example: "Signal"]
20+
q: [in: :query, description: "Search query", type: :string, example: "Signal"],
21+
last_updated: [
22+
in: :query,
23+
description: "Apps that have updates after or on your datetime. Using RFC 3339",
24+
type: %OpenApiSpex.Schema{type: :string, format: "date-time"},
25+
example:
26+
DateTime.utc_now()
27+
|> DateTime.add(-7, :day)
28+
|> DateTime.truncate(:second)
29+
|> DateTime.to_iso8601(:extended)
30+
]
2131
],
2232
responses: [
2333
ok: {"Applications", "application/json", AppsResponse}
@@ -77,6 +87,15 @@ defmodule PlexusWeb.API.V1.AppController do
7787
{"scores", "true"}, acc ->
7888
Keyword.put(acc, :scores, true)
7989

90+
{"last_updated", last_updated}, acc ->
91+
case DateTime.from_iso8601(last_updated) do
92+
{:ok, last_updated_dt, _utc_offset} ->
93+
Keyword.put(acc, :updated_at_greater_than_or_equal_to, last_updated_dt)
94+
95+
_ ->
96+
acc
97+
end
98+
8099
{"page", page}, acc ->
81100
case Integer.parse(page) do
82101
{value, _remainder} ->

lib/plexus_web/controllers/api/v1/app_json.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ defmodule PlexusWeb.API.V1.AppJSON do
1919
%{
2020
package: app.package,
2121
name: app.name,
22-
icon_url: app.icon_url
22+
icon_url: app.icon_url,
23+
updated_at: DateTime.truncate(app.updated_at, :second)
2324
}
2425
|> merge_scores(app.scores)
2526
end

lib/plexus_web/controllers/api/v1/schemas/app.ex

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ defmodule PlexusWeb.API.V1.Schemas.App do
1616
example: %{
1717
"name" => "Signal",
1818
"package" => "org.thoughtcrime.securesms",
19+
"updated_at" => "2024-04-30T22:41:19Z",
1920
"scores" => %{
2021
"native" => %{
2122
"rating_type" => "native",

lib/plexus_web/controllers/api/v1/schemas/app_response.ex

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ defmodule PlexusWeb.API.V1.Schemas.AppResponse do
1414
%{
1515
"name" => "Signal",
1616
"package" => "org.thoughtcrime.securesms",
17+
"updated_at" => "2024-04-30T22:41:19Z",
1718
"scores" => %{
1819
"native" => %{
1920
"rating_type" => "native",

lib/plexus_web/controllers/api/v1/schemas/apps_response.ex

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ defmodule PlexusWeb.API.V1.Schemas.AppsResponse do
1717
%{
1818
"name" => "Signal",
1919
"package" => "org.thoughtcrime.securesms",
20+
"updated_at" => "2024-04-30T22:41:19Z",
2021
"scores" => %{
2122
"native" => %{
2223
"rating_type" => "native",

test/plexus/ratings_test.exs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule Plexus.RatingsTest do
88
alias Plexus.Schemas.Rating
99

1010
@invalid_attrs %{
11-
app_package: nil,
11+
app_package: "",
1212
app_build_number: nil,
1313
app_version: nil,
1414
rating_type: nil,
@@ -65,7 +65,7 @@ defmodule Plexus.RatingsTest do
6565
end
6666

6767
test "invalid data returns error changeset" do
68-
assert {:error, %Ecto.Changeset{}} = Ratings.create_rating(@invalid_attrs)
68+
assert {:error, _reason} = Ratings.create_rating(@invalid_attrs)
6969
end
7070
end
7171
end

0 commit comments

Comments
 (0)