the browser-facing portion of osu!
at master 6.2 kB view raw
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 6declare(strict_types=1); 7 8namespace App\Models; 9 10use App\Models\Traits\WithDbCursorHelper; 11use Illuminate\Database\Eloquent\Builder; 12use Illuminate\Database\Eloquent\Relations\BelongsTo; 13use InvalidArgumentException; 14 15/** 16 * @property-read User|null $actor 17 * @property int|null $actor_id 18 * @property \Carbon\Carbon $created_at 19 * @property-read string $created_at_json 20 * @property array $details 21 * @property-read Group $group 22 * @property int $group_id 23 * @property int $id 24 * @property string $type 25 * @property-read User|null $user 26 * @property int|null $user_id 27 * @method static Builder visibleForUser(User|null $user) 28 */ 29class UserGroupEvent extends Model 30{ 31 use WithDbCursorHelper; 32 33 public const GROUP_ADD = 'group_add'; 34 public const GROUP_REMOVE = 'group_remove'; 35 public const GROUP_RENAME = 'group_rename'; 36 public const USER_ADD = 'user_add'; 37 public const USER_ADD_PLAYMODES = 'user_add_playmodes'; 38 public const USER_REMOVE = 'user_remove'; 39 public const USER_REMOVE_PLAYMODES = 'user_remove_playmodes'; 40 public const USER_SET_DEFAULT = 'user_set_default'; 41 42 public const UPDATED_AT = null; 43 44 protected const DEFAULT_SORT = 'id_desc'; 45 protected const SORTS = [ 46 'id_asc' => [ 47 ['column' => 'id', 'order' => 'ASC'], 48 ], 49 'id_desc' => [ 50 ['column' => 'id', 'order' => 'DESC'], 51 ], 52 ]; 53 54 protected $casts = [ 55 'details' => 'array', 56 'hidden' => 'boolean', 57 ]; 58 59 public static function logGroupAdd(?User $actor, Group $group): void 60 { 61 static::log($actor, static::GROUP_ADD, null, $group); 62 } 63 64 public static function logGroupRemove(?User $actor, Group $group): void 65 { 66 static::log($actor, static::GROUP_REMOVE, null, $group); 67 } 68 69 public static function logGroupRename(?User $actor, Group $group, string $previousName, string $name): void 70 { 71 static::log($actor, static::GROUP_RENAME, null, $group, [ 72 'details' => [ 73 'group_name' => $name, 74 'previous_group_name' => $previousName, 75 ], 76 ]); 77 } 78 79 public static function logUserAdd(?User $actor, User $user, Group $group, ?array $playmodes = null): void 80 { 81 // Never log additions to the default group 82 if ($group->identifier === 'default') { 83 return; 84 } 85 86 if (empty($playmodes)) { 87 $playmodes = null; 88 } 89 90 static::log($actor, static::USER_ADD, $user, $group, [ 91 'details' => compact('playmodes'), 92 ]); 93 } 94 95 public static function logUserAddPlaymodes(?User $actor, User $user, Group $group, array $playmodes): void 96 { 97 if (empty($playmodes)) { 98 throw new InvalidArgumentException('playmodes must not be empty'); 99 } 100 101 static::log($actor, static::USER_ADD_PLAYMODES, $user, $group, [ 102 'details' => compact('playmodes'), 103 ]); 104 } 105 106 public static function logUserRemove(?User $actor, User $user, Group $group): void 107 { 108 static::log($actor, static::USER_REMOVE, $user, $group); 109 } 110 111 public static function logUserRemovePlaymodes(?User $actor, User $user, Group $group, array $playmodes): void 112 { 113 if (empty($playmodes)) { 114 throw new InvalidArgumentException('playmodes must not be empty'); 115 } 116 117 static::log($actor, static::USER_REMOVE_PLAYMODES, $user, $group, [ 118 'details' => compact('playmodes'), 119 ]); 120 } 121 122 public static function logUserSetDefault(?User $actor, User $user, Group $group): void 123 { 124 static::log($actor, static::USER_SET_DEFAULT, $user, $group); 125 } 126 127 private static function log(?User $actor, string $type, ?User $user, Group $group, array $attributes = []): void 128 { 129 $attributes['details'] = array_merge( 130 [ 131 'actor_name' => $actor?->username, 132 'group_name' => $group->group_name, 133 'user_name' => $user?->username, 134 ], 135 $attributes['details'] ?? [], 136 ); 137 138 (new static(array_merge( 139 [ 140 'actor_id' => $actor?->getKey(), 141 'group_id' => $group->getKey(), 142 'hidden' => !$group->hasListing(), 143 'type' => $type, 144 'user_id' => $user?->getKey(), 145 ], 146 $attributes, 147 )))->saveOrExplode(); 148 } 149 150 public function actor(): BelongsTo 151 { 152 return $this->belongsTo(User::class, 'actor_id'); 153 } 154 155 public function group(): BelongsTo 156 { 157 return $this->belongsTo(Group::class, 'group_id'); 158 } 159 160 public function user(): BelongsTo 161 { 162 return $this->belongsTo(User::class, 'user_id'); 163 } 164 165 public function scopeVisibleForUser(Builder $query, ?User $user): void 166 { 167 if (priv_check_user($user, 'UserGroupEventShowAll')->can()) { 168 return; 169 } 170 171 $query->where('hidden', false); 172 173 $userGroupIds = priv_check_user($user, 'IsSpecialScope')->can() 174 ? $user->groupIds()['active'] 175 : []; 176 177 if (!empty($userGroupIds)) { 178 $query->orWhereIn('group_id', $userGroupIds); 179 } 180 } 181 182 public function getAttribute($key) 183 { 184 return match ($key) { 185 'actor_id', 186 'group_id', 187 'id', 188 'type', 189 'user_id' => $this->getRawAttribute($key), 190 191 'details' => json_decode($this->getRawAttribute($key), true), 192 193 'created_at' => $this->getTimeFast($key), 194 195 'created_at_json' => $this->getJsonTimeFast($key), 196 197 'actor', 198 'user' => $this->getRelationValue($key), 199 200 'group' => app('groups')->byIdOrFail($this->getRawAttribute('group_id')), 201 }; 202 } 203 204 // Laravel has own hidden property 205 // TODO: https://github.com/ppy/osu-web/pull/9486#discussion_r1017831112 206 public function isHidden(): bool 207 { 208 return (bool) $this->getRawAttribute('hidden'); 209 } 210}