Skip to content

Commit

Permalink
system_model: add localized attributes
Browse files Browse the repository at this point in the history
Close edgehog-device-manager#441

Signed-off-by: Riccardo Binetti <[email protected]>
  • Loading branch information
rbino committed May 24, 2024
1 parent 298758f commit ab64b8e
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 9 deletions.
33 changes: 31 additions & 2 deletions backend/lib/edgehog/devices/system_model/system_model.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ defmodule Edgehog.Devices.SystemModel do
AshGraphql.Resource
]

alias Edgehog.Localization
alias Edgehog.Devices.SystemModel.Changes
alias Edgehog.Devices.SystemModel.Validations

Expand Down Expand Up @@ -87,6 +88,10 @@ defmodule Edgehog.Devices.SystemModel do
description "A picture representing the system model that will be uploaded to a bucket."
end

argument :localized_descriptions, {:array, Localization.LocalizedAttribute} do
description "A list of descriptions in different languages."
end

validate Validations.EitherPictureUrlOrPictureFile

# TODO: see issue #228, which is still relevant
Expand All @@ -99,13 +104,16 @@ defmodule Edgehog.Devices.SystemModel do

change manage_relationship(:hardware_type_id, :hardware_type, type: :append)
change Changes.HandlePictureUpload

change {Localization.Changes.UpsertLocalizedAttribute,
input_argument: :localized_descriptions, target_attribute: :description}
end

update :update do
description "Updates an system model."
primary? true

# Needed because manage_relationship is not atomic
# Needed because manage_relationship and UpsertLocalizedAttribute are not atomic
require_atomic? false

accept [:handle, :name, :picture_url]
Expand All @@ -119,6 +127,15 @@ defmodule Edgehog.Devices.SystemModel do
description "A picture representing the system model that will be uploaded to a bucket."
end

argument :localized_descriptions, {:array, Localization.LocalizedAttributeUpdateInput} do
description """
A list of descriptions in different languages.
If a language already exists it is updated. If a null value is passed, the language
is deleted.
"""
end

validate Validations.EitherPictureUrlOrPictureFile

change manage_relationship(:part_numbers,
Expand All @@ -131,6 +148,9 @@ defmodule Edgehog.Devices.SystemModel do

change Changes.HandlePictureUpload
change Changes.HandlePictureDeletion

change {Localization.Changes.UpsertLocalizedAttribute,
input_argument: :localized_descriptions, target_attribute: :description}
end

destroy :destroy do
Expand Down Expand Up @@ -174,7 +194,7 @@ defmodule Edgehog.Devices.SystemModel do
description "A URL to a picture representing the system model."
end

# TODO: localized description
attribute :description, :map

create_timestamp :inserted_at
update_timestamp :updated_at
Expand All @@ -193,6 +213,15 @@ defmodule Edgehog.Devices.SystemModel do
end
end

calculations do
calculate :localized_descriptions, {:array, Localization.LocalizedAttribute} do
public? true
description "A list of descriptions in different languages."
calculation {Localization.Calculations.LocalizedAttribute, attribute: :description}
argument :preferred_language_tags, {:array, :string}
end
end

aggregates do
list :part_number_strings, :part_numbers, :part_number
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ defmodule EdgehogWeb.Schema.Mutation.CreateSystemModelTest do
assert %{"partNumber" => "456"} in part_numbers
end

test "allows passing localized descriptions", %{tenant: tenant} do
localized_descriptions = [
%{"languageTag" => "en", "value" => "My Model"},
%{"languageTag" => "it", "value" => "Il mio modello"}
]

result =
create_system_model_mutation(
tenant: tenant,
localized_descriptions: localized_descriptions
)

assert %{"localizedDescriptions" => localized_descriptions} = extract_result!(result)
assert length(localized_descriptions) == 2
assert %{"languageTag" => "en", "value" => "My Model"} in localized_descriptions
assert %{"languageTag" => "it", "value" => "Il mio modello"} in localized_descriptions
end

test "allows saving a picture url", %{tenant: tenant} do
result =
create_system_model_mutation(
Expand Down Expand Up @@ -212,6 +230,10 @@ defmodule EdgehogWeb.Schema.Mutation.CreateSystemModelTest do
result {
id
name
localizedDescriptions {
languageTag
value
}
handle
pictureUrl
partNumbers {
Expand All @@ -237,6 +259,7 @@ defmodule EdgehogWeb.Schema.Mutation.CreateSystemModelTest do
"hardwareTypeId" => hardware_type_id,
"handle" => opts[:handle] || unique_system_model_handle(),
"name" => opts[:name] || unique_system_model_name(),
"localizedDescriptions" => opts[:localized_descriptions],
"partNumbers" => opts[:part_numbers] || [unique_system_model_part_number()],
"pictureUrl" => opts[:picture_url],
"pictureFile" => opts[:picture_file] && "picture_file"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,40 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateSystemModelTest do
assert %{"partNumber" => "D"} in part_numbers
end

test "allows updating localized descriptions", %{tenant: tenant} do
initial_localized_descriptions = [
%{language_tag: "en", value: "Description"},
%{language_tag: "it", value: "Descrizione"}
]

fixture =
system_model_fixture(
tenant: tenant,
localized_descriptions: initial_localized_descriptions
)

id = AshGraphql.Resource.encode_relay_id(fixture)

updated_localized_descriptions = [
# nil value, so it will be removed
%{"languageTag" => "en", "value" => nil},
%{"languageTag" => "it", "value" => "Nuova descrizione"},
%{"languageTag" => "bs", "value" => "Opis"}
]

result =
update_system_model_mutation(
tenant: tenant,
id: id,
localized_descriptions: updated_localized_descriptions
)

assert %{"localizedDescriptions" => localized_descriptions} = extract_result!(result)
assert length(localized_descriptions) == 2
assert %{"languageTag" => "it", "value" => "Nuova descrizione"} in localized_descriptions
assert %{"languageTag" => "bs", "value" => "Opis"} in localized_descriptions
end

test "allows saving a picture url", %{tenant: tenant, id: id} do
result =
update_system_model_mutation(
Expand Down Expand Up @@ -351,6 +385,10 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateSystemModelTest do
result {
id
name
localizedDescriptions {
languageTag
value
}
handle
pictureUrl
partNumbers {
Expand All @@ -368,6 +406,7 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateSystemModelTest do
%{
"handle" => opts[:handle],
"name" => opts[:name],
"localizedDescriptions" => opts[:localized_descriptions],
"partNumbers" => opts[:part_numbers],
"pictureUrl" => opts[:picture_url],
"pictureFile" => opts[:picture_file] && "picture_file"
Expand Down Expand Up @@ -396,9 +435,6 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateSystemModelTest do
end

defp extract_result!(result) do
refute :errors in Map.keys(result)
refute "errors" in Map.keys(result[:data])

assert %{
data: %{
"updateSystemModel" => %{
Expand All @@ -407,6 +443,9 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateSystemModelTest do
}
} = result

refute :errors in Map.keys(result)
refute "errors" in Map.keys(result[:data])

assert system_model != nil

system_model
Expand Down
97 changes: 93 additions & 4 deletions backend/test/edgehog_web/schema/query/system_model_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ defmodule EdgehogWeb.Schema.Query.SystemModelTest do

id = AshGraphql.Resource.encode_relay_id(fixture)

result = system_model_query(tenant: tenant, id: id)
system_model =
system_model_query(tenant: tenant, id: id)
|> extract_result!()

refute Map.has_key?(result, :errors)
assert %{data: %{"systemModel" => system_model}} = result
assert system_model["name"] == fixture.name
assert system_model["handle"] == fixture.handle
assert system_model["pictureUrl"] == fixture.picture_url
Expand All @@ -70,6 +70,83 @@ defmodule EdgehogWeb.Schema.Query.SystemModelTest do
end
end

describe "systemModel localized descriptions" do
setup %{tenant: tenant} do
localized_descriptions = [
%{language_tag: "en-US", value: "My Model"},
%{language_tag: "it", value: "Il mio modello"},
%{language_tag: "fr", value: "Mon modele"}
]

system_model =
system_model_fixture(tenant: tenant, localized_descriptions: localized_descriptions)

id = AshGraphql.Resource.encode_relay_id(system_model)

document = """
query ($id: ID!, $preferredLanguageTags: [String!]) {
systemModel(id: $id) {
localizedDescriptions(preferredLanguageTags: $preferredLanguageTags) {
languageTag
value
}
}
}
"""

%{system_model: system_model, id: id, document: document}
end

test "returns all localized descriptions with no preferredLanguageTags", ctx do
%{tenant: tenant, id: id, document: document} = ctx

%{"localizedDescriptions" => localized_descriptions} =
system_model_query(
tenant: tenant,
id: id,
document: document
)
|> extract_result!()

assert length(localized_descriptions) == 3
assert %{"languageTag" => "en-US", "value" => "My Model"} in localized_descriptions
assert %{"languageTag" => "it", "value" => "Il mio modello"} in localized_descriptions
assert %{"languageTag" => "fr", "value" => "Mon modele"} in localized_descriptions
end

test "returns filtered localized descriptions with preferredLanguageTags", ctx do
%{tenant: tenant, id: id, document: document} = ctx
preferred_language_tags = ["it", "fr"]

%{"localizedDescriptions" => localized_descriptions} =
system_model_query(
tenant: tenant,
id: id,
extra_variables: %{"preferredLanguageTags" => preferred_language_tags},
document: document
)
|> extract_result!()

assert length(localized_descriptions) == 2
assert %{"languageTag" => "it", "value" => "Il mio modello"} in localized_descriptions
assert %{"languageTag" => "fr", "value" => "Mon modele"} in localized_descriptions
end

test "returns empty localized descriptions if no language tag matches exactly", ctx do
%{tenant: tenant, id: id, document: document} = ctx
preferred_language_tags = ["en-GB", "de"]

%{"localizedDescriptions" => []} =
system_model_query(
tenant: tenant,
id: id,
extra_variables: %{"preferredLanguageTags" => preferred_language_tags},
document: document
)
|> extract_result!()
end
end

defp non_existing_system_model_id(tenant) do
fixture = system_model_fixture(tenant: tenant)
id = AshGraphql.Resource.encode_relay_id(fixture)
Expand All @@ -78,6 +155,15 @@ defmodule EdgehogWeb.Schema.Query.SystemModelTest do
id
end

defp extract_result!(result) do
assert %{data: %{"systemModel" => system_model}} = result

refute :errors in Map.keys(result)
assert system_model != nil

system_model
end

defp system_model_query(opts) do
default_document = """
query ($id: ID!) {
Expand All @@ -98,7 +184,10 @@ defmodule EdgehogWeb.Schema.Query.SystemModelTest do
tenant = Keyword.fetch!(opts, :tenant)
id = Keyword.fetch!(opts, :id)

variables = %{"id" => id}
variables =
opts
|> Keyword.get(:extra_variables, %{})
|> Map.merge(%{"id" => id})

document = Keyword.get(opts, :document, default_document)

Expand Down

0 comments on commit ab64b8e

Please sign in to comment.