the browser-facing portion of osu!
at master 5.5 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 6namespace App\Models; 7 8use App\Exceptions\InvariantException; 9use App\Models\Chat\Channel; 10use App\Models\Forum\Topic; 11 12/** 13 * @property \Carbon\Carbon|null $created_at 14 * @property string $category 15 * @property array|null $details 16 * @property int $id 17 * @property Model $notifiable 18 * @property string $notifiable_type 19 * @property int $notifiable_id 20 * @property int $priority 21 * @property User|null $source 22 * @property int|null $source_user_id 23 * @property string $name 24 * @property \Carbon\Carbon|null $updated_at 25 * @property \Illuminate\Database\Eloquent\Collection $userNotifications UserNotification 26 */ 27class Notification extends Model 28{ 29 const BEATMAP_OWNER_CHANGE = 'beatmap_owner_change'; 30 const BEATMAPSET_DISCUSSION_LOCK = 'beatmapset_discussion_lock'; 31 const BEATMAPSET_DISCUSSION_POST_NEW = 'beatmapset_discussion_post_new'; 32 const BEATMAPSET_DISCUSSION_QUALIFIED_PROBLEM = 'beatmapset_discussion_qualified_problem'; 33 const BEATMAPSET_DISCUSSION_REVIEW_NEW = 'beatmapset_discussion_review_new'; 34 const BEATMAPSET_DISCUSSION_UNLOCK = 'beatmapset_discussion_unlock'; 35 const BEATMAPSET_DISQUALIFY = 'beatmapset_disqualify'; 36 const BEATMAPSET_LOVE = 'beatmapset_love'; 37 const BEATMAPSET_NOMINATE = 'beatmapset_nominate'; 38 const BEATMAPSET_QUALIFY = 'beatmapset_qualify'; 39 const BEATMAPSET_RANK = 'beatmapset_rank'; 40 const BEATMAPSET_REMOVE_FROM_LOVED = 'beatmapset_remove_from_loved'; 41 const BEATMAPSET_RESET_NOMINATIONS = 'beatmapset_reset_nominations'; 42 const CHANNEL_ANNOUNCEMENT = 'channel_announcement'; 43 const CHANNEL_MESSAGE = 'channel_message'; 44 const COMMENT_NEW = 'comment_new'; 45 const FORUM_TOPIC_REPLY = 'forum_topic_reply'; 46 const USER_ACHIEVEMENT_UNLOCK = 'user_achievement_unlock'; 47 const USER_BEATMAPSET_NEW = 'user_beatmapset_new'; 48 const USER_BEATMAPSET_REVIVE = 'user_beatmapset_revive'; 49 50 const NAME_TO_CATEGORY = [ 51 self::BEATMAP_OWNER_CHANGE => 'beatmap_owner_change', 52 self::BEATMAPSET_DISCUSSION_LOCK => 'beatmapset_discussion', 53 self::BEATMAPSET_DISCUSSION_POST_NEW => 'beatmapset_discussion', 54 self::BEATMAPSET_DISCUSSION_QUALIFIED_PROBLEM => 'beatmapset_problem', 55 self::BEATMAPSET_DISCUSSION_REVIEW_NEW => 'beatmapset_discussion', 56 self::BEATMAPSET_DISCUSSION_UNLOCK => 'beatmapset_discussion', 57 self::BEATMAPSET_DISQUALIFY => 'beatmapset_state', 58 self::BEATMAPSET_LOVE => 'beatmapset_state', 59 self::BEATMAPSET_NOMINATE => 'beatmapset_state', 60 self::BEATMAPSET_QUALIFY => 'beatmapset_state', 61 self::BEATMAPSET_RANK => 'beatmapset_state', 62 self::BEATMAPSET_REMOVE_FROM_LOVED => 'beatmapset_state', 63 self::BEATMAPSET_RESET_NOMINATIONS => 'beatmapset_state', 64 self::CHANNEL_ANNOUNCEMENT => 'announcement', 65 self::CHANNEL_MESSAGE => 'channel', 66 self::COMMENT_NEW => 'comment', 67 self::FORUM_TOPIC_REPLY => 'forum_topic_reply', 68 self::USER_ACHIEVEMENT_UNLOCK => 'user_achievement_unlock', 69 self::USER_BEATMAPSET_NEW => 'user_beatmapset_new', 70 self::USER_BEATMAPSET_REVIVE => 'user_beatmapset_new', 71 ]; 72 73 const NOTIFIABLE_CLASSES = [ 74 Beatmapset::class, 75 Build::class, 76 Channel::class, 77 Topic::class, 78 NewsPost::class, 79 User::class, 80 ]; 81 82 const SUBTYPES = [ 83 self::COMMENT_NEW => 'comment', 84 self::USER_BEATMAPSET_NEW => 'mapping', 85 ]; 86 87 protected $casts = [ 88 'details' => 'array', 89 ]; 90 91 public static function namesInCategory($category) 92 { 93 static $categories = []; 94 95 if ($categories === []) { 96 foreach (static::NAME_TO_CATEGORY as $key => $value) { 97 if (!array_key_exists($value, $categories)) { 98 $categories[$value] = []; 99 } 100 101 $categories[$value][] = $key; 102 } 103 } 104 105 return $categories[$category] ?? [$category]; 106 } 107 108 public function scopeByIdentity($query, array $params) 109 { 110 $category = $params['category'] ?? null; 111 $objectId = $params['object_id'] ?? null; 112 $objectType = $params['object_type'] ?? null; 113 114 if ($objectType !== null) { 115 $query->where('notifiable_type', $objectType); 116 } 117 118 if ($objectId !== null && $category !== null) { 119 if ($objectType === null) { 120 throw new InvariantException('object_type is required.'); 121 } 122 123 $names = Notification::namesInCategory($category); 124 $query 125 ->where('notifiable_id', $objectId) 126 ->whereIn('name', $names); 127 } 128 129 return $query; 130 } 131 132 public function getCategoryAttribute() 133 { 134 return static::NAME_TO_CATEGORY[$this->name] ?? $this->name; 135 } 136 137 public function notifiable() 138 { 139 return $this->morphTo(); 140 } 141 142 public function source() 143 { 144 return $this->belongsTo(User::class); 145 } 146 147 public function toIdentityJson() 148 { 149 return [ 150 'category' => $this->category, 151 'id' => $this->getKey(), 152 'object_id' => $this->notifiable_id, 153 'object_type' => $this->notifiable_type, 154 ]; 155 } 156 157 public function userNotifications() 158 { 159 return $this->hasMany(UserNotification::class); 160 } 161}