199 lines
5.3 KiB
PHP
199 lines
5.3 KiB
PHP
<?php
|
|
|
|
require_once __DIR__ . '/persona.php';
|
|
|
|
const CHORE_SCHEDULE_ONCE = 'once';
|
|
const CHORE_SCHEDULE_RECURRING = 'recurring';
|
|
|
|
/**
|
|
* @param mixed $raw
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
function normalizeChoresList($raw): array {
|
|
if (!is_array($raw) || !array_is_list($raw)) {
|
|
return [];
|
|
}
|
|
$out = [];
|
|
foreach ($raw as $row) {
|
|
if (is_array($row) && !empty($row['id']) && is_string($row['id'])) {
|
|
$out[] = $row;
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $people
|
|
* @return array<int, string>
|
|
*/
|
|
function legacyAssigneeNameToIds(string $name, array $people): array {
|
|
$name = trim($name);
|
|
if ($name === '') {
|
|
return [];
|
|
}
|
|
$lower = mb_strtolower($name, 'UTF-8');
|
|
$ids = [];
|
|
foreach ($people as $p) {
|
|
$pn = trim((string) ($p['name'] ?? ''));
|
|
if ($pn !== '' && mb_strtolower($pn, 'UTF-8') === $lower) {
|
|
$ids[] = (string) $p['id'];
|
|
}
|
|
}
|
|
return $ids;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $c
|
|
* @param array<int, array<string, mixed>> $people
|
|
* @return array<string, mixed>
|
|
*/
|
|
function migrateLegacyChoreRow(array $c, array $people): array {
|
|
if (isset($c['name']) && !isset($c['title'])) {
|
|
$c['title'] = (string) $c['name'];
|
|
}
|
|
if (!isset($c['assignee_ids']) || !is_array($c['assignee_ids'])) {
|
|
if (isset($c['assignee'])) {
|
|
$c['assignee_ids'] = legacyAssigneeNameToIds((string) $c['assignee'], $people);
|
|
} else {
|
|
$c['assignee_ids'] = [];
|
|
}
|
|
}
|
|
$ids = [];
|
|
foreach ($c['assignee_ids'] as $id) {
|
|
if (is_string($id) && $id !== '') {
|
|
$ids[] = $id;
|
|
}
|
|
}
|
|
$c['assignee_ids'] = array_values(array_unique($ids));
|
|
if (!isset($c['lists']) || !is_array($c['lists'])) {
|
|
$c['lists'] = [];
|
|
}
|
|
$c['lists'] = normalizeChoreLists($c['lists']);
|
|
if (!isset($c['description'])) {
|
|
$c['description'] = '';
|
|
}
|
|
if (!isset($c['image'])) {
|
|
$c['image'] = '';
|
|
}
|
|
if (!isset($c['author_id'])) {
|
|
$c['author_id'] = '';
|
|
}
|
|
if (!isset($c['value'])) {
|
|
$c['value'] = 0;
|
|
}
|
|
$c['value'] = is_numeric($c['value']) ? (float) $c['value'] : 0.0;
|
|
if (!isset($c['due_date'])) {
|
|
$c['due_date'] = '';
|
|
}
|
|
$c['due_date'] = is_string($c['due_date']) ? trim($c['due_date']) : '';
|
|
if ($c['due_date'] !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $c['due_date'])) {
|
|
$c['due_date'] = '';
|
|
}
|
|
$sched = $c['schedule'] ?? CHORE_SCHEDULE_ONCE;
|
|
$c['schedule'] = $sched === CHORE_SCHEDULE_RECURRING ? CHORE_SCHEDULE_RECURRING : CHORE_SCHEDULE_ONCE;
|
|
if (!isset($c['recurrence_days']) || !is_numeric($c['recurrence_days'])) {
|
|
$c['recurrence_days'] = 7;
|
|
}
|
|
$c['recurrence_days'] = max(1, (int) $c['recurrence_days']);
|
|
if (!isset($c['status'])) {
|
|
$c['status'] = 'active';
|
|
}
|
|
$st = (string) $c['status'];
|
|
$c['status'] = in_array($st, ['active', 'completed'], true) ? $st : 'active';
|
|
if (!array_key_exists('pending_submission', $c)) {
|
|
$c['pending_submission'] = null;
|
|
}
|
|
if ($c['pending_submission'] !== null && !is_array($c['pending_submission'])) {
|
|
$c['pending_submission'] = null;
|
|
}
|
|
return $c;
|
|
}
|
|
|
|
/**
|
|
* @param mixed $lists
|
|
* @return array<int, array{type: string, items: array<int, string>}>
|
|
*/
|
|
function normalizeChoreLists($lists): array {
|
|
if (!is_array($lists)) {
|
|
return [];
|
|
}
|
|
$out = [];
|
|
foreach ($lists as $block) {
|
|
if (!is_array($block)) {
|
|
continue;
|
|
}
|
|
$type = isset($block['type']) ? (string) $block['type'] : 'checkbox';
|
|
if (!in_array($type, ['ordered', 'unordered', 'checkbox'], true)) {
|
|
$type = 'checkbox';
|
|
}
|
|
$items = $block['items'] ?? [];
|
|
if (!is_array($items)) {
|
|
$items = [];
|
|
}
|
|
$clean = [];
|
|
foreach ($items as $it) {
|
|
$s = trim((string) $it);
|
|
if ($s !== '') {
|
|
$clean[] = $s;
|
|
}
|
|
}
|
|
$out[] = ['type' => $type, 'items' => $clean];
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $chores
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
function migrateAllChores(array $chores, array $people): array {
|
|
$out = [];
|
|
foreach ($chores as $c) {
|
|
$out[] = migrateLegacyChoreRow($c, $people);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $chores
|
|
*/
|
|
function findChoreById(array $chores, string $id): ?array {
|
|
foreach ($chores as $c) {
|
|
if (($c['id'] ?? '') === $id) {
|
|
return $c;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $chores
|
|
*/
|
|
function findChoreIndexById(array $chores, string $id): ?int {
|
|
foreach ($chores as $i => $c) {
|
|
if (($c['id'] ?? '') === $id) {
|
|
return $i;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, string> $assigneeIds
|
|
* @param array<int, array<string, mixed>> $people
|
|
*/
|
|
function choreAssigneeIdsValid(array $assigneeIds, array $people): bool {
|
|
$set = [];
|
|
foreach ($people as $p) {
|
|
if (!empty($p['id'])) {
|
|
$set[(string) $p['id']] = true;
|
|
}
|
|
}
|
|
foreach ($assigneeIds as $id) {
|
|
if (!isset($set[$id])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|