I'd like to set it so when a user visits the application with a telephone number in the URL Grails directs the user to the specified profile, for example:
localhost:8080/Application/profile/07871216969 -> /user/show/User.findByUserTelephone(07871216969)
or preferably
localhost:8080/Application/07871216969 -> /user/show/User.findByUserTelephone(07871216969)
However, I have no idea how to reference the telephone number in the URL when calling the findByUserTelephone closure; I've noticed something like:
/profile/$telephoneNumber however I'm not entirely sure how that works out.
Also, as the /user/show action requires an id in the parameters I am not sure if the findUserByTelephone closure is any use as it returns the User as an object, and I can't seem to either getId() or .id the object to retrieve the id.
SOLVED/SOLUTION:
I solved this by creating another action in the Controller called profile, this action then had code similar to the following:
def profile = {
if(User.findByUserTelephone(params.userTelephone)) {
def userInstance = User.findByUserTelephone(params.userTelephone)
if (!userInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])}"
redirect(action: "list")
}
else {
[userInstance: userInstance]
}
} else {
render("Sorry, that user wasn't found in our database.")
}
}
I then created the following UrlMapping entry:
`"/$userTelephone"(controller: "user", action: "profile")`
Thus, when a user enters a telephone number into the system (or any string after the /) it will route the user to the user/profile action, which will attempt to find a user by their telephone number. If successful, will show the users details otherwise will show an error message.
It will probably save you some headaches later if you use a url path which is not the same as a controller name. So if you have something like:
"/p/$phoneNumber"(controller:profile, action:show)
you won't have any URL patterns that match multiple URLMapping entries which can get a little confusing. I would guess that just:
"/$phoneNumber"(controller:profile, action:show)
would work, but I would expect to end up in situations where Grails gets confused by multiple URLMappings matching the same request path unless you're very careful.
Related
I'm building a twitter-ish website and I'm having a problem with routing:
this code will bring the user to the profile page of the person with the given id.
Route::get('/profile/{id}', 'ProfileController#show')->name('profile.show');
this code will bring the user to the profile page of the person with the given username.
Route::get('/profile/{username}', 'ProfileController#show')->name('profile.show');
and finally, this code will bring the user to the profile page of the person with the given email.
Route::get('/profile/{email}', 'ProfileController#show')->name('profile.show');
I mean all these three URLs will show the user the same page:
example.com/profile/1
example.com/profile/rahimi0151
example.com/profile/rahimi0151#gmail.com
my question is:
is there a way to merge all these routes? like below:
Route::get('/profile/{id|username|email}', 'ProfileController#show')->name('profile.show');
Am not sure about merging the routes but you could write your route like this
Route::get('/profile/{identifier}', 'ProfileController#show')->name('profile.show');
and then change the method signature for show in ProfileController to something like this
public function show($identifier) {
if (is_numeric($identifier)) {
// do something
} else if ($this->isEmail($identifier)) {
// do something
} else {
// assume it is a username, and do something with that
}
}
// method to check if value provided is an email
// preferably, move this to a file of your custom helper functions
private function isEmail($value) {
// check if value is an email
// and return true/false indicating whether value is an email
}
And here is a link for a good way on how to check if a value is valid email address
I'm using orchardcms 1.9 (no tag created jet). I am writing a custom module that implements its own controller that calles a service wich check some information and based on the service response I either redirect or let the user stay on the page.
The module is on the default layer in other words it is on everypage. So when user tries to log in or register this module checks information normally.
This is my route:
new RouteDescriptor {
Priority = -1,
Route = new Route(
"{*path}", // this is the name of the page url
new RouteValueDictionary {
{"area", "modulename"}, // this is the name of your module
{"controller", "controllername"},
{"action", "Redirect"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "modulename"} // this is the name of your module
},
new MvcRouteHandler())
and this is my controller:
public ActionResult Redirect()
{
String response = _authService.VerifyRegistration(_orchardServices.WorkContext.CurrentUser);
if (response.Equals("2"))
{
Response.Redirect("~/Registration");
}
else if (response.Equals("3"))
{
Response.Redirect("~/Users/Account/LogOn");
}
return View();
}
What happens is that when I go to registration or login controller triggers, checks the infromation, says no redirect needed then returns view. But because the view is empty my page is blank instead of its default login/registration form.
How can I solve this? Am I making a mistake in routing that I somehow override the default view (I tried different priorities but same response).
Your route overrides all routes ({*path}. So when you redirect, you redirect to....your redirector I guess. Therefore the view you are rendering is the one for your controller, not the page you were after.
Whatever the logic flaw - this is not a good way to globally control authorization type scenarios on your site. If you meant to have a single page that people might go to (e.g. http://www.mysite/welcome) then your problem is that your route is too global. However, if, as your code suggests that you want to create a "all pages" check to see if you should go to login or register, then you should implement an authorization filter. An example of an authorization filter (for a slightly different purpose) can be found at https://stackoverflow.com/a/30377097/1638254 . You are looking to fill in the OnAuthorization method with suitable code to redirect the user (or let them through
I am new to grails. I have recently used session in my controller. But for only one page. Now I want to use session for a number of pages. But I have no idea how to do it. Here is my code below which works for one page. Can anyone please help me on this ?
def index() {
def user = springSecurityService.currentUser
if (user){
redirect(controller: 'admistratorAction', action: 'createUser')
}else{
redirect(controller: 'login', action: 'index')
}
}
You may be new to Grails, I hope you are not new to HttpSession. :)
Session information is scoped only to the current web application
(ServletContext), so information stored in one context will not be
directly visible in another.
As long as you are in the same ServletContext you should be able to access session variable directly. Also look at Servlet API in grails.
#Alidad- Scroll back to last question from OP.
In that case you can take advantage of grails filter to do the check before execution of each action. As dmahapatro mentioned you can use session across your app to store user object and with this filter you can do a check before any action.
Something like this can help you achieve it.:
class SecurityFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
if (!session.user)) {
redirect(action: 'login')
return false
}
}
}
}
}
I'm new in Symfony and I have a problem with logical code organisation.
The problem is connected with cache and different version of webpage for guests, logged in users and owner.
For example. I have 'user' module, which has 'show' action, and the URL is /user/show/:id and URL is the same for every visitor. But the content of the page depends on visitor and is selected with 'if' conditions so... If I clear the cache and the first visitor is guest, then others (including owner and logged in users) will see the guest's cached page.
Some kind of solution can be separating each view (owner, guest, logged in user) to partial, but it's against the DRY rule.
How to do this?
You can use the sf_cache_key parameter. See here how. I think you could use the user_id for logged in user, prepended with an arbitrary string for the owner, and for the guests, the string "guest" would do.
A bit of pseudo-code to help you further:
$sf_cache_key = '';
if ($visitor->isLogged())
{
if ($visitor->getId() == $userId )
{
$sf_cache_key = 'owner' . $userId;
}
else
{
$sf_cache_key = 'logged_in' . $userId;
}
}
else
{
$sf_cache_key = 'guest' . $userId;
}
I'm sure you solved this by now, and the app is already upgraded to the latest version. But I solved a similar problem generically by including a filter that sets a user-specific parameter in every URL preventing the data leak. This destroys reporting in GA, which is my current problem.
// Filter class in apps/frontend/lib/accessFilter.class.php
<?php
class accessFilter extends sfFilter
{
public function execute($filterChain)
{
$context = $this->getContext();
$context->getRouting()->setDefaultParameter('sw_user_id', $user_id);
$filterChain->execute();
}
}
// Filter definition in apps/frontend/config/filters.yml
# insert your own filters here
accessFilter:
class: accessFilter
// Use within routes in apps/frontend/config/routing.yml
dashboard:
url: /dashboard/:sw_user_id/home
param: { module: dashboard, action: index }
I'm using the layout support (sitemesh) in Grails which works fine. I'd like to adjust my layout to have it depend on whether or not a user is logged in or not.
My grails-app/views/layouts/main.gsp contains the following code:
<g:if test="${user}">
Username: ${user.username}
</g:if>
However, it appears as if the layout-GSP:s are unable to access the model and hence the user variable (I get a "No session" exception when trying). What would be the recommended way to make my layout depend on whether or not a user is logged in or not?
Thanks in advance!
I would suggest to use either the request or the session scope for that purpose. Probably the most DRY way is to populate the scope is a filter. For example in the file grails-app/conf/SecurityFilters.groovy (you'll need to create it):
class SecurityFilters {
def filters = {
populateCurrentUser(controller: '*', action: '*') {
before = {
request.user = User.get(session.userId)
}
}
}
}
The example assumes that you store the id of the current user in the session attribute "userId" and that you have a Domain class "User". Using it in the layout is as simple as this:
<g:if test="${request.user}">
Current User: ${request.user.username}
</g:if>