aboutsummaryrefslogtreecommitdiff
path: root/apps/dreki_web/src/ui/dreki_web_ui_stores.erl
blob: e39cd483e45b49bbe2b955d1ded8a4bb86a2eb6a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
-module(dreki_web_ui_stores).
-behaviour(cowboy_handler).
-export([init/2]).


init(Req, action) ->
    with_location(Req#{action => cowboy_req:binding(action, Req)}, cowboy_req:binding(location, Req, undefined));
init(Req, Action) ->
    with_location(Req#{action => Action}, cowboy_req:binding(location, Req, undefined)).

with_location(Req, undefined) ->
    with_namespace(Req#{urn => dreki_world:root_path()});
with_location(Req, <<"-">>) ->
    with_namespace(Req#{urn => dreki_world:root_path()});
with_location(Req0, Location) ->
    Root = dreki_world:root_path(),
    {ok, XUrn} = dreki_urn:expand(<<Root/binary, ":", Location/binary>>),
    Req = Req0#{urn => maps:get(urn, XUrn)},
    with_namespace(Req).

with_namespace(Req) ->
    with_namespace(Req, cowboy_req:binding(namespace, Req)).
with_namespace(Req, undefined) ->
    request(Req);
with_namespace(Req = #{urn := Urn0}, Namespace) ->
    Urn = <<Urn0/binary, "::", Namespace/binary>>,
    with_directory(Req#{urn => Urn}).

with_directory(Req) ->
    with_directory(Req, cowboy_req:binding(directory, Req)).
with_directory(Req, undefined) ->
    request(Req);
with_directory(Req = #{urn := Urn0}, Directory) ->
    Urn = <<Urn0/binary, ":", Directory/binary>>,
    with_id(Req#{urn => Urn}).

with_id(Req) ->
    with_id(Req, cowboy_req:binding(id, Req)).
with_id(Req, undefined) ->
    request(Req);
with_id(Req = #{urn := Urn0}, Id) ->
    Urn = <<Urn0/binary, ":", Id/binary>>,
    request(Req#{urn => Urn}).

request(Req = #{action := Action, method := Method, urn := Urn}) ->
    logger:debug("Faked Urn ~p", [Urn]),
    case dreki_urn:expand(Urn) of
      {ok, XUrn} -> request(Method, Action, XUrn, Req);
      {error, EMap=#{}} -> dreki_web_error:init(Req, EMap);
      {error, _Error} -> dreki_web_error:init(Req, #{code => 404, status => "Not Found"})
    end.

%% Stores list
request(<<"GET">>, undefined, #{resource := #{namespace := NS}}, Req) ->
  {ok, Stores0} = dreki_store:stores(NS),
  Stores = lists:map(fun (Store) ->
     S = dreki_store:store_as_map(Store),
     S#{href => urn_to_path(maps:get(urn, S))}
  end, Stores0),
  Html = dreki_web_ui:render(Req, namespace_dtl, [{namespace, NS}, {stores, Stores}]),
  {ok, dreki_web_ui:reply_html(Req, 200, Html), undefined};

%% List
request(<<"GET">>, undefined, Urn = #{location := Loc, resource := #{directory := #{directory := Dir, namespace := NS}}}, Req) ->
    {ok, Result} = dreki_store:list(Urn),
    Results0 = lists:map(fun(Result) ->
      Result#{href => urn_to_path(maps:get('@id', Result))}
    end, maps:get(data, Result)),
    Results = deep_map_to_list(Results0),
    Html = dreki_web_ui:render(Req, store_list_dtl, [
                                                     {location, Loc}, {namespace, NS}, {directory, Dir},
                                                     {results, Results},
                                                     {actions, [
                                                                [{title, "New"}, {href, href(Req, <<"_/new">>)}]
                                                               ]}
                                                    ]),
    {ok, dreki_web_ui:reply_html(Req, 200, Html), undefined};

%% New
request(<<"GET">>, <<"new">>, #{urn := Urn, location := Loc, resource := #{directory := #{directory := Dir, namespace := NS}}}, Req) ->
    logger:debug("Actual Urn: ~p", [Urn]),
    {ok, Schemas} = dreki_store:list(<<Urn/binary, "::", "schemas">>),
    {ok, Schema} = dreki_store:get(<<Urn/binary, "::", "schemas::">>),
    Form = dreki_web_ui_json_form:render_html(Schema, #{}),
    Html = dreki_web_ui:render(Req, store_new_dtl, [
      {location, Loc}, {namespace, NS}, {directory, Dir},
      {schema, Schema}, {schemas, Schemas},
      {target, urn_to_path(Urn)}, {method, <<"POST">>},
      {form, Form}
    ]),
    {ok, dreki_web_ui:reply_html(Req, 200, Html), undefined};

%% Show
request(<<"GET">>, undefined, Urn = #{location := Loc, resource := #{resource := #{id := Id, directory := Dir, namespace := NS}}}, Req) ->
    {ok, Result0} = dreki_store:get(Urn),
    Result = Result0#{'@href' => urn_to_path(Urn)},
    Actions = lists:foldr(fun (#{id := Id, title := Title}, Acc) ->
                                  IdB = atom_to_binary(Id),
                                 Action = [{id, Id}, {title, Title}, {href, href(Req, <<"_/", IdB/binary>>)}],
                                  [Action | Acc]
                         end, [], maps:get('@actions', Result)),
    Html = dreki_web_ui:render(Req, store_show_dtl, [{location, Loc}, {id, Id}, {directory, Dir}, {namespace, NS},
                                                     {result, deep_map_to_list(Result)},
                                                     {actions, [
                                                                [{title, "Edit (UI)"}, {href, href(Req, <<"_/edit">>)}]
                                                                | Actions
                                                               ]}
                                                    ]),
    {ok, dreki_web_ui:reply_html(Req, 200, Html), undefined};

%% Show action
request(<<"GET">>, Action0, Urn = #{location := Loc, resource := #{resource := #{id := Id, directory := Dir, namespace := NS}}}, Req) ->
    {ok, Result0} = dreki_store:get(Urn),
    Result = Result0#{'@href' => urn_to_path(Urn)},
    Action = binary_to_existing_atom(Action0),
    Path = href(Req, <<"_/", Action0/binary>>),
    Act = lists:filter(fun (A) -> maps:get(id, A) =:= Action end, maps:get('@actions', Result)),
    case Act of
        [#{title := Title, new := {Mod, Fun, Args}}] ->
            {ok, Schema} = apply(Mod, Fun, [Result | Args]),
            Form = dreki_web_ui_json_form:render_html(Schema, #{}),
            Html = dreki_web_ui:render(Req, store_new_dtl, [
                                                           {location, Loc}, {id, Id}, {directory, Dir}, {namespace, NS},
                                                            {method, <<"POST">>},
                                                            {title, Title},
                                                            {result, deep_map_to_list(Result)},
                                                            {target, Path},
                                                            {form, Form}
                                                           ]),
            {dreki_web_ui:reply_html(Req, 200, Html), undefined};
        _ ->
            dreki_web_ui_error:init(Req, #{code => 404, status => "Not Found", message => "No such action"})
    end;
request(<<"POST">>, Action0, Urn = #{location := Loc, resource := #{resource := #{id := Id, directory := Dir, namespace := NS}}}, Req) ->
    {ok, Result0} = dreki_store:get(Urn),
    Result = Result0#{'@href' => urn_to_path(Urn)},
    Action = binary_to_existing_atom(Action0),
    Act = lists:filter(fun (A) -> maps:get(id, A) =:= Action end, maps:get('@actions', Result)),
    case Act of
        [#{title := Title, new := {Mod, Fun, Args}}] ->
            Req;
        _ ->
            dreki_web_ui_error:init(Req, #{code => 404, status => "Not Found", message => "No such action"})
    end.

derpinit(Req, _) ->
  Json = #{<<"error">> => false, <<"service">> => <<"dreki">>},
  logger:debug("REQ: ~p", [Req]),
  {ok, dreki_web:reply_json(Req, 200, Json), undefined}.


bad_request(Req) ->
  dreki_web_error:init(Req, #{code => 400, status => "Bad request"}).

href(Req = #{path := Path}, Append) ->
  <<Path/binary, "/", Append/binary>>.

location_to_path(Location) ->
    Root = dreki_world:root_path(),
    case Location =:= Root of
      true -> <<"/admin/-">>;
      false -> binary:replace(Location, <<Root/binary, ":">>, <<"/admin/">>)
    end.

deep_map_to_list(List) when is_list(List) ->
    [deep_map_to_list(Map) || Map <- List];
deep_map_to_list(Map) when is_map(Map) ->
    deep_map_to_list(maps:to_list(Map), []).

deep_map_to_list([{Key, Map} | Rest], Acc) when is_map(Map) ->
    List = deep_map_to_list(Map),
    deep_map_to_list(Rest, [{Key, List} | Acc]);
deep_map_to_list([Item | Rest], Acc) ->
    deep_map_to_list(Rest, [Item | Acc]);
deep_map_to_list([], Acc) ->
    Acc.

urn_to_path(Urn) when is_binary(Urn) ->
  {ok, XUrn} = dreki_urn:expand(Urn),
  urn_to_path(XUrn);
urn_to_path(#{location := Location, resource := #{namespace := NS}}) ->
  LP = location_to_path(Location),
  <<LP/binary, "/", NS/binary>>;
urn_to_path(#{location := Location, resource := #{directory := #{directory := Dir, namespace := NS}}}) ->
  LP = location_to_path(Location),
  <<LP/binary, "/", NS/binary, "/", Dir/binary>>;
urn_to_path(#{location := Location, resource := #{resource := #{id := Id, directory := Dir, namespace := NS}}}) ->
  LP = location_to_path(Location),
  <<LP/binary, "/", NS/binary, "/", Dir/binary, "/", Id/binary>>.