1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Models\Forum;
7
8use App\Casts\LegacyFilename;
9use App\Libraries\Uploader;
10use App\Models\User;
11use DB;
12
13/**
14 * @property \Carbon\Carbon|null $created_at
15 * @property mixed $default_topic_cover
16 * @property array|null $default_topic_cover_json
17 * @property string|null $ext
18 * @property Forum $forum
19 * @property int|null $forum_id
20 * @property string|null $hash
21 * @property int $id
22 * @property mixed $main_cover
23 * @property \Carbon\Carbon|null $updated_at
24 * @property User $user
25 * @property int|null $user_id
26 */
27class ForumCover extends Model
28{
29 const MAX_DIMENSIONS = [2000, 400];
30
31 protected $casts = [
32 'default_topic_cover_json' => 'array',
33 'filename' => LegacyFilename::class,
34 ];
35 protected $table = 'forum_forum_covers';
36
37 private Uploader $defaultTopicCoverUploader;
38 private Uploader $file;
39
40 public static function upload($filePath, $user, $forum = null)
41 {
42 $cover = new static();
43
44 DB::transaction(function () use ($cover, $filePath, $user, $forum) {
45 $cover->save(); // get id
46 $cover->user()->associate($user);
47 $cover->forum()->associate($forum);
48 $cover->file()->store($filePath);
49 $cover->save();
50 });
51
52 return $cover;
53 }
54
55 public function forum()
56 {
57 return $this->belongsTo(Forum::class, 'forum_id');
58 }
59
60 public function user()
61 {
62 return $this->belongsTo(User::class, 'user_id');
63 }
64
65 public function getDefaultTopicCoverAttribute(): Uploader
66 {
67 return $this->defaultTopicCoverUploader ??= new Uploader(
68 'forum-default-topic-covers',
69 $this,
70 'default_topic_cover_filename',
71 ['image' => ['maxDimensions' => TopicCover::MAX_DIMENSIONS]],
72 );
73 }
74
75 public function setDefaultTopicCoverAttribute($value): void
76 {
77 if (($value['_delete'] ?? false) === true) {
78 $this->defaultTopicCover->delete();
79 } elseif (($value['cover_file'] ?? null) !== null) {
80 $this->defaultTopicCover->store($value['cover_file']);
81 }
82 }
83
84 public function getDefaultTopicCoverFilenameAttribute(): ?string
85 {
86 return LegacyFilename::makeFromAttributes($this->default_topic_cover_json);
87 }
88
89 public function setDefaultTopicCoverFilenameAttribute(?string $value): void
90 {
91 $this->default_topic_cover_json = [
92 'ext' => null,
93 'hash' => $value,
94 ];
95 }
96
97 public function setMainCoverAttribute($value): void
98 {
99 if ($value['_delete'] ?? false) {
100 $this->file()->delete();
101 } elseif (isset($value['cover_file'])) {
102 $this->file()->store($value['cover_file']);
103 }
104 }
105
106 public function delete()
107 {
108 $this->file()->delete();
109 $this->defaultTopicCover->delete();
110
111 return parent::delete();
112 }
113
114 public function file(): Uploader
115 {
116 return $this->file ??= new Uploader(
117 'forum-covers',
118 $this,
119 'filename',
120 ['image' => ['maxDimensions' => static::MAX_DIMENSIONS]],
121 );
122 }
123
124 public function updateFile($filePath, $user)
125 {
126 $this->user()->associate($user);
127 $this->file()->store($filePath);
128 $this->save();
129
130 return $this->fresh();
131 }
132}