diff --git a/modules/mod_ginger_base/support/ginger_environment.erl b/modules/mod_ginger_base/support/ginger_environment.erl index 748776715..53f96b452 100644 --- a/modules/mod_ginger_base/support/ginger_environment.erl +++ b/modules/mod_ginger_base/support/ginger_environment.erl @@ -14,13 +14,20 @@ %% @doc Get current environment -spec get(#context{}) -> dev|acc|prod. get(Context) -> - case is_dev(Context) of - true -> dev; - false -> - case is_acc(Context) of - true -> acc; - false -> prod - end + case z_config:get(environment) of + production -> + case is_dev(Context) of + true -> dev; + false -> + case is_acc(Context) of + true -> acc; + false -> prod + end + end; + acceptance -> + acc; + _ -> + dev end. is_dev(Context) -> diff --git a/modules/mod_ginger_rdf/models/m_rdf_export.erl b/modules/mod_ginger_rdf/models/m_rdf_export.erl index c83227d92..9adfaa7ce 100644 --- a/modules/mod_ginger_rdf/models/m_rdf_export.erl +++ b/modules/mod_ginger_rdf/models/m_rdf_export.erl @@ -24,7 +24,10 @@ to_rdf(Id, Context) -> %% - media. -spec to_rdf(m_rsc:resource(), [module()], z:context()) -> m_rdf:rdf_resource(). to_rdf(Id, Ontologies, Context) -> - Properties = m_rsc:get_visible(Id, Context), + Properties = case m_rsc:get_visible(Id, Context) of + undefined -> []; + Props -> Props + end, Edges = m_edge:get_edges(Id, Context), Types = types(proplists:get_value(category_id, Properties), Context), Triples = lists:flatten( diff --git a/modules/mod_ginger_spa/README.md b/modules/mod_ginger_spa/README.md index 923f5ca06..e01bf1abc 100644 --- a/modules/mod_ginger_spa/README.md +++ b/modules/mod_ginger_spa/README.md @@ -1,7 +1,42 @@ mod_ginger_spa -======================== +============== Default template and dispatch rules for a single page app. _Only routes for which a Ginger resource with the same path exists will be served by the `page.tpl` template. Other routes should be manually added to the sites dispatch rules._ + + +Template rendering +------------------ + +The `controller_ginger_spa_template` renders templates and returns the result as plain text. + +Pass the template name in the path, example: + + https://example.com/render-template/public/test.tpl + +This renders the template `"public/test.tpl"`. + +Pass arguments via the query string: + + https://example.com/render-template/public/test.tpl?id=1 + +Or in a POST body as `application/x-www-form-urlencoded` or `multipart/form-data`. + +Use the argument `catinclude=1` to render the template using a *catinclude*. +Any `id` argument is always added as `id` to the template arguments (after mapping using `m_rsc:rid/2`), in +this way the `id` is always available and usable for the optional catinclude. + +Security +........ + +As in Zotonic 0.x template models are not access checked there is a security using the name of the template. + +Templates starting with `public/...` can be rendered by anonymous users. + +Templates starting with `member/...` can be rendered by authenticated users. + +Administrators are allowed to render all templates. + + diff --git a/modules/mod_ginger_spa/controllers/controller_ginger_spa_template.erl b/modules/mod_ginger_spa/controllers/controller_ginger_spa_template.erl new file mode 100644 index 000000000..b1cb25233 --- /dev/null +++ b/modules/mod_ginger_spa/controllers/controller_ginger_spa_template.erl @@ -0,0 +1,83 @@ +%% @copyright Driebit BV 2021 +%% @doc Controller to render templates. Post arguments via the query arguments. + +-module(controller_ginger_spa_template). + +-export([init/1, service_available/2, charsets_provided/2, content_types_provided/2]). +-export([allowed_methods/2, resource_exists/2]). +-export([process_post/2, provide_content/2]). + +-include_lib("controller_webmachine_helper.hrl"). +-include_lib("include/zotonic.hrl"). + +init(DispatchArgs) -> {ok, DispatchArgs}. + +service_available(ReqData, DispatchArgs) when is_list(DispatchArgs) -> + Context1 = z_context:new_request(ReqData, DispatchArgs, ?MODULE), + ?WM_REPLY(true, Context1). + +allowed_methods(ReqData, Context) -> + {[ 'POST', 'GET', 'HEAD' ], ReqData, Context}. + +charsets_provided(ReqData, Context) -> + {[{"utf-8", fun(X) -> X end}], ReqData, Context}. + +content_types_provided(ReqData, Context) -> + {[{"text/plain", provide_content}], ReqData, Context}. + +resource_exists(ReqData, Context) -> + Context1 = ?WM_REQ(ReqData, Context), + Context2 = z_context:ensure_all(Context1), + ?WM_REPLY(true, Context2). + +process_post(ReqData, Context) -> + Context1 = ?WM_REQ(ReqData, Context), + Result = render(Context1), + ReqData1 = wrq:set_resp_body(Result, ReqData), + {{halt, 200}, ReqData1, Context}. + +provide_content(ReqData, Context) -> + Context1 = ?WM_REQ(ReqData, Context), + Result = render(Context1), + ?WM_REPLY(Result, Context1). + +render(Context) -> + case template(Context) of + {ok, Template} -> + Vars = [ + {is_spa_render, true}, + {id, m_rsc:rid(z_context:get_q("id", Context), Context)} + ], + Template1 = case is_catinclude(Context) of + true -> {cat, Template}; + false -> Template + end, + {Data, _} = z_template:render_to_iolist(Template1, Vars, Context), + iolist_to_binary(Data); + {error, _} -> + lager:info("[~p] Denied render of template \"~s\"", [ z_context:site(Context), m_req:get(path, Context) ]), + <<>> + end. + +is_catinclude(Context) -> + z_convert:to_bool(z_context:get_q("catinclude", Context)). + +template(Context) -> + case z_context:get(template, Context) of + undefined -> + case path(Context) of + "api/render-template/" ++ Template -> + {ok, drop_slash(Template)}; + _ -> + {error, enoent} + end; + Template -> + {ok, Template} + end. + +drop_slash("/" ++ Path) -> drop_slash(Path); +drop_slash(Path) -> Path. + +path(Context) -> + DispatchPath = z_context:get_q("zotonic_dispatch_path", Context), + lists:flatten( z_utils:combine($/, DispatchPath) ). diff --git a/modules/mod_ginger_spa/dispatch/dispatch b/modules/mod_ginger_spa/dispatch/dispatch index 29349bd5b..532322267 100644 --- a/modules/mod_ginger_spa/dispatch/dispatch +++ b/modules/mod_ginger_spa/dispatch/dispatch @@ -1,3 +1,6 @@ [{home, [], controller_template, [ {template, "page.tpl"}, {id, home} ]}, - {search, ["search"], controller_template, [ {template, "page.tpl"} ]} + {search, ["search"], controller_template, [ {template, "page.tpl"} ]}, + + % Render a template the path is the template, pass arguments via the query post or get + {spa_render, ["api", "render-template", "public", '*' ], controller_ginger_spa_template, []} ]. diff --git a/modules/mod_ginger_spa/templates/public/test.tpl b/modules/mod_ginger_spa/templates/public/test.tpl new file mode 100644 index 000000000..f9e9006c2 --- /dev/null +++ b/modules/mod_ginger_spa/templates/public/test.tpl @@ -0,0 +1,2 @@ +{% debug %} +{% print q.v %}