What is the correct way to setup a username in a route that then goes off to a controller 'profile' and an action of 'show'. Like the way facebook does: http://www.facebook.com/username
but... if the first part of the URL is not a username do the standard route mechanism.
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
Setting it up like this should work I would think. replicate/rename namedController to the controllers you actually have. A user named "namedController" in this example will never be shown, as non-dynamic token matches (the stuff between "/") has stronger precedence.
(And is also a logical idea, imo.)
"/namedController/$action?/$id?" (controller:"namedController")
"/$username" (controller:"profile", action:"show")
Related
Let's assume we have the following "Create User" scenario:
Users can signup to the application using Facebook, Google+ or LinkedIn;
The backend should retrieve some basic profile information in order to register the user(email, firstName and lastName);
Users are registered with a "client Id" (Just adding complexity to the business rule);
When a signup process is done the data should be sent to a notification topic.
I can imagine a create user request with the following structure:
{
"clientId": "someClientId",
"authProvider": "FACEBOOK | GOOGLE | LINKEDIN",
"accessToken": "someAccessToken"
}
So, thinking about the registration/validation flow we would have:
Check if the create user request is valid;
Check if the clientId is valid;
Try to retrieve the profile information from the social network api;
Check if all the required profile information is filled;
Check if the user exists in the database;
Register the user;
Send the data to the notification topic;
Pass the data to the presenter.
Jumping straight to the use case, we would have a constructor like:
CreateUserUseCase(
ApplicationClientGateway applicationClientGateway,
SocialNetworkGateway socialNetworkGateway,
UserGateway userGateway,
NotificationGateway notificationGateway,
Presenter presenter
)
and an execute method:
execute(CreateUserRequest request)
// validates the payload
// something like
if (request == null)
presenter.setError(someError);
// validates the clientId
applicationClientGateway.findById(request.getClientId())
// retrieves the profile information
// how to inject dinamically the implementation for
// Facebook, Google or LinkeIn based on a request parameter?
profile = socialNetworkGateway.findByAccessToken(request.getAccessToken());
// checks if the user exists
userGateway.findByEmailAndAuthProvider(profile.getEmail(), request.getAuthProvider());
//register the user
userGateway.insert(user);
//sends the notification
notificationGateway.send(user);
// sets the result
presenter.setResult(user);
Now, we have a constructor with lots of arguments(code smells?) and at least 5 validation steps in the execute method.
It looks like a violation of the SRP, so, how can we decompose this code in order to reduce complexity in the interactor?
First of all, lets break this in some small steps:
1) Related to the presenter, looks like you are intersted in give the workflow some output, right? Assuming that, maybe it will be better to return what you want from the usecase and handle this one layer above. (-1 parameter at constructor)
2) Like the others answers are saying, looks like your usecase has a LOT of responsabilities right now. I will suggest you to break this in more then one usecase.
Something like:
... Your first gateway (API)
..... ValidateClientId.execute();
..... profile = RetrieveProfile.execute();
..... InsertUser.execute(...)
3.1) Related to inject the correct bean based on the correct social network, you can handle this logic INSIDE the gateway, not before call it. Remembet that one gateway CAN call another gateway (they are at same layer). So, I suggest you to use something like.
At usercase -> socialNetworkGateway.findByAccessToken(...)
Inside the gateway you can do your "switch" and call somthing like the FacebookGateway, GoogleGateway, etc.
SRP does not say that you have to have small methods or only few constructor parameters. SRP says "there should be only a single reason to change the code".
As far as I can see you explicitly implemented the "business logic sequence" required to register a new user. Even though this may require some "external services" and/or repositories there is still only one reason to change the logic of this code: if the logic "how to register a user" changes.
From this perspective you are not violating SRP.
According to Uncle Bobs picture on "control flow" (https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) it is also totally correct to pass the presenter.
If you still feel the need to reduce the dependencies of your use case class I would suggest looking into "unit of work" pattern and check whether it would make sense to combine some of the dependencies.
More details on "What is a use case in Clean Architecture" you can find in my blog series: http://www.plainionist.net/Implementing-Clean-Architecture-UseCases/
So I’m looking to make some routes within my super cool can.js application. Aiming for something like this…
#!claims ClaimsController - lists claims
#!claims/:id ClaimController - views a single claim
#!claims/new ClaimController - creates a new claim
#!claims/:id/pdf - do nothing, the ClaimController will handle it
#!admin AdminController - loads my Administrative panel with menu
#!admin/users - do nothing, the AdminController will handle it
#!admin/settings - do nothing, the AdminController will handle it
So how might we do this?
“claims route”: function() { load('ClaimsController'); },
“claims/:id route”: function() { load('ClaimController'); },
“admin”: function() { load(‘AdminController’); },
Cool beans, we’re off. So what if someone sends a link to someone like...
http://myapp#!claims/1/pdf
Nothing happens! Ok, well let’s add the route.
“claims/:id/pdf route”: function() { load('ClaimController'); },
Great. Now that link works. Here, the router’s job is only to load the controller. The controller will recognize that the pdf action is wanted, and show the correct view.
So pretend I’ve loaded up a claim claims/:id and I edit one or two things. Then I click the Print Preview button to view the PDF and change my route to claims/:id/pdf.
What should happen… the Claim Controller is watching the route and shows the pdf view.
What actually happens… the router sees the change, matches the claims/:id/pdf route we added, and reloads the Claim Controller, displaying a fresh version of the claim pulled from the server/cache, losing my changes.
To try and define the problem, I need the router to identify when the route changes, what controller the route belongs to, and if the controller is already loaded, ignore it. But this is hard!
claims //
claims/:id // different controllers!
claims/:id //
claims/:id/pdf // same controller!
We could just bind on the "controller" change. So defining routes like can.route(':controller') and binding on :controller.
{can.route} controller
// or
can.route.bind('controller', function() {...})
But clicking on a claim (changing from ClaimsController to ClaimController) won't trigger, as the first token claim is the same in both cases.
Is there a convention I can lean on? Should I be specifying every single route in the app and checking if the controller is loaded? Are my preferred route urls just not working?
The following is how I setup routing in complex CanJS applications. You can see an example of this here.
First, do not use can.Control routes. It's an anti-pattern and will be removed in 3.0 for something like the ideas in this issue.
Instead you setup a routing app module that imports and sets up modules by convention similar to this which is used here.
I will explain how to setup a routing app module in a moment. But first, it's important to understand how can.route is different from how you are probably used to thinking of routing. Its difference makes it difficult to understand at first, but once you get it; you'll hopefully see how powerful and perfect it is for client-side routing.
Instead of thinking of urls, think of can.route's data. What is in can.route.attr(). For example, your URLs seem to have data like:
page - the primary area someone is dealing with
subpage - an optional secondary area within the page
id - the id of a type
For example, admin/users might want can.route.attr() to return:
{page: "admin", subpage: "users"}
And, claims/5 might translate into:
{page: "claims", id: "5"}
When I start building an application, I only use urls that look like #!page=admin&subpage=users and ignore the pretty routing until later. I build an application around state first and foremost.
Once I have the mental picture of the can.route.attr() data that encapsulates my application's state, I build a routing app module that listens to changes in can.route and sets up the right controls or components. Yours might look like:
can.route.bind("change", throttle(function(){
if( can.route.attr("page") == "admin" ) {
load("AdminController")
} else if(can.route.attr("page") === "claims" && can.route.attr("id") {
load("ClaimController")
} else if ( ... ) {
...
} else {
// by convention, load a controller for whatever page is
load(can.capitalize(can.route.attr("page")+"Controller")
}
}) );
Finally, after setting all of that up, I make my pretty routes map to my expected can.route.attr() values:
can.route(":page"); // for #!claims, #!admin
can.route("claims/new", {page: "claims", subpage: "new"});
can.route("claims/:id", {page: "claims"});
can.route("admin/:subpage",{page: "admin"});
By doing it this way, you keep your routes independent of rest of the application. Everything simply listens to changes in can.route's attributes. All your routing rules are maintained in one place.
I'd like for changes in the URL to drive my application, and for changes in the application to change the URL, but not actually change state.
I have a route like this. The country/city example is a bit contrived, hopefully that doesn't confuse things. The relationship in the real application is somewhat hierarchical. Child views don't seem a fit though because there's no need for nested views.
$stateProvider.state( 'viewMap', {
url: '/viewMap/:country/:city',
templateUrl: 'pages/viewMap/viewMap.html',
controller: 'ViewMapController'
};
In ViewMapController, I can construct the page based on $stateParams.country and .city. As these values change, my application reacts and I want the url to stay in sync. I don't want to reload the whole page, however. I just want to update the url and push a history state on to the stack.
I understand I could manually construct a string:
updateUrl = function() {
window.location.hash = '#/viewMap/'+ $stateParams.country +'/'+ $stateParams.city
}
This feels fragile, as the way I build the string is separate from the way the framework parses it. I would prefer for the framework to build me a string based on the current params, but $state.href('.') describes the current route, which doesn't include $stateParams that haven't yet been activated/navigated to.
I've also looked at reloadOnSearch, but I think it only applies to query params.
Is there a better way to model this? It feels like I'm fighting the framework over something simple.
You can pass state params to $state.href function to get the complete URL
$state.href('.', $stateParams)
To generate arbitrary urls you can pass non-current params and/or configuration:
$state.href('.', {country:'usa',city:'sf'}, {absolute:true})
i'm trying to control the session to forbid the access to some pages of my web app. The way is simple, a boolean session variable. The thing is there's one page for every action, but, i think is not elegant at all to ask in every action if the user is logged or not. How can i do this elegantly in a MVC architecture? It looks crappy this way. I was thinking that there is a parent action that redirects to the final one, the one that renders the page, is it right? maybe i could make the check there.
public function createAction(Request $request){
$sess = $this->getRequest()->getSession();
if ($sess->get('logged') == true) {
// ---- ACTION CODE GOES HERE ---- //
}
}
In Symfony2, if the sections of the site that need authorization are under the same path, you can use the access_control section in the security configuration:
# app/config/security.yml
security:
# ...
access_control:
- { path: ^/secured/area, roles: ROLE_USER }
You can find more ways to secure your app in the book
Let's say I'm building a web application whose user pages can be found at http://example.com/NAME. What's the best way to make sure the username doesn't conflict with a reserved word (e.g. 'about', 'contact', etc.)? I can think of two ways:
Maintain a list somewhere in my code. This is great and all, but means I have another piece of code I have to edit if I decide to, say, change the "about" page to "aboutus".
Request the URI (e.g. http://example.com/someusername) and check if it exists (doesn't return a 404). This feels kind of like a hack, but on the other hand it does exactly what it's supposed to do. On the other hand, I can't reserve anything without making a page for it.
What would be the best way to go about this? Manual validation of usernames is not an option. Thanks!
EDIT: I forgot to mention, the username has to go at the root, like this:
http://example.com/USERNAME
Not like this:
http://example.com/users/USERNAME
Hence why I'm asking this question. This is for technical reasons, don't ask.
I would strongly suggest using a unique path like http://example.com/users/NAME instead. Otherwise, what are you going to do if you want to add a reserved word, but a user has already taken it as their user name? You'll end up with all kinds of potential migration problems down the track.
Alternatively, if you must have something that goes straight off http://example.com/, could you possibly prefix all user names? So that user jerryjvl would translate to link http://example.com/user_jerryjvl?
If there is really no other possible solution, then I'd say either check user names against whatever data source determines what the 'reserved words' are, or make a lookup file / table / structure somewhere that contains all the reserved words.
In the interest of completeness, if you can't change the routing. Another possibility is to have your user routes and your non-user routes have a programmatic distinction. For example, if you appended a '_' to the end of each of your user routes, then you can make sure that users are located at: http://example.com/NAME_ and the other route would never end in '_'
How about changing your routing scheme so that users are at example.com/users/NAME ?
I maintain the reserved words inside the code.
This is the PERL code that I use in the http://postbit.com/ website to check if the usernamename is a reserved word:
# Black list of logins and sub-domains reserved keywords
my #black_list = qw(
about access account accounts add address adm admin administration
adult advertising affiliate affiliates ajax analytics android anon
anonymous api app apps archive atom auth authentication
...
);
my $username_normalized = lc($username);
$username_normalized =~ s/\W//gs; # 'log-in' -> 'login'
for my $this_username (#black_list) {
if ($username_normalized eq $this_username) {
die("This username is already taken. Please choose other username.\n");
}
}
The complete list of reserved names (like 'css', 'images', 'js', 'admin', 'root', 'old', 'test', 'www', 'admin', 'login', 'devel'...) with more than 300 login usernames is posted here:
http://blog.postbit.com/reserved-username-list.html
You only know what are these 'reserved' words. So better maintain a list and validate against it.
Another method will be if you use a CMS, then all these keywods 'about', 'contact' etc. will be there in your database. Validate against it.
Right next to the text box something like: "Please use your personal nickname or you real name. Usernames with common words indicating affiliation with the site administration may be revoked".
How about just create dummy accounts first with all the reserve words? just list all the possible ones and create them.
if you use
www.example.com/user/name
then there will be no problem but it seems like you'd like the URL to be short.
Maintain a list somewhere in my code. This is great and all, but means I have another piece of code I have to edit if I decide to, say, change the "about" page to "aboutus".
Your menus should be stored in an array/list. This way you would have only 1 piece of code to edit, not 2. =]
Then, since all menus are in one array, you can match username with elements in the array.
for example
$menu = array('About', 'Contact', 'Home')
if( in_array($username, $menu) ) {
echo 'invalid username'
}
You could always look and see how stackoverflow.com works.