Introduce new flag variable for email confirmation
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / importer / UserImporter.class.php
CommitLineData
78db8ddf
MW
1<?php
2namespace wcf\system\importer;
a96244e1 3use wcf\data\user\group\UserGroup;
7a23a706 4use wcf\data\user\option\UserOption;
2ec5b95d 5use wcf\data\user\option\UserOptionList;
90d1166e 6use wcf\data\user\User;
b72edcd8 7use wcf\data\user\UserEditor;
9f4e72b4 8use wcf\system\language\LanguageFactory;
78db8ddf
MW
9use wcf\system\WCF;
10
11/**
12 * Imports users.
a4dbb8ac 13 *
78db8ddf 14 * @author Marcel Werk
7b7b9764 15 * @copyright 2001-2019 WoltLab GmbH
78db8ddf 16 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
e71525e4 17 * @package WoltLabSuite\Core\System\Importer
78db8ddf 18 */
c2836ca3
MW
19class UserImporter extends AbstractImporter {
20 /**
0fcfe5f6 21 * @inheritDoc
c2836ca3 22 */
157054c9 23 protected $className = User::class;
c2836ca3 24
a96244e1 25 /**
a4dbb8ac 26 * ids of default notification events
7a23a706 27 * @var integer[]
a96244e1 28 */
058cbd6a 29 protected $eventIDs = [];
a96244e1 30
2ec5b95d
MW
31 /**
32 * list of user options
7a23a706 33 * @var UserOption[]
2ec5b95d 34 */
058cbd6a 35 protected $userOptions = [];
2ec5b95d 36
aa113020
TD
37 const MERGE_MODE_EMAIL = 4;
38 const MERGE_MODE_USERNAME_OR_EMAIL = 5;
39
a96244e1
MW
40 /**
41 * Creates a new UserImporter object.
42 */
43 public function __construct() {
a4dbb8ac
MS
44 // get default notification events
45 $sql = "SELECT eventID
46 FROM wcf".WCF_N."_user_notification_event
47 WHERE preset = ?";
48 $statement = WCF::getDB()->prepareStatement($sql);
058cbd6a 49 $statement->execute([1]);
cd975610 50 $this->eventIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
2ec5b95d
MW
51
52 $userOptionList = new UserOptionList();
53 $userOptionList->readObjects();
54 $this->userOptions = $userOptionList->getObjects();
a96244e1
MW
55 }
56
78db8ddf 57 /**
0fcfe5f6 58 * @inheritDoc
78db8ddf 59 */
058cbd6a 60 public function import($oldID, array $data, array $additionalData = []) {
e0d32362
MS
61 $targetUser = null;
62
aa113020
TD
63 // whether to perform a merge
64 $performMerge = false;
65
66 // fetch user with same username
67 $conflictingUser = User::getUserByUsername($data['username']);
68 switch (ImportHandler::getInstance()->getUserMergeMode()) {
3940dc78 69 /** @noinspection PhpMissingBreakStatementInspection */
aa113020
TD
70 case self::MERGE_MODE_USERNAME_OR_EMAIL:
71 // merge target will be the conflicting user
72 $targetUser = $conflictingUser;
73
74 // check whether user exists
75 if ($targetUser->userID) {
76 $performMerge = true;
77 break;
2df9ae32 78 }
aa113020
TD
79 case self::MERGE_MODE_EMAIL:
80 // fetch merge target
81 $targetUser = User::getUserByEmail($data['email']);
82 // if it exists: perform a merge
83 if ($targetUser->userID) $performMerge = true;
84 break;
85 }
86
87 // merge should be performed
88 if ($performMerge) {
89 ImportHandler::getInstance()->saveNewID('com.woltlab.wcf.user', $oldID, $targetUser->userID);
90 return 0;
91 }
92
93 // a conflict arose, but no merge was performed, resolve
94 if ($conflictingUser->userID) {
95 // rename user
96 $data['username'] = self::resolveDuplicate($data['username']);
2df9ae32 97 }
187c9504 98
90d1166e 99 // check existing user id
b2f00d92 100 if (ctype_digit((string)$oldID)) {
d58f9cdf
MW
101 $user = new User($oldID);
102 if (!$user->userID) $data['userID'] = $oldID;
103 }
78db8ddf 104
90d1166e 105 // handle user options
058cbd6a 106 $userOptions = [];
6eb1d790
MW
107 if (isset($additionalData['options'])) {
108 foreach ($additionalData['options'] as $optionName => $optionValue) {
90d1166e
MW
109 if (is_int($optionName)) $optionID = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.user.option', $optionName);
110 else $optionID = User::getUserOptionID($optionName);
111
112 if ($optionID) {
113 $userOptions[$optionID] = $optionValue;
114 }
115 }
2ec5b95d
MW
116
117 // fix option values
118 foreach ($userOptions as $optionID => &$optionValue) {
119 switch ($this->userOptions[$optionID]->optionType) {
120 case 'boolean':
121 if ($optionValue) $optionValue = 1;
122 else $optionValue = 0;
123 break;
124
125 case 'integer':
126 $optionValue = intval($optionValue);
127 if ($optionValue > 2147483647) $optionValue = 2147483647;
128 break;
129
130 case 'float':
131 $optionValue = floatval($optionValue);
132 break;
133
134 case 'textarea':
135 if (strlen($optionValue) > 16777215) $optionValue = substr($optionValue, 0, 16777215);
136 break;
137
138 case 'birthday':
139 case 'date':
140 if (!preg_match('/^\d{4}\-\d{2}\-\d{2}$/', $optionValue)) $optionValue = '0000-00-00';
141 break;
142
143 default:
144 if (strlen($optionValue) > 65535) $optionValue = substr($optionValue, 0, 65535);
145 }
146 }
90d1166e
MW
147 }
148
058cbd6a 149 $languageIDs = [];
09f88236
TD
150 if (isset($additionalData['languages'])) {
151 foreach ($additionalData['languages'] as $languageCode) {
152 $language = LanguageFactory::getInstance()->getLanguageByCode($languageCode);
153 if ($language !== null) $languageIDs[] = $language->languageID;
154 }
155 }
156 if (empty($languageIDs)) {
157 $languageIDs[] = LanguageFactory::getInstance()->getDefaultLanguageID();
158 }
159
160 // assign an interface language
161 $data['languageID'] = reset($languageIDs);
162
90d1166e 163 // create user
a96244e1
MW
164 $user = UserEditor::create($data);
165 $userEditor = new UserEditor($user);
166
167 // updates user options
168 $userEditor->updateUserOptions($userOptions);
169
a4dbb8ac 170 // save user groups
058cbd6a 171 $groupIDs = [];
a4dbb8ac
MS
172 if (isset($additionalData['groupIDs'])) {
173 foreach ($additionalData['groupIDs'] as $oldGroupID) {
174 $newGroupID = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.user.group', $oldGroupID);
175 if ($newGroupID) $groupIDs[] = $newGroupID;
176 }
177 }
a96244e1 178
783b8dda 179 if ($user->isActivated()) $defaultGroupIDs = UserGroup::getGroupIDsByType([UserGroup::EVERYONE, UserGroup::USERS]);
058cbd6a 180 else $defaultGroupIDs = UserGroup::getGroupIDsByType([UserGroup::EVERYONE, UserGroup::GUESTS]);
8c8596be
MW
181
182 $groupIDs = array_merge($groupIDs, $defaultGroupIDs);
a96244e1
MW
183 $sql = "INSERT IGNORE INTO wcf".WCF_N."_user_to_group
184 (userID, groupID)
185 VALUES (?, ?)";
186 $statement = WCF::getDB()->prepareStatement($sql);
a7d39b16 187 WCF::getDB()->beginTransaction();
a4dbb8ac 188 foreach ($groupIDs as $groupID) {
058cbd6a 189 $statement->execute([
a4dbb8ac
MS
190 $user->userID,
191 $groupID
058cbd6a 192 ]);
a96244e1 193 }
a7d39b16 194 WCF::getDB()->commitTransaction();
a96244e1
MW
195
196 // save languages
197 $sql = "INSERT IGNORE INTO wcf".WCF_N."_user_to_language
198 (userID, languageID)
199 VALUES (?, ?)";
200 $statement = WCF::getDB()->prepareStatement($sql);
a4dbb8ac 201 foreach ($languageIDs as $languageID) {
058cbd6a 202 $statement->execute([
a4dbb8ac
MS
203 $user->userID,
204 $languageID
058cbd6a 205 ]);
a96244e1
MW
206 }
207
a4dbb8ac 208 // save default user events
a96244e1
MW
209 $sql = "INSERT IGNORE INTO wcf".WCF_N."_user_notification_event_to_user
210 (userID, eventID)
211 VALUES (?, ?)";
212 $statement = WCF::getDB()->prepareStatement($sql);
a7d39b16 213 WCF::getDB()->beginTransaction();
a4dbb8ac 214 foreach ($this->eventIDs as $eventID) {
058cbd6a 215 $statement->execute([
a4dbb8ac
MS
216 $user->userID,
217 $eventID
058cbd6a 218 ]);
a96244e1 219 }
a7d39b16 220 WCF::getDB()->commitTransaction();
78db8ddf 221
a4dbb8ac
MS
222 // save mapping
223 ImportHandler::getInstance()->saveNewID('com.woltlab.wcf.user', $oldID, $user->userID);
224
225 return $user->userID;
78db8ddf 226 }
187c9504
MW
227
228 /**
06355ec3 229 * Revolves duplicate user names and returns the new user name.
a4dbb8ac 230 *
187c9504 231 * @param string $username
06355ec3 232 * @return string
187c9504
MW
233 */
234 private static function resolveDuplicate($username) {
235 $i = 0;
187c9504
MW
236 do {
237 $i++;
238 $newUsername = 'Duplicate'.($i > 1 ? $i : '').' '.$username;
239 // try username
240 $sql = "SELECT userID
241 FROM wcf".WCF_N."_user
242 WHERE username = ?";
243 $statement = WCF::getDB()->prepareStatement($sql);
058cbd6a 244 $statement->execute([$newUsername]);
187c9504
MW
245 $row = $statement->fetchArray();
246 if (empty($row['userID'])) break;
247 }
248 while (true);
a4dbb8ac 249
187c9504
MW
250 return $newUsername;
251 }
78db8ddf 252}