Unify Google sign-in and registration flow
Some checks are pending
Quality / full-local-gates (push) Waiting to run

This commit is contained in:
SimpleTest 2026-07-21 20:49:13 +03:00
parent ff856f637f
commit 811ddf4c5c
15 changed files with 1993 additions and 977 deletions

View File

@ -819,6 +819,14 @@ defmodule WhoNeedHelp.Accounts do
UserNotifier.deliver_login_instructions(user, magic_link_url_fun.(encoded_token))
end
@doc "Delivers a one-time local-account verification link before connecting Google."
def deliver_google_link_instructions(%User{} = user, magic_link_url_fun)
when is_function(magic_link_url_fun, 1) do
{encoded_token, user_token} = UserToken.build_email_token(user, "login")
Repo.insert!(user_token)
UserNotifier.deliver_google_link_instructions(user, magic_link_url_fun.(encoded_token))
end
@doc """
Deletes the signed token with the given context.
"""

View File

@ -49,6 +49,21 @@ defmodule WhoNeedHelp.Accounts.UserNotifier do
end
end
@doc "Delivers instructions for verifying a local account before connecting Google sign-in."
def deliver_google_link_instructions(user, url) do
with_user_locale(user, fn ->
deliver(
user.email,
gettext("Confirm Google sign-in"),
gettext(
"Hi %{email},\n\nUse the secure link below to sign in and connect Google to your Who Need Help account:\n\n%{url}\n\nIf you did not request this, ignore this email. Google will not be connected.",
email: user.email,
url: url
)
)
end)
end
defp deliver_magic_link_instructions(user, url) do
with_user_locale(user, fn ->
deliver(

View File

@ -5,7 +5,7 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
alias WhoNeedHelp.{Accounts, GoogleAuth, Repo, Trust}
alias WhoNeedHelp.Trust.RateLimiter
alias WhoNeedHelpWeb.UserAuth
alias WhoNeedHelpWeb.{GoogleAuthPending, UserAuth}
import WhoNeedHelpWeb.UserAuth, only: [require_sudo_mode: 2]
@ -16,7 +16,12 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
plug :require_sudo_mode when action in [:start_link, :disconnect]
def start_login(conn, _params) do
start_flow(conn, "login", %{}, ~p"/users/log-in")
start_flow(
conn,
"login",
%{"locale" => Gettext.get_locale(WhoNeedHelpWeb.Gettext)},
~p"/users/log-in"
)
end
def start_registration(conn, %{"google_registration" => params}) when is_map(params) do
@ -70,6 +75,130 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
end
end
def complete(conn, _params) do
case GoogleAuthPending.fetch(conn) do
{:ok, pending} ->
case Accounts.get_user_by_email(pending.email) do
%Accounts.User{moderation_status: :suspended} ->
conn
|> GoogleAuthPending.delete()
|> google_account_unavailable(~p"/users/log-in")
existing_account ->
render(conn, :complete,
pending: pending,
existing_account: not is_nil(existing_account)
)
end
{:error, _reason} ->
conn
|> GoogleAuthPending.delete()
|> put_flash(:error, gettext("Google sign-in session expired. Please start again."))
|> redirect(to: ~p"/users/log-in")
end
end
def complete_registration(conn, %{"google_registration" => params}) when is_map(params) do
terms_accepted = params["terms_accepted"] in [true, "true", "on", "1"]
with true <- terms_accepted,
{:ok, pending} <- GoogleAuthPending.fetch(conn),
nil <- Accounts.get_user_by_email(pending.email),
{:ok, _limit} <- RateLimiter.check(:registration_email, pending.email),
{:ok, {user, _identity}} <-
Accounts.register_user_by_google(identity_attrs(pending), %{
"locale" => normalize_locale(params["locale"] || pending.locale),
"terms_accepted" => true
}) do
conn
|> GoogleAuthPending.delete()
|> put_flash(:info, gettext("Your account was created with Google."))
|> UserAuth.log_in_user(user)
else
false ->
conn
|> put_flash(
:error,
gettext("Confirm that you are 18 or older and accept the safety rules first.")
)
|> redirect(to: ~p"/auth/google/complete")
%Accounts.User{} ->
conn
|> put_flash(
:info,
gettext("This email already has an account. Confirm it once to connect Google.")
)
|> redirect(to: ~p"/auth/google/complete")
{:error, :rate_limited} ->
conn
|> put_flash(
:error,
gettext("Too many registration attempts in the configured time window.")
)
|> redirect(to: ~p"/auth/google/complete")
{:error, :missing} ->
expired_pending_redirect(conn)
{:error, :invalid_or_expired} ->
expired_pending_redirect(conn)
{:error, :email_already_registered} ->
conn
|> put_flash(
:info,
gettext("This email already has an account. Confirm it once to connect Google.")
)
|> redirect(to: ~p"/auth/google/complete")
{:error, _reason} ->
google_account_unavailable(conn, ~p"/users/log-in")
end
end
def complete_registration(conn, _params) do
conn
|> put_flash(:error, gettext("The Google registration form is invalid."))
|> redirect(to: ~p"/auth/google/complete")
end
def verify_existing(conn, _params) do
with {:ok, pending} <- GoogleAuthPending.fetch(conn),
%Accounts.User{moderation_status: status} = user when status != :suspended <-
Accounts.get_user_by_email(pending.email),
{:ok, pending_token} <- GoogleAuthPending.token(conn),
{:ok, _limit} <- RateLimiter.check(:magic_link_email, pending.email),
{:ok, _email} <- deliver_google_verification(conn, user, pending_token) do
conn
|> put_flash(
:info,
gettext(
"We sent a verification link to %{email}. Open it to finish connecting Google.",
email: pending.email
)
)
|> redirect(to: ~p"/users/log-in")
else
{:error, :rate_limited} ->
conn
|> put_flash(
:error,
gettext("Too many sign-in emails in the configured time window.")
)
|> redirect(to: ~p"/auth/google/complete")
{:error, reason} when reason in [:missing, :invalid_or_expired] ->
expired_pending_redirect(conn)
_missing_suspended_or_delivery_error ->
Logger.warning("Unable to send Google account verification instructions")
google_account_unavailable(conn, ~p"/users/log-in")
end
end
def callback(conn, params) do
flow = get_session(conn, @session_key)
conn = delete_session(conn, @session_key)
@ -130,7 +259,7 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
end
end
defp finish_flow(conn, "login", _flow, identity_attrs) do
defp finish_flow(conn, "login", flow, identity_attrs) do
case Accounts.login_user_by_google(identity_attrs) do
{:ok, user} ->
conn
@ -138,14 +267,10 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
|> UserAuth.log_in_user(user)
{:error, :not_linked} ->
conn
|> put_flash(
:error,
gettext(
"This Google account is not connected yet. Create an account or sign in by email and connect Google in account settings."
)
)
|> redirect(to: ~p"/users/log-in")
case GoogleAuthPending.put(conn, identity_attrs, flow_locale(flow)) do
{:ok, conn} -> redirect(conn, to: ~p"/auth/google/complete")
{:error, _reason} -> google_account_unavailable(conn, ~p"/users/log-in")
end
{:error, _reason} ->
google_account_unavailable(conn, ~p"/users/log-in")
@ -164,14 +289,18 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
|> UserAuth.log_in_user(user)
else
{:error, :email_already_registered} ->
conn
|> put_flash(
:error,
gettext(
"An account with this email already exists. Sign in by email or password, then connect Google in account settings."
)
)
|> redirect(to: ~p"/users/log-in")
case GoogleAuthPending.put(conn, identity_attrs, flow_locale(flow)) do
{:ok, conn} ->
conn
|> put_flash(
:info,
gettext("This email already has an account. Confirm it once to connect Google.")
)
|> redirect(to: ~p"/auth/google/complete")
{:error, _reason} ->
google_account_unavailable(conn, ~p"/users/log-in")
end
{:error, :rate_limited} ->
conn
@ -255,6 +384,22 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
|> redirect(to: failure_path(flow))
end
defp deliver_google_verification(conn, user, pending_token) do
login_url = url(conn, ~p"/users/log-in")
Accounts.deliver_google_link_instructions(
user,
&"#{login_url}?google_link=#{URI.encode_www_form(pending_token)}#token=#{URI.encode_www_form(&1)}"
)
end
defp expired_pending_redirect(conn) do
conn
|> GoogleAuthPending.delete()
|> put_flash(:error, gettext("Google sign-in session expired. Please start again."))
|> redirect(to: ~p"/users/log-in")
end
defp google_account_unavailable(conn, path) do
conn
|> put_flash(:error, gettext("This Google account cannot be used right now."))
@ -270,6 +415,12 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
defp normalize_locale(locale) when locale in @supported_locales, do: locale
defp normalize_locale(_locale), do: "en"
defp flow_locale(flow), do: normalize_locale(flow["locale"])
defp identity_attrs(pending) do
Map.take(pending, [:provider_uid, :email, :email_verified, :display_name])
end
defp error_name(error) when is_atom(error), do: Atom.to_string(error)
defp error_name(%{__struct__: module}), do: inspect(module)
defp error_name(_error), do: "unknown_error"

View File

@ -0,0 +1,5 @@
defmodule WhoNeedHelpWeb.GoogleAuthHTML do
use WhoNeedHelpWeb, :html
embed_templates "google_auth_html/*"
end

View File

@ -0,0 +1,103 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-md space-y-5">
<div class="text-center">
<.header>
{gettext("Continue with Google")}
<:subtitle>
{gettext("Google verified your identity. Finish this one-time step to continue.")}
</:subtitle>
</.header>
</div>
<div class="rounded-2xl border border-base-300 bg-base-100 p-4 shadow-sm">
<div class="flex items-center gap-3">
<span
class="flex size-10 items-center justify-center rounded-full bg-base-200"
aria-hidden="true"
>
<span class="text-lg font-bold text-brand">G</span>
</span>
<div class="min-w-0">
<p class="truncate font-semibold">{@pending.display_name}</p>
<p class="truncate text-sm text-base-content/65">{@pending.email}</p>
</div>
<span class="badge badge-success badge-outline ml-auto shrink-0">
{gettext("Verified")}
</span>
</div>
</div>
<%= if @existing_account do %>
<section class="space-y-4 rounded-2xl bg-base-200 p-5">
<div>
<h2 class="font-semibold">{gettext("This email already has an account")}</h2>
<p class="mt-2 text-sm text-base-content/70">
{gettext(
"Confirm access once so nobody can attach Google to your account using only a matching email address."
)}
</p>
</div>
<.form for={%{}} as={:google_verification} action={~p"/auth/google/verify-existing"}>
<.button class="btn btn-primary w-full" phx-disable-with={gettext("Sending...")}>
{gettext("Email me a verification link")} <span aria-hidden="true">→</span>
</.button>
</.form>
<.link navigate={~p"/users/log-in"} class="btn btn-ghost w-full">
{gettext("Use my password instead")}
</.link>
<p class="text-xs text-base-content/60">
{gettext("After this confirmation, future Google sign-ins will take one click.")}
</p>
</section>
<% else %>
<section class="space-y-4 rounded-2xl bg-base-200 p-5">
<div>
<h2 class="font-semibold">{gettext("Create your Who Need Help account")}</h2>
<p class="mt-2 text-sm text-base-content/70">
{gettext("No password is required. Google will be connected as your sign-in method.")}
</p>
</div>
<.form
for={%{}}
as={:google_registration}
action={~p"/auth/google/complete-registration"}
class="space-y-3"
>
<input type="hidden" name="google_registration[locale]" value={@pending.locale} />
<.input
type="checkbox"
id="google_completion_terms"
name="google_registration[terms_accepted]"
value="false"
label={gettext("I am 18 or older and accept the Terms and Safety Rules")}
required
/>
<p class="text-xs text-base-content/60">
{gettext("Read the")}
<.link href={~p"/terms"} class="link font-semibold">{gettext("Terms")}</.link>,
<.link href={~p"/privacy"} class="link font-semibold">{gettext("Privacy Policy")}</.link>
{gettext("and")}
<.link href={~p"/safety"} class="link font-semibold">{gettext("Safety Rules")}</.link>
{gettext("before confirming.")}
</p>
<.button
class="btn btn-primary w-full"
phx-disable-with={gettext("Creating account...")}
>
{gettext("Create account and continue")} <span aria-hidden="true">→</span>
</.button>
</.form>
</section>
<% end %>
<div class="text-center">
<.link href={~p"/users/log-in"} class="link text-sm">
{gettext("Cancel and use another sign-in method")}
</.link>
</div>
</div>
</Layouts.app>

View File

@ -5,16 +5,22 @@ defmodule WhoNeedHelpWeb.UserSessionController do
alias WhoNeedHelp.{Accounts, GoogleAuth}
alias WhoNeedHelp.Trust.RateLimiter
alias WhoNeedHelpWeb.UserAuth
alias WhoNeedHelpWeb.{GoogleAuthPending, UserAuth}
plug :assign_magic_link_form
plug :put_no_store
def new(conn, _params) do
email = get_in(conn.assigns, [:current_scope, Access.key(:user), Access.key(:email)])
def new(conn, params) do
conn = maybe_restore_pending_google(conn, params)
pending_google_email = pending_google_email(conn)
email =
get_in(conn.assigns, [:current_scope, Access.key(:user), Access.key(:email)]) ||
pending_google_email
form = Phoenix.Component.to_form(%{"email" => email}, as: "user")
render(conn, :new, form: form)
render(conn, :new, form: form, pending_google_email: pending_google_email)
end
# magic link login
@ -30,6 +36,7 @@ defmodule WhoNeedHelpWeb.UserSessionController do
{:ok, {user, _expired_tokens}} ->
conn
|> put_flash(:info, info)
|> maybe_connect_pending_google(user)
|> UserAuth.log_in_user(user, user_params)
{:error, :not_found} ->
@ -49,6 +56,7 @@ defmodule WhoNeedHelpWeb.UserSessionController do
if user = Accounts.get_user_by_email_and_password(email, password) do
conn
|> put_flash(:info, gettext("Welcome back!"))
|> maybe_connect_pending_google(user)
|> UserAuth.log_in_user(user, user_params)
else
invalid_password_response(conn, user_params)
@ -125,6 +133,48 @@ defmodule WhoNeedHelpWeb.UserSessionController do
|> render(:new, form: Phoenix.Component.to_form(user_params, as: "user"))
end
defp maybe_restore_pending_google(conn, %{"google_link" => token}) when is_binary(token) do
case GoogleAuthPending.restore(conn, token) do
{:ok, conn} -> conn
{:error, conn, _reason} -> conn
end
end
defp maybe_restore_pending_google(conn, _params), do: conn
defp pending_google_email(conn) do
case GoogleAuthPending.fetch(conn) do
{:ok, pending} -> pending.email
{:error, _reason} -> nil
end
end
defp maybe_connect_pending_google(conn, user) do
case GoogleAuthPending.connect(conn, user) do
{:ok, conn, _identity} ->
put_flash(
conn,
:info,
gettext("Google sign-in connected. You can use it next time.")
)
{:error, conn, :missing} ->
conn
{:error, conn, :invalid_or_expired} ->
conn
{:error, conn, _reason} ->
put_flash(
conn,
:error,
gettext(
"You are signed in, but Google could not be connected. Try again in account settings."
)
)
end
end
defp assign_magic_link_form(conn, _opts) do
conn
|> assign(
@ -132,6 +182,7 @@ defmodule WhoNeedHelpWeb.UserSessionController do
Phoenix.Component.to_form(%{"token" => ""}, as: "user")
)
|> assign(:google_auth_enabled, GoogleAuth.enabled?())
|> assign(:pending_google_email, pending_google_email(conn))
end
defp put_no_store(conn, _opts), do: put_resp_header(conn, "cache-control", "no-store")

View File

@ -71,7 +71,7 @@
id="google_login_form"
>
<.google_auth_button
label={gettext("Sign in with Google")}
label={gettext("Continue with Google")}
disabled={!@google_auth_enabled}
/>
<p :if={!@google_auth_enabled} class="mt-2 text-center text-xs text-base-content/55">
@ -81,6 +81,16 @@
<div :if={!@current_scope} class="divider">{gettext("or use email")}</div>
<p
:if={@pending_google_email && !@current_scope}
class="mb-4 rounded-2xl bg-base-200 p-4 text-sm text-base-content/70"
>
{gettext(
"Sign in to %{email} once to connect Google. You can use the email link or your existing password.",
email: @pending_google_email
)}
</p>
<.form :let={f} for={@form} as={:user} id="login_form_magic" action={~p"/users/log-in"}>
<.input
readonly={!!@current_scope}

View File

@ -0,0 +1,128 @@
defmodule WhoNeedHelpWeb.GoogleAuthPending do
@moduledoc false
import Plug.Conn
alias WhoNeedHelp.{Accounts, Repo, Trust}
@session_key "pending_google_identity"
@token_salt "pending-google-identity"
@max_age_seconds 15 * 60
@supported_locales ~w(en uk ru)
def put(conn, identity_attrs, locale \\ "en") do
with {:ok, payload} <- normalize(identity_attrs, locale) do
token = Phoenix.Token.sign(WhoNeedHelpWeb.Endpoint, @token_salt, payload)
{:ok, put_session(conn, @session_key, token)}
end
end
def fetch(conn) do
conn
|> get_session(@session_key)
|> verify_token()
end
def restore(conn, token) when is_binary(token) do
case verify_token(token) do
{:ok, _pending} -> {:ok, put_session(conn, @session_key, token)}
{:error, reason} -> {:error, conn, reason}
end
end
def restore(conn, _token), do: {:error, conn, :invalid}
def token(conn) do
case fetch(conn) do
{:ok, _pending} -> {:ok, get_session(conn, @session_key)}
{:error, reason} -> {:error, reason}
end
end
def delete(conn), do: delete_session(conn, @session_key)
def connect(conn, user) do
with {:ok, pending} <- fetch(conn),
true <- normalized_email(user.email) == pending.email,
{:ok, identity} <- connect_and_audit(user, pending) do
{:ok, delete(conn), identity}
else
false -> {:error, delete(conn), :email_mismatch}
{:error, reason} -> {:error, delete(conn), reason}
end
end
defp connect_and_audit(user, pending) do
Repo.transact(fn ->
with {:ok, identity} <- Accounts.link_google_identity(user, identity_attrs(pending)),
{:ok, _audit} <-
Trust.audit(
user.id,
"auth_identity.connected",
"auth_identity",
identity.id,
%{"provider" => "google", "method" => "verified_local_sign_in"}
) do
{:ok, identity}
end
end)
end
defp verify_token(token) when is_binary(token) do
with {:ok, payload} <-
Phoenix.Token.verify(WhoNeedHelpWeb.Endpoint, @token_salt, token,
max_age: @max_age_seconds
),
{:ok, pending} <- normalize(payload, value(payload, :locale)) do
{:ok, pending}
else
_invalid_or_expired -> {:error, :invalid_or_expired}
end
end
defp verify_token(_token), do: {:error, :missing}
defp normalize(attrs, locale) when is_map(attrs) do
provider_uid = value(attrs, :provider_uid)
email = value(attrs, :email)
email_verified = value(attrs, :email_verified)
display_name = value(attrs, :display_name)
cond do
email_verified != true ->
{:error, :invalid}
not is_binary(provider_uid) or provider_uid == "" or byte_size(provider_uid) > 255 ->
{:error, :invalid}
not is_binary(email) or email == "" or byte_size(email) > 160 ->
{:error, :invalid}
not is_binary(display_name) or String.trim(display_name) == "" ->
{:error, :invalid}
true ->
{:ok,
%{
provider_uid: provider_uid,
email: normalized_email(email),
email_verified: true,
display_name: display_name |> String.trim() |> String.slice(0, 80),
locale: normalize_locale(locale)
}}
end
end
defp normalize(_attrs, _locale), do: {:error, :invalid}
defp identity_attrs(pending) do
Map.take(pending, [:provider_uid, :email, :email_verified, :display_name])
end
defp value(attrs, key), do: Map.get(attrs, key) || Map.get(attrs, Atom.to_string(key))
defp normalized_email(email), do: email |> String.trim() |> String.downcase()
defp normalize_locale(locale) when locale in @supported_locales, do: locale
defp normalize_locale(_locale), do: "en"
end

View File

@ -120,6 +120,9 @@ defmodule WhoNeedHelpWeb.Router do
post "/users/register", UserRegistrationController, :create
post "/auth/google/login", GoogleAuthController, :start_login
post "/auth/google/register", GoogleAuthController, :start_registration
get "/auth/google/complete", GoogleAuthController, :complete
post "/auth/google/complete-registration", GoogleAuthController, :complete_registration
post "/auth/google/verify-existing", GoogleAuthController, :verify_existing
end
scope "/", WhoNeedHelpWeb do

View File

@ -529,7 +529,7 @@ msgstr ""
msgid "Confirm your email and ensure your account is active before publishing."
msgstr ""
#: lib/who_need_help/accounts/user_notifier.ex:70
#: lib/who_need_help/accounts/user_notifier.ex:85
#, elixir-autogen, elixir-format
msgid "Confirmation instructions"
msgstr ""
@ -637,8 +637,8 @@ msgid "Double-blind review"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:75
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:89
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:122
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:99
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:132
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:15
#, elixir-autogen, elixir-format
msgid "Email"
@ -806,12 +806,12 @@ msgstr ""
msgid "Hi %{email},\n\nYou can change your email by visiting the URL below:\n\n%{url}\n\nIf you didn't request this change, please ignore this."
msgstr ""
#: lib/who_need_help/accounts/user_notifier.ex:71
#: lib/who_need_help/accounts/user_notifier.ex:86
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nYou can confirm your account by visiting the URL below:\n\n%{url}\n\nIf you didn't create an account with us, please ignore this."
msgstr ""
#: lib/who_need_help/accounts/user_notifier.ex:57
#: lib/who_need_help/accounts/user_notifier.ex:72
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nYou can log into your account by visiting the URL below:\n\n%{url}\n\nIf you didn't request this email, please ignore this."
msgstr ""
@ -878,7 +878,7 @@ msgstr ""
msgid "Identity and reputation"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:89
#: lib/who_need_help_web/controllers/user_session_controller.ex:97
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you will receive instructions for logging in shortly."
msgstr ""
@ -915,7 +915,7 @@ msgstr ""
msgid "Internal note"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:124
#: lib/who_need_help_web/controllers/user_session_controller.ex:132
#, elixir-autogen, elixir-format
msgid "Invalid email or password"
msgstr ""
@ -977,22 +977,22 @@ msgstr ""
msgid "Location:"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:136
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:146
#, elixir-autogen, elixir-format
msgid "Log in and stay logged in"
msgstr ""
#: lib/who_need_help/accounts/user_notifier.ex:56
#: lib/who_need_help/accounts/user_notifier.ex:71
#, elixir-autogen, elixir-format
msgid "Log in instructions"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:139
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:149
#, elixir-autogen, elixir-format
msgid "Log in only this time"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:117
#: lib/who_need_help_web/controllers/user_session_controller.ex:125
#, elixir-autogen, elixir-format
msgid "Logged out successfully."
msgstr ""
@ -1323,7 +1323,7 @@ msgstr ""
msgid "Participant"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:130
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:140
#, elixir-autogen, elixir-format
msgid "Password"
msgstr ""
@ -1504,6 +1504,7 @@ msgstr ""
msgid "Rating"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:80
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:43
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
@ -1925,7 +1926,7 @@ msgstr ""
msgid "The last administrator cannot demote themselves."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:37
#: lib/who_need_help_web/controllers/user_session_controller.ex:44
#, elixir-autogen, elixir-format
msgid "The link is invalid or it has expired."
msgstr ""
@ -2046,7 +2047,8 @@ msgstr ""
msgid "Too many actions in the configured time window."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:180
#: lib/who_need_help_web/controllers/google_auth_controller.ex:139
#: lib/who_need_help_web/controllers/google_auth_controller.ex:309
#: lib/who_need_help_web/controllers/user_registration_controller.ex:49
#, elixir-autogen, elixir-format
msgid "Too many registration attempts in the configured time window."
@ -2057,7 +2059,8 @@ msgstr ""
msgid "Too many requests in the configured time window."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:102
#: lib/who_need_help_web/controllers/google_auth_controller.ex:189
#: lib/who_need_help_web/controllers/user_session_controller.ex:110
#, elixir-autogen, elixir-format
msgid "Too many sign-in emails in the configured time window."
msgstr ""
@ -2162,7 +2165,7 @@ msgstr ""
msgid "User blocked. Their requests and new messages are hidden."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:25
#: lib/who_need_help_web/controllers/user_session_controller.ex:31
#, elixir-autogen, elixir-format
msgid "User confirmed successfully."
msgstr ""
@ -2218,9 +2221,9 @@ msgstr ""
msgid "Waiting for a nearby volunteer."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:137
#: lib/who_need_help_web/controllers/user_session_controller.ex:26
#: lib/who_need_help_web/controllers/user_session_controller.ex:51
#: lib/who_need_help_web/controllers/google_auth_controller.ex:266
#: lib/who_need_help_web/controllers/user_session_controller.ex:32
#: lib/who_need_help_web/controllers/user_session_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Welcome back!"
msgstr ""
@ -2423,6 +2426,7 @@ msgstr ""
msgid "activity message"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:48
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
@ -2737,7 +2741,7 @@ msgstr ""
msgid "The settings form is invalid."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:111
#: lib/who_need_help_web/controllers/user_session_controller.ex:119
#, elixir-autogen, elixir-format
msgid "The sign-in form is invalid."
msgstr ""
@ -2762,7 +2766,7 @@ msgstr ""
msgid "This request has expired."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:60
#: lib/who_need_help_web/controllers/user_session_controller.ex:68
#, elixir-autogen, elixir-format
msgid "Too many sign-in attempts in the configured time window."
msgstr ""
@ -2797,7 +2801,7 @@ msgstr ""
msgid "A Google account is connected. You can use it to sign in."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:207
#: lib/who_need_help_web/controllers/google_auth_controller.ex:336
#, elixir-autogen, elixir-format
msgid "A different Google account is already connected."
msgstr ""
@ -2807,12 +2811,8 @@ msgstr ""
msgid "A password is not required. We will email a one-time confirmation link. You can add a password later in account settings."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:170
#, elixir-autogen, elixir-format
msgid "An account with this email already exists. Sign in by email or password, then connect Google in account settings."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:37
#: lib/who_need_help_web/controllers/google_auth_controller.ex:42
#: lib/who_need_help_web/controllers/google_auth_controller.ex:123
#, elixir-autogen, elixir-format
msgid "Confirm that you are 18 or older and accept the safety rules first."
msgstr ""
@ -2832,17 +2832,17 @@ msgstr ""
msgid "Create account and email me a link"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:99
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:109
#, elixir-autogen, elixir-format
msgid "Email me a sign-in link"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:215
#: lib/who_need_help_web/controllers/google_auth_controller.ex:344
#, elixir-autogen, elixir-format
msgid "Google account connection session is invalid."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:97
#: lib/who_need_help_web/controllers/google_auth_controller.ex:226
#, elixir-autogen, elixir-format
msgid "Google did not provide a verified email address."
msgstr ""
@ -2852,32 +2852,34 @@ msgstr ""
msgid "Google sign-in"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:197
#: lib/who_need_help_web/controllers/google_auth_controller.ex:326
#, elixir-autogen, elixir-format
msgid "Google sign-in connected."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:123
#: lib/who_need_help_web/controllers/google_auth_controller.ex:252
#, elixir-autogen, elixir-format
msgid "Google sign-in could not be started."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:102
#: lib/who_need_help_web/controllers/google_auth_controller.ex:231
#, elixir-autogen, elixir-format
msgid "Google sign-in failed. Please try again."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:128
#: lib/who_need_help_web/controllers/google_auth_controller.ex:257
#, elixir-autogen, elixir-format
msgid "Google sign-in is not configured yet."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:87
#: lib/who_need_help_web/controllers/google_auth_controller.ex:97
#: lib/who_need_help_web/controllers/google_auth_controller.ex:216
#: lib/who_need_help_web/controllers/google_auth_controller.ex:399
#, elixir-autogen, elixir-format
msgid "Google sign-in session expired. Please start again."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:91
#: lib/who_need_help_web/controllers/google_auth_controller.ex:220
#, elixir-autogen, elixir-format
msgid "Google sign-in session is invalid."
msgstr ""
@ -2894,52 +2896,44 @@ msgstr ""
msgid "Sending link..."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:74
#, elixir-autogen, elixir-format
msgid "Sign in with Google"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:51
#, elixir-autogen, elixir-format
msgid "Sign up with Google"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:202
#: lib/who_need_help_web/controllers/google_auth_controller.ex:331
#, elixir-autogen, elixir-format
msgid "That Google account belongs to another local account."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:45
#: lib/who_need_help_web/controllers/google_auth_controller.ex:50
#: lib/who_need_help_web/controllers/google_auth_controller.ex:164
#, elixir-autogen, elixir-format
msgid "The Google registration form is invalid."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:260
#: lib/who_need_help_web/controllers/google_auth_controller.ex:405
#, elixir-autogen, elixir-format
msgid "This Google account cannot be used right now."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:144
#, elixir-autogen, elixir-format
msgid "This Google account is not connected yet. Create an account or sign in by email and connect Google in account settings."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:109
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:119
#, elixir-autogen, elixir-format
msgid "This works only if you previously added a password in account settings."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:105
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:115
#, elixir-autogen, elixir-format
msgid "Use a password instead"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:106
#, elixir-autogen, elixir-format
msgid "We will send a one-time sign-in link. No password is required."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:163
#: lib/who_need_help_web/controllers/google_auth_controller.ex:116
#: lib/who_need_help_web/controllers/google_auth_controller.ex:288
#, elixir-autogen, elixir-format
msgid "Your account was created with Google."
msgstr ""
@ -2964,12 +2958,12 @@ msgstr ""
msgid "Disconnect Google sign-in from this account?"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:60
#: lib/who_need_help_web/controllers/google_auth_controller.ex:65
#, elixir-autogen, elixir-format
msgid "Google sign-in disconnected."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:65
#: lib/who_need_help_web/controllers/google_auth_controller.ex:70
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr ""
@ -3603,6 +3597,7 @@ msgstr ""
msgid "Please delete my account and associated personal data."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:76
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:39
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
@ -3614,12 +3609,14 @@ msgstr ""
msgid "Privacy"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:82
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:45
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:92
#, elixir-autogen, elixir-format
msgid "Privacy Policy"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:84
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:47
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:94
#, elixir-autogen, elixir-format
@ -3627,12 +3624,14 @@ msgid "Safety Rules"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:81
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:44
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:91
#, elixir-autogen, elixir-format
msgid "Terms"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:83
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:46
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:93
#, elixir-autogen, elixir-format
@ -3956,3 +3955,111 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "You stay in control of the match"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:52
#, elixir-autogen, elixir-format
msgid "After this confirmation, future Google sign-ins will take one click."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:99
#, elixir-autogen, elixir-format
msgid "Cancel and use another sign-in method"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:35
#, elixir-autogen, elixir-format
msgid "Confirm access once so nobody can attach Google to your account using only a matching email address."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:5
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:74
#, elixir-autogen, elixir-format
msgid "Continue with Google"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:91
#, elixir-autogen, elixir-format
msgid "Create account and continue"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:58
#, elixir-autogen, elixir-format
msgid "Create your Who Need Help account"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:89
#, elixir-autogen, elixir-format
msgid "Creating account..."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:43
#, elixir-autogen, elixir-format
msgid "Email me a verification link"
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:158
#, elixir-autogen, elixir-format
msgid "Google sign-in connected. You can use it next time."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:7
#, elixir-autogen, elixir-format
msgid "Google verified your identity. Finish this one-time step to continue."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:60
#, elixir-autogen, elixir-format
msgid "No password is required. Google will be connected as your sign-in method."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:42
#, elixir-autogen, elixir-format
msgid "Sending..."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:88
#, elixir-autogen, elixir-format
msgid "Sign in to %{email} once to connect Google. You can use the email link or your existing password."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:33
#, elixir-autogen, elixir-format
msgid "This email already has an account"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:131
#: lib/who_need_help_web/controllers/google_auth_controller.ex:153
#: lib/who_need_help_web/controllers/google_auth_controller.ex:297
#, elixir-autogen, elixir-format
msgid "This email already has an account. Confirm it once to connect Google."
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:48
#, elixir-autogen, elixir-format
msgid "Use my password instead"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:25
#, elixir-autogen, elixir-format
msgid "Verified"
msgstr ""
#: lib/who_need_help_web/controllers/google_auth_controller.ex:178
#, elixir-autogen, elixir-format
msgid "We sent a verification link to %{email}. Open it to finish connecting Google."
msgstr ""
#: lib/who_need_help_web/controllers/user_session_controller.ex:171
#, elixir-autogen, elixir-format
msgid "You are signed in, but Google could not be connected. Try again in account settings."
msgstr ""
#: lib/who_need_help/accounts/user_notifier.ex:57
#, elixir-autogen, elixir-format
msgid "Confirm Google sign-in"
msgstr ""
#: lib/who_need_help/accounts/user_notifier.ex:58
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nUse the secure link below to sign in and connect Google to your Who Need Help account:\n\n%{url}\n\nIf you did not request this, ignore this email. Google will not be connected."
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -550,7 +550,7 @@ msgstr ""
"Перед публикацией подтвердите электронную почту и убедитесь, что учётная "
"запись активна."
#: lib/who_need_help/accounts/user_notifier.ex:70
#: lib/who_need_help/accounts/user_notifier.ex:85
#, elixir-autogen, elixir-format
msgid "Confirmation instructions"
msgstr "Инструкции по подтверждению"
@ -665,8 +665,8 @@ msgid "Double-blind review"
msgstr "Двусторонний скрытый отзыв"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:75
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:89
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:122
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:99
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:132
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:15
#, elixir-autogen, elixir-format
msgid "Email"
@ -852,7 +852,7 @@ msgstr ""
"\n"
"Если вы не запрашивали это изменение, просто проигнорируйте письмо."
#: lib/who_need_help/accounts/user_notifier.ex:71
#: lib/who_need_help/accounts/user_notifier.ex:86
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nYou can confirm your account by visiting the URL below:\n\n%{url}\n\nIf you didn't create an account with us, please ignore this."
msgstr ""
@ -864,7 +864,7 @@ msgstr ""
"\n"
"Если вы не создавали у нас учётную запись, просто проигнорируйте письмо."
#: lib/who_need_help/accounts/user_notifier.ex:57
#: lib/who_need_help/accounts/user_notifier.ex:72
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nYou can log into your account by visiting the URL below:\n\n%{url}\n\nIf you didn't request this email, please ignore this."
msgstr ""
@ -949,7 +949,7 @@ msgstr ""
msgid "Identity and reputation"
msgstr "Личность и репутация"
#: lib/who_need_help_web/controllers/user_session_controller.ex:89
#: lib/who_need_help_web/controllers/user_session_controller.ex:97
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you will receive instructions for logging in shortly."
msgstr ""
@ -991,7 +991,7 @@ msgstr "Язык интерфейса"
msgid "Internal note"
msgstr "Внутренняя заметка"
#: lib/who_need_help_web/controllers/user_session_controller.ex:124
#: lib/who_need_help_web/controllers/user_session_controller.ex:132
#, elixir-autogen, elixir-format
msgid "Invalid email or password"
msgstr "Неверная электронная почта или пароль"
@ -1055,22 +1055,22 @@ msgstr "Люди с подтверждением геопозицией"
msgid "Location:"
msgstr "Геопозиция:"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:136
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:146
#, elixir-autogen, elixir-format
msgid "Log in and stay logged in"
msgstr "Войти и оставаться в системе"
#: lib/who_need_help/accounts/user_notifier.ex:56
#: lib/who_need_help/accounts/user_notifier.ex:71
#, elixir-autogen, elixir-format
msgid "Log in instructions"
msgstr "Инструкции для входа"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:139
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:149
#, elixir-autogen, elixir-format
msgid "Log in only this time"
msgstr "Войти только сейчас"
#: lib/who_need_help_web/controllers/user_session_controller.ex:117
#: lib/who_need_help_web/controllers/user_session_controller.ex:125
#, elixir-autogen, elixir-format
msgid "Logged out successfully."
msgstr "Вы успешно вышли."
@ -1422,7 +1422,7 @@ msgstr "Родительская категория (необязательно)
msgid "Participant"
msgstr "Участник"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:130
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:140
#, elixir-autogen, elixir-format
msgid "Password"
msgstr "Пароль"
@ -1620,6 +1620,7 @@ msgstr ""
msgid "Rating"
msgstr "Оценка"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:80
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:43
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
@ -2051,7 +2052,7 @@ msgstr "Браузеру не удалось передать вашу геоп
msgid "The last administrator cannot demote themselves."
msgstr "Последний администратор не может понизить собственную роль."
#: lib/who_need_help_web/controllers/user_session_controller.ex:37
#: lib/who_need_help_web/controllers/user_session_controller.ex:44
#, elixir-autogen, elixir-format
msgid "The link is invalid or it has expired."
msgstr "Ссылка недействительна или просрочена."
@ -2182,7 +2183,8 @@ msgstr "Сегодня"
msgid "Too many actions in the configured time window."
msgstr "Слишком много действий за настроенный промежуток времени."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:180
#: lib/who_need_help_web/controllers/google_auth_controller.ex:139
#: lib/who_need_help_web/controllers/google_auth_controller.ex:309
#: lib/who_need_help_web/controllers/user_registration_controller.ex:49
#, elixir-autogen, elixir-format
msgid "Too many registration attempts in the configured time window."
@ -2193,7 +2195,8 @@ msgstr "Слишком много попыток регистрации за н
msgid "Too many requests in the configured time window."
msgstr "Слишком много запросов за настроенный промежуток времени."
#: lib/who_need_help_web/controllers/user_session_controller.ex:102
#: lib/who_need_help_web/controllers/google_auth_controller.ex:189
#: lib/who_need_help_web/controllers/user_session_controller.ex:110
#, elixir-autogen, elixir-format
msgid "Too many sign-in emails in the configured time window."
msgstr "Слишком много писем для входа за настроенный промежуток времени."
@ -2303,7 +2306,7 @@ msgstr "Пользователь"
msgid "User blocked. Their requests and new messages are hidden."
msgstr "Пользователь заблокирован. Его заявки и новые сообщения скрыты."
#: lib/who_need_help_web/controllers/user_session_controller.ex:25
#: lib/who_need_help_web/controllers/user_session_controller.ex:31
#, elixir-autogen, elixir-format
msgid "User confirmed successfully."
msgstr "Пользователь успешно подтверждён."
@ -2359,9 +2362,9 @@ msgstr "Открытые отзывы"
msgid "Waiting for a nearby volunteer."
msgstr "Ожидаем помощника поблизости."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:137
#: lib/who_need_help_web/controllers/user_session_controller.ex:26
#: lib/who_need_help_web/controllers/user_session_controller.ex:51
#: lib/who_need_help_web/controllers/google_auth_controller.ex:266
#: lib/who_need_help_web/controllers/user_session_controller.ex:32
#: lib/who_need_help_web/controllers/user_session_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Welcome back!"
msgstr "С возвращением!"
@ -2580,6 +2583,7 @@ msgstr "активность"
msgid "activity message"
msgstr "сообщение активности"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:48
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
@ -2894,7 +2898,7 @@ msgstr "Выбранная запись больше недоступна."
msgid "The settings form is invalid."
msgstr "Форма настроек заполнена неверно."
#: lib/who_need_help_web/controllers/user_session_controller.ex:111
#: lib/who_need_help_web/controllers/user_session_controller.ex:119
#, elixir-autogen, elixir-format
msgid "The sign-in form is invalid."
msgstr "Форма входа заполнена неверно."
@ -2919,7 +2923,7 @@ msgstr "Это предложение больше недоступно."
msgid "This request has expired."
msgstr "Срок действия этой заявки истёк."
#: lib/who_need_help_web/controllers/user_session_controller.ex:60
#: lib/who_need_help_web/controllers/user_session_controller.ex:68
#, elixir-autogen, elixir-format
msgid "Too many sign-in attempts in the configured time window."
msgstr "Слишком много попыток входа за настроенный промежуток времени."
@ -2954,7 +2958,7 @@ msgstr "Слишком много запросов на смену email за н
msgid "A Google account is connected. You can use it to sign in."
msgstr "Аккаунт Google подключён. Теперь с его помощью можно входить."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:207
#: lib/who_need_help_web/controllers/google_auth_controller.ex:336
#, elixir-autogen, elixir-format
msgid "A different Google account is already connected."
msgstr "Уже подключён другой аккаунт Google."
@ -2964,12 +2968,8 @@ msgstr "Уже подключён другой аккаунт Google."
msgid "A password is not required. We will email a one-time confirmation link. You can add a password later in account settings."
msgstr "Пароль не обязателен. Мы отправим на email одноразовую ссылку для подтверждения. Пароль можно добавить позже в настройках аккаунта."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:170
#, elixir-autogen, elixir-format
msgid "An account with this email already exists. Sign in by email or password, then connect Google in account settings."
msgstr "Учётная запись с таким email уже существует. Войдите по email или паролю, затем подключите Google в настройках аккаунта."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:37
#: lib/who_need_help_web/controllers/google_auth_controller.ex:42
#: lib/who_need_help_web/controllers/google_auth_controller.ex:123
#, elixir-autogen, elixir-format
msgid "Confirm that you are 18 or older and accept the safety rules first."
msgstr "Сначала подтвердите, что вам уже исполнилось 18 лет, и примите правила безопасности."
@ -2989,17 +2989,17 @@ msgstr "Подключайте Google только после входа зде
msgid "Create account and email me a link"
msgstr "Создать аккаунт и отправить ссылку на email"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:99
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:109
#, elixir-autogen, elixir-format
msgid "Email me a sign-in link"
msgstr "Отправить ссылку для входа на email"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:215
#: lib/who_need_help_web/controllers/google_auth_controller.ex:344
#, elixir-autogen, elixir-format
msgid "Google account connection session is invalid."
msgstr "Сессия подключения аккаунта Google недействительна."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:97
#: lib/who_need_help_web/controllers/google_auth_controller.ex:226
#, elixir-autogen, elixir-format
msgid "Google did not provide a verified email address."
msgstr "Google не предоставил подтверждённый адрес email."
@ -3009,32 +3009,34 @@ msgstr "Google не предоставил подтверждённый адре
msgid "Google sign-in"
msgstr "Вход через Google"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:197
#: lib/who_need_help_web/controllers/google_auth_controller.ex:326
#, elixir-autogen, elixir-format
msgid "Google sign-in connected."
msgstr "Вход через Google подключён."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:123
#: lib/who_need_help_web/controllers/google_auth_controller.ex:252
#, elixir-autogen, elixir-format
msgid "Google sign-in could not be started."
msgstr "Не удалось начать вход через Google."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:102
#: lib/who_need_help_web/controllers/google_auth_controller.ex:231
#, elixir-autogen, elixir-format
msgid "Google sign-in failed. Please try again."
msgstr "Не удалось войти через Google. Попробуйте ещё раз."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:128
#: lib/who_need_help_web/controllers/google_auth_controller.ex:257
#, elixir-autogen, elixir-format
msgid "Google sign-in is not configured yet."
msgstr "Вход через Google пока не настроен."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:87
#: lib/who_need_help_web/controllers/google_auth_controller.ex:97
#: lib/who_need_help_web/controllers/google_auth_controller.ex:216
#: lib/who_need_help_web/controllers/google_auth_controller.ex:399
#, elixir-autogen, elixir-format
msgid "Google sign-in session expired. Please start again."
msgstr "Сессия входа через Google истекла. Начните заново."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:91
#: lib/who_need_help_web/controllers/google_auth_controller.ex:220
#, elixir-autogen, elixir-format
msgid "Google sign-in session is invalid."
msgstr "Сессия входа через Google недействительна."
@ -3051,52 +3053,44 @@ msgstr "Вход через Google станет доступен после на
msgid "Sending link..."
msgstr "Отправляем ссылку..."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:74
#, elixir-autogen, elixir-format
msgid "Sign in with Google"
msgstr "Войти через Google"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:51
#, elixir-autogen, elixir-format
msgid "Sign up with Google"
msgstr "Зарегистрироваться через Google"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:202
#: lib/who_need_help_web/controllers/google_auth_controller.ex:331
#, elixir-autogen, elixir-format
msgid "That Google account belongs to another local account."
msgstr "Этот аккаунт Google принадлежит другой локальной учётной записи."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:45
#: lib/who_need_help_web/controllers/google_auth_controller.ex:50
#: lib/who_need_help_web/controllers/google_auth_controller.ex:164
#, elixir-autogen, elixir-format
msgid "The Google registration form is invalid."
msgstr "Форма регистрации через Google заполнена неверно."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:260
#: lib/who_need_help_web/controllers/google_auth_controller.ex:405
#, elixir-autogen, elixir-format
msgid "This Google account cannot be used right now."
msgstr "Этот аккаунт Google сейчас нельзя использовать."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:144
#, elixir-autogen, elixir-format
msgid "This Google account is not connected yet. Create an account or sign in by email and connect Google in account settings."
msgstr "Этот аккаунт Google ещё не подключён. Создайте учётную запись или войдите по email и подключите Google в настройках аккаунта."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:109
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:119
#, elixir-autogen, elixir-format
msgid "This works only if you previously added a password in account settings."
msgstr "Это работает, только если вы ранее добавили пароль в настройках аккаунта."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:105
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:115
#, elixir-autogen, elixir-format
msgid "Use a password instead"
msgstr "Войти по паролю"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:106
#, elixir-autogen, elixir-format
msgid "We will send a one-time sign-in link. No password is required."
msgstr "Мы отправим одноразовую ссылку для входа. Пароль не требуется."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:163
#: lib/who_need_help_web/controllers/google_auth_controller.ex:116
#: lib/who_need_help_web/controllers/google_auth_controller.ex:288
#, elixir-autogen, elixir-format
msgid "Your account was created with Google."
msgstr "Ваша учётная запись создана через Google."
@ -3121,12 +3115,12 @@ msgstr "Отключить Google"
msgid "Disconnect Google sign-in from this account?"
msgstr "Отключить вход через Google для этой учётной записи?"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:60
#: lib/who_need_help_web/controllers/google_auth_controller.ex:65
#, elixir-autogen, elixir-format
msgid "Google sign-in disconnected."
msgstr "Вход через Google отключён."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:65
#: lib/who_need_help_web/controllers/google_auth_controller.ex:70
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr "Аккаунт Google не подключён."
@ -3760,6 +3754,7 @@ msgstr "Удалить мой аккаунт Who Need Help"
msgid "Please delete my account and associated personal data."
msgstr "Пожалуйста, удалите мой аккаунт и связанные персональные данные."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:76
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:39
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
@ -3771,12 +3766,14 @@ msgstr "Мне 18 лет или больше, и я принимаю Услов
msgid "Privacy"
msgstr "Конфиденциальность"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:82
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:45
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:92
#, elixir-autogen, elixir-format
msgid "Privacy Policy"
msgstr "Политика конфиденциальности"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:84
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:47
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:94
#, elixir-autogen, elixir-format
@ -3784,12 +3781,14 @@ msgid "Safety Rules"
msgstr "Правила безопасности"
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:81
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:44
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:91
#, elixir-autogen, elixir-format
msgid "Terms"
msgstr "Условия"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:83
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:46
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:93
#, elixir-autogen, elixir-format
@ -4113,3 +4112,111 @@ msgstr "Вы сами выбираете видимость. Точные тек
#, elixir-autogen, elixir-format
msgid "You stay in control of the match"
msgstr "Вы контролируете взаимодействие"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:52
#, elixir-autogen, elixir-format
msgid "After this confirmation, future Google sign-ins will take one click."
msgstr "После этого подтверждения дальнейший вход через Google будет выполняться одним нажатием."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:99
#, elixir-autogen, elixir-format
msgid "Cancel and use another sign-in method"
msgstr "Отменить и выбрать другой способ входа"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:35
#, elixir-autogen, elixir-format
msgid "Confirm access once so nobody can attach Google to your account using only a matching email address."
msgstr "Один раз подтвердите доступ, чтобы никто не смог привязать Google к вашему аккаунту лишь по совпадающему email."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:5
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:74
#, elixir-autogen, elixir-format
msgid "Continue with Google"
msgstr "Продолжить с Google"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:91
#, elixir-autogen, elixir-format
msgid "Create account and continue"
msgstr "Создать аккаунт и продолжить"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:58
#, elixir-autogen, elixir-format
msgid "Create your Who Need Help account"
msgstr "Создайте аккаунт Who Need Help"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:89
#, elixir-autogen, elixir-format
msgid "Creating account..."
msgstr "Создаём аккаунт..."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:43
#, elixir-autogen, elixir-format
msgid "Email me a verification link"
msgstr "Отправить ссылку для подтверждения на email"
#: lib/who_need_help_web/controllers/user_session_controller.ex:158
#, elixir-autogen, elixir-format
msgid "Google sign-in connected. You can use it next time."
msgstr "Вход через Google подключён. В следующий раз можно использовать его."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:7
#, elixir-autogen, elixir-format
msgid "Google verified your identity. Finish this one-time step to continue."
msgstr "Google подтвердил вашу личность. Выполните этот разовый шаг, чтобы продолжить."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:60
#, elixir-autogen, elixir-format
msgid "No password is required. Google will be connected as your sign-in method."
msgstr "Пароль не нужен. Google будет подключён как способ входа."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:42
#, elixir-autogen, elixir-format
msgid "Sending..."
msgstr "Отправляем..."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:88
#, elixir-autogen, elixir-format
msgid "Sign in to %{email} once to connect Google. You can use the email link or your existing password."
msgstr "Один раз войдите в %{email}, чтобы подключить Google. Можно использовать ссылку из письма или существующий пароль."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:33
#, elixir-autogen, elixir-format
msgid "This email already has an account"
msgstr "Для этого email уже есть аккаунт"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:131
#: lib/who_need_help_web/controllers/google_auth_controller.ex:153
#: lib/who_need_help_web/controllers/google_auth_controller.ex:297
#, elixir-autogen, elixir-format
msgid "This email already has an account. Confirm it once to connect Google."
msgstr "Для этого email уже есть аккаунт. Один раз подтвердите его, чтобы подключить Google."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:48
#, elixir-autogen, elixir-format
msgid "Use my password instead"
msgstr "Использовать пароль"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:25
#, elixir-autogen, elixir-format
msgid "Verified"
msgstr "Подтверждено"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:178
#, elixir-autogen, elixir-format
msgid "We sent a verification link to %{email}. Open it to finish connecting Google."
msgstr "Мы отправили ссылку для подтверждения на %{email}. Откройте её, чтобы завершить подключение Google."
#: lib/who_need_help_web/controllers/user_session_controller.ex:171
#, elixir-autogen, elixir-format
msgid "You are signed in, but Google could not be connected. Try again in account settings."
msgstr "Вы вошли, но подключить Google не удалось. Повторите попытку в настройках аккаунта."
#: lib/who_need_help/accounts/user_notifier.ex:57
#, elixir-autogen, elixir-format
msgid "Confirm Google sign-in"
msgstr "Подтвердите вход через Google"
#: lib/who_need_help/accounts/user_notifier.ex:58
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nUse the secure link below to sign in and connect Google to your Who Need Help account:\n\n%{url}\n\nIf you did not request this, ignore this email. Google will not be connected."
msgstr "Здравствуйте, %{email}!\n\nПерейдите по защищённой ссылке ниже, чтобы войти и подключить Google к аккаунту Who Need Help:\n\n%{url}\n\nЕсли вы не запрашивали это действие, проигнорируйте письмо. Google не будет подключён."

View File

@ -551,7 +551,7 @@ msgstr ""
"Перед публікацією підтвердьте електронну пошту й переконайтеся, що обліковий"
" запис активний."
#: lib/who_need_help/accounts/user_notifier.ex:70
#: lib/who_need_help/accounts/user_notifier.ex:85
#, elixir-autogen, elixir-format
msgid "Confirmation instructions"
msgstr "Інструкції для підтвердження"
@ -665,8 +665,8 @@ msgid "Double-blind review"
msgstr "Двосторонній прихований відгук"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:75
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:89
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:122
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:99
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:132
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:15
#, elixir-autogen, elixir-format
msgid "Email"
@ -851,7 +851,7 @@ msgstr ""
"\n"
"Якщо ви не запитували цю зміну, просто проігноруйте лист."
#: lib/who_need_help/accounts/user_notifier.ex:71
#: lib/who_need_help/accounts/user_notifier.ex:86
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nYou can confirm your account by visiting the URL below:\n\n%{url}\n\nIf you didn't create an account with us, please ignore this."
msgstr ""
@ -863,7 +863,7 @@ msgstr ""
"\n"
"Якщо ви не створювали в нас обліковий запис, просто проігноруйте лист."
#: lib/who_need_help/accounts/user_notifier.ex:57
#: lib/who_need_help/accounts/user_notifier.ex:72
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nYou can log into your account by visiting the URL below:\n\n%{url}\n\nIf you didn't request this email, please ignore this."
msgstr ""
@ -946,7 +946,7 @@ msgstr ""
msgid "Identity and reputation"
msgstr "Особа й репутація"
#: lib/who_need_help_web/controllers/user_session_controller.ex:89
#: lib/who_need_help_web/controllers/user_session_controller.ex:97
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you will receive instructions for logging in shortly."
msgstr ""
@ -988,7 +988,7 @@ msgstr "Мова інтерфейсу"
msgid "Internal note"
msgstr "Внутрішня нотатка"
#: lib/who_need_help_web/controllers/user_session_controller.ex:124
#: lib/who_need_help_web/controllers/user_session_controller.ex:132
#, elixir-autogen, elixir-format
msgid "Invalid email or password"
msgstr "Неправильна електронна пошта або пароль"
@ -1052,22 +1052,22 @@ msgstr "Люди з підтвердженням геопозицією"
msgid "Location:"
msgstr "Геопозиція:"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:136
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:146
#, elixir-autogen, elixir-format
msgid "Log in and stay logged in"
msgstr "Увійти й залишатися в системі"
#: lib/who_need_help/accounts/user_notifier.ex:56
#: lib/who_need_help/accounts/user_notifier.ex:71
#, elixir-autogen, elixir-format
msgid "Log in instructions"
msgstr "Інструкції для входу"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:139
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:149
#, elixir-autogen, elixir-format
msgid "Log in only this time"
msgstr "Увійти лише зараз"
#: lib/who_need_help_web/controllers/user_session_controller.ex:117
#: lib/who_need_help_web/controllers/user_session_controller.ex:125
#, elixir-autogen, elixir-format
msgid "Logged out successfully."
msgstr "Ви успішно вийшли."
@ -1416,7 +1416,7 @@ msgstr "Батьківська категорія (необов’язково)"
msgid "Participant"
msgstr "Учасник"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:130
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:140
#, elixir-autogen, elixir-format
msgid "Password"
msgstr "Пароль"
@ -1613,6 +1613,7 @@ msgstr ""
msgid "Rating"
msgstr "Оцінка"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:80
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:43
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
@ -2045,7 +2046,7 @@ msgstr "Браузеру не вдалося передати вашу геоп
msgid "The last administrator cannot demote themselves."
msgstr "Останній адміністратор не може понизити власну роль."
#: lib/who_need_help_web/controllers/user_session_controller.ex:37
#: lib/who_need_help_web/controllers/user_session_controller.ex:44
#, elixir-autogen, elixir-format
msgid "The link is invalid or it has expired."
msgstr "Посилання недійсне або прострочене."
@ -2176,7 +2177,8 @@ msgstr "Сьогодні"
msgid "Too many actions in the configured time window."
msgstr "Забагато дій протягом налаштованого проміжку часу."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:180
#: lib/who_need_help_web/controllers/google_auth_controller.ex:139
#: lib/who_need_help_web/controllers/google_auth_controller.ex:309
#: lib/who_need_help_web/controllers/user_registration_controller.ex:49
#, elixir-autogen, elixir-format
msgid "Too many registration attempts in the configured time window."
@ -2187,7 +2189,8 @@ msgstr "Забагато спроб реєстрації протягом нал
msgid "Too many requests in the configured time window."
msgstr "Забагато запитів протягом налаштованого проміжку часу."
#: lib/who_need_help_web/controllers/user_session_controller.ex:102
#: lib/who_need_help_web/controllers/google_auth_controller.ex:189
#: lib/who_need_help_web/controllers/user_session_controller.ex:110
#, elixir-autogen, elixir-format
msgid "Too many sign-in emails in the configured time window."
msgstr "Забагато листів для входу протягом налаштованого проміжку часу."
@ -2296,7 +2299,7 @@ msgstr "Користувач"
msgid "User blocked. Their requests and new messages are hidden."
msgstr "Користувача заблоковано. Його заявки й нові повідомлення приховано."
#: lib/who_need_help_web/controllers/user_session_controller.ex:25
#: lib/who_need_help_web/controllers/user_session_controller.ex:31
#, elixir-autogen, elixir-format
msgid "User confirmed successfully."
msgstr "Користувача успішно підтверджено."
@ -2352,9 +2355,9 @@ msgstr "Відкриті відгуки"
msgid "Waiting for a nearby volunteer."
msgstr "Очікуємо помічника поруч."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:137
#: lib/who_need_help_web/controllers/user_session_controller.ex:26
#: lib/who_need_help_web/controllers/user_session_controller.ex:51
#: lib/who_need_help_web/controllers/google_auth_controller.ex:266
#: lib/who_need_help_web/controllers/user_session_controller.ex:32
#: lib/who_need_help_web/controllers/user_session_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Welcome back!"
msgstr "З поверненням!"
@ -2569,6 +2572,7 @@ msgstr "активність"
msgid "activity message"
msgstr "повідомлення активності"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:48
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
@ -2883,7 +2887,7 @@ msgstr "Вибраний запис більше недоступний."
msgid "The settings form is invalid."
msgstr "Форму налаштувань заповнено неправильно."
#: lib/who_need_help_web/controllers/user_session_controller.ex:111
#: lib/who_need_help_web/controllers/user_session_controller.ex:119
#, elixir-autogen, elixir-format
msgid "The sign-in form is invalid."
msgstr "Форму входу заповнено неправильно."
@ -2908,7 +2912,7 @@ msgstr "Ця пропозиція більше недоступна."
msgid "This request has expired."
msgstr "Термін дії цієї заявки минув."
#: lib/who_need_help_web/controllers/user_session_controller.ex:60
#: lib/who_need_help_web/controllers/user_session_controller.ex:68
#, elixir-autogen, elixir-format
msgid "Too many sign-in attempts in the configured time window."
msgstr "Забагато спроб входу протягом налаштованого проміжку часу."
@ -2943,7 +2947,7 @@ msgstr "Забагато запитів на зміну email протягом
msgid "A Google account is connected. You can use it to sign in."
msgstr "Обліковий запис Google підключено. Тепер за його допомогою можна входити."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:207
#: lib/who_need_help_web/controllers/google_auth_controller.ex:336
#, elixir-autogen, elixir-format
msgid "A different Google account is already connected."
msgstr "Уже підключено інший обліковий запис Google."
@ -2953,12 +2957,8 @@ msgstr "Уже підключено інший обліковий запис Goo
msgid "A password is not required. We will email a one-time confirmation link. You can add a password later in account settings."
msgstr "Пароль не обов’язковий. Ми надішлемо на email одноразове посилання для підтвердження. Пароль можна додати пізніше в налаштуваннях облікового запису."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:170
#, elixir-autogen, elixir-format
msgid "An account with this email already exists. Sign in by email or password, then connect Google in account settings."
msgstr "Обліковий запис із таким email уже існує. Увійдіть за email або паролем, а потім підключіть Google у налаштуваннях облікового запису."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:37
#: lib/who_need_help_web/controllers/google_auth_controller.ex:42
#: lib/who_need_help_web/controllers/google_auth_controller.ex:123
#, elixir-autogen, elixir-format
msgid "Confirm that you are 18 or older and accept the safety rules first."
msgstr "Спочатку підтвердьте, що вам уже виповнилося 18 років, і прийміть правила безпеки."
@ -2978,17 +2978,17 @@ msgstr "Підключайте Google лише після входу тут. М
msgid "Create account and email me a link"
msgstr "Створити обліковий запис і надіслати посилання на email"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:99
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:109
#, elixir-autogen, elixir-format
msgid "Email me a sign-in link"
msgstr "Надіслати посилання для входу на email"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:215
#: lib/who_need_help_web/controllers/google_auth_controller.ex:344
#, elixir-autogen, elixir-format
msgid "Google account connection session is invalid."
msgstr "Сесія підключення облікового запису Google недійсна."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:97
#: lib/who_need_help_web/controllers/google_auth_controller.ex:226
#, elixir-autogen, elixir-format
msgid "Google did not provide a verified email address."
msgstr "Google не надав підтверджену адресу email."
@ -2998,32 +2998,34 @@ msgstr "Google не надав підтверджену адресу email."
msgid "Google sign-in"
msgstr "Вхід через Google"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:197
#: lib/who_need_help_web/controllers/google_auth_controller.ex:326
#, elixir-autogen, elixir-format
msgid "Google sign-in connected."
msgstr "Вхід через Google підключено."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:123
#: lib/who_need_help_web/controllers/google_auth_controller.ex:252
#, elixir-autogen, elixir-format
msgid "Google sign-in could not be started."
msgstr "Не вдалося розпочати вхід через Google."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:102
#: lib/who_need_help_web/controllers/google_auth_controller.ex:231
#, elixir-autogen, elixir-format
msgid "Google sign-in failed. Please try again."
msgstr "Не вдалося увійти через Google. Спробуйте ще раз."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:128
#: lib/who_need_help_web/controllers/google_auth_controller.ex:257
#, elixir-autogen, elixir-format
msgid "Google sign-in is not configured yet."
msgstr "Вхід через Google ще не налаштовано."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:87
#: lib/who_need_help_web/controllers/google_auth_controller.ex:97
#: lib/who_need_help_web/controllers/google_auth_controller.ex:216
#: lib/who_need_help_web/controllers/google_auth_controller.ex:399
#, elixir-autogen, elixir-format
msgid "Google sign-in session expired. Please start again."
msgstr "Сесія входу через Google завершилася. Почніть заново."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:91
#: lib/who_need_help_web/controllers/google_auth_controller.ex:220
#, elixir-autogen, elixir-format
msgid "Google sign-in session is invalid."
msgstr "Сесія входу через Google недійсна."
@ -3040,52 +3042,44 @@ msgstr "Вхід через Google стане доступним після на
msgid "Sending link..."
msgstr "Надсилаємо посилання..."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:74
#, elixir-autogen, elixir-format
msgid "Sign in with Google"
msgstr "Увійти через Google"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:51
#, elixir-autogen, elixir-format
msgid "Sign up with Google"
msgstr "Зареєструватися через Google"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:202
#: lib/who_need_help_web/controllers/google_auth_controller.ex:331
#, elixir-autogen, elixir-format
msgid "That Google account belongs to another local account."
msgstr "Цей обліковий запис Google належить іншому локальному обліковому запису."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:45
#: lib/who_need_help_web/controllers/google_auth_controller.ex:50
#: lib/who_need_help_web/controllers/google_auth_controller.ex:164
#, elixir-autogen, elixir-format
msgid "The Google registration form is invalid."
msgstr "Форму реєстрації через Google заповнено неправильно."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:260
#: lib/who_need_help_web/controllers/google_auth_controller.ex:405
#, elixir-autogen, elixir-format
msgid "This Google account cannot be used right now."
msgstr "Цей обліковий запис Google зараз не можна використовувати."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:144
#, elixir-autogen, elixir-format
msgid "This Google account is not connected yet. Create an account or sign in by email and connect Google in account settings."
msgstr "Цей обліковий запис Google ще не підключено. Створіть обліковий запис або увійдіть за email і підключіть Google у налаштуваннях."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:109
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:119
#, elixir-autogen, elixir-format
msgid "This works only if you previously added a password in account settings."
msgstr "Це працює, лише якщо ви раніше додали пароль у налаштуваннях облікового запису."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:105
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:115
#, elixir-autogen, elixir-format
msgid "Use a password instead"
msgstr "Увійти за паролем"
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:106
#, elixir-autogen, elixir-format
msgid "We will send a one-time sign-in link. No password is required."
msgstr "Ми надішлемо одноразове посилання для входу. Пароль не потрібен."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:163
#: lib/who_need_help_web/controllers/google_auth_controller.ex:116
#: lib/who_need_help_web/controllers/google_auth_controller.ex:288
#, elixir-autogen, elixir-format
msgid "Your account was created with Google."
msgstr "Ваш обліковий запис створено через Google."
@ -3110,12 +3104,12 @@ msgstr "Відключити Google"
msgid "Disconnect Google sign-in from this account?"
msgstr "Відключити вхід через Google для цього облікового запису?"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:60
#: lib/who_need_help_web/controllers/google_auth_controller.ex:65
#, elixir-autogen, elixir-format
msgid "Google sign-in disconnected."
msgstr "Вхід через Google відключено."
#: lib/who_need_help_web/controllers/google_auth_controller.ex:65
#: lib/who_need_help_web/controllers/google_auth_controller.ex:70
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr "Обліковий запис Google не підключено."
@ -3749,6 +3743,7 @@ msgstr "Видалити мій обліковий запис Who Need Help"
msgid "Please delete my account and associated personal data."
msgstr "Будь ласка, видаліть мій обліковий запис і пов’язані персональні дані."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:76
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:39
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
@ -3760,12 +3755,14 @@ msgstr "Мені 18 років або більше, і я приймаю Умо
msgid "Privacy"
msgstr "Конфіденційність"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:82
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:45
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:92
#, elixir-autogen, elixir-format
msgid "Privacy Policy"
msgstr "Політика конфіденційності"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:84
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:47
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:94
#, elixir-autogen, elixir-format
@ -3773,12 +3770,14 @@ msgid "Safety Rules"
msgstr "Правила безпеки"
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:81
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:44
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:91
#, elixir-autogen, elixir-format
msgid "Terms"
msgstr "Умови"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:83
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:46
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:93
#, elixir-autogen, elixir-format
@ -4102,3 +4101,111 @@ msgstr "Ви самі обираєте видимість. Точні поточ
#, elixir-autogen, elixir-format
msgid "You stay in control of the match"
msgstr "Ви контролюєте взаємодію"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:52
#, elixir-autogen, elixir-format
msgid "After this confirmation, future Google sign-ins will take one click."
msgstr "Після цього підтвердження подальший вхід через Google виконуватиметься одним натисканням."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:99
#, elixir-autogen, elixir-format
msgid "Cancel and use another sign-in method"
msgstr "Скасувати й вибрати інший спосіб входу"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:35
#, elixir-autogen, elixir-format
msgid "Confirm access once so nobody can attach Google to your account using only a matching email address."
msgstr "Один раз підтвердьте доступ, щоб ніхто не зміг прив’язати Google до вашого облікового запису лише за збігом email."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:5
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:74
#, elixir-autogen, elixir-format
msgid "Continue with Google"
msgstr "Продовжити з Google"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:91
#, elixir-autogen, elixir-format
msgid "Create account and continue"
msgstr "Створити обліковий запис і продовжити"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:58
#, elixir-autogen, elixir-format
msgid "Create your Who Need Help account"
msgstr "Створіть обліковий запис Who Need Help"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:89
#, elixir-autogen, elixir-format
msgid "Creating account..."
msgstr "Створюємо обліковий запис..."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:43
#, elixir-autogen, elixir-format
msgid "Email me a verification link"
msgstr "Надіслати посилання для підтвердження на email"
#: lib/who_need_help_web/controllers/user_session_controller.ex:158
#, elixir-autogen, elixir-format
msgid "Google sign-in connected. You can use it next time."
msgstr "Вхід через Google підключено. Наступного разу можна скористатися ним."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:7
#, elixir-autogen, elixir-format
msgid "Google verified your identity. Finish this one-time step to continue."
msgstr "Google підтвердив вашу особу. Виконайте цей разовий крок, щоб продовжити."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:60
#, elixir-autogen, elixir-format
msgid "No password is required. Google will be connected as your sign-in method."
msgstr "Пароль не потрібен. Google буде підключено як спосіб входу."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:42
#, elixir-autogen, elixir-format
msgid "Sending..."
msgstr "Надсилаємо..."
#: lib/who_need_help_web/controllers/user_session_html/new.html.heex:88
#, elixir-autogen, elixir-format
msgid "Sign in to %{email} once to connect Google. You can use the email link or your existing password."
msgstr "Один раз увійдіть до %{email}, щоб підключити Google. Можна скористатися посиланням із листа або чинним паролем."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:33
#, elixir-autogen, elixir-format
msgid "This email already has an account"
msgstr "Для цього email уже є обліковий запис"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:131
#: lib/who_need_help_web/controllers/google_auth_controller.ex:153
#: lib/who_need_help_web/controllers/google_auth_controller.ex:297
#, elixir-autogen, elixir-format
msgid "This email already has an account. Confirm it once to connect Google."
msgstr "Для цього email уже є обліковий запис. Один раз підтвердьте його, щоб підключити Google."
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:48
#, elixir-autogen, elixir-format
msgid "Use my password instead"
msgstr "Скористатися паролем"
#: lib/who_need_help_web/controllers/google_auth_html/complete.html.heex:25
#, elixir-autogen, elixir-format
msgid "Verified"
msgstr "Підтверджено"
#: lib/who_need_help_web/controllers/google_auth_controller.ex:178
#, elixir-autogen, elixir-format
msgid "We sent a verification link to %{email}. Open it to finish connecting Google."
msgstr "Ми надіслали посилання для підтвердження на %{email}. Відкрийте його, щоб завершити підключення Google."
#: lib/who_need_help_web/controllers/user_session_controller.ex:171
#, elixir-autogen, elixir-format
msgid "You are signed in, but Google could not be connected. Try again in account settings."
msgstr "Ви ввійшли, але підключити Google не вдалося. Повторіть спробу в налаштуваннях облікового запису."
#: lib/who_need_help/accounts/user_notifier.ex:57
#, elixir-autogen, elixir-format
msgid "Confirm Google sign-in"
msgstr "Підтвердьте вхід через Google"
#: lib/who_need_help/accounts/user_notifier.ex:58
#, elixir-autogen, elixir-format
msgid "Hi %{email},\n\nUse the secure link below to sign in and connect Google to your Who Need Help account:\n\n%{url}\n\nIf you did not request this, ignore this email. Google will not be connected."
msgstr "Вітаємо, %{email}!\n\nПерейдіть за захищеним посиланням нижче, щоб увійти й підключити Google до облікового запису Who Need Help:\n\n%{url}\n\nЯкщо ви не запитували цю дію, проігноруйте лист. Google не буде підключено."

View File

@ -7,6 +7,7 @@ defmodule WhoNeedHelpWeb.GoogleAuthControllerTest do
alias WhoNeedHelp.Trust.AuditEvent
import WhoNeedHelp.AccountsFixtures
import Swoosh.TestAssertions
test "starts a login flow with callback state, nonce, and PKCE session data", %{conn: conn} do
conn = post(conn, ~p"/auth/google/login")
@ -68,7 +69,7 @@ defmodule WhoNeedHelpWeb.GoogleAuthControllerTest do
assert user_id == user.id
end
test "does not automatically merge an existing email account", %{conn: conn} do
test "requires local-account verification before linking a matching email", %{conn: conn} do
user = user_fixture()
conn =
@ -81,10 +82,14 @@ defmodule WhoNeedHelpWeb.GoogleAuthControllerTest do
~p"/auth/google/callback?code=code&state=google-test-state&uid=new-google&email=#{user.email}"
)
assert redirected_to(conn) == ~p"/users/log-in"
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "already exists"
assert redirected_to(conn) == ~p"/auth/google/complete"
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Confirm it once"
refute get_session(conn, :user_token)
refute Repo.get_by(AuthIdentity, provider: :google, provider_uid: "new-google")
html = conn |> recycle() |> get(~p"/auth/google/complete") |> html_response(200)
assert html =~ "This email already has an account"
assert html =~ "Email me a verification link"
end
test "logs in only through an identity already linked to the local account", %{conn: conn} do
@ -110,7 +115,7 @@ defmodule WhoNeedHelpWeb.GoogleAuthControllerTest do
assert get_session(conn, :user_token)
end
test "does not create an account from the login-only flow", %{conn: conn} do
test "continues an unlinked Google user into account creation", %{conn: conn} do
email = unique_user_email()
conn =
@ -121,10 +126,119 @@ defmodule WhoNeedHelpWeb.GoogleAuthControllerTest do
~p"/auth/google/callback?code=code&state=google-test-state&uid=unknown-google&email=#{email}"
)
assert redirected_to(conn) == ~p"/users/log-in"
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "not connected"
assert redirected_to(conn) == ~p"/auth/google/complete"
refute Accounts.get_user_by_email(email)
refute get_session(conn, :user_token)
html = conn |> recycle() |> get(~p"/auth/google/complete") |> html_response(200)
assert html =~ "Create your Who Need Help account"
assert html =~ email
end
test "creates and links an unlinked Google user after terms acceptance", %{conn: conn} do
email = unique_user_email()
conn =
conn
|> post(~p"/auth/google/login")
|> recycle()
|> get(
~p"/auth/google/callback?code=code&state=google-test-state&uid=continue-google&email=#{email}&name=Continued%20Helper"
)
|> recycle()
|> post(~p"/auth/google/complete-registration", %{
"google_registration" => %{"locale" => "uk", "terms_accepted" => "true"}
})
assert redirected_to(conn) == ~p"/"
assert get_session(conn, :user_token)
user = Accounts.get_user_by_email(email)
assert user.confirmed_at
assert user.accepted_terms_at
assert user.locale == "uk"
assert user.display_name == "Continued Helper"
assert %AuthIdentity{user_id: user_id} =
Repo.get_by!(AuthIdentity, provider: :google, provider_uid: "continue-google")
assert user_id == user.id
end
test "does not create a continued Google account without accepting terms", %{conn: conn} do
email = unique_user_email()
conn =
conn
|> post(~p"/auth/google/login")
|> recycle()
|> get(
~p"/auth/google/callback?code=code&state=google-test-state&uid=no-terms-google&email=#{email}"
)
|> recycle()
|> post(~p"/auth/google/complete-registration", %{
"google_registration" => %{"locale" => "en", "terms_accepted" => "false"}
})
assert redirected_to(conn) == ~p"/auth/google/complete"
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "18 or older"
refute Accounts.get_user_by_email(email)
refute Repo.get_by(AuthIdentity, provider: :google, provider_uid: "no-terms-google")
end
test "links an existing account after one magic-link verification", %{conn: conn} do
user = user_fixture()
assert_email_sent()
conn =
conn
|> post(~p"/auth/google/login")
|> recycle()
|> get(
~p"/auth/google/callback?code=code&state=google-test-state&uid=verified-existing-google&email=#{user.email}"
)
|> recycle()
|> post(~p"/auth/google/verify-existing")
assert redirected_to(conn) == ~p"/users/log-in"
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "finish connecting Google"
assert_email_sent(fn email ->
email.subject == "Confirm Google sign-in" and
email.text_body =~ "connect Google to your Who Need Help account" and
email.text_body =~ "google_link=" and email.text_body =~ "#token="
end)
pending_token = get_session(conn, "pending_google_identity")
assert is_binary(pending_token)
{token, _hashed_token} = generate_user_magic_link_token(user)
conn =
build_conn()
|> get(~p"/users/log-in?google_link=#{pending_token}")
|> recycle()
|> post(~p"/users/log-in", %{"user" => %{"token" => token}})
assert redirected_to(conn) == ~p"/"
assert get_session(conn, :user_token)
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Google sign-in connected"
identity =
Repo.get_by!(AuthIdentity,
provider: :google,
provider_uid: "verified-existing-google"
)
assert identity.user_id == user.id
assert %AuditEvent{actor_id: actor_id, metadata: metadata} =
Repo.get_by!(AuditEvent,
action: "auth_identity.connected",
target_id: identity.id
)
assert actor_id == user.id
assert metadata["method"] == "verified_local_sign_in"
end
test "rejects unverified Google email and consumes the flow session", %{conn: conn} do

View File

@ -17,7 +17,7 @@ defmodule WhoNeedHelpWeb.UserSessionControllerTest do
assert response =~ "Log in"
assert response =~ ~p"/users/register"
assert response =~ "Email me a sign-in link"
assert response =~ "Sign in with Google"
assert response =~ "Continue with Google"
assert response =~ "Use a password instead"
assert response =~ ~s(id="magic-link-fragment-form")
assert response =~ ~s(hidden)