diff options
Diffstat (limited to 'apps/dreki_web/src/ui/dreki_web_ui_stores.erl')
-rw-r--r-- | apps/dreki_web/src/ui/dreki_web_ui_stores.erl | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/apps/dreki_web/src/ui/dreki_web_ui_stores.erl b/apps/dreki_web/src/ui/dreki_web_ui_stores.erl new file mode 100644 index 0000000..e39cd48 --- /dev/null +++ b/apps/dreki_web/src/ui/dreki_web_ui_stores.erl @@ -0,0 +1,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>>. |