MVC user's full name in Url, how to handle duplicates - asp.net-mvc-4

I want to setup the following url in my MVC4 website, using the user's full name in the url:
http://www.myapp.com/profile/steve-jones
I have setup the following route in Global.asax:
routeCollection.MapRoute(
"profile", "profile/{userName}",
new { controller = "myController", action = "profile", userName = string.Empty
});
And I can take the parameter 'steve-jones' and match it to a user with matching name. My only problem though is, what if there is more than one 'Steve Jones', how can I handle this?
Does anyone know of a workaround/solution to this so that I can use a user's full name as part of the url and still be able to retrieve the correct user in the controller method?
Am I forced into including the user's id with the url (something that I do not want to appear)?

The usual way of handling this is by appending a number when creating the profiles. So if "steve-jones" is already a name in the database, then make the user's display name "steve-jones2". You basically have to insist that all profile urls are unique, which includes updating any existing database and account creation code.
Alternatively (and/or additionally), if two same names are found then have the script reroute to a disambiguation page where the user is presented with links and snippet of profile info of the many existing Steve Joneseses so they can go to the full correct profile.
Another way of handling it is by giving all user profiles an additional numeric code on the end. At my university all logins are based on name, so they give everyone pseudo-random 3-digit extensions so that they are safe as long as they don't get 1000 people with the exact same names :)
Some people might be happier being steve-jones-342 if there is no steve-jones or steve-jones1, if you're concerned.

Related

Basecamp 3 API : How to get comments created by the authorized user?

I am in the process of integrating my webapp with Basecamp 2 (solved, see edit) and 3, and I want to get all of the comments for a todo item for the authorized user.
First I make a call to https://launchpad.37signals.com/authorization.json which returns json that includes the user's identity, something like {"identity":{"id":99999999, ..... }}.
Then I make a call to the URL to get the comments for the item in question and go through them one by one matching the identity.id from above (99999999) with the creator.id for the comment.
The problem is, they don't match! I am working with one Basecamp2 project and one Basecamp3 project. When testing, using comments I wrote, Basecamp2 and Basecamp3 each have different values for creator.id (even though I wrote both comments!), and neither of them match the identity.id from authorization.json.
How do I link them to find which comments were made by the authorized user
Thanks
EDIT: I figured it out for Basecamp2 - I need to get /people.json which has a mapping from the identity_id of each user to the id for that user in that project. Still not sure how to do it for Basecamp3, which does not include identity_id in people.json!
The correct way to do this for Basecamp2 is to get:
https://basecamp.com/{project_id}/api/v1/people/me.json - the id node contains the id of the authorized user for project {project_id}.
for Basecamp3:
https://3.basecampapi.com/{project_id}/my/profile.json - the id node contains the id of the authorized user for project {project_id}.

Show logged in user's case details in IBM Case Manager

I am creating a Healthcare solution in IBM Case Manager Case Builder. I have a role called 'Patient'. I would like to show the case details of the patient when they log in. Is there any way I can show the case details when the patient logs in.
I have another role called 'Doctor', who can view the case details of any patient by clicking the link in the row of the list of returned search results on searching the patient. However, on the patient side, there is no search and they have to see their case details as soon as they log in.
If someone could point me in the right direction regarding this, I would really appreciate it.
Thanks in advance.
Allright, i guess there are many ways to accomplish this, but having thought about it a few minutes, here's a suggestion.
a. Create a script-adapter on the landing page (Case Manager page).
While it would be more intuitive to connect to the ecm.moel.desktop.onLogin event, the onLogin is within the navigator scope, and we need to be sure that ICM was started because we need to acces role info / ICM api. By using a scriptadapter on the landing page, we not only ensure the ICM context/api is loaded, but we'll also be able to use the ICM api to retrieve a case, and open it...
b. In the script adapter, do your role check; this can be done through:
var role = ecm.model.desktop.currentRole.name; (see this blog)
c. If the role is patient, find out the case(id's) you want to open; you might want to query using the ecm.model.SearchQuery or you could construct a pluginservice (see this redbook on services).
d. With the result of c, you'd then be able to open the case-page using the OpenCase event with a corresponding payload.
var caseId = "the id resulting from c.";
this.getSolution().retrieveCase(caseId, lang.hitch(this, function(caseFolder) {
this.onBroadcastEvent ('icm.OpenCase', {
"caseEditable": caseFolder.createEditable(),
"coordination": new icm.util.Coordination()
});
});

#auth.requires_permission not working ver 2

Good day to all web2py experts!
I can't find a way on how to use the web2py Decorators
#auth.requires_permission('read','person')
def f(): ....
in the pdf manual it says that:
prevents visitors from accessing the function f unless the visitor is a member
of a group whose members have permissions to "read" records of table
"person". If the visitor is not logged in, the visitor gets directed to a login
page (provided by default by web2py). web2py also supports components,
i.e. actions which can be loaded in a view and interact with the visitor via
Ajax without re-loading the entire page. This is done via a LOAD helper which
allows very modular design of applications; it is discussed in chapter 3 in the
context of the wiki and, in some detail, in the last chapter of this book.
This 5th edition of the book describes web2py 2.4.1 and later versions
In my case:
I have list of groups: Admin_Tier_1, Admin_Tier_2, Admin_Tier_3
Admin_Tier_1 - has the highest authority to access all features like adding a school year, set a school year etc.
Admin_Tier_2 - has the authority to add students etc
Admin_Tier_3 - its the lowest level of authority that can only add fines to the students (Organization Officers)
now I use the Decorator code like this:
#auth.requires_permission('Admin_Tier_1','student_list')
def add(): ....
now I login the account of the Chairman which registered in the auth_membership as Admin_Tier_1. Then I click the link "List of Students" which redirect to add(): function but the system returned a message:
Not Authorized
Insufficient privileges
The auth.requires() method can take a callable rather than a boolean value as the condition, and this is preferable when it is expensive to generate the boolean value (otherwise, the boolean value is generated whenever the controller is accessed, even if the particular decorated function is not the one being called). So, to avoid calling auth.has_membership unnecessarily, you can do:
#auth.requires(lambda: auth.has_membership('Admin_Tier_1') or
auth.has_membership('Admin_Tier_2'))
Now the two auth.has_membership calls will only be made when the actual function being decorated is called.
Also, if you need to check a larger number of roles, you can do something like:
#auth.requires(lambda: any([auth.has_membership(r) for r in ['list', 'of', 'roles']))
Problem solved:
#auth.requires(auth.has_membership('Admin_Tier_1') or auth.has_membership('Admin_Tier_2'))
source here.
Whenever I access the page if the user belong to the group of Admin_Tier_3 the system block the acess and redirect it to "/default/user/not_authorized" page :)

What are the Aweber API Variables $account_id and $list_id?

You can check here:
https://labs.aweber.com/docs/code_samples/subs/create
The script to add a new subscriber to the list via api requires those two pieces info...only I cannot figure out for the life of me what those two variables are!! I've beaten through every little aspect of my Aweber Subscriber Account, AND my Aweber Labs account...and I can't find any reference to either of those variables anywhere. I've submitted some tickets to them, and haven't gotten any response yet.
Does anyone have any ideas here? I've tried my account names, my list names, to no avail!
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Okay, I've got it! You can get the values of both of these variables by dumping some other variables in the aweber api after making certain api calls.
get the account id first:
$account = $aweber->getAccount($accessKey, $accessSecret);
then vardump or print_r $account.
next we get the list id:
$account = $aweber->getAccount($accessKey, $accessSecret);
$list_url = 'https://api.aweber.com/1.0/accounts/<id>/lists';
$lists = $account->loadFromUrl($list_url);
then vardump or print_r $lists.
And you are all set! I'm so happy I figured this out, it freakin took long enough. Hopefully this saves some one a bit of time.
I too have agonized over finding the $list_ID, so went to deactivate the list, and create a new one, and "discovered" that if you hover over the Deactivate button, you get a url you can copy, and this gives both %account and %list Ids
https://www.aweber.com/users/lists/deactivate/$accountID/$lisID
like this....
https://www.aweber.com/users/lists/deactivate/123456/123456
Hopefully this will help make someone as it is a super easy solution
The proper answer is Anne Allen's one, but...
Check the return of the /accounts endpoint. It should return the same account id as you detected in the link, but I had cases they were different (strange, isn't it?). Use the account id returned by the /accounts endpoint and other endpoints to retrieve lists, subscribers, etc. will start to work. It's like if some accounts have two ids, one partially works and the other fully works.
Let me tell you how to get $list_id value... login into your AWeber account and then create a new list copy only integer value from list's name.
At first, login.
1) click Reports>Settings. Your account ID will be displayed in the box,example: ?id=XXXXX
2) click List Options>List Settings. There you will see the list ID under the name.
p.s. To add subscriber, you can use this - Automatically add into aweber list

How about using URI path variables for an HTTP POST?

I've searched a lot but I couldn't find the proper answer to my question regarding my conditions.
I'm building a REST API, and the case, which seems a border line case to me, is the following:
-I'm dealing with two entities, Users and Roles. An User can have multiple roles assigned.
-To assign a Role to a User, the Role must be already in the DataBase.
-To assign a Role to a User, the only thing needed is the 'code' of the role, that is a short string.
-The uri path template used now is:
--Users: localhost:8080/api/users
--Given User: localhost:8080/api/users/{userId}
--Roles of a given User: localhost:8080/api/users/{userId}/roles
Now, to 'link' a given User with a given Role, two options come to my mind.
-The first is the one that sounds as best practice in any scenario, sending the post data in the body, perhaps as a JSON.
-The other one, sending it through the uri and with an empty body. For example, to link User with id U001 with role R001, one would have to post to the following uri sending no data in the body: localhost:8080/api/users/U001/roles/R001
The thing is that I don't mind using the first option, and it seems to be the best and most correct one, but in this particular case, I'm not sure wether it is better to send an almost empty body (because it only holds the role id, a very short string) posting it to 'localhost:8080/api/users/U001/roles' or skipping the body and just sending the role id through the uri as a path parameter like localhost:8080/api/users/U001/roles/R001
Thank you all in advance for your help.
There is nothing wrong with putting role in the URI. Your intuition was on the right track. I'd do it this way.
PUT: locahost:8080/api/users/{userid}/role/{roleId}
And here's why.
FIRST: The PUT verb is Idempotent. In other words (taken straight from the spec)
... the side-effects of N > 0 identical requests is the same as for a single request.
Which is what I'd assume you want in this regard. You don't want multiple records in your state storage for each instance of user & role. A user should feel at ease making the same PUT request without adversely effecting (adding duplicate records) the system.
When doing the same thing with a POST I'd expect to have a new record created for every request.
SECOND: The PUT verb is supposed to identify a specific resource. (taken straight from the spec)
... PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,
it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.
What if role R102 becomes obsolete and R104 is preferred? Return a 301 (Moved Permanently) with a HEADER (Location : localhost:8080/api/users/{userid}/role/R104).
FINALLY: When everything works well. Return a 201 (Created) when created and a 200 (No Content) on every subsequent request to the same URI. If they provide a Role that is not in the system return a 501 (Not Implemented).
Hmm - in this case - a POST with a 302 may be a bit messy.
Why not a very simple 'PUT'/'DELETE' with indeed the URIs suggested ?
With simple; 20X meaning succeeded, possibly some 30X to indicate it was already there - and anything else a fail ?