Skip to content

Commit

Permalink
Signup confirm redirect (0.x) (#3243)
Browse files Browse the repository at this point in the history
* mod_signup: add option to redirect to a pre-defined page on signup

* Use q.p, similar to logon

* No redirect to home page

* Make signup redirect backwards compatible
  • Loading branch information
mworrell committed Jan 10, 2023
1 parent 993c4ba commit a05e728
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 14 deletions.
7 changes: 5 additions & 2 deletions include/zotonic_notifications.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
-record(content_types_dispatch, {id}).

% @doc Check where to go after a user logs on. Return an URL or undefined (first)
-record(logon_ready_page, {request_page=[]}).
-record(logon_ready_page, {request_page=""}).

%% @doc Determine post-logon actions; args are the arguments passed to the logon
%% submit wire
Expand Down Expand Up @@ -113,7 +113,10 @@

%% @doc Fetch the page an user is redirected to after signing up with a confirmed identity (first)
%% Return either undefined or a Url
-record(signup_confirm_redirect, {id}).
-record(signup_confirm_redirect, {
id :: m_rsc:resource_id(),
request_page = undefined :: undefined | string()
}).


%% @doc Handle a javascript notification from the postback handler. The 'message' is the z_msg argument of
Expand Down
1 change: 1 addition & 0 deletions modules/mod_authentication/templates/_logon_modal.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Make sure that these CSS files are loaded:
update_template=update_template
style_boxed=style_boxed
style_width=style_width
page=page
%}
{% elseif logon_state == `reminder` %}
{% if logon_context == 'admin_logon' %}
Expand Down
42 changes: 35 additions & 7 deletions modules/mod_signup/controllers/controller_signup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,11 @@ has_email_identity(Email, [_|Rest]) -> has_email_identity(Email, Rest).
signup(Props, SignupProps, RequestConfirm, Context) ->
UserId = proplists:get_value(user_id, SignupProps),
SignupProps1 = proplists:delete(user_id, SignupProps),
case mod_signup:signup_existing(UserId, Props, SignupProps1, RequestConfirm, Context) of
ReadyPage = get_redirect_page(SignupProps1, Context),
SignupProps2 = [ {ready_page, ReadyPage} | proplists:delete(ready_page, SignupProps1) ],
case mod_signup:signup_existing(UserId, Props, SignupProps2, RequestConfirm, Context) of
{ok, NewUserId} ->
handle_confirm(NewUserId, SignupProps1, RequestConfirm, Context);
handle_confirm(NewUserId, ReadyPage, RequestConfirm, Context);
{error, {identity_in_use, username}} ->
show_errors([error_duplicate_username], Context);
{error, {identity_in_use, _}} ->
Expand All @@ -153,13 +155,13 @@ signup(Props, SignupProps, RequestConfirm, Context) ->


%% Handle sending a confirm, or redirect to the 'ready_page' location
handle_confirm(UserId, SignupProps, RequestConfirm, Context) ->
handle_confirm(UserId, ReadyPage, RequestConfirm, Context) ->
case not RequestConfirm orelse m_identity:is_verified(UserId, Context) of
true ->
ensure_published(UserId, z_acl:sudo(Context)),
{ok, ContextUser} = z_auth:logon(UserId, Context),
Location = case get_redirect_page(SignupProps) of
[] ->
Location = case ReadyPage of
"" ->
case z_notifier:first(#signup_confirm_redirect{id=UserId}, ContextUser) of
undefined -> m_rsc:p(UserId, page_url, ContextUser);
Loc -> Loc
Expand All @@ -169,6 +171,20 @@ handle_confirm(UserId, SignupProps, RequestConfirm, Context) ->
end,
z_render:wire({redirect, [{location, Location}]}, ContextUser);
false ->
% Store ready page for later redirect after verification
case z_notifier:first(
#tkvstore_put{
type = <<"signup_ready_page">>,
key = integer_to_binary(UserId),
value = ReadyPage
},
Context)
of
undefined when ReadyPage =/= "", ReadyPage =/= undefined ->
lager:info("Signup ready page not stored, as mod_tkvstore is not running.");
_ ->
ok
end,
% User is not yet verified, send a verification message to the user's external identities
case mod_signup:request_verification(UserId, Context) of
{error, no_verifiable_identities} ->
Expand All @@ -181,8 +197,20 @@ handle_confirm(UserId, SignupProps, RequestConfirm, Context) ->
end
end.

get_redirect_page(SignupProps) ->
z_convert:to_list(proplists:get_value(ready_page, SignupProps, [])).
get_redirect_page(SignupProps, Context) ->
ReadyPage = proplists:get_value(ready_page, SignupProps),
case z_utils:is_empty(ReadyPage) of
true ->
Page = z_context:get_q("page", Context),
case z_utils:is_empty(Page) of
true ->
"";
false ->
z_context:site_url(Page, Context)
end;
false ->
z_context:site_url(z_convert:to_list(ReadyPage))
end.


ensure_published(UserId, Context) ->
Expand Down
41 changes: 36 additions & 5 deletions modules/mod_signup/controllers/controller_signup_confirm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ event(#submit{}, Context) ->
{ok, UserId} ->
{ok, ContextUser} = z_auth:logon(UserId, Context),
Location = confirm_location(UserId, ContextUser),
Location1 = z_context:site_url(Location, Context),
z_render:wire([
{hide, [{target, "confirm_form"}]},
{show, [{target, "confirm_ok"}]},
{redirect, [{location, Location}]}
{redirect, [{location, Location1}]}
], ContextUser);
{error, _Reason} ->
z_render:wire([
Expand All @@ -79,8 +80,38 @@ confirm(Key, Context) ->
{ok, UserId}
end.

confirm_location(UserId, Context) ->
case z_notifier:first(#signup_confirm_redirect{id=UserId}, Context) of
undefined -> m_rsc:p(UserId, page_url, Context);
Loc -> Loc
confirm_location(UserId, ContextUser) ->
% Fetch ready page, stored at signup
ReadyPage = z_notifier:first(
#tkvstore_get{
type = <<"signup_ready_page">>,
key = integer_to_binary(UserId)
},
ContextUser),
z_notifier:first(
#tkvstore_delete{
type = <<"signup_ready_page">>,
key = integer_to_binary(UserId)
},
ContextUser),
ReadyPage1 = case is_empty(ReadyPage) of
true ->
undefined;
false ->
z_convert:to_list(ReadyPage)
end,
case z_notifier:first(#signup_confirm_redirect{ id = UserId, request_page = ReadyPage1 }, ContextUser) of
undefined when ReadyPage1 =:= undefined ->
m_rsc:p(UserId, page_url, ContextUser);
undefined ->
ReadyPage1;
Loc ->
Loc
end.

is_empty(undefined) -> true;
is_empty("") -> true;
is_empty("#reload") -> true;
is_empty(<<>>) -> true;
is_empty(<<"#reload">>) -> true;
is_empty(_) -> false.
7 changes: 7 additions & 0 deletions modules/mod_signup/templates/_signup_form.tpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{% wire id="signup_form" type="submit" postback={signup xs_props=xs_props} delegate=signup_delegate %}
<form id="signup_form" class="setcookie" method="post" action="postback">
<input type="hidden" name="page" value="{{ page|default:q.p|escape }}">
{% include form_fields_tpl %}
</form>

{% if page|default:q.p == '#reload' %}
{% javascript %}
$('#signup_form input[name="page"]').val(window.location.pathname + window.location.search);
{% endjavascript %}
{% endif %}

0 comments on commit a05e728

Please sign in to comment.