Commit a2a3aeda authored by Mayel's avatar Mayel

Merge remote-tracking branch 'antonis/cleanup/valueflows' into extension/valueflows

parents 44db17bc 10911617
Pipeline #214097481 failed with stage
in 1 minute and 8 seconds
# SPDX-License-Identifier: AGPL-3.0-only
defmodule ValueFlows.Claim do
use Pointers.Pointable,
otp_app: :commons_pub,
source: "vf_claim",
table_id: "C0MM0NSPVBVA1VEF10WSC1A1MS"
import CommonsPub.Common.Changeset, only: [change_public: 1, change_disabled: 1]
alias Ecto.Changeset
alias CommonsPub.Users.User
alias Measurement.Measure
alias ValueFlows.Knowledge.Action
alias ValueFlows.Knowledge.ResourceSpecification
alias ValueFlows.Observation.EconomicEvent
@type t :: %__MODULE__{}
pointable_schema do
field(:note, :string)
field(:agreed_in, :string)
field(:finished, :boolean)
field(:created, :utc_datetime_usec)
field(:due, :utc_datetime_usec)
field(:resource_classified_as, {:array, :string})
belongs_to(:action, Action, type: :string)
belongs_to(:provider, Pointers.Pointer)
belongs_to(:receiver, Pointers.Pointer)
belongs_to(:resource_quantity, Measure, on_replace: :nilify)
belongs_to(:effort_quantity, Measure, on_replace: :nilify)
belongs_to(:resource_conforms_to, ResourceSpecification)
belongs_to(:triggered_by, EconomicEvent)
# a.k.a. in_scope_of
belongs_to(:context, Pointers.Pointer)
# not defined in spec, used internally
belongs_to(:creator, User)
field(:is_public, :boolean, virtual: true)
field(:published_at, :utc_datetime_usec)
field(:is_disabled, :boolean, virtual: true, default: false)
field(:disabled_at, :utc_datetime_usec)
field(:deleted_at, :utc_datetime_usec)
timestamps(inserted_at: false)
end
@required ~w(action_id)a
@cast @required ++
~w(note finished agreed_in created due resource_classified_as is_disabled)a ++
~w(context_id resource_conforms_to_id triggered_by_id)a
def create_changeset(%User{} = creator, %{id: _} = provider, %{id: _} = receiver, attrs) do
%__MODULE__{}
|> Changeset.cast(attrs, @cast)
|> Changeset.change(
creator_id: creator.id,
provider_id: provider.id,
receiver_id: receiver.id,
is_public: true
)
|> change_measures(attrs)
|> common_changeset()
end
def validate_required(changeset) do
Changeset.validate_required(changeset, @required)
end
def change_measures(changeset, %{} = attrs) do
measures = Map.take(attrs, measure_fields())
Enum.reduce(measures, changeset, fn {field_name, measure}, c ->
Changeset.put_assoc(c, field_name, measure)
end)
end
defp common_changeset(changeset) do
changeset
|> change_public()
|> change_disabled()
end
def measure_fields, do: [:resource_quantity, :effort_quantity]
end
# SPDX-License-Identifier: AGPL-3.0-only
defmodule ValueFlows.Claim.Claims do
import CommonsPub.Common, only: [maybe_put: 3]
alias CommonsPub.Repo
alias CommonsPub.Users.User
alias ValueFlows.Claim
alias ValueFlows.Claim.Queries
alias CommonsPub.Meta.Pointers
def one(filters), do: Repo.single(Queries.query(Claim, filters))
def many(filters \\ []), do: {:ok, Repo.all(Queries.query(Claim, filters))}
def preload_all(%Claim{} = claim) do
Repo.preload(claim, [
:creator,
:provider,
:receiver,
:context,
:resource_conforms_to,
:resource_quantity,
:effort_quantity,
:triggered_by,
])
end
# TODO: change attributes and then pass to changeset, use preload for rest
def create(%User{} = creator, %{id: _} = provider, %{id: _} = receiver, %{} = attrs) do
Repo.transact_with(fn ->
attrs = prepare_attrs(attrs)
with {:ok, provider_ptr} <- Pointers.one(id: provider.id),
{:ok, receiver_ptr} <- Pointers.one(id: receiver.id) do
Claim.create_changeset(creator, provider_ptr, receiver_ptr, attrs)
|> Claim.validate_required()
|> Repo.insert()
|> CommonsPub.Common.maybe_ok_error(&preload_all/1)
end
end)
end
def update(%Claim{} = claim, %{} = _attrs) do
{:ok, claim}
end
def soft_delete(%Claim{} = claim) do
{:ok, claim}
end
defp prepare_attrs(attrs) do
attrs
|> maybe_put(:action_id, Map.get(attrs, :action))
|> maybe_put(:context_id,
attrs |> Map.get(:in_scope_of) |> CommonsPub.Common.maybe(&List.first/1)
)
|> maybe_put(:resource_conforms_to_id, Map.get(attrs, :resource_conforms_to))
|> maybe_put(:triggered_by_id, Map.get(attrs, :triggered_by))
end
end
# SPDX-License-Identifier: AGPL-3.0-only
defmodule ValueFlows.Claim.Migrations do
use Ecto.Migration
import Pointers.Migration
alias ValueFlows.Knowledge.ResourceSpecification
alias ValueFlows.Observation.EconomicEvent
def up do
create_pointable_table(ValueFlows.Claim) do
add(:note, :text)
add(:agreed_in, :string)
add(:action_id, :string)
add(:finished, :boolean)
add(:created, :timestamptz)
add(:due, :timestamptz)
add(:resource_classified_as, {:array, :string})
add(:provider_id, weak_pointer(), null: true)
add(:receiver_id, weak_pointer(), null: true)
add(:resource_conforms_to_id, weak_pointer(ResourceSpecification), null: true)
add(:triggered_by_id, weak_pointer(EconomicEvent), null: true)
add(:resource_quantity_id, weak_pointer(Measurement.Measure), null: true)
add(:effort_quantity_id, weak_pointer(Measurement.Measure), null: true)
add(:creator_id, references("mn_user", on_delete: :nilify_all))
add(:context_id, weak_pointer(), null: true)
add(:published_at, :timestamptz)
add(:deleted_at, :timestamptz)
add(:disabled_at, :timestamptz)
timestamps(inserted_at: false, type: :utc_datetime_usec)
end
end
def down do
drop_pointable_table(ValueFlows.Claim)
end
end
# SPDX-License-Identifier: AGPL-3.0-only
defmodule ValueFlows.Claim.Queries do
import Ecto.Query
alias ValueFlows.Claim
def query(Claim) do
from(c in Claim, as: :claim)
end
def query(q, filters), do: filter(query(q), filters)
def queries(query, _page_opts, base_filters, data_filters, count_filters) do
base_q = query(query, base_filters)
data_q = filter(base_q, data_filters)
count_q = filter(base_q, count_filters)
{data_q, count_q}
end
def join_to(q, spec, join_qualifier \\ :left)
def join_to(q, specs, jq) when is_list(specs) do
Enum.reduce(specs, q, &join_to(&2, &1, jq))
end
def join_to(q, :context, jq) do
join(q, jq, [claim: c], c2 in assoc(c, :context), as: :context)
end
def filter(q, filters) when is_list(filters) do
Enum.reduce(filters, q, &filter(&2, &1))
end
def filter(q, {:join, {join, qual}}), do: join_to(q, join, qual)
def filter(q, {:join, join}), do: join_to(q, join)
def filter(q, :default) do
filter(q, [:deleted])
end
def filter(q, :deleted) do
where(q, [claim: c], is_nil(c.deleted_at))
end
def filter(q, {:id, id}) when is_binary(id) do
where(q, [claim: c], c.id == ^id)
end
def filter(q, {:id, ids}) when is_list(ids) do
where(q, [claim: c], c.id in ^ids)
end
end
......@@ -36,7 +36,6 @@ defmodule ValueFlows.Hydration do
inventoried_economic_resources: [
resolve: &ValueFlows.Observation.EconomicResource.GraphQL.agent_resources/3
],
}
%{
......@@ -138,16 +137,29 @@ defmodule ValueFlows.Hydration do
in_scope_of: [
resolve: &CommonResolver.context_edge/3
],
input_of: [
resolve: &ValueFlows.Observation.EconomicEvent.GraphQL.fetch_input_of_edge/3
],
output_of: [
resolve: &ValueFlows.Observation.EconomicEvent.GraphQL.fetch_output_of_edge/3
],
resource_inventoried_as: [
resolve:
&ValueFlows.Observation.EconomicEvent.GraphQL.fetch_resource_inventoried_as_edge/3
],
to_resource_inventoried_as: [
resolve:
&ValueFlows.Observation.EconomicEvent.GraphQL.fetch_to_resource_inventoried_as_edge/3
],
resource_classified_as: [
resolve: &ValueFlows.Util.GraphQL.fetch_classifications_edge/3
],
at_location: [
resolve: &ValueFlows.Util.GraphQL.at_location_edge/3
],
triggered_by: [
resolve: &ValueFlows.Observation.EconomicEvent.GraphQL.fetch_triggered_by_edge/3
],
tags: [
resolve: &CommonsPub.Tag.GraphQL.TagResolver.tags_edges/3
],
......@@ -180,6 +192,18 @@ defmodule ValueFlows.Hydration do
onhand_quantity: [
resolve: &ValueFlows.Util.GraphQL.onhand_quantity_edge/3
],
primary_accountable: [
resolve: &ValueFlows.Observation.EconomicResource.GraphQL.fetch_primary_accountable_edge/3
],
unit_of_effort: [
resolve: &ValueFlows.Observation.EconomicResource.GraphQL.fetch_unit_of_effort_edge/3
],
contained_in: [
resolve: &ValueFlows.Observation.EconomicResource.GraphQL.fetch_contained_in_edge/3
],
conforms_to: [
resolve: &ValueFlows.Observation.EconomicResource.GraphQL.fetch_conforms_to_edge/3
],
tags: [
resolve: &CommonsPub.Tag.GraphQL.TagResolver.tags_edges/3
],
......
......@@ -186,87 +186,31 @@ defmodule ValueFlows.Knowledge.ProcessSpecification.GraphQL do
})
end
def create_process_spec(
%{process_specification: %{in_scope_of: context_ids} = process_spec_attrs},
info
)
when is_list(context_ids) do
# FIXME: support multiple contexts?
context_id = List.first(context_ids)
create_process_spec(
%{process_specification: Map.merge(process_spec_attrs, %{in_scope_of: context_id})},
info
)
end
def create_process_spec(
%{process_specification: %{in_scope_of: context_id} = process_spec_attrs},
info
)
when not is_nil(context_id) do
# FIXME, need to do something like validate_thread_context to validate the provider/receiver agent ID
def create_process_spec(%{process_specification: process_spec_attrs}, info) do
Repo.transact_with(fn ->
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
{:ok, pointer} <- Pointers.one(id: context_id),
context = Pointers.follow!(pointer),
{:ok, uploads} <- UploadResolver.upload(user, process_spec_attrs, info),
process_spec_attrs = Map.merge(process_spec_attrs, uploads),
process_spec_attrs = Map.merge(process_spec_attrs, %{is_public: true}),
{:ok, process_spec} <-
ProcessSpecifications.create(user, context, process_spec_attrs) do
{:ok, process_spec} <- ProcessSpecifications.create(user, process_spec_attrs) do
{:ok, %{process_specification: process_spec}}
end
end)
end
# FIXME: duplication!
def create_process_spec(%{process_specification: process_spec_attrs}, info) do
def update_process_spec(%{process_specification: %{id: id} = changes}, info) do
Repo.transact_with(fn ->
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
{:ok, uploads} <- UploadResolver.upload(user, process_spec_attrs, info),
process_spec_attrs = Map.merge(process_spec_attrs, uploads),
process_spec_attrs = Map.merge(process_spec_attrs, %{is_public: true}),
{:ok, process_spec} <- ProcessSpecifications.create(user, process_spec_attrs) do
{:ok, process_spec} <- process_spec(%{id: id}, info),
:ok <- ensure_update_permission(user, process_spec),
{:ok, uploads} <- UploadResolver.upload(user, changes, info),
changes = Map.merge(changes, uploads),
{:ok, process_spec} <- ProcessSpecifications.update(process_spec, changes) do
{:ok, %{process_specification: process_spec}}
end
end)
end
def update_process_spec(%{process_specification: %{in_scope_of: context_ids} = changes}, info) do
context_id = List.first(context_ids)
Repo.transact_with(fn ->
do_update(changes, info, fn process_spec, changes ->
with {:ok, pointer} <- Pointers.one(id: context_id) do
context = Pointers.follow!(pointer)
ProcessSpecifications.update(process_spec, context, changes)
end
end)
end)
end
def update_process_spec(%{process_specification: changes}, info) do
Repo.transact_with(fn ->
do_update(changes, info, fn process_spec, changes ->
ProcessSpecifications.update(process_spec, changes)
end)
end)
end
defp do_update(%{id: id} = changes, info, update_fn) do
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
{:ok, process_spec} <- process_spec(%{id: id}, info),
:ok <- ensure_update_permission(user, process_spec),
{:ok, uploads} <- UploadResolver.upload(user, changes, info),
changes = Map.merge(changes, uploads),
{:ok, process_spec} <- update_fn.(process_spec, changes) do
{:ok, %{process_specification: process_spec}}
end
end
def delete_process_spec(%{id: id}, info) do
Repo.transact_with(fn ->
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
......
......@@ -8,18 +8,14 @@ defmodule ValueFlows.Knowledge.ProcessSpecification do
alias Ecto.Changeset
alias CommonsPub.Users.User
#
# alias CommonsPub.Communities.Community
# alias ValueFlows.Knowledge.Action
alias ValueFlows.Knowledge.ProcessSpecification
# alias Measurement.Measure
@type t :: %__MODULE__{}
pointable_schema do
field(:name, :string)
field(:note, :string)
# belongs_to(:image, Content)
field(:classified_as, {:array, :string}, virtual: true)
......@@ -44,23 +40,7 @@ defmodule ValueFlows.Knowledge.ProcessSpecification do
end
@required ~w(name is_public)a
@cast @required ++ ~w(note classified_as is_disabled)a
def create_changeset(
%User{} = creator,
%{id: _} = context,
attrs
) do
%ProcessSpecification{}
|> Changeset.cast(attrs, @cast)
|> Changeset.validate_required(@required)
|> Changeset.change(
creator_id: creator.id,
context_id: context.id,
is_public: true
)
|> common_changeset()
end
@cast @required ++ ~w(note classified_as is_disabled context_id)a
def create_changeset(
%User{} = creator,
......@@ -76,17 +56,6 @@ defmodule ValueFlows.Knowledge.ProcessSpecification do
|> common_changeset()
end
def update_changeset(
%ProcessSpecification{} = process_spec,
%{id: _} = context,
attrs
) do
process_spec
|> Changeset.cast(attrs, @cast)
|> Changeset.change(context_id: context.id)
|> common_changeset()
end
def update_changeset(%ProcessSpecification{} = process_spec, attrs) do
process_spec
|> Changeset.cast(attrs, @cast)
......
# SPDX-License-Identifier: AGPL-3.0-only
defmodule ValueFlows.Knowledge.ProcessSpecification.ProcessSpecifications do
import CommonsPub.Common, only: [maybe_put: 3]
alias CommonsPub.{Activities, Common, Feeds, Repo}
alias CommonsPub.GraphQL.{Fields, Page}
alias CommonsPub.Contexts
alias CommonsPub.Feeds.FeedActivities
alias CommonsPub.Users.User
# alias CommonsPub.Meta.Pointers
# alias Measurement.Measure
alias ValueFlows.Knowledge.ProcessSpecification
alias ValueFlows.Knowledge.ProcessSpecification.Queries
# alias ValueFlows.Knowledge.Action
# alias ValueFlows.Knowledge.Action.Actions
def cursor(), do: &[&1.id]
def test_cursor(), do: &[&1["id"]]
......@@ -86,26 +84,12 @@ defmodule ValueFlows.Knowledge.ProcessSpecification.ProcessSpecifications do
## mutations
# @spec create(User.t(), Community.t(), attrs :: map) :: {:ok, ProcessSpecification.t()} | {:error, Changeset.t()}
def create(%User{} = creator, %{id: _id} = context, attrs)
when is_map(attrs) do
do_create(creator, attrs, fn ->
ProcessSpecification.create_changeset(creator, context, attrs)
end)
end
# @spec create(User.t(), attrs :: map) :: {:ok, ProcessSpecification.t()} | {:error, Changeset.t()}
@spec create(User.t(), attrs :: map) :: {:ok, ProcessSpecification.t()} | {:error, Changeset.t()}
def create(%User{} = creator, attrs) when is_map(attrs) do
do_create(creator, attrs, fn ->
ProcessSpecification.create_changeset(creator, attrs)
end)
end
def do_create(creator, attrs, changeset_fn) do
Repo.transact_with(fn ->
cs = changeset_fn.()
attrs = prepare_attrs(attrs)
with {:ok, item} <- Repo.insert(cs),
with {:ok, item} <- Repo.insert(ProcessSpecification.create_changeset(creator, attrs)),
{:ok, item} <- ValueFlows.Util.try_tag_thing(creator, item, attrs),
act_attrs = %{verb: "created", is_local: true},
# FIXME
......@@ -166,20 +150,10 @@ defmodule ValueFlows.Knowledge.ProcessSpecification.ProcessSpecifications do
# TODO: take the user who is performing the update
# @spec update(%ProcessSpecification{}, attrs :: map) :: {:ok, ProcessSpecification.t()} | {:error, Changeset.t()}
def update(%ProcessSpecification{} = process_spec, attrs) do
do_update(process_spec, attrs, &ProcessSpecification.update_changeset(&1, attrs))
end
def update(%ProcessSpecification{} = process_spec, %{id: _id} = context, attrs) do
do_update(process_spec, attrs, &ProcessSpecification.update_changeset(&1, context, attrs))
end
def do_update(process_spec, attrs, changeset_fn) do
Repo.transact_with(fn ->
cs =
process_spec
|> changeset_fn.()
attrs = prepare_attrs(attrs)
with {:ok, process_spec} <- Repo.update(cs),
with {:ok, process_spec} <- Repo.update(ProcessSpecification.update_changeset(process_spec, attrs)),
{:ok, process_spec} <- ValueFlows.Util.try_tag_thing(nil, process_spec, attrs),
:ok <- publish(process_spec, :updated) do
{:ok, process_spec}
......@@ -221,4 +195,11 @@ defmodule ValueFlows.Knowledge.ProcessSpecification.ProcessSpecifications do
:ok
end
defp prepare_attrs(attrs) do
attrs
|> maybe_put(:context_id,
attrs |> Map.get(:in_scope_of) |> CommonsPub.Common.maybe(&List.first/1)
)
end
end
......@@ -180,39 +180,6 @@ defmodule ValueFlows.Knowledge.ResourceSpecification.GraphQL do
})
end
def create_resource_spec(
%{resource_specification: %{in_scope_of: context_ids} = resource_spec_attrs},
info
)
when is_list(context_ids) do
# FIXME: support multiple contexts?
context_id = List.first(context_ids)
create_resource_spec(