Add captcha to support requests
This commit is contained in:
parent
a9a65adb8c
commit
a1dcc36dab
4 changed files with 69 additions and 4 deletions
32
lib/recycledcloud/captcha.ex
Normal file
32
lib/recycledcloud/captcha.ex
Normal file
|
@ -0,0 +1,32 @@
|
|||
defmodule RecycledCloud.Captcha do
|
||||
# We can't use a graphical-only captcha library such as
|
||||
# https://hex.pm/packages/captcha since it would break accessibility for
|
||||
# blind people. Let's make it simple maths instead!
|
||||
|
||||
def validate(changeset, expected_result) do
|
||||
captcha_result = Ecto.Changeset.get_field(changeset, :captcha)
|
||||
if captcha_result == expected_result do
|
||||
changeset
|
||||
else
|
||||
Ecto.Changeset.add_error(changeset, :captcha, "does not match")
|
||||
end
|
||||
end
|
||||
|
||||
def generate do
|
||||
terms = 1..6
|
||||
operands = ["+", "-", "*"]
|
||||
|
||||
left = terms |> Enum.random
|
||||
right = terms |> Enum.random
|
||||
operation = operands |> Enum.random
|
||||
|
||||
text = "#{left} #{operation} #{right}"
|
||||
value = case operation do
|
||||
"+" -> left + right
|
||||
"-" -> left - right
|
||||
"*" -> left * right
|
||||
end
|
||||
|
||||
{text, value}
|
||||
end
|
||||
end
|
|
@ -5,19 +5,24 @@ defmodule RecycledCloud.SupportRequest do
|
|||
|
||||
alias RecycledCloud.SupportRequest
|
||||
alias RecycledCloud.Mailer
|
||||
alias RecycledCloud.Captcha
|
||||
|
||||
embedded_schema do
|
||||
field :name, :string
|
||||
field :email, :string
|
||||
field :message, :string
|
||||
field :captcha, :integer
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
def changeset(key, attrs) do
|
||||
expected_captcha_result = attrs |> Map.get("expected_captcha")
|
||||
|
||||
key
|
||||
|> cast(attrs, [:name, :email, :message])
|
||||
|> validate_required([:name, :email, :message])
|
||||
|> cast(attrs, [:name, :email, :message, :captcha])
|
||||
|> validate_required([:name, :email, :message, :captcha])
|
||||
|> Captcha.validate(expected_captcha_result)
|
||||
end
|
||||
|
||||
def send(%SupportRequest{} = request) do
|
||||
|
|
|
@ -2,18 +2,26 @@ defmodule RecycledCloudWeb.SupportController do
|
|||
use RecycledCloudWeb, :controller
|
||||
|
||||
alias RecycledCloud.SupportRequest
|
||||
alias RecycledCloud.Captcha
|
||||
|
||||
def new(conn, _params) do
|
||||
{captcha_text, captcha_result} = Captcha.generate()
|
||||
|
||||
conn
|
||||
|> assign(:request_changeset, SupportRequest.changeset(%SupportRequest{}, %{}))
|
||||
|> assign(:captcha, captcha_text)
|
||||
|> put_session(:captcha, captcha_result)
|
||||
|> render("new.html")
|
||||
end
|
||||
|
||||
def create(conn, %{"support_request" => request} = params) do
|
||||
action = SupportRequest.changeset(%SupportRequest{}, request)
|
||||
def create(conn, %{"support_request" => raw} = params) do
|
||||
attrs = raw |> Map.put("expected_captcha", get_session(conn, :captcha))
|
||||
action = SupportRequest.changeset(%SupportRequest{}, attrs)
|
||||
|> Ecto.Changeset.apply_action(:update)
|
||||
|
||||
case action do
|
||||
{:ok, request} ->
|
||||
# FIXME: check for error?
|
||||
SupportRequest.send(request)
|
||||
|
||||
conn
|
||||
|
@ -21,8 +29,12 @@ defmodule RecycledCloudWeb.SupportController do
|
|||
|> redirect(to: Routes.page_path(conn, :index))
|
||||
|
||||
{:error, changeset} ->
|
||||
{captcha_text, captcha_result} = Captcha.generate()
|
||||
|
||||
conn
|
||||
|> assign(:request_changeset, changeset)
|
||||
|> assign(:captcha, captcha_text)
|
||||
|> put_session(:captcha, captcha_result)
|
||||
|> render("new.html")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,22 @@
|
|||
<%= textarea f, :message, placeholder: "Your message" %>
|
||||
<%= error_tag f, :message %>
|
||||
|
||||
<br />
|
||||
|
||||
<p>
|
||||
Can you answer the following expression to confirm that you are not basic
|
||||
robot?
|
||||
|
||||
<br />
|
||||
|
||||
<b><%= @captcha %> = </b>
|
||||
|
||||
<%= text_input f, :captcha, placeholder: "Captcha" %>
|
||||
<%= error_tag f, :captcha %>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<div>
|
||||
<%= submit "Send" %>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue