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\Libraries\Transactions\AfterCommit;
9
10/**
11 * @property string|null $colour
12 * @property int $display_order
13 * @property string $group_avatar
14 * @property int $group_avatar_height
15 * @property int $group_avatar_type
16 * @property int $group_avatar_width
17 * @property string $group_colour
18 * @property string|null $group_desc
19 * @property string $group_desc_bitfield
20 * @property int $group_desc_options
21 * @property string $group_desc_uid
22 * @property int $group_display
23 * @property int $group_founder_manage
24 * @property int $group_id
25 * @property int $group_legend
26 * @property int $group_message_limit
27 * @property string $group_name
28 * @property int $group_rank
29 * @property int $group_receive_pm
30 * @property int $group_sig_chars
31 * @property int $group_type
32 * @property bool $has_playmodes
33 * @property string $identifier
34 * @property string $short_name
35 */
36class Group extends Model implements AfterCommit
37{
38 // Identifier of groups which involved in permission checks
39 // and assumed to always exist in database.
40 const PRIV_IDENTIFIERS = [
41 'admin',
42 'alumni',
43 'announce',
44 'bng',
45 'bng_limited',
46 'bot',
47 'default',
48 'dev',
49 'gmt',
50 'loved',
51 'nat',
52 'no_profile',
53 ];
54
55 public $timestamps = false;
56
57 protected $casts = [
58 'has_playmodes' => 'boolean',
59 ];
60 protected $primaryKey = 'group_id';
61 protected $table = 'phpbb_groups';
62
63 public function getAttribute($key)
64 {
65 return match ($key) {
66 'display_order',
67 'group_avatar',
68 'group_avatar_height',
69 'group_avatar_type',
70 'group_avatar_width',
71 'group_colour',
72 'group_desc_bitfield',
73 'group_desc_options',
74 'group_desc_uid',
75 'group_display',
76 'group_founder_manage',
77 'group_id',
78 'group_legend',
79 'group_message_limit',
80 'group_name',
81 'group_rank',
82 'group_receive_pm',
83 'group_sig_chars',
84 'group_type',
85 'identifier',
86 'short_name' => $this->getRawAttribute($key),
87
88 'has_playmodes' => (bool) $this->getRawAttribute($key),
89
90 'colour' => $this->getColour(),
91
92 'group_desc' => presence($this->getRawAttribute($key)),
93 };
94 }
95
96 public function descriptionHtml(): ?string
97 {
98 return $this->group_desc === null ? null : markdown($this->group_desc, 'group');
99 }
100
101 public function hasBadge(): bool
102 {
103 return $this->display_order !== null;
104 }
105
106 public function hasListing(): bool
107 {
108 return $this->group_type === 1;
109 }
110
111 public function isProbationary(): bool
112 {
113 // TODO: move this to a DB field or something if other groups end up needing 'probation'
114 return $this->identifier === 'bng_limited';
115 }
116
117 public function users()
118 {
119 // 'cuz hasManyThrough is derp
120 $userIds = UserGroup::where('group_id', $this->group_id)->pluck('user_id');
121
122 return User::whereIn('user_id', $userIds);
123 }
124
125 public function rename(string $name, ?User $actor = null): void
126 {
127 if ($this->group_name === $name) {
128 return;
129 }
130
131 $this->getConnection()->transaction(function () use ($actor, $name) {
132 UserGroupEvent::logGroupRename($actor, $this, $this->group_name, $name);
133 $this->update(['group_name' => $name]);
134 });
135 }
136
137 public function afterCommit()
138 {
139 app('groups')->resetMemoized();
140 }
141
142 private function getColour(): ?string
143 {
144 $value = $this->getRawAttribute('colour');
145
146 return $value === null ? null : "#{$value}";
147 }
148}