lml / fine_print

Rails gem for managing web site agreements (terms, privacy policy, etc).
MIT License
38 stars 18 forks source link

401 When loading FinePrint contracts. #29

Open ediewoelfle opened 5 years ago

ediewoelfle commented 5 years ago

When I create a new account (using devise), I am greeted with a broken webpage and the following error.

Account Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('Account') AND "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 6], ["LIMIT", 1]]

FinePrint::Contract Load (1.4ms) SELECT "fine_print_contracts".* FROM "fine_print_contracts" INNER JOIN "fine_print_contracts" "same_names_fine_print_contracts" ON "same_names_fine_print_contracts"."name" = "fine_print_contracts"."name" WHERE ("fine_print_contracts"."version" IS NOT NULL) AND "fine_print_contracts"."name" IN ('privacy', 'terms') GROUP BY "fine_print_contracts"."id" HAVING "fine_print_contracts"."version" = max("same_names_fine_print_contracts"."version") ORDER BY "fine_print_contracts"."name" ASC, "fine_print_contracts"."version" DESC

FinePrint::Contract Load (1.0ms) SELECT "fine_print_contracts".* FROM "fine_print_contracts" INNER JOIN "fine_print_contracts" "same_names_fine_print_contracts" ON "same_names_fine_print_contracts"."name" = "fine_print_contracts"."name" INNER JOIN "fine_print_signatures" ON "fine_print_signatures"."contract_id" = "fine_print_contracts"."id" WHERE ("fine_print_contracts"."version" IS NOT NULL) AND "fine_print_contracts"."name" IN ('privacy', 'terms') AND "fine_print_signatures"."user_id" = $1 AND "fine_print_signatures"."user_type" = $2 GROUP BY "fine_print_contracts"."id" HAVING "fine_print_contracts"."version" = max("same_names_fine_print_contracts"."version") ORDER BY "fine_print_contracts"."name" ASC, "fine_print_contracts"."version" DESC [["user_id", 6], ["user_type", "User"]]

method=GET path=/ format=html controller=DashboardController action=index status=302 duration=10.24 view=0.00 db=2.59 location=http://localhost:3000/fine_print/contracts/1/signatures/new method=GET path=/fine_print/contracts/1/signatures/new format=html controller=FinePrint::SignaturesController action=new status=401 duration=0.76 view=0.00 db=0.00

If I attempt to login in another account, I am able to see my contracts, however, when I accept them, it reminds me that I have already agreed and won't let me proceed. The only thing that gets me through is clearing my cache.

FinePrint is being used for my Privacy Policy and Terms. I require users to have "signed" these prior to entering into the dashboard:

dashboard_controller.rb

class DashboardController < ApplicationController
  before_action :load_resource
  before_action :authenticate_user!
  fine_print_require :all
end

fine_print.rb

FinePrint.configure do |config|

  # Engine Configuration: Must be set in an initializer

  # Layout to be used for FinePrint's controllers
  # Default: 'application'
  config.layout = 'fine_print'

  # Array of custom helpers for FinePrint's controllers
  # Default: [] (no custom helpers)
  config.helpers = []

  # Proc called with a controller as self. Returns the current user.
  # Default: lambda { current_user }
  config.current_user_proc = lambda { current_user }

  # Proc called with a user as argument and a controller as self.
  # This proc is called when a user tries to access FinePrint's controllers.
  # Should raise and exception, render or redirect unless the user is a manager
  # or admin. Contract managers can create and edit agreements and terminate
  # accepted agreements. The default renders 403 Forbidden for all users.
  # Note: Proc must account for nil users, if current_user_proc returns nil.
  # Default: lambda { |user| head(:forbidden) }
  config.authenticate_manager_proc = lambda { |user| user&.is_admin? ? true : head(:forbidden) }

  # Proc called with a user as argument and a controller as self.
  # This proc is called before FinePrint determines if contracts need to be
  # signed. If it returns true, FinePrint will proceed with its checks and
  # potentially call the redirect_to_contracts_proc with the user as argument.
  # If it returns false, renders or redirects, FinePrint will stop its checks.
  # Note that returning false will allow the user to proceed without signing
  # contracts, unless another before_filter renders or redirects (to a login
  # page, for example). The default renders 401 Unauthorized for nil users and
  # checks all others for contracts to be signed.
  # Default: lambda { |user| !user.nil? || head(:unauthorized) }
  config.authenticate_user_proc = lambda { |user| !user.nil? || \
                                              head(:unauthorized) }

  # Controller Configuration
  # Can be set in this initializer or passed as options to `fine_print_require`

  # Proc called with a user and an array of contracts as arguments and a
  # controller as self. This proc is called when a user tries to access a
  # resource protected by FinePrint, but has not signed all the required
  # contracts. Should redirect the user, render or raise an exception.
  # The `contracts` argument contains the contracts that need to be signed.
  # The default redirects users to FinePrint's contract signing views.
  # The `fine_print_return` method can be used to return from this redirect.
  # Default: lambda { |user, contracts|
  #            redirect_to(fine_print.new_contract_signature_path(
  #              contract_id: contracts.first.id
  #            ))
  #          }
  config.redirect_to_contracts_proc = lambda { |user, contracts|
    redirect_to(
      fine_print.new_contract_signature_path(contract_id: contracts.first.id)
    )
  }

  # Proc called whenever a contract is published, useful if the application
  # needs to hook into this event and take some action
  config.contract_published_proc = lambda { |contract| }

end

Here are my two contracts on my local:

#<FinePrint::Contract id: 1, name: "privacy", version: 1, title: "Privacy Policy", content: "privacy", created_at: "2018-12-29 22:12:40", updated_at: "2018-12-29 22:12:45">
#<FinePrint::Contract id: 2, name: "terms", version: 1, title: "Terms & Conditions", content: "terns", created_at: "2018-12-29 22:12:55", updated_at: "2018-12-29 22:12:59">

Is anyone else getting this issue or have a work-around?

malachaifrazier commented 5 years ago

Have you found a fix for this yet?

jpslav commented 5 years ago

I think all the query stuff in your output is ok. FinePrint is loading the user Account (id 6), then finding the privacy and terms contracts, then looking for signatures for those contracts for user 6. Then it probably isn't finding signatures which is why it 302 redirects to the new signature page.

The broken web page is probably from the last GET request is returning a 401 status (unauthorized). That in turn is likely due to this line from your fine print config:

config.authenticate_user_proc = lambda { |user| !user.nil? || head(:unauthorized) }

user is likely nil, which will give a 401 head response. (You could also change the head(:unauthorized) to do something like redirect_to my_special_path.) The user field should be coming from this other line in your fine print config:

config.current_user_proc = lambda { current_user }

i.e. from current_user. I'd recommend putting a debugger breakpoint in these lambdas to see if the value of current_user and later user are valid, and if not, then you can move in the direction of figuring out why they are not. You can also poke around in the console in the middle of this flow to see if there are signatures in the database.