riverrun / openmaize

No longer maintained - was an Authentication library for Plug-based applications in Elixir
Other
206 stars 30 forks source link

Help: Change login module to accommodate RethinkDB #18

Closed driventv closed 8 years ago

driventv commented 8 years ago

Hey Riverrun,

First off, awesome package. The structure is easy to understand and integrate. I appreciate the good work. I am looking for some help. I am using RethinkDB with Phoenix and trying to use Openmaize. I got the signup working using RethinkDB-elixir and RethinkDB-ecto from hamiltonp which are some awesome packages as well. But, I am having trouble getting the login to work. The issue happens whenever the process hits the check_user function. I need to change out the SQL query for RethinkDB and change the other pipes to reflect this. I think there are some issues when it hits |> Config.repo.one

In the config, I have the repo set as: Appname.RethinkDB I have a module called Appname.RethinDB using RethinkDB.Ecto.Connection that handles the dirty work. Not all Ecto operations are supported, so I have to import RethinkDB.Query and use it for any queries instead of Ecto. So, I have to track down any areas of Openmaize that use Ecto queries (not insert, delete, or other basic CRUD actions as those are supported by the Ecto shim). I know this may not be enough, but is there any advice you can give me to swap out Postgres Ecto queries for RethinkDB? Thanks!!

riverrun commented 8 years ago

I've just updated to version 0.12, and this version contains the ability to use a custom database call to Openmaize.Login. The new module Openmaize.LoginTools show an example of how to define the function to query the database. What you need to do is define your own query function (with 3 arguments) and then call it when using Openmaize.Login, like this (imagining your function is called Tools.query_func):

plug Openmaize.Login, [database_call: &Tools.query_func/3] when action in [:login_user]

Let me know if you have any questions / problems.

driventv commented 8 years ago

Thats awesome, but I'm still a little fuzzy on how to use it. Would I just create my own module with the query to get the user and then pipe it back to the check_password function to continue the process? For instance:

plug Openmaize.Login, [database_call: &Database.find_user/3] when action in [:login_user]

def module Database do

alias Openmaize.Login

blah blah

def find_user do
{query}
|> check_password

What three parameters is the find_user/3 function expecting? Thank you for the help!

riverrun commented 8 years ago

If you're using :name to identify the user in the database, find_user expects :name and "name" as the first two arguments (if you're using :email, they would be :email and "email"). The third argument will be the following map - %{"name" => name, "password" => password} Your Database module would be something like:

defmodule Database do

  alias Openmaize.LoginTools

  def find_user(:name, "name", user_params) do
    %{"name" => name, "password" => password} = user_params
    rethink_query_func(name) # this needs to return a user model
    |> LoginTools.check_pass(password)
  end
end

And then in your controller file:

plug Openmaize.Login, [database_call: &Database.find_user/3] when action in [:login_user]

Let me know if you have any further questions.

driventv commented 8 years ago

So, I got it set up, but I am receiving an error when trying to log in. It is saying: no function clause matching in Userquery.find_user/3

Here is the output from the console: lib/App/userquery.ex:7: Userquery.find_user(:name, "name", %{"password" => "pass", "username" => "bob"})

I have this in my page_controller:

plug Openmaize.Login, [database_call: &Userquery.find_user/3] when action in [:login_user]

Here is my Userquery module:

    defmodule Userquery do

  alias Openmaize.LoginTools

  import RethinkDB.Query

  def find_user(:username, "username", user_params) do
    %{"username" => username, "password" => password} = user_params
    Query.table("users")
    |> Query.filter(%{username: username}) # this needs to return a user model
    |> LoginTools.check_pass(password)
  end
end
riverrun commented 8 years ago

In the |> Query.filter(%{username: username}) line, could you add |> IO.inspect to it (instead of the comment), and let me know what the output is? If you could me any other info about the error, that would be really helpful.

driventv commented 8 years ago

Thanks for all the help. Another question: The path for a user's profile is /profiles/show/:id, so how can I redirect to this upon login and /profiles/new upon registration? I know there are redirects in the openmaize config, but this goes beyond the examples. Thanks

riverrun commented 8 years ago

Ok, it will help people searching these issues if we close this one first. Then you can open a new issue about the redirects. Please give me a little more information about what you want to achieve.

riverrun commented 8 years ago

In the latest version in the master branch (and for versioin 0.13), I've changed this function to just cover the query, and I've changed the name of the option from database_call to query_function. The query_tools file will give you some idea of how it should now be written.

Your custom function needs to be called with two arguments - in your case it will be the username as the first argument and :username as the second argument. It then needs to return the user model (you don't have to include the check_pass call).

Sorry about making you change your code, but I think it makes more sense to restrict this function to just the query.

Let me know if you have any questions.