mirror of
https://github.com/valitydev/fistful-server.git
synced 2024-11-06 02:35:18 +00:00
[WIP] Make up some basic identity challenge
This commit is contained in:
parent
7a8588f327
commit
3fa9e30889
@ -15,19 +15,56 @@
|
|||||||
|
|
||||||
%% API
|
%% API
|
||||||
|
|
||||||
-type party() :: ff_party:id().
|
-type id(T) :: T.
|
||||||
-type provider() :: ff_provider:provider().
|
-type timestamp() :: machinery:timestamp().
|
||||||
-type contract() :: ff_party:contract().
|
-type party() :: ff_party:id().
|
||||||
|
-type provider() :: ff_provider:provider().
|
||||||
|
-type contract() :: ff_party:contract().
|
||||||
|
-type class() :: ff_identity_class:class().
|
||||||
|
-type level() :: ff_identity_class:level().
|
||||||
|
-type challenge_class() :: ff_identity_class:challenge_class().
|
||||||
|
|
||||||
-type identity() :: #{
|
-type identity() :: #{
|
||||||
|
id := id(_),
|
||||||
party := party(),
|
party := party(),
|
||||||
provider := provider(),
|
provider := provider(),
|
||||||
class := class(),
|
class := class(),
|
||||||
contract => contract()
|
level := level(),
|
||||||
|
contract => contract(),
|
||||||
|
challenges => #{id(_) => challenge()}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-type challenge() :: #{
|
||||||
|
identity := id(_),
|
||||||
|
class := challenge_class(),
|
||||||
|
proofs := [proof()],
|
||||||
|
status := challenge_status()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-type proof() ::
|
||||||
|
_TODO.
|
||||||
|
|
||||||
|
-type challenge_status() ::
|
||||||
|
pending |
|
||||||
|
{completed , challenge_completion()} |
|
||||||
|
{failed , challenge_failure()} |
|
||||||
|
cancelled .
|
||||||
|
|
||||||
|
-type challenge_completion() :: #{
|
||||||
|
valid_until => timestamp()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-type challenge_failure() ::
|
||||||
|
_TODO.
|
||||||
|
|
||||||
-type ev() ::
|
-type ev() ::
|
||||||
{contract_set, contract()}.
|
{contract_set , contract()} |
|
||||||
|
{level_changed , level()} |
|
||||||
|
{challenge_started , id(_), challenge()} |
|
||||||
|
{challenge , id(_), challenge_ev()} .
|
||||||
|
|
||||||
|
-type challenge_ev() ::
|
||||||
|
{status_changed , challenge_status()}.
|
||||||
|
|
||||||
-type outcome() ::
|
-type outcome() ::
|
||||||
[ev()].
|
[ev()].
|
||||||
@ -35,42 +72,7 @@
|
|||||||
-export_type([identity/0]).
|
-export_type([identity/0]).
|
||||||
-export_type([ev/0]).
|
-export_type([ev/0]).
|
||||||
|
|
||||||
%% TODO
|
-export([id/1]).
|
||||||
%% - Factor out into dedicated module
|
|
||||||
|
|
||||||
-type class_id() :: binary().
|
|
||||||
-type contract_template_ref() :: dmsl_domain_thrift:'ContractTemplateRef'().
|
|
||||||
|
|
||||||
-type class() :: #{
|
|
||||||
contract_template_ref := contract_template_ref(),
|
|
||||||
initial_level_id := level_id(),
|
|
||||||
levels := #{level_id() => level()},
|
|
||||||
challenges := #{challenge_id() => challenge()}
|
|
||||||
}.
|
|
||||||
|
|
||||||
-type level_id() :: binary().
|
|
||||||
-type contractor_level() :: dmsl_domain_thrift:'ContractorIdentificationLevel'().
|
|
||||||
|
|
||||||
-type level() :: #{
|
|
||||||
name := binary(),
|
|
||||||
contractor_level := contractor_level()
|
|
||||||
}.
|
|
||||||
|
|
||||||
-type challenge_id() :: binary().
|
|
||||||
|
|
||||||
-type challenge() :: #{
|
|
||||||
name := binary(),
|
|
||||||
base_level_id := level_id(),
|
|
||||||
target_level_id := level_id()
|
|
||||||
}.
|
|
||||||
|
|
||||||
-export_type([class_id/0]).
|
|
||||||
-export_type([class/0]).
|
|
||||||
-export_type([level_id/0]).
|
|
||||||
-export_type([level/0]).
|
|
||||||
-export_type([challenge_id/0]).
|
|
||||||
-export_type([challenge/0]).
|
|
||||||
|
|
||||||
-export([provider/1]).
|
-export([provider/1]).
|
||||||
-export([party/1]).
|
-export([party/1]).
|
||||||
-export([class/1]).
|
-export([class/1]).
|
||||||
@ -80,27 +82,33 @@
|
|||||||
|
|
||||||
-export([create/3]).
|
-export([create/3]).
|
||||||
-export([setup_contract/1]).
|
-export([setup_contract/1]).
|
||||||
-export([start_challenge/2]).
|
-export([start_challenge/4]).
|
||||||
|
|
||||||
|
-export([challenge/2]).
|
||||||
|
-export([challenge_status/1]).
|
||||||
|
|
||||||
|
-export([poll_challenge_completion/2]).
|
||||||
|
|
||||||
-export([apply_event/2]).
|
-export([apply_event/2]).
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
-export([contract_template/1]).
|
|
||||||
-export([initial_level/1]).
|
|
||||||
|
|
||||||
%% Pipeline
|
%% Pipeline
|
||||||
|
|
||||||
-import(ff_pipeline, [do/1, unwrap/1]).
|
-import(ff_pipeline, [do/1, unwrap/1, unwrap/2, expect/2, flip/1, valid/2]).
|
||||||
|
|
||||||
%% Accessors
|
%% Accessors
|
||||||
|
|
||||||
|
-spec id(identity()) -> id(_).
|
||||||
|
id(#{id := V}) -> V.
|
||||||
|
|
||||||
-spec provider(identity()) -> provider().
|
-spec provider(identity()) -> provider().
|
||||||
provider(#{provider := V}) -> V.
|
provider(#{provider := V}) -> V.
|
||||||
|
|
||||||
-spec class(identity()) -> class().
|
-spec class(identity()) -> class().
|
||||||
class(#{class := V}) -> V.
|
class(#{class := V}) -> V.
|
||||||
|
|
||||||
|
-spec level(identity()) -> level().
|
||||||
|
level(#{level := V}) -> V.
|
||||||
|
|
||||||
-spec party(identity()) -> party().
|
-spec party(identity()) -> party().
|
||||||
party(#{party := V}) -> V.
|
party(#{party := V}) -> V.
|
||||||
|
|
||||||
@ -118,30 +126,6 @@ contract(V) ->
|
|||||||
is_accessible(Identity) ->
|
is_accessible(Identity) ->
|
||||||
ff_party:is_accessible(party(Identity)).
|
ff_party:is_accessible(party(Identity)).
|
||||||
|
|
||||||
%% Class
|
|
||||||
|
|
||||||
-spec contract_template(class()) -> contract_template_ref().
|
|
||||||
contract_template(#{contract_template_ref := V}) -> V.
|
|
||||||
|
|
||||||
-spec initial_level(class()) ->
|
|
||||||
level().
|
|
||||||
|
|
||||||
initial_level(#{initial_level_id := V} = Identity) ->
|
|
||||||
{ok, Level} = level(V, Identity),
|
|
||||||
Level.
|
|
||||||
|
|
||||||
-spec level(level_id(), class()) ->
|
|
||||||
{ok, level()} |
|
|
||||||
{error, notfound}.
|
|
||||||
|
|
||||||
level(ID, #{levels := Levels}) ->
|
|
||||||
ff_map:find(ID, Levels).
|
|
||||||
|
|
||||||
%% Level
|
|
||||||
|
|
||||||
-spec contractor_level(level()) -> contractor_level().
|
|
||||||
contractor_level(#{contractor_level := V}) -> V.
|
|
||||||
|
|
||||||
%% Constructor
|
%% Constructor
|
||||||
|
|
||||||
-spec create(party(), provider(), class()) ->
|
-spec create(party(), provider(), class()) ->
|
||||||
@ -152,7 +136,8 @@ create(Party, Provider, Class) ->
|
|||||||
#{
|
#{
|
||||||
party => Party,
|
party => Party,
|
||||||
provider => Provider,
|
provider => Provider,
|
||||||
class => Class
|
class => Class,
|
||||||
|
level => ff_identity_class:initial_level(Class)
|
||||||
}
|
}
|
||||||
end).
|
end).
|
||||||
|
|
||||||
@ -167,20 +152,78 @@ setup_contract(Identity) ->
|
|||||||
Class = class(Identity),
|
Class = class(Identity),
|
||||||
Contract = unwrap(ff_party:create_contract(party(Identity), #{
|
Contract = unwrap(ff_party:create_contract(party(Identity), #{
|
||||||
payinst => ff_provider:payinst(provider(Identity)),
|
payinst => ff_provider:payinst(provider(Identity)),
|
||||||
contract_template => contract_template(Class),
|
contract_template => ff_identity_class:contract_template(Class),
|
||||||
contractor_level => contractor_level(initial_level(Class))
|
contractor_level => ff_identity_class:contractor_level(level(Identity))
|
||||||
})),
|
})),
|
||||||
[{contract_set, Contract}]
|
[{contract_set, Contract}]
|
||||||
end).
|
end).
|
||||||
|
|
||||||
-spec start_challenge(level(), identity()) ->
|
%%
|
||||||
|
|
||||||
|
-spec start_challenge(id(_), challenge_class(), [proof()], identity()) ->
|
||||||
{ok, outcome()} |
|
{ok, outcome()} |
|
||||||
{error,
|
{error,
|
||||||
{level, invalid}
|
exists |
|
||||||
|
{level, ff_identity_class:level()} |
|
||||||
|
_IdentityClassError
|
||||||
}.
|
}.
|
||||||
|
|
||||||
start_challenge(Level, Identity) ->
|
start_challenge(ChallengeID, ChallengeClass, Proofs, Identity) ->
|
||||||
oops.
|
do(fun () ->
|
||||||
|
Class = class(Identity),
|
||||||
|
BaseLevel = ff_identity_class:base_level(ChallengeClass, Class),
|
||||||
|
notfound = expect(exists, flip(challenge(ChallengeID, Identity))),
|
||||||
|
ok = unwrap(level, valid(BaseLevel, level(Identity))),
|
||||||
|
Challenge = unwrap(create_challenge(ChallengeID, id(Identity), ChallengeClass, Proofs)),
|
||||||
|
[{challenge_started, ChallengeID, Challenge}]
|
||||||
|
end).
|
||||||
|
|
||||||
|
create_challenge(_ID, IdentityID, Class, Proofs) ->
|
||||||
|
do(fun () ->
|
||||||
|
#{
|
||||||
|
identity => IdentityID,
|
||||||
|
class => Class,
|
||||||
|
proofs => Proofs,
|
||||||
|
status => pending
|
||||||
|
}
|
||||||
|
end).
|
||||||
|
|
||||||
|
-spec challenge(id(_), identity()) ->
|
||||||
|
{ok, challenge()} |
|
||||||
|
{error, notfound}.
|
||||||
|
|
||||||
|
challenge(ChallengeID, #{challenges := Challenges}) ->
|
||||||
|
ff_map:find(ChallengeID, Challenges).
|
||||||
|
|
||||||
|
-spec challenge_status(challenge()) ->
|
||||||
|
challenge_status().
|
||||||
|
|
||||||
|
challenge_status(#{challenge_status := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
-spec challenge_class(challenge()) ->
|
||||||
|
challenge_class().
|
||||||
|
|
||||||
|
challenge_class(#{class := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
-spec poll_challenge_completion(id(_), challenge()) ->
|
||||||
|
{ok, outcome()} |
|
||||||
|
{error,
|
||||||
|
notfound |
|
||||||
|
challenge_status()
|
||||||
|
}.
|
||||||
|
|
||||||
|
poll_challenge_completion(ID, Identity) ->
|
||||||
|
do(fun () ->
|
||||||
|
Challenge = unwrap(challenge(ID, Identity)),
|
||||||
|
ok = unwrap(valid(pending, challenge_status(Challenge))),
|
||||||
|
TargetLevel = ff_identity_class:target_level(challenge_class(Challenge)),
|
||||||
|
[
|
||||||
|
{challenge, ID, {status_changed, {completed, #{}}}},
|
||||||
|
{level_changed, TargetLevel}
|
||||||
|
]
|
||||||
|
end).
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -188,4 +231,20 @@ start_challenge(Level, Identity) ->
|
|||||||
identity().
|
identity().
|
||||||
|
|
||||||
apply_event({contract_set, C}, Identity) ->
|
apply_event({contract_set, C}, Identity) ->
|
||||||
Identity#{contract => C}.
|
Identity#{contract => C};
|
||||||
|
apply_event({level_changed, L}, Identity) ->
|
||||||
|
Identity#{level := L};
|
||||||
|
apply_event({challenge_started, ID, C}, Identity) ->
|
||||||
|
Cs = maps:get(challenges, Identity, #{}),
|
||||||
|
Identity#{
|
||||||
|
challenges => Cs#{ID => C}
|
||||||
|
};
|
||||||
|
apply_event({challenge, ID, Ev}, Identity = #{challenges := Cs}) ->
|
||||||
|
Identity#{
|
||||||
|
challenges := Cs#{
|
||||||
|
ID := apply_challenge_event(Ev, maps:get(ID, Cs))
|
||||||
|
}
|
||||||
|
}.
|
||||||
|
|
||||||
|
apply_challenge_event({status_changed, S}, Challenge) ->
|
||||||
|
Challenge#{status := S}.
|
||||||
|
127
apps/fistful/src/ff_identity_class.erl
Normal file
127
apps/fistful/src/ff_identity_class.erl
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
%%%
|
||||||
|
%%% Identity class
|
||||||
|
%%%
|
||||||
|
|
||||||
|
-module(ff_identity_class).
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
-type id() :: binary().
|
||||||
|
|
||||||
|
-type class() :: #{
|
||||||
|
contract_template_ref := contract_template_ref(),
|
||||||
|
initial_level_id := level_id(),
|
||||||
|
levels := #{level_id() => level()},
|
||||||
|
challenge_classes := #{challenge_class_id() => challenge_class()}
|
||||||
|
}.
|
||||||
|
|
||||||
|
-type contract_template_ref() ::
|
||||||
|
dmsl_domain_thrift:'ContractTemplateRef'().
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
-type level_id() :: binary().
|
||||||
|
-type level() :: #{
|
||||||
|
name := binary(),
|
||||||
|
contractor_level := contractor_level()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-type contractor_level() ::
|
||||||
|
dmsl_domain_thrift:'ContractorIdentificationLevel'().
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
-type challenge_class_id() :: binary().
|
||||||
|
|
||||||
|
-type challenge_class() :: #{
|
||||||
|
name := binary(),
|
||||||
|
base_level_id := level_id(),
|
||||||
|
target_level_id := level_id()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-export([name/1]).
|
||||||
|
-export([contract_template/1]).
|
||||||
|
-export([initial_level/1]).
|
||||||
|
-export([level/2]).
|
||||||
|
-export([level_name/1]).
|
||||||
|
-export([contractor_level/1]).
|
||||||
|
-export([challenge_class/2]).
|
||||||
|
-export([base_level/2]).
|
||||||
|
-export([target_level/2]).
|
||||||
|
-export([challenge_class_name/1]).
|
||||||
|
|
||||||
|
-export_type([id/0]).
|
||||||
|
-export_type([class/0]).
|
||||||
|
-export_type([level_id/0]).
|
||||||
|
-export_type([level/0]).
|
||||||
|
-export_type([challenge_class_id/0]).
|
||||||
|
-export_type([challenge_class/0]).
|
||||||
|
|
||||||
|
%% Class
|
||||||
|
|
||||||
|
-spec name(class()) ->
|
||||||
|
binary().
|
||||||
|
|
||||||
|
name(#{name := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
-spec contract_template(class()) ->
|
||||||
|
contract_template_ref().
|
||||||
|
|
||||||
|
contract_template(#{contract_template_ref := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
-spec initial_level(class()) ->
|
||||||
|
level().
|
||||||
|
|
||||||
|
initial_level(#{initial_level_id := V} = Class) ->
|
||||||
|
{ok, Level} = level(V, Class), Level.
|
||||||
|
|
||||||
|
-spec level(level_id(), class()) ->
|
||||||
|
{ok, level()} |
|
||||||
|
{error, notfound}.
|
||||||
|
|
||||||
|
level(ID, #{levels := Levels}) ->
|
||||||
|
ff_map:find(ID, Levels).
|
||||||
|
|
||||||
|
-spec challenge_class(challenge_class_id(), class()) ->
|
||||||
|
{ok, challenge_class()} |
|
||||||
|
{error, notfound}.
|
||||||
|
|
||||||
|
challenge_class(ID, #{challenge_classs := ChallengeClasses}) ->
|
||||||
|
ff_map:find(ID, ChallengeClasses).
|
||||||
|
|
||||||
|
%% Level
|
||||||
|
|
||||||
|
-spec level_name(level()) ->
|
||||||
|
binary().
|
||||||
|
|
||||||
|
level_name(#{name := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
-spec contractor_level(level()) ->
|
||||||
|
contractor_level().
|
||||||
|
|
||||||
|
contractor_level(#{contractor_level := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
%% Challenge
|
||||||
|
|
||||||
|
-spec challenge_class_name(challenge_class()) ->
|
||||||
|
binary().
|
||||||
|
|
||||||
|
challenge_class_name(#{name := V}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
|
-spec base_level(challenge_class(), class()) ->
|
||||||
|
level().
|
||||||
|
|
||||||
|
base_level(#{base_level_id := ID}, Class) ->
|
||||||
|
{ok, Level} = level(ID, Class), Level.
|
||||||
|
|
||||||
|
-spec target_level(challenge_class(), class()) ->
|
||||||
|
level().
|
||||||
|
|
||||||
|
target_level(#{target_level_id := ID}, Class) ->
|
||||||
|
{ok, Level} = level(ID, Class),
|
||||||
|
Level.
|
@ -22,7 +22,8 @@
|
|||||||
-type ctx() :: ff_ctx:ctx().
|
-type ctx() :: ff_ctx:ctx().
|
||||||
|
|
||||||
-type activity() ::
|
-type activity() ::
|
||||||
idle.
|
{challenge, challenge_id()} |
|
||||||
|
undefined .
|
||||||
|
|
||||||
-type st() :: #{
|
-type st() :: #{
|
||||||
activity := activity(),
|
activity := activity(),
|
||||||
@ -31,6 +32,9 @@
|
|||||||
ctx => ctx()
|
ctx => ctx()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-type challenge_id() ::
|
||||||
|
machinery:id().
|
||||||
|
|
||||||
-export_type([id/0]).
|
-export_type([id/0]).
|
||||||
|
|
||||||
-export([identity/1]).
|
-export([identity/1]).
|
||||||
@ -38,6 +42,7 @@
|
|||||||
|
|
||||||
-export([create/3]).
|
-export([create/3]).
|
||||||
-export([get/1]).
|
-export([get/1]).
|
||||||
|
-export([start_challenge/2]).
|
||||||
|
|
||||||
%% Machinery
|
%% Machinery
|
||||||
|
|
||||||
@ -49,7 +54,7 @@
|
|||||||
|
|
||||||
%% Pipeline
|
%% Pipeline
|
||||||
|
|
||||||
-import(ff_pipeline, [do/1, unwrap/1, unwrap/2]).
|
-import(ff_pipeline, [do/1, do/2, unwrap/1, unwrap/2]).
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -96,6 +101,26 @@ get(ID) ->
|
|||||||
identity(collapse(unwrap(machinery:get(?NS, ID, backend()))))
|
identity(collapse(unwrap(machinery:get(?NS, ID, backend()))))
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
-type challenge_params() :: #{
|
||||||
|
id := challenge_id(),
|
||||||
|
class := ff_identity_class:challenge_class_id(),
|
||||||
|
proofs := [ff_identity:proof()]
|
||||||
|
}.
|
||||||
|
|
||||||
|
-spec start_challenge(id(), challenge_params()) ->
|
||||||
|
ok |
|
||||||
|
{error,
|
||||||
|
notfound |
|
||||||
|
{challenge,
|
||||||
|
{pending, challenge_id()} |
|
||||||
|
{class, notfound} |
|
||||||
|
_IdentityChallengeError
|
||||||
|
}
|
||||||
|
}.
|
||||||
|
|
||||||
|
start_challenge(ID, Params) ->
|
||||||
|
machinery:call(?NS, ID, {start_challenge, Params}, backend()).
|
||||||
|
|
||||||
backend() ->
|
backend() ->
|
||||||
fistful:backend(?NS).
|
fistful:backend(?NS).
|
||||||
|
|
||||||
@ -124,17 +149,63 @@ init({Events, Ctx}, #{}, _, _Opts) ->
|
|||||||
aux_state => #{ctx => Ctx}
|
aux_state => #{ctx => Ctx}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
-spec process_timeout(machine(), _, handler_opts()) ->
|
-spec process_timeout(machine(), _, handler_opts()) ->
|
||||||
result().
|
result().
|
||||||
|
|
||||||
process_timeout(_Machine, _, _Opts) ->
|
process_timeout(Machine, _, _Opts) ->
|
||||||
#{}.
|
process_activity(collapse(Machine)).
|
||||||
|
|
||||||
-spec process_call(_, machine(), _, handler_opts()) ->
|
process_activity(#{activity := {challenge, ChallengeID}} = St) ->
|
||||||
{ok, result()}.
|
Identity = identity(St),
|
||||||
|
{ok, Events} = ff_identity:poll_challenge_completion(ChallengeID, Identity),
|
||||||
|
case Events of
|
||||||
|
[] ->
|
||||||
|
#{action => set_poll_timer(St)};
|
||||||
|
_Some ->
|
||||||
|
#{events => emit_ts_events(Events)}
|
||||||
|
end.
|
||||||
|
|
||||||
process_call(_CallArgs, #{}, _, _Opts) ->
|
set_poll_timer(St) ->
|
||||||
{ok, #{}}.
|
Now = machinery_time:now(),
|
||||||
|
Timeout = erlang:max(1, machinery_time:interval(Now, updated(St))),
|
||||||
|
{set_timer, {timeout, Timeout}}.
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
-type call() ::
|
||||||
|
{start_challenge, challenge_params()}.
|
||||||
|
|
||||||
|
-spec process_call(call(), machine(), _, handler_opts()) ->
|
||||||
|
{_TODO, result()}.
|
||||||
|
|
||||||
|
process_call({start_challenge, Params}, Machine, _, _Opts) ->
|
||||||
|
do_start_challenge(Params, collapse(Machine)).
|
||||||
|
|
||||||
|
do_start_challenge(Params, #{activity := undefined} = St) ->
|
||||||
|
Identity = identity(St),
|
||||||
|
handle_result(do(challenge, fun () ->
|
||||||
|
#{
|
||||||
|
id := ChallengeID,
|
||||||
|
class := ChallengeClassID,
|
||||||
|
proofs := Proofs
|
||||||
|
} = Params,
|
||||||
|
Class = ff_identity:class(Identity),
|
||||||
|
ChallengeClass = unwrap(class, ff_identity_class:challenge_class(ChallengeClassID, Class)),
|
||||||
|
Events = unwrap(ff_identity:start_challenge(ChallengeID, ChallengeClass, Proofs, Identity)),
|
||||||
|
#{
|
||||||
|
events => emit_ts_events(Events),
|
||||||
|
action => continue
|
||||||
|
}
|
||||||
|
end));
|
||||||
|
do_start_challenge(_Params, #{activity := {challenge, ChallengeID}}) ->
|
||||||
|
handle_result({error, {challenge, {pending, ChallengeID}}}).
|
||||||
|
|
||||||
|
handle_result({ok, R}) ->
|
||||||
|
{ok, R};
|
||||||
|
handle_result({error, _} = Error) ->
|
||||||
|
{Error, #{}}.
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -154,7 +225,22 @@ merge_event_body({created, Identity}, St) ->
|
|||||||
identity => Identity
|
identity => Identity
|
||||||
};
|
};
|
||||||
merge_event_body(IdentityEv, St = #{identity := Identity}) ->
|
merge_event_body(IdentityEv, St = #{identity := Identity}) ->
|
||||||
St#{identity := ff_identity:apply_event(IdentityEv, Identity)}.
|
St#{
|
||||||
|
activity := deduce_activity(IdentityEv),
|
||||||
|
identity := ff_identity:apply_event(IdentityEv, Identity)
|
||||||
|
}.
|
||||||
|
|
||||||
|
deduce_activity({contract_set, _}) ->
|
||||||
|
undefined;
|
||||||
|
deduce_activity({level_changed, _}) ->
|
||||||
|
undefined;
|
||||||
|
deduce_activity({challenge_created, ChallengeID, _}) ->
|
||||||
|
{challenge, ChallengeID};
|
||||||
|
deduce_activity({challenge, _ChallengeID, {status_changed, _}}) ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
updated(#{times := {_, V}}) ->
|
||||||
|
V.
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
@ -83,15 +83,15 @@ get(ID) ->
|
|||||||
end,
|
end,
|
||||||
maps:get(levels, ICC)
|
maps:get(levels, ICC)
|
||||||
),
|
),
|
||||||
Challenges = maps:map(
|
ChallengeClasses = maps:map(
|
||||||
fun (ChallengeID, CC) ->
|
fun (ChallengeClassID, CCC) ->
|
||||||
CName = maps:get(name, CC, ChallengeID),
|
CCName = maps:get(name, CCC, ChallengeClassID),
|
||||||
BaseLevelID = maps:get(base, CC),
|
BaseLevelID = maps:get(base, CCC),
|
||||||
TargetLevelID = maps:get(target, CC),
|
TargetLevelID = maps:get(target, CCC),
|
||||||
{ok, _} = maps:find(BaseLevelID, Levels),
|
{ok, _} = maps:find(BaseLevelID, Levels),
|
||||||
{ok, _} = maps:find(TargetLevelID, Levels),
|
{ok, _} = maps:find(TargetLevelID, Levels),
|
||||||
#{
|
#{
|
||||||
name => CName,
|
name => CCName,
|
||||||
base_level_id => BaseLevelID,
|
base_level_id => BaseLevelID,
|
||||||
target_level_id => TargetLevelID
|
target_level_id => TargetLevelID
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ get(ID) ->
|
|||||||
contract_template_ref => ContractTemplateRef,
|
contract_template_ref => ContractTemplateRef,
|
||||||
initial_level_id => maps:get(initial_level, ICC),
|
initial_level_id => maps:get(initial_level, ICC),
|
||||||
levels => Levels,
|
levels => Levels,
|
||||||
challenges => Challenges
|
challenge_classes => ChallengeClasses
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
maps:get(identity_classes, C)
|
maps:get(identity_classes, C)
|
||||||
|
Loading…
Reference in New Issue
Block a user