Permalink
Browse files

core: added support for signing up with facebook for a known user.

Moved some check functions to m_identity.
Fixed problem where an email identity could be added multiple times (when signing up using FB)
  • Loading branch information...
1 parent e93467c commit bb0e7fa4ff6f97ff630dc113cbb58c450c67ee12 @mworrell mworrell committed Mar 27, 2013
@@ -184,8 +184,8 @@ event(#postback{message={identity_add, Args}}, Context) ->
<<>> ->
Context;
Key ->
- KeyNorm = normalize_key(Type, Key),
- case is_valid_key(Type, KeyNorm, Context) of
+ KeyNorm = m_identity:normalize_key(Type, Key),
+ case m_identity:is_valid_key(Type, KeyNorm, Context) of
true ->
case is_existing_key(RscId, Type, KeyNorm, Context) of
true ->
@@ -206,10 +206,6 @@ event(#postback{message={identity_add, Args}}, Context) ->
z_render:growl_error(?__("You are not allowed to edit identities.", Context), Context)
end.
-is_valid_key(email, Key, _Context) ->
- z_email_utils:is_email(Key);
-is_valid_key(_Type, _Key, _Context) ->
- true.
is_existing_key(RscId, Type, Key, Context) ->
Existing = m_identity:get_rsc_by_type(RscId, Type, Context),
@@ -218,20 +214,11 @@ is_existing_key(RscId, Type, Key, Context) ->
_ -> true
end.
-normalize_key(email, Key) ->
- z_convert:to_binary(z_string:trim(z_string:to_lower(Key)));
-normalize_key(_Type, Key) ->
- Key.
-
ensure(_RscId, _Type, undefined, _Context) -> ok;
ensure(_RscId, _Type, <<>>, _Context) -> ok;
ensure(_RscId, _Type, [], _Context) -> ok;
ensure(RscId, Type, Key, Context) ->
- KeyNorm = normalize_key(Type, Key),
- case is_valid_key(Type, KeyNorm, Context) of
- true -> m_identity:ensure(RscId, Type, KeyNorm, Context);
- false -> {error, invalid_key}
- end.
+ m_identity:insert(RscId, Type, Key, Context).
optional_update_list(_RscId, _Type, [], Context) ->
@@ -48,13 +48,12 @@ previously_existed(ReqData, Context) ->
{true, ReqData, Context}.
moved_temporarily(ReqData, Context) ->
- %% @todo add the redirect page parameter of the logon page to the redirect url
Context1 = ?WM_REQ(ReqData, Context),
{AppId, _AppSecret, Scope} = mod_facebook:get_config(Context1),
- Page = get_page(Context1),
+ Args = get_args(Context1),
RedirectUrl = z_convert:to_list(
z_context:abs_url(
- z_dispatcher:url_for(facebook_redirect, [{p,Page}], Context1),
+ z_dispatcher:url_for(facebook_redirect, Args, Context1),
Context1)),
Location = "https://www.facebook.com/dialog/oauth?client_id="
++ z_utils:url_encode(AppId)
@@ -63,6 +62,15 @@ moved_temporarily(ReqData, Context) ->
?WM_REPLY({true, Location}, Context1).
+get_args(Context) ->
+ case z_context:get_q("pk", Context, []) of
+ [] ->
+ Page = get_page(Context),
+ [{pk, z_utils:pickle([{p,Page}], Context)}];
+ PK ->
+ [{pk, PK}]
+ end.
+
%% @doc Get the page we should redirect to after a successful log on.
get_page(Context) ->
case z_context:get_q("p", Context, []) of
@@ -1,11 +1,10 @@
%% @author Marc Worrell <marc@worrell.nl>
-%% @copyright 2010 Marc Worrell
-%% Date: 2010-05-11
+%% @copyright 2010-2013 Marc Worrell
%% @doc Handle the OAuth redirect of the Facebook logon handshake.
%% See http://developers.facebook.com/docs/authentication/
%% @todo Update a user record when we receive a new e-mail address.
-%% Copyright 2010 Marc Worrell
+%% Copyright 2010-2013 Marc Worrell
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -59,7 +58,7 @@ moved_temporarily(ReqData, Context) ->
case fetch_user_data(AccessToken) of
{ok, UserProps} ->
- logon_fb_user(UserProps, z_context:get_q("p", Context1), Context1);
+ logon_fb_user(UserProps, unpack_args(Context1), Context1);
{error, Reason} ->
redirect_error(Reason, Context1)
end;
@@ -70,7 +69,6 @@ moved_temporarily(ReqData, Context) ->
%% @doc Redirect user to a signup failure URL, or to the logon page.
redirect_error(Reason, Context) ->
- ?DEBUG({?MODULE, Reason}),
z_context:set_session(facebook_logon, false, Context),
z_context:set_session(facebook_access_token, undefined, Context),
z_context:set_session(facebook_access_token_expires, undefined, Context),
@@ -85,8 +83,8 @@ redirect_error(Reason, Context) ->
% Exchange the code for an access token
fetch_access_token(Code, Context) ->
{AppId, AppSecret, _Scope} = mod_facebook:get_config(Context),
- Page = z_context:get_q("p", Context, "/"),
- RedirectUrl = z_context:abs_url(z_dispatcher:url_for(facebook_redirect, [{p,Page}], Context), Context),
+ PK = z_context:get_q("pk", Context, []),
+ RedirectUrl = z_context:abs_url(z_dispatcher:url_for(facebook_redirect, [{pk,PK}], Context), Context),
FacebookUrl = "https://graph.facebook.com/oauth/access_token?client_id="
++ z_utils:url_encode(AppId)
@@ -114,11 +112,7 @@ fetch_user_data(AccessToken) ->
%% @doc Check if the user exists, if not then hand over control to the auth_signup resource.
-logon_fb_user(FacebookProps, LocationAfterSignup0, Context) ->
- LocationAfterSignup = case z_utils:is_empty(LocationAfterSignup0) of
- true -> undefined;
- false -> LocationAfterSignup0
- end,
+logon_fb_user(FacebookProps, Args, Context) ->
Props = [
{title, unicode:characters_to_binary(proplists:get_value(name, FacebookProps))},
{name_first, unicode:characters_to_binary(proplists:get_value(first_name, FacebookProps))},
@@ -131,60 +125,59 @@ logon_fb_user(FacebookProps, LocationAfterSignup0, Context) ->
undefined ->
% Register the Facebook identities as verified
SignupProps = [
- {identity, {username_pw, {z_utils:generate_username(Props, Context), z_ids:id(6)}, true, true}},
+ {identity, {username_pw, {z_utils:generate_username(Props, Context), z_ids:id(10)}, true, true}},
{identity, {facebook, UID, true, true}},
- {identity, {email, proplists:get_value(email, FacebookProps), true, true}},
- {ready_page, LocationAfterSignup}
+ {identity, {email, proplists:get_value(email, FacebookProps), true, true}}
+ | Args
],
case z_notifier:first(#signup_url{props=Props, signup_props=SignupProps}, Context) of
{ok, Location} ->
- use_see_other(Location, Context);
- %?WM_REPLY({true, Location}, Context);
+ ?WM_REPLY({true, Location}, Context);
undefined ->
throw({error, {?MODULE, "No result from signup_url notification handler"}})
end;
Row ->
UserId = proplists:get_value(rsc_id, Row),
- {Location,Context1} = case z_auth:logon(UserId, Context) of
- {ok, ContextUser} ->
- update_user(UserId, Props, ContextUser),
- case z_notifier:first(#logon_ready_page{request_page=LocationAfterSignup}, ContextUser) of
- undefined ->
- case LocationAfterSignup of
- undefined ->
- {m_rsc:p(UserId, page_url, ContextUser), ContextUser};
- _ ->
- {LocationAfterSignup, ContextUser}
- end;
- Url -> {Url, ContextUser}
- end;
- {error, _Reason} ->
- {z_dispatcher:url_for(logon, [{error_uid,UserId}], Context), Context}
- end,
- LocationAbs = lists:flatten(z_context:abs_url(Location, Context1)),
- use_see_other(LocationAbs, Context1)
+ {Location,Context1} = case z_auth:logon(UserId, Context) of
+ {ok, ContextUser} ->
+ update_user(UserId, Props, ContextUser),
+ LocationAfterSignup = proplists:get_value(p, Args),
+ case z_notifier:first(#logon_ready_page{request_page=LocationAfterSignup}, ContextUser) of
+ undefined ->
+ case LocationAfterSignup of
+ undefined ->
+ {m_rsc:p(UserId, page_url, ContextUser), ContextUser};
+ _ ->
+ {LocationAfterSignup, ContextUser}
+ end;
+ Url -> {Url, ContextUser}
+ end;
+ {error, _Reason} ->
+ {z_dispatcher:url_for(logon, [{error_uid,UserId}], Context), Context}
+ end,
+ LocationAbs = z_convert:to_list(z_context:abs_url(Location, Context1)),
+ ?WM_REPLY({true, LocationAbs}, Context1)
end.
- %% HACK ALERT!
- %% We use a 303 See Other here as there is a serious bug in Safari 4.0.5
- %% When we use a 307 then the orginal login post at Facebook will be posted
- %% to our redirect location. Including the Facebook username and password....
- use_see_other(Location, Context) ->
- ContextLoc = z_context:set_resp_header("Location", Location, Context),
- ?WM_REPLY({halt, 303}, ContextLoc).
-
-
-% [{"id","100001090298809"},
-% {"name","Marc Worrell"},
-% {"first_name","Marc"},
-% {"last_name","Worrell"},
-% {"link","http://www.facebook.com/profile.php?id=100001090298809"},
+% [{"id","10000123456789"},
+% {"name","Jane Doe"},
+% {"first_name","Jane"},
+% {"last_name","Doe"},
+% {"link","http://www.facebook.com/profile.php?id=10000123456789"},
% {"gender","man"},
-% {"email","marc@worrell.nl"},
+% {"email","me@example.com"},
% {"timezone",2},
% {"updated_time","2010-05-09T11:27:09+0000"}]
-
update_user(_UserId, _Props, _Context) ->
ok.
+
+%% @doc Unpickle the optional argument. This give a list of args given by the redirect
+unpack_args(Context) ->
+ case z_context:get_q("pk", Context) of
+ undefined -> [];
+ Pickled -> z_utils:depickle(Pickled, Context)
+ end.
+
+
@@ -27,9 +27,13 @@
-export([
observe_auth_logoff/3,
observe_search_query/2,
- observe_admin_menu/3
+ observe_admin_menu/3,
+
+ event/2
+]).
+-export([
+ get_config/1
]).
--export([get_config/1]).
-include("zotonic.hrl").
-include_lib("modules/mod_admin/include/admin_menu.hrl").
@@ -43,16 +47,8 @@
%% @doc Reset the received facebook access token (as set in the session)
observe_auth_logoff(auth_logoff, AccContext, _Context) ->
- AccContext1 = case z_context:get_session(facebook_logon, AccContext) of
- true ->
- z_script:add_script(
- "FB.logout(function() { window.location = '/'; }); setTimeout(function() { window.location='/'; }, 8000)",
- AccContext);
- _ ->
- AccContext
- end,
- z_context:set_session(facebook_logon, false, AccContext1),
- z_context:set_session(facebook_access_token, undefined, AccContext1).
+ z_context:set_session(facebook_logon, false, AccContext),
+ z_context:set_session(facebook_access_token, undefined, AccContext).
%% @doc Return the facebook appid, secret and scope
@@ -79,3 +75,16 @@ observe_admin_menu(admin_menu, Acc, Context) ->
visiblecheck={acl, use, mod_facebook}}
|Acc].
+
+
+%% @doc Redirect to facebook, keep extra arguments in query arg
+event(#postback{message={logon_redirect, Args}}, Context) ->
+ Pickled = z_utils:pickle(Args, Context),
+ z_render:wire([
+ {alert, [
+ {title, ?__("One moment please", Context)},
+ {text, ?__("Redirecting to Facebook", Context)}
+ ]},
+ {redirect, [{dispatch, facebook_authorize}, {pk, Pickled}]}
+ ], Context).
+
@@ -2,6 +2,6 @@
{% wire id=#fb_logon
action={mask target=mask_target|default:"logon_outer" message="Waiting for Facebook …"}
- action={redirect dispatch="facebook_authorize" p=page}
+ postback={logon_redirect ready_page=page user_id=user_id}
+ delegate=`mod_facebook`
%}
-
Oops, something went wrong.

0 comments on commit bb0e7fa

Please sign in to comment.