ok($this->me()); } public function update(Request $request): JsonResponse { $onboarding = []; foreach (['onboarding_checklist_completed', 'onboarding_tour_completed'] as $field) { if (!$request->has($field)) { continue; } $value = $request->input($field); if (!is_bool($value)) { return $this->validationError([$field => [__('Choose whether onboarding is complete.', 'maze-graph')]]); } $onboarding[$field] = $value; } if ($request->has('instructions')) { $text = Redactor::cleanText((string) $request->input('instructions')); if (mb_strlen($text) > UserPreferences::INSTRUCTIONS_LIMIT) { return $this->validationError(['instructions' => [sprintf( /* translators: %s: maximum number of characters. */ __('Keep the instructions under %s characters.', 'maze-graph'), number_format_i18n(UserPreferences::INSTRUCTIONS_LIMIT) )]]); } $this->preferences->setInstructions($this->userId(), $text); } if (array_key_exists('onboarding_checklist_completed', $onboarding)) { $this->preferences->setOnboardingChecklistCompleted($this->userId(), $onboarding['onboarding_checklist_completed']); } if (array_key_exists('onboarding_tour_completed', $onboarding)) { $this->preferences->setOnboardingTourCompleted($this->userId(), $onboarding['onboarding_tour_completed']); } return $this->ok($this->me()); } public function consent(): JsonResponse { $this->preferences->consent($this->userId()); return $this->ok($this->me()); } /** Export one bounded page of the signed-in person's MazeGraph data. */ public function exportData(Request $request, PersonalData $personalData): JsonResponse { $page = filter_var($request->query('page', 1), FILTER_VALIDATE_INT); if ($page === false || $page < 1 || $page > PersonalData::SELF_SERVICE_EXPORT_MAX_PAGE) { return $this->validationError(['page' => [__('Choose a valid export page.', 'maze-graph')]]); } return $this->noStore($this->ok($personalData->exportUser($this->userId(), $page))); } /** Erase the signed-in person's MazeGraph data, leaving site settings and other users untouched. */ public function eraseData(PersonalData $personalData): JsonResponse { return $this->noStore($this->ok(['erased' => $personalData->eraseUser($this->userId()) > 0])); } /** * `DELETE /me/sessions`: every session of the current user, for good (no undo). */ public function eraseSessions(SessionRepository $sessions): JsonResponse { return $this->ok(['deleted' => $sessions->eraseUser($this->userId())]); } /** * `GET /me/notes`: the person's own notes and the site's (CORE-12). */ public function notes(OptionsMemoryStore $memory): JsonResponse { return $this->ok(['notes' => $memory->recall($this->userId(), '', 100)]); } /** * `POST /me/notes` `{content}`: a note the person writes themselves. */ public function addNote(Request $request, OptionsMemoryStore $memory): JsonResponse { $content = Redactor::cleanText((string) $request->input('content', '')); if ($content === '' || mb_strlen($content) > OptionsMemoryStore::MAX_LENGTH) { return $this->validationError(['content' => [sprintf( /* translators: %s: maximum number of characters. */ __('Write a note of up to %s characters.', 'maze-graph'), number_format_i18n(OptionsMemoryStore::MAX_LENGTH) )]]); } $scope = $request->input('scope') === 'site' && current_user_can(Access::MANAGE) ? 'site' : 'user'; $memory->save($this->userId(), $content, $scope); return $this->notes($memory); } /** * `DELETE /me/notes/{note}`: forget one of the person's notes (or a site note, for people who manage). */ public function forgetNote(Request $request, OptionsMemoryStore $memory): JsonResponse { $id = (int) $request->route('note'); $done = $memory->forget($this->userId(), $id) || (current_user_can(Access::MANAGE) && $memory->forgetSite($id)); return $done ? $this->notes($memory) : $this->notFound(__('That note does not exist.', 'maze-graph')); } /** * @return array */ protected function me(): array { $userId = $this->userId(); return [ 'instructions' => $this->preferences->instructions($userId), 'consent' => [ 'accepted' => $this->preferences->consented($userId), 'version' => UserPreferences::CONSENT_VERSION, ], 'onboarding' => [ 'checklist_completed' => $this->preferences->onboardingChecklistCompleted($userId), 'tour_completed' => $this->preferences->onboardingTourCompleted($userId), ], 'can_manage' => current_user_can(Access::MANAGE), ]; } protected function noStore(JsonResponse $response): JsonResponse { return $response->header('Cache-Control', 'no-store, private'); } }