From a1151e3ca3cc7221205d372564cb4d233f34aa78 Mon Sep 17 00:00:00 2001 From: dinama Date: Mon, 28 Jun 2021 18:43:17 +0300 Subject: [PATCH] ED-184: migrate to party_client (#546) --- Makefile | 4 +- apps/capi/src/capi.app.src | 3 +- apps/capi/src/capi_cors_policy.erl | 6 +- apps/capi/src/capi_handler.erl | 26 ++-- apps/capi/src/capi_handler_accounts.erl | 6 +- apps/capi/src/capi_handler_claims.erl | 40 ++---- apps/capi/src/capi_handler_contracts.erl | 84 +++++------ .../src/capi_handler_decoder_invoicing.erl | 8 +- .../src/capi_handler_invoice_templates.erl | 7 +- apps/capi/src/capi_handler_invoices.erl | 17 ++- apps/capi/src/capi_handler_parties.erl | 69 +++++---- .../src/capi_handler_payment_institutions.erl | 13 +- apps/capi/src/capi_handler_payments.erl | 2 +- apps/capi/src/capi_handler_payouts.erl | 22 +-- apps/capi/src/capi_handler_shops.erl | 54 +++---- apps/capi/src/capi_handler_utils.erl | 29 +--- apps/capi/src/capi_handler_webhooks.erl | 31 ++-- apps/capi/src/capi_party.erl | 133 ++++++++++++++++++ apps/capi/src/capi_sup.erl | 26 ++-- apps/capi/src/capi_swagger_server.erl | 6 +- .../test/capi_authorization_tests_SUITE.erl | 10 +- .../test/capi_base_api_token_tests_SUITE.erl | 93 ++++++++++-- apps/capi/test/capi_ct_helper.erl | 39 +++-- apps/capi/test/capi_deadline_tests_SUITE.erl | 15 +- .../test/capi_idempotency_tests_SUITE.erl | 14 +- .../capi_invoice_access_token_tests_SUITE.erl | 5 +- ...oice_template_access_token_tests_SUITE.erl | 5 +- apps/capi/test/capi_self_tests_SUITE.erl | 5 +- apps/capi/test/capi_woody_tests_SUITE.erl | 22 +-- .../src/capi_woody_client.erl | 5 +- build_utils | 2 +- config/sys.config | 25 ++++ rebar.config | 5 +- rebar.lock | 51 +++---- 34 files changed, 556 insertions(+), 326 deletions(-) create mode 100644 apps/capi/src/capi_party.erl diff --git a/Makefile b/Makefile index 1ebc7c5..73f48d7 100644 --- a/Makefile +++ b/Makefile @@ -17,10 +17,10 @@ SERVICE_IMAGE_PUSH_TAG ?= $(SERVICE_IMAGE_TAG) # Base image for the service BASE_IMAGE_NAME := service-erlang -BASE_IMAGE_TAG := d2b5ac42305aadae44d6f8b1d859fd1065749997 +BASE_IMAGE_TAG := c114fc51a7b166d22144fcbf856f217dc7b5946f BUILD_IMAGE_NAME := build-erlang -BUILD_IMAGE_TAG := cc2d319150ec0b9cd23ad9347692a8066616b0f4 +BUILD_IMAGE_TAG := 2ea61e9556ad67d5918f060ed50353662ed84e59 CALL_ANYWHERE := \ submodules \ diff --git a/apps/capi/src/capi.app.src b/apps/capi/src/capi.app.src index 09e93e1..fa5b859 100644 --- a/apps/capi/src/capi.app.src +++ b/apps/capi/src/capi.app.src @@ -30,7 +30,8 @@ prometheus, prometheus_cowboy, bouncer_client, - token_keeper_client + token_keeper_client, + party_client ]}, {env, []} ]}. diff --git a/apps/capi/src/capi_cors_policy.erl b/apps/capi/src/capi_cors_policy.erl index 86e4443..90048c4 100644 --- a/apps/capi/src/capi_cors_policy.erl +++ b/apps/capi/src/capi_cors_policy.erl @@ -17,7 +17,8 @@ allowed_origins(_, State) -> -spec allowed_headers(cowboy_req:req(), any()) -> {[binary()], any()}. allowed_headers(_, State) -> - {[ + { + [ <<"x-requested-with">>, <<"content-type">>, <<"accept">>, @@ -25,7 +26,8 @@ allowed_headers(_, State) -> <<"x-request-id">>, <<"x-request-deadline">> ], - State}. + State + }. -spec allowed_methods(cowboy_req:req(), any()) -> {[binary()], any()}. allowed_methods(_, State) -> diff --git a/apps/capi/src/capi_handler.erl b/apps/capi/src/capi_handler.erl index 407baac..44bdc02 100644 --- a/apps/capi/src/capi_handler.erl +++ b/apps/capi/src/capi_handler.erl @@ -21,7 +21,9 @@ -type processing_context() :: #{ operation_id := operation_id(), swagger_context := swag_server:request_context(), - woody_context := woody_context:ctx() + woody_context := woody_context:ctx(), + party_client := party_client:client(), + party_client_context := party_client:context() }. -type throw(_T) :: no_return(). @@ -31,14 +33,18 @@ process := fun(() -> {ok, response()} | throw(response())) }. +-type handler_opts() :: + swag_server:handler_opts(#{ + party_client := party_client:client() + }). + -export_type([operation_id/0]). -export_type([request_data/0]). -export_type([request_context/0]). -export_type([processing_context/0]). -export_type([request_state/0]). -export_type([response/0]). - --type handler_opts() :: swag_server:handler_opts(_). +-export_type([handler_opts/0]). %% Handler behaviour @@ -129,7 +135,7 @@ handle_request(OperationID, Req, SwagContext, HandlerOpts) -> SwagContext :: request_context(), HandlerOpts :: handler_opts() ) -> {ok | error, response()}. -handle_function_(OperationID, Req, SwagContext0, _HandlerOpts) -> +handle_function_(OperationID, Req, SwagContext0, HandlerOpts) -> try RpcID = create_rpc_id(Req), ok = set_rpc_meta(RpcID), @@ -138,10 +144,10 @@ handle_function_(OperationID, Req, SwagContext0, _HandlerOpts) -> WoodyContext0 = attach_deadline(Req, create_woody_context(RpcID)), SwagContext = do_authorize_api_key(SwagContext0, WoodyContext0), WoodyContext = put_user_identity(WoodyContext0, get_auth_context(SwagContext)), - Context = create_processing_context(OperationID, SwagContext, WoodyContext), + Context = create_processing_context(OperationID, SwagContext, WoodyContext, HandlerOpts), ok = set_context_meta(Context), - {ok, #{authorize := Authorize, process := Process}} = - prepare(OperationID, Req, Context, get_handlers()), + {ok, RequestState} = prepare(OperationID, Req, Context, get_handlers()), + #{authorize := Authorize, process := Process} = RequestState, {ok, Resolution} = Authorize(), case Resolution of allowed -> @@ -219,11 +225,13 @@ make_token_context(#{cowboy_req := CowboyReq}) -> undefined end. -create_processing_context(OperationID, SwaggerContext, WoodyContext) -> +create_processing_context(OperationID, SwaggerContext, WoodyContext, HandlerOpts) -> #{ operation_id => OperationID, woody_context => WoodyContext, - swagger_context => SwaggerContext + swagger_context => SwaggerContext, + party_client_context => party_client:create_context(#{woody_context => WoodyContext}), + party_client => maps:get(party_client, HandlerOpts) }. -spec create_rpc_id(request_data()) -> woody:rpc_id(). diff --git a/apps/capi/src/capi_handler_accounts.erl b/apps/capi/src/capi_handler_accounts.erl index 962a4c9..ff07a52 100644 --- a/apps/capi/src/capi_handler_accounts.erl +++ b/apps/capi/src/capi_handler_accounts.erl @@ -21,12 +21,10 @@ prepare(OperationID, Req, Context) when OperationID =:= 'GetAccountByID' -> end, Process = fun() -> AccountID = genlib:to_int(maps:get('accountID', Req)), - CallArgs = {PartyID, AccountID}, - Call = {party_management, 'GetAccountState', CallArgs}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of + case capi_party:get_account_state(PartyID, AccountID, Context) of {ok, S} -> {ok, {200, #{}, decode_account_state(S)}}; - {exception, #payproc_AccountNotFound{}} -> + {error, #payproc_AccountNotFound{}} -> {ok, general_error(404, <<"Account not found">>)} end end, diff --git a/apps/capi/src/capi_handler_claims.erl b/apps/capi/src/capi_handler_claims.erl index c4749cb..1672072 100644 --- a/apps/capi/src/capi_handler_claims.erl +++ b/apps/capi/src/capi_handler_claims.erl @@ -22,10 +22,7 @@ prepare(OperationID = 'GetClaims', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'GetClaims', {PartyID}}, - Claims = capi_utils:unwrap( - capi_handler_utils:service_call_with([user_info], Call, Context) - ), + Claims = capi_utils:unwrap(capi_party:get_claims(PartyID, Context)), {ok, {200, #{}, decode_claims(filter_claims(maps:get('claimStatus', Req), Claims))}} end, {ok, #{authorize => Authorize, process => Process}}; @@ -39,9 +36,7 @@ prepare(OperationID = 'GetClaimByID', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - CallArgs = {PartyID, genlib:to_int(ClaimID)}, - Call = {party_management, 'GetClaim', CallArgs}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of + case capi_party:get_claim(PartyID, genlib:to_int(ClaimID), Context) of {ok, Claim} -> case is_wallet_claim(Claim) of true -> @@ -50,7 +45,7 @@ prepare(OperationID = 'GetClaimByID', Req, Context) -> false -> {ok, {200, #{}, decode_claim(Claim)}} end; - {exception, #payproc_ClaimNotFound{}} -> + {error, #payproc_ClaimNotFound{}} -> {ok, general_error(404, <<"Claim not found">>)} end end, @@ -66,12 +61,10 @@ prepare(OperationID = 'CreateClaim', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - CallArgs = {PartyID, Changeset}, - Call = {party_management, 'CreateClaim', CallArgs}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of + case capi_party:create_claim(PartyID, Changeset, Context) of {ok, Claim} -> {ok, {201, #{}, decode_claim(Claim)}}; - {exception, Exception} -> + {error, Exception} -> case Exception of #payproc_InvalidPartyStatus{} -> {ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)}; @@ -107,15 +100,12 @@ prepare(OperationID = 'CreateClaim', Req, Context) -> % {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} % end, % Process = fun() -> -% Call = -% {party_management, 'UpdateClaim', { +% Party = capi_utils:unwrap( +% capi_party:update_claim( % PartyID, % genlib:to_int(ClaimID), % genlib:to_int(maps:get('claimRevision', Req)), -% encode_claim_changeset(maps:get('claimChangeset', Req)) -% }}, -% Party = capi_utils:unwrap( -% capi_handler_utils:service_call_with([user_info], Call, Context) +% encode_claim_changeset(maps:get('claimChangeset', Req)), Context) % ), % {ok, {200, #{}, capi_handler_decoder_party:decode_party(Party)}} % end, @@ -130,17 +120,17 @@ prepare(OperationID = 'RevokeClaimByID', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - CallArgs = { + Result = capi_party:revoke_claim( PartyID, genlib:to_int(ClaimID), genlib:to_int(maps:get('claimRevision', Req)), - encode_reason(maps:get('Reason', Req)) - }, - Call = {party_management, 'RevokeClaim', CallArgs}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _} -> + encode_reason(maps:get('Reason', Req)), + Context + ), + case Result of + ok -> {ok, {204, #{}, undefined}}; - {exception, Exception} -> + {error, Exception} -> case Exception of #payproc_InvalidPartyStatus{} -> {ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)}; diff --git a/apps/capi/src/capi_handler_contracts.erl b/apps/capi/src/capi_handler_contracts.erl index 8b11bc5..fbf96fd 100644 --- a/apps/capi/src/capi_handler_contracts.erl +++ b/apps/capi/src/capi_handler_contracts.erl @@ -14,27 +14,30 @@ Context :: capi_handler:processing_context() ) -> {ok, capi_handler:request_state()} | {error, noimpl}. prepare(OperationID = 'GetContracts', Req, Context) -> - Party = capi_utils:unwrap(capi_handler_utils:get_party(Context)), + PartyID = capi_handler_utils:get_party_id(Context), Authorize = fun() -> Prototypes = [ - {operation, #{party => Party#domain_Party.id, id => OperationID}} + {operation, #{party => PartyID, id => OperationID}} ], {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> + {ok, Party} = capi_party:get_party(PartyID, Context), {ok, {200, #{}, decode_contracts_map(Party#domain_Party.contracts, Party#domain_Party.contractors)}} end, {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID = 'GetContractByID', Req, Context) -> ContractID = maps:get('contractID', Req), - Party = capi_utils:unwrap(capi_handler_utils:get_party(Context)), + PartyID = capi_handler_utils:get_party_id(Context), Authorize = fun() -> Prototypes = [ - {operation, #{party => Party#domain_Party.id, contract => ContractID, id => OperationID}} + {operation, #{party => PartyID, contract => ContractID, id => OperationID}} ], {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> + % Получение Party требуется для извлечения domain_Party.contractors + {ok, Party} = capi_party:get_party(PartyID, Context), case genlib_map:get(ContractID, Party#domain_Party.contracts) of undefined -> {ok, general_error(404, <<"Contract not found">>)}; @@ -45,34 +48,34 @@ prepare(OperationID = 'GetContractByID', Req, Context) -> {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID = 'GetContractAdjustments', Req, Context) -> ContractID = maps:get('contractID', Req), - Party = capi_utils:unwrap(capi_handler_utils:get_party(Context)), + PartyID = capi_handler_utils:get_party_id(Context), Authorize = fun() -> Prototypes = [ - {operation, #{party => Party#domain_Party.id, contract => ContractID, id => OperationID}} + {operation, #{party => PartyID, contract => ContractID, id => OperationID}} ], {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_contract_by_id(ContractID, Context) of + case capi_party:get_contract(PartyID, ContractID, Context) of {ok, #domain_Contract{adjustments = Adjustments}} -> Resp = [decode_contract_adjustment(A) || A <- Adjustments], {ok, {200, #{}, Resp}}; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID = 'GetContractAdjustmentByID', Req, Context) -> ContractID = maps:get('contractID', Req), - Party = capi_utils:unwrap(capi_handler_utils:get_party(Context)), + PartyID = capi_handler_utils:get_party_id(Context), Authorize = fun() -> Prototypes = [ - {operation, #{party => Party#domain_Party.id, contract => ContractID, id => OperationID}} + {operation, #{party => PartyID, contract => ContractID, id => OperationID}} ], {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_contract_by_id(ContractID, Context) of + case capi_party:get_contract(PartyID, ContractID, Context) of {ok, #domain_Contract{adjustments = Adjustments}} -> AdjustmentID = maps:get('adjustmentID', Req), case lists:keyfind(AdjustmentID, #domain_ContractAdjustment.id, Adjustments) of @@ -81,17 +84,13 @@ prepare(OperationID = 'GetContractAdjustmentByID', Req, Context) -> false -> {ok, general_error(404, <<"Adjustment not found">>)} end; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID = 'GetContractsForParty', Req, Context) -> PartyID = maps:get('partyID', Req), - % TODO - % Here we're relying on hellgate ownership check, thus no explicit authorization. - % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation - % remains authorized. Authorize = fun() -> Prototypes = [ {operation, #{party => PartyID, id => OperationID}} @@ -99,12 +98,12 @@ prepare(OperationID = 'GetContractsForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_party(PartyID, Context) of + case capi_party:get_party(PartyID, Context) of {ok, Party} -> {ok, {200, #{}, decode_contracts_map(Party#domain_Party.contracts, Party#domain_Party.contractors)}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)} end end, @@ -112,10 +111,6 @@ prepare(OperationID = 'GetContractsForParty', Req, Context) -> prepare(OperationID = 'GetContractByIDForParty', Req, Context) -> ContractID = maps:get('contractID', Req), PartyID = maps:get('partyID', Req), - % TODO - % Here we're relying on hellgate ownership check, thus no explicit authorization. - % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation - % remains authorized. Authorize = fun() -> Prototypes = [ {operation, #{party => PartyID, contract => ContractID, id => OperationID}} @@ -123,28 +118,19 @@ prepare(OperationID = 'GetContractByIDForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_party(PartyID, Context) of - {ok, Party} -> - case genlib_map:get(ContractID, Party#domain_Party.contracts) of - undefined -> - {ok, general_error(404, <<"Contract not found">>)}; - Contract -> - {ok, {200, #{}, decode_contract(Contract, Party#domain_Party.contractors)}} - end; - {exception, #payproc_InvalidUser{}} -> - {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)} + case capi_party:get_contract(PartyID, ContractID, Context) of + {ok, Contract} -> + % Получение Party требуется для извлечения domain_Party.contractors + {ok, Party} = capi_party:get_party(PartyID, Context), + {ok, {200, #{}, decode_contract(Contract, Party#domain_Party.contractors)}}; + {error, #payproc_ContractNotFound{}} -> + {ok, general_error(404, <<"Contract not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID = 'GetContractAdjustmentsForParty', Req, Context) -> ContractID = maps:get('contractID', Req), PartyID = maps:get('partyID', Req), - % TODO - % Here we're relying on hellgate ownership check, thus no explicit authorization. - % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation - % remains authorized. Authorize = fun() -> Prototypes = [ {operation, #{party => PartyID, contract => ContractID, id => OperationID}} @@ -152,15 +138,15 @@ prepare(OperationID = 'GetContractAdjustmentsForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_contract_by_id(PartyID, ContractID, Context) of + case capi_party:get_contract(PartyID, ContractID, Context) of {ok, #domain_Contract{adjustments = Adjustments}} -> Resp = [decode_contract_adjustment(A) || A <- Adjustments], {ok, {200, #{}, Resp}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, @@ -168,10 +154,6 @@ prepare(OperationID = 'GetContractAdjustmentsForParty', Req, Context) -> prepare(OperationID = 'GetContractAdjustmentByIDForParty', Req, Context) -> ContractID = maps:get('contractID', Req), PartyID = maps:get('partyID', Req), - % TODO - % Here we're relying on hellgate ownership check, thus no explicit authorization. - % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation - % remains authorized. Authorize = fun() -> Prototypes = [ {operation, #{party => PartyID, contract => ContractID, id => OperationID}} @@ -179,7 +161,7 @@ prepare(OperationID = 'GetContractAdjustmentByIDForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_contract_by_id(PartyID, ContractID, Context) of + case capi_party:get_contract(PartyID, ContractID, Context) of {ok, #domain_Contract{adjustments = Adjustments}} -> AdjustmentID = maps:get('adjustmentID', Req), case lists:keyfind(AdjustmentID, #domain_ContractAdjustment.id, Adjustments) of @@ -188,11 +170,11 @@ prepare(OperationID = 'GetContractAdjustmentByIDForParty', Req, Context) -> false -> {ok, general_error(404, <<"Adjustment not found">>)} end; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, diff --git a/apps/capi/src/capi_handler_decoder_invoicing.erl b/apps/capi/src/capi_handler_decoder_invoicing.erl index 0c34a94..15b94d9 100644 --- a/apps/capi/src/capi_handler_decoder_invoicing.erl +++ b/apps/capi/src/capi_handler_decoder_invoicing.erl @@ -549,15 +549,15 @@ decode_bank_card(#domain_BankCardPaymentMethod{payment_system_deprecated = PS}) decode_tokenized_bank_cards([#domain_BankCardPaymentMethod{} | _] = TokenizedBankCards) -> PropTokenizedBankCards = [ {TP, PS} - || #domain_BankCardPaymentMethod{payment_system_deprecated = PS, token_provider_deprecated = TP} <- - TokenizedBankCards + || #domain_BankCardPaymentMethod{payment_system_deprecated = PS, token_provider_deprecated = TP} <- + TokenizedBankCards ], do_decode_tokenized_bank_cards(PropTokenizedBankCards); decode_tokenized_bank_cards([#domain_TokenizedBankCard{} | _] = TokenizedBankCards) -> PropTokenizedBankCards = [ {TP, PS} - || #domain_TokenizedBankCard{payment_system_deprecated = PS, token_provider_deprecated = TP} <- - TokenizedBankCards + || #domain_TokenizedBankCard{payment_system_deprecated = PS, token_provider_deprecated = TP} <- + TokenizedBankCards ], do_decode_tokenized_bank_cards(PropTokenizedBankCards); decode_tokenized_bank_cards([]) -> diff --git a/apps/capi/src/capi_handler_invoice_templates.erl b/apps/capi/src/capi_handler_invoice_templates.erl index 7b943d0..2da8d4e 100644 --- a/apps/capi/src/capi_handler_invoice_templates.erl +++ b/apps/capi/src/capi_handler_invoice_templates.erl @@ -257,9 +257,10 @@ prepare('GetInvoicePaymentMethodsByTemplateID' = OperationID, Req, Context) -> Process = fun() -> capi_handler:respond_if_undefined(InvoiceTemplate, general_error(404, <<"Invoice template not found">>)), Timestamp = genlib_rfc3339:format_relaxed(erlang:system_time(microsecond), microsecond), - {ok, Party} = capi_handler_utils:get_party(Context), - Revision = Party#domain_Party.revision, - Args = {InvoiceTemplateID, Timestamp, {revision, Revision}}, + PartyID = InvoiceTemplate#domain_InvoiceTemplate.owner_id, + % В данном контексте - Party не может не существовать + {ok, Party} = capi_party:get_party(PartyID, Context), + Args = {InvoiceTemplateID, Timestamp, {revision, Party#domain_Party.revision}}, case capi_handler_decoder_invoicing:construct_payment_methods(invoice_templating, Args, Context) of {ok, PaymentMethods0} when is_list(PaymentMethods0) -> PaymentMethods = capi_utils:deduplicate_payment_methods(PaymentMethods0), diff --git a/apps/capi/src/capi_handler_invoices.erl b/apps/capi/src/capi_handler_invoices.erl index 1aa8172..cd80107 100644 --- a/apps/capi/src/capi_handler_invoices.erl +++ b/apps/capi/src/capi_handler_invoices.erl @@ -256,18 +256,27 @@ prepare('GetInvoiceEvents' = OperationID, Req, Context) -> {ok, #{authorize => Authorize, process => Process}}; prepare('GetInvoicePaymentMethods' = OperationID, Req, Context) -> InvoiceID = maps:get(invoiceID, Req), + ResultInvoice = + case capi_handler_utils:get_invoice_by_id(InvoiceID, Context) of + {ok, Result} -> + Result; + {exception, _Exception} -> + undefined + end, Authorize = fun() -> Prototypes = [ {operation, #{id => OperationID, invoice => InvoiceID}}, - {payproc, #{invoice => InvoiceID}} + {payproc, #{invoice => ResultInvoice}} ], Resolution = capi_auth:authorize_operation(Prototypes, Context, Req), {ok, Resolution} end, Process = fun() -> - Party = capi_utils:unwrap(capi_handler_utils:get_party(Context)), - Revision = Party#domain_Party.revision, - Args = {InvoiceID, {revision, Revision}}, + capi_handler:respond_if_undefined(ResultInvoice, general_error(404, <<"Invoice not found">>)), + PartyID = ResultInvoice#payproc_Invoice.invoice#domain_Invoice.owner_id, + % В данном контексте - Party не может не существовать + {ok, Party} = capi_party:get_party(PartyID, Context), + Args = {InvoiceID, {revision, Party#domain_Party.revision}}, case capi_handler_decoder_invoicing:construct_payment_methods(invoicing, Args, Context) of {ok, PaymentMethods0} when is_list(PaymentMethods0) -> PaymentMethods = capi_utils:deduplicate_payment_methods(PaymentMethods0), diff --git a/apps/capi/src/capi_handler_parties.erl b/apps/capi/src/capi_handler_parties.erl index 07ab84b..02c00cf 100644 --- a/apps/capi/src/capi_handler_parties.erl +++ b/apps/capi/src/capi_handler_parties.erl @@ -26,9 +26,9 @@ prepare('GetMyParty' = OperationID, Req, Context) -> {ok, Party} -> DecodedParty = capi_handler_decoder_party:decode_party(Party), {ok, {200, #{}, DecodedParty}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)} end end, @@ -40,15 +40,14 @@ prepare('ActivateMyParty' = OperationID, Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'Activate', {PartyID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:activate_party(PartyID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {exception, #payproc_InvalidPartyStatus{status = {suspension, {active, _}}}} -> + {error, #payproc_InvalidPartyStatus{status = {suspension, {active, _}}}} -> {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} end end, @@ -60,15 +59,14 @@ prepare('SuspendMyParty' = OperationID, Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'Suspend', {PartyID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:suspend_party(PartyID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {exception, #payproc_InvalidPartyStatus{status = {suspension, {suspended, _}}}} -> + {error, #payproc_InvalidPartyStatus{status = {suspension, {suspended, _}}}} -> {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} end end, @@ -80,13 +78,13 @@ prepare('GetPartyByID' = OperationID, Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_party(PartyID, Context) of + case capi_party:get_party(PartyID, Context) of {ok, Party} -> DecodedParty = capi_handler_decoder_party:decode_party(Party), {ok, {200, #{}, DecodedParty}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)} end end, @@ -98,15 +96,14 @@ prepare('ActivatePartyByID' = OperationID, Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'Activate', {PartyID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:activate_party(PartyID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_InvalidPartyStatus{status = {suspension, {active, _}}}} -> + {error, #payproc_InvalidPartyStatus{status = {suspension, {active, _}}}} -> {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} end end, @@ -118,15 +115,14 @@ prepare('SuspendPartyByID' = OperationID, Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'Suspend', {PartyID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:suspend_party(PartyID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_InvalidPartyStatus{status = {suspension, {suspended, _}}}} -> + {error, #payproc_InvalidPartyStatus{status = {suspension, {suspended, _}}}} -> {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} end end, @@ -138,8 +134,8 @@ prepare(_OperationID, _Req, _Context) -> -spec get_or_create_party(binary(), processing_context()) -> woody:result(). get_or_create_party(PartyID, Context) -> - case capi_handler_utils:get_party(PartyID, Context) of - {exception, #payproc_PartyNotFound{}} -> + case capi_party:get_party(PartyID, Context) of + {error, #payproc_PartyNotFound{}} -> _ = logger:info("Attempting to create a missing party"), create_party(PartyID, Context); Reply -> @@ -156,12 +152,11 @@ create_party(PartyID, Context) -> ) } }, - Call = {party_management, 'Create', {PartyID, PartyParams}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _} -> - capi_handler_utils:get_party(PartyID, Context); - {exception, #payproc_PartyExists{}} -> - capi_handler_utils:get_party(PartyID, Context); + case capi_party:create_party(PartyID, PartyParams, Context) of + ok -> + capi_party:get_party(PartyID, Context); + {error, #payproc_PartyExists{}} -> + capi_party:get_party(PartyID, Context); Error -> Error end. diff --git a/apps/capi/src/capi_handler_payment_institutions.erl b/apps/capi/src/capi_handler_payment_institutions.erl index 4f9ceca..e634537 100644 --- a/apps/capi/src/capi_handler_payment_institutions.erl +++ b/apps/capi/src/capi_handler_payment_institutions.erl @@ -60,7 +60,7 @@ prepare(OperationID = 'GetPaymentInstitutionPaymentTerms', Req, Context) -> case compute_payment_institution_terms(PaymentInstitutionID, #payproc_Varset{}, Context) of {ok, #domain_TermSet{payments = PaymentTerms}} -> {ok, {200, #{}, decode_payment_terms(PaymentTerms)}}; - {exception, #payproc_PaymentInstitutionNotFound{}} -> + {error, #payproc_PaymentInstitutionNotFound{}} -> {ok, general_error(404, <<"Payment institution not found">>)} end end, @@ -74,7 +74,7 @@ prepare(OperationID = 'GetPaymentInstitutionPayoutMethods', Req, Context) -> {ok, {200, #{}, decode_payout_methods_selector(PayoutMethods)}}; {ok, #domain_TermSet{payouts = undefined}} -> {ok, general_error(404, <<"Automatic payouts not allowed">>)}; - {exception, #payproc_PaymentInstitutionNotFound{}} -> + {error, #payproc_PaymentInstitutionNotFound{}} -> {ok, general_error(404, <<"Payment institution not found">>)} end end, @@ -88,7 +88,7 @@ prepare(OperationID = 'GetPaymentInstitutionPayoutSchedules', Req, Context) -> {ok, {200, #{}, decode_business_schedules_selector(Schedules)}}; {ok, #domain_TermSet{payouts = undefined}} -> {ok, general_error(404, <<"Automatic payouts not allowed">>)}; - {exception, #payproc_PaymentInstitutionNotFound{}} -> + {error, #payproc_PaymentInstitutionNotFound{}} -> {ok, general_error(404, <<"Payment institution not found">>)} end end, @@ -125,9 +125,8 @@ check_payment_institution_residence(Residence, #domain_PaymentInstitutionObject{ ordsets:is_element(Residence, Residences). compute_payment_institution_terms(PaymentInstitutionID, VS, Context) -> - CallArgs = {?payment_institution_ref(PaymentInstitutionID), VS}, - Call = {party_management, 'ComputePaymentInstitutionTerms', CallArgs}, - capi_handler_utils:service_call_with([user_info], Call, Context). + Ref = ?payment_institution_ref(PaymentInstitutionID), + capi_party:compute_payment_institution_terms(Ref, VS, Context). prepare_request_varset(Req, Context) -> #payproc_Varset{ @@ -160,7 +159,7 @@ decode_payment_institution_obj(#domain_PaymentInstitutionObject{ref = Ref, data <<"realm">> => genlib:to_binary(Data#domain_PaymentInstitution.realm), <<"residences">> => [ capi_handler_decoder_party:decode_residence(R) - || R <- ordsets:to_list(Data#domain_PaymentInstitution.residences) + || R <- ordsets:to_list(Data#domain_PaymentInstitution.residences) ] }). diff --git a/apps/capi/src/capi_handler_payments.erl b/apps/capi/src/capi_handler_payments.erl index 01e3a4f..4897b3b 100644 --- a/apps/capi/src/capi_handler_payments.erl +++ b/apps/capi/src/capi_handler_payments.erl @@ -364,7 +364,7 @@ prepare(OperationID = 'GetRefunds', Req, Context) -> {ok, {200, #{}, [ capi_handler_decoder_invoicing:decode_refund(R, Context) - || #payproc_InvoicePaymentRefund{refund = R} <- Refunds + || #payproc_InvoicePaymentRefund{refund = R} <- Refunds ]}}; {error, payment_not_found} -> {ok, general_error(404, <<"Payment not found">>)} diff --git a/apps/capi/src/capi_handler_payouts.erl b/apps/capi/src/capi_handler_payouts.erl index a0d646c..4456474 100644 --- a/apps/capi/src/capi_handler_payouts.erl +++ b/apps/capi/src/capi_handler_payouts.erl @@ -77,32 +77,34 @@ prepare(OperationID, Req, Context) when OperationID =:= 'CreatePayout' -> end, {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID, Req, Context) when OperationID =:= 'GetPayoutTools' -> + PartyID = capi_handler_utils:get_party_id(Context), OperationContext = #{ id => OperationID, - party => capi_handler_utils:get_party_id(Context) + party => PartyID }, Authorize = fun() -> {ok, capi_auth:authorize_operation([{operation, OperationContext}], Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_contract_by_id(maps:get('contractID', Req), Context) of + case capi_party:get_contract(PartyID, maps:get('contractID', Req), Context) of {ok, #domain_Contract{payout_tools = PayoutTools}} -> {ok, {200, #{}, [decode_payout_tool(P) || P <- PayoutTools]}}; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; prepare(OperationID, Req, Context) when OperationID =:= 'GetPayoutToolByID' -> + PartyID = capi_handler_utils:get_party_id(Context), OperationContext = #{ id => OperationID, - party => capi_handler_utils:get_party_id(Context) + party => PartyID }, Authorize = fun() -> {ok, capi_auth:authorize_operation([{operation, OperationContext}], Context, Req)} end, Process = fun() -> - case capi_handler_utils:get_contract_by_id(maps:get('contractID', Req), Context) of + case capi_party:get_contract(PartyID, maps:get('contractID', Req), Context) of {ok, #domain_Contract{payout_tools = PayoutTools}} -> PayoutToolID = maps:get('payoutToolID', Req), case lists:keyfind(PayoutToolID, #domain_PayoutTool.id, PayoutTools) of @@ -111,7 +113,7 @@ prepare(OperationID, Req, Context) when OperationID =:= 'GetPayoutToolByID' -> false -> {ok, general_error(404, <<"PayoutTool not found">>)} end; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, @@ -127,10 +129,10 @@ prepare(OperationID, Req, Context) when OperationID =:= 'GetPayoutToolsForParty' end, Process = fun() -> ContractID = maps:get('contractID', Req), - case capi_handler_utils:get_contract_by_id(PartyID, ContractID, Context) of + case capi_party:get_contract(PartyID, ContractID, Context) of {ok, #domain_Contract{payout_tools = PayoutTools}} -> {ok, {200, #{}, [decode_payout_tool(P) || P <- PayoutTools]}}; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, @@ -146,7 +148,7 @@ prepare(OperationID, Req, Context) when OperationID =:= 'GetPayoutToolByIDForPar end, Process = fun() -> ContractID = maps:get('contractID', Req), - case capi_handler_utils:get_contract_by_id(PartyID, ContractID, Context) of + case capi_party:get_contract(PartyID, ContractID, Context) of {ok, #domain_Contract{payout_tools = PayoutTools}} -> PayoutToolID = maps:get('payoutToolID', Req), case lists:keyfind(PayoutToolID, #domain_PayoutTool.id, PayoutTools) of @@ -155,7 +157,7 @@ prepare(OperationID, Req, Context) when OperationID =:= 'GetPayoutToolByIDForPar false -> {ok, general_error(404, <<"PayoutTool not found">>)} end; - {exception, #payproc_ContractNotFound{}} -> + {error, #payproc_ContractNotFound{}} -> {ok, general_error(404, <<"Contract not found">>)} end end, diff --git a/apps/capi/src/capi_handler_shops.erl b/apps/capi/src/capi_handler_shops.erl index 8954d61..49bb99f 100644 --- a/apps/capi/src/capi_handler_shops.erl +++ b/apps/capi/src/capi_handler_shops.erl @@ -21,11 +21,10 @@ prepare(OperationID = 'ActivateShop', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'ActivateShop', {PartyID, ShopID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:activate_shop(PartyID, ShopID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, Exception} -> + {error, Exception} -> case Exception of #payproc_ShopNotFound{} -> {ok, general_error(404, <<"Shop not found">>)}; @@ -43,11 +42,10 @@ prepare(OperationID = 'SuspendShop', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'SuspendShop', {PartyID, ShopID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:suspend_shop(PartyID, ShopID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, Exception} -> + {error, Exception} -> case Exception of #payproc_ShopNotFound{} -> {ok, general_error(404, <<"Shop not found">>)}; @@ -64,7 +62,7 @@ prepare(OperationID = 'GetShops', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Party = capi_utils:unwrap(capi_handler_utils:get_party(Context)), + Party = capi_utils:unwrap(capi_party:get_party(PartyID, Context)), {ok, {200, #{}, decode_shops_map(Party#domain_Party.shops)}} end, {ok, #{authorize => Authorize, process => Process}}; @@ -76,11 +74,10 @@ prepare(OperationID = 'GetShopByID', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'GetShop', {PartyID, ShopID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of + case capi_party:get_shop(PartyID, ShopID, Context) of {ok, Shop} -> {ok, {200, #{}, decode_shop(Shop)}}; - {exception, #payproc_ShopNotFound{}} -> + {error, #payproc_ShopNotFound{}} -> {ok, general_error(404, <<"Shop not found">>)} end end, @@ -96,12 +93,12 @@ prepare(OperationID = 'GetShopsForParty', Req, Context) -> % Here we're relying on hellgate ownership check, thus no explicit authorization. % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation % remains authorized. - case capi_handler_utils:get_party(PartyID, Context) of + case capi_party:get_party(PartyID, Context) of {ok, Party} -> {ok, {200, #{}, decode_shops_map(Party#domain_Party.shops)}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)} end end, @@ -114,19 +111,18 @@ prepare(OperationID = 'GetShopByIDForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'GetShop', {PartyID, ShopID}}, % TODO % Here we're relying on hellgate ownership check, thus no explicit authorization. % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation % remains authorized. - case capi_handler_utils:service_call_with([user_info], Call, Context) of + case capi_party:get_shop(PartyID, ShopID, Context) of {ok, Shop} -> {ok, {200, #{}, decode_shop(Shop)}}; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_PartyNotFound{}} -> + {error, #payproc_PartyNotFound{}} -> {ok, general_error(404, <<"Party not found">>)}; - {exception, #payproc_ShopNotFound{}} -> + {error, #payproc_ShopNotFound{}} -> {ok, general_error(404, <<"Shop not found">>)} end end, @@ -139,15 +135,14 @@ prepare(OperationID = 'ActivateShopForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'ActivateShop', {PartyID, ShopID}}, % TODO % Here we're relying on hellgate ownership check, thus no explicit authorization. % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation % remains authorized. - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:activate_shop(PartyID, ShopID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, Exception} -> + {error, Exception} -> case Exception of #payproc_InvalidUser{} -> {ok, general_error(404, <<"Party not found">>)}; @@ -169,15 +164,10 @@ prepare(OperationID = 'SuspendShopForParty', Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context, Req)} end, Process = fun() -> - Call = {party_management, 'SuspendShop', {PartyID, ShopID}}, - % TODO - % Here we're relying on hellgate ownership check, thus no explicit authorization. - % Hovewer we're going to drop hellgate authz eventually, then we'll need to make sure that operation - % remains authorized. - case capi_handler_utils:service_call_with([user_info], Call, Context) of - {ok, _R} -> + case capi_party:suspend_shop(PartyID, ShopID, Context) of + ok -> {ok, {204, #{}, undefined}}; - {exception, Exception} -> + {error, Exception} -> case Exception of #payproc_InvalidUser{} -> {ok, general_error(404, <<"Party not found">>)}; diff --git a/apps/capi/src/capi_handler_utils.erl b/apps/capi/src/capi_handler_utils.erl index c2e14cf..6763329 100644 --- a/apps/capi/src/capi_handler_utils.erl +++ b/apps/capi/src/capi_handler_utils.erl @@ -13,10 +13,8 @@ -export([service_call_with/3]). -export([service_call/2]). --export([get_party/1]). --export([get_party/2]). - -export([get_auth_context/1]). +-export([get_user_info/1]). -export([get_user_id/1]). -export([get_party_id/1]). -export([get_extra_properties/1]). @@ -34,8 +32,6 @@ -export([get_invoice_by_id/2]). -export([get_payment_by_id/3]). -export([get_refund_by_id/4]). --export([get_contract_by_id/2]). --export([get_contract_by_id/3]). -export([create_dsl/3]). @@ -107,6 +103,7 @@ service_call({ServiceName, Function, Args}, #{woody_context := WoodyContext}) -> get_auth_context(#{swagger_context := #{auth_context := AuthContext}}) -> AuthContext. +-spec get_user_info(processing_context()) -> dmsl_payment_processing_thrift:'UserInfo'(). get_user_info(Context) -> #payproc_UserInfo{ id = get_user_id(Context), @@ -126,18 +123,6 @@ get_extra_properties(Context) -> Claims = capi_auth:get_legacy_claims(get_auth_context(Context)), maps:with(capi_auth_legacy:get_extra_properties(), Claims). -%% Common functions - --spec get_party(processing_context()) -> woody:result(). -get_party(Context) -> - Call = {party_management, 'Get', {}}, - service_call_with([user_info, party_id], Call, Context). - --spec get_party(binary(), processing_context()) -> woody:result(). -get_party(PartyID, Context) -> - Call = {party_management, 'Get', {PartyID}}, - service_call_with([user_info], Call, Context). - %% Utils -spec append_to_tuple(any(), tuple()) -> tuple(). @@ -275,16 +260,6 @@ get_payment_by_id(InvoiceID, PaymentID, Context) -> get_refund_by_id(InvoiceID, PaymentID, RefundID, Context) -> service_call_with([user_info], {invoicing, 'GetPaymentRefund', {InvoiceID, PaymentID, RefundID}}, Context). --spec get_contract_by_id(binary(), processing_context()) -> woody:result(). -get_contract_by_id(ContractID, Context) -> - Call = {party_management, 'GetContract', {ContractID}}, - service_call_with([user_info, party_id], Call, Context). - --spec get_contract_by_id(binary(), binary(), processing_context()) -> woody:result(). -get_contract_by_id(PartyID, ContractID, Context) -> - Call = {party_management, 'GetContract', {PartyID, ContractID}}, - service_call_with([user_info], Call, Context). - -spec create_dsl(atom(), map(), map()) -> map(). create_dsl(QueryType, QueryBody, QueryParams) -> merge_and_compact( diff --git a/apps/capi/src/capi_handler_webhooks.erl b/apps/capi/src/capi_handler_webhooks.erl index b0077b8..8bef3d4 100644 --- a/apps/capi/src/capi_handler_webhooks.erl +++ b/apps/capi/src/capi_handler_webhooks.erl @@ -26,8 +26,7 @@ prepare('CreateWebhook' = OperationID, Req, Context) -> Process = fun() -> WebhookParams = encode_webhook_params(PartyID, Params), ShopID = validate_webhook_params(WebhookParams), - Call = {party_management, 'GetShop', {PartyID, ShopID}}, - case capi_handler_utils:service_call_with([user_info], Call, Context) of + case capi_party:get_shop(PartyID, ShopID, Context) of {ok, _} -> case capi_handler_utils:service_call({webhook_manager, 'Create', {WebhookParams}}, Context) of {ok, Webhook} -> @@ -35,9 +34,9 @@ prepare('CreateWebhook' = OperationID, Req, Context) -> {exception, #webhooker_LimitExceeded{}} -> {ok, general_error(429, <<"Webhook limit exceeded">>)} end; - {exception, #payproc_InvalidUser{}} -> + {error, #payproc_InvalidUser{}} -> {ok, logic_error(invalidPartyID, <<"Party not found">>)}; - {exception, #payproc_ShopNotFound{}} -> + {error, #payproc_ShopNotFound{}} -> {ok, logic_error(invalidShopID, <<"Shop not found">>)} end end, @@ -269,11 +268,11 @@ decode_invoice_event_type({status_changed, #webhooker_InvoiceStatusChanged{value % TODO seems unmaintainable [ decode_invoice_status_event_type(V) - || V <- [ - ?invpaid(), - ?invcancelled(), - ?invfulfilled() - ] + || V <- [ + ?invpaid(), + ?invcancelled(), + ?invfulfilled() + ] ]; decode_invoice_event_type({status_changed, #webhooker_InvoiceStatusChanged{value = Value}}) -> [decode_invoice_status_event_type(Value)]; @@ -283,13 +282,13 @@ decode_invoice_event_type({payment, {status_changed, #webhooker_InvoicePaymentSt % TODO seems unmaintainable [ decode_payment_status_event_type(V) - || V <- [ - ?pmtprocessed(), - ?pmtcaptured(), - ?pmtcancelled(), - ?pmtrefunded(), - ?pmtfailed() - ] + || V <- [ + ?pmtprocessed(), + ?pmtcaptured(), + ?pmtcancelled(), + ?pmtrefunded(), + ?pmtfailed() + ] ]; decode_invoice_event_type({payment, {status_changed, #webhooker_InvoicePaymentStatusChanged{value = Value}}}) -> [decode_payment_status_event_type(Value)]; diff --git a/apps/capi/src/capi_party.erl b/apps/capi/src/capi_party.erl new file mode 100644 index 0000000..78d53ac --- /dev/null +++ b/apps/capi/src/capi_party.erl @@ -0,0 +1,133 @@ +-module(capi_party). + +-export([create_party/3]). +-export([get_party/2]). +-export([checkout_party/3]). +-export([activate_party/2]). +-export([suspend_party/2]). +-export([get_contract/3]). +-export([get_shop/3]). +-export([activate_shop/3]). +-export([suspend_shop/3]). +-export([compute_payment_institution_terms/3]). +-export([create_claim/3]). +-export([revoke_claim/5]). +-export([get_claim/3]). +-export([get_claims/2]). +-export([get_account_state/3]). + +-type result() :: ok | {ok, woody:result()} | {error, woody_error:business_error()}. +-type processing_context() :: capi_handler:processing_context(). + +-type party_id() :: party_client_thrift:party_id(). +-type party_params() :: party_client_thrift:party_params(). +-type party_revision_param() :: party_client_thrift:party_revision_param(). +-type payment_institution_ref() :: party_client_thrift:payment_institution_ref(). +-type varset() :: party_client_thrift:varset(). +-type contract_id() :: party_client_thrift:contract_id(). +-type shop_id() :: party_client_thrift:shop_id(). +-type claim_id() :: party_client_thrift:claim_id(). +-type claim_revision() :: party_client_thrift:claim_revision(). +-type changeset() :: party_client_thrift:changeset(). +-type revoke_reason() :: party_client_thrift:revoke_reason(). +-type account_id() :: party_client_thrift:account_id(). + +-spec create_party(party_id(), party_params(), processing_context()) -> result(). +create_party(PartyID, PartyParams, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:create(PartyID, PartyParams, Client, ClientContext). + +-spec get_party(party_id(), processing_context()) -> result(). +get_party(PartyID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:get(PartyID, Client, ClientContext). + +-spec checkout_party(party_id(), party_revision_param(), processing_context()) -> result(). +checkout_party(PartyID, PartyRevision, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:checkout(PartyID, PartyRevision, Client, ClientContext). + +-spec activate_party(party_id(), processing_context()) -> result(). +activate_party(PartyID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:activate(PartyID, Client, ClientContext). + +-spec suspend_party(party_id(), processing_context()) -> result(). +suspend_party(PartyID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:suspend(PartyID, Client, ClientContext). + +-spec get_contract(party_id(), contract_id(), processing_context()) -> result(). +get_contract(PartyID, ContractID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:get_contract(PartyID, ContractID, Client, ClientContext). + +-spec get_shop(party_id(), shop_id(), processing_context()) -> result(). +get_shop(PartyID, ShopID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:get_shop(PartyID, ShopID, Client, ClientContext). + +-spec activate_shop(party_id(), shop_id(), processing_context()) -> result(). +activate_shop(PartyID, ShopID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:activate_shop(PartyID, ShopID, Client, ClientContext). + +-spec suspend_shop(party_id(), shop_id(), processing_context()) -> result(). +suspend_shop(PartyID, ShopID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:suspend_shop(PartyID, ShopID, Client, ClientContext). + +-spec compute_payment_institution_terms( + payment_institution_ref(), + varset(), + processing_context() +) -> result(). +compute_payment_institution_terms(Ref, Varset, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:compute_payment_institution_terms( + Ref, + Varset, + Client, + ClientContext + ). + +-spec create_claim(party_id(), changeset(), processing_context()) -> result(). +create_claim(PartyID, Changeset, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:create_claim(PartyID, Changeset, Client, ClientContext). + +-spec revoke_claim( + party_id(), + claim_id(), + claim_revision(), + revoke_reason(), + processing_context() +) -> result(). +revoke_claim(PartyID, ClaimID, Revision, Reason, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:revoke_claim( + PartyID, + ClaimID, + Revision, + Reason, + Client, + ClientContext + ). + +-spec get_claim(party_id(), claim_id(), processing_context()) -> result(). +get_claim(PartyID, ClaimID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:get_claim(PartyID, ClaimID, Client, ClientContext). + +-spec get_claims(party_id(), processing_context()) -> result(). +get_claims(PartyID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:get_claims(PartyID, Client, ClientContext). + +-spec get_account_state(party_id(), account_id(), processing_context()) -> result(). +get_account_state(PartyID, AccountID, Context) -> + {Client, ClientContext} = client_context(Context), + party_client_thrift:get_account_state(PartyID, AccountID, Client, ClientContext). + +client_context(#{party_client := Client, party_client_context := ClientContext}) -> + {Client, ClientContext}. diff --git a/apps/capi/src/capi_sup.erl b/apps/capi/src/capi_sup.erl index 2246970..700a31e 100644 --- a/apps/capi/src/capi_sup.erl +++ b/apps/capi/src/capi_sup.erl @@ -23,26 +23,30 @@ start_link() -> -spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. init([]) -> + UacConf = get_uac_config(), + ok = uac:configure(UacConf), LechiffreOpts = genlib_app:env(capi, lechiffre_opts), LechiffreSpec = lechiffre:child_spec(lechiffre, LechiffreOpts), - {LogicHandler, LogicHandlerSpecs} = get_logic_handler_info(), HealthCheck = enable_health_logging(genlib_app:env(?APP, health_check, #{})), + BlacklistSpec = capi_api_key_blacklist:child_spec(), + PartyClient = party_client:create_client(), + PartyClientSpec = party_client:child_spec(party_client, PartyClient), + {LogicHandler, []} = get_logic_handler_info(#{party_client => PartyClient}), AdditionalRoutes = [{'_', [erl_health_handle:get_route(HealthCheck), get_prometheus_route()]}], SwaggerHandlerOpts = genlib_app:env(?APP, swagger_handler_opts, #{}), SwaggerSpec = capi_swagger_server:child_spec({AdditionalRoutes, LogicHandler, SwaggerHandlerOpts}), - BlacklistSpecs = capi_api_key_blacklist:child_spec(), - UacConf = get_uac_config(), - ok = uac:configure(UacConf), - {ok, { - {one_for_all, 0, 1}, - [LechiffreSpec] ++ LogicHandlerSpecs ++ [SwaggerSpec] ++ [BlacklistSpecs] - }}. + {ok, + { + {one_for_all, 0, 1}, + [LechiffreSpec, SwaggerSpec, BlacklistSpec, PartyClientSpec] + }}. --spec get_logic_handler_info() -> {Handler :: atom(), [Spec :: supervisor:child_spec()] | []}. -get_logic_handler_info() -> +-spec get_logic_handler_info(capi_handler:handler_opts()) -> + {Handler :: swag_server:logic_handler(_), [Spec :: supervisor:child_spec()] | []}. +get_logic_handler_info(HandlerOpts) -> case genlib_app:env(?APP, service_type) of real -> - {capi_handler, []}; + {{capi_handler, HandlerOpts}, []}; undefined -> exit(undefined_service_type) end. diff --git a/apps/capi/src/capi_swagger_server.erl b/apps/capi/src/capi_swagger_server.erl index 00058c7..02e04ee 100644 --- a/apps/capi/src/capi_swagger_server.erl +++ b/apps/capi/src/capi_swagger_server.erl @@ -10,7 +10,11 @@ -define(START_TIME_TAG, processing_start_time). --type params() :: {cowboy_router:routes(), module(), swag_server_router:swagger_handler_opts()}. +-type params() :: { + cowboy_router:routes(), + swag_server:logic_handler(_), + swag_server_router:swagger_handler_opts() +}. -spec child_spec(params()) -> supervisor:child_spec(). child_spec({AdditionalRoutes, LogicHandler, SwaggerHandlerOpts}) -> diff --git a/apps/capi/test/capi_authorization_tests_SUITE.erl b/apps/capi/test/capi_authorization_tests_SUITE.erl index 014a5ed..dadf98e 100644 --- a/apps/capi/test/capi_authorization_tests_SUITE.erl +++ b/apps/capi/test/capi_authorization_tests_SUITE.erl @@ -112,7 +112,15 @@ authorization_far_future_deadline_ok_test(_Config) -> -spec authorization_permission_ok_test(config()) -> _. authorization_permission_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} + ], + Config + ), {ok, Token} = capi_ct_helper:issue_token([{[party], read}], unlimited), {ok, _} = capi_client_parties:get_my_party(capi_ct_helper:get_context(Token)). diff --git a/apps/capi/test/capi_base_api_token_tests_SUITE.erl b/apps/capi/test/capi_base_api_token_tests_SUITE.erl index b0a149f..63db668 100644 --- a/apps/capi/test/capi_base_api_token_tests_SUITE.erl +++ b/apps/capi/test/capi_base_api_token_tests_SUITE.erl @@ -1102,7 +1102,15 @@ get_account_by_id_ok_test(Config) -> -spec get_my_party_ok_test(config()) -> _. get_my_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} + ], + Config + ), _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetMyParty">>, ?STRING, Config), {ok, _} = capi_client_parties:get_my_party(?config(context, Config)). @@ -1120,7 +1128,15 @@ activate_my_party_ok_test(Config) -> -spec get_party_by_id_ok_test(config()) -> _. get_party_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} + ], + Config + ), _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetPartyByID">>, ?STRING, Config), {ok, _} = capi_client_parties:get_party_by_id(?config(context, Config), ?STRING). @@ -1175,7 +1191,15 @@ get_shop_by_id_for_party_error_test(Config) -> -spec get_shops_ok_test(config()) -> _. get_shops_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} + ], + Config + ), _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetShops">>, ?STRING, Config), {ok, _} = capi_client_shops:get_shops(?config(context, Config)). @@ -1183,7 +1207,10 @@ get_shops_ok_test(Config) -> get_shops_for_party_ok_test(Config) -> _ = capi_ct_helper:mock_services( [ - {party_management, fun('Get', _) -> {ok, ?PARTY} end} + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} ], Config ), @@ -1193,9 +1220,10 @@ get_shops_for_party_ok_test(Config) -> -spec get_shops_for_party_error_test(config()) -> _. get_shops_for_party_error_test(Config) -> _ = capi_ct_helper:mock_services( - [{party_management, fun('Get', {_, <<"WrongPartyID">>}) -> {throwing, #payproc_InvalidUser{}} end}], + [{party_management, fun('GetRevision', {_, <<"WrongPartyID">>}) -> {throwing, #payproc_InvalidUser{}} end}], Config ), + _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetShopsForParty">>, <<"WrongPartyID">>, Config), ?assertMatch( {error, {404, _}}, @@ -1487,7 +1515,17 @@ create_claim_invalid_residence_test(Config) -> -spec get_contract_by_id_ok_test(config()) -> _. get_contract_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY}; + ('GetContract', _) -> {ok, ?CONTRACT} + end} + ], + Config + ), + _ = capi_ct_helper_bouncer:mock_arbiter( ?assertContextMatches( #bctx_v1_ContextFragment{ @@ -1501,7 +1539,17 @@ get_contract_by_id_ok_test(Config) -> -spec get_contract_by_id_for_party_ok_test(config()) -> _. get_contract_by_id_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY}; + ('GetContract', _) -> {ok, ?CONTRACT} + end} + ], + Config + ), + _ = capi_ct_helper_bouncer:mock_assert_contract_op_ctx( <<"GetContractByIDForParty">>, ?STRING, @@ -1512,13 +1560,30 @@ get_contract_by_id_for_party_ok_test(Config) -> -spec get_contracts_ok_test(config()) -> _. get_contracts_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} + ], + Config + ), + _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetContracts">>, ?STRING, Config), {ok, [_First, _Second]} = capi_client_contracts:get_contracts(?config(context, Config)). -spec get_contracts_for_party_ok_test(config()) -> _. get_contracts_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, ?PARTY} end}], Config), + _ = capi_ct_helper:mock_services( + [ + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} + ], + Config + ), _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetContractsForParty">>, ?STRING, Config), {ok, [_First, _Second]} = capi_client_contracts:get_contracts_for_party(?config(context, Config), ?STRING). @@ -1527,8 +1592,9 @@ get_contract_adjustments_ok_test(Config) -> _ = capi_ct_helper:mock_services( [ {party_management, fun - ('GetContract', _) -> {ok, ?CONTRACT}; - ('Get', _) -> {ok, ?PARTY} + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY}; + ('GetContract', _) -> {ok, ?CONTRACT} end} ], Config @@ -1557,8 +1623,9 @@ get_contract_adjustment_by_id_ok_test(Config) -> _ = capi_ct_helper:mock_services( [ {party_management, fun - ('GetContract', _) -> {ok, ?CONTRACT}; - ('Get', _) -> {ok, ?PARTY} + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY}; + ('GetContract', _) -> {ok, ?CONTRACT} end} ], Config diff --git a/apps/capi/test/capi_ct_helper.erl b/apps/capi/test/capi_ct_helper.erl index 7e9ce90..21960ce 100644 --- a/apps/capi/test/capi_ct_helper.erl +++ b/apps/capi/test/capi_ct_helper.erl @@ -40,8 +40,7 @@ init_suite(Module, Config) -> -spec init_suite(module(), config(), any()) -> config(). init_suite(Module, Config, CapiEnv) -> SupPid = start_mocked_service_sup(Module), - Apps1 = - start_app(woody), + WoodyApp = start_app(woody), ServiceURLs = mock_services_( [ { @@ -52,11 +51,15 @@ init_suite(Module, Config, CapiEnv) -> ], SupPid ), - Apps2 = - start_app(dmt_client, [{max_cache_size, #{}}, {service_urls, ServiceURLs}, {cache_update_interval, 50000}]) ++ - start_capi(Config, CapiEnv) ++ - capi_ct_helper_bouncer:mock_client(SupPid), - [{apps, lists:reverse(Apps1 ++ Apps2)}, {suite_test_sup, SupPid} | Config]. + DmtApp = start_app(dmt_client, [ + {max_cache_size, #{}}, + {service_urls, ServiceURLs}, + {cache_update_interval, 50000} + ]), + CapiApp = start_capi(Config, CapiEnv), + BouncerApp = capi_ct_helper_bouncer:mock_client(SupPid), + Apps = lists:reverse([WoodyApp, DmtApp, CapiApp, BouncerApp]), + [{apps, Apps}, {suite_test_sup, SupPid} | Config]. -spec start_app(app_name()) -> [app_name()]. start_app(woody = AppName) -> @@ -184,15 +187,27 @@ stop_mocked_service_sup(SupPid) -> -spec mock_services(_, _) -> _. mock_services(Services, SupOrConfig) -> - {BenderClientServices, WoodyServices} = lists:partition( - fun({ServiceName, _}) -> - ServiceName == generator + {PartyClientServices, Other} = lists:partition( + fun + ({party_management, _}) -> true; + (_) -> false end, Services ), + {BenderClientServices, WoodyServices} = lists:partition( + fun + ({generator, _}) -> true; + (_) -> false + end, + Other + ), + _ = start_party_client(mock_services_(PartyClientServices, SupOrConfig)), _ = start_bender_client(mock_services_(BenderClientServices, SupOrConfig)), start_woody_client(mock_services_(WoodyServices, SupOrConfig)). +start_party_client(Services) -> + start_app(party_client, [{services, Services}]). + start_bender_client(Services) -> start_app(bender_client, [{services, Services}]). @@ -201,6 +216,8 @@ start_woody_client(Services) -> -spec mock_services_(_, _) -> _. % TODO need a better name +mock_services_([], _Config) -> + #{}; mock_services_(Services, Config) when is_list(Config) -> mock_services_(Services, ?config(test_sup, Config)); mock_services_(Services, SupPid) when is_pid(SupPid) -> @@ -234,6 +251,8 @@ get_service_name({ServiceName, _WoodyService, _Fun}) -> mock_service_handler({generator, Fun}) -> mock_service_handler('Generator', {bender_thrift, 'Generator'}, Fun); +mock_service_handler({party_management, Fun}) -> + mock_service_handler(party_management, {dmsl_payment_processing_thrift, 'PartyManagement'}, Fun); mock_service_handler({ServiceName, Fun}) -> mock_service_handler(ServiceName, capi_woody_client:get_service_modname(ServiceName), Fun); mock_service_handler({ServiceName, WoodyService, Fun}) -> diff --git a/apps/capi/test/capi_deadline_tests_SUITE.erl b/apps/capi/test/capi_deadline_tests_SUITE.erl index a0a721b..1a12adc 100644 --- a/apps/capi/test/capi_deadline_tests_SUITE.erl +++ b/apps/capi/test/capi_deadline_tests_SUITE.erl @@ -3,6 +3,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("damsel/include/dmsl_domain_thrift.hrl"). +-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl"). -include_lib("capi_dummy_data.hrl"). -export([all/0]). @@ -118,16 +119,16 @@ deadline_absolute_ok_test(Config) -> Context = ?config(context_with_absolute_deadline, Config), _ = capi_ct_helper:mock_services( [ - {party_management, fun('Get', _) -> - timer:sleep(5000), - {ok, ?PARTY} + {invoicing, fun('Get', _) -> + timer:sleep(10000), + {ok, ?PAYPROC_INVOICE} end} ], Config ), Deadline = woody_deadline:from_timeout(3000), BinDeadline = woody_deadline:to_binary(Deadline), - ?badresp(504) = capi_client_parties:get_my_party(Context#{deadline => BinDeadline}), + ?badresp(504) = capi_client_invoices:get_invoice_by_id(Context#{deadline => BinDeadline}, ?STRING), Deadline2 = woody_deadline:from_timeout(3000), BinDeadline2 = woody_deadline:to_binary(Deadline2), {ok, _} = capi_client_categories:get_categories(Context#{deadline => BinDeadline2}). @@ -137,14 +138,14 @@ deadline_relative_ok_test(Config) -> Context = ?config(context_with_relative_deadline, Config), _ = capi_ct_helper:mock_services( [ - {party_management, fun('Get', _) -> + {invoicing, fun('Get', _) -> timer:sleep(10000), - {ok, ?PARTY} + {ok, ?PAYPROC_INVOICE} end} ], Config ), - ?badresp(504) = capi_client_parties:get_my_party(Context), + ?badresp(504) = capi_client_invoices:get_invoice_by_id(Context, ?STRING), {ok, _} = capi_client_categories:get_categories(Context). get_context(Token, Deadline) -> diff --git a/apps/capi/test/capi_idempotency_tests_SUITE.erl b/apps/capi/test/capi_idempotency_tests_SUITE.erl index f932bea..c447f43 100644 --- a/apps/capi/test/capi_idempotency_tests_SUITE.erl +++ b/apps/capi/test/capi_idempotency_tests_SUITE.erl @@ -143,10 +143,12 @@ init_per_group(payment_creation, Config) -> SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE), Apps1 = capi_ct_helper_tk:mock_service(capi_ct_helper_tk:user_session_handler(), SupPid), Apps2 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid), - {{ok, #{ + { + {ok, #{ <<"invoiceAccessToken">> := #{<<"payload">> := InvAccToken} }}, - _} = + _ + } = with_feature_storage(fun() -> capi_client_invoices:create_invoice(capi_ct_helper:get_context(Token, ExtraProperties), Req) end), @@ -854,7 +856,7 @@ create_customers(BenderKey, Requests, Config) -> ), [ with_feature_storage(fun() -> capi_client_customers:create_customer(Context, R) end) - || R <- Requests + || R <- Requests ] end ). @@ -886,7 +888,7 @@ create_customer_bindings(BenderKey, Requests, Config) -> ), [ with_feature_storage(fun() -> capi_client_customers:create_binding(Context, ?STRING, R) end) - || R <- Requests + || R <- Requests ] end ). @@ -911,7 +913,7 @@ create_invoice_templates(BenderKey, Requests, Config) -> ), [ with_feature_storage(fun() -> capi_client_invoice_templates:create(Context, R) end) - || R <- Requests + || R <- Requests ] end ). @@ -941,7 +943,7 @@ create_invoices_with_templates(BenderKey, Requests, Config) -> with_feature_storage(fun() -> capi_client_invoice_templates:create_invoice(Context, InvoiceTemplateID, Request) end) - || {InvoiceTemplateID, Request} <- Requests + || {InvoiceTemplateID, Request} <- Requests ] end ). diff --git a/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl b/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl index 0249b33..024c8da 100644 --- a/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl +++ b/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl @@ -234,7 +234,10 @@ get_invoice_payment_methods_ok_test(Config) -> ('ComputeTerms', _) -> {ok, ?TERM_SET}; ('Get', _) -> {ok, ?PAYPROC_INVOICE} end}, - {party_management, fun('Get', _) -> {ok, ?PARTY} end} + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} ], Config ), diff --git a/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl b/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl index c0bf6a0..f2d4ff1 100644 --- a/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl +++ b/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl @@ -176,7 +176,10 @@ get_invoice_payment_methods_by_tpl_id_ok_test(Config) -> ('ComputeTerms', _) -> {ok, ?TERM_SET}; ('Get', _) -> {ok, ?INVOICE_TPL} end}, - {party_management, fun('Get', _) -> {ok, ?PARTY} end} + {party_management, fun + ('GetRevision', _) -> {ok, ?INTEGER}; + ('Checkout', _) -> {ok, ?PARTY} + end} ], Config ), diff --git a/apps/capi/test/capi_self_tests_SUITE.erl b/apps/capi/test/capi_self_tests_SUITE.erl index 0ba9919..bb574ac 100644 --- a/apps/capi/test/capi_self_tests_SUITE.erl +++ b/apps/capi/test/capi_self_tests_SUITE.erl @@ -111,9 +111,10 @@ end_per_testcase(_Name, C) -> -spec oops_body_test(config()) -> _. oops_body_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, "spanish inquisition"} end}], Config), + _ = capi_ct_helper:mock_services([{invoicing, fun('Get', _) -> {ok, "spanish inquisition"} end}], Config), Context = ?config(context, Config), - {Endpoint, PreparedParams, Opts0} = capi_client_lib:make_request(Context, #{}), + Params = #{binding => #{<<"invoiceID">> => ?STRING}}, + {Endpoint, PreparedParams, Opts0} = capi_client_lib:make_request(Context, Params), Url = swag_client_utils:get_url(Endpoint, "/v2/processing/me"), Headers = maps:to_list(maps:get(header, PreparedParams)), Body = <<"{}">>, diff --git a/apps/capi/test/capi_woody_tests_SUITE.erl b/apps/capi/test/capi_woody_tests_SUITE.erl index a4bc677..ec9d8db 100644 --- a/apps/capi/test/capi_woody_tests_SUITE.erl +++ b/apps/capi/test/capi_woody_tests_SUITE.erl @@ -1,6 +1,8 @@ -module(capi_woody_tests_SUITE). -include_lib("common_test/include/ct.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). +-include_lib("capi_dummy_data.hrl"). -export([all/0]). -export([groups/0]). @@ -102,38 +104,38 @@ end_per_testcase(_Name, C) -> -spec woody_unexpected_test(config()) -> _. woody_unexpected_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> {ok, "spanish inquisition"} end}], Config), - ?badresp(500) = capi_client_parties:get_my_party(?config(context, Config)). + _ = capi_ct_helper:mock_services([{invoicing, fun('Get', _) -> {ok, "spanish inquisition"} end}], Config), + ?badresp(500) = capi_client_invoices:get_invoice_by_id(?config(context, Config), ?STRING). -spec woody_unavailable_test(config()) -> _. woody_unavailable_test(Config) -> _ = capi_ct_helper:start_app(capi_woody_client, [ {services, #{ - party_management => #{url => <<"http://spanish.inquision/v1/partymgmt">>} + invoicing => #{url => <<"http://spanish.inquision/v1/partymgmt">>} }} ]), - ?badresp(503) = capi_client_parties:get_my_party(?config(context, Config)). + ?badresp(503) = capi_client_invoices:get_invoice_by_id(?config(context, Config), ?STRING). -spec woody_retry_test(config()) -> _. woody_retry_test(Config) -> _ = capi_ct_helper:start_app(capi_woody_client, [ {services, #{ - party_management => #{url => <<"http://spanish.inquision/v1/partymgmt">>} + invoicing => #{url => <<"http://spanish.inquision/v1/partymgmt">>} }}, {service_retries, #{ - party_management => #{ + invoicing => #{ 'Get' => {linear, 30, 1000}, '_' => finish } }}, {service_deadlines, #{ - party_management => 5000 + invoicing => 5000 }} ]), - {Time, ?badresp(503)} = timer:tc(capi_client_parties, get_my_party, [?config(context, Config)]), + {Time, ?badresp(503)} = timer:tc(capi_client_invoices, get_invoice_by_id, [?config(context, Config), ?STRING]), true = (Time > 3000000) and (Time < 10000000). -spec woody_unknown_test(config()) -> _. woody_unknown_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Get', _) -> timer:sleep(60000) end}], Config), - ?badresp(504) = capi_client_parties:get_my_party(?config(context, Config)). + _ = capi_ct_helper:mock_services([{invoicing, fun('Get', _) -> timer:sleep(60000) end}], Config), + ?badresp(504) = capi_client_invoices:get_invoice_by_id(?config(context, Config), ?STRING). diff --git a/apps/capi_woody_client/src/capi_woody_client.erl b/apps/capi_woody_client/src/capi_woody_client.erl index 71b94fc..becffb5 100644 --- a/apps/capi_woody_client/src/capi_woody_client.erl +++ b/apps/capi_woody_client/src/capi_woody_client.erl @@ -13,7 +13,10 @@ transport_opts => woody_client_thrift_http_transport:transport_options() }. --spec call_service(service_name(), woody:func(), tuple(), woody_context:ctx()) -> woody:result(). +-spec call_service(service_name(), woody:func(), tuple(), woody_context:ctx()) -> + {ok, woody:result()} + | {exception, woody_error:business_error()} + | no_return(). call_service(ServiceName, Function, Args, Context0) -> Deadline = get_service_deadline(ServiceName), Context1 = set_deadline(Deadline, Context0), diff --git a/build_utils b/build_utils index c67c259..a7655bc 160000 --- a/build_utils +++ b/build_utils @@ -1 +1 @@ -Subproject commit c67c2590c921274e0d03fbdb437c893bb035fba4 +Subproject commit a7655bc60c877a65cdfe3d9b668021d970d88a76 diff --git a/config/sys.config b/config/sys.config index 11da705..cf33b54 100644 --- a/config/sys.config +++ b/config/sys.config @@ -122,6 +122,31 @@ }} ]}, + {party_client, [ + {services, #{ + 'party_management' => "http://hellgate:8022/v1/processing/partymgmt" + }}, + {woody, #{ + cache_mode => safe, % disabled | safe | aggressive + options => #{ + woody_client => #{ + event_handler => {scoper_woody_event_handler, #{ + event_handler_opts => #{ + formatter_opts => #{ + max_length => 1000 + } + } + }} + } + }, + %retries => #{ + % 'GetRevision' => finish, + % '_' => finish + %}, + deadline_timeout => 60000 + }} + ]}, + {bender_client, [ {services, #{ 'Bender' => <<"http://bender:8022/v1/bender">>, diff --git a/rebar.config b/rebar.config index 5edc088..09ce285 100644 --- a/rebar.config +++ b/rebar.config @@ -48,7 +48,8 @@ {prometheus_cowboy, "0.1.8"}, {bouncer_proto, {git, "https://github.com/rbkmoney/bouncer-proto.git", {branch, master}}}, {bouncer_client, {git, "https://github.com/rbkmoney/bouncer_client_erlang.git", {branch, master}}}, - {token_keeper_client, {git, "git@github.com:rbkmoney/token-keeper-client.git", {branch, master}}} + {token_keeper_client, {git, "git@github.com:rbkmoney/token-keeper-client.git", {branch, master}}}, + {party_client, {git, "https://github.com/rbkmoney/party_client_erlang.git", {branch, master}}} ]}. %% XRef checks @@ -120,7 +121,7 @@ ]}. {plugins, [ - {erlfmt, "0.10.0"} + {erlfmt, "0.15.1"} ]}. {erlfmt, [ diff --git a/rebar.lock b/rebar.lock index f18a39a..576a2fa 100644 --- a/rebar.lock +++ b/rebar.lock @@ -15,10 +15,10 @@ 0}, {<<"bouncer_proto">>, {git,"https://github.com/rbkmoney/bouncer-proto.git", - {ref,"584e0edf326ad77948f26b19d2e280b0da3e01a5"}}, + {ref,"60cedce6c0147558e3ba322387151d23b001d68b"}}, 0}, {<<"cache">>,{pkg,<<"cache">>,<<"2.3.3">>},1}, - {<<"certifi">>,{pkg,<<"certifi">>,<<"2.5.3">>},1}, + {<<"certifi">>,{pkg,<<"certifi">>,<<"2.6.1">>},1}, {<<"cg_mon">>, {git,"https://github.com/rbkmoney/cg_mon.git", {ref,"5a87a37694e42b6592d3b4164ae54e0e87e24e18"}}, @@ -43,16 +43,16 @@ 0}, {<<"dmt_client">>, {git,"https://github.com/rbkmoney/dmt_client.git", - {ref,"9e11f50e9c4db32fe46d6f8a2429ca060a3acd57"}}, + {ref,"37f376e239a2182cbb2a7a052797e99955edbaad"}}, 0}, {<<"dmt_core">>, {git,"https://github.com/rbkmoney/dmt_core.git", {ref,"5a0ff399dee3fd606bb864dd0e27ddde539345e2"}}, 1}, - {<<"email_validator">>,{pkg,<<"email_validator">>,<<"1.0.0">>},0}, + {<<"email_validator">>,{pkg,<<"email_validator">>,<<"1.1.0">>},0}, {<<"erl_health">>, {git,"https://github.com/rbkmoney/erlang-health.git", - {ref,"982af88738ca062eea451436d830eef8c1fbe3f9"}}, + {ref,"5958e2f35cd4d09f40685762b82b82f89b4d9333"}}, 0}, {<<"folsom">>, {git,"https://github.com/folsom-project/folsom.git", @@ -62,12 +62,12 @@ {git,"https://github.com/rbkmoney/genlib.git", {ref,"3e1776536802739d8819351b15d54ec70568aba7"}}, 0}, - {<<"gproc">>,{pkg,<<"gproc">>,<<"0.8.0">>},1}, + {<<"gproc">>,{pkg,<<"gproc">>,<<"0.9.0">>},1}, {<<"gun">>, {git,"https://github.com/ninenines/gun.git", {ref,"e7dd9f227e46979d8073e71c683395a809b78cb4"}}, 1}, - {<<"hackney">>,{pkg,<<"hackney">>,<<"1.17.0">>},0}, + {<<"hackney">>,{pkg,<<"hackney">>,<<"1.17.4">>},0}, {<<"how_are_you">>, {git,"https://github.com/rbkmoney/how_are_you.git", {ref,"8f11d17eeb6eb74096da7363a9df272fd3099718"}}, @@ -78,10 +78,10 @@ {ref,"9b980b7f9ce09b6a136fe5a23d404d1b903f3061"}}, 0}, {<<"jose">>,{pkg,<<"jose">>,<<"1.11.1">>},0}, - {<<"jsx">>,{pkg,<<"jsx">>,<<"3.0.0">>},0}, + {<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},0}, {<<"lechiffre">>, {git,"https://github.com/rbkmoney/lechiffre.git", - {ref,"a9ea635b9db03ec58e7cb2f015f124aa9edf0c4b"}}, + {ref,"7915b7650abc80535d8c183642c5a409c942edf0"}}, 0}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},1}, {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},1}, @@ -93,9 +93,10 @@ {git,"git@github.com:rbkmoney/org-management-proto.git", {ref,"06c5c8430e445cb7874e54358e457cbb5697fc32"}}, 1}, - {<<"parse_trans">>, - {git,"https://github.com/uwiger/parse_trans.git", - {ref,"8ba366f81789c913cd63d69c6d1da948c200d18a"}}, + {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.0">>},0}, + {<<"party_client">>, + {git,"https://github.com/rbkmoney/party_client_erlang.git", + {ref,"a6471d4074f8098f8db0da57a2e676a22804d3ff"}}, 0}, {<<"payproc_errors">>, {git,"https://github.com/rbkmoney/payproc-errors-erlang.git", @@ -107,7 +108,7 @@ {<<"ranch">>,{pkg,<<"ranch">>,<<"1.7.1">>},1}, {<<"reporter_proto">>, {git,"https://github.com/rbkmoney/reporter-proto.git", - {ref,"fa3631e940d544003ce4c25787d91d80cc9b386f"}}, + {ref,"aafbfac4463711d43f8e8ed4da103967b95e1fb6"}}, 0}, {<<"scoper">>, {git,"https://github.com/rbkmoney/scoper.git", @@ -137,7 +138,7 @@ {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, {<<"woody">>, {git,"https://github.com/rbkmoney/woody_erlang.git", - {ref,"f2cd30883d58eb1c3ab2172556956f757bc27e23"}}, + {ref,"d9fca6da55a46e39bdb7ad2c0dba0b7205a7e70b"}}, 0}, {<<"woody_user_identity">>, {git,"https://github.com/rbkmoney/woody_erlang_user_identity.git", @@ -148,17 +149,18 @@ {<<"accept">>, <<"B33B127ABCA7CC948BBE6CAA4C263369ABF1347CFA9D8E699C6D214660F10CD1">>}, {<<"bear">>, <<"16264309AE5D005D03718A5C82641FCC259C9E8F09ADEB6FD79CA4271168656F">>}, {<<"cache">>, <<"B23A5FE7095445A88412A6E614C933377E0137B44FFED77C9B3FEF1A731A20B2">>}, - {<<"certifi">>, <<"70BDD7E7188C804F3A30EE0E7C99655BC35D8AC41C23E12325F36AB449B70651">>}, + {<<"certifi">>, <<"DBAB8E5E155A0763EEA978C913CA280A6B544BFA115633FA20249C3D396D9493">>}, {<<"cowboy">>, <<"91ED100138A764355F43316B1D23D7FF6BDB0DE4EA618CB5D8677C93A7A2F115">>}, {<<"cowlib">>, <<"FD0FF1787DB84AC415B8211573E9A30A3EBE71B5CBFF7F720089972B2319C8A4">>}, - {<<"email_validator">>, <<"3F942B6AF1A309165B9399C71D5251EF5933774CEBC59EEAF18A7D9C4A8FA092">>}, - {<<"gproc">>, <<"CEA02C578589C61E5341FCE149EA36CCEF236CC2ECAC8691FBA408E7EA77EC2F">>}, - {<<"hackney">>, <<"717EA195FD2F898D9FE9F1CE0AFCC2621A41ECFE137FAE57E7FE6E9484B9AA99">>}, + {<<"email_validator">>, <<"7E09A862E9AA99AE2CA6FD2A718D2B94360E32940A1339B53DFEE6B774BCDB03">>}, + {<<"gproc">>, <<"853CCB7805E9ADA25D227A157BA966F7B34508F386A3E7E21992B1B484230699">>}, + {<<"hackney">>, <<"99DA4674592504D3FB0CFEF0DB84C3BA02B4508BAE2DFF8C0108BAA0D6E0977C">>}, {<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>}, {<<"jose">>, <<"59DA64010C69AAD6CDE2F5B9248B896B84472E99BD18F246085B7B9FE435DCDB">>}, - {<<"jsx">>, <<"20A170ABD4335FC6DB24D5FAD1E5D677C55DADF83D1B20A8A33B5FE159892A39">>}, + {<<"jsx">>, <<"D12516BAA0BB23A59BB35DCCAF02A1BD08243FCBB9EFE24F2D9D056CCFF71268">>}, {<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>}, {<<"mimerl">>, <<"67E2D3F571088D5CFD3E550C383094B47159F3EEE8FFA08E64106CDF5E981BE3">>}, + {<<"parse_trans">>, <<"BB87AC362A03CA674EBB7D9D498F45C03256ADED7214C9101F7035EF44B798C7">>}, {<<"prometheus">>, <<"20510F381DB1CCAB818B4CF2FAC5FA6AB5CC91BC364A154399901C001465F46F">>}, {<<"prometheus_cowboy">>, <<"CFCE0BC7B668C5096639084FCD873826E6220EA714BF60A716F5BD080EF2A99C">>}, {<<"prometheus_httpd">>, <<"F616ED9B85B536B195D94104063025A91F904A4CFC20255363F49A197D96C896">>}, @@ -169,17 +171,18 @@ {<<"accept">>, <<"11B18C220BCC2EAB63B5470C038EF10EB6783BCB1FCDB11AA4137DEFA5AC1BB8">>}, {<<"bear">>, <<"534217DCE6A719D59E54FB0EB7A367900DBFC5F85757E8C1F94269DF383F6D9B">>}, {<<"cache">>, <<"44516CE6FA03594D3A2AF025DD3A87BFE711000EB730219E1DDEFC816E0AA2F4">>}, - {<<"certifi">>, <<"ED516ACB3929B101208A9D700062D520F3953DA3B6B918D866106FFA980E1C10">>}, + {<<"certifi">>, <<"524C97B4991B3849DD5C17A631223896272C6B0AF446778BA4675A1DFF53BB7E">>}, {<<"cowboy">>, <<"04FD8C6A39EDC6AAA9C26123009200FC61F92A3A94F3178C527B70B767C6E605">>}, {<<"cowlib">>, <<"79F954A7021B302186A950A32869DBC185523D99D3E44CE430CD1F3289F41ED4">>}, - {<<"email_validator">>, <<"44CBDB6E9615FE3D558715E4E6D60610E934CD3FE4B8C650FEC5C560304526D6">>}, - {<<"gproc">>, <<"580ADAFA56463B75263EF5A5DF4C86AF321F68694E7786CB057FD805D1E2A7DE">>}, - {<<"hackney">>, <<"64C22225F1EA8855F584720C0E5B3CD14095703AF1C9FBC845BA042811DC671C">>}, + {<<"email_validator">>, <<"2B1E6DF7BB14155C8D7D131F1C95CF4676200BC056EEBA82123396833FF94DA2">>}, + {<<"gproc">>, <<"587E8AF698CCD3504CF4BA8D90F893EDE2B0F58CABB8A916E2BF9321DE3CF10B">>}, + {<<"hackney">>, <<"DE16FF4996556C8548D512F4DBE22DD58A587BF3332E7FD362430A7EF3986B16">>}, {<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>}, {<<"jose">>, <<"078F6C9FB3CD2F4CFAFC972C814261A7D1E8D2B3685C0A76EB87E158EFFF1AC5">>}, - {<<"jsx">>, <<"37BECA0435F5CA8A2F45F76A46211E76418FBEF80C36F0361C249FC75059DC6D">>}, + {<<"jsx">>, <<"0C5CC8FDC11B53CC25CF65AC6705AD39E54ECC56D1C22E4ADB8F5A53FB9427F3">>}, {<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>}, {<<"mimerl">>, <<"F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323">>}, + {<<"parse_trans">>, <<"F99E368830BEA44552224E37E04943A54874F08B8590485DE8D13832B63A2DC3">>}, {<<"prometheus">>, <<"4905FD2992F8038ECCD7AA0CD22F40637ED618C0BED1F75C05AACEC15B7545DE">>}, {<<"prometheus_cowboy">>, <<"BA286BECA9302618418892D37BCD5DC669A6CC001F4EB6D6AF85FF81F3F4F34C">>}, {<<"prometheus_httpd">>, <<"0BBE831452CFDF9588538EB2F570B26F30C348ADAE5E95A7D87F35A5910BCF92">>},