テーマ等の設定ユーザーでも保存

守矢諏訪子 <suwako@076.moe>、2026-11-11 11:33
コミット b4b752a69e126ba54a0043b53e392de3ebe53182 ・親 8d4ccf4 ・ファイルを見る

3個のファイル、+65 -0

@@ -354,6 +354,26 @@
354354 return [Result::Success(), $me, $user];
355355 }
356356
357+ /**
358+ * ログイン中のユーザーの表示の設定(テーマ等)をプロフィールに保存する
359+ *
360+ * @param array $prefs 名前 => 値(nullなら消す)
361+ * @return Result
362+ */
363+ public function savePrefs(array $prefs): Result {
364+ if (!AUTH_ENABLED || $this->id === 0) return Result::Error('エラー:ログインしていません。');
365+ $user = $this->getUserData();
366+ if (!$user instanceof \stdClass) return Result::Error('エラー:ユーザーが見つかりません。');
367+ $cur = (array)($user->prefs ?? []);
368+ foreach ($prefs as $k => $v) {
369+ if ($v === null) unset($cur[$k]);
370+ else $cur[$k] = (string)$v;
371+ }
372+ $user->prefs = (object)$cur;
373+ if (!$this->saveUser($user, 'savePrefs')) return Result::Error('エラー:ユーザーデータの保存に失敗。');
374+ return Result::Success();
375+ }
376+
357377 /** ユーザーのJSONファイルを書き換える */
358378 private function saveUser(\stdClass $user, string $where): bool {
359379 $path = $this->dataDir.$user->id.'.'.$user->username.'.json';
@@ -378,6 +378,36 @@
378378 });
379379 });
380380
381+$test->describe('表示の設定', function($test) use ($make, $read, $base): void {
382+ if (!AUTH_ENABLED) $test->skipAll('AUTH_ENABLEDが無効');
383+
384+ // 登録(DNSが必要)を使わずにユーザーを作る
385+ foreach (['prefuser01' => 901, 'prefuser02' => 902] as $name => $id) {
386+ file_put_contents("{$base}/user/{$id}.{$name}.json", json_encode(['id' => $id, 'username' => $name, 'role' => \Roles::MEMBER, 'tokens' => []]));
387+ }
388+
389+ $test->it('ログイン中のユーザーのプロフィールに保存するはず', function($test) use ($make, $read): void {
390+ $res = $make('prefuser01')->savePrefs(['theme' => 'loli', 'glowring_off' => 1]);
391+ $test->assertTrue($res->isSuccess, (string)$res->message);
392+ $test->assertEquals('loli', $read('prefuser01')->prefs->theme);
393+ $test->assertEquals('1', $read('prefuser01')->prefs->glowring_off);
394+ $test->assertFalse(isset($read('prefuser02')->prefs), '他のユーザーは変わらない');
395+ });
396+
397+ $test->it('他の設定を残したまま変更・削除出来るはず', function($test) use ($make, $read): void {
398+ $test->assertTrue($make('prefuser01')->savePrefs(['theme' => 'void'])->isSuccess);
399+ $test->assertEquals('void', $read('prefuser01')->prefs->theme);
400+ $test->assertEquals('1', $read('prefuser01')->prefs->glowring_off);
401+ $test->assertTrue($make('prefuser01')->savePrefs(['glowring_off' => null])->isSuccess);
402+ $test->assertFalse(isset($read('prefuser01')->prefs->glowring_off));
403+ $test->assertEquals(901, $read('prefuser01')->id, 'ユーザーデータは消えない');
404+ });
405+
406+ $test->it('ログインしていなければ保存しないはず', function($test) use ($make): void {
407+ $test->assertFalse($make()->savePrefs(['theme' => 'tux'])->isSuccess);
408+ });
409+});
410+
381411 // 一時ディレクトリを削除する
382412 $rm = function(string $dir) use (&$rm): void {
383413 foreach (scandir($dir) ?: [] as $f) {
変更 util.php
@@ -384,6 +384,21 @@
384384 return $_COOKIE[$name] ?? null;
385385 }
386386
387+/**
388+ * 表示の設定(テーマ等)。ログイン中ならプロフィールに保存した値、無ければクッキー
389+ *
390+ * @param string $name 設定の名前(クッキーと同じ名前)
391+ * @return string|null
392+ */
393+function pref(string $name): string|null {
394+ static $prefs = null;
395+ if ($prefs === null) {
396+ $user = AUTH_ENABLED ? (new \Std\Lib\Auth())->getLoggedInUser() : null;
397+ $prefs = (array)($user->prefs ?? []);
398+ }
399+ return isset($prefs[$name]) ? (string)$prefs[$name] : getcookie($name);
400+}
401+
387402 function namecolor(\stdClass $userData): string {
388403 $ban = "#888888";
389404 $male = "#97ACEF";