107 lines
4.2 KiB
PHP
107 lines
4.2 KiB
PHP
<?php
|
|
require __DIR__ . '/_bootstrap.php';
|
|
|
|
/**
|
|
* @OA\Post(
|
|
* path="/account-delete.php",
|
|
* tags={"Auth"},
|
|
* summary="Delete the account and all related data",
|
|
* description="Immediate hard delete: documents on disk, homes, owners, sharing, tokens and the user row. Irreversible.",
|
|
* security={{"bearerAuth":{}}},
|
|
* @OA\RequestBody(required=true, @OA\JsonContent(
|
|
* required={"confirm"},
|
|
* @OA\Property(property="confirm", type="boolean", example=true,
|
|
* description="guard against an accidental call")
|
|
* )),
|
|
* @OA\Response(response=200, ref="#/components/responses/Success"),
|
|
* @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
|
|
* @OA\Response(response=422, ref="#/components/responses/ValidationError")
|
|
* )
|
|
*/
|
|
require_method('POST');
|
|
$user = require_auth($pdo);
|
|
$config = require __DIR__ . '/config.php';
|
|
|
|
if (empty(body()['confirm'])) {
|
|
json_error(422, 'Validation failed', ['confirm' => ['Required']]);
|
|
}
|
|
|
|
$userId = (int) $user['id'];
|
|
$email = (string) $user['email'];
|
|
|
|
// Ids owned by the user.
|
|
$stmt = $pdo->prepare('SELECT idhome FROM home WHERE iduser = ?');
|
|
$stmt->execute([$userId]);
|
|
$homeIds = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
$stmt = $pdo->prepare('SELECT owner_id FROM property_owners WHERE user_id = ?');
|
|
$stmt->execute([$userId]);
|
|
$ownerIds = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
// Collect files before the rows disappear; they are unlinked after a successful commit.
|
|
$files = [];
|
|
if ($homeIds || $ownerIds) {
|
|
$where = [];
|
|
$params = [];
|
|
if ($homeIds) {
|
|
$where[] = 'idhome IN (' . implode(',', array_fill(0, count($homeIds), '?')) . ')';
|
|
$params = array_merge($params, $homeIds);
|
|
}
|
|
if ($ownerIds) {
|
|
$where[] = 'owner_id IN (' . implode(',', array_fill(0, count($ownerIds), '?')) . ')';
|
|
$params = array_merge($params, $ownerIds);
|
|
}
|
|
$stmt = $pdo->prepare('SELECT filename, entity_type, idhome FROM doc_storage WHERE ' . implode(' OR ', $where));
|
|
$stmt->execute($params);
|
|
foreach ($stmt->fetchAll() as $f) {
|
|
$isPerson = ($f['entity_type'] ?? '') === 'person' || empty($f['idhome']);
|
|
$files[] = ($isPerson ? $config['persondocs_dir'] : $config['homedocs_dir'])
|
|
. '/' . basename((string) $f['filename']);
|
|
}
|
|
}
|
|
|
|
$in = fn (array $ids) => implode(',', array_fill(0, count($ids), '?'));
|
|
|
|
$pdo->beginTransaction();
|
|
try {
|
|
// Sharing granted by the user, received by the user, or addressed to their e-mail.
|
|
$pdo->prepare('DELETE FROM home_sharing WHERE iduser = ? OR idshareduser = ? OR shared_email = ?')
|
|
->execute([$userId, $userId, $email]);
|
|
|
|
if ($homeIds) {
|
|
$pdo->prepare('DELETE FROM doc_storage WHERE idhome IN (' . $in($homeIds) . ')')->execute($homeIds);
|
|
$pdo->prepare('DELETE FROM home_owners WHERE home_id IN (' . $in($homeIds) . ')')->execute($homeIds);
|
|
$pdo->prepare('DELETE FROM home_sharing WHERE idhome IN (' . $in($homeIds) . ')')->execute($homeIds);
|
|
}
|
|
if ($ownerIds) {
|
|
$pdo->prepare('DELETE FROM doc_storage WHERE owner_id IN (' . $in($ownerIds) . ')')->execute($ownerIds);
|
|
$pdo->prepare('DELETE FROM home_owners WHERE owner_id IN (' . $in($ownerIds) . ')')->execute($ownerIds);
|
|
}
|
|
|
|
$pdo->prepare('DELETE FROM home WHERE iduser = ?')->execute([$userId]);
|
|
$pdo->prepare('DELETE FROM property_owners WHERE user_id = ?')->execute([$userId]);
|
|
|
|
// Credentials and sessions.
|
|
$pdo->prepare('DELETE FROM api_tokens WHERE user_id = ?')->execute([$userId]);
|
|
$pdo->prepare('DELETE FROM auth_sessions WHERE user_id = ?')->execute([$userId]);
|
|
$pdo->prepare('DELETE FROM auth_personal_access_tokens WHERE tokenable_id = ?')->execute([$userId]);
|
|
$pdo->prepare('DELETE FROM auth_password_resets WHERE email = ?')->execute([$email]);
|
|
|
|
// Cascades auth_social_logins, auth_user_activity, auth_announcements.
|
|
$pdo->prepare('DELETE FROM auth_users WHERE id = ?')->execute([$userId]);
|
|
|
|
$pdo->commit();
|
|
} catch (Throwable $e) {
|
|
$pdo->rollBack();
|
|
json_error(500, 'Account deletion failed');
|
|
}
|
|
|
|
// Files last: an orphaned file is harmless, a lost file after a rollback is not.
|
|
foreach ($files as $path) {
|
|
if (is_file($path)) {
|
|
@unlink($path);
|
|
}
|
|
}
|
|
|
|
json_ok();
|