Add read-only Play review readiness check

This commit is contained in:
SimpleTest 2026-08-03 22:18:55 +03:00
parent 07f96a6070
commit 9e0d41eadf
4 changed files with 82 additions and 12 deletions

View File

@ -46,8 +46,18 @@ access field:
second factor, one-time code, developer browser session, or location gate. second factor, one-time code, developer browser session, or location gate.
After both dedicated accounts have registered, confirmed their email, and set After both dedicated accounts have registered, confirmed their email, and set
their fixed passwords through the production UI, an operator can create the their fixed passwords through the production UI, first run the read-only
stable synthetic records from the production checkout: readiness check from the production checkout:
```bash
./scripts/prepare-play-review.sh \
REVIEWER_EMAIL COUNTERPART_EMAIL \
--check-only whoneedhelp.com \
/srv/who_need_help-production/.env
```
Only after that check succeeds should an operator create the stable synthetic
records:
```bash ```bash
./scripts/prepare-play-review.sh \ ./scripts/prepare-play-review.sh \

View File

@ -65,6 +65,32 @@ defmodule WhoNeedHelp.Release do
@play_review_request_title "Play review — medicine pickup" @play_review_request_title "Play review — medicine pickup"
@play_review_activity_title "Play review — public cinema meetup" @play_review_activity_title "Play review — public cinema meetup"
@doc """
Checks whether two existing ordinary accounts can be used for Google Play
review without creating or changing any records.
"""
def play_review_readiness(reviewer_email, counterpart_email)
when is_binary(reviewer_email) and is_binary(counterpart_email) do
load_app()
with {:ok, reviewer} <- play_review_user(reviewer_email, :reviewer),
{:ok, counterpart} <- play_review_user(counterpart_email, :counterpart),
:ok <- different_play_review_users(reviewer, counterpart),
{:ok, medicine_category} <- active_category("medicine-pickup", :help),
{:ok, cinema_category} <- active_category("cinema-meetup", :activity) do
{:ok,
%{
reviewer: reviewer,
counterpart: counterpart,
medicine_category: medicine_category,
cinema_category: cinema_category
}}
end
end
def play_review_readiness(_reviewer_email, _counterpart_email),
do: {:error, :invalid_email}
@doc """ @doc """
Prepares stable, synthetic records for Google Play review using two existing Prepares stable, synthetic records for Google Play review using two existing
ordinary accounts. ordinary accounts.
@ -75,13 +101,13 @@ defmodule WhoNeedHelp.Release do
""" """
def prepare_play_review(reviewer_email, counterpart_email) def prepare_play_review(reviewer_email, counterpart_email)
when is_binary(reviewer_email) and is_binary(counterpart_email) do when is_binary(reviewer_email) and is_binary(counterpart_email) do
load_app() with {:ok,
%{
with {:ok, reviewer} <- play_review_user(reviewer_email, :reviewer), reviewer: reviewer,
{:ok, counterpart} <- play_review_user(counterpart_email, :counterpart), counterpart: counterpart,
:ok <- different_play_review_users(reviewer, counterpart), medicine_category: medicine_category,
{:ok, medicine_category} <- active_category("medicine-pickup", :help), cinema_category: cinema_category
{:ok, cinema_category} <- active_category("cinema-meetup", :activity), }} <- play_review_readiness(reviewer_email, counterpart_email),
{:ok, request} <- {:ok, request} <-
ensure_play_review_request(reviewer, counterpart, medicine_category), ensure_play_review_request(reviewer, counterpart, medicine_category),
{:ok, activity} <- {:ok, activity} <-

View File

@ -6,14 +6,18 @@ EXPECTED_ROOT=/srv/who_need_help-production
EXPECTED_PROJECT=who_need_help_production EXPECTED_PROJECT=who_need_help_production
EXPECTED_ORIGIN=https://whoneedhelp.com EXPECTED_ORIGIN=https://whoneedhelp.com
if [ "$#" -ne 5 ] || [ "$3" != "--confirm" ] || [ "$4" != "whoneedhelp.com" ]; then if [ "$#" -ne 5 ] ||
echo "Usage: $0 REVIEWER_EMAIL COUNTERPART_EMAIL --confirm whoneedhelp.com ENV_FILE" >&2 { [ "$3" != "--check-only" ] && [ "$3" != "--confirm" ]; } ||
[ "$4" != "whoneedhelp.com" ]; then
echo "Usage: $0 REVIEWER_EMAIL COUNTERPART_EMAIL --check-only whoneedhelp.com ENV_FILE" >&2
echo " $0 REVIEWER_EMAIL COUNTERPART_EMAIL --confirm whoneedhelp.com ENV_FILE" >&2
echo "Both existing accounts must be active, confirmed, password-enabled, and non-staff." >&2 echo "Both existing accounts must be active, confirmed, password-enabled, and non-staff." >&2
exit 1 exit 1
fi fi
REVIEWER_EMAIL=$1 REVIEWER_EMAIL=$1
COUNTERPART_EMAIL=$2 COUNTERPART_EMAIL=$2
ACTION=$3
ENV_FILE=$5 ENV_FILE=$5
if [ "$(realpath --canonicalize-existing "$ROOT")" != "$EXPECTED_ROOT" ]; then if [ "$(realpath --canonicalize-existing "$ROOT")" != "$EXPECTED_ROOT" ]; then
@ -95,6 +99,11 @@ encode() {
reviewer=$(encode "$REVIEWER_EMAIL") reviewer=$(encode "$REVIEWER_EMAIL")
counterpart=$(encode "$COUNTERPART_EMAIL") counterpart=$(encode "$COUNTERPART_EMAIL")
expression="case WhoNeedHelp.Release.prepare_play_review(Base.decode64!(\"$reviewer\"), Base.decode64!(\"$counterpart\")) do {:ok, result} -> IO.inspect(result); {:error, reason} -> raise \"Play review preparation failed: #{inspect(reason)}\" end"
if [ "$ACTION" = "--check-only" ]; then
expression="case WhoNeedHelp.Release.play_review_readiness(Base.decode64!(\"$reviewer\"), Base.decode64!(\"$counterpart\")) do {:ok, result} -> IO.inspect(%{reviewer_id: result.reviewer.id, counterpart_id: result.counterpart.id, medicine_category_id: result.medicine_category.id, cinema_category_id: result.cinema_category.id}, label: :play_review_ready); {:error, reason} -> raise \"Play review readiness failed: #{inspect(reason)}\" end"
else
expression="case WhoNeedHelp.Release.prepare_play_review(Base.decode64!(\"$reviewer\"), Base.decode64!(\"$counterpart\")) do {:ok, result} -> IO.inspect(result); {:error, reason} -> raise \"Play review preparation failed: #{inspect(reason)}\" end"
fi
docker exec "$container" /app/bin/who_need_help rpc "$expression" docker exec "$container" /app/bin/who_need_help rpc "$expression"

View File

@ -20,6 +20,22 @@ defmodule WhoNeedHelp.ReleaseTest do
%{reviewer: reviewer, counterpart: counterpart} %{reviewer: reviewer, counterpart: counterpart}
end end
test "checks reviewer readiness without creating review records", %{
reviewer: reviewer,
counterpart: counterpart
} do
before_counts = review_record_counts()
assert {:ok, readiness} =
Release.play_review_readiness(reviewer.email, counterpart.email)
assert readiness.reviewer.id == reviewer.id
assert readiness.counterpart.id == counterpart.id
assert readiness.medicine_category.slug == "medicine-pickup"
assert readiness.cinema_category.slug == "cinema-meetup"
assert review_record_counts() == before_counts
end
test "prepares stable non-staff reviewer records idempotently", %{ test "prepares stable non-staff reviewer records idempotently", %{
reviewer: reviewer, reviewer: reviewer,
counterpart: counterpart counterpart: counterpart
@ -90,4 +106,13 @@ defmodule WhoNeedHelp.ReleaseTest do
assert {:error, {:reviewer, :staff_account_forbidden}} = assert {:error, {:reviewer, :staff_account_forbidden}} =
Release.prepare_play_review(staff.email, counterpart.email) Release.prepare_play_review(staff.email, counterpart.email)
end end
defp review_record_counts do
%{
requests: Repo.aggregate(HelpRequest, :count),
assignments: Repo.aggregate(Assignment, :count),
activities: Repo.aggregate(Activity, :count),
participants: Repo.aggregate(Participant, :count)
}
end
end end