diff --git a/.github/workflows/erlang.yml b/.github/workflows/erlang.yml index 9a916dc..5466cb4 100644 --- a/.github/workflows/erlang.yml +++ b/.github/workflows/erlang.yml @@ -11,12 +11,15 @@ jobs: strategy: fail-fast: false matrix: - otp: [23.2.1] + otp: [25.3.2.5] + rebar3: [3.22.0] steps: - uses: actions/checkout@v2 - - uses: gleam-lang/setup-erlang@v1.1.2 + - uses: erlef/setup-beam@v1 with: otp-version: ${{matrix.otp}} + rebar3-version: ${{matrix.rebar3}} + version-type: strict - name: Compile run: rebar3 compile - name: Run dialyzer diff --git a/Dockerfile b/Dockerfile index e93e86c..cc06edf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage 0 -FROM erlang:23.3.4-alpine +FROM erlang:25.3.2.3-alpine # Set working directory RUN mkdir /buildroot diff --git a/config/sys.docker.config b/config/sys.docker.config index 62769b3..25302e3 100644 --- a/config/sys.docker.config +++ b/config/sys.docker.config @@ -26,6 +26,7 @@ {pre_request, nova_request_plugin, #{decode_json_body => true, parse_bindings => true, parse_qs => true}} ]} ]}, - {ldf, [{chatli_path, <<"http://localhost:8090/v1">>}]} + {ldf, [{chatli_path, <<"http://localhost:8090/v1">>}, + ldf_callbac, <<"http://localhost:8095/receiver">>]} %% Please change your app.src-file instead if you intend to add app-specific configurations ]. \ No newline at end of file diff --git a/priv/assets/admin.html b/priv/assets/admin.html index 9c30a53..5135a1a 100644 --- a/priv/assets/admin.html +++ b/priv/assets/admin.html @@ -16,9 +16,7 @@

LDF Admin

- - @@ -81,15 +79,6 @@

LDF Admin

.delete('http://localhost:8095/li/' + item.callback_id); window.location.reload(); - }, - getHistory: function() { - var dateObj = new Date(this.date); - var timestamp = Date.parse(dateObj); - item = {value: this.newItem, - type: this.picked, - timestamp: timestamp}; - axios - .post('http://localhost:8095/history', item); } } }); diff --git a/priv/assets/receiver.html b/priv/assets/receiver.html index e966ae1..a891196 100644 --- a/priv/assets/receiver.html +++ b/priv/assets/receiver.html @@ -21,6 +21,14 @@

LDF Receiver

+
+ + + + + + +
@@ -60,6 +68,15 @@

LDF Receiver

"&sender=" + this.sender + "&receiver=" + this.receiver ) .then(response => (this.items = response.data)) + }, + getHistory: function() { + var dateObj = new Date(this.date); + var timestamp = Date.parse(dateObj); + item = {value: this.newItem, + type: this.picked, + timestamp: timestamp}; + axios + .post('http://localhost:8095/history', item); } } }); diff --git a/priv/ldf.routes.erl b/priv/ldf.routes.erl deleted file mode 100644 index 9d0cfe8..0000000 --- a/priv/ldf.routes.erl +++ /dev/null @@ -1,15 +0,0 @@ -#{prefix => "", - security => false, - routes => [ - {"/receiver", { ldf_receiver_controller, create_message}, #{methods => [post]}}, - {"/receiver", { ldf_receiver_controller, get_message}, #{methods => [get]}}, - {"/message/:messageid", { ldf_message_controller, message}, #{methods => [get]}}, - {"/li", {ldf_li_controller, create_li}, #{methods => [post]}}, - {"/li", {ldf_li_controller, manage_li}, #{methods => [get]}}, - {"/history", {ldf_li_controller, manage_history}, #{methods => [post]}}, - {"/li/:liid", {ldf_li_controller, delete_li}, #{methods => [delete]}}, - {"/www/admin", "assets/admin.html"}, - {"/www/receiver", "assets/receiver.html"}, - {"/assets/[...]", "assets"} - ] -}. \ No newline at end of file diff --git a/rebar.config b/rebar.config index 2072a53..b5e4457 100644 --- a/rebar.config +++ b/rebar.config @@ -4,100 +4,119 @@ {src_dirs, ["src", "src/controllers"]}. {shell, [{config, "./config/sys.docker.config"}]}. -{erlydtl_opts, [{doc_root, "src/views"}, - {recursive, true}, - {libraries, [ - {nova_erlydtl_inventory, nova_erlydtl_inventory} - ]}, - {default_libraries, [nova_erlydtl_inventory]} - ]}. +{erlydtl_opts, [ + {doc_root, "src/views"}, + {recursive, true}, + {libraries, [ + {nova_erlydtl_inventory, nova_erlydtl_inventory} + ]}, + {default_libraries, [nova_erlydtl_inventory]} +]}. {deps, [ - {pgo, ".*", {git, "https://github.com/erleans/pgo.git", {ref, "6bbd5478ac08ae184cdd8f2331ff81fd94b66610"}}}, - {nova, ".*", {git, "https://github.com/novaframework/nova.git", {ref, "f3e2fb52a5cbc07f986583f48222cc6c8be9b5c8"}}} - ]}. - + {pgo, ".*", + {git, "https://github.com/erleans/pgo.git", + {ref, "6bbd5478ac08ae184cdd8f2331ff81fd94b66610"}}}, + {nova, ".*", + {git, "https://github.com/novaframework/nova.git", + {ref, "b5d03d3bdcafb51e0aa2e51ed34ae9dfe1681e7e"}}} +]}. %% Release profiles %% To create a release just run %% rebar3 release -n ldf-prod -{relx, [{release, {ldf, "0.1.0"}, - [ldf], - [{dev_mode, false}, - {include_erts, true}, - {extended_start_script, true}]} - ]}. - +{relx, [ + {release, {ldf, "0.1.0"}, [ldf], [ + {dev_mode, false}, + {include_erts, true}, + {extended_start_script, true} + ]} +]}. %% Plugins for rebar3 {plugins, [ - rebar3_auto, - {rebar3_erlydtl_plugin, ".*", - {git, "https://github.com/tsloughter/rebar3_erlydtl_plugin.git", {branch, "master"}}} - ]}. + rebar3_auto, + {rebar3_erlydtl_plugin, ".*", + {git, "https://github.com/tsloughter/rebar3_erlydtl_plugin.git", {branch, "master"}}}, + erlfmt +]}. {provider_hooks, [ - {pre, [{compile, {erlydtl, compile}}]} - ]}. -{xref_checks,[ - undefined_function_calls, - undefined_functions, - locals_not_used, - deprecated_function_calls, - deprecated_functions - ]}. + {pre, [{compile, {erlydtl, compile}}]} +]}. +{xref_checks, [ + undefined_function_calls, + undefined_functions, + locals_not_used, + deprecated_function_calls, + deprecated_functions +]}. {profiles, [ - {lint, [ - {plugins, [ - {rebar3_lint, {git, "https://github.com/project-fifo/rebar3_lint.git", {tag, "0.1.11"}}} - ]} - ]} - ]}. + {lint, [ + {plugins, [ + {rebar3_lint, {git, "https://github.com/project-fifo/rebar3_lint.git", {tag, "0.1.11"}}} + ]} + ]} +]}. + +{alias, [{run, [{fmt, "--write"}, shell]}]}. -{elvis, - [#{dirs => ["src"], - filter => "*.erl", - ignore => [etsi103120], - rules => [{elvis_style, line_length, - #{ignore => [], - limit => 120, - skip_comments => false}}, - {elvis_style, no_tabs}, - {elvis_style, no_trailing_whitespace}, - {elvis_style, macro_names, #{ignore => []}}, - {elvis_style, macro_module_names}, - {elvis_style, operator_spaces, #{rules => [{right, ","}, - {right, "++"}, - {left, "++"}]}}, - {elvis_style, nesting_level, #{level => 3}}, - {elvis_style, god_modules, - #{limit => 25, - ignore => []}}, - {elvis_style, no_if_expression}, - {elvis_style, used_ignored_variable}, - {elvis_style, no_behavior_info}, - { - elvis_style, - module_naming_convention, - #{regex => "^[a-z]([a-z0-9]*_?)*(_SUITE)?$", - ignore => []} - }, - { - elvis_style, - function_naming_convention, - #{regex => "^([a-z][a-z0-9]*_?)*$"} - }, - {elvis_style, state_record_and_type}, - {elvis_style, no_spec_with_records}, - {elvis_style, dont_repeat_yourself, #{min_complexity => 10}}, - {elvis_style, no_debug_call, #{ignore => []}} - ] - }, - #{dirs => ["."], - filter => "rebar.config", - rules => [{elvis_project, no_deps_master_rebar, #{ignore => []}}, - {elvis_project, protocol_for_deps_rebar, #{ignore => []}}] - } - ] -}. \ No newline at end of file +{elvis, [ + #{ + dirs => ["src"], + filter => "*.erl", + ignore => [etsi103120], + rules => [ + {elvis_style, line_length, #{ + ignore => [], + limit => 120, + skip_comments => false + }}, + {elvis_style, no_tabs}, + {elvis_style, no_trailing_whitespace}, + {elvis_style, macro_names, #{ignore => []}}, + {elvis_style, macro_module_names}, + {elvis_style, operator_spaces, #{ + rules => [ + {right, ","}, + {right, "++"}, + {left, "++"} + ] + }}, + {elvis_style, nesting_level, #{level => 3}}, + {elvis_style, god_modules, #{ + limit => 25, + ignore => [] + }}, + {elvis_style, no_if_expression}, + {elvis_style, used_ignored_variable}, + {elvis_style, no_behavior_info}, + { + elvis_style, + module_naming_convention, + #{ + regex => "^[a-z]([a-z0-9]*_?)*(_SUITE)?$", + ignore => [] + } + }, + { + elvis_style, + function_naming_convention, + #{regex => "^([a-z][a-z0-9]*_?)*$"} + }, + {elvis_style, state_record_and_type}, + {elvis_style, no_spec_with_records}, + {elvis_style, dont_repeat_yourself, #{min_complexity => 10}}, + {elvis_style, no_debug_call, #{ignore => []}} + ] + }, + #{ + dirs => ["."], + filter => "rebar.config", + rules => [ + {elvis_project, no_deps_master_rebar, #{ignore => []}}, + {elvis_project, protocol_for_deps_rebar, #{ignore => []}} + ] + } +]}. diff --git a/rebar.lock b/rebar.lock index 5f02e8e..1e41553 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,15 +1,12 @@ {"1.2.0", [{<<"backoff">>,{pkg,<<"backoff">>,<<"1.1.6">>},1}, - {<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.9.0">>},1}, - {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.11.0">>},2}, - {<<"dh_date">>,{pkg,<<"dh_date">>,<<"1.0.0">>},2}, - {<<"erldb">>,{pkg,<<"erldb">>,<<"1.0.0">>},1}, + {<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.10.0">>},1}, + {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.12.1">>},2}, {<<"erlydtl">>,{pkg,<<"erlydtl">>,<<"0.14.0">>},1}, {<<"jhn_stdlib">>,{pkg,<<"jhn_stdlib">>,<<"3.6.2">>},1}, - {<<"mysql">>,{pkg,<<"mysql">>,<<"1.6.0">>},2}, {<<"nova">>, {git,"https://github.com/novaframework/nova.git", - {ref,"f3e2fb52a5cbc07f986583f48222cc6c8be9b5c8"}}, + {ref,"b5d03d3bdcafb51e0aa2e51ed34ae9dfe1681e7e"}}, 0}, {<<"pg_types">>, {git,"https://github.com/tsloughter/pg_types.git", @@ -20,43 +17,37 @@ {ref,"6bbd5478ac08ae184cdd8f2331ff81fd94b66610"}}, 0}, {<<"pmod_transform">>,{pkg,<<"pmod_transform">>,<<"1.1.0">>},1}, - {<<"poolboy">>,{pkg,<<"poolboy">>,<<"1.5.2">>},2}, - {<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.2">>},2}, + {<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.5">>},2}, {<<"ranch">>,{pkg,<<"ranch">>,<<"1.8.0">>},2}, - {<<"routing_tree">>,{pkg,<<"routing_tree">>,<<"1.0.1">>},1}, + {<<"routing_tree">>,{pkg,<<"routing_tree">>,<<"1.0.6">>},1}, {<<"telemetry">>,{pkg,<<"telemetry">>,<<"0.4.0">>},1}, - {<<"uuid">>,{pkg,<<"uuid_erl">>,<<"2.0.0">>},1}]}. + {<<"thoas">>,{pkg,<<"thoas">>,<<"0.4.0">>},1}, + {<<"uuid">>,{pkg,<<"uuid_erl">>,<<"2.0.5">>},1}]}. [ {pkg_hash,[ {<<"backoff">>, <<"83B72ED2108BA1EE8F7D1C22E0B4A00CFE3593A67DBC792799E8CCE9F42F796B">>}, - {<<"cowboy">>, <<"865DD8B6607E14CF03282E10E934023A1BD8BE6F6BACF921A7E2A96D800CD452">>}, - {<<"cowlib">>, <<"0B9FF9C346629256C42EBE1EEB769A83C6CB771A6EE5960BD110AB0B9B872063">>}, - {<<"dh_date">>, <<"5B0C286665E160DE44132552931BEF06B5CB2244D5BD20E333A686E9D8BF92E3">>}, - {<<"erldb">>, <<"5061C4E7FCBF7E6FD0C920ADD88243B6718FD739AB4B3F7D3F885FA51250BAD1">>}, + {<<"cowboy">>, <<"FF9FFEFF91DAE4AE270DD975642997AFE2A1179D94B1887863E43F681A203E26">>}, + {<<"cowlib">>, <<"A9FA9A625F1D2025FE6B462CB865881329B5CAFF8F1854D1CBC9F9533F00E1E1">>}, {<<"erlydtl">>, <<"964B2DC84F8C17ACFAA69C59BA129EF26AC45D2BA898C3C6AD9B5BDC8BA13CED">>}, {<<"jhn_stdlib">>, <<"DBF19025FB1CCD7BEDCD19DC655A29618AA5943505DFE707C562E25F69C56BAA">>}, - {<<"mysql">>, <<"F7858A8BAB3DEB21684161F3A557DFC9698B1E212DCFCD182F89F93AEA740431">>}, {<<"pmod_transform">>, <<"A3A4FA607B947C90410BC459DCA27F6B60D25D1588D568280F7276AC8767E106">>}, - {<<"poolboy">>, <<"392B007A1693A64540CEAD79830443ABF5762F5D30CF50BC95CB2C1AAAFA006B">>}, - {<<"quickrand">>, <<"1D73FAA52E0C149FCBC72A63C26135FF68BE8FA7870675C73645896788A7540C">>}, + {<<"quickrand">>, <<"06FCAD85CB47D5C85C51D6BC9C84A082501BA098A89D64AD0A2F69599E034C04">>}, {<<"ranch">>, <<"8C7A100A139FD57F17327B6413E4167AC559FBC04CA7448E9BE9057311597A1D">>}, - {<<"routing_tree">>, <<"BEE537F992DA54AC31CDC1F0BD39DABA1BEF1A1EF691B2601774BE7FC2F201D1">>}, + {<<"routing_tree">>, <<"D565314CC3170DE52D534ECC77E7EB9146E8B6D6B3FDC17E01F24B8A360B4364">>}, {<<"telemetry">>, <<"8339BEE3FA8B91CB84D14C2935F8ECF399CCD87301AD6DA6B71C09553834B2AB">>}, - {<<"uuid">>, <<"02C713FAC0E73E5F366CBA541216F1E956E2F00C91C7530D4B21DEC7D3ADA164">>}]}, + {<<"thoas">>, <<"86A72CCDC5EC388A13F9F843BCD6C1076640233B95440E47FFB8E3C0DBDB5A17">>}, + {<<"uuid">>, <<"60FAEEB7EDFD40847ED13CB0DD1044BAABE4E79A00C0CA9C4D13A073914B1016">>}]}, {pkg_hash_ext,[ {<<"backoff">>, <<"CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39">>}, - {<<"cowboy">>, <<"2C729F934B4E1AA149AFF882F57C6372C15399A20D54F65C8D67BEF583021BDE">>}, - {<<"cowlib">>, <<"2B3E9DA0B21C4565751A6D4901C20D1B4CC25CBB7FD50D91D2AB6DD287BC86A9">>}, - {<<"dh_date">>, <<"3F5D908383A0243A693147EA85A5654769B90078AC999A076ED6F0917F7614CF">>}, - {<<"erldb">>, <<"115A40D487597295403F26118CF017F91BA955B5A6DED9D81E98BF700D30AF22">>}, + {<<"cowboy">>, <<"3AFDCCB7183CC6F143CB14D3CF51FA00E53DB9EC80CDCD525482F5E99BC41D6B">>}, + {<<"cowlib">>, <<"163B73F6367A7341B33C794C4E88E7DBFE6498AC42DCD69EF44C5BC5507C8DB0">>}, {<<"erlydtl">>, <<"D80EC044CD8F58809C19D29AC5605BE09E955040911B644505E31E9DD8143431">>}, {<<"jhn_stdlib">>, <<"C6F6AE9BC636B0011ABA7B4DACAFF549C0B5CFB58229EBD09959B77391F6ED47">>}, - {<<"mysql">>, <<"0B7B72927F99EB89E5AC2DAA5DB05DAAC6FDE99FDEA33B02406913A617F4A1A7">>}, {<<"pmod_transform">>, <<"68C7FF7354C0D837681990D093D367FCC617C32570A1009B8E7ACFF6445499AA">>}, - {<<"poolboy">>, <<"DAD79704CE5440F3D5A3681C8590B9DC25D1A561E8F5A9C995281012860901E3">>}, - {<<"quickrand">>, <<"E21C6C7F29CA995468662085CA54D7D09E861C180A9DFEC2CF4A2E75364A16D6">>}, + {<<"quickrand">>, <<"252CF0493570EBF1A58985CB71990982CDDCD4396B6427F1E10CF58924C1C052">>}, {<<"ranch">>, <<"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5">>}, - {<<"routing_tree">>, <<"DE024259AFAE96BAABE573B6A10A7E8F17236C68AF19044262C4CEE8D132A915">>}, + {<<"routing_tree">>, <<"49EADC682FCD8F1061272A77306E334716EAEA24E5F36AF118CB3A21A802BFAE">>}, {<<"telemetry">>, <<"E9E3CACFD37C1531C0CA70CA7C0C30CE2DBB02998A4F7719DE180FE63F8D41E4">>}, - {<<"uuid">>, <<"CE1C1ED1D786BA98F93204BE66F93A797504993954141122FCC5FE59B5331367">>}]} + {<<"thoas">>, <<"442296847ACA11DB8D25180693D7CA3073D6D7179F66952F07B16415306513B6">>}, + {<<"uuid">>, <<"E54373262CA88401689277947C54B95E9ECBC977BD5C57C9DD44AD9DA278E360">>}]} ]. diff --git a/src/controllers/ldf_receiver_controller.erl b/src/controllers/ldf_receiver_controller.erl index 5641698..45798cf 100644 --- a/src/controllers/ldf_receiver_controller.erl +++ b/src/controllers/ldf_receiver_controller.erl @@ -19,6 +19,7 @@ create_message(#{json := #{<<"id">> := MessageId} = Json}) -> {status, 200}. get_message(#{parsed_qs := ParsedQS}) -> + logger:debug("parse qs"), {ok, List} = ldf_db:get_messages(), Xml = case maps:get(<<"type">>, ParsedQS, undefined) of <<"103120">> -> #{<<"countryCode">> := CountryCode, @@ -27,14 +28,15 @@ get_message(#{parsed_qs := ParsedQS}) -> [etsi103120:json_to_xml(decode(Json), CountryCode, Sender, Receiver) || #{payload := Json} <- List]; _ -> [etsi103707:json_to_xml(decode(Json)) || #{payload := Json} <- List] end, - {json, 200, #{}, Xml}; + {json, 200, #{<<"Content-type">> => <<"application/json">>}, Xml}; get_message(_) -> {ok, List} = ldf_db:get_messages(), Xml = [etsi103707:json_to_xml(decode(Json)) || #{payload := Json} <- List], - {json, 200, #{}, Xml}. + {json, 200, #{<<"Content-type">> => <<"application/json; charset=utf-8">>}, Xml}. encode(Item) -> - json:encode(Item, [maps, binary]). + thoas:encode(Item). decode(Item) -> - json:decode(Item, [maps]). \ No newline at end of file + {ok, Map} = thoas:decode(Item), + Map. \ No newline at end of file diff --git a/src/etsi103120.erl b/src/etsi103120.erl index 311498a..e6c0a90 100644 --- a/src/etsi103120.erl +++ b/src/etsi103120.erl @@ -6,288 +6,509 @@ -include_lib("xmerl/include/xmerl.hrl"). -json_to_xml(#{<<"chat_id">> := ChatId, - <<"id">> := MessageId, - <<"payload">> := Payload, - <<"sender">> := Sender, - <<"timestamp">> := Timestamp} = Object, - CountryCode, - SenderUUID, - ReceiverUUID) -> +json_to_xml( + #{ + <<"chat_id">> := ChatId, + <<"id">> := MessageId, + <<"payload">> := Payload, + <<"sender">> := Sender, + <<"timestamp">> := Timestamp + } = Object, + CountryCode, + SenderUUID, + ReceiverUUID +) -> logger:debug("converting to 103 120"), CspDefinedParameters = csp_defined_parameters(Object), logger:debug("payload: ~p", [Payload]), - Mime = case Payload of - #{<<"mime">> := [MimeType]} -> MimeType; - _ -> - <<"text/plain">> - end, + Mime = + case Payload of + #{<<"mime">> := [MimeType]} -> MimeType; + _ -> <<"text/plain">> + end, logger:debug("mime: ~p", [Mime]), - ContentLength = case is_binary(Payload) of - true -> - integer_to_binary(byte_size(Payload)); - false -> - case is_map(Payload) of - true -> - Json = json:encode(Payload, [maps, binary]), - integer_to_binary(byte_size(Json)); - false -> - <<"0">> - end - end, + ContentLength = + case is_binary(Payload) of + true -> + integer_to_binary(byte_size(Payload)); + false -> + case is_map(Payload) of + true -> + Json = json:encode(Payload, [maps, binary]), + integer_to_binary(byte_size(Json)); + false -> + <<"0">> + end + end, Content = [ - #xmlElement{name = 'etsi707:header', - content = [#xmlElement{name = 'etsi707:applicationCorrelation', - content = [#xmlElement{name = 'etsi707:applicationLevelID', - content = [#xmlText{value = <<"1">>}]}, - #xmlElement{name = 'etsi707:applicationSequenceNumber', - content = [#xmlText{value = <<"3">>}]} - ]}]}, - #xmlElement{name = 'etsi707:payload', - attributes = [ - #xmlAttribute{ - name = 'xsi:type', - value = [<<"etsi707:MessagingPayload">>] - } - ], - content = [core_parameters(Sender, - dummy, - ChatId, - calendar:system_time_to_rfc3339(Timestamp, - [{unit, millisecond}]), - MessageId, - ContentLength, - Mime), - CspDefinedParameters - ] - } - ], - list_to_binary(lists:flatten(xmerl:export_simple([hi1(header(Content), CountryCode, SenderUUID, ReceiverUUID)], xmerl_xml))). - - + #xmlElement{ + name = 'etsi707:header', + content = [ + #xmlElement{ + name = 'etsi707:applicationCorrelation', + content = [ + #xmlElement{ + name = 'etsi707:applicationLevelID', + content = [#xmlText{value = <<"1">>}] + }, + #xmlElement{ + name = 'etsi707:applicationSequenceNumber', + content = [#xmlText{value = <<"3">>}] + } + ] + } + ] + }, + #xmlElement{ + name = 'etsi707:payload', + attributes = [ + #xmlAttribute{ + name = 'xsi:type', + value = [<<"etsi707:MessagingPayload">>] + } + ], + content = [ + core_parameters( + Sender, + dummy, + ChatId, + calendar:system_time_to_rfc3339( + Timestamp, + [{unit, microsecond}] + ), + MessageId, + ContentLength, + Mime + ), + CspDefinedParameters + ] + } + ], + list_to_binary( + lists:flatten( + xmerl:export_simple( + [hi1(header(Content), CountryCode, SenderUUID, ReceiverUUID)], xmerl_xml + ) + ) + ). header(Content) -> - [#xmlElement{ - name = 'etsi707:handoverItem', - attributes = [], - content = Content - }]. + [ + #xmlElement{ + name = 'etsi707:handoverItem', + attributes = [], + content = Content + } + ]. core_parameters(Sender, _, Receiver, Timestamp, MessageId, ContentLength, Mime) -> - {IsTargetedPartyBool, SenderInfo} = case ldf_db:get_li_user_id(Sender) of - {ok, User} -> {<<"true">>, User}; - _ -> {<<"false">>, #{}} - end, + {IsTargetedPartyBool, SenderInfo} = + case ldf_db:get_li_user_id(Sender) of + {ok, User} -> {<<"true">>, User}; + _ -> {<<"false">>, #{}} + end, logger:debug("sender info: ~p", [SenderInfo]), - #xmlElement{name = coreParameters, - content = [message_sender({Sender, SenderInfo}, IsTargetedPartyBool), - message_receiver(Receiver), - timestamp(Timestamp), - associated_binary_data(MessageId, ContentLength, Mime)] - }. + #xmlElement{ + name = 'etsi707:coreParameters', + content = [ + message_sender({Sender, SenderInfo}, IsTargetedPartyBool), + message_receiver(Receiver), + timestamp(Timestamp), + associated_binary_data(MessageId, ContentLength, Mime) + ] + }. message_sender({Sender, SenderInfo}, IsTargetedParty) -> - #xmlElement{name = 'etsi707:messageSender', - content = [identifiers(Sender, SenderInfo), - #xmlElement{name = 'etsi707:isTargetedParty', - content = [#xmlText{value = [IsTargetedParty]}]}] - }. + #xmlElement{ + name = 'etsi707:messageSender', + content = [ + identifiers(Sender, SenderInfo), + #xmlElement{ + name = 'etsi707:isTargetedParty', + content = [#xmlText{value = [IsTargetedParty]}] + } + ] + }. -identifiers(Identifier, #{email := Email, - phone_number := PhoneNumber}) -> - #xmlElement{name = 'etsi707:identifiers', - content = [#xmlElement{name = 'etsi707:identifier', - content = [#xmlText{value = [Identifier]}] - }, - #xmlElement{name = 'etsi707:identifier', - content = [#xmlText{value = [Email]}] - }, - #xmlElement{name = 'etsi707:identifier', - content = [#xmlText{value = [PhoneNumber]}] - } - ] - }; -identifiers(Identifier, _) -> identifiers(Identifier). +identifiers(Identifier, #{ + email := Email, + phone_number := PhoneNumber +}) -> + #xmlElement{ + name = 'etsi707:identifiers', + content = [ + #xmlElement{ + name = 'etsi707:identifier', + content = [#xmlText{value = [Identifier]}] + }, + #xmlElement{ + name = 'etsi707:identifier', + content = [#xmlText{value = [Email]}] + }, + #xmlElement{ + name = 'etsi707:identifier', + content = [#xmlText{value = [PhoneNumber]}] + } + ] + }; +identifiers(Identifier, _) -> + identifiers(Identifier). identifiers(Identifier) -> - #xmlElement{name = 'etsi707:identifiers', - content = [#xmlElement{name = 'etsi707:identifier', - content = [#xmlText{value = [Identifier]}] - } - ] + #xmlElement{ + name = 'etsi707:identifiers', + content = [ + #xmlElement{ + name = 'etsi707:identifier', + content = [#xmlText{value = [Identifier]}] + } + ] }. message_receiver(Receiver) -> - #xmlElement{name = 'etsi707:messageReceivers', - content = [#xmlElement{name = 'etsi707:recipient', - content = [identifiers(Receiver)]}] - }. + #xmlElement{ + name = 'etsi707:messageReceivers', + content = [ + #xmlElement{ + name = 'etsi707:recipient', + content = [identifiers(Receiver)] + } + ] + }. timestamp(Timestamp) -> - #xmlElement{name = 'etsi707:timestamp', - content = [#xmlText{value = [Timestamp]}]}. + #xmlElement{ + name = 'etsi707:timestamp', + content = [#xmlText{value = [Timestamp]}] + }. associated_binary_data(MessageId, ContentLength, Mime) -> - Url = #xmlElement{name = 'etsi707:url', - content = [#xmlText{value = [<<"http://localhost:8095/message/", - MessageId/binary>>]}]}, - #xmlElement{name = 'etsi707:associatedBinaryData', - content = [#xmlElement{name = 'etsi707:binaryObject', - content = [Url, - #xmlElement{name = 'etsi707:contentLength', - content = [#xmlText{value = [ContentLength]}]}, - #xmlElement{name = 'etsi707:contentType', - content = [#xmlText{value = [Mime]}]}, - #xmlElement{name = 'etsi707:cspDefinedIdentifier', - content = [#xmlText{value = [MessageId]}]}]}]}. + Url = #xmlElement{ + name = 'etsi707:url', + content = [#xmlText{value = [<<"http://localhost:8095/message/", MessageId/binary>>]}] + }, + #xmlElement{ + name = 'etsi707:associatedBinaryData', + content = [ + #xmlElement{ + name = 'etsi707:binaryObject', + content = [ + Url, + #xmlElement{ + name = 'etsi707:contentLength', + content = [#xmlText{value = [ContentLength]}] + }, + #xmlElement{ + name = 'etsi707:contentType', + content = [#xmlText{value = [Mime]}] + }, + #xmlElement{ + name = 'etsi707:cspDefinedIdentifier', + content = [#xmlText{value = [MessageId]}] + } + ] + } + ] + }. csp_defined_parameters(Object) -> Keys = maps:keys(Object), - #xmlElement{name = 'etsi707:cspDefinedParameters', - content = [csp_defined_metadata(Keys)]}. + #xmlElement{ + name = 'etsi707:cspDefinedParameters', + content = [csp_defined_metadata(Keys)] + }. csp_defined_metadata(Keys) -> - #xmlElement{name = 'etsi707:cspDefinedMetadata', - content = [schema_details(Keys), - #xmlElement{name = 'etsi707:xmlData', - content = [chatli_defined_parameters(Keys)]}]}. + #xmlElement{ + name = 'etsi707:cspDefinedMetadata', + content = [ + schema_details(Keys), + #xmlElement{ + name = 'etsi707:xmlData', + content = [chatli_defined_parameters(Keys)] + } + ] + }. schema_details(Keys) -> - #xmlElement{name = 'etsi707:schemaDetails', - content = [#xmlElement{name = 'etsi707:schemaIdentifier', - content = [#xmlText{value = [?SCHEMAIDENTIFIER]}]} - ]}. + #xmlElement{ + name = 'etsi707:schemaDetails', + content = [ + #xmlElement{ + name = 'etsi707:schemaIdentifier', + content = [#xmlText{value = [?SCHEMAIDENTIFIER]}] + } + ] + }. chatli_defined_parameters(Keys) -> - #xmlElement{name = 'etsi707:chatLiDefinedParameters', - attributes = [#xmlAttribute{ - name = 'xmlns:xs', - value = [<<"http://www.w3.org/2001/XMLSchema">>] - }], - content = items(Keys, 1)}. + #xmlElement{ + name = 'chat:chatLiDefinedParameters', + content = items(Keys, 1) + }. items(Keys, N) -> Nbin = integer_to_binary(N), case Keys of - [] -> []; - [Key|T] -> - [#xmlElement{name = binary_to_atom(<<"chat:item", Nbin/binary>>, utf8), - content = [#xmlText{value = [Key]}]} | items(T, N+1)] + [] -> + []; + [Key | T] -> + [ + #xmlElement{ + name = binary_to_atom(<<"chat:item", Nbin/binary>>, utf8), + content = [#xmlText{value = [Key]}] + } + | items(T, N + 1) + ] end. - -hi1(Etsi707, CountryCode, Sender, Receiver)-> +hi1(Etsi707, CountryCode, Sender, Receiver) -> TransactionId = get_v4(), Timestamp = calendar:system_time_to_rfc3339(os:system_time(microsecond), [{unit, microsecond}]), ObjectIdentifier = get_v4(), - CC = case CountryCode of - <<"undefined">> -> <<"SE">>; - CountryCode -> CountryCode - end, - SenderUnique = case Sender of - <<"undefined">> -> <<"f7b38465-a0c7-4b2a-91cd-acb52152451f">>; - Sender -> Sender - end, - ReceiverUnique = case Receiver of - <<"undefined">> -> <<"1538d92a-0838-4864-8bb7-3b8825d6adbd">>; - Receiver -> Receiver - end, - #xmlElement{name = 'HI1Message', - attributes = [#xmlAttribute{name = 'xmlns', - value = <<"http://uri.etsi.org/03120/common/2019/10/Core">>}, - #xmlAttribute{name = 'xmlns:common', - value = <<"http://uri.etsi.org/03120/common/2016/02/Common">>}, - #xmlAttribute{name = 'xmlns:delivery', - value = <<"http://uri.etsi.org/03120/common/2019/10/Delivery">>}, - #xmlAttribute{name = 'xmlns:etsi707', - value = <<"http://uri.etsi.org/03707/2020/02">>}, - #xmlAttribute{name = 'xmlns:xsi', - value = <<"http://www.w3.org/2001/XMLSchema-instance">>}], - content = [#xmlElement{name = 'Header', - content = [ - #xmlElement{name = 'SenderIdentifier', - content = hi1_identifier(CC, SenderUnique)}, - #xmlElement{name = 'ReceiverIdentifier', - content = hi1_identifier(CC, ReceiverUnique)}, - #xmlElement{name = 'TransactionIdentifier', - content = [#xmlText{value = [TransactionId]}]}, - #xmlElement{name = 'Timestamp', - content = [#xmlText{value = [Timestamp]}]}, - #xmlElement{name = 'Version', - content = [#xmlElement{name = 'ETSIVersion', - content = [#xmlText{value = [<<"V1.1.1">>]}]}, - #xmlElement{name = 'NationalProfileOwner', - content = [#xmlText{value = [CC]}]}, - #xmlElement{name = 'NationalProfileVersion', - content = [#xmlText{value = [<<"None">>]}]} - ]} - ] - }, - #xmlElement{name = 'Payload', - content = [#xmlElement{name = 'RequestPayload', - content = [#xmlElement{name = 'ActionRequests', - content = [#xmlElement{name = 'ActionRequest', - content = [#xmlElement{name = 'ActionIdentifier', - content = [#xmlText{value = <<"0">>}]}, - #xmlElement{name = 'DELIVER', - content = [#xmlElement{name = 'Identifier', - content = [#xmlText{value = ObjectIdentifier}]}, - #xmlElement{name = 'HI1Object', - attributes = [#xmlAttribute{name = 'xsi:type', - value = <<"delivery:DeliveryObject">>}], - content = [#xmlElement{name = 'ObjectIdentifier', - content = [#xmlText{value = [ObjectIdentifier]}]}, - #xmlElement{name = 'CountryCode', - content = [#xmlText{value = [CC]}]}, - #xmlElement{name = 'OwnerIdentifier', - content = [#xmlText{value = [SenderUnique]}]}, - #xmlElement{name = 'delivery:Reference', - content = [#xmlElement{name = 'delivery:LIID', - content = [#xmlText{value = [ReceiverUnique]}]}]}, - #xmlElement{name = 'delivery:DeliveryID', - content = [#xmlText{value = [ObjectIdentifier]}]}, - #xmlElement{name = 'delivery:SequenceNumber', - content = [#xmlText{value = <<"1">>}]}, - #xmlElement{name = 'delivery:LastSequence', - content = [#xmlText{value = <<"true">>}]}, - #xmlElement{name = 'delivery:Manifest', - content = [#xmlElement{name = 'delivery:Specification', - content = [#xmlElement{name = 'common:Owner', - content = []}, - #xmlElement{name = 'common:Name', - content = []}, - #xmlElement{name = 'common:Value', - content = []} - ] - } - ] - }, - #xmlElement{name = 'delivery:Delivery', - content = [#xmlElement{name = 'delivery:XMLData', - content = Etsi707} - ]} - ] - } - ] - } - ] - } - ] + CC = + case CountryCode of + <<"undefined">> -> <<"SE">>; + CountryCode -> CountryCode + end, + SenderUnique = + case Sender of + <<"undefined">> -> <<"f7b38465-a0c7-4b2a-91cd-acb52152451f">>; + Sender -> Sender + end, + ReceiverUnique = + case Receiver of + <<"undefined">> -> <<"1538d92a-0838-4864-8bb7-3b8825d6adbd">>; + Receiver -> Receiver + end, + #xmlElement{ + name = 'HI1Message', + attributes = [ + #xmlAttribute{ + name = 'xmlns', + value = <<"http://uri.etsi.org/03120/common/2019/10/Core">> + }, + #xmlAttribute{ + name = 'xmlns:common', + value = <<"http://uri.etsi.org/03120/common/2016/02/Common">> + }, + #xmlAttribute{ + name = 'xmlns:delivery', + value = <<"http://uri.etsi.org/03120/common/2019/10/Delivery">> + }, + #xmlAttribute{ + name = 'xmlns:etsi707', + value = <<"http://uri.etsi.org/03707/2020/02">> + }, + #xmlAttribute{ + name = 'xmlns:xsi', + value = <<"http://www.w3.org/2001/XMLSchema-instance">> + }, + #xmlAttribute{ + name = 'xmlns:chat', + value = <<"chat">> + } + ], + content = [ + #xmlElement{ + name = 'Header', + content = [ + #xmlElement{ + name = 'SenderIdentifier', + content = hi1_identifier(CC, SenderUnique) + }, + #xmlElement{ + name = 'ReceiverIdentifier', + content = hi1_identifier(CC, ReceiverUnique) + }, + #xmlElement{ + name = 'TransactionIdentifier', + content = [#xmlText{value = [TransactionId]}] + }, + #xmlElement{ + name = 'Timestamp', + content = [#xmlText{value = [Timestamp]}] + }, + #xmlElement{ + name = 'Version', + content = [ + #xmlElement{ + name = 'ETSIVersion', + content = [#xmlText{value = [<<"V1.1.1">>]}] + }, + #xmlElement{ + name = 'NationalProfileOwner', + content = [#xmlText{value = [CC]}] + }, + #xmlElement{ + name = 'NationalProfileVersion', + content = [#xmlText{value = [<<"None">>]}] + } + ] + } + ] + }, + #xmlElement{ + name = 'Payload', + content = [ + #xmlElement{ + name = 'RequestPayload', + content = [ + #xmlElement{ + name = 'ActionRequests', + content = [ + #xmlElement{ + name = 'ActionRequest', + content = [ + #xmlElement{ + name = 'ActionIdentifier', + content = [#xmlText{value = <<"0">>}] + }, + #xmlElement{ + name = 'DELIVER', + content = [ + #xmlElement{ + name = 'Identifier', + content = [ + #xmlText{value = ObjectIdentifier} + ] + }, + #xmlElement{ + name = 'HI1Object', + attributes = [ + #xmlAttribute{ + name = 'xsi:type', + value = + <<"delivery:DeliveryObject">> + } + ], + content = [ + #xmlElement{ + name = 'ObjectIdentifier', + content = [ + #xmlText{ + value = [ObjectIdentifier] + } + ] + }, + #xmlElement{ + name = 'CountryCode', + content = [#xmlText{value = [CC]}] + }, + #xmlElement{ + name = 'OwnerIdentifier', + content = [ + #xmlText{value = [SenderUnique]} + ] + }, + #xmlElement{ + name = 'delivery:Reference', + content = [ + #xmlElement{ + name = 'delivery:LIID', + content = [ + #xmlText{ + value = [<<"LIID">>] + } + ] + } + ] + }, + #xmlElement{ + name = 'delivery:DeliveryID', + content = [ + #xmlText{ + value = [ObjectIdentifier] + } + ] + }, + #xmlElement{ + name = 'delivery:SequenceNumber', + content = [ + #xmlText{value = <<"1">>} + ] + }, + #xmlElement{ + name = 'delivery:LastSequence', + content = [ + #xmlText{value = <<"true">>} + ] + }, + #xmlElement{ + name = 'delivery:Manifest', + content = [ + #xmlElement{ + name = + 'delivery:Specification', + content = [ + #xmlElement{ + name = + 'common:Owner', + content = [ + #xmlText{ + value = + <<"ETSI">> } + ] + }, + #xmlElement{ + name = + 'common:Name', + content = [ + #xmlText{ + value = + <<"ManifestSpecification">> + } + ] + }, + #xmlElement{ + name = + 'common:Value', + content = [ + #xmlText{ + value = + <<"TS103707">> + } + ] + } ] + } + ] + }, + #xmlElement{ + name = 'delivery:Delivery', + content = [ + #xmlElement{ + name = 'delivery:XMLData', + content = Etsi707 + } + ] } + ] + } ] - } - ] - }. - + } + ] + } + ] + } + ] + } + ] + } + ] + }. hi1_identifier(CountryCode, Identifier) -> - [#xmlElement{name = 'CountryCode', - content = [#xmlText{value = [CountryCode]}]}, - #xmlElement{name = 'UniqueIdentifier', - content = [#xmlText{value = [Identifier]}]} + [ + #xmlElement{ + name = 'CountryCode', + content = [#xmlText{value = [CountryCode]}] + }, + #xmlElement{ + name = 'UniqueIdentifier', + content = [#xmlText{value = [Identifier]}] + } ]. - get_v4() -> - uuid:uuid_to_string(uuid:get_v4(), binary_standard). \ No newline at end of file + uuid:uuid_to_string(uuid:get_v4(), binary_standard). diff --git a/src/etsi103707.erl b/src/etsi103707.erl index 43aa323..4fdcf76 100644 --- a/src/etsi103707.erl +++ b/src/etsi103707.erl @@ -11,210 +11,256 @@ %% <<"payload">> => <<"hi hi">>, %% <<"sender">> => <<"9eccd7c2-85e0-4233-b31a-68f546923d9c">>, %% <<"timestamp">> => 1606135533171} -json_to_xml(#{<<"chat_id">> := ChatId, - <<"id">> := MessageId, - <<"payload">> := Payload, - <<"sender">> := Sender, - <<"timestamp">> := Timestamp} = Object) -> +json_to_xml( + #{ + <<"chat_id">> := ChatId, + <<"id">> := MessageId, + <<"payload">> := Payload, + <<"sender">> := Sender, + <<"timestamp">> := Timestamp + } = Object +) -> logger:debug("converting to 103 707"), CspDefinedParameters = csp_defined_parameters(Object), logger:debug("payload: ~p", [Payload]), - Mime = case Payload of - #{<<"mime">> := [MimeType]} -> MimeType; - _ -> - <<"text/plain">> - end, + Mime = + case Payload of + #{<<"mime">> := [MimeType]} -> MimeType; + _ -> <<"text/plain">> + end, logger:debug("mime: ~p", [Mime]), - ContentLength = case is_binary(Payload) of - true -> - integer_to_binary(byte_size(Payload)); - false -> - case is_map(Payload) of - true -> - Json = json:encode(Payload, [maps, binary]), - integer_to_binary(byte_size(Json)); - false -> - <<"0">> - end - end, + ContentLength = + case is_binary(Payload) of + true -> + integer_to_binary(byte_size(Payload)); + false -> + case is_map(Payload) of + true -> + Json = json:encode(Payload, [maps, binary]), + integer_to_binary(byte_size(Json)); + false -> + <<"0">> + end + end, Content = [ - #xmlElement{name = header, - content = [#xmlElement{name = 'applicationCorrelation', - content = [#xmlElement{name = 'applicationLevelID', - content = [#xmlText{value = <<"something">>}]}, - #xmlElement{name = 'applicationSequenceNumber', - content = [#xmlText{value = <<"3">>}]} - ]}]}, - #xmlElement{name = payload, - attributes = [ - #xmlAttribute{ - name = 'xsi:type', - value = [<<"MessagingPayload">>] - } - ], - content = [core_parameters(Sender, - dummy, - ChatId, - calendar:system_time_to_rfc3339(Timestamp, - [{unit, millisecond}]), - MessageId, - ContentLength, - Mime), - CspDefinedParameters - ] - } - ], + #xmlElement{ + name = header, + content = [ + #xmlElement{ + name = 'applicationCorrelation', + content = [ + #xmlElement{ + name = 'applicationLevelID', + content = [#xmlText{value = <<"something">>}] + }, + #xmlElement{ + name = 'applicationSequenceNumber', + content = [#xmlText{value = <<"3">>}] + } + ] + } + ] + }, + #xmlElement{ + name = payload, + attributes = [ + #xmlAttribute{ + name = 'xsi:type', + value = [<<"MessagingPayload">>] + } + ], + content = [ + core_parameters( + Sender, + dummy, + ChatId, + calendar:system_time_to_rfc3339( + Timestamp, + [{unit, millisecond}] + ), + MessageId, + ContentLength, + Mime + ), + CspDefinedParameters + ] + } + ], list_to_binary(lists:flatten(xmerl:export_simple([header(Content)], xmerl_xml))). - - header(Content) -> #xmlElement{ - name = handoverItem, - attributes = [ - #xmlAttribute{ - name = xmlns, - value = [<<"http://uri.etsi.org/03707/2020/02">>] - }, - #xmlAttribute{ - name = 'xmlns:xsi', - value = [<<"http://www.w3.org/2001/XMLSchema-instance">>] - } - ], - content = Content - }. + name = handoverItem, + attributes = [ + #xmlAttribute{ + name = xmlns, + value = [<<"http://uri.etsi.org/03707/2020/02">>] + }, + #xmlAttribute{ + name = 'xmlns:xsi', + value = [<<"http://www.w3.org/2001/XMLSchema-instance">>] + } + ], + content = Content + }. core_parameters(Sender, _, Receiver, Timestamp, MessageId, ContentLength, Mime) -> - {IsTargetedPartyBool, SenderInfo} = case ldf_db:get_li_user_id(Sender) of - {ok, User} -> {<<"true">>, User}; - _ -> {<<"false">>, #{}} - end, + {IsTargetedPartyBool, SenderInfo} = + case ldf_db:get_li_user_id(Sender) of + {ok, User} -> {<<"true">>, User}; + _ -> {<<"false">>, #{}} + end, logger:debug("sender info: ~p", [SenderInfo]), - #xmlElement{name = coreParameters, - content = [message_sender({Sender, SenderInfo}, IsTargetedPartyBool), - message_receiver(Receiver), - timestamp(Timestamp), - associated_binary_data(MessageId, ContentLength, Mime)] - }. + #xmlElement{ + name = coreParameters, + content = [ + message_sender({Sender, SenderInfo}, IsTargetedPartyBool), + message_receiver(Receiver), + timestamp(Timestamp), + associated_binary_data(MessageId, ContentLength, Mime) + ] + }. message_sender({Sender, SenderInfo}, IsTargetedParty) -> - #xmlElement{name = messageSender, - content = [identifiers(Sender, SenderInfo), - #xmlElement{name = isTargetedParty, - content = [#xmlText{value = [IsTargetedParty]}]}] - }. + #xmlElement{ + name = messageSender, + content = [ + identifiers(Sender, SenderInfo), + #xmlElement{ + name = isTargetedParty, + content = [#xmlText{value = [IsTargetedParty]}] + } + ] + }. -identifiers(Identifier, #{email := Email, - phone_number := PhoneNumber}) -> - #xmlElement{name = identifiers, - content = [#xmlElement{name = identifier, - content = [#xmlText{value = [Identifier]}] - }, - #xmlElement{name = identifier, - content = [#xmlText{value = [Email]}] - }, - #xmlElement{name = identifier, - content = [#xmlText{value = [PhoneNumber]}] - } - ] - }; -identifiers(Identifier, _) -> identifiers(Identifier). +identifiers(Identifier, #{ + email := Email, + phone_number := PhoneNumber +}) -> + #xmlElement{ + name = identifiers, + content = [ + #xmlElement{ + name = identifier, + content = [#xmlText{value = [Identifier]}] + }, + #xmlElement{ + name = identifier, + content = [#xmlText{value = [Email]}] + }, + #xmlElement{ + name = identifier, + content = [#xmlText{value = [PhoneNumber]}] + } + ] + }; +identifiers(Identifier, _) -> + identifiers(Identifier). identifiers(Identifier) -> -#xmlElement{name = identifiers, - content = [#xmlElement{name = identifier, - content = [#xmlText{value = [Identifier]}] - } - ] - }. + #xmlElement{ + name = identifiers, + content = [ + #xmlElement{ + name = identifier, + content = [#xmlText{value = [Identifier]}] + } + ] + }. message_receiver(Receiver) -> - #xmlElement{name = messageReceiver, - content = [identifiers(Receiver)] - }. + #xmlElement{ + name = messageReceiver, + content = [identifiers(Receiver)] + }. timestamp(Timestamp) -> - #xmlElement{name = timestamp, - content = [#xmlText{value = [Timestamp]}]}. + #xmlElement{ + name = timestamp, + content = [#xmlText{value = [Timestamp]}] + }. associated_binary_data(MessageId, ContentLength, Mime) -> - Url = #xmlElement{name = url, - content = [#xmlText{value = [<<"http://localhost:8095/message/", - MessageId/binary>>]}]}, - #xmlElement{name = associatedBinaryData, - content = [#xmlElement{name = binaryObject, - content = [Url, - #xmlElement{name = cspDefinedIdentifier, - content = [#xmlText{value = [MessageId]}]}, - #xmlElement{name = contentLength, - content = [#xmlText{value = [ContentLength]}]}, - #xmlElement{name = contentType, - content = [#xmlText{value = [Mime]}]}]}]}. + Url = #xmlElement{ + name = url, + content = [#xmlText{value = [<<"http://localhost:8095/message/", MessageId/binary>>]}] + }, + #xmlElement{ + name = associatedBinaryData, + content = [ + #xmlElement{ + name = binaryObject, + content = [ + Url, + #xmlElement{ + name = cspDefinedIdentifier, + content = [#xmlText{value = [MessageId]}] + }, + #xmlElement{ + name = contentLength, + content = [#xmlText{value = [ContentLength]}] + }, + #xmlElement{ + name = contentType, + content = [#xmlText{value = [Mime]}] + } + ] + } + ] + }. csp_defined_parameters(Object) -> Keys = maps:keys(Object), - #xmlElement{name = cspDefinedParameters, - content = [csp_defined_metadata(Keys)]}. + #xmlElement{ + name = cspDefinedParameters, + content = [csp_defined_metadata(Keys)] + }. csp_defined_metadata(Keys) -> - #xmlElement{name = cspDefinedMetadata, - content = [schema_details(Keys), - #xmlElement{name = xmlData, - content = [chatli_defined_parameters(Keys)]}]}. + #xmlElement{ + name = cspDefinedMetadata, + content = [ + schema_details(Keys), + #xmlElement{ + name = xmlData, + content = [chatli_defined_parameters(Keys)] + } + ] + }. schema_details(Keys) -> - #xmlElement{name = schemaDetails, - content = [#xmlElement{name = schemaIdentifier, - content = [#xmlText{value = [?SCHEMAIDENTIFIER]}]} - ]}. + #xmlElement{ + name = schemaDetails, + content = [ + #xmlElement{ + name = schemaIdentifier, + content = [#xmlText{value = [?SCHEMAIDENTIFIER]}] + } + ] + }. chatli_defined_parameters(Keys) -> - #xmlElement{name = chatLiDefinedParameters, - attributes = [#xmlAttribute{ - name = 'xmlns:xs', - value = [<<"http://www.w3.org/2001/XMLSchema">>] - }], - content = items(Keys, 1)}. + #xmlElement{ + name = chatLiDefinedParameters, + attributes = [ + #xmlAttribute{ + name = 'xmlns:xs', + value = [?SCHEMAIDENTIFIER] + } + ], + content = items(Keys, 1) + }. items(Keys, N) -> Nbin = integer_to_binary(N), case Keys of - [] -> []; - [Key|T] -> - [#xmlElement{name = binary_to_atom(<<"item", Nbin/binary>>, utf8), - content = [#xmlText{value = [Key]}]} | items(T, N+1)] + [] -> + []; + [Key | T] -> + [ + #xmlElement{ + name = binary_to_atom(<<"item", Nbin/binary>>, utf8), + content = [#xmlText{value = [Key]}] + } + | items(T, N + 1) + ] end. - -% schema_content(Keys) -> -% #xmlElement{name = schema, -% attributes = [#xmlAttribute{ -% name = 'xmlns:xs', -% value = [<<"http://www.w3.org/2001/XMLSchema">>] -% }, -% #xmlAttribute{ name = targetNamespace, -% value = [?SCHEMAIDENTIFIER]} -% ], -% content = [#xmlElement{name = 'xs:element', -% attributes = [#xmlAttribute{name = name, -% value = [chatLiDefinedParameters]}, -% #xmlAttribute{name = type, -% value = [chatLiDefinedParameters]}]}] -% } - -% csp_defined_metadata(Keys) -% -%
-% -%XX -%ACTOR02 -% -% -%XX -%ACTOR01 -% -%8854cfad-44ac-43b8-99ae-530b690b43da -%2019-09-30T13:37:37.000000Z -% -%V1.9.1 -%XX -%v1.0 -% diff --git a/src/ldf.app.src b/src/ldf.app.src index 9b87df4..d9f6492 100644 --- a/src/ldf.app.src +++ b/src/ldf.app.src @@ -1,21 +1,20 @@ %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -{application, ldf, - [{description, "ldf managed by Nova"}, - {vsn, "0.1.0"}, - {registered, []}, - {mod, { ldf_app, []}}, - {included_applications, []}, - {applications, - [ - kernel, - stdlib, - nova, - xmerl, - pgo - ]}, - {env,[]}, - {modules, []}, - {maintainers, []}, - {licenses, ["Apache 2.0"]}, - {links, []} - ]}. +{application, ldf, [ + {description, "ldf managed by Nova"}, + {vsn, "0.1.0"}, + {registered, []}, + {mod, {ldf_app, []}}, + {included_applications, []}, + {applications, [ + kernel, + stdlib, + nova, + xmerl, + pgo + ]}, + {env, []}, + {modules, []}, + {maintainers, []}, + {licenses, ["Apache 2.0"]}, + {links, []} +]}. diff --git a/src/ldf_db.erl b/src/ldf_db.erl index 360c43f..3b6881c 100644 --- a/src/ldf_db.erl +++ b/src/ldf_db.erl @@ -1,13 +1,15 @@ -module(ldf_db). --export([get_all_li/0, - get_li_user_id/1, - add_li/7, - find_li/2, - remove_li/1, - add_message/2, - get_messages/0, - get_message/1]). +-export([ + get_all_li/0, + get_li_user_id/1, + add_li/7, + find_li/2, + remove_li/1, + add_message/2, + get_messages/0, + get_message/1 +]). get_all_li() -> SQL = <<"SELECT * FROM li">>, @@ -25,26 +27,32 @@ find_li(email, Email) -> query1(SQL, [Email]). add_li(Type, Value, CallbackId, UserId, Username, PhoneNumber, Email) -> - PhoneLi = case find_li(phone_number, PhoneNumber) of - {ok, Li2} -> Li2; - undefined -> undefined - end, - EmailLi = case find_li(email, Email) of - {ok, Li} -> Li; - undefined -> undefined - end, + PhoneLi = + case find_li(phone_number, PhoneNumber) of + {ok, Li2} -> Li2; + undefined -> undefined + end, + EmailLi = + case find_li(email, Email) of + {ok, Li} -> Li; + undefined -> undefined + end, case {PhoneLi, EmailLi} of - {undefined, undefined} -> - SQL = <<"INSERT INTO li (type, - value, - callback_id, - user_id, - username, - phone_number, - email) - VALUES ($1, $2, $3, $4, $5, $6, $7)">>, - query1(SQL, [Type, Value, CallbackId, UserId, Username, PhoneNumber, Email]); - _ -> ok + {undefined, undefined} -> + SQL = + << + "INSERT INTO li (type,\n" + " value,\n" + " callback_id,\n" + " user_id,\n" + " username,\n" + " phone_number,\n" + " email)\n" + " VALUES ($1, $2, $3, $4, $5, $6, $7)" + >>, + query1(SQL, [Type, Value, CallbackId, UserId, Username, PhoneNumber, Email]); + _ -> + ok end. remove_li(Id) -> @@ -66,17 +74,33 @@ get_message(MessageId) -> % Expect 1 result query1(SQL, Values) -> case pgo:query(SQL, Values) of - #{command := insert, - num_rows := 1} -> ok; - #{command := select, - rows := []} -> undefined; - #{command := select, - rows := [Row]} -> {ok, Row}; - #{command := update, - num_rows := Num} -> {ok, Num}; - #{command := delete, - num_rows := 1} -> ok; - #{command := delete} -> undefined; + #{ + command := insert, + num_rows := 1 + } -> + ok; + #{ + command := select, + rows := [] + } -> + undefined; + #{ + command := select, + rows := [Row] + } -> + {ok, Row}; + #{ + command := update, + num_rows := Num + } -> + {ok, Num}; + #{ + command := delete, + num_rows := 1 + } -> + ok; + #{command := delete} -> + undefined; {error, Error} -> logger:error("Error: ~p on SQL ~p Values ~p", [Error, SQL, Values]), {error, Error} @@ -84,15 +108,27 @@ query1(SQL, Values) -> query(SQL, Values) -> case pgo:query(SQL, Values) of - #{command := insert, - num_rows := Num} -> {ok, Num}; - #{command := select, - rows := Rows} -> {ok, Rows}; - #{command := update, - num_rows := Num} -> {ok, Num}; - #{command := delete, - num_rows := Num} -> {ok, Num}; + #{ + command := insert, + num_rows := Num + } -> + {ok, Num}; + #{ + command := select, + rows := Rows + } -> + {ok, Rows}; + #{ + command := update, + num_rows := Num + } -> + {ok, Num}; + #{ + command := delete, + num_rows := Num + } -> + {ok, Num}; {error, Error} -> logger:error("Error: ~p on SQL ~p Values ~p", [Error, SQL, Values]), {error, Error} - end. \ No newline at end of file + end. diff --git a/src/ldf_router.erl b/src/ldf_router.erl new file mode 100644 index 0000000..10ca830 --- /dev/null +++ b/src/ldf_router.erl @@ -0,0 +1,23 @@ +-module(ldf_router). + +-export([routes/1]). + +routes(_Env) -> + [ + #{ + prefix => "", + security => false, + routes => [ + {"/receiver", {ldf_receiver_controller, create_message}, #{methods => [post]}}, + {"/receiver", {ldf_receiver_controller, get_message}, #{methods => [get]}}, + {"/message/:messageid", {ldf_message_controller, message}, #{methods => [get]}}, + {"/li", {ldf_li_controller, create_li}, #{methods => [post]}}, + {"/li", {ldf_li_controller, manage_li}, #{methods => [get]}}, + {"/history", {ldf_li_controller, manage_history}, #{methods => [post]}}, + {"/li/:liid", {ldf_li_controller, delete_li}, #{methods => [delete]}}, + {"/www/admin", "assets/admin.html"}, + {"/www/receiver", "assets/receiver.html"}, + {"/assets/[...]", "assets"} + ] + } + ]. diff --git a/src/ldf_srv.erl b/src/ldf_srv.erl index 573f18c..b37a932 100644 --- a/src/ldf_srv.erl +++ b/src/ldf_srv.erl @@ -3,15 +3,24 @@ -behaviour(gen_server). %% API --export([start_link/0, - add_li/2, - remove_li/1, - get_all_li/0, - get_history/1]). +-export([ + start_link/0, + add_li/2, + remove_li/1, + get_all_li/0, + get_history/1 +]). %% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3, format_status/2]). +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3, + format_status/2 +]). -define(SERVER, ?MODULE). @@ -26,10 +35,11 @@ %% Starts the server %% @end %%-------------------------------------------------------------------- --spec start_link() -> {ok, Pid :: pid()} | - {error, Error :: {already_started, pid()}} | - {error, Error :: term()} | - ignore. +-spec start_link() -> + {ok, Pid :: pid()} + | {error, Error :: {already_started, pid()}} + | {error, Error :: term()} + | ignore. start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). @@ -54,11 +64,12 @@ get_all_li() -> %% Initializes the server %% @end %%-------------------------------------------------------------------- --spec init(Args :: term()) -> {ok, State :: term()} | - {ok, State :: term(), Timeout :: timeout()} | - {ok, State :: term(), hibernate} | - {stop, Reason :: term()} | - ignore. +-spec init(Args :: term()) -> + {ok, State :: term()} + | {ok, State :: term(), Timeout :: timeout()} + | {ok, State :: term(), hibernate} + | {stop, Reason :: term()} + | ignore. init([]) -> process_flag(trap_exit, true), {ok, #state{}}. @@ -70,47 +81,61 @@ init([]) -> %% @end %%-------------------------------------------------------------------- -spec handle_call(Request :: term(), From :: {pid(), term()}, State :: term()) -> - {reply, Reply :: term(), NewState :: term()} | - {reply, Reply :: term(), NewState :: term(), Timeout :: timeout()} | - {reply, Reply :: term(), NewState :: term(), hibernate} | - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Timeout :: timeout()} | - {noreply, NewState :: term(), hibernate} | - {stop, Reason :: term(), Reply :: term(), NewState :: term()} | - {stop, Reason :: term(), NewState :: term()}. + {reply, Reply :: term(), NewState :: term()} + | {reply, Reply :: term(), NewState :: term(), Timeout :: timeout()} + | {reply, Reply :: term(), NewState :: term(), hibernate} + | {noreply, NewState :: term()} + | {noreply, NewState :: term(), Timeout :: timeout()} + | {noreply, NewState :: term(), hibernate} + | {stop, Reason :: term(), Reply :: term(), NewState :: term()} + | {stop, Reason :: term(), NewState :: term()}. handle_call({add, Type, Value}, _, State) -> - Url = case application:get_env(ldf, ldf_callback) of - {ok, Config} -> Config; - undefined -> + Url = + case application:get_env(ldf, ldf_callback) of + {ok, Config} -> + Config; + undefined -> {ok, IfConfig} = inet:getifaddrs(), Eth0 = proplists:get_value("eth0", IfConfig), - [IP] = [ {A, B, C, D} || {addr, {A, B, C, D}} <- Eth0], + [IP] = [{A, B, C, D} || {addr, {A, B, C, D}} <- Eth0], IP2 = list_to_binary(inet:ntoa(IP)), <<"http://", IP2/binary, ":8095/receiver">> - end, - Object = #{<<"type">> => Type, - <<"value">> => Value, - <<"url">> => Url}, + end, + Object = #{ + <<"type">> => Type, + <<"value">> => Value, + <<"url">> => Url + }, {ok, ChatliPath} = application:get_env(ldf, chatli_path), - case shttpc:post([ChatliPath, <<"/callback">>], - json:encode(Object, [maps, binary]), - #{headers => #{'Content-Type' => <<"application/json">>}, close => true}) of + case + shttpc:post( + [ChatliPath, <<"/callback">>], + json:encode(Object, [maps, binary]), + #{headers => #{'Content-Type' => <<"application/json">>}, close => true} + ) + of #{status := {404, _}} -> {reply, undefined, State}; #{status := {200, _}, body := RespBody} -> - #{<<"id">> := CallbackId, - <<"user_id">> := UserId, - <<"username">> := Username, - <<"phone_number">> := PhoneNumber, - <<"email">> := Email} = json:decode(RespBody, [maps]), + #{ + <<"id">> := CallbackId, + <<"user_id">> := UserId, + <<"username">> := Username, + <<"phone_number">> := PhoneNumber, + <<"email">> := Email + } = json:decode(RespBody, [maps]), ok = ldf_db:add_li(Type, Value, CallbackId, UserId, Username, PhoneNumber, Email), {reply, #{callback_id => CallbackId}, State} end; handle_call({remove, CallbackId}, _, State) -> {ok, ChatliPath} = application:get_env(ldf, chatli_path), - #{status := {200, _}} = shttpc:delete([ChatliPath, <<"/callback">>, <<"/">>, CallbackId], - #{headers => #{'Content-Type' => <<"application/json">>}, - close => true}), + #{status := {200, _}} = shttpc:delete( + [ChatliPath, <<"/callback">>, <<"/">>, CallbackId], + #{ + headers => #{'Content-Type' => <<"application/json">>}, + close => true + } + ), ok = ldf_db:remove_li(CallbackId), {reply, #{status => ok}, State}; handle_call(get_all, _, State) -> @@ -118,10 +143,14 @@ handle_call(get_all, _, State) -> {reply, List, State}; handle_call({history, Json}, _, State) -> {ok, ChatliPath} = application:get_env(ldf, chatli_path), - #{status := {200, _}} = shttpc:post([ChatliPath, <<"/history">>], - Json, - #{headers => #{'Content-Type' => <<"application/json">>}, - close => true}), + #{status := {200, _}} = shttpc:post( + [ChatliPath, <<"/history">>], + Json, + #{ + headers => #{'Content-Type' => <<"application/json">>}, + close => true + } + ), {reply, ok, State}; handle_call(_Request, _From, State) -> Reply = ok, @@ -134,10 +163,10 @@ handle_call(_Request, _From, State) -> %% @end %%-------------------------------------------------------------------- -spec handle_cast(Request :: term(), State :: term()) -> - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Timeout :: timeout()} | - {noreply, NewState :: term(), hibernate} | - {stop, Reason :: term(), NewState :: term()}. + {noreply, NewState :: term()} + | {noreply, NewState :: term(), Timeout :: timeout()} + | {noreply, NewState :: term(), hibernate} + | {stop, Reason :: term(), NewState :: term()}. handle_cast(_Request, State) -> {noreply, State}. @@ -148,10 +177,10 @@ handle_cast(_Request, State) -> %% @end %%-------------------------------------------------------------------- -spec handle_info(Info :: timeout() | term(), State :: term()) -> - {noreply, NewState :: term()} | - {noreply, NewState :: term(), Timeout :: timeout()} | - {noreply, NewState :: term(), hibernate} | - {stop, Reason :: normal | term(), NewState :: term()}. + {noreply, NewState :: term()} + | {noreply, NewState :: term(), Timeout :: timeout()} + | {noreply, NewState :: term(), hibernate} + | {stop, Reason :: normal | term(), NewState :: term()}. handle_info(_Info, State) -> {noreply, State}. @@ -164,8 +193,10 @@ handle_info(_Info, State) -> %% with Reason. The return value is ignored. %% @end %%-------------------------------------------------------------------- --spec terminate(Reason :: normal | shutdown | {shutdown, term()} | term(), - State :: term()) -> any(). +-spec terminate( + Reason :: normal | shutdown | {shutdown, term()} | term(), + State :: term() +) -> any(). terminate(_Reason, _State) -> ok. @@ -175,10 +206,13 @@ terminate(_Reason, _State) -> %% Convert process state when code is changed %% @end %%-------------------------------------------------------------------- --spec code_change(OldVsn :: term() | {down, term()}, - State :: term(), - Extra :: term()) -> {ok, NewState :: term()} | - {error, Reason :: term()}. +-spec code_change( + OldVsn :: term() | {down, term()}, + State :: term(), + Extra :: term() +) -> + {ok, NewState :: term()} + | {error, Reason :: term()}. code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -190,11 +224,13 @@ code_change(_OldVsn, State, _Extra) -> %% or when it appears in termination error logs. %% @end %%-------------------------------------------------------------------- --spec format_status(Opt :: normal | terminate, - Status :: list()) -> Status :: term(). +-spec format_status( + Opt :: normal | terminate, + Status :: list() +) -> Status :: term(). format_status(_Opt, Status) -> Status. %%%=================================================================== %%% Internal functions -%%%=================================================================== \ No newline at end of file +%%%=================================================================== diff --git a/src/ldf_sup.erl b/src/ldf_sup.erl index 0077daa..5769909 100644 --- a/src/ldf_sup.erl +++ b/src/ldf_sup.erl @@ -28,16 +28,18 @@ start_link() -> %% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules} init([]) -> - {ok, { {one_for_all, 0, 1}, [child(ldf_srv, worker)]} }. + {ok, {{one_for_all, 0, 1}, [child(ldf_srv, worker)]}}. %%==================================================================== %% Internal functions %%==================================================================== child(Module, Type) -> - #{id => Module, - start => {Module, start_link, []}, - restart => permanent, - shutdown => 5000, - type => Type, - modules => [Module]}. \ No newline at end of file + #{ + id => Module, + start => {Module, start_link, []}, + restart => permanent, + shutdown => 5000, + type => Type, + modules => [Module] + }.