예제 #1
0
    public static LoginResult FacebookLogin(WebPage page, bool createAccount = false, bool isProvider = false)
    {
        var returnProfile = Request.Form["returnProfile"].AsBool();

        // Get Facebook User using the Request["accessToken"],
        // or signed_request or cookie.
        var fbuser  = LcFacebook.GetUserFromCurrentRequest();
        var fuserid = fbuser != null ? ((string)fbuser["id"] ?? "0").AsLong() : 0;

        if (fuserid > 0)
        {
            // It exists?
            var user = LcAuth.GetFacebookUser(fuserid);
            if (user != null)
            {
                // Become provider
                if (createAccount && isProvider)
                {
                    LcAuth.BecomeProvider(user.UserID);
                    user.IsProvider = true;
                    LcAuth.SendRegisterUserEmail(user);
                }
            }
            else
            {
                if (createAccount)
                {
                    user = CreateFacebookAccount(fbuser, isProvider);
                }
                else
                {
                    throw new HttpException(400, "[[[Incorrect user]]]");
                }
            }

            // Performs system login, using the autologin info since
            // there is no password here.
            var ret = GetLoginResultForID(new LcAuth.UserAuthorization
            {
                userID = user.UserID,
                token  = LcAuth.RegisterAuthorizationForUser(user.UserID)
            }, returnProfile);
            LcAuth.Autologin(ret.userID.ToString(), ret.authKey);
            return(ret);
        }
        else
        {
            throw new HttpException(500, "[[[Invalid Facebook credentials]]]");
        }
    }
예제 #2
0
    /// <summary>
    /// Signup with fields:
    /// - email [required]
    /// - password [required when no facebookUserID is given]
    /// - facebookUserID [optional]
    /// - countryID [optional defaults to COUNTRY_CODE_USA]
    /// - profileType [optional defaults to client]
    /// - utm [optional, not a named form parameter but the whole query string]
    /// - firstName [optional for professionals, required for clients]
    /// - lastName [optional for professionals, required for clients]
    /// - postalCode [optional]
    /// - referralCode [optional]
    /// - device [optional]
    /// - phone [optional for professionals, required for clients]
    /// - returnProfile [optional defaults to false] Returns the user profile in a property of the result
    /// </summary>
    /// <param name="page"></param>
    /// <returns></returns>
    public static LoginResult Signup(WebPage page)
    {
        page.Validation.RequireField("email", "You must specify an email.");
        // Username is an email currently, so need to be restricted
        page.Validation.Add("email",
                            Validator.Regex(LcValidators.EmailAddressRegexPattern, "The email is not valid."));

        // First data
        var profileTypeStr        = Request.Form["profileType"] ?? "";
        var isServiceProfessional = SERVICE_PROFESSIONAL_TYPE == profileTypeStr.ToUpper();
        var isClient            = !isServiceProfessional;
        var facebookUserID      = Request.Form["facebookUserID"].AsLong(0);
        var facebookAccessToken = Request.Form["facebookAccessToken"];
        var email = Request.Form["email"];

        //
        // Conditional validations
        // Facebook
        var useFacebookConnect = facebookUserID > 0 && !String.IsNullOrEmpty(facebookAccessToken);

        if (!useFacebookConnect)
        {
            page.Validation.RequireField("password", "You must specify a password.");
            // We manually validate if a password was given, in order to prevent
            // showing up the validation format message additionally to the 'required password' message
            if (!String.IsNullOrWhiteSpace(Request.Form["password"]))
            {
                page.Validation.Add("password", new PasswordValidator());
            }
        }
        else
        {
            var prevFbUser = LcAuth.GetFacebookUser(facebookUserID);
            if (prevFbUser != null)
            {
                throw new HttpException(409, "Facebook account already connected. Sign in.");
            }
        }
        // Profile Type
        if (isClient)
        {
            page.Validation.RequireField("phone", "You must specify your mobile phone number.");
            page.Validation.RequireField("firstName", "You must specify your first name.");
            page.Validation.RequireField("lastName", "You must specify your last name.");
        }

        if (page.Validation.IsValid())
        {
            var postalCode = Request.Form["postalCode"];
            // TODO To use countryCode for a more 'open' public REST API, where 'code' is a well know ISO 2-letters CODE
            //var countryCode = Request.Form["countryCode"] ?? "US";
            var countryID = Request.Form["countryID"].AsInt(COUNTRY_CODE_USA);

            // Postal code is Optional
            if (!String.IsNullOrEmpty(postalCode))
            {
                // Validate postal code before continue
                var add = new LcRest.Address
                {
                    postalCode = postalCode,
                    //countryCode = countryCode
                    countryID = countryID
                };
                if (!LcRest.Address.AutosetByCountryPostalCode(add))
                {
                    // bad postal code
                    page.ModelState.AddError("postalCode", "Invalid postal code");
                    throw new HttpException(400, LcRessources.ValidationSummaryTitle);
                }
            }

            // Autogenerated password (we need to save one) on facebook connect:
            var password      = useFacebookConnect ? LcAuth.GeneratePassword() : Request.Form["password"];
            var firstName     = Request.Form["firstName"];
            var lastName      = Request.Form["lastName"];
            var referralCode  = Request.Form["referralCode"];
            var device        = Request.Form["device"];
            var phone         = Request.Form["phone"];
            var returnProfile = Request.Form["returnProfile"].AsBool();

            var         utm    = Request.Url.Query;
            LoginResult logged = null;

            // If the user exists, try to log-in with the given password,
            // becoming a provider if that was the requested profileType and follow as
            // a normal login.
            // If the password didn't match, throw a sign-up specific error (email in use)
            // Otherwise, just register the user.
            if (LcAuth.ExistsEmail(email))
            {
                // If the email exists, we try to log-in using the provided password, to don't bother with "e-mail in use" error
                // if the user provides the correct credentials (maybe just don't remember he/she has already an account; make it easy for them
                // to return).
                // BUT we have a special situation that needs extra checks:
                // CLIENT--CONFIRMATION LOGIC
                // The email can exists because the user has an account created as client by a service professional:
                // - A: On that cases, we need to communicate that specific situation (error message), generate a confirmation code
                // for the existent user, send email to let him to confirm it owns the given e-mail.
                // - B: On returning here after point A, a confirmation code is provided and we must proceed
                // by checking the confirmation code and, on success, unlock and update the membership password and
                // continue updating any given data.
                var userID = WebSecurity.GetUserId(email);
                var user   = LcRest.UserProfile.Get(userID);
                if (user.accountStatusID != (int)LcEnum.AccountStatus.serviceProfessionalClient)
                {
                    // NOT a client, just standard sign-up that requires verify the email/password or fail
                    // Try Login
                    try
                    {
                        logged = Login(email, password, false, returnProfile, true);
                        userID = logged.userID;
                        // throw exception on error
                        if (isServiceProfessional)
                        {
                            LcAuth.BecomeProvider(userID);
                        }
                    }
                    catch (HttpException)
                    {
                        // Not valid log-in, throw a 'email exists' error with Conflict http code
                        throw new HttpException(409, "E-mail address is already in use.");
                    }
                }
                else
                {
                    // CLIENT--CONFIRMATION LOGIC
                    // The email can exists because the user has an account created as client by a service professional:
                    // - A: On that cases, we need to communicate that specific situation (error message), generate a confirmation code
                    // for the existent user, send email to let him to confirm it owns the given e-mail.
                    // - B: On returning here after point A, a confirmation code is provided and we must proceed
                    // by checking the confirmation code and, on success, unlock and update the membership password and
                    // continue updating any given data.
                    var confirmationCode = Request["confirmationCode"];
                    var errMsg           = String.Format(@"We see one of our service professionals has already scheduled services for you in the past.
                        We've just sent an invitation to create your account to {0}.
                        Please follow its instructions. We can't wait to get you on board!", email
                                                         );
                    if (String.IsNullOrEmpty(confirmationCode))
                    {
                        // Point A: create confirmation code
                        // generate a confirmation code (creates the Membership record, that does not exists still since is as just a client)
                        // this needs a random password (we still didn't verified the user, so do NOT trust on the given password).
                        // NOTE: since this can be attempted several time by the user, and next attempts will fail because the Membership
                        // record will exists already, just double check and try creation only if record don't exists:
                        if (!LcAuth.HasMembershipRecord(userID))
                        {
                            WebSecurity.CreateAccount(email, LcAuth.GeneratePassword(), true);
                        }
                        // send email to let him to confirm it owns the given e-mail
                        LcMessaging.SendWelcomeCustomer(userID, email);
                        // Not valid after all, just communicate was was done and needs to do to active its account:
                        throw new HttpException(409, errMsg);
                    }
                    else
                    {
                        // Point B: confirm confirmation code
                        if (LcAuth.GetConfirmationToken(userID) == confirmationCode)
                        {
                            // We know is valid, we can update the accountStatus to not be any more a "service professional's client"
                            // and that will allow to set the account as confirmed
                            using (var db = new LcDatabase())
                            {
                                db.Execute("UPDATE users SET accountStatusID = @1 WHERE UserID = @0", userID, LcEnum.AccountStatus.active);
                            }
                            // now we can confirm (we already know the code is valid, it will just double check and update database)
                            LcAuth.ConfirmAccount(confirmationCode);
                            // set the password provided by the user. Trick: we need to generate a reset token in order to set the password.
                            var token = WebSecurity.GeneratePasswordResetToken(email);
                            LcAuth.ResetPassword(token, password);
                            // Left continue with profile data update..
                        }
                        else
                        {
                            // RE-send email to let him to confirm it owns the given e-mail
                            LcMessaging.SendWelcomeCustomer(userID, email);
                            throw new HttpException(409, errMsg);
                        }
                    }

                    // We need a logged object, and additionally a double check is performed (so we ensure setting the password process worked).
                    logged = Login(email, password, false, returnProfile, false);
                }

                // Update account data with the extra information.
                using (var db = new LcDatabase())
                {
                    db.Execute(@"
                        UPDATE users SET
                            firstName = coalesce(@1, firstName),
                            lastName = coalesce(@2, lastName),
                            mobilePhone = coalesce(@3, mobilePhone),
                            signupDevice = coalesce(@4, signupDevice)
                        WHERE userID = @0
                    ", userID, firstName, lastName, phone, device);

                    if (!String.IsNullOrEmpty(postalCode))
                    {
                        var address = LcRest.Address.GetHomeAddress(userID);
                        if (address.postalCode != postalCode)
                        {
                            address.postalCode = postalCode;
                            //address.countryCode = countryCode;
                            address.countryCode = LcRest.Locale.GetCountryCodeByID(countryID);
                            address.countryID   = countryID;
                            LcRest.Address.SetAddress(address);
                        }
                    }
                }

                // SIGNUP
                LcMessaging.SendMail("*****@*****.**", "Sign-up", String.Format(@"
                    <html><body><h3>Sign-up.</h3>
                    <strong>This user was already in the database, is re-registering itself again!</strong><br/>
                    <dl>
                    <dt>Profile:</dt><dd>{0}</dd>
                    <dt>First Name:</dt><dd>{1}</dd>
                    <dt>Last Name:</dt><dd>{2}</dd>
                    <dt>Postal code:</dt><dd>{3}</dd>
                    <dt>Country:</dt><dd>{9}</dd>
                    <dt>Referral code:</dt><dd>{4}</dd>
                    <dt>Device:</dt><dd>{5}</dd>
                    <dt>Phone:</dt><dd>{6}</dd>
                    <dt>Email:</dt><dd>{7}</dd>
                    <dt>UserID:</dt><dd>{8}</dd>
                    </dl>
                    </body></html>
                ", profileTypeStr, firstName, lastName, postalCode, referralCode, device, phone, email, logged.userID, countryID));

                return(logged);
            }
            else
            {
                if (useFacebookConnect)
                {
                    // Verify Facebook ID and accessToken contacting to Facebook Servers
                    if (LcFacebook.GetUserFromAccessToken(facebookUserID.ToString(), facebookAccessToken) == null)
                    {
                        throw new HttpException(400, "Facebook account does not exists.");
                    }
                }

                var registered = LcAuth.RegisterUser(email, firstName, lastName, password, isServiceProfessional, utm, -1, null, phone, device);
                if (!String.IsNullOrEmpty(postalCode))
                {
                    // Set address
                    var address = LcRest.Address.GetHomeAddress(registered.UserID);
                    address.postalCode = postalCode;
                    //address.countryCode = countryCode;
                    address.countryCode = LcRest.Locale.GetCountryCodeByID(countryID);
                    address.countryID   = countryID;
                    LcRest.Address.SetAddress(address);
                }

                if (useFacebookConnect)
                {
                    // Register connection between the new account and the Facebook account
                    LcAuth.ConnectWithFacebookAccount(registered.UserID, facebookUserID);
                }

                // Welcome and confirmation e-mail
                LcAuth.SendRegisterUserEmail(registered);

                // SIGNUP
                LcMessaging.SendMail("*****@*****.**", "Sign-up", String.Format(@"
                    <html><body><h3>Sign-up.</h3>
                    <dl>
                    <dt>Profile:</dt><dd>{0}</dd>
                    <dt>First Name:</dt><dd>{1}</dd>
                    <dt>Last Name:</dt><dd>{2}</dd>
                    <dt>Postal code:</dt><dd>{3}</dd>
                    <dt>Country:</dt><dd>{9}</dd>
                    <dt>Referral code:</dt><dd>{4}</dd>
                    <dt>Device:</dt><dd>{5}</dd>
                    <dt>Phone:</dt><dd>{6}</dd>
                    <dt>Email:</dt><dd>{7}</dd>
                    <dt>UserID:</dt><dd>{8}</dd>
                    </dl>
                    </body></html>
                ", profileTypeStr, firstName, lastName, postalCode, referralCode, device, phone, email, registered.UserID, countryID));

                // Auto login:
                return(Login(email, password, false, returnProfile, true));
            }
        }
        else
        {
            // Bad request, input data incorrect because of validation rules
            throw new HttpException(400, LcRessources.ValidationSummaryTitle);
        }
    }
예제 #3
0
    /// <summary>
    /// Signup with fields:
    /// - email [required]
    /// - password [required when no facebookUserID is given]
    /// - facebookUserID [optional]
    /// - countryID [optional defaults to COUNTRY_CODE_USA]
    /// - profileType [optional defaults to client]
    /// - utm [optional, not a named form parameter but the whole query string]
    /// - firstName [optional except atBooking]
    /// - lastName [optional except atBooking]
    /// - phone [optional except atBooking]
    /// - returnProfile [optional defaults to false] Returns the user profile in a property of the result
    /// - atBooking [optional]
    /// - isOrganization [optional] Default false
    /// </summary>
    /// <param name="page"></param>
    /// <returns></returns>
    public static LoginResult Signup(WebPage page)
    {
        page.Validation.RequireField("email", "[[[You must specify an email.]]]");
        // Username is an email currently, so need to be restricted
        page.Validation.Add("email",
                            Validator.Regex(LcValidators.EmailAddressRegexPattern, "[[[The email is not valid.]]]"));

        // First data
        var profileTypeStr        = Request.Form["profileType"] ?? "";
        var isServiceProfessional = SERVICE_PROFESSIONAL_TYPE == profileTypeStr.ToUpper();
        var isClient            = !isServiceProfessional;
        var facebookUserID      = Request.Form["facebookUserID"].AsLong(0);
        var facebookAccessToken = Request.Form["facebookAccessToken"];
        var email          = Request.Form["email"];
        var atBooking      = Request.Form["atBooking"].AsBool();
        var isOrganization = Request.Form["isOrganization"].AsBool();

        //
        // Conditional validations
        // Facebook
        var useFacebookConnect = facebookUserID > 0 && !String.IsNullOrEmpty(facebookAccessToken);

        if (!useFacebookConnect)
        {
            page.Validation.RequireField("password", "[[[You must specify a password.]]]");
            // We manually validate if a password was given, in order to prevent
            // showing up the validation format message additionally to the 'required password' message
            if (!String.IsNullOrWhiteSpace(Request.Form["password"]))
            {
                page.Validation.Add("password", new PasswordValidator());
            }
        }
        else
        {
            var prevFbUser = LcAuth.GetFacebookUser(facebookUserID);
            if (prevFbUser != null)
            {
                throw new HttpException(409, "[[[Facebook account already connected. Sign in.]]]");
            }
        }

        // For a signup at a client booking, we require more fields
        if (atBooking)
        {
            page.Validation.RequireField("phone", "[[[You must specify your mobile phone number.]]]");
            page.Validation.RequireField("firstName", "[[[You must specify your first name.]]]");
            page.Validation.RequireField("lastName", "[[[You must specify your last name.]]]");
        }

        if (page.Validation.IsValid())
        {
            // TODO To use countryCode for a more 'open' public REST API, where 'code' is a well know ISO 2-letters CODE
            //var countryCode = Request.Form["countryCode"] ?? "US";
            var countryID = Request.Form["countryID"].AsInt(COUNTRY_CODE_AU);

            // Autogenerated password (we need to save one) on facebook connect:
            var password      = useFacebookConnect ? LcAuth.GeneratePassword() : Request.Form["password"];
            var firstName     = Request.Form["firstName"];
            var lastName      = Request.Form["lastName"];
            var phone         = Request.Form["phone"];
            var returnProfile = Request.Form["returnProfile"].AsBool();

            var         utm    = Request.Url.Query;
            LoginResult logged = null;

            // If the user exists, try to log-in with the given password,
            // becoming a provider if that was the requested profileType and follow as
            // a normal login.
            // If the password didn't match, throw a sign-up specific error (email in use)
            // Otherwise, just register the user.
            if (LcAuth.ExistsEmail(email))
            {
                // We query the user with that email
                var userID = WebSecurity.GetUserId(email);
                var user   = LcRest.UserProfile.Get(userID);
                // There are special cases when a user is registered, but never has accepted TOU or created a password (Not Enabled Account),
                // and is possible for that user to become an regular/enabled account.
                if (IsUserButNotEnabledAccount(user))
                {
                    logged = SignupANotEnabledAccount(userID, email, password, returnProfile, user.accountStatusID, isOrganization);
                }
                else
                {
                    // If the email exists, we try to log-in using the provided password, to don't bother with "e-mail in use" error
                    // if the user provides the correct credentials (maybe just don't remember he/she has already an account; make it easy for them
                    // to return).
                    // Try Login
                    try
                    {
                        logged = Login(email, password, false, returnProfile, true);
                        userID = logged.userID;
                        // Ensure we set-up
                        // as a professional if requested
                        // Next code will throw exception on error
                        if (isServiceProfessional)
                        {
                            LcAuth.BecomeProvider(userID);
                        }
                    }
                    catch (HttpException)
                    {
                        // Not valid log-in, throw a 'email exists' error with Conflict http code
                        throw new HttpException(409, "[[[E-mail address is already in use.]]]");
                    }
                }

                // Update account data with the extra information.
                using (var db = new LcDatabase())
                {
                    db.Execute(@"
                        UPDATE users SET
                            firstName = coalesce(@1, firstName),
                            lastName = coalesce(@2, lastName),
                            mobilePhone = coalesce(@3, mobilePhone),
                            isOrganization = @4
                        WHERE userID = @0
                    ", userID, firstName, lastName, phone, isOrganization);
                    // Create a home address record almost with the country
                    var home = LcRest.Address.GetHomeAddress(userID);
                    home.countryCode = LcRest.Locale.GetCountryCodeByID(countryID);
                    home.countryID   = countryID;
                    LcRest.Address.SetAddress(home);

                    StartOnboardingForUser(userID);
                }

                // SIGNUP
                LcMessaging.SendMail("*****@*****.**", "Sign-up", String.Format(@"
                    <html><body><h3>Sign-up.</h3>
                    <strong>This user was already in the database, is re-registering itself again!</strong><br/>
                    <dl>
                    <dt>Profile:</dt><dd>{0}</dd>
                    <dt>First Name:</dt><dd>{1}</dd>
                    <dt>Last Name:</dt><dd>{2}</dd>
                    <dt>Country:</dt><dd>{5}</dd>
                    <dt>Email:</dt><dd>{3}</dd>
                    <dt>UserID:</dt><dd>{4}</dd>
                    <dt>Phone:</dt><dd>{6}</dd>
                    </dl>
                    </body></html>
                ", profileTypeStr, firstName, lastName, email, logged.userID, countryID, phone));

                return(logged);
            }
            else
            {
                if (useFacebookConnect)
                {
                    // Verify Facebook ID and accessToken contacting to Facebook Servers
                    if (LcFacebook.GetUserFromAccessToken(facebookUserID.ToString(), facebookAccessToken) == null)
                    {
                        throw new HttpException(400, "[[[Facebook account does not exists.]]]");
                    }
                }

                var registered = LcAuth.RegisterUser(email, firstName, lastName, password,
                                                     isServiceProfessional, utm, -1, null, phone, null, countryID, isOrganization);

                // Create a home address record almost with the country
                var home = LcRest.Address.GetHomeAddress(registered.UserID);
                home.countryCode = LcRest.Locale.GetCountryCodeByID(countryID);
                home.countryID   = countryID;
                LcRest.Address.SetAddress(home);

                if (useFacebookConnect)
                {
                    // Register connection between the new account and the Facebook account
                    LcAuth.ConnectWithFacebookAccount(registered.UserID, facebookUserID);
                }

                // Welcome and confirmation e-mail
                LcAuth.SendRegisterUserEmail(registered);

                // SIGNUP
                LcMessaging.SendMail("*****@*****.**", "Sign-up", String.Format(@"
                    <html><body><h3>Sign-up.</h3>
                    <dl>
                    <dt>Profile:</dt><dd>{0}</dd>
                    <dt>First Name:</dt><dd>{1}</dd>
                    <dt>Last Name:</dt><dd>{2}</dd>
                    <dt>Country:</dt><dd>{5}</dd>
                    <dt>Email:</dt><dd>{3}</dd>
                    <dt>UserID:</dt><dd>{4}</dd>
                    <dt>Phone:</dt><dd>{6}</dd>
                    </dl>
                    </body></html>
                ", profileTypeStr, firstName, lastName, email, registered.UserID, countryID, phone));

                // Auto login:
                return(Login(email, password, false, returnProfile, true));
            }
        }
        else
        {
            // Bad request, input data incorrect because of validation rules
            throw new HttpException(400, LcRessources.ValidationSummaryTitle);
        }
    }