Packages
nova
0.0.1
0.15.1
0.14.3
0.14.1
0.13.7
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.11
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.4.4
0.4.3
0.4.2
0.4.1
0.2.2
0.1.0
0.0.1
0.0.0
Nova is a web application framework
Current section
Files
Jump to
Current section
Files
src/nova_controller.erl
%%% @author Niclas Axelsson <niclas@burbas.se>
%%% @copyright (C) 2018, Niclas Axelsson
%%% @doc
%%%
%%% @end
%%% Created : 25 Jun 2018 by Niclas Axelsson <niclas@burbas.se>
-module(nova_controller).
-export([
init/2,
terminate/3
]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Public functions %
%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(Req, State = #{secure := false}) -> dispatch(Req, State);
init(Req, State = #{secure := {Mod, Func}}) ->
case Mod:Func(Req) of
true ->
dispatch(Req, State);
_ ->
Req1 = cowboy_req:reply(401, Req),
{ok, Req1, State}
end.
terminate(_Reason, _Req, _State) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Private functions %
%%%%%%%%%%%%%%%%%%%%%%%%%%%
dispatch(Req = #{method := ReqMethod},
State = #{mod := Mod, func := Func, method := Method}) when Method == '_' orelse
Method == ReqMethod ->
handle(Mod, Func, Req, State);
dispatch(Req, State) ->
Req1 = cowboy_req:reply(404, Req),
{ok, Req1, State}.
handle(Mod, Fun, Req = #{method := Method}, State) ->
case Mod:Fun(Req) of
{json, JSON} ->
EncodedJSON = jsone:encode(JSON, [undefined_as_null]),
StatusCode = case Method of
<<"POST">> -> 201;
_ -> 200
end,
Req1 = cowboy_req:reply(StatusCode, #{
<<"content-type">> => <<"application/json">>
}, EncodedJSON, Req),
{ok, Req1, State};
{json, StatusCode, Headers, JSON} ->
EncodedJSON = jsone:encode(JSON, [undefined_as_null]),
Req1 = cowboy_req:reply(StatusCode,
maps:merge(#{<<"content-type">> =>
<<"application/json">>},
Headers),
EncodedJSON,
Req),
{ok, Req1, State};
{ok, Variables} ->
%% Derive the view from module
ViewName = atom_to_list(Mod) ++ "_dtl",
ViewNameAtom = list_to_atom(ViewName),
handle_view(ViewNameAtom, Variables, #{}, Req, State);
{ok, Variables, Options} ->
View =
case maps:get(view, Options, undefined) of
undefined ->
ViewName = atom_to_list(Mod) ++ "_dtl",
list_to_atom(ViewName);
CustomView ->
CustomView
end,
handle_view(View, Variables, Options, Req, State);
{status, Status} when is_integer(Status) ->
Req1 = cowboy_req:reply(Status, #{}, Req),
{ok, Req1, State};
{status, Status, Headers} when is_integer(Status) ->
Req1 = cowboy_req:reply(Status, Headers, Req),
{ok, Req1, State};
{cowboy_req, CowboyReq} ->
{ok, CowboyReq, State};
Other ->
logger:info("Unsupported return value from controller ~p:~p/1. Returned: ~p", [Mod, Fun, Other]),
Req1 = cowboy_req:reply(500, #{}, Req),
{ok, Req1, State}
end.
handle_view(View, Variables, Options, Req, State) ->
{ok, HTML} = render_dtl(View, Variables, []),
Headers =
case maps:get(headers, Options, undefined) of
undefined ->
#{<<"content-type">> => <<"text/html">>};
UserHeaders ->
UserHeaders
end,
StatusCode = maps:get(status_code, Options, 200),
Req1 = cowboy_req:reply(StatusCode, Headers, HTML, Req),
{ok, Req1, State}.
render_dtl(View, Variables, Options) ->
case code:is_loaded(View) of
false ->
%% Cast a warning since the module could not be found
logger:warning("Could not render ~p cause it's not loaded.", [View]);
_ ->
View:render(Variables, Options)
end.