So, given that I have user table with a field of "is_confirmed", I want funnel anyone with an "is_confirmed" that is equal to 0 to a single url using the redirect...
Is there a way to do this check so that it only needs to be implemented once? I guess a good example would be the default user functionality of how any page that requires a logged-in user forces the user to the login page...
Haven't tried this specifically myself, but based on Yii's documentation one would probably redirect the user inside the login action based on the value. If the user is confirmed, call the CWebUser::login(..) method to store the identity in persistent storage and use the returnUrl redirect, otherwise the user is not confirmed so skip that part and just render the in limbo page.
Inside your SiteController::actionLogin() you'll probably do something like this (additionally the UserIdentity component should have a method for returning the value of the confirmation field)-
$identity = new UserIdentity();
if($identity->authenticate()) {
if($identity->isConfirmed() == 1) {
Yii::app()->user->login($identity);
$this->redirect(Yii::app()->user->returnUrl);
} else {
$this->render('not_yet_confirmed_view');
}
} else {
throw new CHttpException(500,'Internal Server Error. Could not authenticate.');
}
Edit- Removed the accidental extra CWebUser::login() and clarified that the UserIdentity component will require just a bit of additional smarts.
Related
I need help. How do I create profile visitors in Laravel 8? I have not written the code yet and I do not even have an idea how to complete this task. I would be very grateful if you could help me.
You can leave the visitor without any profile. He will be able to access public web pages without authentication and therefore only logged in users will have profile.
UPDATE
Proposed skeleton in two steps using cookies
1- When a user make request on profile page generate an unique identifier and store it in user cookie with a long enough validity if it not yet exists
2- Using this unique token register a new view count (if not yet done) before sending response to user.
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Requests;
use App\Http\Controllers\Controller;
public function getProfilePage(Request $request){
if(!Cookie::has('uniqueId')){
$uniqueId = Str::uuid(); // generate unique id for current user
Cookie::queue('uniqueId', $uniqueId, [live time in minutes]);
// save it using Cookie::queue
// one year for example as live time
}
// check if view count already exists for $uniqueId
// and save it in a persistent way if not
// other stuff ....
return ....
}
If a customer lands on any page of the Shopify site (not Plus), with a referral parameter in GET (?ref=something), how can this value be carried over to the checkout and order confirmation pages, where the domain is different?
One idea I had was to set a cookie on our domain, and then modify URL one navigates to upon clicking Checkout to include the values of the cookies, but I am unsure if this is the cleanest way, and where the best place to modify the URL would be.
I see that _ga parameter appears to be included automatically, in checkout URL. How can this be done for custom GET parameters?
One is the tricky way for doing this by modifying the checkout URL before submitting.
For doing this on your cart.liquid file find the form with action="/cart" and add attribute:
onsubmit="update_action(this)"
And add the javascript code at the bottom of your theme.liquid file :
<script type="text/javascript">
function update_action(form){
var new_action;
var some_value = "something";
var form_action = form.action;
if( (form_action.indexOf("?") >= 0) ) {
if(form_action.indexOf("ref")>=0) {
new_action = form_action.replaceAt(form_action.indexOf("ref"),"ref="+some_value);
}else{
new_action = form_action+"&ref="+some_value;
}
}else{
new_action = form_action+"?ref="+some_value;
}
$(form).attr("action",new_action);
}
</script>
Hope this will solve your problem.
Note that the ref and landing page are automatically stored by Shopify, meaning without you doing anything, you get those values in the order placed by the customer. You do not have manually manipulate them as per this thread.
Why do you need the value on checkout (you can do nothing with it anyway) and why on the order confirmation where again, it serves no purpose for the customer?
I want to implement a mechanism to obfuscate the id fields in my application . Right now all the id fields are integers. I want to use some sort of reversible hashing to create random strings corresponding to the id fields. Also, I am trying to accomplish this with minimal changes to the overall project.
One thing that came to my mind was to write a middleware to intercept every request and response object and check for the presence of id field. If the request contains id field and it is an obfuscated version, decode the string and replace the request parameter with the integer id.
If the response contains the integer id, run the encode function on it to send the obfuscated id to the client.
The problem I am facing is with modifying the req object. The id field can be present in req.body or req.params or res.query. However, in the middleware, I cannot see the id field when it is present in req.params.
I tried using policies. But the problem I am facing there is even after changing the req.params, the changes are lost when the control reaches the controller. What would be the recommended way of solving this problem ?
Here is the sample code:
In the policy:
module.exports = function (req, res, next) {
req.params.id = '12345';
req.query.pageSize = 30;
req.body = {};
sails.log.info('req.params', req.params);
sails.log.info('req.query', req.query);
sails.log.info('req.body', req.body);
return next();
};
I am just modifying values of req.params, req.query and req.body.
When I try to access these values in the controller, the values of req.query and req.body are the modified values as changed in the policy. However, req.params changes back to what was sent by the client and the changes made in the policy are lost
I think you are confusing policy and middleware? Is your code above in api/policies? If so, you still need to define which controller(s) this policy is applied to in config/policies.
So config/policies.js should look like:
modue.exports.policies = {
// If you really want this policy for every controller and action
'*': 'policyName.js',
// If you want it for a specific controller. '*' denotes every action in controller
specificController: {
'*': 'policyName.js'
},
// If you want it for a specific action on a specific controller
specificController: {
'specificAction': 'policyName.js'
}
};
Also I'd like to add. Policies are generally meant for authorization of controllers but this seems like a decent use case. Since every single request is not going to have these fields this should be a policy. Policies are great when applying something to a handful of controllers/actions. Middleware is great when you need to apply to every single action that comes into your app.
http://sailsjs.org/documentation/concepts/policies
http://sailsjs.org/documentation/concepts/middleware
Gitter response:
sgress454 #sgress454 10:45
#mandeepm91
In the policy, if I change req.body or req.query, the changes persist in the next policy or controller. However, changes made to req.params are lost.
This is one of the main use cases for req.options. This object is intended to be used to store request data that can be mutated by one handler before being passed on to the next. The req.params object is meant to provide each handler with a copy of the original request parameters.
How you approach this really depends on what your goal is. If you really need each request handler (that is, policies and controller actions) to see an encoded version of the ID, then a good approach would be to encode the ID in a policy as #S-Stephen suggested, store that value in req.options.id and refer to that in your other request handlers. If, on the other hand, you're really only concerned with the response having the encoded ID, the suggested practice is to use the res.ok() response in your handlers (rather than res.send() or res.json), and adjust the code for that response in api/responses/ok.js to encode the ID before sending. You can also use a custom response if this is only required for certain requests. See custom responses for more info.
Hi #sadlerw, you should be able to modify the code for res.ok() in your api/responses/ok.js file to have it always return JSON if that's what you want for every response. If it's something you only want for certain actions, you could create a custom response instead and use that where appropriate.
My user login with database is set up following this guide: http://www.bsourcecode.com/yiiframework2/yii-2-user-login-from-database/
Now my question is: how to implement last login feature so that every time user logs in, the appropriate database field is updated with current time?
I've set up rules in user model and also tried Timestamp Behavior, but no luck.
Thanks in advance!
Ended up using the login function where assigning date to user model was piece of cake.
$user->logintime = new Expression('NOW()');
$user->save();
The problem earlier was that I tried to implement it in the action of User model rather than in login form.
Simple way to make it happen is in your login method just add touch
function login(){
// check login
if(//login true)
{
$user = User::findIdentity(Yii::$app->user->id);
$user->touch('lastlogin_at'); // Datatable column name that you want to update the time.
}
}
See more about touch() over here
I have a table driven by DataTables 1.10. Filtering is turned on. When I talk about "doing a search" below, I'm talking about using the filtering function of this table.
Description of the Problem
Everything works fine with stateSave off. However, when stateSave is on, the following happens:
Alice logs in as admin. Because admin has all privileges, when she does a search through articles, she can see all articles. Because some articles are published and some are unpublished the table has a column that show which are published and which are not. So far so good.
Bob, a random user, accesses the site. Random users cannot ever see unpublished articles so the table hides the column that shows publication status. So far so good.
Alice logs out. She now accesses the site like a random user. So she should see exactly what Bob sees. However, when she does a search she still sees the column that indicates publication status.
(Note: The issue I'm discussing here is purely one of user interface. The server ensures that unprivileged users cannot ever get a record for an unpublished article. The problem though is that the additional column gives unpriviledged users information that they do not need. They can only see published articles in their search so they don't need to see that every article they get in a search is published.)
The code that configures the datatable hides the publication column by doing something like this:
var columnDefs = [];
if (!privileged) {
columnDefs.push({
targets: [1],
orderable: false,
visible: false
});
}
columnDefs is passed to DataTables as the columnDefs option.
Technical Reason for the Problem
The problem is that DataTables store things like column visibility into the state it saves into localStorage. So when Alice logs out and makes a search again as an unprivileged user, even though the value of columnDefs is correct, it is overwritten by the saved state. That state was stored when Alice was an admin, and it declared the publication column to be visible, so it remains visible even when Alice is accessing the site as an unprivileged user.
What I want is for users to benefit from the saved state but avoid having this state carry over when the user's privileges change.
Caveats:
I don't want to use sessionStorage because I want the state to persist between browser closings, but sessionStorage is cleared when the browser is closed.
I cannot use the session cookie assigned by the server to detect logins and logouts because it is HTTP only. Besides, privileges could change for other reasons.
I do not want to arbitrarily set an expiration time on the saved state.
The solution I've settled on is to use an additional field in the saved data to know when the conditions I care about have changed. This is a field whose value changes depending on the privileges that the user currently has. For instance, because in the case I described here, I decide to hide or show a column on the basis of a variable named priviledged (which is initialized from data provided by the server), it could be as simple as:
var token = privileged;
Then I set stateSaveParams to record the token when the state is saved:
stateSaveParams: function (settings, data) {
data.myapp_token = token;
}
The prefix myapp_ is just there to avoid possible collisions with DataTable's own fields.
I set stateLoadParams so that if the current value of token differs from what has been recorded before, the state is cleared:
stateLoadParams: function (settings, data) {
if (data.myapp_token !== token) {
this.api().state.clear(); // Clears the state.
return false; // Tells DataTables to not use the state that was stored.
}
// This return is here to keep the IDE happy but does not do anything special.
return undefined;
},
I've just set token to the single condition I've shown in my question (privileged) in this example but in production I use a combination of variables plus a local version number so I can bump the value of token as needed if I do something that requires clearing the state but cannot be detected just as a privilege change.