tenzil

tenzil

hi @danschultzer I am planning on adding a referral code in Login form, i generated the templates and added referral_code as text field, in the generated registration form. I have few doubts with the custom controllers
(The ask is): I want to add this referral code only on registration controller, in a transactional way. if code given , then i check presence of code and finally create user. If code not given, i directly create user.
I use pow_assent. I have read about invitation extension but i want to go with my own.

Doubts:

  1. I want to modify only create action of registration controller. Do i need to modify the routes as well?
  2. Do i need to add all action for both registration, session controllers and point their routes as mentioned in Custom controllers — Pow v1.0.11.
  3. Is there a way to overwrite only create action of registration controller?

First 10 of 28 Posts Switch mode

danschultzer

danschultzer

Pow Core Team

How do you want to verify and use the referral code during registration? You can set up a changeset as described in the Creating custom controller callbacks with Pow - #2 by danschultzer thread. It describes how to check for an association only when the user is created.

Yeah, but you only need to override that single route:

  scope "/", MyAppWeb do
    resources "/registration", RegistrationController, singleton: true, only: [:create]
  end

  scope "/" do
    pow_routes()
  end

No.

See above.

Alternatively you can set up a custom context:

defmodule MyApp.Users do
  use Pow.Ecto.Context,
    repo: MyApp.Repo,
    user: MyApp.Users.User

  def create(params) do
    case verify_referral_code(params) do
      {:ok, _any}         -> pow_create(params)
      {:error, changeset} -> {:error, changeset}
    end
  end

  # ...
end

If the referral code is also used in the PowAssent callback phase then you would need to do this for the user identities context too.

AlchemistCamp

AlchemistCamp

Is there a generator for Contexts (or Controllers, for that matter)? I actually just posted a related question on Spec about this a few hours ago!

danschultzer

danschultzer

Pow Core Team

No, but the context modules are minimal since they use macros. It’s done this way so you only have to override the methods that you want custom logic for, and let Pow handle the rest. The callbacks should be used as reference for what to override.

As for controllers, I think it’s best to let developers decide the design rather than having a generator set it up. You only need to use Pow.Plug methods, Pow controllers are extremely thin. There is a guide in the docs that shows how to set up custom controllers: Custom controllers — Pow v1.0.15

In PowAssent it’s more complex though.

I set up Pow and PowAssent and got a new Phoenix app running locally with email and Github login. After creating account with email and a password, I logged out and then tried an Oauth login via a Github account. That Github account is also under the same email address. Rather than logging me in or maybe asking me to verify my existing password, it asks for another email to link to the Github auth (which seems like a bad idea).

We had a discussion about this recently on Github. TLDR; it works like this for security, but the UX would be much better (as you wrote) if the user had the option to auth themselves to link up the provider instead of selecting another user id or having to exit the flow and sign in first. I plan to look into this as soon as I got free time for it.

AlchemistCamp

AlchemistCamp

Basically the main thing I was looking for was a way to get whatever the Auth provider sends back in its callback so I could parse it and deal with it. That’s what I’m currently doing with Ueberauth.

AlchemistCamp

AlchemistCamp

One other question. Is there a way to generate the context for users or see what’s in pow_user_fields()?

I’d like a way to get the equivalent of Accounts.list_users() or Accounts.get_user!(57) and to have a module to add more related logic.

Can we add fields to the Pow User schema? I’ve looked through the guide on Github and I’m trying to figure out how to use Pow in the context of a larger app.

danschultzer

danschultzer

Pow Core Team

What info is it you want to retrieve and what do you want to do with it after? FYI Assent is what’s used under the hood as the low level multi provider framework, while PowAssent handles the Phoenix/Plug/Ecto integration. The PowAssent callback controller action sends along the info to the context and changeset.

It’s described in the docs: Pow.Ecto.Schema — Pow v1.0.15

Just do what you normally would do in a Phoenix app and create the context module yourself :smile: It’s the idea of the custom context module in Pow, it works the same way as what you usually do in Phoenix/Ecto. No magic, it’s the same as you would do without Pow.

Yep, works the same way as without Pow: Pow.Ecto.Schema — Pow v1.0.15

pow_user_fields/0 could be replaced with the appropriate field macro calls. It’s just a helper to ease integration and development.

You might also be interested in seeing how you can store the access token with PowAssent: Capture access token — PowAssent v0.4.5

AlchemistCamp

AlchemistCamp

Thanks for all the answers! This is really helpful.

Since I don’t like typing boilerplate, I normally use built-in Phoenix generators and then add and/or customize as needed :innocent:

For this very simple app, I just want to get the authenticated user’s email, avatar image and name. I’ll use the email to determine whether or not an account already exists or not (as explained in my original question). Then, I’ll use the name and avatar_url to update their User record.

For other apps, I might want to inspect the contents of what the Auth provider sends back and use other details from struct.

danschultzer

danschultzer

Pow Core Team

In that case mix phx.gen.context Users User users --no-schema will suffice :smile:

Setting name and avatar should only happen on registration, or every time the user auths?

The first is easiest (basically what’s in the readme):

defmodule MyApp.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema
  use PowAssent.Ecto.Schema

  schema "users" do
    field :name, :string
    field :picture, :string

    pow_user_fields()

    timestamps()
  end

  def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do
    user_or_changeset
    |> Ecto.Changeset.cast(attrs, [:picture, :name])
    |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs)
  end
end

The second you would also need a custom context module to trigger when upserting the user identity, so the name/avatar gets updated on each auth request:

defmodule MyApp.UserIdentities do
  use PowAssent.Ecto.UserIdentities.Context,
    repo: MyApp.Repo,
    user: MyApp.Users.User

  def upsert(user, user_identity_params) do
    MyApp.Repo.transaction fn ->
      case pow_upsert(user, user_identity_params) do
        {:ok, user}     -> update_user(user, user_identity_params)
        {:error, error} -> {:error, error}
      end
    end
  end

  defp update_user(user, user_identity_params) do
    user
    |> MyApp.Users.User.changeset(user_identity_params)
    |> MyApp.Repo.update()
  end
end

If you use the second, you have to remember to update the changeset so it casts :picture and :name, since user_identity_changeset only triggers when a user is created. You can also cast it right there in the context method.

Remember to add user_identities_context: MyApp.UserIdentities to the config.

Assent conforms the result to OpenID Connect Core 1.0 Standard Claims spec for all strategies (why for Github it’s picture instead of avatar_url). You can inspect the values in custom changeset or context if it’s only for dev purpose.

AlchemistCamp

AlchemistCamp

This generates a Context file where every function raises “TODO”. It’s better than nothing at all generated, but certainly not as good as the default experience with Phoenix generators.

A more typical use case would probably involve some fields on the user, so it would probably make sense to have an example of a mix phx.gen.html (or api) where there’s at least one field on the user to see how it interacts with Pow. (I’ll write one such example myself once I understand how everything works and figure out a nice flow!)

This was useful in getting a handle with which to inspect the incoming data. However, adding it also causes my (new Phoenix) app to crash entirely on Github auth because PowAssent.RegistrationView isn’t available.

Here’s my entire User.ex:

defmodule MyApp.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema
  use PowAssent.Ecto.Schema

  schema "users" do
    pow_user_fields()

    timestamps()
  end

  def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do
    user_or_changeset
    |> Ecto.Changeset.cast(attrs, [])
    |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs)
  end
end

I saw your comments on this thread so I tried making some changes in my router but with no success thus far. Other than the addition of the one protected route, “/secret”, it’s just a fresh install plus what the PowAssent “getting started” section advised. Here’s the relevant portion of it:

scope "/" do
  pipe_through :skip_csrf_protection

  pow_assent_authorization_post_callback_routes()
end

scope "/" do
  pipe_through [:browser]
  pow_routes()
  pow_assent_routes()
end

scope "/", MyAppWeb do
  pipe_through [:browser]

  scope "secret" do
    pipe_through [:protected]
    get "/", PageController, :secret
  end

  get "/", PageController, :index
end
danschultzer

danschultzer

Pow Core Team

Oh right, forgot that the Phoenix generator just adds todo stubs when no schema will be generated. I don’t think it’s flexible enough to use the existing schema module.

Can you share the stack trace? PowAssent routes are scoped with PowAssent.Phoenix module, so I can only think of some invalid route setup that causes this. Your routes and schema looks right though.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement