1

I have a webapp where a user can log in and see a dashboard with some data. I'm using APIary for mock data and in my Postgres Database each of my users have an ID. These ID's are also used in the APIary JSON file with relevant information.

I'm using REST::Client and JSON to connect so for example the url for the user's dashboard is: "/user/dashboard/12345" (in Apiary) and in the database there is a user with the ID "12345".

How can I make it so when the user logs in, their ID is used to pull the data that is relevant to them? (/user/dashboard/{id})? Any documentation or advice would be much appreciated!

vanilla_splsh
  • 153
  • 1
  • 12
  • Is your web app built around Dancer? Have you written a DBIx::Class schema for your database? – Borodin May 14 '15 at 11:28
  • @Borodin yes! I use Dancer2 and yes I've written a DBIx::Class schema for the db – vanilla_splsh May 14 '15 at 12:58
  • Okay, well it seems to me that the synopsis in [the documentation for `Dancer2::Plugin::DBIC`](https://metacpan.org/pod/Dancer2::Plugin::DBIC) is very close to what you need. Have you looked there? – Borodin May 14 '15 at 15:15
  • @Borodin In that example, the route would require my ID yes? That's how it's getting the `user_id`? But in my case it's just a user logging in (I use Dancer2::Plugin::Auth::Extensible), the url has no extra params on it (it's just `get '/' => sub { ...` ). Unless there's a way where once a user logs in the url get the ID as a param? – vanilla_splsh May 14 '15 at 16:07

2 Answers2

1

The docs of Dancer2::Plugin::Auth::Extensible are showing one part of what you need to do already. In short, save the user ID in the session. I took part of code in the doc and added the session.

post '/login' => sub {
    my ($success, $realm) = authenticate_user(
        params->{username}, params->{password}
    );
    if ($success) {
        #  we are saving your user ID to the session here
        session logged_in_user => params->{username};
        session logged_in_user_realm => $realm;
    } else {
        # authentication failed
    }
};

get '/dashboard' => sub {
    my $client = REST::Client->new();

    # ... and now we use the user ID from the session to get the
    # from the webservice

    $client->GET( $apiary . '/user/dashboard/' . session('logged_in_user') );
    my $data = $client->responseContent();

    # do stuff with $data
}; 
simbabque
  • 53,749
  • 8
  • 73
  • 136
  • I'm confused with the "we are saving your user ID to the session here" part - do I add params ->{id} as well? And the `'/user/dashboard/' . session('logged_in_user')` part, i'd change to whatever the id is? Sorry if these are all silly questions ! – vanilla_splsh May 15 '15 at 16:30
  • There are no silly questions, we are all here to learn. :-) You can save the id to the session. The username was just the example from the documentation. `session "logged_in_user" => params->{id}` would work just the same. In the route handler you can use it to append it to the request to the api like I showed. I also suggest you go to irc.perl.org and check out #dancer there. The community is great and the maintainers are nice people that take time to answer your questions. :-) – simbabque May 15 '15 at 20:49
  • Thank you @simbabque! I tried this but still getting an error :( `Use of uninitialized value in concatenation (.) or string` and also `Route exception: malformed JSON string, neither tag, array, object, number, string or atom, at character offset 0 (before " \n – vanilla_splsh May 17 '15 at 19:03
  • @scz What line is the error on? Check what variable you used there. It means you have used a variable that you did not declare with `my`. Did you maybe just copy my example verbatim without adapting the variable names? The other one is from the json conversion because you try to convert HTML to json but it expects a perl data structure. It's a route exception because it stops Dancer from finishing delivery of the page while in the route handler. – simbabque May 17 '15 at 19:24
  • I've added my code above. It may have something to do with the fact I've put the Rest::Client code in a subroutine as I'm planning to have more routes with more URLs so I thought it easier to put in a sub. The error is around the "logged_in_user_id" – vanilla_splsh May 17 '15 at 20:13
  • @scz was there a `params->{user_id}` available when you logged in the user/saved to the session? It looks like that one is `undef`. Furthermore, you are putting stuff in `$content` but you never use that variable. Your route handler for `/` returns a template if `$user` exists, but if it doesn't something else happens. Because there is no other `return` statement, it will implicitly return the last true statement, which in this case is the return value of the `$content .= '...'` line. That is probably not what you are expecting. You should put that in a template file, not in the controller. – simbabque May 17 '15 at 21:12
  • yeah the `$content` stuff was temporary. As for `params->{user_id}` it's something I added. So I added the `user_id` column to the schema and some values, what would I do next? – vanilla_splsh May 17 '15 at 21:23
  • If you put the `user_id` into the database, did you also have that as a parameter that is collected from the form? The `params` keyword gives you your `POST` parameters. If that's from the schema based on the `username` from `POST` you would have to fetch it first. – simbabque May 17 '15 at 21:39
  • oh of course! No the id is not being collected from the form, that makes sense, I was confused about the params there. How would I go about fetching it? Each user has a username, password and id. – vanilla_splsh May 17 '15 at 21:44
  • Since you have the DBIC plugin you have the `schema` keyword. You can do something like `schema->resultset('User')->find(params->{username})->{user_id}` where you do the login after it's verified. I'm assuming the username is the primary key in your user table and the able is called _User_. That will give you the *user_id* of the record with that *username*. I would also ask a conceptual question at this point: why do you have a name and an ID? If they use the username to log in, it is already unique and an identifier. No need for a redundant second identifier. – simbabque May 17 '15 at 21:52
  • good point - in the system I'm planning to link this to each of the user's data has an ID which is why I did that. Would've been easier to just have the username be the identifier though. Also in this case my username isn't the primary key - but this makes sense so thank you so much for your help. – vanilla_splsh May 18 '15 at 09:49
  • sorry to drag you back in - is there a way to use schema keyword without the primary key? In my case I just put an ID as a primary key which isn't used in the login form obviously. Or is making my username a PK my best option? – vanilla_splsh May 19 '15 at 10:51
  • You should make the username the PK because it's already unique. Also, for new questions just open a new question in SO please. – simbabque May 19 '15 at 11:18
0

For those who want to know what I ended up doing:

Dancer2::Plugin::Auth::Extensible has

$user = logged_in_user();

When I printed this it showed me a hash of all the values that user had in the database including the additional ID I had. So I accessed the id with

my $user_id = $user->{user_id};

And appended $user_id to the end of the url!

vanilla_splsh
  • 153
  • 1
  • 12