Commit b6867519 authored by Antonis Kalou's avatar Antonis Kalou

WIP: Cleanup ValueFlows.Planning.Intent

parent e4804c3a
......@@ -12,10 +12,10 @@ defmodule ValueFlows.Planning.Intent do
alias Measurement.Measure
alias ValueFlows.Knowledge.Action
alias ValueFlows.Planning.Intent
alias ValueFlows.Knowledge.ResourceSpecification
alias ValueFlows.Proposal
alias ValueFlows.Proposal.ProposedIntent
alias ValueFlows.Observation.EconomicResource
alias ValueFlows.Observation.Process
......@@ -38,6 +38,7 @@ defmodule ValueFlows.Planning.Intent do
field(:has_end, :utc_datetime_usec)
field(:has_point_in_time, :utc_datetime_usec)
field(:due, :utc_datetime_usec)
field(:finished, :boolean, default: false)
# array of URI
field(:resource_classified_as, {:array, :string})
......@@ -62,8 +63,6 @@ defmodule ValueFlows.Planning.Intent do
belongs_to(:creator, User)
belongs_to(:context, Pointers.Pointer)
field(:finished, :boolean, default: false)
# field(:deletable, :boolean) # TODO - virtual field? how is it calculated?
field(:is_public, :boolean, virtual: true)
......@@ -82,59 +81,26 @@ defmodule ValueFlows.Planning.Intent do
timestamps(inserted_at: false)
end
@required ~w(name is_public)a
@cast @required ++ ~w(note at_location_id is_disabled image_id)a
def create_changeset(
%User{} = creator,
%Action{} = action,
%{id: _} = context,
attrs
) do
%Intent{}
|> Changeset.cast(attrs, @cast)
|> Changeset.validate_required(@required)
|> Changeset.change(
creator_id: creator.id,
context_id: context.id,
# TODO: move action to context and validate that it's a valid action
action_id: action.id,
is_public: true
)
|> common_changeset()
end
@required ~w(name is_public action_id)a
@cast @required ++
~w(note at_location_id is_disabled image_id context_id input_of_id output_of_id)a ++
~w(resource_conforms_to_id resource_inventoried_as_id provider_id receiver_id)a
def create_changeset(
%User{} = creator,
%Action{} = action,
attrs
) do
%Intent{}
def create_changeset(%User{} = creator, attrs) do
%__MODULE__{}
|> Changeset.cast(attrs, @cast)
|> Changeset.validate_required(@required)
|> Changeset.change(
creator_id: creator.id,
action_id: action.id,
is_public: true
)
|> common_changeset()
end
def update_changeset(
%Intent{} = intent,
%{id: _} = context,
attrs
) do
intent
|> Changeset.cast(attrs, @cast)
|> Changeset.change(context_id: context.id)
|> common_changeset()
|> common_changeset(attrs)
end
def update_changeset(%Intent{} = intent, attrs) do
def update_changeset(%__MODULE__{} = intent, attrs) do
intent
|> Changeset.cast(attrs, @cast)
|> common_changeset()
|> common_changeset(attrs)
end
def measure_fields do
......@@ -149,27 +115,9 @@ defmodule ValueFlows.Planning.Intent do
end)
end
def change_at_location(changeset, %Geolocation{} = location) do
Changeset.change(changeset,
at_location: location,
at_location_id: location.id
)
end
def change_action(changeset, %Action{} = action) do
Changeset.change(changeset, action_id: action.id)
end
def change_provider(changeset, %{id: _} = provider) do
Changeset.change(changeset, provider_id: provider.id)
end
def change_receiver(changeset, %{id: _} = receiver) do
Changeset.change(changeset, receiver_id: receiver.id)
end
defp common_changeset(changeset) do
defp common_changeset(changeset, attrs) do
changeset
|> change_measures(attrs)
|> change_public()
|> change_disabled()
|> Changeset.foreign_key_constraint(
......
......@@ -6,42 +6,23 @@ defmodule ValueFlows.Planning.Intent.GraphQL do
require Logger
alias CommonsPub.{
# Activities,
# Communities,
GraphQL,
Repo
# User
}
alias CommonsPub.{GraphQL, Repo}
alias CommonsPub.GraphQL.{
ResolveField,
# ResolveFields,
# ResolvePage,
ResolvePages,
ResolveRootPage,
FetchPage
# FetchPages,
# CommonResolver
}
# alias CommonsPub.Resources.Resource
# alias CommonsPub.Common.Enums
alias CommonsPub.Meta.Pointers
# alias CommonsPub.Communities.Community
# alias CommonsPub.Web.GraphQL.CommunitiesResolver
alias ValueFlows.Planning.Intent
alias ValueFlows.Planning.Intent.Intents
alias ValueFlows.Planning.Intent.Queries
alias ValueFlows.Knowledge.Action.Actions
# alias CommonsPub.Web.GraphQL.CommonResolver
alias CommonsPub.Web.GraphQL.UploadResolver
# SDL schema import
# use Absinthe.Schema.Notation
# import_sdl path: "lib/value_flows/graphql/schemas/planning.gql"
## resolvers
def intent(%{id: id}, info) do
......@@ -359,76 +340,25 @@ defmodule ValueFlows.Planning.Intent.GraphQL do
end
end
def create_intent(%{intent: %{in_scope_of: context_ids} = intent_attrs}, info)
when is_list(context_ids) do
# FIXME: support multiple contexts?
context_id = List.first(context_ids)
create_intent(
%{intent: Map.merge(intent_attrs, %{in_scope_of: context_id})},
info
)
end
def create_intent(%{intent: %{in_scope_of: context_id, action: action_id} = intent_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
Repo.transact_with(fn ->
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
{:ok, action} <- Actions.action(action_id),
{:ok, pointer} <- Pointers.one(id: context_id),
context = Pointers.follow!(pointer),
{:ok, uploads} <- UploadResolver.upload(user, intent_attrs, info),
intent_attrs = Map.merge(intent_attrs, uploads),
intent_attrs = Map.merge(intent_attrs, %{is_public: true}),
{:ok, intent} <- Intents.create(user, action, context, intent_attrs) do
{:ok, %{intent: %{intent | action: action}}}
end
end)
end
# FIXME: duplication!
def create_intent(%{intent: %{action: action_id} = intent_attrs}, info) do
def create_intent(%{intent: intent_attrs}, info) do
Repo.transact_with(fn ->
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
{:ok, action} <- Actions.action(action_id),
{:ok, uploads} <- UploadResolver.upload(user, intent_attrs, info),
intent_attrs = Map.merge(intent_attrs, uploads),
intent_attrs = Map.merge(intent_attrs, %{is_public: true}),
{:ok, intent} <- Intents.create(user, action, intent_attrs) do
{:ok, %{intent: %{intent | action: action}}}
{:ok, intent} <- Intents.create(user, intent_attrs) do
{:ok, %{intent: intent}}
end
end)
end
def update_intent(%{intent: %{in_scope_of: context_ids} = changes}, info) do
context_id = List.first(context_ids)
Repo.transact_with(fn ->
do_update(changes, info, fn intent, changes ->
with {:ok, pointer} <- Pointers.one(id: context_id) do
context = Pointers.follow!(pointer)
Intents.update(intent, context, changes)
end
end)
end)
end
def update_intent(%{intent: changes}, info) do
Repo.transact_with(fn ->
do_update(changes, info, fn intent, changes ->
Intents.update(intent, changes)
end)
end)
end
defp do_update(%{id: id} = changes, info, update_fn) do
def update_intent(%{intent: %{id: id} = changes}, info) do
with {:ok, user} <- GraphQL.current_user_or_not_logged_in(info),
{:ok, intent} <- intent(%{id: id}, info),
:ok <- ensure_update_permission(user, intent),
{:ok, uploads} <- UploadResolver.upload(user, changes, info),
changes = Map.merge(changes, uploads),
{:ok, intent} <- update_fn.(intent, changes) do
{:ok, intent} <- Intents.update(intent, changes) do
{:ok, %{intent: intent}}
end
end
......
......@@ -62,20 +62,6 @@ defmodule ValueFlows.Planning.Intent.Queries do
join(q, jq, [intent: c], q in assoc(c, :available_quantity), as: :available_quantity)
end
# def join_to(q, :provider, jq) do
# join q, jq, [follow: f], c in assoc(f, :provider), as: :pointer
# end
# def join_to(q, :receiver, jq) do
# join q, jq, [follow: f], c in assoc(f, :receiver), as: :pointer
# end
# def join_to(q, :follower_count, jq) do
# join q, jq, [intent: c],
# f in FollowerCount, on: c.id == f.context_id,
# as: :follower_count
# end
### filter/2
## by many
......@@ -270,19 +256,18 @@ defmodule ValueFlows.Planning.Intent.Queries do
select(q, [intent: c], {field(c, ^key), count(c.id)})
end
def filter(q, {:preload, :provider}) do
preload(q, [pointer: p], provider: p)
end
def filter(q, {:preload, :receiver}) do
preload(q, [pointer: p], receiver: p)
end
def filter(q, {:preload, :at_location}) do
def filter(q, {:preload, :all}) do
q
|> join_to(:geolocation)
|> preload(:at_location)
# preload(q, [geolocation: g], at_location: g)
|> preload([
:provider,
:receiver,
:input_of,
:output_of,
:creator,
:context,
:at_location,
])
|> filter({:preload, :quantities})
end
def filter(q, {:preload, :quantities}) do
......
# SPDX-License-Identifier: AGPL-3.0-only
defmodule ValueFlows.Planning.Intent.Intents do
import CommonsPub.Common, only: [maybe_put: 3]
alias CommonsPub.{Activities, Common, Feeds, Repo}
alias CommonsPub.GraphQL.{Fields, Page}
alias CommonsPub.Contexts
......@@ -11,8 +13,6 @@ defmodule ValueFlows.Planning.Intent.Intents do
# alias Measurement.Measure
alias ValueFlows.Planning.Intent
alias ValueFlows.Planning.Intent.Queries
alias ValueFlows.Knowledge.Action
alias ValueFlows.Knowledge.Action.Actions
def cursor(), do: &[&1.id]
def test_cursor(), do: &[&1["id"]]
......@@ -85,50 +85,28 @@ defmodule ValueFlows.Planning.Intent.Intents do
)
end
## mutations
# @spec create(User.t(), Community.t(), attrs :: map) :: {:ok, Intent.t()} | {:error, Changeset.t()}
def create(%User{} = creator, %Action{} = action, nil, attrs)
when is_map(attrs) do
do_create(creator, attrs, fn ->
Intent.create_changeset(creator, action, attrs)
end)
def preload_all(%Intent{} = intent) do
# shouldn't fail
{:ok, intent} = one(id: intent.id, preload: :all)
intent
end
def create(%User{} = creator, %Action{} = action, %{id: _id} = context, attrs)
when is_map(attrs) do
do_create(creator, attrs, fn ->
Intent.create_changeset(creator, action, context, attrs)
end)
end
# @spec create(User.t(), attrs :: map) :: {:ok, Intent.t()} | {:error, Changeset.t()}
def create(%User{} = creator, %Action{} = action, attrs) when is_map(attrs) do
do_create(creator, attrs, fn ->
Intent.create_changeset(creator, action, attrs)
end)
end
## mutations
def do_create(creator, attrs, changeset_fn) do
attrs = parse_measurement_attrs(attrs)
@spec create(User.t(), attrs :: map) :: {:ok, Intent.t()} | {:error, Changeset.t()}
def create(%User{} = creator, attrs) when is_map(attrs) do
attrs = prepare_attrs(attrs)
Repo.transact_with(fn ->
cs =
changeset_fn.()
|> Intent.change_measures(attrs)
with {:ok, cs} <- change_at_location(cs, attrs),
{:ok, cs} <- change_agent(cs, attrs),
{:ok, item} <- Repo.insert(cs),
{:ok, item} <- ValueFlows.Util.try_tag_thing(nil, item, attrs),
with {:ok, intent} <- Repo.insert(Intent.create_changeset(creator, attrs)),
{:ok, intent} <- ValueFlows.Util.try_tag_thing(nil, intent, attrs),
act_attrs = %{verb: "created", is_local: true},
# FIXME
{:ok, activity} <- Activities.create(creator, item, act_attrs),
:ok <- publish(creator, item, activity, :created) do
item = %{item | creator: creator}
index(item)
{:ok, item}
{:ok, activity} <- Activities.create(creator, intent, act_attrs),
:ok <- publish(creator, intent, activity, :created) do
intent = %{intent | creator: creator}
index(intent)
{:ok, preload_all(intent)}
end
end)
end
......@@ -181,37 +159,13 @@ defmodule ValueFlows.Planning.Intent.Intents do
# TODO: take the user who is performing the update
# @spec update(%Intent{}, attrs :: map) :: {:ok, Intent.t()} | {:error, Changeset.t()}
def update(%Intent{} = intent, attrs) do
do_update(intent, attrs, &Intent.update_changeset(&1, attrs))
end
def update(%Intent{} = intent, %{id: _id} = context, attrs) do
do_update(intent, attrs, &Intent.update_changeset(&1, context, attrs))
end
def do_update(intent, attrs, changeset_fn) do
attrs = parse_measurement_attrs(attrs)
Repo.transact_with(fn ->
intent =
Repo.preload(intent, [
:available_quantity,
:resource_quantity,
:effort_quantity,
:at_location
])
cs =
intent
|> changeset_fn.()
|> Intent.change_measures(attrs)
with {:ok, cs} <- change_at_location(cs, attrs),
{:ok, cs} <- change_agent(cs, attrs),
{:ok, cs} <- change_action(cs, attrs),
{:ok, intent} <- Repo.update(cs),
with {:ok, intent} <- Repo.update(Intent.update_changeset(intent, attrs)),
{:ok, intent} <- ValueFlows.Util.try_tag_thing(nil, intent, attrs),
:ok <- publish(intent, :updated) do
{:ok, intent}
{:ok, preload_all(intent)}
end
end)
end
......@@ -251,46 +205,22 @@ defmodule ValueFlows.Planning.Intent.Intents do
:ok
end
defp change_agent(changeset, attrs) do
with {:ok, changeset} <- change_provider(changeset, attrs) do
change_receiver(changeset, attrs)
end
end
defp change_provider(changeset, %{provider: provider_id}) do
with {:ok, pointer} <- Pointers.one(id: provider_id) do
provider = Pointers.follow!(pointer)
{:ok, Intent.change_provider(changeset, provider)}
end
end
defp change_provider(changeset, _attrs), do: {:ok, changeset}
defp change_receiver(changeset, %{receiver: receiver_id}) do
with {:ok, pointer} <- Pointers.one(id: receiver_id) do
receiver = Pointers.follow!(pointer)
{:ok, Intent.change_receiver(changeset, receiver)}
end
end
defp change_receiver(changeset, _attrs), do: {:ok, changeset}
defp change_action(changeset, %{action: action_id}) do
with {:ok, action} <- Actions.action(action_id) do
{:ok, Intent.change_action(changeset, action)}
end
end
defp change_action(changeset, _attrs), do: {:ok, changeset}
defp change_at_location(changeset, %{at_location: id}) do
with {:ok, location} <- Geolocations.one([:default, id: id]) do
{:ok, Intent.change_at_location(changeset, location)}
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(:at_location_id, Map.get(attrs, :at_location))
|> maybe_put(:provider_id, Map.get(attrs, :provider))
|> maybe_put(:receiver_id, Map.get(attrs, :receiver))
|> maybe_put(:input_of_id, Map.get(attrs, :input_of))
|> maybe_put(:output_of_id, Map.get(attrs, :output_of))
|> maybe_put(:resource_conforms_to_id, Map.get(attrs, :resource_conforms_to))
|> maybe_put(:resource_inventoried_as_id, Map.get(attrs, :resource_inventoried_as_id))
|> parse_measurement_attrs()
end
defp change_at_location(changeset, _attrs), do: {:ok, changeset}
defp parse_measurement_attrs(attrs) do
Enum.reduce(attrs, %{}, fn {k, v}, acc ->
if is_map(v) and Map.has_key?(v, :has_unit) do
......
......@@ -37,13 +37,6 @@ defmodule ValueFlows.Proposal.ProposedIntentGraphQL do
end
def publishes_edge(%{id: proposal_id}, _, _info) do
# ResolveFields.run(%ResolveFields{
# module: __MODULE__,
# fetcher: :fetch_proposed_intents,
# context: proposal_id,
# info: info
# })
Proposals.many_proposed_intents([:default, published_in_id: proposal_id])
end
......@@ -59,15 +52,6 @@ defmodule ValueFlows.Proposal.ProposedIntentGraphQL do
Proposals.one_proposed_intent([:default, id: id])
end
# def fetch_proposed_intents(_info, _ids) do
# FetchFields.run(%FetchFields{
# queries: Proposal.ProposedIntentQueries,
# query: ProposedIntent,
# group_fn: & &1.id,
# filters: [:deleted, published_in_id: ids]
# })
# end
def propose_intent(
%{published_in: published_in_proposal_id, publishes: publishes_intent_id} = params,
info
......
......@@ -245,14 +245,14 @@ defmodule ValueFlows.Simulate do
claim
end
def fake_intent!(user, unit \\ nil, context \\ nil, overrides \\ %{})
def fake_intent!(user, unit \\ nil, overrides \\ %{})
def fake_intent!(user, unit, context, overrides) when is_nil(unit) do
{:ok, intent} = Intents.create(user, action(), context, intent(overrides))
def fake_intent!(user, unit, overrides) when is_nil(unit) do
{:ok, intent} = Intents.create(user, intent(overrides))
intent
end
def fake_intent!(user, unit, context, overrides) do
def fake_intent!(user, unit, overrides) do
measure_attrs = %{unit_id: unit.id}
measures = %{
......@@ -262,7 +262,7 @@ defmodule ValueFlows.Simulate do
}
overrides = Map.merge(overrides, measures)
{:ok, intent} = Intents.create(user, action(), context, intent(overrides))
{:ok, intent} = Intents.create(user, intent(overrides))
intent
end
......
......@@ -39,7 +39,7 @@ defmodule ValueFlows.Planning.Intent.GraphQLTest do
parent = fake_user!()
intent = fake_intent!(user, unit, parent)
intent = fake_intent!(user, unit, %{in_scope_of: [parent.id]})
proposal = fake_proposal!(user)
......@@ -110,7 +110,7 @@ defmodule ValueFlows.Planning.Intent.GraphQLTest do
test "returns the scope of the intent" do
user = fake_user!()
parent = fake_user!()
intent = fake_intent!(user, nil, parent)
intent = fake_intent!(user, %{in_scope_of: [parent.id]})
q = intent_query(fields: [in_scope_of: [:__typename]])
conn = user_conn(user)
......
......@@ -33,7 +33,7 @@ defmodule ValueFlows.Planning.Intent.IntentsTest do
test "can create an intent" do
user = fake_user!()
assert {:ok, intent} = Intents.create(user, action(), intent())
assert {:ok, intent} = Intents.create(user, intent())
assert_intent(intent)
end
......@@ -47,7 +47,7 @@ defmodule ValueFlows.Planning.Intent.IntentsTest do
available_quantity: measure(%{unit_id: unit.id})
}