1:- module(bitrix24_install, [
    2          payload_context/3,
    3          payload_contexts/2,
    4          save_payload_contexts/3
    5      ]).    6
    7:- use_module(library(json)).    8
    9payload_context(Payload, ContextRef, Context) :-
   10    normalize_install_payload(Payload, Normalized),
   11    extract_context_ref(Normalized, ContextRef),
   12    build_context(Normalized, Context).
   13
   14payload_contexts(Payload, ContextPairs) :-
   15    payload_context(Payload, ContextRef, Context),
   16    ContextPairs = [ContextRef-Context].
   17
   18save_payload_contexts(Provider, Payload, ContextPairs) :-
   19    payload_contexts(Payload, ContextPairs),
   20    forall(member(ContextRef-Context, ContextPairs),
   21           call(Provider:save_context(ContextRef, Context))).
   22
   23normalize_install_payload(Payload, Payload) :-
   24    is_dict(Payload),
   25    !.
   26normalize_install_payload(form(Pairs), Dict) :-
   27    !,
   28    pairs_to_dict(Pairs, Dict).
   29normalize_install_payload(Pairs, Dict) :-
   30    is_list(Pairs),
   31    pairs_to_dict(Pairs, Dict).
   32
   33pairs_to_dict(Pairs, Dict) :-
   34    findall(Key-Value,
   35            ( member(Pair, Pairs),
   36              pair_key_value(Pair, Key, Value)
   37            ),
   38            DictPairs),
   39    dict_pairs(Dict, install, DictPairs).
   40
   41pair_key_value(Key=Value, Key, Value).
   42pair_key_value(Key-Value, Key, Value).
   43
   44extract_context_ref(Payload, member(MemberID)) :-
   45    payload_value(Payload, 'auth[member_id]', MemberID0),
   46    normalize_member_id(MemberID0, MemberID),
   47    !.
   48extract_context_ref(_Payload, global).
   49
   50build_context(Payload, Context) :-
   51    derive_expires_at(Payload, ExpiresAt),
   52    payload_optional_value(Payload, 'auth[member_id]', MemberID),
   53    payload_value(Payload, 'auth[access_token]', AccessToken),
   54    payload_value(Payload, 'auth[refresh_token]', RefreshToken),
   55    payload_value(Payload, 'auth[client_endpoint]', ClientEndpoint),
   56    payload_optional_value(Payload, 'auth[server_endpoint]', ServerEndpoint),
   57    payload_optional_value(Payload, 'auth[application_token]', ApplicationToken),
   58    payload_optional_value(Payload, 'auth[user_id]', UserID),
   59    payload_optional_value(Payload, 'auth[domain]', Domain),
   60    Context = _{
   61        member_id: MemberID,
   62        access_token: AccessToken,
   63        refresh_token: RefreshToken,
   64        expires_at: ExpiresAt,
   65        client_endpoint: ClientEndpoint,
   66        server_endpoint: ServerEndpoint,
   67        application_token: ApplicationToken,
   68        user_id: UserID,
   69        domain: Domain
   70    }.
   71
   72derive_expires_at(Payload, ExpiresAt) :-
   73    payload_optional_value(Payload, 'auth[expires]', ExpiresValue),
   74    normalize_optional_integer(ExpiresValue, ExpiresAt),
   75    ExpiresAt > 0,
   76    !.
   77derive_expires_at(Payload, ExpiresAt) :-
   78    payload_value(Payload, 'auth[expires_in]', ExpiresInValue),
   79    normalize_integer(ExpiresInValue, ExpiresIn),
   80    get_time(Now),
   81    ExpiresAt is floor(Now) + ExpiresIn.
   82
   83payload_value(Payload, Key, Value) :-
   84    atom(Key),
   85    get_dict(Key, Payload, Value),
   86    !.
   87payload_value(Payload, Key, Value) :-
   88    string(Key),
   89    atom_string(KeyAtom, Key),
   90    get_dict(KeyAtom, Payload, Value).
   91
   92payload_optional_value(Payload, Key, Value) :-
   93    payload_value(Payload, Key, Value),
   94    !.
   95payload_optional_value(_Payload, _Key, '').
   96
   97normalize_member_id(Value, MemberID) :-
   98    string(Value),
   99    !,
  100    atom_string(MemberID, Value).
  101normalize_member_id(Value, MemberID) :-
  102    atom(Value),
  103    !,
  104    MemberID = Value.
  105normalize_member_id(Value, MemberID) :-
  106    term_string(Value, MemberString),
  107    atom_string(MemberID, MemberString).
  108
  109normalize_optional_integer('', 0) :-
  110    !.
  111normalize_optional_integer(Value, Integer) :-
  112    normalize_integer(Value, Integer).
  113
  114normalize_integer(Value, Integer) :-
  115    integer(Value),
  116    !,
  117    Integer = Value.
  118normalize_integer(Value, Integer) :-
  119    number(Value),
  120    !,
  121    Integer is floor(Value).
  122normalize_integer(Value, Integer) :-
  123    string(Value),
  124    !,
  125    number_string(Integer, Value).
  126normalize_integer(Value, Integer) :-
  127    atom(Value),
  128    atom_number(Value, Integer)