Split additional joins into multiple lines
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / user / trophy / UserTrophyAction.class.php
1 <?php
2
3 namespace wcf\data\user\trophy;
4
5 use wcf\data\AbstractDatabaseObjectAction;
6 use wcf\data\user\UserAction;
7 use wcf\data\user\UserProfile;
8 use wcf\data\user\UserProfileAction;
9 use wcf\system\cache\runtime\UserProfileRuntimeCache;
10 use wcf\system\database\util\PreparedStatementConditionBuilder;
11 use wcf\system\exception\IllegalLinkException;
12 use wcf\system\exception\PermissionDeniedException;
13 use wcf\system\user\activity\event\UserActivityEventHandler;
14 use wcf\system\user\notification\object\UserTrophyNotificationObject;
15 use wcf\system\user\notification\UserNotificationHandler;
16 use wcf\system\user\storage\UserStorageHandler;
17 use wcf\system\WCF;
18
19 /**
20 * Provides user trophy actions.
21 *
22 * @author Joshua Ruesweg
23 * @copyright 2001-2019 WoltLab GmbH
24 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
25 * @package WoltLabSuite\Core\Data\User\Trophy
26 * @since 3.1
27 *
28 * @method UserTrophyEditor[] getObjects()
29 * @method UserTrophyEditor getSingleObject()
30 */
31 class UserTrophyAction extends AbstractDatabaseObjectAction
32 {
33 /**
34 * @inheritDoc
35 */
36 protected $permissionsDelete = ['admin.trophy.canAwardTrophy'];
37
38 /**
39 * @inheritDoc
40 */
41 protected $allowGuestAccess = ['getGroupedUserTrophyList'];
42
43 /**
44 * @var UserProfile
45 */
46 public $userProfile;
47
48 /**
49 * @inheritDoc
50 */
51 public function create()
52 {
53 /** @var UserTrophy $userTrophy */
54 $userTrophy = parent::create();
55
56 if (!$userTrophy->getTrophy()->isDisabled()) {
57 $userAction = new UserAction([$userTrophy->userID], 'update', [
58 'counters' => [
59 'trophyPoints' => 1,
60 ],
61 ]);
62 $userAction->executeAction();
63
64 // checks if the user still has space to add special trophies
65 if (\count($userTrophy->getUserProfile()->getSpecialTrophies()) < $userTrophy->getUserProfile()->getPermission('user.profile.trophy.maxUserSpecialTrophies')) {
66 $hasTrophy = false;
67 foreach (UserTrophyList::getUserTrophies([$userTrophy->getUserProfile()->userID])[$userTrophy->getUserProfile()->userID] as $trophy) {
68 if ($trophy->trophyID == $userTrophy->trophyID && $trophy->userTrophyID !== $userTrophy->userTrophyID) {
69 $hasTrophy = true;
70 break;
71 }
72 }
73
74 if (!$hasTrophy) {
75 $userProfileAction = new UserProfileAction(
76 [$userTrophy->getUserProfile()->getDecoratedObject()],
77 'updateSpecialTrophies',
78 [
79 'trophyIDs' => \array_unique(\array_merge(\array_map(static function ($trophy) {
80 return $trophy->trophyID;
81 }, $userTrophy->getUserProfile()->getSpecialTrophies()), [$userTrophy->trophyID])),
82 ]
83 );
84 $userProfileAction->executeAction();
85 }
86 }
87 }
88
89 UserActivityEventHandler::getInstance()->fireEvent(
90 'com.woltlab.wcf.userTrophy.recentActivityEvent.trophyReceived',
91 $userTrophy->getObjectID(),
92 null,
93 $userTrophy->userID
94 );
95
96 UserNotificationHandler::getInstance()->fireEvent(
97 'received',
98 'com.woltlab.wcf.userTrophy.notification',
99 new UserTrophyNotificationObject($userTrophy),
100 [
101 $userTrophy->userID,
102 ]
103 );
104
105 return $userTrophy;
106 }
107
108 /**
109 * @inheritDoc
110 */
111 public function validateDelete()
112 {
113 parent::validateDelete();
114
115 /** @var UserTrophy $object */
116 foreach ($this->objects as $object) {
117 if ($object->getTrophy()->awardAutomatically) {
118 throw new PermissionDeniedException();
119 }
120 }
121 }
122
123 /**
124 * @inheritDoc
125 */
126 public function delete()
127 {
128 if (empty($this->objects)) {
129 $this->readObjects();
130 }
131
132 $trophyIDs = $userIDs = [];
133 foreach ($this->getObjects() as $object) {
134 $trophyIDs[] = $object->trophyID;
135 $userIDs[] = $object->userID;
136 }
137
138 $returnValues = parent::delete();
139
140 if (!empty($this->objects)) {
141 // update user special trophies trophies
142 $userTrophies = UserTrophyList::getUserTrophies($userIDs);
143
144 foreach ($userTrophies as $userID => $trophies) {
145 $userTrophyIDs = [];
146 foreach ($trophies as $trophy) {
147 $userTrophyIDs[] = $trophy->trophyID;
148 }
149
150 $conditionBuilder = new PreparedStatementConditionBuilder();
151 if (!empty($userTrophyIDs)) {
152 $conditionBuilder->add('trophyID NOT IN (?)', [\array_unique($userTrophyIDs)]);
153 }
154 $conditionBuilder->add('userID = ?', [$userID]);
155
156 $sql = "DELETE FROM wcf" . WCF_N . "_user_special_trophy
157 " . $conditionBuilder;
158 $statement = WCF::getDB()->prepareStatement($sql);
159 $statement->execute($conditionBuilder->getParameters());
160
161 UserStorageHandler::getInstance()->reset([$userID], 'specialTrophies');
162 }
163
164 $updateUserTrophies = [];
165 foreach ($this->getObjects() as $object) {
166 if (!$object->getTrophy()->isDisabled()) {
167 if (!isset($updateUserTrophies[$object->userID])) {
168 $updateUserTrophies[$object->userID] = 0;
169 }
170 $updateUserTrophies[$object->userID]--;
171 }
172 }
173
174 foreach ($updateUserTrophies as $userID => $count) {
175 $userAction = new UserAction([$userID], 'update', [
176 'counters' => [
177 'trophyPoints' => $count,
178 ],
179 ]);
180 $userAction->executeAction();
181 }
182 }
183
184 return $returnValues;
185 }
186
187 /**
188 * Validates the getGroupedUserTrophyList method.
189 */
190 public function validateGetGroupedUserTrophyList()
191 {
192 if (!MODULE_TROPHY) {
193 throw new IllegalLinkException();
194 }
195
196 WCF::getSession()->checkPermissions(['user.profile.trophy.canSeeTrophies']);
197
198 $this->readInteger('pageNo');
199 $this->readInteger('userID');
200
201 $this->userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->parameters['userID']);
202 if (!$this->userProfile->isAccessible('canViewTrophies') && !($this->userProfile->userID == WCF::getSession()->userID)) {
203 throw new PermissionDeniedException();
204 }
205 }
206
207 /**
208 * Returns a viewable user trophy list for a specific user.
209 */
210 public function getGroupedUserTrophyList()
211 {
212 $userTrophyList = new UserTrophyList();
213 $userTrophyList->getConditionBuilder()->add('userID = ?', [$this->parameters['userID']]);
214 if (!empty($userTrophyList->sqlJoins)) {
215 $userTrophyList->sqlJoins .= ' ';
216 }
217 if (!empty($userTrophyList->sqlConditionJoins)) {
218 $userTrophyList->sqlConditionJoins .= ' ';
219 }
220 $userTrophyList->sqlJoins .= '
221 LEFT JOIN wcf' . WCF_N . '_trophy trophy
222 ON user_trophy.trophyID = trophy.trophyID';
223 $userTrophyList->sqlConditionJoins .= '
224 LEFT JOIN wcf' . WCF_N . '_trophy trophy
225 ON user_trophy.trophyID = trophy.trophyID';
226
227 // trophy category join
228 $userTrophyList->sqlJoins .= '
229 LEFT JOIN wcf' . WCF_N . '_category category
230 ON trophy.categoryID = category.categoryID';
231 $userTrophyList->sqlConditionJoins .= '
232 LEFT JOIN wcf' . WCF_N . '_category category
233 ON trophy.categoryID = category.categoryID';
234
235 $userTrophyList->getConditionBuilder()->add('trophy.isDisabled = ?', [0]);
236 $userTrophyList->getConditionBuilder()->add('category.isDisabled = ?', [0]);
237 $userTrophyList->sqlLimit = 10;
238 $userTrophyList->sqlOffset = ($this->parameters['pageNo'] - 1) * 10;
239 $userTrophyList->sqlOrderBy = 'time DESC';
240 $pageCount = \ceil($userTrophyList->countObjects() / 10);
241 $userTrophyList->readObjects();
242
243 return [
244 'pageCount' => $pageCount,
245 'title' => WCF::getLanguage()->getDynamicVariable(
246 'wcf.user.trophy.dialogTitle',
247 ['username' => $this->userProfile->username]
248 ),
249 'template' => WCF::getTPL()->fetch('groupedUserTrophyList', 'wcf', [
250 'userTrophyList' => $userTrophyList,
251 ]),
252 ];
253 }
254 }