Magento - How to Login with “Secondary Email” customer attribute? - php

How would a customer be able to login with both their primary email address they signed up with as well as a Secondary email address customer attribute field? (I’ve created a customer attribute text field secondary_email).
Assuming it has something to do with customerEntity and would be similair to what people have been doing to get usernames to work: http://www.magentocommerce.com/magento-connect/Sylvain_Raye/extension/7928/diglin_username
or
http://www.magentocommerce.com/boards/viewthread/195573/P15/
I just need for customers to have 1 single password, but be able to use an alternate email address specified within their account if they want.
Thank you!

Magento is no different from almost all other PHP-based frameworks in that it has a serial flow of execution. Thinking from a request flow standpoint, an entry point to suss out your requirement would be the class which handles the login form POST. You can see this in the rendered source in your browser: action="https://demo.magentocommerce.com/customer/account/loginPost/".
The above URI resolves to the method Mage_Customer_AccountController::loginPostAction(). In there one finds typical login logic for a login controller action: is user logged in? is the user posting in login data? is the the login data valid? and so forth. This quickly points to the customer session model, Mage_Customer_Model_Session, particularly to the authenticate() method. In this method is a call to Mage_Customer_Model_Customer->loadByEmail(), which gets us to Mage_Customer_Model_Entity_Model->loadByEmail()`.
At this point, we know that we can rewrite the resource model and change its loadByEmail() to handle lookup of a secondary email method (messy & obtrusive). We could also rewrite and change Mage_Customer_Model_Session->authenticate(), providing some pre-processing to first load the customer record by secondary email, then extract the main email and allow things to proceed as normal.
//rewritten authenticate method
public function authenticate($username,$password) {
$customer = Mage::getResourceModel('customer/customer_collection')
->addAttributeToFilter('secondary_email',$username)
->getFirstItem();
//check we found customer record by secondary email
if ($customer->getId()) {
parent::authenticate($login,$customer->getEmail());
}
else {
parent::authenticate($username,$password)
}
}
I've not really looked into the above snippet, nor would I vouch for its security, but hopefully this demonstrates the process by which one can answer these types of questions using awareness of the framework. This may not be a bad starting point; with something similar in the configured class rewrite plus a setup script to add the secondary_email attribute, this should be quick to implement.
A note worth mentioning:
It's also possible to accomplish this by observing the runtime-constructed controller_action_predispatch_customer_account_loginpost event (see Mage_Core_Controller_Varien_Action::preDispatch()). While it is generally advisable to use the event observe system to effect functional rewrites when possible, this would be quite unintuitive and the messiest option of all.

Related

Laravel: check if two users are simultaneously logged in

I want to validate the use of coupons in my app by checking if both the business' owner and the final client are the ones redeeming the coupon. This would be the process:
Client shows his QR code
Owner scans it
Coupon is redeemed if both of them are logged in (this would happen when the Owner's device makes a post request and uses CouponController)
I know I can use auth() to validate the owner's status (he wouldn't be able to access the Redeem view when logged out anyway), but is there any way to check if the Client is also logged in without modifying the User row in the database? Right now, I use the following:
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
class LoginController extends Controller
{
...
public function store()
{
if( !auth()->attempt(request(['email','password'])) ){
return back()->withErrors([
'message' => 'Please check your credentials and try again.'
]);
}
$user = User::find(auth()->id());
$user->active = 1;
$user->save();
return redirect()->home();
}
Let's first clarify on how PHP scripts work and how that impacts your path to know if a user is online or not.
Under your Laravel application, for the very reasons on how PHP processes HTTP requests, you can only identify hits (requests), that you can interpret like heartbeats. So, you cannot (at least with bare PHP) see the user online all the time, but you can assume the user is there if the page hit was recently.
That said, it will be up-to-you what will be the acceptable time window to interpret if the user is online or not, once given a page hit/http request.
If you only record that the user is active (as a boolean/int flag like $user->active = 1) upon login, you will think the user is active even long after the user is gone from the application, as the user session may perfectly remain still active (open) but the user is actually inactive.
There are many ways to go around this.
One possible approach is to remember the last time a user hit your page, so you consider him online after the next -say- 5 minutes (this value is up to you). This approach is fair enough for what you are willing to achieve. Keeping this track can be achieved with middlewares, so your controllers are kept clean.
On how exactly implement this, well, that would be an entire and opinionated git project to post here and it's probably outside the scope of this answer. Long story short, think of keeping record of timestamps of the events you will consider relevant as user activity, instead of a flag with no timing information.
If you are willing to implement this as a usable feature with external packages, here are a few options:
https://github.com/highideas/laravel-users-online
https://github.com/thomastkim/laravel-online-users
https://github.com/joshrainwater/active-users
Even if you are not willing to pull in a third party package, feel free to dig in their sources (start on the Traits) to get some ideas on how to go around this.
You will also notice that some of them use Cache to keep track of disposable data without the need of storing this into your business ERD in database.
Hope this helps as a starting point.

Where do you put common data setters in DDD for update/insert?

I have a question regarding Domain Driven Design. Let's imagine a simple scenario.
I have an Entity called "User" that has some properties. One of these properties is "date_created", "date_modified" and "last_login_ip".
Let's say we have a form that creates a user and if the create is successful, it authenticates him.
The controller gets the POST data
Sends the post data to a UsersService via the method "createAndAuthenticateUser"
The service receives the data, validates it (doing it here and NOT in the entity because the validation is tied to repositories, such as to validate if the email already exists, etc).
If the validation is OK, it creates a new Entity, assigns the data to it and then sends the entity to the repository to save it. The repository then saves this user in a datasource.
So far so good. The problem here is that, the date_created/date_modified/last_login_ip have to be set in this service method.
What if I want to set the date_modified ANYTIME when the user object is updated (for instance,at login I want to update the date_modified, at user update i want it again, at user creation I want it again.
Logically, my own answer would be to put this in the repository like...
(meta code here sort of, the syntax doesn't matter)
function save($User) {
if (!$User->id) $User->date_created = 'YYYY-MM-DD HH:II:SS';
$User->date_modified = 'YYYY-MM-DD HH:II:SS';
$DataSource->Save($User);
return $User;
}
However, from what I've been reading, the repository should always just map data between the caller and the datasource (and the reverse) and that's it. It should never SET data or anything like that.
Of course, you could tell me this is a behavior, so I could have a behavior that says $User->markAsUpdated() which would just set the date_modified property. But again, this means that this method must be called from more than one place, instead of having a centralized place to do it. I don't see the benefit of NOT having this code in the repository.
Any ideas?
If the concept of last login ip is actually central to your user for some reason, then it's valid to update the user on login. The fact that you're expressing concern about performing that update to save the last login IP implies that it's not really a user concept, but a security, audit, or otherwise-external-to-user concept.
As for setting the modify and create dates, I'd make the same argument. If it's a requirement of the system that the user both maintain and expose that information, then create a private method on the user that each public method calls when it modifies the state, which will set the modify date. If it's not, then you pretty much have two options - either create an auditing service that is notified of the update and keeps its own audit record, or have the repository set the fields when it updates the record.

User permission and software security

I am developing an application in php codeigniter. Now I am worrried abt the permission.
I need page wise permission, page may be add records page, edit page, delete page and print report etc. There will be many users as well, and applicaiton will grow with passage of time.
If I implement ACL that will better for me or not
what can be ideal for me any suggestion.
First, let's clear up some terms: I personally use the security term for things like preventing SQL injection, XSS attacks, where we have to validate input, filter/sanitize values, take care of the dynamically generated SQL commands, take care of properly escaping output (for JSON or HTML text or HTML attributes), etc. This is not about what you are asking, if I understood well.
The access control or permissions system is where you give or deny access to a function for a user. It can be secure or not. I understand that to deny a user which does not have permission the access to a function may sound like "security", but I wouldn't use this specific word in this context, to avoid confusion.
Now, the answer:
I strongly recommend you create a few base controller classes to your needs. Read the following blog post carefully (it is short and useful): http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-base-Classes-Keeping-it-DRY
A code to check if the user is properly authenticated (logged in) is essential. If the user is not logged in, redirect to home page or login page.
For fine-grained control, you could create your ACL in the database using the users table, plus an actions table, plus an acl table...
The users table would contain the users data (id, name, login, password, etc)
The actions table would contain the id field and at least one more field containing what suits best for your application: it can be only the controller class name (the first part of the URL, for example: "products"), granting access to the whole "products" controller or not. Or you may want to include both the controller class AND the method name (the first and second parts of the URL, for example: "products/add" and "products/delete"), and so on.
To decide about the actions table is the most decisive step. Think very well about it, balance your needs (your "true" needs)... I developed a system where each and every action has its entry. It is good, but it needs work to be maintained.
A very useful column for the actions table is a human-readable description of the action.
The acl then would be nothing more than a column for the user id and another column for the action id.
A "master" grant/deny access field in the users table is useful too, in case you want to temporarily deny access from a specific user, without having to delete all his permissions and maybe having to restore it later.
With the database tables and your "controller/method" or "actions" strategy well defined, you can easily code in your base controller class a function which checks if the user have permission to execute the requested action.
This is the basic. In my system, I have the users administration interface, where I can grant/deny the actions for each user (I use an ExtJS tree with checkboxes). One of these actions is the own user management. I have gone one step further, where the user who can access the user management may "delegate" (grant/deny) to other users only the actions he himself has access to.
The system has several modules, and functions. The interface does not show anything the user does not have access. So, I have users who can see only a single or a couple of modules, and they don't even imagine the existence of the other modules.
It requires more work to manage all this, but the result worths.
I also log each granted access, so it is possible to track who did what, and when. This log feature is very very easy to add, since you have this base controller "master function" allowing or disallowing the users to perform the actions.
I hope I have helped. I've just shared a bit of what worked (and works) for me...

Best way to track the stages of a form across different controllers - $_GET or routing

I am in a bit of a dilemma about how best to handle the following situation. I have a long registration process on a site, where there are around 10 form sections to fill in. Some of these forms relate specifically to the user and their own personal data, while most of them relate to the user's pets - my current set up handles user specific forms in a User_Controller (e.g via methods like user/profile, user/household etc), and similarly the pet related forms are handled in a Pet_Controller (e.g pet/health). Whether or not all of these methods should be combined into a single Registration_Controller, I'm not sure - I'm open to any advice on that.
Anyway, my main issue is that I want to generate a progress bar which shows how far along in the registration process each user is. As the urls in each form section can potentially be mapping to different controllers, I'm trying to find a clean way to extract which stage a person is at in the overall process. I could just use the query string to pass a stage parameter with each request, e.g user/profile?stage=1. Another way to do it potentially is to use routing - e.g the urls for each section of the form could be set up to be registration/stage/1, registration/stage/2 - then i could just map these urls to the appropriate controller/method behind the scenes.
If this makes any sense at all, does anyone have any advice for me?
I think creating a SignupController is a fine idea. The initial user registration is a distinct process, and ought to be separate from general profile management tasks.
If you've been a good developer and keeping your controllers thin and your models fat, you ought to be able to avoid any code duplication. If you find yourself duplicating, it's probably a good idea to think about refactoring.
As a concrete example, consider your user's email address. Let's say you're pretty strict, and any time a user changes their email address, they have to do a little confirmation-email dance. During signup, you'll want the user to return to the signup process after they click their confirmation link. When an existing user is changing their email address, you'll want them to land somewhere else (like their profile). It's likely that you'll want different content in the body of the confirmation email is each case. Trying to make /user/profile handle both cases is going to start creating a bunch of complexity where the action needs to figure out context and behave accordingly.
The better solution is to decide that signup is it's own mode of interaction, distinct from general profile management. Therefore, it gets its own controller, which shares model and view resources with other controllers.
That's my take, anyway.

Best practices: how to implement an invitation system in Zend Framework?

I've built out most of the functionality, now I'm getting stuck...
I am creating a private, web application that has an invite only registration system. An admin user sends an email invitation to a user, the user clicks the link, and takes them to a page where they can create an account that has been linked to their email address.
When the form is submitted and does not have any validation errors, the data is inserted into the database for the first time. The email column of the invitations table is unique, so this is the token that the user needs in order to verify that they have permission to create an account.
The situation that I am confused about is when the admin user tries sending an invitation to the same email address. The email address column is unique so there is an SQL error. I don't know if I should do a check for that email address before inserting that record in the database, or what I should do.
I want to create a re-send invitation feature for emails that get lost, or accidentally deleted. Which is why I didn't want the admin user to be able to send a duplicate email to the same person, rather, they should use the re-send feature.
I hope this is all making sense. Any insights would be appreciated.
I use paper and pen to visualaize what I realy want. If the flow is clear I think you can make it ;)
I would definitely add a check to see if that address is already in the database before you attempt the insert. You could trap for the exception, but I would prefer to explicitly test for the presence of the email address.
An idea for you... When the email address already exists, you could make the system resend the invite. If you did that, you may be able to reduce some code repeat by not having to write an additional 'resend invite' function. Just call the same 'send invite' function on the initial invite request, or a 'resend invite' link described by others.
I also like the idea that others have already mentioned of the "Resend invite", especially philipnorton42's implementation.
I would use a validator inside your form, so the emailaddress is checked against your allready stored emails. So there should be no duplicate entry. Also i would implement an action that lists all your entered accounts and the creation- and activationtime in a nice table. Of course the action and view will support a pagination, so you can easy navigate through your data. If an entry has not yet been activated there should be a link, maybe an icon too, to a resend-the-email action for this special entry. And another action which resend the email to all not yet activated entries would be handy. Last but not least i would implement a reporting action so i can easily figure out whats going on.
I would say that Valter is correct, you perhaps need to draw out what you want to accomplish.
However, you appear (from what I can tell) to have all of the information in place for a "Resend invitation" button that the admin can click on to resend the invitation. I would create some reports in the backend that would allow me to view invitations that have been sent, that converted into users and that haven't been answered yet. Adding a button to the haven't answered yet report that resends individual invitations shouldn't be too hard.
Hum, i would create an view where all "Activations" are visible, with an button to just resend the invitation ? Without changing the record inside the database.

Categories