feat: add support and content removal workflows
Some checks are pending
Quality / full-local-gates (push) Waiting to run

This commit is contained in:
SimpleTest 2026-07-21 03:01:13 +03:00
parent 0a588182a0
commit e2ea2252bc
44 changed files with 5291 additions and 112 deletions

View File

@ -124,6 +124,8 @@ SMTP_TLS=never
SMTP_SSL=false
EMAIL_FROM_NAME="Who Need Help"
EMAIL_FROM_ADDRESS=contact@example.com
# Optional monitored inbox. It receives new-case alerts and is used as Reply-To.
SUPPORT_INBOX_ADDRESS=
CODEX_SESSION_ID=copy-the-main-local-codex-session-id
# Optional shared PostgreSQL-backed policies. Keep {} until product thresholds are approved.

View File

@ -34,6 +34,9 @@ thank-you link; money goes directly between users outside the platform.
- Bidirectional discovery blocks, scoped reports, account/request/category
moderation, abuse-signal review, and audited moderator access to only the
conversation linked by a report.
- Separate public support and content-removal intake, including moderation
appeals, account deletion/data requests, a URL-only TAKE IT DOWN form,
verified-contact status links, operator alerts, and audited staff queues.
- Optional GPS evidence derived from browser accuracy envelopes. Raw current
positions are deleted on stop, terminal match state, or participant block.
- PostgreSQL-backed cross-replica action-limit policies configured by the
@ -201,7 +204,11 @@ existing file:
Configure the verified reverse-proxy source IP/CIDR and transactional SMTP
provider in that file. Email registration and magic-link login are unusable for
real recipients until that relay and its accepted sender are configured.
real recipients until that relay and its accepted sender are configured. Set
the optional `SUPPORT_INBOX_ADDRESS` to a monitored mailbox to receive
metadata-only new-case alerts and make replies return to the support team; the
database queues continue to work when it is empty. See
[the support and content-removal runbook](docs/support-and-content-removal.md).
Then validate the file structure and the production Compose render:
```bash

View File

@ -26,6 +26,7 @@ x-app-environment: &app-environment
SMTP_SSL: ${SMTP_SSL:?Set SMTP_SSL in .env}
EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:?Set EMAIL_FROM_NAME in .env}
EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:?Set EMAIL_FROM_ADDRESS in .env}
SUPPORT_INBOX_ADDRESS: ${SUPPORT_INBOX_ADDRESS:-}
CODEX_SESSION_ID: ${CODEX_SESSION_ID:-not-configured}
RATE_LIMIT_POLICIES_JSON: ${RATE_LIMIT_POLICIES_JSON:-{}}
MAP_TILE_URL: ${MAP_TILE_URL:-https://tile.openstreetmap.org/{z}/{x}/{y}.png}

View File

@ -11,6 +11,8 @@ config :who_need_help, :mailer_from,
name: "Who Need Help",
address: "contact@example.com"
config :who_need_help, :support_inbox_address, nil
config :who_need_help, :scopes,
user: [
default: true,

View File

@ -444,6 +444,19 @@ if config_env() == :prod do
name: System.get_env("EMAIL_FROM_NAME", "Who Need Help"),
address: System.get_env("EMAIL_FROM_ADDRESS", "contact@example.com")
support_inbox_address =
case System.get_env("SUPPORT_INBOX_ADDRESS") do
value when value in [nil, ""] -> nil
value -> value
end
if support_inbox_address &&
not Regex.match?(~r/^[^@,;\s]+@[^@,;\s]+$/, support_inbox_address) do
raise "SUPPORT_INBOX_ADDRESS must be a single email address without spaces."
end
config :who_need_help, :support_inbox_address, support_inbox_address
config :who_need_help, WhoNeedHelp.Mailer, smtp_config
config :who_need_help, WhoNeedHelpWeb.Endpoint,

View File

@ -40,7 +40,8 @@ app:
# HANDOVER_SECRET, RELEASE_COOKIE, and METRICS_TOKEN. It may also contain both
# GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_CLIENT_SECRET to enable verified
# GitHub linking, and both GOOGLE_OAUTH_CLIENT_ID and
# GOOGLE_OAUTH_CLIENT_SECRET to enable Google registration/sign-in. Push is
# GOOGLE_OAUTH_CLIENT_SECRET to enable Google registration/sign-in. Optional
# SUPPORT_INBOX_ADDRESS enables metadata-only operator alerts and Reply-To. Push is
# opt-in: provide PUSH_HTTP_ENDPOINT,
# PUSH_HTTP_BEARER_TOKEN, PUSH_HTTP_MAX_ATTEMPTS,
# PUSH_HTTP_RECEIVE_TIMEOUT_MS, PUSH_HTTP_CONNECT_TIMEOUT_MS, and

View File

@ -71,7 +71,10 @@ do not copy the temporary VPN value into an unrelated server.
Configure the transactional SMTP relay and sender accepted by that provider.
Provider-specific auth, TLS, ports, and credentials can be supplied to the
initializer through the documented `PRODUCTION_SMTP_*` environment values or
edited in the resulting ignored file. If Google registration/sign-in is
edited in the resulting ignored file. Set optional `SUPPORT_INBOX_ADDRESS` to
a monitored address for support/removal queue alerts and email `Reply-To`;
leaving it empty disables operator email alerts, not the protected queues. If
Google registration/sign-in is
enabled, also set both Google Web client credentials and register
`https://YOUR_PHX_HOST/auth/google/callback` as the exact authorized redirect
URI. Leave both credentials empty to keep the feature disabled. Then run:

View File

@ -0,0 +1,137 @@
# Support and content-removal operations
Status: implemented intake and operator workflow. This document describes the
software behavior; it is not a legal opinion and does not establish that a
particular law applies to the operator.
## Separate queues
Who Need Help deliberately separates three mechanisms:
1. An authenticated in-product report targets exactly one request, assignment,
message, Activity, or Activity message and follows the existing audited
trust-and-safety workflow.
2. A support request covers account access, technical issues, safety concerns,
moderation appeals, privacy questions, data export, and account deletion.
3. A content-removal notice covers a precise item alleged to be illegal or to
infringe a right. TAKE IT DOWN notices have a dedicated public form and a
separate regime value in the removal queue.
The operator workspace is `/support/operations`. It is protected by the same
database-checked moderator or administrator authorization as the existing
moderation workspace. Every creation and decision records an audit event.
## Public routes
- `/support` — ordinary support.
- `/account/delete` — external account-deletion request path suitable for use
as the Google Play account-deletion web resource.
- `/legal/content-removal` — general electronic notice-and-action intake.
- `/legal/take-it-down` — dedicated intimate-visual-material removal intake.
The request and Activity screens link to the general form with the exact local
content URL prefilled. Only same-origin relative paths can be prefilled this
way. The server validates one complete HTTP or HTTPS URL per line and accepts
at most 20 locations in one notice.
## Contact verification and status access
Public submissions display a reference but never expose the signed status token
in the redirect. The private status link is sent to the contact email. Opening
it marks that contact address as verified. An authenticated submission uses the
confirmed account email and is verified immediately.
Email-link verification establishes access to the mailbox, not government
identity, authority to act for another person, or the truth of the claim.
Operators must perform any additional verification appropriate to the requested
action. In particular, an account-deletion request must not be fulfilled against
another person's account merely because an address was typed into the form.
Identity and contact fields may be omitted from a general report of sexual
material involving a minor. Such a report still receives an urgent queue state,
but no status email can be sent without a contact address.
## TAKE IT DOWN boundary
The dedicated form accepts exact URLs and textual identification only. It does
not accept file uploads and explicitly tells the submitter not to reproduce or
email the intimate image or video. A submitted notice is marked for urgent
review and records a review due time 48 hours after receipt.
The current product does not accept user-uploaded images or videos. The presence
of this preparedness workflow therefore does not claim that Who Need Help is a
covered platform, that a submitted item satisfies the statutory definition, or
that identical-copy detection exists. If media hosting is added, the operator
must review the then-current law, implement safe media hashing and
identical-copy handling where applicable, and test the entire removal path
before enabling uploads.
The primary US text currently requires a clear and conspicuous process and, for
a valid request to a covered platform, removal of the depiction plus reasonable
efforts concerning known identical copies as soon as possible and no later than
48 hours:
- <https://www.govinfo.gov/content/pkg/COMPS-18158/pdf/COMPS-18158.pdf>
## EU electronic notices
The general form captures the elements listed in Article 16 of Regulation (EU)
2022/2065: a reasoned explanation, exact electronic location, submitter name and
email subject to the child-sexual-abuse exception, and a good-faith accuracy
statement. It sends an acknowledgement when email is available and sends the
recorded decision after a verified-contact operator update.
- <https://eur-lex.europa.eu/eli/reg/2022/2065/oj/eng>
Product implementation alone does not determine the service's legal
classification, establishment, target markets, applicable national law, or
redress obligations. Those remain launch decisions requiring jurisdiction-
specific review.
## Email and operator notification
`EMAIL_FROM_ADDRESS` remains the outbound sender. Optional
`SUPPORT_INBOX_ADDRESS` has two separate effects:
- outgoing support/removal messages use it as `Reply-To`;
- it receives a metadata-only alert containing the reference, queue type, and
protected operator URL when a case is created.
The alert intentionally excludes the free-text report and reported URLs. The
full record remains in the protected database queue. If the variable is empty,
intake and reporter acknowledgement still work, but no operator inbox alert is
sent. The configured inbox must be monitored operationally; the application
cannot prove staffing or response availability.
## Account deletion and data export
The web application and Android WebView expose the account-deletion request from
account settings, and the public `/account/delete` route remains usable after an
app is uninstalled. The workflow verifies the contact and creates an audited
account-lifecycle request.
Actual erasure/anonymization and export are not automated because the operator
has not yet selected a jurisdiction-specific retention policy for safety,
fraud, disputes, and legal records. An operator must not mark a request resolved
until the applicable data action has actually been completed and communicated.
Before public launch, legal review must define which linked records are erased,
anonymized, or retained and for how long; only then should a destructive
execution routine be implemented and tested against backups and relational
constraints.
Google Play's current policy requires both an in-app path and an external web
resource when an app allows account creation:
- <https://support.google.com/googleplay/android-developer/answer/13327111?hl=en>
## Abuse controls and operational limits
`support_request` and `content_removal_notice` are supported names in the shared
PostgreSQL rate limiter. As with the other actions, no numeric policy is enabled
unless the operator supplies measured values through
`RATE_LIMIT_POLICIES_JSON`. CSRF protection, validation, exact URL limits,
contact verification, staff authorization, and audit events apply regardless.
The software does not provide emergency response. Threats to life or safety are
prioritized in the queue, while every public safety screen continues to direct
people in immediate danger to local emergency services.

View File

@ -135,3 +135,10 @@ requires an explicit one-time operational bootstrap, and later role changes are
audited; the last administrator cannot demote themselves.
The operator must publish jurisdiction-specific emergency contacts, privacy
notice, prohibited-items policy, and data-retention policy before public launch.
Public support and legal removal are separate from in-product reports. Support,
moderation appeals, privacy/data requests, general electronic removal notices,
and a dedicated TAKE IT DOWN intake are described in
`docs/support-and-content-removal.md`. Public contacts are verified through an
emailed private status link; moderator/admin decisions and access remain
audited. The removal forms never accept intimate-media uploads.

View File

@ -1,6 +1,6 @@
# Who Need Help — implementation verification
Observed through 2026-07-20 in the local workspace. This report separates observed
Observed through 2026-07-21 in the local workspace. This report separates observed
results from product limits and unknown production properties.
## Verified MVP capabilities
@ -18,6 +18,7 @@ results from product limits and unknown production properties.
| Reputation and anti-abuse | Implemented at MVP level | Handover codes, two-party completion, double-blind reviews, unique-counterpart ranking, optional movement/proximity evidence, reports, blocks, abuse signals, and moderator audit paths have automated tests. | The system is not bot-proof and does not claim identity verification. No punitive numeric policy is enabled without measured and approved thresholds. |
| Account registration and sign-in | Implemented and browser-verified | Email registration sends a confirmation magic link and does not require a password. Confirmed users can keep using magic links or add a password in settings. Google OpenID Connect registration, sign-in, link, unlink, replay prevention, verified-email enforcement, and account-ownership rules are covered by the 260-test suite. A headed Chrome run completed registration, confirmation through Mailpit, password setup, logout, password login, and localized settings with zero console warnings or errors. | The local Compose environment captures email in Mailpit. A production SMTP relay and a real Google Web client are not configured or externally verified. |
| Social profiles | Manual links implemented; optional GitHub verification implemented and automated-tested | Manual links cannot set verification fields. The optional GitHub flow uses state, PKCE, a user-bound one-time session, unique provider ownership, and an audit record. The local protocol drill also performs real HTTP token/user exchanges without returning an access token to the application. | GitHub OAuth credentials are intentionally absent and are not required for registration or the help flow. The real external provider redirect/callback remains disabled and unverified; other providers remain manual/unverified. |
| Support and content removal | Implemented and browser-verified | Public support, account deletion, general removal, and TAKE IT DOWN forms create separate audited queues; private email status links verify public contacts; authenticated submissions use the account email; moderator-only operations can update status and notify verified contacts. TAKE IT DOWN accepts URLs/text only and records a 48-hour review due time. | The current product hosts no user media and does not claim TAKE IT DOWN coverage. Staffing, jurisdiction-specific legal classification, final retention rules, actual account erasure/export, and identical-media-copy handling remain operational/legal work. |
| Voluntary thanks | Implemented as an external optional link | A helper can expose an optional link after completion; the UI states that the platform does not process the payment. | The platform does not provide payments, escrow, refunds, tax reporting, or payment guarantees. |
| Android client | Local and public-staging clients implemented and emulator-verified | The native packages `org.whoneedhelp.mobile.debug` and `org.whoneedhelp.mobile.staging` launch the same authenticated LiveView app. Seven lifecycle, permission, deep-link, foreground tracking, recoverable main-page failure, notification-Stop, and Activity-destruction tests passed on each of API 30, 34, and 37. The API 37 staging smoke asserted the public home and Safety DOM over HTTPS. A run-scoped Android/browser staging test passed login, private chat in both directions, foreground tracking, live marker appearance/removal, and exact cleanup. | Production signing, Play Store publication, verified Android App Links, unattended/background-permission tracking, and iOS are not implemented. |
| Multiple web/worker instances | Implemented and locally failure/rollout-verified | The final isolated Compose drill passed BEAM crashes and sequential replacement with 3 web/2 worker replicas: all five nodes joined, PubSub passed, and 744/744 readiness requests succeeded. The project-owned kind cluster replaced all 2 web/2 worker pod UIDs under `maxUnavailable=0`; all four replacement pods joined, PubSub passed, and 363/363 samples ultimately succeeded. | Local PostGIS is a single instance. Production database HA, backups, and recovery are operator work and are not claimed complete. |
@ -27,6 +28,16 @@ results from product limits and unknown production properties.
## Reproducible checks
- On 2026-07-21, `./scripts/test.sh` and the Dockerized `mix precommit` each
passed 273 tests after the support/content-removal implementation. The full
isolated `./scripts/quality.sh` gate passed compiler, xref, Credo, Sobelow,
Dialyzer, Hex/npm audits, Compose/Helm validation, and configured source/image
scans. Headed Chrome over `https://whoneedhelp.imalto.site` verified public
support acknowledgement and contact verification, general removal intake,
the separate urgent TAKE IT DOWN form and 48-hour due time, passwordless
account confirmation, admin-only queues, audited operator response email,
account-deletion navigation, Russian localization, selected-status
preservation, and zero browser-console errors or warnings.
- On 2026-07-20, after adding Google OpenID Connect authentication,
`./scripts/test.sh` and `mix precommit` each passed 260 tests with zero
failures. The full isolated `./scripts/quality.sh` gate also passed format,
@ -1115,10 +1126,12 @@ availability, or target-server capacity.
autoscaling, and action-limit policies.
- Publish jurisdiction-specific emergency contacts, privacy, retention,
prohibited-items, and voluntary-payment guidance after legal review.
- The current UI has no self-service account deletion or data-export flow.
Decide the retention/anonymization behavior, implement the selected control,
and verify it before promising that capability to users.
- Establish moderation/support operations and incident response for real users.
- The UI now has authenticated and external account-deletion/data-request
intake, contact verification, case status, and an audited operator queue.
Actual erasure/anonymization and export remain manual until a legally reviewed
retention policy defines the treatment of linked safety and dispute records.
- Staff and monitor the implemented moderation/support queues and establish an
incident-response/on-call process for real users.
- If verified GitHub identity is desired, create and configure its OAuth App and
exercise the external redirect/callback. This is an optional enhancement, not
a registration or launch blocker.

View File

@ -0,0 +1,256 @@
defmodule WhoNeedHelp.ContentRemoval do
@moduledoc "Separate intake and review queue for electronic content-removal notices."
import Ecto.Query
alias WhoNeedHelp.Accounts
alias WhoNeedHelp.Accounts.{Scope, User}
alias WhoNeedHelp.ContentRemoval.{Notice, Notifier}
alias WhoNeedHelp.Pagination
alias WhoNeedHelp.Repo
alias WhoNeedHelp.Trust
alias WhoNeedHelp.Trust.RateLimiter
@access_salt "content-removal-access"
@urgent_categories [
:non_consensual_intimate_media,
:child_sexual_abuse_material,
:threat_to_life_or_safety
]
def change_notice(%Notice{} = notice, attrs \\ %{}) do
Notice.submission_changeset(notice, attrs)
end
def create_notice(scope, regime, attrs) when regime in [:general, :dsa, :take_it_down] do
user = scope_user(scope)
attrs = normalize_keys(attrs)
attrs = maybe_use_user_email(attrs, user)
category = enum_value(Notice, :category, attrs["category"])
status = if category in @urgent_categories, do: :urgent_review, else: :open
response_due_at =
if regime == :take_it_down, do: DateTime.add(DateTime.utc_now(:second), 48, :hour)
with {:ok, _limit} <-
RateLimiter.check(:content_removal_notice, rate_scope(user, attrs["contact_email"])) do
Repo.transact(fn ->
with {:ok, notice} <-
%Notice{
reference: unique_reference(),
regime: regime,
status: status,
response_due_at: response_due_at,
requester_id: user && user.id,
contact_verified_at: user && DateTime.utc_now(:second)
}
|> Notice.submission_changeset(attrs)
|> Repo.insert(),
{:ok, _audit} <-
Trust.audit(
user && user.id,
"content_removal_notice.created",
"content_removal_notice",
notice.id,
%{
"category" => to_string(notice.category),
"regime" => to_string(notice.regime),
"status" => to_string(notice.status)
}
) do
{:ok, notice}
end
end)
|> notify_received()
end
end
def list_for_user(%Scope{user: %User{id: user_id}}) do
Notice
|> where([notice], notice.requester_id == ^user_id)
|> order_by([notice], desc: notice.inserted_at, desc: notice.id)
|> Repo.all()
end
def get_by_access_token(id, token) when is_binary(token) do
with {:ok, id} <- Ecto.UUID.cast(id),
{:ok, ^id} <-
Phoenix.Token.verify(WhoNeedHelpWeb.Endpoint, @access_salt, token, max_age: 31_536_000),
%Notice{} = notice <- Repo.get(Notice, id) do
verify_contact(notice)
else
_ -> {:error, :not_found}
end
end
def get_by_access_token(_id, _token), do: {:error, :not_found}
def access_token(%Notice{id: id}) do
Phoenix.Token.sign(WhoNeedHelpWeb.Endpoint, @access_salt, id)
end
def status_url(%Notice{} = notice) do
token = access_token(notice)
WhoNeedHelpWeb.Endpoint.url() <>
"/legal/content-removal/#{notice.id}?token=#{URI.encode_www_form(token)}"
end
def paginate_for_staff(%Scope{user: user}, options \\ []) do
if Accounts.moderator_authorized?(user) do
limit = Pagination.limit(options)
cursor = Pagination.cursor(options)
Notice
|> maybe_regime(Keyword.get(options, :regime))
|> before(cursor)
|> order_by([notice], desc: notice.inserted_at, desc: notice.id)
|> limit(^(limit + 1))
|> preload([:requester, :reviewed_by])
|> Repo.all()
|> Pagination.page(limit, &{&1.inserted_at, &1.id})
else
%Pagination.Page{}
end
end
def moderate(%Scope{user: moderator}, id, attrs) do
with {:ok, id} <- Ecto.UUID.cast(id),
true <- Accounts.moderator_authorized?(moderator) do
attrs =
attrs
|> normalize_keys()
|> Map.merge(%{
"reviewed_at" => DateTime.utc_now(:second),
"reviewed_by_id" => moderator.id
})
Repo.transact(fn ->
notice =
Notice
|> where([notice], notice.id == ^id)
|> lock("FOR UPDATE")
|> Repo.one()
if notice do
with {:ok, notice} <- notice |> Notice.moderation_changeset(attrs) |> Repo.update(),
{:ok, _audit} <-
Trust.audit(
moderator.id,
"content_removal_notice.moderated",
"content_removal_notice",
notice.id,
%{
"status" => to_string(notice.status)
}
) do
{:ok, notice}
end
else
{:error, :not_found}
end
end)
|> notify_decision()
else
false -> {:error, :forbidden}
_ -> {:error, :not_found}
end
end
defp notify_received({:ok, %Notice{contact_email: email} = notice}) when email in [nil, ""],
do: notify_operator(notice)
defp notify_received({:ok, notice}) do
result =
case Notifier.deliver_received(notice, status_url(notice)) do
{:ok, _metadata} ->
notice
|> Ecto.Changeset.change(acknowledgement_sent_at: DateTime.utc_now(:second))
|> Repo.update()
_error ->
{:ok, notice}
end
case result do
{:ok, current} -> notify_operator(current)
error -> error
end
end
defp notify_received(result), do: result
defp notify_operator(notice) do
_ = Notifier.deliver_operator_alert(notice)
{:ok, notice}
end
defp notify_decision({:ok, %Notice{contact_verified_at: nil} = notice}), do: {:ok, notice}
defp notify_decision({:ok, notice}) do
case Notifier.deliver_decision(notice, status_url(notice)) do
{:ok, _metadata} ->
notice
|> Ecto.Changeset.change(decision_sent_at: DateTime.utc_now(:second))
|> Repo.update()
_error ->
{:ok, notice}
end
end
defp notify_decision(result), do: result
defp verify_contact(%Notice{contact_verified_at: nil} = notice) do
notice
|> Ecto.Changeset.change(contact_verified_at: DateTime.utc_now(:second))
|> Repo.update()
end
defp verify_contact(%Notice{} = notice), do: {:ok, notice}
defp before(query, nil), do: query
defp before(query, {inserted_at, id}) do
where(
query,
[notice],
notice.inserted_at < ^inserted_at or
(notice.inserted_at == ^inserted_at and notice.id < ^id)
)
end
defp maybe_regime(query, nil), do: query
defp maybe_regime(query, regime), do: where(query, [notice], notice.regime == ^regime)
defp maybe_use_user_email(attrs, %User{email: email}) do
Map.put(attrs, "contact_email", email)
end
defp maybe_use_user_email(attrs, nil), do: attrs
defp rate_scope(%User{id: id}, _email), do: "user:#{id}"
defp rate_scope(nil, email) when is_binary(email),
do: "email:#{String.downcase(String.trim(email))}"
defp rate_scope(nil, _email), do: "missing-email"
defp scope_user(%Scope{user: %User{} = user}), do: user
defp scope_user(_scope), do: nil
defp enum_value(module, field, value) do
Ecto.Enum.cast_value(module, field, value)
|> case do
{:ok, enum} -> enum
:error -> nil
end
end
defp unique_reference do
suffix = 8 |> :crypto.strong_rand_bytes() |> Base.encode32(case: :upper, padding: false)
"REM-#{suffix}"
end
defp normalize_keys(attrs), do: Map.new(attrs, fn {key, value} -> {to_string(key), value} end)
end

View File

@ -0,0 +1,177 @@
defmodule WhoNeedHelp.ContentRemoval.Notice do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "content_removal_notices" do
field :reference, :string
field :regime, Ecto.Enum,
values: [:general, :dsa, :take_it_down],
default: :general
field :category, Ecto.Enum,
values: [
:illegal_content,
:privacy_violation,
:copyright,
:impersonation,
:non_consensual_intimate_media,
:child_sexual_abuse_material,
:threat_to_life_or_safety,
:other
]
field :status, Ecto.Enum,
values: [
:open,
:urgent_review,
:reviewing,
:needs_information,
:actioned,
:rejected,
:closed
],
default: :open
field :submitter_name, :string
field :contact_email, :string
field :relationship, Ecto.Enum, values: [:self, :authorized_representative, :other]
field :content_locations, :string
field :explanation, :string
field :legal_basis, :string
field :contact_verified_at, :utc_datetime
field :good_faith, :boolean, default: false
field :accurate_complete, :boolean, default: false
field :electronic_signature, :string
field :resolution_note, :string
field :reviewed_at, :utc_datetime
field :response_due_at, :utc_datetime
field :acknowledgement_sent_at, :utc_datetime
field :decision_sent_at, :utc_datetime
belongs_to :requester, WhoNeedHelp.Accounts.User
belongs_to :reviewed_by, WhoNeedHelp.Accounts.User
timestamps(type: :utc_datetime)
end
def submission_changeset(notice, attrs) do
notice
|> cast(attrs, [
:category,
:submitter_name,
:contact_email,
:relationship,
:content_locations,
:explanation,
:legal_basis,
:good_faith,
:accurate_complete,
:electronic_signature
])
|> validate_required([
:category,
:content_locations,
:explanation,
:reference,
:regime
])
|> update_change(:contact_email, &normalize_email/1)
|> validate_format(:contact_email, ~r/^[^@,;\s]+@[^@,;\s]+$/,
message: "must have the @ sign and no spaces"
)
|> validate_length(:submitter_name, min: 2, max: 160)
|> validate_length(:contact_email, max: 160)
|> validate_length(:content_locations, min: 5, max: 10_000)
|> validate_length(:explanation, min: 20, max: 10_000)
|> validate_length(:legal_basis, max: 2_000)
|> validate_length(:electronic_signature, min: 2, max: 160)
|> validate_acceptance(:good_faith,
message: "you must confirm your good-faith belief"
)
|> validate_acceptance(:accurate_complete,
message: "you must confirm that the notice is accurate and complete"
)
|> validate_identity_requirements()
|> validate_content_locations()
|> validate_take_it_down_category()
|> unique_constraint(:reference)
end
def moderation_changeset(notice, attrs) do
notice
|> cast(attrs, [:status, :resolution_note, :reviewed_at, :reviewed_by_id, :decision_sent_at])
|> validate_required([:status, :reviewed_at, :reviewed_by_id])
|> validate_length(:resolution_note, max: 10_000)
end
def content_urls(%__MODULE__{content_locations: locations}) when is_binary(locations) do
locations
|> String.split(~r/[\r\n]+/, trim: true)
|> Enum.map(&String.trim/1)
end
def content_urls(_notice), do: []
defp validate_content_locations(changeset) do
validate_change(changeset, :content_locations, fn :content_locations, locations ->
urls = locations |> String.split(~r/[\r\n]+/, trim: true) |> Enum.map(&String.trim/1)
cond do
urls == [] ->
[content_locations: "must contain at least one exact URL"]
length(urls) > 20 ->
[content_locations: "cannot contain more than 20 URLs"]
Enum.any?(urls, &(not valid_http_url?(&1))) ->
[content_locations: "must contain one full HTTP or HTTPS URL per line"]
true ->
[]
end
end)
end
defp validate_take_it_down_category(changeset) do
if get_field(changeset, :regime) == :take_it_down and
get_field(changeset, :category) not in [
:non_consensual_intimate_media,
:child_sexual_abuse_material
] do
add_error(changeset, :category, "must describe intimate visual material")
else
changeset
end
end
defp validate_identity_requirements(changeset) do
if get_field(changeset, :category) == :child_sexual_abuse_material and
get_field(changeset, :regime) != :take_it_down do
changeset
else
validate_required(changeset, [
:submitter_name,
:contact_email,
:relationship,
:electronic_signature
])
end
end
defp valid_http_url?(value) do
case URI.parse(value) do
%URI{scheme: scheme, host: host}
when scheme in ["http", "https"] and is_binary(host) and host != "" ->
true
_ ->
false
end
end
defp normalize_email(email), do: email |> String.trim() |> String.downcase()
end

View File

@ -0,0 +1,91 @@
defmodule WhoNeedHelp.ContentRemoval.Notifier do
import Swoosh.Email
alias WhoNeedHelp.ContentRemoval.Notice
alias WhoNeedHelp.Mailer
def deliver_received(%Notice{contact_email: email} = notice, status_url)
when is_binary(email) and email != "" do
deliver(
email,
"Who Need Help removal notice #{notice.reference}",
"""
We received removal notice #{notice.reference}.
Status: #{notice.status}
View the current status:
#{status_url}
Do not reply with or upload intimate visual material. If someone is in immediate danger,
contact the emergency service for their location.
"""
)
end
def deliver_received(%Notice{}, _status_url), do: {:ok, :no_contact_email}
def deliver_decision(%Notice{contact_email: email} = notice, status_url)
when is_binary(email) and email != "" do
deliver(
email,
"Who Need Help removal notice update #{notice.reference}",
"""
Removal notice #{notice.reference} was updated.
Status: #{notice.status}
Decision or request for information:
#{notice.resolution_note || "No additional response was provided."}
View the current status:
#{status_url}
"""
)
end
def deliver_decision(%Notice{}, _status_url), do: {:ok, :no_contact_email}
def deliver_operator_alert(%Notice{} = notice) do
case Application.get_env(:who_need_help, :support_inbox_address) do
address when is_binary(address) and address != "" ->
urgency = if notice.status == :urgent_review, do: "URGENT: ", else: ""
deliver(
address,
"#{urgency}New removal notice #{notice.reference}",
"""
A new #{notice.regime} content-removal notice is waiting for review.
Reference: #{notice.reference}
Category: #{notice.category}
Review due: #{notice.response_due_at || "no statutory deadline recorded"}
Operator queue: #{WhoNeedHelpWeb.Endpoint.url()}/support/operations
Do not request the submitter to email or upload intimate visual material.
"""
)
_other ->
{:ok, :not_configured}
end
end
defp deliver(recipient, subject, body) do
from = Application.fetch_env!(:who_need_help, :mailer_from)
new()
|> to(recipient)
|> from({from[:name], from[:address]})
|> maybe_reply_to()
|> subject(subject)
|> text_body(body)
|> Mailer.deliver()
end
defp maybe_reply_to(email) do
case Application.get_env(:who_need_help, :support_inbox_address) do
address when is_binary(address) and address != "" -> reply_to(email, address)
_other -> email
end
end
end

View File

@ -0,0 +1,227 @@
defmodule WhoNeedHelp.Support do
@moduledoc "Public and authenticated support, privacy, and account-lifecycle requests."
import Ecto.Query
alias WhoNeedHelp.Accounts
alias WhoNeedHelp.Accounts.{Scope, User}
alias WhoNeedHelp.Pagination
alias WhoNeedHelp.Repo
alias WhoNeedHelp.Support.{Notifier, SupportRequest}
alias WhoNeedHelp.Trust
alias WhoNeedHelp.Trust.RateLimiter
@access_salt "support-request-access"
def change_request(%SupportRequest{} = request, attrs \\ %{}) do
SupportRequest.submission_changeset(request, attrs)
end
def create_request(scope, attrs) when is_map(attrs) do
user = scope_user(scope)
attrs = normalize_keys(attrs)
contact_email = if user, do: user.email, else: attrs["contact_email"]
attrs = Map.put(attrs, "contact_email", contact_email)
with {:ok, _limit} <- RateLimiter.check(:support_request, rate_scope(user, contact_email)) do
Repo.transact(fn ->
with {:ok, request} <-
%SupportRequest{
reference: unique_reference("SUP"),
requester_id: user && user.id,
contact_verified_at: user && DateTime.utc_now(:second)
}
|> SupportRequest.submission_changeset(attrs)
|> Repo.insert(),
{:ok, _audit} <-
Trust.audit(
user && user.id,
"support_request.created",
"support_request",
request.id,
%{
"kind" => to_string(request.kind)
}
) do
{:ok, request}
end
end)
|> notify_received()
end
end
def create_account_deletion_request(%Scope{user: %User{}} = scope, details \\ nil) do
create_request(scope, %{
"kind" => "account_deletion",
"subject" => "Delete my Who Need Help account",
"details" => details || "Please delete my account and associated personal data."
})
end
def list_for_user(%Scope{user: %User{id: user_id}}) do
SupportRequest
|> where([request], request.requester_id == ^user_id)
|> order_by([request], desc: request.inserted_at, desc: request.id)
|> Repo.all()
end
def get_for_user(%Scope{user: %User{id: user_id}}, id) do
with {:ok, id} <- Ecto.UUID.cast(id),
%SupportRequest{} = request <-
Repo.get_by(SupportRequest, id: id, requester_id: user_id) do
{:ok, request}
else
_ -> {:error, :not_found}
end
end
def get_by_access_token(id, token) when is_binary(token) do
with {:ok, id} <- Ecto.UUID.cast(id),
{:ok, ^id} <-
Phoenix.Token.verify(WhoNeedHelpWeb.Endpoint, @access_salt, token, max_age: 31_536_000),
%SupportRequest{} = request <- Repo.get(SupportRequest, id) do
verify_contact(request)
else
_ -> {:error, :not_found}
end
end
def get_by_access_token(_id, _token), do: {:error, :not_found}
def access_token(%SupportRequest{id: id}) do
Phoenix.Token.sign(WhoNeedHelpWeb.Endpoint, @access_salt, id)
end
def status_url(%SupportRequest{} = request) do
token = access_token(request)
WhoNeedHelpWeb.Endpoint.url() <>
"/support/cases/#{request.id}?token=#{URI.encode_www_form(token)}"
end
def paginate_for_staff(%Scope{user: user}, options \\ []) do
if Accounts.moderator_authorized?(user) do
limit = Pagination.limit(options)
cursor = Pagination.cursor(options)
SupportRequest
|> maybe_kind(Keyword.get(options, :kind))
|> before(cursor)
|> order_by([request], desc: request.inserted_at, desc: request.id)
|> limit(^(limit + 1))
|> preload([:requester, :reviewed_by])
|> Repo.all()
|> Pagination.page(limit, &{&1.inserted_at, &1.id})
else
%Pagination.Page{}
end
end
def moderate(%Scope{user: moderator}, id, attrs) do
with {:ok, id} <- Ecto.UUID.cast(id),
true <- Accounts.moderator_authorized?(moderator) do
attrs =
attrs
|> normalize_keys()
|> Map.merge(%{
"reviewed_at" => DateTime.utc_now(:second),
"reviewed_by_id" => moderator.id
})
Repo.transact(fn ->
request =
SupportRequest
|> where([request], request.id == ^id)
|> lock("FOR UPDATE")
|> Repo.one()
if request do
with {:ok, request} <-
request |> SupportRequest.moderation_changeset(attrs) |> Repo.update(),
{:ok, _audit} <-
Trust.audit(
moderator.id,
"support_request.moderated",
"support_request",
request.id,
%{
"status" => to_string(request.status)
}
) do
{:ok, request}
end
else
{:error, :not_found}
end
end)
|> notify_decision()
else
false -> {:error, :forbidden}
_ -> {:error, :not_found}
end
end
defp notify_received({:ok, request}) do
_ = Notifier.deliver_received(request, status_url(request))
_ = Notifier.deliver_operator_alert(request)
{:ok, request}
end
defp notify_received(result), do: result
defp notify_decision({:ok, %SupportRequest{contact_verified_at: nil} = request}),
do: {:ok, request}
defp notify_decision({:ok, request}) do
case Notifier.deliver_decision(request, status_url(request)) do
{:ok, _metadata} ->
request
|> Ecto.Changeset.change(response_sent_at: DateTime.utc_now(:second))
|> Repo.update()
_error ->
{:ok, request}
end
end
defp notify_decision(result), do: result
defp verify_contact(%SupportRequest{contact_verified_at: nil} = request) do
request
|> Ecto.Changeset.change(contact_verified_at: DateTime.utc_now(:second))
|> Repo.update()
end
defp verify_contact(%SupportRequest{} = request), do: {:ok, request}
defp before(query, nil), do: query
defp before(query, {inserted_at, id}) do
where(
query,
[request],
request.inserted_at < ^inserted_at or
(request.inserted_at == ^inserted_at and request.id < ^id)
)
end
defp maybe_kind(query, nil), do: query
defp maybe_kind(query, kind), do: where(query, [request], request.kind == ^kind)
defp rate_scope(%User{id: id}, _email), do: "user:#{id}"
defp rate_scope(nil, email) when is_binary(email),
do: "email:#{String.downcase(String.trim(email))}"
defp rate_scope(nil, _email), do: "missing-email"
defp scope_user(%Scope{user: %User{} = user}), do: user
defp scope_user(_scope), do: nil
defp unique_reference(prefix) do
suffix = 8 |> :crypto.strong_rand_bytes() |> Base.encode32(case: :upper, padding: false)
"#{prefix}-#{suffix}"
end
defp normalize_keys(attrs), do: Map.new(attrs, fn {key, value} -> {to_string(key), value} end)
end

View File

@ -0,0 +1,81 @@
defmodule WhoNeedHelp.Support.Notifier do
import Swoosh.Email
alias WhoNeedHelp.Mailer
alias WhoNeedHelp.Support.SupportRequest
def deliver_received(%SupportRequest{} = request, status_url) do
deliver(
request.contact_email,
"Who Need Help support request #{request.reference}",
"""
We received your support request #{request.reference}.
Subject: #{request.subject}
Status: #{request.status}
View the current status:
#{status_url}
If there is immediate danger, contact the emergency service for your location.
"""
)
end
def deliver_decision(%SupportRequest{} = request, status_url) do
deliver(
request.contact_email,
"Who Need Help support update #{request.reference}",
"""
Your support request #{request.reference} was updated.
Status: #{request.status}
Response:
#{request.resolution_note || "No additional response was provided."}
View the current status:
#{status_url}
"""
)
end
def deliver_operator_alert(%SupportRequest{} = request) do
case Application.get_env(:who_need_help, :support_inbox_address) do
address when is_binary(address) and address != "" ->
deliver(
address,
"New support request #{request.reference}",
"""
A new #{request.kind} support request is waiting for review.
Reference: #{request.reference}
Operator queue: #{WhoNeedHelpWeb.Endpoint.url()}/support/operations
Sign in with an authorised moderator or administrator account to review it.
"""
)
_other ->
{:ok, :not_configured}
end
end
defp deliver(recipient, subject, body) do
from = Application.fetch_env!(:who_need_help, :mailer_from)
new()
|> to(recipient)
|> from({from[:name], from[:address]})
|> maybe_reply_to()
|> subject(subject)
|> text_body(body)
|> Mailer.deliver()
end
defp maybe_reply_to(email) do
case Application.get_env(:who_need_help, :support_inbox_address) do
address when is_binary(address) and address != "" -> reply_to(email, address)
_other -> email
end
end
end

View File

@ -0,0 +1,61 @@
defmodule WhoNeedHelp.Support.SupportRequest do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "support_requests" do
field :reference, :string
field :kind, Ecto.Enum,
values: [
:account_access,
:technical_issue,
:safety_concern,
:moderation_appeal,
:account_deletion,
:data_export,
:privacy_request,
:other
]
field :status, Ecto.Enum,
values: [:open, :reviewing, :waiting_for_requester, :resolved, :closed],
default: :open
field :contact_email, :string
field :subject, :string
field :details, :string
field :contact_verified_at, :utc_datetime
field :resolution_note, :string
field :reviewed_at, :utc_datetime
field :response_sent_at, :utc_datetime
belongs_to :requester, WhoNeedHelp.Accounts.User
belongs_to :reviewed_by, WhoNeedHelp.Accounts.User
timestamps(type: :utc_datetime)
end
def submission_changeset(request, attrs) do
request
|> cast(attrs, [:kind, :contact_email, :subject, :details])
|> validate_required([:kind, :contact_email, :subject, :details, :reference])
|> update_change(:contact_email, &normalize_email/1)
|> validate_format(:contact_email, ~r/^[^@,;\s]+@[^@,;\s]+$/,
message: "must have the @ sign and no spaces"
)
|> validate_length(:contact_email, max: 160)
|> validate_length(:subject, min: 3, max: 160)
|> validate_length(:details, min: 10, max: 5_000)
|> unique_constraint(:reference)
end
def moderation_changeset(request, attrs) do
request
|> cast(attrs, [:status, :resolution_note, :reviewed_at, :reviewed_by_id, :response_sent_at])
|> validate_required([:status, :reviewed_at, :reviewed_by_id])
|> validate_length(:resolution_note, max: 5_000)
end
defp normalize_email(email), do: email |> String.trim() |> String.downcase()
end

View File

@ -144,6 +144,10 @@ defmodule WhoNeedHelpWeb.Layouts do
<footer class="border-t border-base-300 px-4 py-6 text-center text-xs text-base-content/70">
<.link href={~p"/safety"} class="link">{gettext("Safety rules")}</.link>
<span class="mx-2">·</span>
<.link href={~p"/support"} class="link">{gettext("Support")}</.link>
<span class="mx-2">·</span>
<.link href={~p"/legal/content-removal"} class="link">{gettext("Report content")}</.link>
<span class="mx-2">·</span>
<.link href={~p"/feedback"} class="link">{gettext("Build Week feedback")}</.link>
</footer>
@ -181,6 +185,11 @@ defmodule WhoNeedHelpWeb.Layouts do
{gettext("Moderation")}
</.link>
</li>
<li :if={@current_scope && @current_scope.user.role in [:moderator, :admin]}>
<.link navigate={~p"/support/operations"} class={["btn-warning", @link_class]}>
{gettext("Support queue")}
</.link>
</li>
"""
end

View File

@ -0,0 +1,103 @@
defmodule WhoNeedHelpWeb.ContentRemovalController do
use WhoNeedHelpWeb, :controller
alias WhoNeedHelp.ContentRemoval
alias WhoNeedHelp.ContentRemoval.Notice
def new(conn, params) do
attrs =
case internal_location(params["location"]) do
nil -> %{}
location -> %{"content_locations" => location}
end
render_form(conn, :general, %Notice{}, attrs)
end
def take_it_down(conn, _params), do: render_form(conn, :take_it_down, %Notice{}, %{})
def create(conn, %{"notice" => params}) when is_map(params),
do: create_notice(conn, :general, params)
def create(conn, _params), do: send_resp(conn, :bad_request, "Bad Request")
def create_take_it_down(conn, %{"notice" => params}) when is_map(params),
do: create_notice(conn, :take_it_down, params)
def create_take_it_down(conn, _params),
do: send_resp(conn, :bad_request, "Bad Request")
def show(conn, %{"id" => id, "token" => token}) do
case ContentRemoval.get_by_access_token(id, token) do
{:ok, notice} -> render(conn, :show, notice: notice)
{:error, :not_found} -> send_resp(conn, :not_found, "Not found")
end
end
def show(conn, _params), do: send_resp(conn, :not_found, "Not found")
defp create_notice(conn, regime, params) do
case ContentRemoval.create_notice(conn.assigns.current_scope, regime, params) do
{:ok, notice} ->
redirect(conn,
to: ~p"/legal/content-removal/received?reference=#{notice.reference}"
)
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render_form(regime, changeset, params)
{:error, :rate_limited} ->
conn
|> put_status(:too_many_requests)
|> put_flash(:error, gettext("Too many removal notices. Please try again later."))
|> render_form(regime, %Notice{}, params)
end
end
def received(conn, %{"reference" => reference}) when is_binary(reference) do
render(conn, :received, reference: String.slice(reference, 0, 64))
end
def received(conn, _params), do: redirect(conn, to: ~p"/legal/content-removal")
defp render_form(conn, regime, %Ecto.Changeset{} = changeset, _attrs) do
render(conn, form_template(regime),
form: Phoenix.Component.to_form(changeset, as: :notice),
contact_email: current_email(conn)
)
end
defp render_form(conn, regime, %Notice{} = notice, attrs) do
attrs = with_contact_email(conn, attrs)
notice = %{notice | regime: regime}
changeset = ContentRemoval.change_notice(notice, attrs)
render_form(conn, regime, changeset, attrs)
end
defp form_template(:take_it_down), do: :take_it_down
defp form_template(_regime), do: :new
defp with_contact_email(conn, attrs) do
case current_email(conn) do
nil -> attrs
email -> Map.put(attrs, "contact_email", email)
end
end
defp current_email(%{assigns: %{current_scope: %{user: %{email: email}}}}), do: email
defp current_email(_conn), do: nil
defp internal_location(value) when is_binary(value) do
uri = URI.parse(value)
if uri.scheme == nil and uri.host == nil and is_binary(uri.path) and
String.starts_with?(uri.path, "/") and not String.starts_with?(uri.path, "//") and
not String.contains?(value, ["\r", "\n"]) do
WhoNeedHelpWeb.Endpoint.url() <> value
end
end
defp internal_location(_value), do: nil
end

View File

@ -0,0 +1,29 @@
defmodule WhoNeedHelpWeb.ContentRemovalHTML do
use WhoNeedHelpWeb, :html
embed_templates "content_removal_html/*"
def category_label(:illegal_content), do: gettext("Illegal content")
def category_label(:privacy_violation), do: gettext("Privacy violation")
def category_label(:copyright), do: gettext("Copyright")
def category_label(:impersonation), do: gettext("Impersonation")
def category_label(:non_consensual_intimate_media),
do: gettext("Non-consensual intimate image or video")
def category_label(:child_sexual_abuse_material),
do: gettext("Sexual material involving a minor")
def category_label(:threat_to_life_or_safety), do: gettext("Threat to life or safety")
def category_label(:other), do: gettext("Other")
def category_label(value), do: to_string(value)
def status_label(:open), do: gettext("Open")
def status_label(:urgent_review), do: gettext("Urgent review")
def status_label(:reviewing), do: gettext("Reviewing")
def status_label(:needs_information), do: gettext("More information needed")
def status_label(:actioned), do: gettext("Action taken")
def status_label(:rejected), do: gettext("Rejected")
def status_label(:closed), do: gettext("Closed")
def status_label(value), do: to_string(value)
end

View File

@ -0,0 +1,100 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-2xl">
<div class="text-sm font-semibold text-error">{gettext("CONTENT REMOVAL")}</div>
<h1 class="mt-2 text-4xl font-black">{gettext("Report illegal or harmful content")}</h1>
<p class="mt-3 text-base-content/65">
{gettext(
"Use this electronic notice for specific content on Who Need Help that you believe is illegal or infringes your rights. Ordinary safety reports inside a request or chat remain available to signed-in users."
)}
</p>
<div class="alert alert-info mt-5 text-sm">
{gettext(
"Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information."
)}
</div>
<.form for={@form} action={~p"/legal/content-removal"} class="mt-8 space-y-4">
<.input
field={@form[:category]}
type="select"
label={gettext("Reason")}
options={[
{gettext("Illegal content"), "illegal_content"},
{gettext("Privacy violation"), "privacy_violation"},
{gettext("Copyright"), "copyright"},
{gettext("Impersonation"), "impersonation"},
{gettext("Non-consensual intimate image or video"), "non_consensual_intimate_media"},
{gettext("Sexual material involving a minor"), "child_sexual_abuse_material"},
{gettext("Threat to life or safety"), "threat_to_life_or_safety"},
{gettext("Other"), "other"}
]}
prompt={gettext("Choose a reason")}
required
/>
<.input field={@form[:submitter_name]} label={gettext("Your name or organisation")} />
<.input
field={@form[:contact_email]}
type="email"
label={gettext("Contact email")}
value={@contact_email || @form[:contact_email].value}
readonly={not is_nil(@contact_email)}
/>
<.input
field={@form[:relationship]}
type="select"
label={gettext("Your relationship to the affected person or rights holder")}
options={[
{gettext("I am the affected person or rights holder"), "self"},
{gettext("I am an authorised representative"), "authorized_representative"},
{gettext("Other"), "other"}
]}
prompt={gettext("Choose a relationship")}
/>
<.input
field={@form[:content_locations]}
type="textarea"
label={gettext("Exact content URLs — one per line")}
required
/>
<.input
field={@form[:explanation]}
type="textarea"
label={gettext("Why do you believe this content should be removed?")}
required
/>
<.input
field={@form[:legal_basis]}
type="textarea"
label={gettext("Law, right, or policy involved, if known")}
/>
<.input
field={@form[:electronic_signature]}
label={gettext("Electronic signature (type your full name)")}
/>
<.input
field={@form[:good_faith]}
type="checkbox"
label={
gettext(
"I believe in good faith that the identified content is illegal or infringes the stated right."
)
}
/>
<.input
field={@form[:accurate_complete]}
type="checkbox"
label={
gettext(
"I confirm that this notice is accurate and complete to the best of my knowledge."
)
}
/>
<p class="text-xs text-base-content/55">
{gettext(
"Identity and contact fields may be omitted for reports of sexual material involving a minor. Do not include or upload the material itself."
)}
</p>
<.button class="btn btn-error w-full">{gettext("Submit removal notice")}</.button>
</.form>
</div>
</Layouts.app>

View File

@ -0,0 +1,16 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-xl text-center">
<div class="text-sm font-semibold text-success">{gettext("NOTICE RECEIVED")}</div>
<h1 class="mt-2 text-4xl font-black">
{gettext("Your reference is %{reference}", reference: @reference)}
</h1>
<p class="mt-4 text-base-content/65">
{gettext(
"A private status link has been sent when a contact email was provided and delivery is configured. Opening that link verifies the contact address. Keep the reference for follow-up."
)}
</p>
<.link navigate={~p"/legal/content-removal"} class="btn btn-primary mt-7">
{gettext("Back to removal form")}
</.link>
</div>
</Layouts.app>

View File

@ -0,0 +1,39 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-2xl">
<div class="flex flex-wrap items-center gap-2">
<span class="badge badge-outline">{@notice.reference}</span>
<span class={[
"badge",
@notice.status == :urgent_review && "badge-error",
@notice.status != :urgent_review && "badge-primary"
]}>
{status_label(@notice.status)}
</span>
</div>
<h1 class="mt-4 text-3xl font-black">{gettext("Content-removal notice")}</h1>
<p class="mt-2 text-sm text-base-content/55">{category_label(@notice.category)}</p>
<section class="mt-6 rounded-2xl bg-base-200 p-5">
<h2 class="font-bold">{gettext("Reported locations")}</h2>
<ul class="mt-3 list-disc space-y-1 pl-5 text-sm">
<li
:for={url <- WhoNeedHelp.ContentRemoval.Notice.content_urls(@notice)}
class="break-all"
>
{url}
</li>
</ul>
</section>
<section
:if={@notice.resolution_note not in [nil, ""]}
class="mt-5 rounded-2xl border border-primary/30 p-5"
>
<h2 class="font-bold">{gettext("Decision or request for information")}</h2>
<p class="mt-2 whitespace-pre-wrap">{@notice.resolution_note}</p>
</section>
<p class="mt-5 text-xs text-base-content/55">
{gettext(
"Keep this status link private. The submitter identity is not shown publicly or automatically disclosed to the person who posted the reported content."
)}
</p>
</div>
</Layouts.app>

View File

@ -0,0 +1,92 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-2xl">
<div class="text-sm font-semibold text-error">{gettext("TAKE IT DOWN")}</div>
<h1 class="mt-2 text-4xl font-black">
{gettext("Request removal of intimate visual material")}
</h1>
<p class="mt-3 text-base-content/65">
{gettext(
"Use this dedicated process when an identifiable person is shown in an intimate image or video shared without consent, including a digital forgery. You may submit for yourself or as an authorised representative."
)}
</p>
<div class="alert alert-error mt-5 text-sm font-semibold">
{gettext(
"Do not upload the image or video. Provide only the exact Who Need Help URL where it appears and enough text to identify it safely."
)}
</div>
<.form for={@form} action={~p"/legal/take-it-down"} class="mt-8 space-y-4">
<.input
field={@form[:category]}
type="select"
label={gettext("Material involved")}
options={[
{gettext("Non-consensual intimate image or video"), "non_consensual_intimate_media"},
{gettext("Sexual material involving a minor"), "child_sexual_abuse_material"}
]}
prompt={gettext("Choose a category")}
required
/>
<.input field={@form[:submitter_name]} label={gettext("Your full name")} required />
<.input
field={@form[:contact_email]}
type="email"
label={gettext("Contact email")}
value={@contact_email || @form[:contact_email].value}
readonly={not is_nil(@contact_email)}
required
/>
<.input
field={@form[:relationship]}
type="select"
label={gettext("Who are you submitting for?")}
options={[
{gettext("Myself"), "self"},
{gettext("A person I am authorised to represent"), "authorized_representative"}
]}
prompt={gettext("Choose a relationship")}
required
/>
<.input
field={@form[:content_locations]}
type="textarea"
label={gettext("Exact content URLs — one per line")}
required
/>
<.input
field={@form[:explanation]}
type="textarea"
label={
gettext(
"Identify the material without reproducing it and explain why it is non-consensual"
)
}
required
/>
<.input
field={@form[:electronic_signature]}
label={gettext("Electronic signature (type your full name)")}
required
/>
<.input
field={@form[:good_faith]}
type="checkbox"
label={
gettext(
"I have a good-faith belief that this intimate visual material was shared without consent."
)
}
/>
<.input
field={@form[:accurate_complete]}
type="checkbox"
label={
gettext(
"I confirm that the information in this request is accurate and that I am the depicted person or authorised to act for them."
)
}
/>
<.button class="btn btn-error w-full">{gettext("Submit urgent removal request")}</.button>
</.form>
</div>
</Layouts.app>

View File

@ -0,0 +1,128 @@
defmodule WhoNeedHelpWeb.SupportController do
use WhoNeedHelpWeb, :controller
alias WhoNeedHelp.Support
alias WhoNeedHelp.Support.SupportRequest
def index(conn, _params) do
requests =
case conn.assigns.current_scope do
nil -> []
scope -> Support.list_for_user(scope)
end
render(conn, :index, requests: requests)
end
def new(conn, _params) do
render_form(conn, %SupportRequest{}, %{}, :new)
end
def create(conn, %{"support_request" => params}) when is_map(params) do
case Support.create_request(conn.assigns.current_scope, params) do
{:ok, request} ->
redirect(conn, to: ~p"/support/received?reference=#{request.reference}")
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render_form(changeset, %{}, :new)
{:error, :rate_limited} ->
conn
|> put_status(:too_many_requests)
|> put_flash(:error, gettext("Too many support requests. Please try again later."))
|> render_form(%SupportRequest{}, params, :new)
end
end
def create(conn, _params), do: send_resp(conn, :bad_request, "Bad Request")
def delete_account(conn, _params) do
render_form(
conn,
%SupportRequest{},
%{
"kind" => "account_deletion",
"subject" => gettext("Delete my Who Need Help account"),
"details" => gettext("Please delete my account and associated personal data.")
},
:delete_account
)
end
def request_account_deletion(conn, %{"support_request" => params}) when is_map(params) do
params =
params
|> Map.put("kind", "account_deletion")
|> Map.put("subject", gettext("Delete my Who Need Help account"))
case Support.create_request(conn.assigns.current_scope, params) do
{:ok, request} ->
redirect(conn, to: ~p"/support/received?reference=#{request.reference}")
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render_form(changeset, params, :delete_account)
{:error, :rate_limited} ->
conn
|> put_status(:too_many_requests)
|> put_flash(:error, gettext("Too many support requests. Please try again later."))
|> render_form(%SupportRequest{}, params, :delete_account)
end
end
def request_account_deletion(conn, _params),
do: send_resp(conn, :bad_request, "Bad Request")
def show(conn, %{"id" => id} = params) do
token = params["token"]
result =
case conn.assigns.current_scope do
nil ->
Support.get_by_access_token(id, token)
scope ->
case Support.get_for_user(scope, id) do
{:ok, request} -> {:ok, request}
_ -> Support.get_by_access_token(id, token)
end
end
case result do
{:ok, request} -> render(conn, :show, request: request)
{:error, :not_found} -> send_resp(conn, :not_found, "Not found")
end
end
def received(conn, %{"reference" => reference}) when is_binary(reference) do
render(conn, :received, reference: String.slice(reference, 0, 64))
end
def received(conn, _params), do: redirect(conn, to: ~p"/support")
defp render_form(conn, %Ecto.Changeset{} = changeset, _attrs, page) do
render(conn, page,
form: Phoenix.Component.to_form(changeset, as: :support_request),
contact_email: current_email(conn)
)
end
defp render_form(conn, %SupportRequest{} = request, attrs, page) do
changeset = Support.change_request(request, with_contact_email(conn, attrs))
render_form(conn, changeset, attrs, page)
end
defp with_contact_email(conn, attrs) do
case current_email(conn) do
nil -> attrs
email -> Map.put(attrs, "contact_email", email)
end
end
defp current_email(%{assigns: %{current_scope: %{user: %{email: email}}}}), do: email
defp current_email(_conn), do: nil
end

View File

@ -0,0 +1,22 @@
defmodule WhoNeedHelpWeb.SupportHTML do
use WhoNeedHelpWeb, :html
embed_templates "support_html/*"
def kind_label(:account_access), do: gettext("Account access")
def kind_label(:technical_issue), do: gettext("Technical issue")
def kind_label(:safety_concern), do: gettext("Safety concern")
def kind_label(:moderation_appeal), do: gettext("Moderation appeal")
def kind_label(:account_deletion), do: gettext("Account deletion")
def kind_label(:data_export), do: gettext("Data export")
def kind_label(:privacy_request), do: gettext("Privacy request")
def kind_label(:other), do: gettext("Other")
def kind_label(value), do: to_string(value)
def status_label(:open), do: gettext("Open")
def status_label(:reviewing), do: gettext("Reviewing")
def status_label(:waiting_for_requester), do: gettext("Waiting for your response")
def status_label(:resolved), do: gettext("Resolved")
def status_label(:closed), do: gettext("Closed")
def status_label(value), do: to_string(value)
end

View File

@ -0,0 +1,40 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-2xl">
<div class="text-sm font-semibold text-error">{gettext("ACCOUNT AND DATA")}</div>
<h1 class="mt-2 text-4xl font-black">{gettext("Request account deletion")}</h1>
<p class="mt-3 text-base-content/65">
{gettext(
"This requests deletion of your Who Need Help account and associated personal data. Some records may need to be retained when required for safety, fraud prevention, legal obligations, or resolving an active dispute; any retained data must be described in the applicable retention notice."
)}
</p>
<div class="alert alert-warning mt-5 text-sm">
{gettext(
"Submitting this form does not immediately sign you out or erase evidence required for an open safety investigation. Support will verify and process the request."
)}
</div>
<.form for={@form} action={~p"/account/delete"} class="mt-8 space-y-4">
<input type="hidden" name="support_request[kind]" value="account_deletion" />
<input
type="hidden"
name="support_request[subject]"
value="Delete my Who Need Help account"
/>
<.input
field={@form[:contact_email]}
type="email"
label={gettext("Account email")}
value={@contact_email || @form[:contact_email].value}
readonly={not is_nil(@contact_email)}
required
/>
<.input
field={@form[:details]}
type="textarea"
label={gettext("Additional information")}
required
/>
<.button class="btn btn-error w-full">{gettext("Request account deletion")}</.button>
</.form>
</div>
</Layouts.app>

View File

@ -0,0 +1,30 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-4xl">
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<div class="text-sm font-semibold text-primary">{gettext("SUPPORT")}</div>
<h1 class="mt-1 text-4xl font-black">{gettext("Your requests")}</h1>
</div>
<.link navigate={~p"/support/new"} class="btn btn-primary">{gettext("New request")}</.link>
</div>
<div class="mt-8 space-y-3">
<.link
:for={request <- @requests}
navigate={~p"/support/cases/#{request.id}"}
class="block rounded-2xl border border-base-300 p-5 transition hover:border-primary"
>
<div class="flex flex-wrap items-center gap-2">
<span class="badge badge-outline">{request.reference}</span>
<span class="badge badge-primary">{status_label(request.status)}</span>
<span class="text-xs text-base-content/55">{kind_label(request.kind)}</span>
</div>
<h2 class="mt-3 font-bold">{request.subject}</h2>
<time class="mt-1 block text-xs text-base-content/50">{request.inserted_at}</time>
</.link>
<p :if={@requests == []} class="rounded-2xl bg-base-200 p-6 text-base-content/60">
{gettext("You have not submitted any support requests.")}
</p>
</div>
</div>
</Layouts.app>

View File

@ -0,0 +1,63 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-2xl">
<div class="text-sm font-semibold text-primary">{gettext("SUPPORT")}</div>
<h1 class="mt-2 text-4xl font-black">{gettext("Contact Who Need Help")}</h1>
<p class="mt-3 text-base-content/65">
{gettext(
"Use this form for account access, technical problems, privacy questions, or other support. For illegal content or a removal request, use the dedicated removal form."
)}
</p>
<div class="mt-5 flex flex-wrap gap-2">
<.link navigate={~p"/legal/content-removal"} class="btn btn-outline btn-sm">
{gettext("Report content")}
</.link>
<.link navigate={~p"/legal/take-it-down"} class="btn btn-outline btn-sm">
{gettext("TAKE IT DOWN request")}
</.link>
<.link navigate={~p"/account/delete"} class="btn btn-outline btn-sm">
{gettext("Delete an account")}
</.link>
</div>
<.form for={@form} action={~p"/support"} class="mt-8 space-y-4">
<.input
field={@form[:kind]}
type="select"
label={gettext("What do you need help with?")}
options={[
{gettext("Account access"), "account_access"},
{gettext("Technical issue"), "technical_issue"},
{gettext("Safety concern"), "safety_concern"},
{gettext("Appeal a moderation decision"), "moderation_appeal"},
{gettext("Privacy request"), "privacy_request"},
{gettext("Data export"), "data_export"},
{gettext("Other"), "other"}
]}
prompt={gettext("Choose a topic")}
required
/>
<.input
field={@form[:contact_email]}
type="email"
label={gettext("Contact email")}
value={@contact_email || @form[:contact_email].value}
readonly={not is_nil(@contact_email)}
required
/>
<.input field={@form[:subject]} label={gettext("Subject")} required />
<.input
field={@form[:details]}
type="textarea"
label={gettext("Describe the problem")}
required
/>
<p class="text-xs text-base-content/55">
{gettext(
"Do not include passwords, payment card details, access codes, prescriptions, or unnecessary medical information."
)}
</p>
<.button class="btn btn-primary w-full">{gettext("Send support request")}</.button>
</.form>
</div>
</Layouts.app>

View File

@ -0,0 +1,13 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-xl text-center">
<div class="text-sm font-semibold text-success">{gettext("REQUEST RECEIVED")}</div>
<h1 class="mt-2 text-4xl font-black">{gettext("Check your email")}</h1>
<p class="mt-4 text-base-content/65">
{gettext(
"We created support request %{reference}. A private status link has been sent to the contact email when delivery is configured. Opening that link verifies the address for public requests.",
reference: @reference
)}
</p>
<.link navigate={~p"/support"} class="btn btn-primary mt-7">{gettext("Back to support")}</.link>
</div>
</Layouts.app>

View File

@ -0,0 +1,25 @@
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-2xl">
<div class="flex flex-wrap items-center gap-2">
<span class="badge badge-outline">{@request.reference}</span>
<span class="badge badge-primary">{status_label(@request.status)}</span>
</div>
<h1 class="mt-4 text-3xl font-black">{@request.subject}</h1>
<p class="mt-2 text-sm text-base-content/55">{kind_label(@request.kind)}</p>
<div class="mt-6 rounded-2xl bg-base-200 p-5">
<p class="whitespace-pre-wrap">{@request.details}</p>
</div>
<section
:if={@request.resolution_note not in [nil, ""]}
class="mt-5 rounded-2xl border border-primary/30 p-5"
>
<h2 class="font-bold">{gettext("Support response")}</h2>
<p class="mt-2 whitespace-pre-wrap">{@request.resolution_note}</p>
</section>
<p class="mt-5 text-xs text-base-content/55">
{gettext(
"Keep this status link private. A copy is sent to the contact email when email delivery is configured."
)}
</p>
</div>
</Layouts.app>

View File

@ -108,4 +108,23 @@
{gettext("Save Password")}
</.button>
</.form>
<div class="divider" />
<section class="rounded-3xl border border-error/40 p-5">
<h2 class="text-lg font-bold text-error">{gettext("Account and personal data")}</h2>
<p class="mt-1 text-sm text-base-content/60">
{gettext(
"Request deletion of your account and associated personal data, or contact support about access and export requests."
)}
</p>
<div class="mt-4 flex flex-wrap gap-2">
<.link navigate={~p"/account/delete"} class="btn btn-error btn-outline">
{gettext("Request account deletion")}
</.link>
<.link navigate={~p"/support/requests"} class="btn btn-outline">
{gettext("View support requests")}
</.link>
</div>
</section>
</Layouts.app>

View File

@ -689,6 +689,12 @@ defmodule WhoNeedHelpWeb.ActivityLive.Show do
</.button>
</.form>
</section>
<.link
navigate={~p"/legal/content-removal?location=/activities/#{@activity.id}"}
class="btn btn-ghost btn-sm w-full"
>
{gettext("Submit a legal content-removal notice")}
</.link>
</aside>
</div>
</Layouts.app>

View File

@ -1120,6 +1120,12 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
</.button>
</.form>
</div>
<.link
navigate={~p"/legal/content-removal?location=/requests/#{@request.id}"}
class="btn btn-ghost btn-sm w-full"
>
{gettext("Submit a legal content-removal notice")}
</.link>
</aside>
</div>
</Layouts.app>

View File

@ -0,0 +1,282 @@
defmodule WhoNeedHelpWeb.SupportOperationsLive do
use WhoNeedHelpWeb, :live_view
alias WhoNeedHelp.{ContentRemoval, Support}
@impl true
def mount(_params, _session, socket) do
{:ok, socket |> assign(:page_title, gettext("Support operations")) |> load()}
end
@impl true
def handle_event("moderate-support", %{"id" => id, "moderation" => params}, socket) do
respond(
socket,
Support.moderate(socket.assigns.current_scope, id, params),
gettext("Support request updated.")
)
end
def handle_event("moderate-removal", %{"id" => id, "moderation" => params}, socket) do
respond(
socket,
ContentRemoval.moderate(socket.assigns.current_scope, id, params),
gettext("Removal notice updated.")
)
end
def handle_event("load-more-support", _params, socket) do
page =
Support.paginate_for_staff(socket.assigns.current_scope,
after: socket.assigns.support_cursor
)
{:noreply, append_page(socket, :support_requests, :support_cursor, page)}
end
def handle_event("load-more-removals", _params, socket) do
page =
ContentRemoval.paginate_for_staff(socket.assigns.current_scope,
after: socket.assigns.removal_cursor
)
{:noreply, append_page(socket, :removal_notices, :removal_cursor, page)}
end
defp respond(socket, {:ok, _record}, message) do
{:noreply, socket |> put_flash(:info, message) |> load()}
end
defp respond(socket, {:error, reason}, _message) do
{:noreply, put_flash(socket, :error, error_message(reason))}
end
defp load(socket) do
support = Support.paginate_for_staff(socket.assigns.current_scope)
removals = ContentRemoval.paginate_for_staff(socket.assigns.current_scope)
socket
|> assign(:support_requests, support.entries)
|> assign(:support_cursor, support.next_cursor)
|> assign(:removal_notices, removals.entries)
|> assign(:removal_cursor, removals.next_cursor)
end
defp append_page(socket, entries_key, cursor_key, page) do
existing = socket.assigns[entries_key]
existing_ids = MapSet.new(existing, & &1.id)
entries = existing ++ Enum.reject(page.entries, &MapSet.member?(existing_ids, &1.id))
socket |> assign(entries_key, entries) |> assign(cursor_key, page.next_cursor)
end
defp error_message(:forbidden), do: gettext("Moderator access is required.")
defp error_message(:not_found), do: gettext("The selected record is no longer available.")
defp error_message(%Ecto.Changeset{}), do: gettext("Please check the submitted fields.")
defp error_message(_reason), do: gettext("Could not update the request. Please try again.")
defp support_kind(:account_access), do: gettext("Account access")
defp support_kind(:technical_issue), do: gettext("Technical issue")
defp support_kind(:safety_concern), do: gettext("Safety concern")
defp support_kind(:moderation_appeal), do: gettext("Moderation appeal")
defp support_kind(:account_deletion), do: gettext("Account deletion")
defp support_kind(:data_export), do: gettext("Data export")
defp support_kind(:privacy_request), do: gettext("Privacy request")
defp support_kind(:other), do: gettext("Other")
defp support_kind(value), do: to_string(value)
defp removal_category(:illegal_content), do: gettext("Illegal content")
defp removal_category(:privacy_violation), do: gettext("Privacy violation")
defp removal_category(:copyright), do: gettext("Copyright")
defp removal_category(:impersonation), do: gettext("Impersonation")
defp removal_category(:non_consensual_intimate_media),
do: gettext("Non-consensual intimate image or video")
defp removal_category(:child_sexual_abuse_material),
do: gettext("Sexual material involving a minor")
defp removal_category(:threat_to_life_or_safety), do: gettext("Threat to life or safety")
defp removal_category(:other), do: gettext("Other")
defp removal_category(value), do: to_string(value)
defp status_label(value), do: value |> to_string() |> String.replace("_", " ")
defp scoped_form(data, id), do: to_form(data, as: :moderation, id: id)
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="text-sm font-semibold text-warning">{gettext("RESTRICTED WORKSPACE")}</div>
<div class="flex flex-wrap items-end justify-between gap-3">
<div>
<h1 class="mt-1 text-4xl font-black">{gettext("Support operations")}</h1>
<p class="mt-2 text-base-content/60">
{gettext(
"Support requests and legal removal notices are separate queues. Decisions and operator identity are audited."
)}
</p>
</div>
<.link navigate={~p"/moderation"} class="btn btn-outline btn-sm">
{gettext("Trust and safety moderation")}
</.link>
</div>
<section class="mt-8">
<h2 class="text-2xl font-bold">{gettext("Content removal and TAKE IT DOWN")}</h2>
<div class="mt-4 space-y-4">
<article
:for={notice <- @removal_notices}
class={[
"rounded-2xl border p-5",
notice.status == :urgent_review && "border-error bg-error/5",
notice.status != :urgent_review && "border-base-300"
]}
>
<% form =
scoped_form(
%{
"status" => to_string(notice.status),
"resolution_note" => notice.resolution_note || ""
},
"removal-#{notice.id}"
) %>
<div class="flex flex-wrap items-center gap-2">
<span class="badge badge-error">{notice.reference}</span>
<span class="badge badge-outline">{notice.regime}</span>
<span class="badge">{status_label(notice.status)}</span>
<span :if={is_nil(notice.contact_verified_at)} class="badge badge-warning">
{gettext("contact unverified")}
</span>
<span class="text-xs text-base-content/55">{removal_category(notice.category)}</span>
<span :if={notice.response_due_at} class="badge badge-error badge-outline">
{gettext("review by %{time}", time: notice.response_due_at)}
</span>
</div>
<dl class="mt-4 grid gap-2 text-sm sm:grid-cols-[10rem_1fr]">
<dt class="font-semibold">{gettext("Submitter")}</dt>
<dd>{notice.submitter_name || gettext("Not provided")}</dd>
<dt class="font-semibold">{gettext("Contact")}</dt>
<dd>{notice.contact_email || gettext("Not provided")}</dd>
<dt class="font-semibold">{gettext("Locations")}</dt>
<dd class="space-y-1">
<div
:for={url <- WhoNeedHelp.ContentRemoval.Notice.content_urls(notice)}
class="break-all font-mono text-xs"
>
{url}
</div>
</dd>
</dl>
<p class="mt-4 whitespace-pre-wrap text-sm">{notice.explanation}</p>
<p
:if={notice.legal_basis not in [nil, ""]}
class="mt-3 whitespace-pre-wrap text-sm text-base-content/65"
>
<strong>{gettext("Stated basis:")}</strong> {notice.legal_basis}
</p>
<.form
for={form}
phx-submit="moderate-removal"
phx-value-id={notice.id}
class="mt-4 grid gap-2 md:grid-cols-[13rem_1fr_auto]"
>
<.input
field={form[:status]}
type="select"
options={[
{gettext("Open"), "open"},
{gettext("Urgent review"), "urgent_review"},
{gettext("Reviewing"), "reviewing"},
{gettext("More information needed"), "needs_information"},
{gettext("Action taken"), "actioned"},
{gettext("Rejected"), "rejected"},
{gettext("Closed"), "closed"}
]}
/>
<.input
field={form[:resolution_note]}
type="textarea"
placeholder={gettext("Decision or information request")}
/>
<.button class="btn btn-error self-end">{gettext("Save and notify")}</.button>
</.form>
</article>
<p :if={@removal_notices == []} class="text-base-content/50">
{gettext("No removal notices.")}
</p>
</div>
<button
:if={@removal_cursor}
phx-click="load-more-removals"
class="btn btn-outline btn-sm mt-4"
>
{gettext("Load more")}
</button>
</section>
<section class="mt-12">
<h2 class="text-2xl font-bold">{gettext("General support and data requests")}</h2>
<div class="mt-4 space-y-4">
<article :for={request <- @support_requests} class="rounded-2xl border border-base-300 p-5">
<% form =
scoped_form(
%{
"status" => to_string(request.status),
"resolution_note" => request.resolution_note || ""
},
"support-#{request.id}"
) %>
<div class="flex flex-wrap items-center gap-2">
<span class="badge badge-primary">{request.reference}</span>
<span class="badge">{status_label(request.status)}</span>
<span :if={is_nil(request.contact_verified_at)} class="badge badge-warning">
{gettext("contact unverified")}
</span>
<span class="text-xs text-base-content/55">{support_kind(request.kind)}</span>
</div>
<h3 class="mt-3 font-bold">{request.subject}</h3>
<p class="mt-1 text-xs text-base-content/55">{request.contact_email}</p>
<p class="mt-3 whitespace-pre-wrap text-sm">{request.details}</p>
<.form
for={form}
phx-submit="moderate-support"
phx-value-id={request.id}
class="mt-4 grid gap-2 md:grid-cols-[13rem_1fr_auto]"
>
<.input
field={form[:status]}
type="select"
options={[
{gettext("Open"), "open"},
{gettext("Reviewing"), "reviewing"},
{gettext("Waiting for requester"), "waiting_for_requester"},
{gettext("Resolved"), "resolved"},
{gettext("Closed"), "closed"}
]}
/>
<.input
field={form[:resolution_note]}
type="textarea"
placeholder={gettext("Support response")}
/>
<.button class="btn btn-primary self-end">{gettext("Save and notify")}</.button>
</.form>
</article>
<p :if={@support_requests == []} class="text-base-content/50">
{gettext("No support requests.")}
</p>
</div>
<button
:if={@support_cursor}
phx-click="load-more-support"
class="btn btn-outline btn-sm mt-4"
>
{gettext("Load more")}
</button>
</section>
</Layouts.app>
"""
end
end

View File

@ -72,6 +72,19 @@ defmodule WhoNeedHelpWeb.Router do
get "/", PageController, :home
get "/feedback", FeedbackController, :show
get "/safety", PageController, :safety
get "/support", SupportController, :new
get "/support/new", SupportController, :new
post "/support", SupportController, :create
get "/support/received", SupportController, :received
get "/support/cases/:id", SupportController, :show
get "/account/delete", SupportController, :delete_account
post "/account/delete", SupportController, :request_account_deletion
get "/legal/content-removal", ContentRemovalController, :new
post "/legal/content-removal", ContentRemovalController, :create
get "/legal/content-removal/received", ContentRemovalController, :received
get "/legal/content-removal/:id", ContentRemovalController, :show
get "/legal/take-it-down", ContentRemovalController, :take_it_down
post "/legal/take-it-down", ContentRemovalController, :create_take_it_down
end
# Other scopes may use custom stacks.
@ -118,6 +131,7 @@ defmodule WhoNeedHelpWeb.Router do
delete "/auth/google/link", GoogleAuthController, :disconnect
get "/auth/social/:provider", SocialOAuthController, :request
get "/auth/social/:provider/callback", SocialOAuthController, :callback
get "/support/requests", SupportController, :index
end
scope "/", WhoNeedHelpWeb do
@ -139,6 +153,7 @@ defmodule WhoNeedHelpWeb.Router do
live_session :moderation,
on_mount: [{WhoNeedHelpWeb.UserAuth, :ensure_moderator}] do
live "/moderation", ModerationLive, :index
live "/support/operations", SupportOperationsLive, :index
end
end

View File

@ -12,7 +12,7 @@ msgid ""
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:111
#: lib/who_need_help_web/components/layouts.ex:257
#: lib/who_need_help_web/components/layouts.ex:266
#, elixir-autogen, elixir-format
msgid "Account settings"
msgstr ""
@ -30,13 +30,13 @@ msgstr ""
msgid "Ask for help"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:295
#: lib/who_need_help_web/components/layouts.ex:310
#: lib/who_need_help_web/components/layouts.ex:304
#: lib/who_need_help_web/components/layouts.ex:319
#, elixir-autogen, elixir-format
msgid "Attempting to reconnect"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:171
#: lib/who_need_help_web/components/layouts.ex:175
#, elixir-autogen, elixir-format
msgid "Categories"
msgstr ""
@ -65,13 +65,13 @@ msgid "Log in"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:114
#: lib/who_need_help_web/components/layouts.ex:260
#: lib/who_need_help_web/components/layouts.ex:269
#, elixir-autogen, elixir-format
msgid "Log out"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:108
#: lib/who_need_help_web/components/layouts.ex:254
#: lib/who_need_help_web/components/layouts.ex:263
#: lib/who_need_help_web/live/profile_live.ex:16
#, elixir-autogen, elixir-format
msgid "Profile"
@ -83,7 +83,7 @@ msgstr ""
msgid "Register"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:161
#: lib/who_need_help_web/components/layouts.ex:165
#, elixir-autogen, elixir-format
msgid "Requests"
msgstr ""
@ -93,12 +93,12 @@ msgstr ""
msgid "See nearby requests"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:302
#: lib/who_need_help_web/components/layouts.ex:311
#, elixir-autogen, elixir-format
msgid "Something went wrong!"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:287
#: lib/who_need_help_web/components/layouts.ex:296
#, elixir-autogen, elixir-format
msgid "We can't find the internet"
msgstr ""
@ -174,7 +174,7 @@ msgid "Account Settings"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:63
#: lib/who_need_help_web/components/layouts.ex:192
#: lib/who_need_help_web/components/layouts.ex:201
#, elixir-autogen, elixir-format
msgid "Account and language"
msgstr ""
@ -195,7 +195,7 @@ msgstr ""
msgid "Active"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:166
#: lib/who_need_help_web/components/layouts.ex:170
#: lib/who_need_help_web/live/activity_live/index.ex:118
#, elixir-autogen, elixir-format
msgid "Activities"
@ -367,7 +367,7 @@ msgstr ""
msgid "Briefly describe the help you need"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:147
#: lib/who_need_help_web/components/layouts.ex:151
#, elixir-autogen, elixir-format
msgid "Build Week feedback"
msgstr ""
@ -641,7 +641,7 @@ msgstr ""
msgid "Dismissed"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:71
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:76
#: lib/who_need_help_web/live/profile_live.ex:149
#, elixir-autogen, elixir-format
msgid "Display name"
@ -662,7 +662,7 @@ msgstr ""
msgid "Double-blind review"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:62
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:67
#: 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_settings_html/edit.html.heex:15
@ -817,7 +817,7 @@ msgstr ""
msgid "Helper: %{name}"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:176
#: lib/who_need_help_web/components/layouts.ex:180
#, elixir-autogen, elixir-format
msgid "Helpers"
msgstr ""
@ -872,7 +872,7 @@ msgid "Human decisions retained"
msgstr ""
#: 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:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
msgid "I am 18 or older and accept the safety rules"
msgstr ""
@ -913,9 +913,12 @@ msgstr ""
msgid "If your email is in our system, you will receive instructions for logging in shortly."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:9
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:25
#: lib/who_need_help_web/live/activity_live/show.ex:678
#: lib/who_need_help_web/live/moderation_live.ex:253
#: lib/who_need_help_web/live/request_live/show.ex:1109
#: lib/who_need_help_web/live/support_operations_live.ex:91
#, elixir-autogen, elixir-format
msgid "Impersonation"
msgstr ""
@ -1122,7 +1125,7 @@ msgstr ""
msgid "Mode"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:181
#: lib/who_need_help_web/components/layouts.ex:185
#: lib/who_need_help_web/live/moderation_live.ex:9
#: lib/who_need_help_web/live/moderation_live.ex:291
#, elixir-autogen, elixir-format
@ -1136,6 +1139,7 @@ msgid "Moderator"
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:230
#: lib/who_need_help_web/live/support_operations_live.ex:73
#: lib/who_need_help_web/user_auth.ex:306
#, elixir-autogen, elixir-format
msgid "Moderator access is required."
@ -1270,12 +1274,16 @@ msgstr ""
msgid "Only the organizer and approved participants can read or send these messages."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:21
#: lib/who_need_help_web/controllers/support_html.ex:16
#: lib/who_need_help_web/live/activity_live/index.ex:166
#: lib/who_need_help_web/live/activity_live/show.ex:342
#: lib/who_need_help_web/live/moderation_live.ex:257
#: lib/who_need_help_web/live/request_live/index.ex:176
#: lib/who_need_help_web/live/request_live/index.ex:177
#: lib/who_need_help_web/live/request_live/show.ex:636
#: lib/who_need_help_web/live/support_operations_live.ex:189
#: lib/who_need_help_web/live/support_operations_live.ex:252
#, elixir-autogen, elixir-format
msgid "Open"
msgstr ""
@ -1320,10 +1328,17 @@ msgstr ""
msgid "Organizer social links"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:18
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:29
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:49
#: lib/who_need_help_web/controllers/support_html.ex:13
#: lib/who_need_help_web/controllers/support_html/new.html.heex:35
#: lib/who_need_help_web/live/activity_live/show.ex:679
#: lib/who_need_help_web/live/moderation_live.ex:254
#: lib/who_need_help_web/live/profile_live.ex:311
#: lib/who_need_help_web/live/request_live/show.ex:1110
#: lib/who_need_help_web/live/support_operations_live.ex:85
#: lib/who_need_help_web/live/support_operations_live.ex:100
#, elixir-autogen, elixir-format
msgid "Other"
msgstr ""
@ -1374,6 +1389,7 @@ msgid "Please check the entered data."
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:240
#: lib/who_need_help_web/live/support_operations_live.ex:75
#, elixir-autogen, elixir-format
msgid "Please check the submitted fields."
msgstr ""
@ -1497,6 +1513,7 @@ msgid "READ BEFORE USING THE SERVICE"
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:290
#: lib/who_need_help_web/live/support_operations_live.ex:111
#, elixir-autogen, elixir-format
msgid "RESTRICTED WORKSPACE"
msgstr ""
@ -1517,11 +1534,12 @@ msgstr ""
msgid "Rating"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:77
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:82
#, elixir-autogen, elixir-format
msgid "Read the"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:20
#: lib/who_need_help_web/live/activity_live/show.ex:672
#, elixir-autogen, elixir-format
msgid "Reason"
@ -1633,8 +1651,10 @@ msgstr ""
msgid "Resolution note"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:19
#: lib/who_need_help_web/live/moderation_live.ex:259
#: lib/who_need_help_web/live/moderation_live.ex:365
#: lib/who_need_help_web/live/support_operations_live.ex:255
#, elixir-autogen, elixir-format
msgid "Resolved"
msgstr ""
@ -1662,8 +1682,12 @@ msgstr ""
msgid "Reviewed"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:23
#: lib/who_need_help_web/controllers/support_html.ex:17
#: lib/who_need_help_web/live/moderation_live.ex:258
#: lib/who_need_help_web/live/moderation_live.ex:364
#: lib/who_need_help_web/live/support_operations_live.ex:191
#: lib/who_need_help_web/live/support_operations_live.ex:253
#, elixir-autogen, elixir-format
msgid "Reviewing"
msgstr ""
@ -2129,12 +2153,12 @@ msgstr ""
msgid "Use a public first meeting point. Do not publish a home address, access code, travel document, or other sensitive information."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:349
#: lib/who_need_help_web/components/layouts.ex:358
#, elixir-autogen, elixir-format
msgid "Use dark theme"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:340
#: lib/who_need_help_web/components/layouts.ex:349
#, elixir-autogen, elixir-format
msgid "Use light theme"
msgstr ""
@ -2150,7 +2174,7 @@ msgstr ""
msgid "Use private chat and optional live location sharing."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:331
#: lib/who_need_help_web/components/layouts.ex:340
#, elixir-autogen, elixir-format
msgid "Use system theme"
msgstr ""
@ -2266,7 +2290,7 @@ msgstr ""
msgid "Who Need Help home"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
msgid "Who Need Help is not an emergency or medical service. Medicine requests are limited to pickup of legal items already purchased or reserved."
msgstr ""
@ -2407,6 +2431,7 @@ msgstr ""
msgid "Your request is now visible to nearby helpers."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:6
#: lib/who_need_help_web/live/request_live/index.ex:342
#, elixir-autogen, elixir-format
msgid "Your requests"
@ -2432,7 +2457,7 @@ msgstr ""
msgid "activity message"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:79
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:84
#, elixir-autogen, elixir-format
msgid "before confirming."
msgstr ""
@ -2509,7 +2534,7 @@ msgstr ""
msgid "rating %{rating}"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:78
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:83
#, elixir-autogen, elixir-format
msgid "safety rules"
msgstr ""
@ -2617,7 +2642,9 @@ msgstr ""
msgid "Reciprocal rating ring"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:26
#: lib/who_need_help_web/live/moderation_live.ex:263
#: lib/who_need_help_web/live/support_operations_live.ex:194
#, elixir-autogen, elixir-format
msgid "Rejected"
msgstr ""
@ -2650,6 +2677,8 @@ msgstr ""
#: lib/who_need_help_web/live/profile_live.ex:354
#: lib/who_need_help_web/live/request_live/index.ex:303
#: lib/who_need_help_web/live/request_live/index.ex:360
#: lib/who_need_help_web/live/support_operations_live.ex:215
#: lib/who_need_help_web/live/support_operations_live.ex:276
#, elixir-autogen, elixir-format
msgid "Load more"
msgstr ""
@ -2736,6 +2765,7 @@ msgid "The registration form is invalid."
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:239
#: lib/who_need_help_web/live/support_operations_live.ex:74
#, elixir-autogen, elixir-format
msgid "The selected record is no longer available."
msgstr ""
@ -2835,7 +2865,7 @@ msgstr ""
msgid "Connect Google only after signing in here. We never merge accounts automatically by matching email addresses."
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
msgid "Create account and email me a link"
msgstr ""
@ -2897,7 +2927,7 @@ msgstr ""
msgid "Google sign-in will be available after the operator configures it."
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:100
#, elixir-autogen, elixir-format
msgid "Sending link..."
msgstr ""
@ -2981,3 +3011,632 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:45
#, elixir-autogen, elixir-format
msgid "A person I am authorised to represent"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:8
#, elixir-autogen, elixir-format
msgid "A private status link has been sent when a contact email was provided and delivery is configured. Opening that link verifies the contact address. Keep the reference for follow-up."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:3
#, elixir-autogen, elixir-format
msgid "ACCOUNT AND DATA"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:6
#: lib/who_need_help_web/controllers/support_html/new.html.heex:29
#: lib/who_need_help_web/live/support_operations_live.ex:78
#, elixir-autogen, elixir-format
msgid "Account access"
msgstr ""
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:115
#, elixir-autogen, elixir-format
msgid "Account and personal data"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:10
#: lib/who_need_help_web/live/support_operations_live.ex:82
#, elixir-autogen, elixir-format
msgid "Account deletion"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:26
#, elixir-autogen, elixir-format
msgid "Account email"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:25
#: lib/who_need_help_web/live/support_operations_live.ex:193
#, elixir-autogen, elixir-format
msgid "Action taken"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:34
#, elixir-autogen, elixir-format
msgid "Additional information"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:32
#, elixir-autogen, elixir-format
msgid "Appeal a moderation decision"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:13
#, elixir-autogen, elixir-format
msgid "Back to removal form"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:11
#, elixir-autogen, elixir-format
msgid "Back to support"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "CONTENT REMOVAL"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:4
#, elixir-autogen, elixir-format
msgid "Check your email"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:27
#, elixir-autogen, elixir-format
msgid "Choose a category"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:31
#, elixir-autogen, elixir-format
msgid "Choose a reason"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:51
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:47
#, elixir-autogen, elixir-format
msgid "Choose a relationship"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:37
#, elixir-autogen, elixir-format
msgid "Choose a topic"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:27
#: lib/who_need_help_web/controllers/support_html.ex:20
#: lib/who_need_help_web/live/support_operations_live.ex:195
#: lib/who_need_help_web/live/support_operations_live.ex:256
#, elixir-autogen, elixir-format
msgid "Closed"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:160
#, elixir-autogen, elixir-format
msgid "Contact"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Contact Who Need Help"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:38
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:34
#: lib/who_need_help_web/controllers/support_html/new.html.heex:43
#, elixir-autogen, elixir-format
msgid "Contact email"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:127
#, elixir-autogen, elixir-format
msgid "Content removal and TAKE IT DOWN"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:13
#, elixir-autogen, elixir-format
msgid "Content-removal notice"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:8
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:90
#, elixir-autogen, elixir-format
msgid "Copyright"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:76
#, elixir-autogen, elixir-format
msgid "Could not update the request. Please try again."
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:11
#: lib/who_need_help_web/controllers/support_html/new.html.heex:34
#: lib/who_need_help_web/live/support_operations_live.ex:83
#, elixir-autogen, elixir-format
msgid "Data export"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:201
#, elixir-autogen, elixir-format
msgid "Decision or information request"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:30
#, elixir-autogen, elixir-format
msgid "Decision or request for information"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:19
#, elixir-autogen, elixir-format
msgid "Delete an account"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:52
#, elixir-autogen, elixir-format
msgid "Describe the problem"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:56
#, elixir-autogen, elixir-format
msgid "Do not include passwords, payment card details, access codes, prescriptions, or unnecessary medical information."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:13
#, elixir-autogen, elixir-format
msgid "Do not upload the image or video. Provide only the exact Who Need Help URL where it appears and enough text to identify it safely."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:72
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:68
#, elixir-autogen, elixir-format
msgid "Electronic signature (type your full name)"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:56
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:53
#, elixir-autogen, elixir-format
msgid "Exact content URLs — one per line"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:220
#, elixir-autogen, elixir-format
msgid "General support and data requests"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "I am an authorised representative"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "I am the affected person or rights holder"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:78
#, elixir-autogen, elixir-format
msgid "I believe in good faith that the identified content is illegal or infringes the stated right."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:84
#, elixir-autogen, elixir-format
msgid "I confirm that the information in this request is accurate and that I am the depicted person or authorised to act for them."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:87
#, elixir-autogen, elixir-format
msgid "I confirm that this notice is accurate and complete to the best of my knowledge."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:75
#, elixir-autogen, elixir-format
msgid "I have a good-faith belief that this intimate visual material was shared without consent."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:60
#, elixir-autogen, elixir-format
msgid "Identify the material without reproducing it and explain why it is non-consensual"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:93
#, elixir-autogen, elixir-format
msgid "Identity and contact fields may be omitted for reports of sexual material involving a minor. Do not include or upload the material itself."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:6
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:22
#: lib/who_need_help_web/live/support_operations_live.ex:88
#, elixir-autogen, elixir-format
msgid "Illegal content"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/show.html.heex:20
#, elixir-autogen, elixir-format
msgid "Keep this status link private. A copy is sent to the contact email when email delivery is configured."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:34
#, elixir-autogen, elixir-format
msgid "Keep this status link private. The submitter identity is not shown publicly or automatically disclosed to the person who posted the reported content."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:68
#, elixir-autogen, elixir-format
msgid "Law, right, or policy involved, if known"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:162
#, elixir-autogen, elixir-format
msgid "Locations"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:22
#, elixir-autogen, elixir-format
msgid "Material involved"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:9
#: lib/who_need_help_web/live/support_operations_live.ex:81
#, elixir-autogen, elixir-format
msgid "Moderation appeal"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:24
#: lib/who_need_help_web/live/support_operations_live.ex:192
#, elixir-autogen, elixir-format
msgid "More information needed"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:44
#, elixir-autogen, elixir-format
msgid "Myself"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "NOTICE RECEIVED"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "New request"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:207
#, elixir-autogen, elixir-format
msgid "No removal notices."
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:268
#, elixir-autogen, elixir-format
msgid "No support requests."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:12
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:26
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:94
#, elixir-autogen, elixir-format
msgid "Non-consensual intimate image or video"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:159
#: lib/who_need_help_web/live/support_operations_live.ex:161
#, elixir-autogen, elixir-format
msgid "Not provided"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:12
#: lib/who_need_help_web/controllers/support_html/new.html.heex:33
#: lib/who_need_help_web/live/support_operations_live.ex:84
#, elixir-autogen, elixir-format
msgid "Privacy request"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:7
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:23
#: lib/who_need_help_web/live/support_operations_live.ex:89
#, elixir-autogen, elixir-format
msgid "Privacy violation"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:11
#, elixir-autogen, elixir-format
msgid "Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "REQUEST RECEIVED"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:24
#, elixir-autogen, elixir-format
msgid "Removal notice updated."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/support_html/new.html.heex:13
#, elixir-autogen, elixir-format
msgid "Report content"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Report illegal or harmful content"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:16
#, elixir-autogen, elixir-format
msgid "Reported locations"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:4
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:37
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:123
#, elixir-autogen, elixir-format
msgid "Request account deletion"
msgstr ""
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:117
#, elixir-autogen, elixir-format
msgid "Request deletion of your account and associated personal data, or contact support about access and export requests."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:5
#, elixir-autogen, elixir-format
msgid "Request removal of intimate visual material"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:5
#: lib/who_need_help_web/controllers/support_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "SUPPORT"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:8
#: lib/who_need_help_web/controllers/support_html/new.html.heex:31
#: lib/who_need_help_web/live/support_operations_live.ex:80
#, elixir-autogen, elixir-format
msgid "Safety concern"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:203
#: lib/who_need_help_web/live/support_operations_live.ex:264
#, elixir-autogen, elixir-format
msgid "Save and notify"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:60
#, elixir-autogen, elixir-format
msgid "Send support request"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:15
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:27
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:25
#: lib/who_need_help_web/live/support_operations_live.ex:97
#, elixir-autogen, elixir-format
msgid "Sexual material involving a minor"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:177
#, elixir-autogen, elixir-format
msgid "Stated basis:"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "Subject"
msgstr ""
#: lib/who_need_help_web/live/activity_live/show.ex:696
#: lib/who_need_help_web/live/request_live/show.ex:1127
#, elixir-autogen, elixir-format
msgid "Submit a legal content-removal notice"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:97
#, elixir-autogen, elixir-format
msgid "Submit removal notice"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:89
#, elixir-autogen, elixir-format
msgid "Submit urgent removal request"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:158
#, elixir-autogen, elixir-format
msgid "Submitter"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:11
#, elixir-autogen, elixir-format
msgid "Submitting this form does not immediately sign you out or erase evidence required for an open safety investigation. Support will verify and process the request."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:147
#, elixir-autogen, elixir-format
msgid "Support"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:8
#: lib/who_need_help_web/live/support_operations_live.ex:114
#, elixir-autogen, elixir-format
msgid "Support operations"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:190
#, elixir-autogen, elixir-format
msgid "Support queue"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:16
#, elixir-autogen, elixir-format
msgid "Support request updated."
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:116
#, elixir-autogen, elixir-format
msgid "Support requests and legal removal notices are separate queues. Decisions and operator identity are audited."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/show.html.heex:16
#: lib/who_need_help_web/live/support_operations_live.ex:262
#, elixir-autogen, elixir-format
msgid "Support response"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:3
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:16
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN request"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:7
#: lib/who_need_help_web/controllers/support_html/new.html.heex:30
#: lib/who_need_help_web/live/support_operations_live.ex:79
#, elixir-autogen, elixir-format
msgid "Technical issue"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:6
#, elixir-autogen, elixir-format
msgid "This requests deletion of your Who Need Help account and associated personal data. Some records may need to be retained when required for safety, fraud prevention, legal obligations, or resolving an active dispute; any retained data must be described in the applicable retention notice."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:17
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:28
#: lib/who_need_help_web/live/support_operations_live.ex:99
#, elixir-autogen, elixir-format
msgid "Threat to life or safety"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_controller.ex:54
#, elixir-autogen, elixir-format
msgid "Too many removal notices. Please try again later."
msgstr ""
#: lib/who_need_help_web/controllers/support_controller.ex:34
#: lib/who_need_help_web/controllers/support_controller.ex:72
#, elixir-autogen, elixir-format
msgid "Too many support requests. Please try again later."
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:122
#, elixir-autogen, elixir-format
msgid "Trust and safety moderation"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:22
#: lib/who_need_help_web/live/support_operations_live.ex:190
#, elixir-autogen, elixir-format
msgid "Urgent review"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:8
#, elixir-autogen, elixir-format
msgid "Use this dedicated process when an identifiable person is shown in an intimate image or video shared without consent, including a digital forgery. You may submit for yourself or as an authorised representative."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this electronic notice for specific content on Who Need Help that you believe is illegal or infringes your rights. Ordinary safety reports inside a request or chat remain available to signed-in users."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this form for account access, technical problems, privacy questions, or other support. For illegal content or a removal request, use the dedicated removal form."
msgstr ""
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:126
#, elixir-autogen, elixir-format
msgid "View support requests"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:254
#, elixir-autogen, elixir-format
msgid "Waiting for requester"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:18
#, elixir-autogen, elixir-format
msgid "Waiting for your response"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:6
#, elixir-autogen, elixir-format
msgid "We created support request %{reference}. A private status link has been sent to the contact email when delivery is configured. Opening that link verifies the address for public requests."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:27
#, elixir-autogen, elixir-format
msgid "What do you need help with?"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:42
#, elixir-autogen, elixir-format
msgid "Who are you submitting for?"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:62
#, elixir-autogen, elixir-format
msgid "Why do you believe this content should be removed?"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:26
#, elixir-autogen, elixir-format
msgid "You have not submitted any support requests."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:30
#, elixir-autogen, elixir-format
msgid "Your full name"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:34
#, elixir-autogen, elixir-format
msgid "Your name or organisation"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:5
#, elixir-autogen, elixir-format
msgid "Your reference is %{reference}"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:45
#, elixir-autogen, elixir-format
msgid "Your relationship to the affected person or rights holder"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:150
#: lib/who_need_help_web/live/support_operations_live.ex:235
#, elixir-autogen, elixir-format
msgid "contact unverified"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:154
#, elixir-autogen, elixir-format
msgid "review by %{time}"
msgstr ""
#: lib/who_need_help_web/controllers/support_controller.ex:47
#: lib/who_need_help_web/controllers/support_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Delete my Who Need Help account"
msgstr ""
#: lib/who_need_help_web/controllers/support_controller.ex:48
#, elixir-autogen, elixir-format
msgid "Please delete my account and associated personal data."
msgstr ""

View File

@ -12,7 +12,7 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: lib/who_need_help_web/components/layouts.ex:111
#: lib/who_need_help_web/components/layouts.ex:257
#: lib/who_need_help_web/components/layouts.ex:266
#, elixir-autogen, elixir-format
msgid "Account settings"
msgstr ""
@ -30,13 +30,13 @@ msgstr ""
msgid "Ask for help"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:295
#: lib/who_need_help_web/components/layouts.ex:310
#: lib/who_need_help_web/components/layouts.ex:304
#: lib/who_need_help_web/components/layouts.ex:319
#, elixir-autogen, elixir-format
msgid "Attempting to reconnect"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:171
#: lib/who_need_help_web/components/layouts.ex:175
#, elixir-autogen, elixir-format
msgid "Categories"
msgstr ""
@ -65,13 +65,13 @@ msgid "Log in"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:114
#: lib/who_need_help_web/components/layouts.ex:260
#: lib/who_need_help_web/components/layouts.ex:269
#, elixir-autogen, elixir-format
msgid "Log out"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:108
#: lib/who_need_help_web/components/layouts.ex:254
#: lib/who_need_help_web/components/layouts.ex:263
#: lib/who_need_help_web/live/profile_live.ex:16
#, elixir-autogen, elixir-format
msgid "Profile"
@ -83,7 +83,7 @@ msgstr ""
msgid "Register"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:161
#: lib/who_need_help_web/components/layouts.ex:165
#, elixir-autogen, elixir-format
msgid "Requests"
msgstr ""
@ -93,12 +93,12 @@ msgstr ""
msgid "See nearby requests"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:302
#: lib/who_need_help_web/components/layouts.ex:311
#, elixir-autogen, elixir-format
msgid "Something went wrong!"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:287
#: lib/who_need_help_web/components/layouts.ex:296
#, elixir-autogen, elixir-format
msgid "We can't find the internet"
msgstr ""
@ -174,7 +174,7 @@ msgid "Account Settings"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:63
#: lib/who_need_help_web/components/layouts.ex:192
#: lib/who_need_help_web/components/layouts.ex:201
#, elixir-autogen, elixir-format
msgid "Account and language"
msgstr ""
@ -195,7 +195,7 @@ msgstr ""
msgid "Active"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:166
#: lib/who_need_help_web/components/layouts.ex:170
#: lib/who_need_help_web/live/activity_live/index.ex:118
#, elixir-autogen, elixir-format
msgid "Activities"
@ -367,7 +367,7 @@ msgstr ""
msgid "Briefly describe the help you need"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:147
#: lib/who_need_help_web/components/layouts.ex:151
#, elixir-autogen, elixir-format
msgid "Build Week feedback"
msgstr ""
@ -641,7 +641,7 @@ msgstr ""
msgid "Dismissed"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:71
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:76
#: lib/who_need_help_web/live/profile_live.ex:149
#, elixir-autogen, elixir-format
msgid "Display name"
@ -662,7 +662,7 @@ msgstr ""
msgid "Double-blind review"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:62
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:67
#: 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_settings_html/edit.html.heex:15
@ -817,7 +817,7 @@ msgstr ""
msgid "Helper: %{name}"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:176
#: lib/who_need_help_web/components/layouts.ex:180
#, elixir-autogen, elixir-format
msgid "Helpers"
msgstr ""
@ -872,7 +872,7 @@ msgid "Human decisions retained"
msgstr ""
#: 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:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
msgid "I am 18 or older and accept the safety rules"
msgstr ""
@ -913,9 +913,12 @@ msgstr ""
msgid "If your email is in our system, you will receive instructions for logging in shortly."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:9
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:25
#: lib/who_need_help_web/live/activity_live/show.ex:678
#: lib/who_need_help_web/live/moderation_live.ex:253
#: lib/who_need_help_web/live/request_live/show.ex:1109
#: lib/who_need_help_web/live/support_operations_live.ex:91
#, elixir-autogen, elixir-format
msgid "Impersonation"
msgstr ""
@ -1122,7 +1125,7 @@ msgstr ""
msgid "Mode"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:181
#: lib/who_need_help_web/components/layouts.ex:185
#: lib/who_need_help_web/live/moderation_live.ex:9
#: lib/who_need_help_web/live/moderation_live.ex:291
#, elixir-autogen, elixir-format
@ -1136,6 +1139,7 @@ msgid "Moderator"
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:230
#: lib/who_need_help_web/live/support_operations_live.ex:73
#: lib/who_need_help_web/user_auth.ex:306
#, elixir-autogen, elixir-format
msgid "Moderator access is required."
@ -1270,12 +1274,16 @@ msgstr ""
msgid "Only the organizer and approved participants can read or send these messages."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:21
#: lib/who_need_help_web/controllers/support_html.ex:16
#: lib/who_need_help_web/live/activity_live/index.ex:166
#: lib/who_need_help_web/live/activity_live/show.ex:342
#: lib/who_need_help_web/live/moderation_live.ex:257
#: lib/who_need_help_web/live/request_live/index.ex:176
#: lib/who_need_help_web/live/request_live/index.ex:177
#: lib/who_need_help_web/live/request_live/show.ex:636
#: lib/who_need_help_web/live/support_operations_live.ex:189
#: lib/who_need_help_web/live/support_operations_live.ex:252
#, elixir-autogen, elixir-format
msgid "Open"
msgstr ""
@ -1320,10 +1328,17 @@ msgstr ""
msgid "Organizer social links"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:18
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:29
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:49
#: lib/who_need_help_web/controllers/support_html.ex:13
#: lib/who_need_help_web/controllers/support_html/new.html.heex:35
#: lib/who_need_help_web/live/activity_live/show.ex:679
#: lib/who_need_help_web/live/moderation_live.ex:254
#: lib/who_need_help_web/live/profile_live.ex:311
#: lib/who_need_help_web/live/request_live/show.ex:1110
#: lib/who_need_help_web/live/support_operations_live.ex:85
#: lib/who_need_help_web/live/support_operations_live.ex:100
#, elixir-autogen, elixir-format
msgid "Other"
msgstr ""
@ -1374,6 +1389,7 @@ msgid "Please check the entered data."
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:240
#: lib/who_need_help_web/live/support_operations_live.ex:75
#, elixir-autogen, elixir-format
msgid "Please check the submitted fields."
msgstr ""
@ -1497,6 +1513,7 @@ msgid "READ BEFORE USING THE SERVICE"
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:290
#: lib/who_need_help_web/live/support_operations_live.ex:111
#, elixir-autogen, elixir-format
msgid "RESTRICTED WORKSPACE"
msgstr ""
@ -1517,11 +1534,12 @@ msgstr ""
msgid "Rating"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:77
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:82
#, elixir-autogen, elixir-format
msgid "Read the"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:20
#: lib/who_need_help_web/live/activity_live/show.ex:672
#, elixir-autogen, elixir-format
msgid "Reason"
@ -1633,8 +1651,10 @@ msgstr ""
msgid "Resolution note"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:19
#: lib/who_need_help_web/live/moderation_live.ex:259
#: lib/who_need_help_web/live/moderation_live.ex:365
#: lib/who_need_help_web/live/support_operations_live.ex:255
#, elixir-autogen, elixir-format
msgid "Resolved"
msgstr ""
@ -1662,8 +1682,12 @@ msgstr ""
msgid "Reviewed"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:23
#: lib/who_need_help_web/controllers/support_html.ex:17
#: lib/who_need_help_web/live/moderation_live.ex:258
#: lib/who_need_help_web/live/moderation_live.ex:364
#: lib/who_need_help_web/live/support_operations_live.ex:191
#: lib/who_need_help_web/live/support_operations_live.ex:253
#, elixir-autogen, elixir-format
msgid "Reviewing"
msgstr ""
@ -2129,12 +2153,12 @@ msgstr ""
msgid "Use a public first meeting point. Do not publish a home address, access code, travel document, or other sensitive information."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:349
#: lib/who_need_help_web/components/layouts.ex:358
#, elixir-autogen, elixir-format
msgid "Use dark theme"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:340
#: lib/who_need_help_web/components/layouts.ex:349
#, elixir-autogen, elixir-format
msgid "Use light theme"
msgstr ""
@ -2150,7 +2174,7 @@ msgstr ""
msgid "Use private chat and optional live location sharing."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:331
#: lib/who_need_help_web/components/layouts.ex:340
#, elixir-autogen, elixir-format
msgid "Use system theme"
msgstr ""
@ -2266,7 +2290,7 @@ msgstr ""
msgid "Who Need Help home"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
msgid "Who Need Help is not an emergency or medical service. Medicine requests are limited to pickup of legal items already purchased or reserved."
msgstr ""
@ -2407,6 +2431,7 @@ msgstr ""
msgid "Your request is now visible to nearby helpers."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:6
#: lib/who_need_help_web/live/request_live/index.ex:342
#, elixir-autogen, elixir-format
msgid "Your requests"
@ -2432,7 +2457,7 @@ msgstr ""
msgid "activity message"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:79
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:84
#, elixir-autogen, elixir-format
msgid "before confirming."
msgstr ""
@ -2509,7 +2534,7 @@ msgstr ""
msgid "rating %{rating}"
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:78
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:83
#, elixir-autogen, elixir-format
msgid "safety rules"
msgstr ""
@ -2617,7 +2642,9 @@ msgstr ""
msgid "Reciprocal rating ring"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:26
#: lib/who_need_help_web/live/moderation_live.ex:263
#: lib/who_need_help_web/live/support_operations_live.ex:194
#, elixir-autogen, elixir-format
msgid "Rejected"
msgstr ""
@ -2650,6 +2677,8 @@ msgstr ""
#: lib/who_need_help_web/live/profile_live.ex:354
#: lib/who_need_help_web/live/request_live/index.ex:303
#: lib/who_need_help_web/live/request_live/index.ex:360
#: lib/who_need_help_web/live/support_operations_live.ex:215
#: lib/who_need_help_web/live/support_operations_live.ex:276
#, elixir-autogen, elixir-format
msgid "Load more"
msgstr ""
@ -2736,6 +2765,7 @@ msgid "The registration form is invalid."
msgstr ""
#: lib/who_need_help_web/live/moderation_live.ex:239
#: lib/who_need_help_web/live/support_operations_live.ex:74
#, elixir-autogen, elixir-format
msgid "The selected record is no longer available."
msgstr ""
@ -2835,7 +2865,7 @@ msgstr ""
msgid "Connect Google only after signing in here. We never merge accounts automatically by matching email addresses."
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
msgid "Create account and email me a link"
msgstr ""
@ -2897,7 +2927,7 @@ msgstr ""
msgid "Google sign-in will be available after the operator configures it."
msgstr ""
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:100
#, elixir-autogen, elixir-format
msgid "Sending link..."
msgstr ""
@ -2981,3 +3011,632 @@ msgstr "Google sign-in disconnected."
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr "No Google account is connected."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:45
#, elixir-autogen, elixir-format
msgid "A person I am authorised to represent"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:8
#, elixir-autogen, elixir-format
msgid "A private status link has been sent when a contact email was provided and delivery is configured. Opening that link verifies the contact address. Keep the reference for follow-up."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:3
#, elixir-autogen, elixir-format
msgid "ACCOUNT AND DATA"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:6
#: lib/who_need_help_web/controllers/support_html/new.html.heex:29
#: lib/who_need_help_web/live/support_operations_live.ex:78
#, elixir-autogen, elixir-format, fuzzy
msgid "Account access"
msgstr ""
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:115
#, elixir-autogen, elixir-format
msgid "Account and personal data"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:10
#: lib/who_need_help_web/live/support_operations_live.ex:82
#, elixir-autogen, elixir-format, fuzzy
msgid "Account deletion"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:26
#, elixir-autogen, elixir-format, fuzzy
msgid "Account email"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:25
#: lib/who_need_help_web/live/support_operations_live.ex:193
#, elixir-autogen, elixir-format, fuzzy
msgid "Action taken"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:34
#, elixir-autogen, elixir-format
msgid "Additional information"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:32
#, elixir-autogen, elixir-format
msgid "Appeal a moderation decision"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:13
#, elixir-autogen, elixir-format
msgid "Back to removal form"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:11
#, elixir-autogen, elixir-format
msgid "Back to support"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "CONTENT REMOVAL"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:4
#, elixir-autogen, elixir-format
msgid "Check your email"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:27
#, elixir-autogen, elixir-format, fuzzy
msgid "Choose a category"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:31
#, elixir-autogen, elixir-format
msgid "Choose a reason"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:51
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:47
#, elixir-autogen, elixir-format
msgid "Choose a relationship"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:37
#, elixir-autogen, elixir-format
msgid "Choose a topic"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:27
#: lib/who_need_help_web/controllers/support_html.ex:20
#: lib/who_need_help_web/live/support_operations_live.ex:195
#: lib/who_need_help_web/live/support_operations_live.ex:256
#, elixir-autogen, elixir-format, fuzzy
msgid "Closed"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:160
#, elixir-autogen, elixir-format
msgid "Contact"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Contact Who Need Help"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:38
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:34
#: lib/who_need_help_web/controllers/support_html/new.html.heex:43
#, elixir-autogen, elixir-format
msgid "Contact email"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:127
#, elixir-autogen, elixir-format
msgid "Content removal and TAKE IT DOWN"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:13
#, elixir-autogen, elixir-format
msgid "Content-removal notice"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:8
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:90
#, elixir-autogen, elixir-format
msgid "Copyright"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:76
#, elixir-autogen, elixir-format, fuzzy
msgid "Could not update the request. Please try again."
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:11
#: lib/who_need_help_web/controllers/support_html/new.html.heex:34
#: lib/who_need_help_web/live/support_operations_live.ex:83
#, elixir-autogen, elixir-format
msgid "Data export"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:201
#, elixir-autogen, elixir-format
msgid "Decision or information request"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:30
#, elixir-autogen, elixir-format
msgid "Decision or request for information"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:19
#, elixir-autogen, elixir-format
msgid "Delete an account"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:52
#, elixir-autogen, elixir-format
msgid "Describe the problem"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:56
#, elixir-autogen, elixir-format
msgid "Do not include passwords, payment card details, access codes, prescriptions, or unnecessary medical information."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:13
#, elixir-autogen, elixir-format
msgid "Do not upload the image or video. Provide only the exact Who Need Help URL where it appears and enough text to identify it safely."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:72
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:68
#, elixir-autogen, elixir-format
msgid "Electronic signature (type your full name)"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:56
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:53
#, elixir-autogen, elixir-format
msgid "Exact content URLs — one per line"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:220
#, elixir-autogen, elixir-format
msgid "General support and data requests"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "I am an authorised representative"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "I am the affected person or rights holder"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:78
#, elixir-autogen, elixir-format
msgid "I believe in good faith that the identified content is illegal or infringes the stated right."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:84
#, elixir-autogen, elixir-format
msgid "I confirm that the information in this request is accurate and that I am the depicted person or authorised to act for them."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:87
#, elixir-autogen, elixir-format
msgid "I confirm that this notice is accurate and complete to the best of my knowledge."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:75
#, elixir-autogen, elixir-format
msgid "I have a good-faith belief that this intimate visual material was shared without consent."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:60
#, elixir-autogen, elixir-format
msgid "Identify the material without reproducing it and explain why it is non-consensual"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:93
#, elixir-autogen, elixir-format
msgid "Identity and contact fields may be omitted for reports of sexual material involving a minor. Do not include or upload the material itself."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:6
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:22
#: lib/who_need_help_web/live/support_operations_live.ex:88
#, elixir-autogen, elixir-format
msgid "Illegal content"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/show.html.heex:20
#, elixir-autogen, elixir-format
msgid "Keep this status link private. A copy is sent to the contact email when email delivery is configured."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:34
#, elixir-autogen, elixir-format
msgid "Keep this status link private. The submitter identity is not shown publicly or automatically disclosed to the person who posted the reported content."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:68
#, elixir-autogen, elixir-format
msgid "Law, right, or policy involved, if known"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:162
#, elixir-autogen, elixir-format, fuzzy
msgid "Locations"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:22
#, elixir-autogen, elixir-format
msgid "Material involved"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:9
#: lib/who_need_help_web/live/support_operations_live.ex:81
#, elixir-autogen, elixir-format, fuzzy
msgid "Moderation appeal"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:24
#: lib/who_need_help_web/live/support_operations_live.ex:192
#, elixir-autogen, elixir-format
msgid "More information needed"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:44
#, elixir-autogen, elixir-format
msgid "Myself"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "NOTICE RECEIVED"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:8
#, elixir-autogen, elixir-format, fuzzy
msgid "New request"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:207
#, elixir-autogen, elixir-format
msgid "No removal notices."
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:268
#, elixir-autogen, elixir-format
msgid "No support requests."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:12
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:26
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:94
#, elixir-autogen, elixir-format
msgid "Non-consensual intimate image or video"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:159
#: lib/who_need_help_web/live/support_operations_live.ex:161
#, elixir-autogen, elixir-format
msgid "Not provided"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:12
#: lib/who_need_help_web/controllers/support_html/new.html.heex:33
#: lib/who_need_help_web/live/support_operations_live.ex:84
#, elixir-autogen, elixir-format
msgid "Privacy request"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:7
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:23
#: lib/who_need_help_web/live/support_operations_live.ex:89
#, elixir-autogen, elixir-format
msgid "Privacy violation"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:11
#, elixir-autogen, elixir-format
msgid "Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "REQUEST RECEIVED"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:24
#, elixir-autogen, elixir-format
msgid "Removal notice updated."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/support_html/new.html.heex:13
#, elixir-autogen, elixir-format, fuzzy
msgid "Report content"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Report illegal or harmful content"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:16
#, elixir-autogen, elixir-format
msgid "Reported locations"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:4
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:37
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:123
#, elixir-autogen, elixir-format, fuzzy
msgid "Request account deletion"
msgstr ""
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:117
#, elixir-autogen, elixir-format
msgid "Request deletion of your account and associated personal data, or contact support about access and export requests."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:5
#, elixir-autogen, elixir-format
msgid "Request removal of intimate visual material"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:5
#: lib/who_need_help_web/controllers/support_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "SUPPORT"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:8
#: lib/who_need_help_web/controllers/support_html/new.html.heex:31
#: lib/who_need_help_web/live/support_operations_live.ex:80
#, elixir-autogen, elixir-format, fuzzy
msgid "Safety concern"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:203
#: lib/who_need_help_web/live/support_operations_live.ex:264
#, elixir-autogen, elixir-format
msgid "Save and notify"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:60
#, elixir-autogen, elixir-format
msgid "Send support request"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:15
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:27
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:25
#: lib/who_need_help_web/live/support_operations_live.ex:97
#, elixir-autogen, elixir-format
msgid "Sexual material involving a minor"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:177
#, elixir-autogen, elixir-format
msgid "Stated basis:"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "Subject"
msgstr ""
#: lib/who_need_help_web/live/activity_live/show.ex:696
#: lib/who_need_help_web/live/request_live/show.ex:1127
#, elixir-autogen, elixir-format
msgid "Submit a legal content-removal notice"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:97
#, elixir-autogen, elixir-format, fuzzy
msgid "Submit removal notice"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:89
#, elixir-autogen, elixir-format
msgid "Submit urgent removal request"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:158
#, elixir-autogen, elixir-format
msgid "Submitter"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:11
#, elixir-autogen, elixir-format
msgid "Submitting this form does not immediately sign you out or erase evidence required for an open safety investigation. Support will verify and process the request."
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:147
#, elixir-autogen, elixir-format
msgid "Support"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:8
#: lib/who_need_help_web/live/support_operations_live.ex:114
#, elixir-autogen, elixir-format
msgid "Support operations"
msgstr ""
#: lib/who_need_help_web/components/layouts.ex:190
#, elixir-autogen, elixir-format
msgid "Support queue"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:16
#, elixir-autogen, elixir-format
msgid "Support request updated."
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:116
#, elixir-autogen, elixir-format
msgid "Support requests and legal removal notices are separate queues. Decisions and operator identity are audited."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/show.html.heex:16
#: lib/who_need_help_web/live/support_operations_live.ex:262
#, elixir-autogen, elixir-format
msgid "Support response"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:3
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:16
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN request"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:7
#: lib/who_need_help_web/controllers/support_html/new.html.heex:30
#: lib/who_need_help_web/live/support_operations_live.ex:79
#, elixir-autogen, elixir-format
msgid "Technical issue"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:6
#, elixir-autogen, elixir-format
msgid "This requests deletion of your Who Need Help account and associated personal data. Some records may need to be retained when required for safety, fraud prevention, legal obligations, or resolving an active dispute; any retained data must be described in the applicable retention notice."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:17
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:28
#: lib/who_need_help_web/live/support_operations_live.ex:99
#, elixir-autogen, elixir-format
msgid "Threat to life or safety"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_controller.ex:54
#, elixir-autogen, elixir-format
msgid "Too many removal notices. Please try again later."
msgstr ""
#: lib/who_need_help_web/controllers/support_controller.ex:34
#: lib/who_need_help_web/controllers/support_controller.ex:72
#, elixir-autogen, elixir-format
msgid "Too many support requests. Please try again later."
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:122
#, elixir-autogen, elixir-format
msgid "Trust and safety moderation"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html.ex:22
#: lib/who_need_help_web/live/support_operations_live.ex:190
#, elixir-autogen, elixir-format
msgid "Urgent review"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:8
#, elixir-autogen, elixir-format
msgid "Use this dedicated process when an identifiable person is shown in an intimate image or video shared without consent, including a digital forgery. You may submit for yourself or as an authorised representative."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this electronic notice for specific content on Who Need Help that you believe is illegal or infringes your rights. Ordinary safety reports inside a request or chat remain available to signed-in users."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this form for account access, technical problems, privacy questions, or other support. For illegal content or a removal request, use the dedicated removal form."
msgstr ""
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:126
#, elixir-autogen, elixir-format
msgid "View support requests"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:254
#, elixir-autogen, elixir-format, fuzzy
msgid "Waiting for requester"
msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:18
#, elixir-autogen, elixir-format
msgid "Waiting for your response"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/received.html.heex:6
#, elixir-autogen, elixir-format
msgid "We created support request %{reference}. A private status link has been sent to the contact email when delivery is configured. Opening that link verifies the address for public requests."
msgstr ""
#: lib/who_need_help_web/controllers/support_html/new.html.heex:27
#, elixir-autogen, elixir-format, fuzzy
msgid "What do you need help with?"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:42
#, elixir-autogen, elixir-format
msgid "Who are you submitting for?"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:62
#, elixir-autogen, elixir-format
msgid "Why do you believe this content should be removed?"
msgstr ""
#: lib/who_need_help_web/controllers/support_html/index.html.heex:26
#, elixir-autogen, elixir-format
msgid "You have not submitted any support requests."
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:30
#, elixir-autogen, elixir-format
msgid "Your full name"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:34
#, elixir-autogen, elixir-format
msgid "Your name or organisation"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:5
#, elixir-autogen, elixir-format
msgid "Your reference is %{reference}"
msgstr ""
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:45
#, elixir-autogen, elixir-format
msgid "Your relationship to the affected person or rights holder"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:150
#: lib/who_need_help_web/live/support_operations_live.ex:235
#, elixir-autogen, elixir-format, fuzzy
msgid "contact unverified"
msgstr ""
#: lib/who_need_help_web/live/support_operations_live.ex:154
#, elixir-autogen, elixir-format
msgid "review by %{time}"
msgstr ""
#: lib/who_need_help_web/controllers/support_controller.ex:47
#: lib/who_need_help_web/controllers/support_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Delete my Who Need Help account"
msgstr ""
#: lib/who_need_help_web/controllers/support_controller.ex:48
#, elixir-autogen, elixir-format
msgid "Please delete my account and associated personal data."
msgstr ""

View File

@ -12,7 +12,7 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100 != 11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10||n%100>=20) ? 1 : 2);\n"
#: lib/who_need_help_web/components/layouts.ex:111
#: lib/who_need_help_web/components/layouts.ex:257
#: lib/who_need_help_web/components/layouts.ex:266
#, elixir-autogen, elixir-format
msgid "Account settings"
msgstr "Настройки аккаунта"
@ -30,13 +30,13 @@ msgstr "Действия"
msgid "Ask for help"
msgstr "Попросить о помощи"
#: lib/who_need_help_web/components/layouts.ex:295
#: lib/who_need_help_web/components/layouts.ex:310
#: lib/who_need_help_web/components/layouts.ex:304
#: lib/who_need_help_web/components/layouts.ex:319
#, elixir-autogen, elixir-format
msgid "Attempting to reconnect"
msgstr "Пытаемся восстановить соединение"
#: lib/who_need_help_web/components/layouts.ex:171
#: lib/who_need_help_web/components/layouts.ex:175
#, elixir-autogen, elixir-format
msgid "Categories"
msgstr "Категории"
@ -65,13 +65,13 @@ msgid "Log in"
msgstr "Войти"
#: lib/who_need_help_web/components/layouts.ex:114
#: lib/who_need_help_web/components/layouts.ex:260
#: lib/who_need_help_web/components/layouts.ex:269
#, elixir-autogen, elixir-format
msgid "Log out"
msgstr "Выйти"
#: lib/who_need_help_web/components/layouts.ex:108
#: lib/who_need_help_web/components/layouts.ex:254
#: lib/who_need_help_web/components/layouts.ex:263
#: lib/who_need_help_web/live/profile_live.ex:16
#, elixir-autogen, elixir-format
msgid "Profile"
@ -83,7 +83,7 @@ msgstr "Профиль"
msgid "Register"
msgstr "Регистрация"
#: lib/who_need_help_web/components/layouts.ex:161
#: lib/who_need_help_web/components/layouts.ex:165
#, elixir-autogen, elixir-format
msgid "Requests"
msgstr "Заявки"
@ -93,12 +93,12 @@ msgstr "Заявки"
msgid "See nearby requests"
msgstr "Заявки рядом"
#: lib/who_need_help_web/components/layouts.ex:302
#: lib/who_need_help_web/components/layouts.ex:311
#, elixir-autogen, elixir-format
msgid "Something went wrong!"
msgstr "Что-то пошло не так!"
#: lib/who_need_help_web/components/layouts.ex:287
#: lib/who_need_help_web/components/layouts.ex:296
#, elixir-autogen, elixir-format
msgid "We can't find the internet"
msgstr "Нет соединения с интернетом"
@ -179,7 +179,7 @@ msgid "Account Settings"
msgstr "Настройки аккаунта"
#: lib/who_need_help_web/components/layouts.ex:63
#: lib/who_need_help_web/components/layouts.ex:192
#: lib/who_need_help_web/components/layouts.ex:201
#, elixir-autogen, elixir-format
msgid "Account and language"
msgstr "Аккаунт и язык"
@ -200,7 +200,7 @@ msgstr "Центр действий"
msgid "Active"
msgstr "Активный"
#: lib/who_need_help_web/components/layouts.ex:166
#: lib/who_need_help_web/components/layouts.ex:170
#: lib/who_need_help_web/live/activity_live/index.ex:118
#, elixir-autogen, elixir-format
msgid "Activities"
@ -384,7 +384,7 @@ msgstr ""
msgid "Briefly describe the help you need"
msgstr "Кратко опишите, какая помощь вам нужна"
#: lib/who_need_help_web/components/layouts.ex:147
#: lib/who_need_help_web/components/layouts.ex:151
#, elixir-autogen, elixir-format
msgid "Build Week feedback"
msgstr "Отчёт для Build Week"
@ -667,7 +667,7 @@ msgstr ""
msgid "Dismissed"
msgstr "Отклонено"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:71
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:76
#: lib/who_need_help_web/live/profile_live.ex:149
#, elixir-autogen, elixir-format
msgid "Display name"
@ -691,7 +691,7 @@ msgstr "Нет аккаунта?"
msgid "Double-blind review"
msgstr "Двусторонний скрытый отзыв"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:62
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:67
#: 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_settings_html/edit.html.heex:15
@ -857,7 +857,7 @@ msgstr "Помощник"
msgid "Helper: %{name}"
msgstr "Помощник: %{name}"
#: lib/who_need_help_web/components/layouts.ex:176
#: lib/who_need_help_web/components/layouts.ex:180
#, elixir-autogen, elixir-format
msgid "Helpers"
msgstr "Помощники"
@ -933,7 +933,7 @@ msgid "Human decisions retained"
msgstr "Решения остаются за человеком"
#: 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:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
msgid "I am 18 or older and accept the safety rules"
msgstr "Мне 18 лет и я принимаю правила безопасности."
@ -987,9 +987,12 @@ msgstr ""
"Если этот адрес электронной почты есть в нашей системе, вскоре вы получите "
"инструкции для входа."
#: lib/who_need_help_web/controllers/content_removal_html.ex:9
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:25
#: lib/who_need_help_web/live/activity_live/show.ex:678
#: lib/who_need_help_web/live/moderation_live.ex:253
#: lib/who_need_help_web/live/request_live/show.ex:1109
#: lib/who_need_help_web/live/support_operations_live.ex:91
#, elixir-autogen, elixir-format
msgid "Impersonation"
msgstr "Выдача себя за другого человека"
@ -1212,7 +1215,7 @@ msgstr "Написать одобренной группе"
msgid "Mode"
msgstr "Режим"
#: lib/who_need_help_web/components/layouts.ex:181
#: lib/who_need_help_web/components/layouts.ex:185
#: lib/who_need_help_web/live/moderation_live.ex:9
#: lib/who_need_help_web/live/moderation_live.ex:291
#, elixir-autogen, elixir-format
@ -1226,6 +1229,7 @@ msgid "Moderator"
msgstr "Модератор"
#: lib/who_need_help_web/live/moderation_live.ex:230
#: lib/who_need_help_web/live/support_operations_live.ex:73
#: lib/who_need_help_web/user_auth.ex:306
#, elixir-autogen, elixir-format
msgid "Moderator access is required."
@ -1370,12 +1374,16 @@ msgstr ""
"Только организатор и одобренные участники могут читать или отправлять эти "
"сообщения."
#: lib/who_need_help_web/controllers/content_removal_html.ex:21
#: lib/who_need_help_web/controllers/support_html.ex:16
#: lib/who_need_help_web/live/activity_live/index.ex:166
#: lib/who_need_help_web/live/activity_live/show.ex:342
#: lib/who_need_help_web/live/moderation_live.ex:257
#: lib/who_need_help_web/live/request_live/index.ex:176
#: lib/who_need_help_web/live/request_live/index.ex:177
#: lib/who_need_help_web/live/request_live/show.ex:636
#: lib/who_need_help_web/live/support_operations_live.ex:189
#: lib/who_need_help_web/live/support_operations_live.ex:252
#, elixir-autogen, elixir-format
msgid "Open"
msgstr "Открыта"
@ -1420,10 +1428,17 @@ msgstr "Управление организатора"
msgid "Organizer social links"
msgstr "Ссылки организатора на соцсети"
#: lib/who_need_help_web/controllers/content_removal_html.ex:18
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:29
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:49
#: lib/who_need_help_web/controllers/support_html.ex:13
#: lib/who_need_help_web/controllers/support_html/new.html.heex:35
#: lib/who_need_help_web/live/activity_live/show.ex:679
#: lib/who_need_help_web/live/moderation_live.ex:254
#: lib/who_need_help_web/live/profile_live.ex:311
#: lib/who_need_help_web/live/request_live/show.ex:1110
#: lib/who_need_help_web/live/support_operations_live.ex:85
#: lib/who_need_help_web/live/support_operations_live.ex:100
#, elixir-autogen, elixir-format
msgid "Other"
msgstr "Другое"
@ -1474,6 +1489,7 @@ msgid "Please check the entered data."
msgstr "Пожалуйста, проверьте введенные данные."
#: lib/who_need_help_web/live/moderation_live.ex:240
#: lib/who_need_help_web/live/support_operations_live.ex:75
#, elixir-autogen, elixir-format
msgid "Please check the submitted fields."
msgstr "Пожалуйста, проверьте представленные поля."
@ -1610,6 +1626,7 @@ msgid "READ BEFORE USING THE SERVICE"
msgstr "ПРОЧИТАЙТЕ ПЕРЕД ИСПОЛЬЗОВАНИЕМ СЕРВИСА"
#: lib/who_need_help_web/live/moderation_live.ex:290
#: lib/who_need_help_web/live/support_operations_live.ex:111
#, elixir-autogen, elixir-format
msgid "RESTRICTED WORKSPACE"
msgstr "ОГРАНИЧЕННАЯ РАБОЧАЯ ОБЛАСТЬ"
@ -1634,11 +1651,12 @@ msgstr ""
msgid "Rating"
msgstr "Оценка"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:77
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:82
#, elixir-autogen, elixir-format
msgid "Read the"
msgstr "Прочитайте"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:20
#: lib/who_need_help_web/live/activity_live/show.ex:672
#, elixir-autogen, elixir-format
msgid "Reason"
@ -1752,8 +1770,10 @@ msgstr "Автор заявки: %{count} завершено"
msgid "Resolution note"
msgstr "Примечание к решению"
#: lib/who_need_help_web/controllers/support_html.ex:19
#: lib/who_need_help_web/live/moderation_live.ex:259
#: lib/who_need_help_web/live/moderation_live.ex:365
#: lib/who_need_help_web/live/support_operations_live.ex:255
#, elixir-autogen, elixir-format
msgid "Resolved"
msgstr "Решено"
@ -1782,8 +1802,12 @@ msgstr ""
msgid "Reviewed"
msgstr "Проверено"
#: lib/who_need_help_web/controllers/content_removal_html.ex:23
#: lib/who_need_help_web/controllers/support_html.ex:17
#: lib/who_need_help_web/live/moderation_live.ex:258
#: lib/who_need_help_web/live/moderation_live.ex:364
#: lib/who_need_help_web/live/support_operations_live.ex:191
#: lib/who_need_help_web/live/support_operations_live.ex:253
#, elixir-autogen, elixir-format
msgid "Reviewing"
msgstr "На рассмотрении"
@ -2269,12 +2293,12 @@ msgstr ""
"адрес, код доступа, документ для поездки или другую чувствительную "
"информацию."
#: lib/who_need_help_web/components/layouts.ex:349
#: lib/who_need_help_web/components/layouts.ex:358
#, elixir-autogen, elixir-format
msgid "Use dark theme"
msgstr "Включить тёмную тему"
#: lib/who_need_help_web/components/layouts.ex:340
#: lib/who_need_help_web/components/layouts.ex:349
#, elixir-autogen, elixir-format
msgid "Use light theme"
msgstr "Включить светлую тему"
@ -2292,7 +2316,7 @@ msgstr ""
"Используйте приватный чат и, по желанию, передачу геопозиции в реальном "
"времени."
#: lib/who_need_help_web/components/layouts.ex:331
#: lib/who_need_help_web/components/layouts.ex:340
#, elixir-autogen, elixir-format
msgid "Use system theme"
msgstr "Использовать системную тему"
@ -2414,7 +2438,7 @@ msgstr ""
msgid "Who Need Help home"
msgstr "Главная Who Need Help"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
msgid "Who Need Help is not an emergency or medical service. Medicine requests are limited to pickup of legal items already purchased or reserved."
msgstr ""
@ -2567,6 +2591,7 @@ msgstr "Ваш профиль"
msgid "Your request is now visible to nearby helpers."
msgstr "Теперь вашу заявку видят помощники рядом."
#: lib/who_need_help_web/controllers/support_html/index.html.heex:6
#: lib/who_need_help_web/live/request_live/index.ex:342
#, elixir-autogen, elixir-format
msgid "Your requests"
@ -2593,7 +2618,7 @@ msgstr "активность"
msgid "activity message"
msgstr "сообщение активности"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:79
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:84
#, elixir-autogen, elixir-format
msgid "before confirming."
msgstr "перед подтверждением."
@ -2670,7 +2695,7 @@ msgstr "оценка"
msgid "rating %{rating}"
msgstr "оценка %{rating}"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:78
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:83
#, elixir-autogen, elixir-format
msgid "safety rules"
msgstr "Правила безопасности"
@ -2778,7 +2803,9 @@ msgstr "Объединено"
msgid "Reciprocal rating ring"
msgstr "Кольцо взаимных оценок"
#: lib/who_need_help_web/controllers/content_removal_html.ex:26
#: lib/who_need_help_web/live/moderation_live.ex:263
#: lib/who_need_help_web/live/support_operations_live.ex:194
#, elixir-autogen, elixir-format
msgid "Rejected"
msgstr "Отклонено"
@ -2811,6 +2838,8 @@ msgstr "Загрузить предыдущие сообщения"
#: lib/who_need_help_web/live/profile_live.ex:354
#: lib/who_need_help_web/live/request_live/index.ex:303
#: lib/who_need_help_web/live/request_live/index.ex:360
#: lib/who_need_help_web/live/support_operations_live.ex:215
#: lib/who_need_help_web/live/support_operations_live.ex:276
#, elixir-autogen, elixir-format
msgid "Load more"
msgstr "Загрузить ещё"
@ -2897,6 +2926,7 @@ msgid "The registration form is invalid."
msgstr "Форма регистрации заполнена неверно."
#: lib/who_need_help_web/live/moderation_live.ex:239
#: lib/who_need_help_web/live/support_operations_live.ex:74
#, elixir-autogen, elixir-format
msgid "The selected record is no longer available."
msgstr "Выбранная запись больше недоступна."
@ -2996,7 +3026,7 @@ msgstr "Подключить аккаунт Google"
msgid "Connect Google only after signing in here. We never merge accounts automatically by matching email addresses."
msgstr "Подключайте Google только после входа здесь. Мы никогда не объединяем аккаунты автоматически по совпадению email."
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
msgid "Create account and email me a link"
msgstr "Создать аккаунт и отправить ссылку на email"
@ -3058,7 +3088,7 @@ msgstr "Сессия входа через Google недействительна
msgid "Google sign-in will be available after the operator configures it."
msgstr "Вход через Google станет доступен после настройки оператором."
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:100
#, elixir-autogen, elixir-format
msgid "Sending link..."
msgstr "Отправляем ссылку..."
@ -3142,3 +3172,632 @@ msgstr "Вход через Google отключён."
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr "Аккаунт Google не подключён."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:45
#, elixir-autogen, elixir-format
msgid "A person I am authorised to represent"
msgstr "Лицо, которое я уполномочен представлять"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:8
#, elixir-autogen, elixir-format
msgid "A private status link has been sent when a contact email was provided and delivery is configured. Opening that link verifies the contact address. Keep the reference for follow-up."
msgstr "Если указан контактный email и настроена доставка писем, на него отправлена приватная ссылка для проверки статуса. Переход по ссылке подтверждает адрес. Сохраните номер обращения."
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:3
#, elixir-autogen, elixir-format
msgid "ACCOUNT AND DATA"
msgstr "АККАУНТ И ДАННЫЕ"
#: lib/who_need_help_web/controllers/support_html.ex:6
#: lib/who_need_help_web/controllers/support_html/new.html.heex:29
#: lib/who_need_help_web/live/support_operations_live.ex:78
#, elixir-autogen, elixir-format
msgid "Account access"
msgstr "Доступ к аккаунту"
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:115
#, elixir-autogen, elixir-format
msgid "Account and personal data"
msgstr "Аккаунт и персональные данные"
#: lib/who_need_help_web/controllers/support_html.ex:10
#: lib/who_need_help_web/live/support_operations_live.ex:82
#, elixir-autogen, elixir-format
msgid "Account deletion"
msgstr "Удаление аккаунта"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:26
#, elixir-autogen, elixir-format
msgid "Account email"
msgstr "Email аккаунта"
#: lib/who_need_help_web/controllers/content_removal_html.ex:25
#: lib/who_need_help_web/live/support_operations_live.ex:193
#, elixir-autogen, elixir-format
msgid "Action taken"
msgstr "Приняты меры"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:34
#, elixir-autogen, elixir-format
msgid "Additional information"
msgstr "Дополнительная информация"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:32
#, elixir-autogen, elixir-format
msgid "Appeal a moderation decision"
msgstr "Обжаловать решение модерации"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:13
#, elixir-autogen, elixir-format
msgid "Back to removal form"
msgstr "Вернуться к форме удаления"
#: lib/who_need_help_web/controllers/support_html/received.html.heex:11
#, elixir-autogen, elixir-format
msgid "Back to support"
msgstr "Вернуться в поддержку"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "CONTENT REMOVAL"
msgstr "УДАЛЕНИЕ КОНТЕНТА"
#: lib/who_need_help_web/controllers/support_html/received.html.heex:4
#, elixir-autogen, elixir-format
msgid "Check your email"
msgstr "Проверьте почту"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:27
#, elixir-autogen, elixir-format
msgid "Choose a category"
msgstr "Выберите категорию"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:31
#, elixir-autogen, elixir-format
msgid "Choose a reason"
msgstr "Выберите причину"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:51
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:47
#, elixir-autogen, elixir-format
msgid "Choose a relationship"
msgstr "Выберите отношение"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:37
#, elixir-autogen, elixir-format
msgid "Choose a topic"
msgstr "Выберите тему"
#: lib/who_need_help_web/controllers/content_removal_html.ex:27
#: lib/who_need_help_web/controllers/support_html.ex:20
#: lib/who_need_help_web/live/support_operations_live.ex:195
#: lib/who_need_help_web/live/support_operations_live.ex:256
#, elixir-autogen, elixir-format
msgid "Closed"
msgstr "Закрыто"
#: lib/who_need_help_web/live/support_operations_live.ex:160
#, elixir-autogen, elixir-format
msgid "Contact"
msgstr "Контакт"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Contact Who Need Help"
msgstr "Связаться с Who Need Help"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:38
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:34
#: lib/who_need_help_web/controllers/support_html/new.html.heex:43
#, elixir-autogen, elixir-format
msgid "Contact email"
msgstr "Контактный email"
#: lib/who_need_help_web/live/support_operations_live.ex:127
#, elixir-autogen, elixir-format
msgid "Content removal and TAKE IT DOWN"
msgstr "Удаление контента и TAKE IT DOWN"
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:13
#, elixir-autogen, elixir-format
msgid "Content-removal notice"
msgstr "Уведомление об удалении контента"
#: lib/who_need_help_web/controllers/content_removal_html.ex:8
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:90
#, elixir-autogen, elixir-format
msgid "Copyright"
msgstr "Авторские права"
#: lib/who_need_help_web/live/support_operations_live.ex:76
#, elixir-autogen, elixir-format
msgid "Could not update the request. Please try again."
msgstr "Не удалось обновить обращение. Попробуйте ещё раз."
#: lib/who_need_help_web/controllers/support_html.ex:11
#: lib/who_need_help_web/controllers/support_html/new.html.heex:34
#: lib/who_need_help_web/live/support_operations_live.ex:83
#, elixir-autogen, elixir-format
msgid "Data export"
msgstr "Экспорт данных"
#: lib/who_need_help_web/live/support_operations_live.ex:201
#, elixir-autogen, elixir-format
msgid "Decision or information request"
msgstr "Решение или запрос дополнительной информации"
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:30
#, elixir-autogen, elixir-format
msgid "Decision or request for information"
msgstr "Решение или запрос дополнительной информации"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:19
#, elixir-autogen, elixir-format
msgid "Delete an account"
msgstr "Удалить аккаунт"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:52
#, elixir-autogen, elixir-format
msgid "Describe the problem"
msgstr "Опишите проблему"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:56
#, elixir-autogen, elixir-format
msgid "Do not include passwords, payment card details, access codes, prescriptions, or unnecessary medical information."
msgstr "Не указывайте пароли, данные платёжных карт, коды доступа, рецепты или лишнюю медицинскую информацию."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:13
#, elixir-autogen, elixir-format
msgid "Do not upload the image or video. Provide only the exact Who Need Help URL where it appears and enough text to identify it safely."
msgstr "Не загружайте изображение или видео. Укажите только точный URL в Who Need Help и безопасное текстовое описание, достаточное для идентификации материала."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:72
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:68
#, elixir-autogen, elixir-format
msgid "Electronic signature (type your full name)"
msgstr "Электронная подпись (введите полное имя)"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:56
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:53
#, elixir-autogen, elixir-format
msgid "Exact content URLs — one per line"
msgstr "Точные URL контента — по одному в строке"
#: lib/who_need_help_web/live/support_operations_live.ex:220
#, elixir-autogen, elixir-format
msgid "General support and data requests"
msgstr "Общая поддержка и запросы по данным"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "I am an authorised representative"
msgstr "Я уполномоченный представитель"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "I am the affected person or rights holder"
msgstr "Я пострадавшее лицо или правообладатель"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:78
#, elixir-autogen, elixir-format
msgid "I believe in good faith that the identified content is illegal or infringes the stated right."
msgstr "Я добросовестно считаю, что указанный контент незаконен или нарушает заявленное право."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:84
#, elixir-autogen, elixir-format
msgid "I confirm that the information in this request is accurate and that I am the depicted person or authorised to act for them."
msgstr "Я подтверждаю точность сведений и то, что являюсь изображённым лицом либо уполномочен действовать от его имени."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:87
#, elixir-autogen, elixir-format
msgid "I confirm that this notice is accurate and complete to the best of my knowledge."
msgstr "Я подтверждаю, что, насколько мне известно, это уведомление является точным и полным."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:75
#, elixir-autogen, elixir-format
msgid "I have a good-faith belief that this intimate visual material was shared without consent."
msgstr "Я добросовестно считаю, что этот интимный визуальный материал был опубликован без согласия."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:60
#, elixir-autogen, elixir-format
msgid "Identify the material without reproducing it and explain why it is non-consensual"
msgstr "Опишите материал, не воспроизводя его, и объясните, почему он размещён без согласия"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:93
#, elixir-autogen, elixir-format
msgid "Identity and contact fields may be omitted for reports of sexual material involving a minor. Do not include or upload the material itself."
msgstr "При сообщении о сексуальном материале с участием несовершеннолетнего поля имени и контакта можно не заполнять. Не прикладывайте и не загружайте сам материал."
#: lib/who_need_help_web/controllers/content_removal_html.ex:6
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:22
#: lib/who_need_help_web/live/support_operations_live.ex:88
#, elixir-autogen, elixir-format
msgid "Illegal content"
msgstr "Незаконный контент"
#: lib/who_need_help_web/controllers/support_html/show.html.heex:20
#, elixir-autogen, elixir-format
msgid "Keep this status link private. A copy is sent to the contact email when email delivery is configured."
msgstr "Не передавайте эту ссылку статуса другим. При настроенной доставке писем её копия отправляется на контактный email."
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:34
#, elixir-autogen, elixir-format
msgid "Keep this status link private. The submitter identity is not shown publicly or automatically disclosed to the person who posted the reported content."
msgstr "Не передавайте эту ссылку статуса другим. Личность заявителя не публикуется и не раскрывается автоматически автору обжалуемого контента."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:68
#, elixir-autogen, elixir-format
msgid "Law, right, or policy involved, if known"
msgstr "Применимый закон, право или правило, если известно"
#: lib/who_need_help_web/live/support_operations_live.ex:162
#, elixir-autogen, elixir-format
msgid "Locations"
msgstr "Адреса контента"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:22
#, elixir-autogen, elixir-format
msgid "Material involved"
msgstr "Тип материала"
#: lib/who_need_help_web/controllers/support_html.ex:9
#: lib/who_need_help_web/live/support_operations_live.ex:81
#, elixir-autogen, elixir-format
msgid "Moderation appeal"
msgstr "Обжалование модерации"
#: lib/who_need_help_web/controllers/content_removal_html.ex:24
#: lib/who_need_help_web/live/support_operations_live.ex:192
#, elixir-autogen, elixir-format
msgid "More information needed"
msgstr "Нужна дополнительная информация"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:44
#, elixir-autogen, elixir-format
msgid "Myself"
msgstr "Себя"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "NOTICE RECEIVED"
msgstr "УВЕДОМЛЕНИЕ ПОЛУЧЕНО"
#: lib/who_need_help_web/controllers/support_html/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "New request"
msgstr "Новое обращение"
#: lib/who_need_help_web/live/support_operations_live.ex:207
#, elixir-autogen, elixir-format
msgid "No removal notices."
msgstr "Нет уведомлений об удалении."
#: lib/who_need_help_web/live/support_operations_live.ex:268
#, elixir-autogen, elixir-format
msgid "No support requests."
msgstr "Нет обращений в поддержку."
#: lib/who_need_help_web/controllers/content_removal_html.ex:12
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:26
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:94
#, elixir-autogen, elixir-format
msgid "Non-consensual intimate image or video"
msgstr "Интимное изображение или видео без согласия"
#: lib/who_need_help_web/live/support_operations_live.ex:159
#: lib/who_need_help_web/live/support_operations_live.ex:161
#, elixir-autogen, elixir-format
msgid "Not provided"
msgstr "Не указано"
#: lib/who_need_help_web/controllers/support_html.ex:12
#: lib/who_need_help_web/controllers/support_html/new.html.heex:33
#: lib/who_need_help_web/live/support_operations_live.ex:84
#, elixir-autogen, elixir-format
msgid "Privacy request"
msgstr "Запрос по конфиденциальности"
#: lib/who_need_help_web/controllers/content_removal_html.ex:7
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:23
#: lib/who_need_help_web/live/support_operations_live.ex:89
#, elixir-autogen, elixir-format
msgid "Privacy violation"
msgstr "Нарушение конфиденциальности"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:11
#, elixir-autogen, elixir-format
msgid "Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information."
msgstr "Укажите точные URL в Who Need Help. Не загружайте и не вставляйте интимные материалы, документы, удостоверяющие личность, пароли, коды доступа или лишнюю медицинскую информацию."
#: lib/who_need_help_web/controllers/support_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "REQUEST RECEIVED"
msgstr "ОБРАЩЕНИЕ ПОЛУЧЕНО"
#: lib/who_need_help_web/live/support_operations_live.ex:24
#, elixir-autogen, elixir-format
msgid "Removal notice updated."
msgstr "Уведомление об удалении обновлено."
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/support_html/new.html.heex:13
#, elixir-autogen, elixir-format
msgid "Report content"
msgstr "Пожаловаться"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Report illegal or harmful content"
msgstr "Сообщить о незаконном или вредоносном контенте"
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:16
#, elixir-autogen, elixir-format
msgid "Reported locations"
msgstr "Указанные адреса контента"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:4
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:37
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:123
#, elixir-autogen, elixir-format
msgid "Request account deletion"
msgstr "Запросить удаление аккаунта"
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:117
#, elixir-autogen, elixir-format
msgid "Request deletion of your account and associated personal data, or contact support about access and export requests."
msgstr "Запросите удаление аккаунта и связанных персональных данных либо обратитесь в поддержку по вопросам доступа и экспорта."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:5
#, elixir-autogen, elixir-format
msgid "Request removal of intimate visual material"
msgstr "Запросить удаление интимного визуального материала"
#: lib/who_need_help_web/controllers/support_html/index.html.heex:5
#: lib/who_need_help_web/controllers/support_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "SUPPORT"
msgstr "ПОДДЕРЖКА"
#: lib/who_need_help_web/controllers/support_html.ex:8
#: lib/who_need_help_web/controllers/support_html/new.html.heex:31
#: lib/who_need_help_web/live/support_operations_live.ex:80
#, elixir-autogen, elixir-format
msgid "Safety concern"
msgstr "Проблема безопасности"
#: lib/who_need_help_web/live/support_operations_live.ex:203
#: lib/who_need_help_web/live/support_operations_live.ex:264
#, elixir-autogen, elixir-format
msgid "Save and notify"
msgstr "Сохранить и уведомить"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:60
#, elixir-autogen, elixir-format
msgid "Send support request"
msgstr "Отправить обращение"
#: lib/who_need_help_web/controllers/content_removal_html.ex:15
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:27
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:25
#: lib/who_need_help_web/live/support_operations_live.ex:97
#, elixir-autogen, elixir-format
msgid "Sexual material involving a minor"
msgstr "Сексуальный материал с участием несовершеннолетнего"
#: lib/who_need_help_web/live/support_operations_live.ex:177
#, elixir-autogen, elixir-format
msgid "Stated basis:"
msgstr "Указанное основание:"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "Subject"
msgstr "Тема"
#: lib/who_need_help_web/live/activity_live/show.ex:696
#: lib/who_need_help_web/live/request_live/show.ex:1127
#, elixir-autogen, elixir-format
msgid "Submit a legal content-removal notice"
msgstr "Подать юридическое уведомление об удалении контента"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:97
#, elixir-autogen, elixir-format
msgid "Submit removal notice"
msgstr "Отправить уведомление об удалении"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:89
#, elixir-autogen, elixir-format
msgid "Submit urgent removal request"
msgstr "Отправить срочный запрос на удаление"
#: lib/who_need_help_web/live/support_operations_live.ex:158
#, elixir-autogen, elixir-format
msgid "Submitter"
msgstr "Заявитель"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:11
#, elixir-autogen, elixir-format
msgid "Submitting this form does not immediately sign you out or erase evidence required for an open safety investigation. Support will verify and process the request."
msgstr "Отправка формы не приводит к немедленному выходу из аккаунта и не удаляет доказательства, необходимые для открытого расследования безопасности. Поддержка проверит и обработает запрос."
#: lib/who_need_help_web/components/layouts.ex:147
#, elixir-autogen, elixir-format
msgid "Support"
msgstr "Поддержка"
#: lib/who_need_help_web/live/support_operations_live.ex:8
#: lib/who_need_help_web/live/support_operations_live.ex:114
#, elixir-autogen, elixir-format
msgid "Support operations"
msgstr "Рабочее место поддержки"
#: lib/who_need_help_web/components/layouts.ex:190
#, elixir-autogen, elixir-format
msgid "Support queue"
msgstr "Очередь поддержки"
#: lib/who_need_help_web/live/support_operations_live.ex:16
#, elixir-autogen, elixir-format
msgid "Support request updated."
msgstr "Обращение в поддержку обновлено."
#: lib/who_need_help_web/live/support_operations_live.ex:116
#, elixir-autogen, elixir-format
msgid "Support requests and legal removal notices are separate queues. Decisions and operator identity are audited."
msgstr "Обращения в поддержку и юридические уведомления об удалении находятся в разных очередях. Решения и личность оператора фиксируются в аудите."
#: lib/who_need_help_web/controllers/support_html/show.html.heex:16
#: lib/who_need_help_web/live/support_operations_live.ex:262
#, elixir-autogen, elixir-format
msgid "Support response"
msgstr "Ответ поддержки"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:3
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN"
msgstr "TAKE IT DOWN"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:16
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN request"
msgstr "Запрос TAKE IT DOWN"
#: lib/who_need_help_web/controllers/support_html.ex:7
#: lib/who_need_help_web/controllers/support_html/new.html.heex:30
#: lib/who_need_help_web/live/support_operations_live.ex:79
#, elixir-autogen, elixir-format
msgid "Technical issue"
msgstr "Техническая проблема"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:6
#, elixir-autogen, elixir-format
msgid "This requests deletion of your Who Need Help account and associated personal data. Some records may need to be retained when required for safety, fraud prevention, legal obligations, or resolving an active dispute; any retained data must be described in the applicable retention notice."
msgstr "Это запрос на удаление аккаунта Who Need Help и связанных персональных данных. Некоторые записи могут сохраняться, если это необходимо для безопасности, предотвращения мошенничества, выполнения закона или разрешения активного спора; сохранённые данные должны быть описаны в применимом уведомлении о хранении."
#: lib/who_need_help_web/controllers/content_removal_html.ex:17
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:28
#: lib/who_need_help_web/live/support_operations_live.ex:99
#, elixir-autogen, elixir-format
msgid "Threat to life or safety"
msgstr "Угроза жизни или безопасности"
#: lib/who_need_help_web/controllers/content_removal_controller.ex:54
#, elixir-autogen, elixir-format
msgid "Too many removal notices. Please try again later."
msgstr "Слишком много уведомлений об удалении. Повторите попытку позже."
#: lib/who_need_help_web/controllers/support_controller.ex:34
#: lib/who_need_help_web/controllers/support_controller.ex:72
#, elixir-autogen, elixir-format
msgid "Too many support requests. Please try again later."
msgstr "Слишком много обращений в поддержку. Повторите попытку позже."
#: lib/who_need_help_web/live/support_operations_live.ex:122
#, elixir-autogen, elixir-format
msgid "Trust and safety moderation"
msgstr "Модерация доверия и безопасности"
#: lib/who_need_help_web/controllers/content_removal_html.ex:22
#: lib/who_need_help_web/live/support_operations_live.ex:190
#, elixir-autogen, elixir-format
msgid "Urgent review"
msgstr "Срочное рассмотрение"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:8
#, elixir-autogen, elixir-format
msgid "Use this dedicated process when an identifiable person is shown in an intimate image or video shared without consent, including a digital forgery. You may submit for yourself or as an authorised representative."
msgstr "Используйте эту специальную процедуру, если узнаваемый человек показан на интимном изображении или видео, опубликованном без согласия, включая цифровую подделку. Запрос можно подать за себя или как уполномоченный представитель."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this electronic notice for specific content on Who Need Help that you believe is illegal or infringes your rights. Ordinary safety reports inside a request or chat remain available to signed-in users."
msgstr "Используйте это электронное уведомление для конкретного контента в Who Need Help, который вы считаете незаконным или нарушающим ваши права. Обычные жалобы на безопасность внутри заявки или чата доступны вошедшим пользователям."
#: lib/who_need_help_web/controllers/support_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this form for account access, technical problems, privacy questions, or other support. For illegal content or a removal request, use the dedicated removal form."
msgstr "Используйте эту форму для вопросов доступа к аккаунту, технических проблем, конфиденциальности и другой поддержки. Для незаконного контента или запроса на удаление используйте специальную форму."
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:126
#, elixir-autogen, elixir-format
msgid "View support requests"
msgstr "Посмотреть обращения в поддержку"
#: lib/who_need_help_web/live/support_operations_live.ex:254
#, elixir-autogen, elixir-format
msgid "Waiting for requester"
msgstr "Ожидается ответ заявителя"
#: lib/who_need_help_web/controllers/support_html.ex:18
#, elixir-autogen, elixir-format
msgid "Waiting for your response"
msgstr "Ожидается ваш ответ"
#: lib/who_need_help_web/controllers/support_html/received.html.heex:6
#, elixir-autogen, elixir-format
msgid "We created support request %{reference}. A private status link has been sent to the contact email when delivery is configured. Opening that link verifies the address for public requests."
msgstr "Мы создали обращение %{reference}. При настроенной доставке писем приватная ссылка статуса отправлена на контактный email. Переход по ней подтверждает адрес для публичных обращений."
#: lib/who_need_help_web/controllers/support_html/new.html.heex:27
#, elixir-autogen, elixir-format
msgid "What do you need help with?"
msgstr "Какая помощь вам нужна?"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:42
#, elixir-autogen, elixir-format
msgid "Who are you submitting for?"
msgstr "От чьего имени вы подаёте запрос?"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:62
#, elixir-autogen, elixir-format
msgid "Why do you believe this content should be removed?"
msgstr "Почему вы считаете, что этот контент следует удалить?"
#: lib/who_need_help_web/controllers/support_html/index.html.heex:26
#, elixir-autogen, elixir-format
msgid "You have not submitted any support requests."
msgstr "Вы ещё не отправляли обращений в поддержку."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:30
#, elixir-autogen, elixir-format
msgid "Your full name"
msgstr "Ваше полное имя"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:34
#, elixir-autogen, elixir-format
msgid "Your name or organisation"
msgstr "Ваше имя или организация"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:5
#, elixir-autogen, elixir-format
msgid "Your reference is %{reference}"
msgstr "Номер вашего обращения: %{reference}"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:45
#, elixir-autogen, elixir-format
msgid "Your relationship to the affected person or rights holder"
msgstr "Ваше отношение к пострадавшему лицу или правообладателю"
#: lib/who_need_help_web/live/support_operations_live.ex:150
#: lib/who_need_help_web/live/support_operations_live.ex:235
#, elixir-autogen, elixir-format
msgid "contact unverified"
msgstr "контакт не подтверждён"
#: lib/who_need_help_web/live/support_operations_live.ex:154
#, elixir-autogen, elixir-format
msgid "review by %{time}"
msgstr "рассмотреть до %{time}"
#: lib/who_need_help_web/controllers/support_controller.ex:47
#: lib/who_need_help_web/controllers/support_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Delete my Who Need Help account"
msgstr "Удалить мой аккаунт Who Need Help"
#: lib/who_need_help_web/controllers/support_controller.ex:48
#, elixir-autogen, elixir-format
msgid "Please delete my account and associated personal data."
msgstr "Пожалуйста, удалите мой аккаунт и связанные персональные данные."

View File

@ -12,7 +12,7 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100 != 11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10||n%100>=20) ? 1 : 2);\n"
#: lib/who_need_help_web/components/layouts.ex:111
#: lib/who_need_help_web/components/layouts.ex:257
#: lib/who_need_help_web/components/layouts.ex:266
#, elixir-autogen, elixir-format
msgid "Account settings"
msgstr "Параметри облікового запису"
@ -30,13 +30,13 @@ msgstr "Дії"
msgid "Ask for help"
msgstr "Попросити допомоги"
#: lib/who_need_help_web/components/layouts.ex:295
#: lib/who_need_help_web/components/layouts.ex:310
#: lib/who_need_help_web/components/layouts.ex:304
#: lib/who_need_help_web/components/layouts.ex:319
#, elixir-autogen, elixir-format
msgid "Attempting to reconnect"
msgstr "Спроба повторного з’єднання"
#: lib/who_need_help_web/components/layouts.ex:171
#: lib/who_need_help_web/components/layouts.ex:175
#, elixir-autogen, elixir-format
msgid "Categories"
msgstr "Категорії"
@ -65,13 +65,13 @@ msgid "Log in"
msgstr "Вхід"
#: lib/who_need_help_web/components/layouts.ex:114
#: lib/who_need_help_web/components/layouts.ex:260
#: lib/who_need_help_web/components/layouts.ex:269
#, elixir-autogen, elixir-format
msgid "Log out"
msgstr "Вийти"
#: lib/who_need_help_web/components/layouts.ex:108
#: lib/who_need_help_web/components/layouts.ex:254
#: lib/who_need_help_web/components/layouts.ex:263
#: lib/who_need_help_web/live/profile_live.ex:16
#, elixir-autogen, elixir-format
msgid "Profile"
@ -83,7 +83,7 @@ msgstr "Профіль"
msgid "Register"
msgstr "Зареєструватися"
#: lib/who_need_help_web/components/layouts.ex:161
#: lib/who_need_help_web/components/layouts.ex:165
#, elixir-autogen, elixir-format
msgid "Requests"
msgstr "Запити"
@ -93,12 +93,12 @@ msgstr "Запити"
msgid "See nearby requests"
msgstr "Переглянути заявки поруч"
#: lib/who_need_help_web/components/layouts.ex:302
#: lib/who_need_help_web/components/layouts.ex:311
#, elixir-autogen, elixir-format
msgid "Something went wrong!"
msgstr "Щось пішло не так!"
#: lib/who_need_help_web/components/layouts.ex:287
#: lib/who_need_help_web/components/layouts.ex:296
#, elixir-autogen, elixir-format
msgid "We can't find the internet"
msgstr "Немає з’єднання з інтернетом"
@ -179,7 +179,7 @@ msgid "Account Settings"
msgstr "Параметри облікового запису"
#: lib/who_need_help_web/components/layouts.ex:63
#: lib/who_need_help_web/components/layouts.ex:192
#: lib/who_need_help_web/components/layouts.ex:201
#, elixir-autogen, elixir-format
msgid "Account and language"
msgstr "Акаунт і мова"
@ -200,7 +200,7 @@ msgstr "Центр дій"
msgid "Active"
msgstr "Активний"
#: lib/who_need_help_web/components/layouts.ex:166
#: lib/who_need_help_web/components/layouts.ex:170
#: lib/who_need_help_web/live/activity_live/index.ex:118
#, elixir-autogen, elixir-format
msgid "Activities"
@ -385,7 +385,7 @@ msgstr ""
msgid "Briefly describe the help you need"
msgstr "Коротко опишіть, яка допомога вам потрібна"
#: lib/who_need_help_web/components/layouts.ex:147
#: lib/who_need_help_web/components/layouts.ex:151
#, elixir-autogen, elixir-format
msgid "Build Week feedback"
msgstr "Звіт для Build Week"
@ -668,7 +668,7 @@ msgstr ""
msgid "Dismissed"
msgstr "Відхилено"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:71
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:76
#: lib/who_need_help_web/live/profile_live.ex:149
#, elixir-autogen, elixir-format
msgid "Display name"
@ -692,7 +692,7 @@ msgstr "Немає акаунта?"
msgid "Double-blind review"
msgstr "Двосторонній прихований відгук"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:62
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:67
#: 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_settings_html/edit.html.heex:15
@ -857,7 +857,7 @@ msgstr "Помічник"
msgid "Helper: %{name}"
msgstr "Помічник: %{name}"
#: lib/who_need_help_web/components/layouts.ex:176
#: lib/who_need_help_web/components/layouts.ex:180
#, elixir-autogen, elixir-format
msgid "Helpers"
msgstr "Помічники"
@ -933,7 +933,7 @@ msgid "Human decisions retained"
msgstr "Рішення залишаються за людиною"
#: 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:85
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#, elixir-autogen, elixir-format
msgid "I am 18 or older and accept the safety rules"
msgstr "Мені 18 років, і я приймаю правила безпеки."
@ -985,9 +985,12 @@ msgstr ""
"Якщо ця адреса електронної пошти є в нашій системі, незабаром ви отримаєте "
"інструкції для входу."
#: lib/who_need_help_web/controllers/content_removal_html.ex:9
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:25
#: lib/who_need_help_web/live/activity_live/show.ex:678
#: lib/who_need_help_web/live/moderation_live.ex:253
#: lib/who_need_help_web/live/request_live/show.ex:1109
#: lib/who_need_help_web/live/support_operations_live.ex:91
#, elixir-autogen, elixir-format
msgid "Impersonation"
msgstr "Видавання себе за іншу особу"
@ -1208,7 +1211,7 @@ msgstr "Надіслати повідомлення схваленій груп
msgid "Mode"
msgstr "Режим"
#: lib/who_need_help_web/components/layouts.ex:181
#: lib/who_need_help_web/components/layouts.ex:185
#: lib/who_need_help_web/live/moderation_live.ex:9
#: lib/who_need_help_web/live/moderation_live.ex:291
#, elixir-autogen, elixir-format
@ -1222,6 +1225,7 @@ msgid "Moderator"
msgstr "Модератор"
#: lib/who_need_help_web/live/moderation_live.ex:230
#: lib/who_need_help_web/live/support_operations_live.ex:73
#: lib/who_need_help_web/user_auth.ex:306
#, elixir-autogen, elixir-format
msgid "Moderator access is required."
@ -1365,12 +1369,16 @@ msgstr ""
"Тільки організатор і схвалені учасники можуть читати або надсилати ці "
"повідомлення."
#: lib/who_need_help_web/controllers/content_removal_html.ex:21
#: lib/who_need_help_web/controllers/support_html.ex:16
#: lib/who_need_help_web/live/activity_live/index.ex:166
#: lib/who_need_help_web/live/activity_live/show.ex:342
#: lib/who_need_help_web/live/moderation_live.ex:257
#: lib/who_need_help_web/live/request_live/index.ex:176
#: lib/who_need_help_web/live/request_live/index.ex:177
#: lib/who_need_help_web/live/request_live/show.ex:636
#: lib/who_need_help_web/live/support_operations_live.ex:189
#: lib/who_need_help_web/live/support_operations_live.ex:252
#, elixir-autogen, elixir-format
msgid "Open"
msgstr "Відкрита"
@ -1415,10 +1423,17 @@ msgstr "Керування організатора"
msgid "Organizer social links"
msgstr "Посилання організатора на соцмережі"
#: lib/who_need_help_web/controllers/content_removal_html.ex:18
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:29
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:49
#: lib/who_need_help_web/controllers/support_html.ex:13
#: lib/who_need_help_web/controllers/support_html/new.html.heex:35
#: lib/who_need_help_web/live/activity_live/show.ex:679
#: lib/who_need_help_web/live/moderation_live.ex:254
#: lib/who_need_help_web/live/profile_live.ex:311
#: lib/who_need_help_web/live/request_live/show.ex:1110
#: lib/who_need_help_web/live/support_operations_live.ex:85
#: lib/who_need_help_web/live/support_operations_live.ex:100
#, elixir-autogen, elixir-format
msgid "Other"
msgstr "Інше"
@ -1469,6 +1484,7 @@ msgid "Please check the entered data."
msgstr "Будь ласка, перевірте введені дані."
#: lib/who_need_help_web/live/moderation_live.ex:240
#: lib/who_need_help_web/live/support_operations_live.ex:75
#, elixir-autogen, elixir-format
msgid "Please check the submitted fields."
msgstr "Будь ласка, перевірте вказані поля."
@ -1605,6 +1621,7 @@ msgid "READ BEFORE USING THE SERVICE"
msgstr "ПРОЧИТАЙТЕ ПЕРЕД ВИКОРИСТАННЯМ СЕРВІСУ"
#: lib/who_need_help_web/live/moderation_live.ex:290
#: lib/who_need_help_web/live/support_operations_live.ex:111
#, elixir-autogen, elixir-format
msgid "RESTRICTED WORKSPACE"
msgstr "ОБМЕЖЕНА РОБОЧА ОБЛАСТЬ"
@ -1628,11 +1645,12 @@ msgstr ""
msgid "Rating"
msgstr "Оцінка"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:77
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:82
#, elixir-autogen, elixir-format
msgid "Read the"
msgstr "Прочитайте"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:20
#: lib/who_need_help_web/live/activity_live/show.ex:672
#, elixir-autogen, elixir-format
msgid "Reason"
@ -1746,8 +1764,10 @@ msgstr "Автор заявки: %{count} завершено"
msgid "Resolution note"
msgstr "Примітка до рішення"
#: lib/who_need_help_web/controllers/support_html.ex:19
#: lib/who_need_help_web/live/moderation_live.ex:259
#: lib/who_need_help_web/live/moderation_live.ex:365
#: lib/who_need_help_web/live/support_operations_live.ex:255
#, elixir-autogen, elixir-format
msgid "Resolved"
msgstr "Вирішено"
@ -1777,8 +1797,12 @@ msgstr ""
msgid "Reviewed"
msgstr "Перевірено"
#: lib/who_need_help_web/controllers/content_removal_html.ex:23
#: lib/who_need_help_web/controllers/support_html.ex:17
#: lib/who_need_help_web/live/moderation_live.ex:258
#: lib/who_need_help_web/live/moderation_live.ex:364
#: lib/who_need_help_web/live/support_operations_live.ex:191
#: lib/who_need_help_web/live/support_operations_live.ex:253
#, elixir-autogen, elixir-format
msgid "Reviewing"
msgstr "На розгляді"
@ -2263,12 +2287,12 @@ msgstr ""
"Призначайте першу зустріч у громадському місці. Не публікуйте домашню "
"адресу, код доступу, документ для подорожі чи іншу чутливу інформацію."
#: lib/who_need_help_web/components/layouts.ex:349
#: lib/who_need_help_web/components/layouts.ex:358
#, elixir-autogen, elixir-format
msgid "Use dark theme"
msgstr "Увімкнути темну тему"
#: lib/who_need_help_web/components/layouts.ex:340
#: lib/who_need_help_web/components/layouts.ex:349
#, elixir-autogen, elixir-format
msgid "Use light theme"
msgstr "Увімкнути світлу тему"
@ -2286,7 +2310,7 @@ msgstr ""
"Користуйтеся приватним чатом і, за бажанням, передаванням геопозиції в "
"реальному часі."
#: lib/who_need_help_web/components/layouts.ex:331
#: lib/who_need_help_web/components/layouts.ex:340
#, elixir-autogen, elixir-format
msgid "Use system theme"
msgstr "Використати системну тему"
@ -2408,7 +2432,7 @@ msgstr ""
msgid "Who Need Help home"
msgstr "Головна Who Need Help"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:90
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#, elixir-autogen, elixir-format
msgid "Who Need Help is not an emergency or medical service. Medicine requests are limited to pickup of legal items already purchased or reserved."
msgstr ""
@ -2557,6 +2581,7 @@ msgstr "Ваш профіль"
msgid "Your request is now visible to nearby helpers."
msgstr "Тепер вашу заявку бачать помічники поруч."
#: lib/who_need_help_web/controllers/support_html/index.html.heex:6
#: lib/who_need_help_web/live/request_live/index.ex:342
#, elixir-autogen, elixir-format
msgid "Your requests"
@ -2583,7 +2608,7 @@ msgstr "активність"
msgid "activity message"
msgstr "повідомлення активності"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:79
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:84
#, elixir-autogen, elixir-format
msgid "before confirming."
msgstr "перед підтвердженням."
@ -2660,7 +2685,7 @@ msgstr "оцінка"
msgid "rating %{rating}"
msgstr "оцінка %{rating}"
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:78
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:83
#, elixir-autogen, elixir-format
msgid "safety rules"
msgstr "правила безпеки"
@ -2768,7 +2793,9 @@ msgstr "Об’єднано"
msgid "Reciprocal rating ring"
msgstr "Кільце взаємних оцінок"
#: lib/who_need_help_web/controllers/content_removal_html.ex:26
#: lib/who_need_help_web/live/moderation_live.ex:263
#: lib/who_need_help_web/live/support_operations_live.ex:194
#, elixir-autogen, elixir-format
msgid "Rejected"
msgstr "Відхилено"
@ -2801,6 +2828,8 @@ msgstr "Завантажити попередні повідомлення"
#: lib/who_need_help_web/live/profile_live.ex:354
#: lib/who_need_help_web/live/request_live/index.ex:303
#: lib/who_need_help_web/live/request_live/index.ex:360
#: lib/who_need_help_web/live/support_operations_live.ex:215
#: lib/who_need_help_web/live/support_operations_live.ex:276
#, elixir-autogen, elixir-format
msgid "Load more"
msgstr "Завантажити ще"
@ -2887,6 +2916,7 @@ msgid "The registration form is invalid."
msgstr "Форму реєстрації заповнено неправильно."
#: lib/who_need_help_web/live/moderation_live.ex:239
#: lib/who_need_help_web/live/support_operations_live.ex:74
#, elixir-autogen, elixir-format
msgid "The selected record is no longer available."
msgstr "Вибраний запис більше недоступний."
@ -2986,7 +3016,7 @@ msgstr "Підключити обліковий запис Google"
msgid "Connect Google only after signing in here. We never merge accounts automatically by matching email addresses."
msgstr "Підключайте Google лише після входу тут. Ми ніколи не об’єднуємо облікові записи автоматично за збігом email."
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:96
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:101
#, elixir-autogen, elixir-format
msgid "Create account and email me a link"
msgstr "Створити обліковий запис і надіслати посилання на email"
@ -3048,7 +3078,7 @@ msgstr "Сесія входу через Google недійсна."
msgid "Google sign-in will be available after the operator configures it."
msgstr "Вхід через Google стане доступним після налаштування оператором."
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:95
#: lib/who_need_help_web/controllers/user_registration_html/new.html.heex:100
#, elixir-autogen, elixir-format
msgid "Sending link..."
msgstr "Надсилаємо посилання..."
@ -3132,3 +3162,632 @@ msgstr "Вхід через Google відключено."
#, elixir-autogen, elixir-format
msgid "No Google account is connected."
msgstr "Обліковий запис Google не підключено."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:45
#, elixir-autogen, elixir-format
msgid "A person I am authorised to represent"
msgstr "Особа, яку я уповноважений представляти"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:8
#, elixir-autogen, elixir-format
msgid "A private status link has been sent when a contact email was provided and delivery is configured. Opening that link verifies the contact address. Keep the reference for follow-up."
msgstr "Якщо вказано контактний email і налаштовано доставку листів, на нього надіслано приватне посилання для перевірки статусу. Перехід за посиланням підтверджує адресу. Збережіть номер звернення."
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:3
#, elixir-autogen, elixir-format
msgid "ACCOUNT AND DATA"
msgstr "ОБЛІКОВИЙ ЗАПИС І ДАНІ"
#: lib/who_need_help_web/controllers/support_html.ex:6
#: lib/who_need_help_web/controllers/support_html/new.html.heex:29
#: lib/who_need_help_web/live/support_operations_live.ex:78
#, elixir-autogen, elixir-format
msgid "Account access"
msgstr "Доступ до облікового запису"
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:115
#, elixir-autogen, elixir-format
msgid "Account and personal data"
msgstr "Обліковий запис і персональні дані"
#: lib/who_need_help_web/controllers/support_html.ex:10
#: lib/who_need_help_web/live/support_operations_live.ex:82
#, elixir-autogen, elixir-format
msgid "Account deletion"
msgstr "Видалення облікового запису"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:26
#, elixir-autogen, elixir-format
msgid "Account email"
msgstr "Email облікового запису"
#: lib/who_need_help_web/controllers/content_removal_html.ex:25
#: lib/who_need_help_web/live/support_operations_live.ex:193
#, elixir-autogen, elixir-format
msgid "Action taken"
msgstr "Вжито заходів"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:34
#, elixir-autogen, elixir-format
msgid "Additional information"
msgstr "Додаткова інформація"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:32
#, elixir-autogen, elixir-format
msgid "Appeal a moderation decision"
msgstr "Оскаржити рішення модерації"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:13
#, elixir-autogen, elixir-format
msgid "Back to removal form"
msgstr "Повернутися до форми видалення"
#: lib/who_need_help_web/controllers/support_html/received.html.heex:11
#, elixir-autogen, elixir-format
msgid "Back to support"
msgstr "Повернутися до підтримки"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "CONTENT REMOVAL"
msgstr "ВИДАЛЕННЯ КОНТЕНТУ"
#: lib/who_need_help_web/controllers/support_html/received.html.heex:4
#, elixir-autogen, elixir-format
msgid "Check your email"
msgstr "Перевірте пошту"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:27
#, elixir-autogen, elixir-format
msgid "Choose a category"
msgstr "Виберіть категорію"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:31
#, elixir-autogen, elixir-format
msgid "Choose a reason"
msgstr "Виберіть причину"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:51
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:47
#, elixir-autogen, elixir-format
msgid "Choose a relationship"
msgstr "Виберіть відношення"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:37
#, elixir-autogen, elixir-format
msgid "Choose a topic"
msgstr "Виберіть тему"
#: lib/who_need_help_web/controllers/content_removal_html.ex:27
#: lib/who_need_help_web/controllers/support_html.ex:20
#: lib/who_need_help_web/live/support_operations_live.ex:195
#: lib/who_need_help_web/live/support_operations_live.ex:256
#, elixir-autogen, elixir-format
msgid "Closed"
msgstr "Закрито"
#: lib/who_need_help_web/live/support_operations_live.ex:160
#, elixir-autogen, elixir-format
msgid "Contact"
msgstr "Контакт"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Contact Who Need Help"
msgstr "Зв’язатися з Who Need Help"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:38
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:34
#: lib/who_need_help_web/controllers/support_html/new.html.heex:43
#, elixir-autogen, elixir-format
msgid "Contact email"
msgstr "Контактний email"
#: lib/who_need_help_web/live/support_operations_live.ex:127
#, elixir-autogen, elixir-format
msgid "Content removal and TAKE IT DOWN"
msgstr "Видалення контенту та TAKE IT DOWN"
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:13
#, elixir-autogen, elixir-format
msgid "Content-removal notice"
msgstr "Повідомлення про видалення контенту"
#: lib/who_need_help_web/controllers/content_removal_html.ex:8
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:90
#, elixir-autogen, elixir-format
msgid "Copyright"
msgstr "Авторські права"
#: lib/who_need_help_web/live/support_operations_live.ex:76
#, elixir-autogen, elixir-format
msgid "Could not update the request. Please try again."
msgstr "Не вдалося оновити звернення. Спробуйте ще раз."
#: lib/who_need_help_web/controllers/support_html.ex:11
#: lib/who_need_help_web/controllers/support_html/new.html.heex:34
#: lib/who_need_help_web/live/support_operations_live.ex:83
#, elixir-autogen, elixir-format
msgid "Data export"
msgstr "Експорт даних"
#: lib/who_need_help_web/live/support_operations_live.ex:201
#, elixir-autogen, elixir-format
msgid "Decision or information request"
msgstr "Рішення або запит додаткової інформації"
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:30
#, elixir-autogen, elixir-format
msgid "Decision or request for information"
msgstr "Рішення або запит додаткової інформації"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:19
#, elixir-autogen, elixir-format
msgid "Delete an account"
msgstr "Видалити обліковий запис"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:52
#, elixir-autogen, elixir-format
msgid "Describe the problem"
msgstr "Опишіть проблему"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:56
#, elixir-autogen, elixir-format
msgid "Do not include passwords, payment card details, access codes, prescriptions, or unnecessary medical information."
msgstr "Не вказуйте паролі, дані платіжних карток, коди доступу, рецепти або зайву медичну інформацію."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:13
#, elixir-autogen, elixir-format
msgid "Do not upload the image or video. Provide only the exact Who Need Help URL where it appears and enough text to identify it safely."
msgstr "Не завантажуйте зображення чи відео. Укажіть лише точний URL у Who Need Help і безпечний текстовий опис, достатній для ідентифікації матеріалу."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:72
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:68
#, elixir-autogen, elixir-format
msgid "Electronic signature (type your full name)"
msgstr "Електронний підпис (введіть повне ім’я)"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:56
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:53
#, elixir-autogen, elixir-format
msgid "Exact content URLs — one per line"
msgstr "Точні URL контенту — по одному в рядку"
#: lib/who_need_help_web/live/support_operations_live.ex:220
#, elixir-autogen, elixir-format
msgid "General support and data requests"
msgstr "Загальна підтримка та запити щодо даних"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "I am an authorised representative"
msgstr "Я уповноважений представник"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "I am the affected person or rights holder"
msgstr "Я постраждала особа або правовласник"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:78
#, elixir-autogen, elixir-format
msgid "I believe in good faith that the identified content is illegal or infringes the stated right."
msgstr "Я добросовісно вважаю, що зазначений контент є незаконним або порушує заявлене право."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:84
#, elixir-autogen, elixir-format
msgid "I confirm that the information in this request is accurate and that I am the depicted person or authorised to act for them."
msgstr "Я підтверджую точність відомостей і те, що є зображеною особою або уповноважений діяти від її імені."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:87
#, elixir-autogen, elixir-format
msgid "I confirm that this notice is accurate and complete to the best of my knowledge."
msgstr "Я підтверджую, що, наскільки мені відомо, це повідомлення є точним і повним."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:75
#, elixir-autogen, elixir-format
msgid "I have a good-faith belief that this intimate visual material was shared without consent."
msgstr "Я добросовісно вважаю, що цей інтимний візуальний матеріал було поширено без згоди."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:60
#, elixir-autogen, elixir-format
msgid "Identify the material without reproducing it and explain why it is non-consensual"
msgstr "Опишіть матеріал, не відтворюючи його, і поясніть, чому його поширено без згоди"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:93
#, elixir-autogen, elixir-format
msgid "Identity and contact fields may be omitted for reports of sexual material involving a minor. Do not include or upload the material itself."
msgstr "У повідомленні про сексуальний матеріал за участю неповнолітнього поля імені й контакту можна не заповнювати. Не додавайте й не завантажуйте сам матеріал."
#: lib/who_need_help_web/controllers/content_removal_html.ex:6
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:22
#: lib/who_need_help_web/live/support_operations_live.ex:88
#, elixir-autogen, elixir-format
msgid "Illegal content"
msgstr "Незаконний контент"
#: lib/who_need_help_web/controllers/support_html/show.html.heex:20
#, elixir-autogen, elixir-format
msgid "Keep this status link private. A copy is sent to the contact email when email delivery is configured."
msgstr "Не передавайте це посилання статусу іншим. Якщо доставку листів налаштовано, його копія надсилається на контактний email."
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:34
#, elixir-autogen, elixir-format
msgid "Keep this status link private. The submitter identity is not shown publicly or automatically disclosed to the person who posted the reported content."
msgstr "Не передавайте це посилання статусу іншим. Особа заявника не публікується й автоматично не розкривається автору оскаржуваного контенту."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:68
#, elixir-autogen, elixir-format
msgid "Law, right, or policy involved, if known"
msgstr "Застосовний закон, право або правило, якщо відомо"
#: lib/who_need_help_web/live/support_operations_live.ex:162
#, elixir-autogen, elixir-format
msgid "Locations"
msgstr "Адреси контенту"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:22
#, elixir-autogen, elixir-format
msgid "Material involved"
msgstr "Тип матеріалу"
#: lib/who_need_help_web/controllers/support_html.ex:9
#: lib/who_need_help_web/live/support_operations_live.ex:81
#, elixir-autogen, elixir-format
msgid "Moderation appeal"
msgstr "Оскарження модерації"
#: lib/who_need_help_web/controllers/content_removal_html.ex:24
#: lib/who_need_help_web/live/support_operations_live.ex:192
#, elixir-autogen, elixir-format
msgid "More information needed"
msgstr "Потрібна додаткова інформація"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:44
#, elixir-autogen, elixir-format
msgid "Myself"
msgstr "Себе"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "NOTICE RECEIVED"
msgstr "ПОВІДОМЛЕННЯ ОТРИМАНО"
#: lib/who_need_help_web/controllers/support_html/index.html.heex:8
#, elixir-autogen, elixir-format
msgid "New request"
msgstr "Нове звернення"
#: lib/who_need_help_web/live/support_operations_live.ex:207
#, elixir-autogen, elixir-format
msgid "No removal notices."
msgstr "Немає повідомлень про видалення."
#: lib/who_need_help_web/live/support_operations_live.ex:268
#, elixir-autogen, elixir-format
msgid "No support requests."
msgstr "Немає звернень до підтримки."
#: lib/who_need_help_web/controllers/content_removal_html.ex:12
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:26
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:24
#: lib/who_need_help_web/live/support_operations_live.ex:94
#, elixir-autogen, elixir-format
msgid "Non-consensual intimate image or video"
msgstr "Інтимне зображення або відео без згоди"
#: lib/who_need_help_web/live/support_operations_live.ex:159
#: lib/who_need_help_web/live/support_operations_live.ex:161
#, elixir-autogen, elixir-format
msgid "Not provided"
msgstr "Не вказано"
#: lib/who_need_help_web/controllers/support_html.ex:12
#: lib/who_need_help_web/controllers/support_html/new.html.heex:33
#: lib/who_need_help_web/live/support_operations_live.ex:84
#, elixir-autogen, elixir-format
msgid "Privacy request"
msgstr "Запит щодо конфіденційності"
#: lib/who_need_help_web/controllers/content_removal_html.ex:7
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:23
#: lib/who_need_help_web/live/support_operations_live.ex:89
#, elixir-autogen, elixir-format
msgid "Privacy violation"
msgstr "Порушення конфіденційності"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:11
#, elixir-autogen, elixir-format
msgid "Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information."
msgstr "Укажіть точні URL у Who Need Help. Не завантажуйте й не вставляйте інтимні матеріали, документи, що посвідчують особу, паролі, коди доступу або зайву медичну інформацію."
#: lib/who_need_help_web/controllers/support_html/received.html.heex:3
#, elixir-autogen, elixir-format
msgid "REQUEST RECEIVED"
msgstr "ЗВЕРНЕННЯ ОТРИМАНО"
#: lib/who_need_help_web/live/support_operations_live.ex:24
#, elixir-autogen, elixir-format
msgid "Removal notice updated."
msgstr "Повідомлення про видалення оновлено."
#: lib/who_need_help_web/components/layouts.ex:149
#: lib/who_need_help_web/controllers/support_html/new.html.heex:13
#, elixir-autogen, elixir-format
msgid "Report content"
msgstr "Поскаржитися"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:4
#, elixir-autogen, elixir-format
msgid "Report illegal or harmful content"
msgstr "Повідомити про незаконний або шкідливий контент"
#: lib/who_need_help_web/controllers/content_removal_html/show.html.heex:16
#, elixir-autogen, elixir-format
msgid "Reported locations"
msgstr "Указані адреси контенту"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:4
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:37
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:123
#, elixir-autogen, elixir-format
msgid "Request account deletion"
msgstr "Запросити видалення облікового запису"
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:117
#, elixir-autogen, elixir-format
msgid "Request deletion of your account and associated personal data, or contact support about access and export requests."
msgstr "Запросіть видалення облікового запису та пов’язаних персональних даних або зверніться до підтримки щодо доступу й експорту."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:5
#, elixir-autogen, elixir-format
msgid "Request removal of intimate visual material"
msgstr "Запросити видалення інтимного візуального матеріалу"
#: lib/who_need_help_web/controllers/support_html/index.html.heex:5
#: lib/who_need_help_web/controllers/support_html/new.html.heex:3
#, elixir-autogen, elixir-format
msgid "SUPPORT"
msgstr "ПІДТРИМКА"
#: lib/who_need_help_web/controllers/support_html.ex:8
#: lib/who_need_help_web/controllers/support_html/new.html.heex:31
#: lib/who_need_help_web/live/support_operations_live.ex:80
#, elixir-autogen, elixir-format
msgid "Safety concern"
msgstr "Проблема безпеки"
#: lib/who_need_help_web/live/support_operations_live.ex:203
#: lib/who_need_help_web/live/support_operations_live.ex:264
#, elixir-autogen, elixir-format
msgid "Save and notify"
msgstr "Зберегти й повідомити"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:60
#, elixir-autogen, elixir-format
msgid "Send support request"
msgstr "Надіслати звернення"
#: lib/who_need_help_web/controllers/content_removal_html.ex:15
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:27
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:25
#: lib/who_need_help_web/live/support_operations_live.ex:97
#, elixir-autogen, elixir-format
msgid "Sexual material involving a minor"
msgstr "Сексуальний матеріал за участю неповнолітнього"
#: lib/who_need_help_web/live/support_operations_live.ex:177
#, elixir-autogen, elixir-format
msgid "Stated basis:"
msgstr "Зазначена підстава:"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:48
#, elixir-autogen, elixir-format
msgid "Subject"
msgstr "Тема"
#: lib/who_need_help_web/live/activity_live/show.ex:696
#: lib/who_need_help_web/live/request_live/show.ex:1127
#, elixir-autogen, elixir-format
msgid "Submit a legal content-removal notice"
msgstr "Подати юридичне повідомлення про видалення контенту"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:97
#, elixir-autogen, elixir-format
msgid "Submit removal notice"
msgstr "Надіслати повідомлення про видалення"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:89
#, elixir-autogen, elixir-format
msgid "Submit urgent removal request"
msgstr "Надіслати терміновий запит на видалення"
#: lib/who_need_help_web/live/support_operations_live.ex:158
#, elixir-autogen, elixir-format
msgid "Submitter"
msgstr "Заявник"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:11
#, elixir-autogen, elixir-format
msgid "Submitting this form does not immediately sign you out or erase evidence required for an open safety investigation. Support will verify and process the request."
msgstr "Надсилання форми не призводить до негайного виходу з облікового запису й не видаляє докази, потрібні для відкритого розслідування безпеки. Підтримка перевірить та опрацює запит."
#: lib/who_need_help_web/components/layouts.ex:147
#, elixir-autogen, elixir-format
msgid "Support"
msgstr "Підтримка"
#: lib/who_need_help_web/live/support_operations_live.ex:8
#: lib/who_need_help_web/live/support_operations_live.ex:114
#, elixir-autogen, elixir-format
msgid "Support operations"
msgstr "Робоче місце підтримки"
#: lib/who_need_help_web/components/layouts.ex:190
#, elixir-autogen, elixir-format
msgid "Support queue"
msgstr "Черга підтримки"
#: lib/who_need_help_web/live/support_operations_live.ex:16
#, elixir-autogen, elixir-format
msgid "Support request updated."
msgstr "Звернення до підтримки оновлено."
#: lib/who_need_help_web/live/support_operations_live.ex:116
#, elixir-autogen, elixir-format
msgid "Support requests and legal removal notices are separate queues. Decisions and operator identity are audited."
msgstr "Звернення до підтримки та юридичні повідомлення про видалення перебувають у різних чергах. Рішення й особа оператора фіксуються в аудиті."
#: lib/who_need_help_web/controllers/support_html/show.html.heex:16
#: lib/who_need_help_web/live/support_operations_live.ex:262
#, elixir-autogen, elixir-format
msgid "Support response"
msgstr "Відповідь підтримки"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:3
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN"
msgstr "TAKE IT DOWN"
#: lib/who_need_help_web/controllers/support_html/new.html.heex:16
#, elixir-autogen, elixir-format
msgid "TAKE IT DOWN request"
msgstr "Запит TAKE IT DOWN"
#: lib/who_need_help_web/controllers/support_html.ex:7
#: lib/who_need_help_web/controllers/support_html/new.html.heex:30
#: lib/who_need_help_web/live/support_operations_live.ex:79
#, elixir-autogen, elixir-format
msgid "Technical issue"
msgstr "Технічна проблема"
#: lib/who_need_help_web/controllers/support_html/delete_account.html.heex:6
#, elixir-autogen, elixir-format
msgid "This requests deletion of your Who Need Help account and associated personal data. Some records may need to be retained when required for safety, fraud prevention, legal obligations, or resolving an active dispute; any retained data must be described in the applicable retention notice."
msgstr "Це запит на видалення облікового запису Who Need Help і пов’язаних персональних даних. Деякі записи можуть зберігатися, якщо це потрібно для безпеки, запобігання шахрайству, виконання закону або вирішення активного спору; збережені дані мають бути описані у відповідному повідомленні про зберігання."
#: lib/who_need_help_web/controllers/content_removal_html.ex:17
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:28
#: lib/who_need_help_web/live/support_operations_live.ex:99
#, elixir-autogen, elixir-format
msgid "Threat to life or safety"
msgstr "Загроза життю або безпеці"
#: lib/who_need_help_web/controllers/content_removal_controller.ex:54
#, elixir-autogen, elixir-format
msgid "Too many removal notices. Please try again later."
msgstr "Забагато повідомлень про видалення. Спробуйте пізніше."
#: lib/who_need_help_web/controllers/support_controller.ex:34
#: lib/who_need_help_web/controllers/support_controller.ex:72
#, elixir-autogen, elixir-format
msgid "Too many support requests. Please try again later."
msgstr "Забагато звернень до підтримки. Спробуйте пізніше."
#: lib/who_need_help_web/live/support_operations_live.ex:122
#, elixir-autogen, elixir-format
msgid "Trust and safety moderation"
msgstr "Модерація довіри й безпеки"
#: lib/who_need_help_web/controllers/content_removal_html.ex:22
#: lib/who_need_help_web/live/support_operations_live.ex:190
#, elixir-autogen, elixir-format
msgid "Urgent review"
msgstr "Терміновий розгляд"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:8
#, elixir-autogen, elixir-format
msgid "Use this dedicated process when an identifiable person is shown in an intimate image or video shared without consent, including a digital forgery. You may submit for yourself or as an authorised representative."
msgstr "Скористайтеся цією спеціальною процедурою, якщо впізнавану людину показано на інтимному зображенні чи відео, поширеному без згоди, зокрема на цифровій підробці. Запит можна подати за себе або як уповноважений представник."
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this electronic notice for specific content on Who Need Help that you believe is illegal or infringes your rights. Ordinary safety reports inside a request or chat remain available to signed-in users."
msgstr "Скористайтеся цим електронним повідомленням для конкретного контенту в Who Need Help, який ви вважаєте незаконним або таким, що порушує ваші права. Звичайні скарги на безпеку всередині заявки чи чату доступні користувачам, які ввійшли."
#: lib/who_need_help_web/controllers/support_html/new.html.heex:6
#, elixir-autogen, elixir-format
msgid "Use this form for account access, technical problems, privacy questions, or other support. For illegal content or a removal request, use the dedicated removal form."
msgstr "Скористайтеся цією формою для питань доступу до облікового запису, технічних проблем, конфіденційності та іншої підтримки. Для незаконного контенту або запиту на видалення скористайтеся спеціальною формою."
#: lib/who_need_help_web/controllers/user_settings_html/edit.html.heex:126
#, elixir-autogen, elixir-format
msgid "View support requests"
msgstr "Переглянути звернення до підтримки"
#: lib/who_need_help_web/live/support_operations_live.ex:254
#, elixir-autogen, elixir-format
msgid "Waiting for requester"
msgstr "Очікується відповідь заявника"
#: lib/who_need_help_web/controllers/support_html.ex:18
#, elixir-autogen, elixir-format
msgid "Waiting for your response"
msgstr "Очікується ваша відповідь"
#: lib/who_need_help_web/controllers/support_html/received.html.heex:6
#, elixir-autogen, elixir-format
msgid "We created support request %{reference}. A private status link has been sent to the contact email when delivery is configured. Opening that link verifies the address for public requests."
msgstr "Ми створили звернення %{reference}. Якщо доставку листів налаштовано, приватне посилання статусу надіслано на контактний email. Перехід за ним підтверджує адресу для публічних звернень."
#: lib/who_need_help_web/controllers/support_html/new.html.heex:27
#, elixir-autogen, elixir-format
msgid "What do you need help with?"
msgstr "Яка допомога вам потрібна?"
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:42
#, elixir-autogen, elixir-format
msgid "Who are you submitting for?"
msgstr "Від чийого імені ви подаєте запит?"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:62
#, elixir-autogen, elixir-format
msgid "Why do you believe this content should be removed?"
msgstr "Чому ви вважаєте, що цей контент слід видалити?"
#: lib/who_need_help_web/controllers/support_html/index.html.heex:26
#, elixir-autogen, elixir-format
msgid "You have not submitted any support requests."
msgstr "Ви ще не надсилали звернень до підтримки."
#: lib/who_need_help_web/controllers/content_removal_html/take_it_down.html.heex:30
#, elixir-autogen, elixir-format
msgid "Your full name"
msgstr "Ваше повне ім’я"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:34
#, elixir-autogen, elixir-format
msgid "Your name or organisation"
msgstr "Ваше ім’я або організація"
#: lib/who_need_help_web/controllers/content_removal_html/received.html.heex:5
#, elixir-autogen, elixir-format
msgid "Your reference is %{reference}"
msgstr "Номер вашого звернення: %{reference}"
#: lib/who_need_help_web/controllers/content_removal_html/new.html.heex:45
#, elixir-autogen, elixir-format
msgid "Your relationship to the affected person or rights holder"
msgstr "Ваше відношення до постраждалої особи або правовласника"
#: lib/who_need_help_web/live/support_operations_live.ex:150
#: lib/who_need_help_web/live/support_operations_live.ex:235
#, elixir-autogen, elixir-format
msgid "contact unverified"
msgstr "контакт не підтверджено"
#: lib/who_need_help_web/live/support_operations_live.ex:154
#, elixir-autogen, elixir-format
msgid "review by %{time}"
msgstr "розглянути до %{time}"
#: lib/who_need_help_web/controllers/support_controller.ex:47
#: lib/who_need_help_web/controllers/support_controller.ex:58
#, elixir-autogen, elixir-format
msgid "Delete my Who Need Help account"
msgstr "Видалити мій обліковий запис Who Need Help"
#: lib/who_need_help_web/controllers/support_controller.ex:48
#, elixir-autogen, elixir-format
msgid "Please delete my account and associated personal data."
msgstr "Будь ласка, видаліть мій обліковий запис і пов’язані персональні дані."

View File

@ -0,0 +1,58 @@
defmodule WhoNeedHelp.Repo.Migrations.CreateSupportAndContentRemoval do
use Ecto.Migration
def change do
create table(:support_requests, primary_key: false) do
add :id, :binary_id, primary_key: true
add :reference, :string, null: false
add :kind, :string, null: false
add :status, :string, null: false, default: "open"
add :contact_email, :string, null: false
add :subject, :string, null: false
add :details, :text, null: false
add :contact_verified_at, :utc_datetime
add :resolution_note, :text
add :reviewed_at, :utc_datetime
add :response_sent_at, :utc_datetime
add :requester_id, references(:users, type: :binary_id, on_delete: :nilify_all)
add :reviewed_by_id, references(:users, type: :binary_id, on_delete: :nilify_all)
timestamps(type: :utc_datetime)
end
create unique_index(:support_requests, [:reference])
create index(:support_requests, [:status, :inserted_at, :id])
create index(:support_requests, [:kind, :status, :inserted_at, :id])
create index(:support_requests, [:requester_id, :inserted_at, :id])
create table(:content_removal_notices, primary_key: false) do
add :id, :binary_id, primary_key: true
add :reference, :string, null: false
add :regime, :string, null: false, default: "general"
add :category, :string, null: false
add :status, :string, null: false, default: "open"
add :submitter_name, :string
add :contact_email, :string
add :relationship, :string
add :content_locations, :text, null: false
add :explanation, :text, null: false
add :legal_basis, :text
add :contact_verified_at, :utc_datetime
add :good_faith, :boolean, null: false, default: false
add :accurate_complete, :boolean, null: false, default: false
add :electronic_signature, :string
add :resolution_note, :text
add :reviewed_at, :utc_datetime
add :response_due_at, :utc_datetime
add :acknowledgement_sent_at, :utc_datetime
add :decision_sent_at, :utc_datetime
add :requester_id, references(:users, type: :binary_id, on_delete: :nilify_all)
add :reviewed_by_id, references(:users, type: :binary_id, on_delete: :nilify_all)
timestamps(type: :utc_datetime)
end
create unique_index(:content_removal_notices, [:reference])
create index(:content_removal_notices, [:status, :inserted_at, :id])
create index(:content_removal_notices, [:regime, :status, :inserted_at, :id])
create index(:content_removal_notices, [:requester_id, :inserted_at, :id])
end
end

View File

@ -96,6 +96,7 @@ smtp_auth=${PRODUCTION_SMTP_AUTH:-always}
smtp_tls=${PRODUCTION_SMTP_TLS:-always}
smtp_ssl=${PRODUCTION_SMTP_SSL:-false}
email_from_address=${PRODUCTION_EMAIL_FROM_ADDRESS:-"contact@$domain"}
support_inbox_address=${PRODUCTION_SUPPORT_INBOX_ADDRESS:-}
tmp=$(mktemp "$target_dir/.production-env.XXXXXX")
trap 'rm -f "$tmp"' EXIT HUP INT TERM
@ -123,6 +124,7 @@ SMTP_AUTH_VALUE=$smtp_auth \
SMTP_TLS_VALUE=$smtp_tls \
SMTP_SSL_VALUE=$smtp_ssl \
EMAIL_FROM_ADDRESS_VALUE=$email_from_address \
SUPPORT_INBOX_ADDRESS_VALUE=$support_inbox_address \
awk '
BEGIN {
replacement["DEPLOYMENT_TARGET"] = "compose"
@ -155,6 +157,7 @@ EMAIL_FROM_ADDRESS_VALUE=$email_from_address \
replacement["SMTP_TLS"] = ENVIRON["SMTP_TLS_VALUE"]
replacement["SMTP_SSL"] = ENVIRON["SMTP_SSL_VALUE"]
replacement["EMAIL_FROM_ADDRESS"] = ENVIRON["EMAIL_FROM_ADDRESS_VALUE"]
replacement["SUPPORT_INBOX_ADDRESS"] = ENVIRON["SUPPORT_INBOX_ADDRESS_VALUE"]
replacement["CODEX_SESSION_ID"] = "not-configured"
}
{

View File

@ -97,6 +97,7 @@ smtp_auth=$(require_value SMTP_AUTH)
smtp_tls=$(require_value SMTP_TLS)
smtp_ssl=$(require_value SMTP_SSL)
email_from_address=$(require_value EMAIL_FROM_ADDRESS)
support_inbox_address=$(optional_value SUPPORT_INBOX_ADDRESS)
google_oauth_client_id=$(optional_value GOOGLE_OAUTH_CLIENT_ID)
google_oauth_client_secret=$(optional_value GOOGLE_OAUTH_CLIENT_SECRET)
@ -224,6 +225,11 @@ fi
echo "EMAIL_FROM_ADDRESS is not an email address." >&2
exit 1
}
if [[ -n "$support_inbox_address" &&
! "$support_inbox_address" =~ ^[^@,\;[:space:]]+@[^@,\;[:space:]]+$ ]]; then
echo "SUPPORT_INBOX_ADDRESS is not an email address." >&2
exit 1
fi
if [[ -n "$google_oauth_client_id" || -n "$google_oauth_client_secret" ]]; then
[[ -n "$google_oauth_client_id" && -n "$google_oauth_client_secret" ]] || {

View File

@ -0,0 +1,202 @@
defmodule WhoNeedHelp.SupportAndContentRemovalTest do
use WhoNeedHelp.DataCase, async: false
import WhoNeedHelp.AccountsFixtures
import Swoosh.TestAssertions
alias WhoNeedHelp.{ContentRemoval, Repo, Support}
alias WhoNeedHelp.ContentRemoval.Notice
alias WhoNeedHelp.Support.SupportRequest
alias WhoNeedHelp.Trust.AuditEvent
test "public support request is persisted, acknowledged, and verified only through its email link" do
assert {:ok, request} =
Support.create_request(nil, %{
"kind" => "technical_issue",
"contact_email" => " Person@Example.com ",
"subject" => "Map does not open",
"details" => "The request map remains unavailable after reloading the page."
})
assert request.reference =~ "SUP-"
assert request.contact_email == "person@example.com"
assert is_nil(request.contact_verified_at)
assert_email_sent(fn email ->
email.subject =~ request.reference and email.text_body =~ Support.status_url(request)
end)
assert {:error, :not_found} = Support.get_by_access_token(request.id, "invalid")
assert {:ok, verified} =
Support.get_by_access_token(request.id, Support.access_token(request))
assert verified.contact_verified_at
assert Repo.exists?(
from event in AuditEvent,
where:
event.action == "support_request.created" and
event.target_id == ^request.id
)
end
test "configured support inbox receives a metadata-only operator alert and Reply-To" do
previous = Application.get_env(:who_need_help, :support_inbox_address)
Application.put_env(:who_need_help, :support_inbox_address, "support@example.com")
on_exit(fn -> Application.put_env(:who_need_help, :support_inbox_address, previous) end)
assert {:ok, request} =
Support.create_request(nil, %{
"kind" => "moderation_appeal",
"contact_email" => "appeal@example.com",
"subject" => "Appeal moderation decision",
"details" =>
"Please review the moderation decision identified in my account notice."
})
assert_email_sent(fn email ->
email.to == [{"", "appeal@example.com"}] and
email.reply_to == {"", "support@example.com"}
end)
assert_email_sent(fn email ->
email.to == [{"", "support@example.com"}] and email.subject =~ request.reference and
email.text_body =~ "/support/operations" and
not String.contains?(email.text_body, request.details)
end)
end
test "authenticated support uses the account email and staff moderation is audited" do
user = user_fixture()
assert_email_sent()
scope = user_scope_fixture(user)
assert {:ok, request} =
Support.create_request(scope, %{
"kind" => "data_export",
"contact_email" => "forged@example.com",
"subject" => "Export my data",
"details" =>
"Please prepare an export of the personal data associated with my account."
})
assert request.contact_email == user.email
assert request.contact_verified_at
assert_email_sent()
moderator =
user_fixture()
|> Ecto.Changeset.change(role: :moderator)
|> Repo.update!()
assert_email_sent()
assert {:error, :forbidden} =
Support.moderate(scope, request.id, %{
"status" => "resolved",
"resolution_note" => "Not allowed"
})
assert {:ok, resolved} =
Support.moderate(user_scope_fixture(moderator), request.id, %{
"status" => "resolved",
"resolution_note" => "The export is ready for the verified account owner."
})
assert resolved.status == :resolved
assert resolved.response_sent_at
assert_email_sent(fn email ->
email.subject =~ "support update" and email.text_body =~ "export is ready"
end)
end
test "TAKE IT DOWN notices use a separate urgent queue and never accept an unrelated category" do
attrs = %{
"category" => "non_consensual_intimate_media",
"submitter_name" => "Affected Person",
"contact_email" => "affected@example.com",
"relationship" => "self",
"content_locations" => "https://example.test/requests/one",
"explanation" => "An intimate visual depiction of me was posted without my consent.",
"electronic_signature" => "Affected Person",
"good_faith" => "true",
"accurate_complete" => "true"
}
assert {:ok, notice} = ContentRemoval.create_notice(nil, :take_it_down, attrs)
assert notice.regime == :take_it_down
assert notice.status == :urgent_review
assert notice.response_due_at
assert is_nil(notice.contact_verified_at)
assert_email_sent(fn email ->
email.subject =~ notice.reference and
email.text_body =~ "Do not reply with or upload intimate visual material"
end)
assert {:error, changeset} =
ContentRemoval.create_notice(nil, :take_it_down, %{
attrs
| "category" => "copyright",
"contact_email" => "copyright@example.com"
})
assert "must describe intimate visual material" in errors_on(changeset).category
end
test "general notice validates exact URLs and permits anonymous child-safety reporting" do
assert {:error, changeset} =
ContentRemoval.create_notice(nil, :general, %{
"category" => "illegal_content",
"submitter_name" => "Reporter",
"contact_email" => "reporter@example.com",
"relationship" => "other",
"content_locations" => "not a URL",
"explanation" =>
"This is a sufficiently long explanation of the reported content.",
"electronic_signature" => "Reporter",
"good_faith" => "true",
"accurate_complete" => "true"
})
assert "must contain one full HTTP or HTTPS URL per line" in errors_on(changeset).content_locations
assert {:ok, notice} =
ContentRemoval.create_notice(nil, :general, %{
"category" => "child_sexual_abuse_material",
"content_locations" => "https://example.test/messages/safety-reference",
"explanation" =>
"The referenced location appears to contain sexual material involving a minor.",
"good_faith" => "true",
"accurate_complete" => "true"
})
assert notice.status == :urgent_review
assert is_nil(notice.contact_email)
assert is_nil(notice.acknowledgement_sent_at)
assert [%Notice{id: id}] = ContentRemoval.paginate_for_staff(moderator_scope()).entries
assert id == notice.id
end
test "account deletion is represented as a dedicated verified account-lifecycle request" do
user = user_fixture()
assert {:ok, request} =
user
|> user_scope_fixture()
|> Support.create_account_deletion_request()
assert %SupportRequest{kind: :account_deletion, requester_id: requester_id} = request
assert requester_id == user.id
assert request.contact_verified_at
end
defp moderator_scope do
user_fixture()
|> Ecto.Changeset.change(role: :moderator)
|> Repo.update!()
|> user_scope_fixture()
end
end

View File

@ -0,0 +1,158 @@
defmodule WhoNeedHelpWeb.SupportControllerTest do
use WhoNeedHelpWeb.ConnCase, async: false
import WhoNeedHelp.AccountsFixtures
import Swoosh.TestAssertions
describe "public support and removal intake" do
test "renders each public form", %{conn: conn} do
assert html_response(get(conn, ~p"/support"), 200) =~ "Contact Who Need Help"
assert html_response(get(conn, ~p"/account/delete"), 200) =~ "Request account deletion"
assert html_response(get(conn, ~p"/legal/content-removal"), 200) =~
"Report illegal or harmful content"
assert html_response(
get(conn, ~p"/legal/content-removal?location=/requests/specific-id"),
200
) =~ "/requests/specific-id"
assert html_response(get(conn, ~p"/legal/take-it-down"), 200) =~
"Do not upload the image or video"
end
test "creates support request without exposing its status token in the redirect", %{
conn: conn
} do
conn =
post(conn, ~p"/support", %{
"support_request" => %{
"kind" => "technical_issue",
"contact_email" => "person@example.com",
"subject" => "Unable to open a request",
"details" => "The request page reports an error after the form is submitted."
}
})
location = redirected_to(conn)
assert location =~ "/support/received?reference=SUP-"
refute location =~ "token="
assert_email_sent()
end
test "creates urgent TAKE IT DOWN notice without accepting a media upload", %{conn: conn} do
conn =
post(conn, ~p"/legal/take-it-down", %{
"notice" => %{
"category" => "non_consensual_intimate_media",
"submitter_name" => "Affected Person",
"contact_email" => "affected@example.com",
"relationship" => "self",
"content_locations" => "https://example.test/requests/reported",
"explanation" => "The identified intimate image was posted without my consent.",
"electronic_signature" => "Affected Person",
"good_faith" => "true",
"accurate_complete" => "true"
}
})
location = redirected_to(conn)
assert location =~ "/legal/content-removal/received?reference=REM-"
refute location =~ "token="
assert_email_sent()
end
test "rejects malformed public form shapes without crashing", %{conn: conn} do
assert response(post(conn, ~p"/support", %{"support_request" => "invalid"}), 400)
assert response(
post(conn, ~p"/legal/content-removal", %{"notice" => "invalid"}),
400
)
assert response(
post(conn, ~p"/legal/take-it-down", %{"notice" => "invalid"}),
400
)
end
end
describe "authenticated support" do
setup :register_and_log_in_user
test "lists the current user's cases and links account deletion from settings", %{
conn: conn,
user: user
} do
{:ok, request} =
WhoNeedHelp.Support.create_request(user_scope_fixture(user), %{
"kind" => "account_access",
"subject" => "Account question",
"details" => "I need assistance understanding an account setting."
})
assert html_response(get(conn, ~p"/support/requests"), 200) =~ request.reference
assert html_response(get(conn, ~p"/users/settings"), 200) =~ ~p"/account/delete"
end
end
describe "operator queue authorization" do
test "requires a moderator", %{conn: conn} do
conn = get(conn, ~p"/support/operations")
assert redirected_to(conn) == ~p"/users/log-in"
end
test "renders separate support and removal queues for a moderator", %{conn: conn} do
moderator =
user_fixture()
|> Ecto.Changeset.change(role: :moderator)
|> WhoNeedHelp.Repo.update!()
{:ok, _support_request} =
WhoNeedHelp.Support.create_request(nil, %{
"kind" => "technical_issue",
"contact_email" => "support-queue@example.com",
"subject" => "Check the support queue",
"details" => "This request verifies that an open status remains selected."
})
{:ok, _removal_notice} =
WhoNeedHelp.ContentRemoval.create_notice(nil, :general, %{
"category" => "illegal_content",
"submitter_name" => "Queue Reporter",
"contact_email" => "removal-queue@example.com",
"relationship" => "self",
"content_locations" => "https://example.test/requests/queue-check",
"explanation" => "This notice verifies that an open status remains selected.",
"electronic_signature" => "Queue Reporter",
"good_faith" => "true",
"accurate_complete" => "true"
})
response =
conn
|> log_in_user(moderator)
|> get(~p"/support/operations")
|> html_response(200)
assert response =~ "Content removal and TAKE IT DOWN"
assert response =~ "General support and data requests"
document = LazyHTML.from_document(response)
assert Enum.count(
LazyHTML.query(
document,
"select[id^='removal-'] option[value='open'][selected]"
)
) == 1
assert Enum.count(
LazyHTML.query(
document,
"select[id^='support-'] option[value='open'][selected]"
)
) == 1
end
end
end