Merge branch '5.2' into 5.3
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / worker / UserRebuildDataWorker.class.php
CommitLineData
e3667539
MW
1<?php
2namespace wcf\system\worker;
557115b5 3use wcf\data\reaction\type\ReactionTypeCache;
2772d4eb
MW
4use wcf\data\user\avatar\UserAvatar;
5use wcf\data\user\avatar\UserAvatarEditor;
6use wcf\data\user\avatar\UserAvatarList;
8a413435 7use wcf\data\user\User;
e3667539 8use wcf\data\user\UserEditor;
157054c9 9use wcf\data\user\UserList;
e3667539 10use wcf\data\user\UserProfileAction;
7e058783 11use wcf\system\bbcode\BBCodeHandler;
e3667539 12use wcf\system\database\util\PreparedStatementConditionBuilder;
c5c9e424 13use wcf\system\exception\SystemException;
b8c48208 14use wcf\system\html\input\HtmlInputProcessor;
2772d4eb 15use wcf\system\image\ImageHandler;
e3667539
MW
16use wcf\system\WCF;
17
18/**
19 * Worker implementation for updating users.
20 *
21 * @author Marcel Werk
7b7b9764 22 * @copyright 2001-2019 WoltLab GmbH
e3667539 23 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
e71525e4 24 * @package WoltLabSuite\Core\System\Worker
bbd89532
MS
25 *
26 * @method UserList getObjectList()
e3667539
MW
27 */
28class UserRebuildDataWorker extends AbstractRebuildDataWorker {
29 /**
0fcfe5f6 30 * @inheritDoc
e3667539 31 */
157054c9 32 protected $objectListClassName = UserList::class;
e3667539
MW
33
34 /**
0fcfe5f6 35 * @inheritDoc
e3667539
MW
36 */
37 protected $limit = 50;
38
39 /**
0fcfe5f6 40 * @inheritDoc
e3667539
MW
41 */
42 protected function initObjectList() {
43 parent::initObjectList();
44
8a413435
AE
45 $this->objectList->sqlSelects = 'user_option_value.userOption' . User::getUserOptionID('aboutMe') . ' AS aboutMe';
46 $this->objectList->sqlJoins = "LEFT JOIN wcf".WCF_N."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
e3667539
MW
47 $this->objectList->sqlOrderBy = 'user_table.userID';
48 }
49
50 /**
0fcfe5f6 51 * @inheritDoc
e3667539
MW
52 */
53 public function execute() {
54 parent::execute();
55
058cbd6a 56 $users = $userIDs = [];
e3667539
MW
57 foreach ($this->getObjectList() as $user) {
58 $users[] = new UserEditor($user);
59 $userIDs[] = $user->userID;
60 }
61
62 // update user ranks
63 if (!empty($users)) {
64 $action = new UserProfileAction($users, 'updateUserOnlineMarking');
65 $action->executeAction();
66 }
67
68 if (!empty($userIDs)) {
bd1067ab
AE
69 // update article counter
70 $conditionBuilder = new PreparedStatementConditionBuilder();
71 $conditionBuilder->add('user_table.userID IN (?)', [$userIDs]);
72 $sql = "UPDATE wcf".WCF_N."_user user_table
73 SET articles = (
74 SELECT COUNT(*)
75 FROM wcf".WCF_N."_article
76 WHERE userID = user_table.userID
77 )
78 ".$conditionBuilder;
79 $statement = WCF::getDB()->prepareStatement($sql);
80 $statement->execute($conditionBuilder->getParameters());
81
e3667539
MW
82 // update like counter
83 if (MODULE_LIKE) {
557115b5 84 $sql = "UPDATE wcf".WCF_N."_user user_table SET";
25f91a2f 85
1626fe3e 86 $reactionTypeIDs = array_keys(ReactionTypeCache::getInstance()->getReactionTypes());
25f91a2f 87 if (!empty($reactionTypeIDs)) {
557115b5 88 $sql .= " likesReceived = (
e3667539
MW
89 SELECT COUNT(*)
90 FROM wcf".WCF_N."_like
91 WHERE objectUserID = user_table.userID
25f91a2f
AE
92 AND reactionTypeID IN (". implode(',', $reactionTypeIDs) .")
93 )";
557115b5
JR
94 }
95 else {
25f91a2f 96 $sql .= " likesReceived = 0";
557115b5
JR
97 }
98
557115b5 99 $sql .= " ".$conditionBuilder;
e3667539
MW
100 $statement = WCF::getDB()->prepareStatement($sql);
101 $statement->execute($conditionBuilder->getParameters());
102 }
2772d4eb 103
85f59bb3
JR
104 // update trophy points
105 if (MODULE_TROPHY) {
85f59bb3
JR
106 $sql = "UPDATE wcf".WCF_N."_user user_table
107 SET trophyPoints = (
108 SELECT COUNT(*)
109 FROM wcf".WCF_N."_user_trophy user_trophy
110 LEFT JOIN wcf".WCF_N."_trophy trophy ON user_trophy.trophyID = trophy.trophyID
111 LEFT JOIN wcf".WCF_N."_category trophy_category ON trophy.categoryID = trophy_category.categoryID
112 WHERE user_trophy.userID = user_table.userID
113 AND trophy.isDisabled = 0
114 AND trophy_category.isDisabled = 0
115 )
116 ".$conditionBuilder;
117 $statement = WCF::getDB()->prepareStatement($sql);
118 $statement->execute($conditionBuilder->getParameters());
119 }
120
8a413435
AE
121 // update signatures and about me
122 $sql = "UPDATE wcf".WCF_N."_user_option_value
123 SET userOption" . User::getUserOptionID('aboutMe') . " = ?
124 WHERE userID = ?";
125 $statement = WCF::getDB()->prepareStatement($sql);
126
7e058783
AE
127 // retrieve permissions
128 $userIDs = [];
129 foreach ($users as $user) {
130 $userIDs[] = $user->userID;
131 }
132 $userPermissions = $this->getBulkUserPermissions($userIDs, ['user.message.disallowedBBCodes', 'user.signature.disallowedBBCodes']);
133
b8c48208
AE
134 $htmlInputProcessor = new HtmlInputProcessor();
135 WCF::getDB()->beginTransaction();
136 /** @var UserEditor $user */
137 foreach ($users as $user) {
7e058783
AE
138 BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', $this->getBulkUserPermissionValue($userPermissions, $user->userID, 'user.signature.disallowedBBCodes')));
139
b8c48208
AE
140 if (!$user->signatureEnableHtml) {
141 $htmlInputProcessor->process($user->signature, 'com.woltlab.wcf.user.signature', $user->userID, true);
142
143 $user->update([
144 'signature' => $htmlInputProcessor->getHtml(),
145 'signatureEnableHtml' => 1
146 ]);
13825b39
AE
147 }
148 else {
149 $htmlInputProcessor->reprocess($user->signature, 'com.woltlab.wcf.user.signature', $user->userID);
150 $user->update(['signature' => $htmlInputProcessor->getHtml()]);
151 }
152
153 if ($user->aboutMe) {
7e058783
AE
154 BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', $this->getBulkUserPermissionValue($userPermissions, $user->userID, 'user.message.disallowedBBCodes')));
155
13825b39 156 if (!$user->signatureEnableHtml) {
8a413435 157 $htmlInputProcessor->process($user->aboutMe, 'com.woltlab.wcf.user.aboutMe', $user->userID, true);
8a413435 158 }
13825b39
AE
159 else {
160 $htmlInputProcessor->reprocess($user->aboutMe, 'com.woltlab.wcf.user.aboutMe', $user->userID);
161 }
162
163 $html = $htmlInputProcessor->getHtml();
164 // MySQL's TEXT type allows for 65,535 bytes, hence we need to count
165 // the bytes rather than the actual amount of characters
166 if (strlen($html) > 65535) {
167 // content does not fit the available space, and any
168 // attempts to truncate it will yield awkward results
169 $html = '';
170 }
171
172 $statement->execute([$html, $user->userID]);
b8c48208
AE
173 }
174 }
175 WCF::getDB()->commitTransaction();
176
bbabc452 177 // update old/imported avatars
2772d4eb
MW
178 $avatarList = new UserAvatarList();
179 $avatarList->getConditionBuilder()->add('user_avatar.userID IN (?)', [$userIDs]);
180 $avatarList->getConditionBuilder()->add('(user_avatar.width <> ? OR user_avatar.height <> ?)', [UserAvatar::AVATAR_SIZE, UserAvatar::AVATAR_SIZE]);
181 $avatarList->readObjects();
182 foreach ($avatarList as $avatar) {
1fe8a30f
AE
183 $editor = new UserAvatarEditor($avatar);
184 if (!file_exists($avatar->getLocation()) || @getimagesize($avatar->getLocation()) === false) {
185 // delete avatars that are missing or broken
186 $editor->delete();
187 continue;
188 }
189
2772d4eb
MW
190 $width = $avatar->width;
191 $height = $avatar->height;
192 if ($width != $height) {
bbabc452 193 // make avatar quadratic
2772d4eb
MW
194 $width = $height = min($width, $height, UserAvatar::AVATAR_SIZE);
195 $adapter = ImageHandler::getInstance()->getAdapter();
c5c9e424
AE
196
197 try {
198 $adapter->loadFile($avatar->getLocation());
199 }
200 catch (SystemException $e) {
201 // broken image
202 $editor->delete();
203 continue;
204 }
205
2772d4eb
MW
206 $thumbnail = $adapter->createThumbnail($width, $height, false);
207 $adapter->writeImage($thumbnail, $avatar->getLocation());
99397679
TD
208 // Clear thumbnail as soon as possible to free up the memory.
209 $thumbnail = null;
2772d4eb
MW
210 }
211
bbabc452
MW
212 if ($width != UserAvatar::AVATAR_SIZE || $height != UserAvatar::AVATAR_SIZE) {
213 // resize avatar
3461e167 214 $adapter = ImageHandler::getInstance()->getAdapter();
c5c9e424
AE
215
216 try {
217 $adapter->loadFile($avatar->getLocation());
218 }
219 catch (SystemException $e) {
220 // broken image
221 $editor->delete();
222 continue;
223 }
224
3461e167
MW
225 $adapter->resize(0, 0, $width, $height, UserAvatar::AVATAR_SIZE, UserAvatar::AVATAR_SIZE);
226 $adapter->writeImage($adapter->getImage(), $avatar->getLocation());
227 $width = $height = UserAvatar::AVATAR_SIZE;
2772d4eb
MW
228 }
229
2772d4eb 230 $editor->update([
3461e167
MW
231 'width' => $width,
232 'height' => $height
2772d4eb
MW
233 ]);
234 }
e3667539
MW
235 }
236 }
237}