PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.8.1
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.8.1
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / Modules / Migrations / Http / Controllers / BPMigrationController.php

BPMigrationController.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.8.1, at Modules/Migrations/Http/Controllers/BPMigrationController.php

352 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\Modules\Migrations\Http\Controllers;
4
5 use FluentCommunity\App\Functions\Utility;
6 use FluentCommunity\App\Http\Controllers\Controller;
7 use FluentCommunity\App\Models\User;
8 use FluentCommunity\App\Services\Helper;
9 use FluentCommunity\Framework\Http\Request\Request;
10 use FluentCommunity\Framework\Support\Arr;
11 use FluentCommunity\Modules\Migrations\Helpers\BPMigratorHelper;
12
13 class BPMigrationController extends Controller
14 {
15 protected $timeLimit = 40;
16
17 protected $startTimeStamp = 0;
18
19 public function getMigrationConfig(Request $request)
20 {
21 $previousConfig = $this->getCurrentStatus();
22
23 $groups = [];
24 $hasGroups = bp_is_active('groups');
25
26 if ($hasGroups) {
27 $groups = fluentCommunityApp('db')->table('bp_groups')->select('id', 'name')->get();
28 foreach ($groups as $group) {
29 $group->members_count = fluentCommunityApp('db')->table('bp_groups_members')->where('group_id', $group->id)->count();
30 $group->is_migrated = isset($previousConfig['migrated_groups'][$group->id]);
31 }
32 }
33
34 $data = [
35 'groupItems' => $groups,
36 'featureConfig' => [
37 'has_groups' => $hasGroups
38 ],
39 'stats' => BPMigratorHelper::getBbDataStats(),
40 'current_status' => $previousConfig,
41 'has_previous' => !empty($previousConfig['migrated_groups']) || !empty($previousConfig['last_migrated_user_id'])
42 ];
43
44 return $data;
45 }
46
47 public function startMigration(Request $request)
48 {
49 // Validate the destructive confirmation before mutating anything, so a rejected request
50 // never clears saved migration progress.
51 if ($request->get('delete_current_data') === 'yes' && $request->get('delete_current_data_confirmation') !== 'DELETE') {
52 return $this->sendError([
53 // translators: %s is the confirmation word the user must type (DELETE)
54 'message' => sprintf(__('Please type %s to confirm permanently removing all existing FluentCommunity data.', 'fluent-community'), 'DELETE')
55 ]);
56 }
57
58 if ($request->get('reset_migration') === 'yes') {
59 update_option('_fcom_bp_migrations_status', [], false);
60 }
61
62 if ($request->get('delete_current_data') === 'yes') {
63 $this->deleteCurrentData();
64 }
65
66 $configMap = (array)$request->get('config', []);
67 $prevStatus = $this->getCurrentStatus();
68
69 if (bp_is_active('groups')) {
70 $groups = fluentCommunityApp('db')->table('bp_groups')->get();
71 if ($groups) {
72 foreach ($groups as $group) {
73 if (!empty($configMap[$group->id])) {
74 $group->space_menu_id = $configMap[$group->id];
75 }
76 }
77
78 $createdMaps = $this->migrateGroups($groups);
79 $prevStatus['migrated_groups'] = $createdMaps;
80 }
81 $prevStatus['current_stage'] = 'group_members';
82 } else {
83 $prevStatus['current_stage'] = 'posts';
84 }
85
86 BPMigratorHelper::maybeEnableFollowersModule();
87
88 $status = $this->updateCurrentStatus($prevStatus);
89
90 return [
91 'current_status' => $status,
92 'max_ids' => [
93 'group_member_max' => fluentCommunityApp('db')->table('bp_groups_members')->max('id'),
94 'max_user_id' => fluentCommunityApp('db')->table('bp_xprofile_data')->count('user_id'),
95 'max_activity_id' => fluentCommunityApp('db')->table('bp_activity')->max('id')
96 ]
97 ];
98 }
99
100 public function getPollingStatus()
101 {
102 $this->timeLimit = Utility::getMaxRunTime();
103 $this->startTimeStamp = time();
104
105 $status = $this->getCurrentStatus();
106 $currentStep = Arr::get($status, 'current_stage', 'groups');
107
108 $validStages = ['group_members', 'posts', 'users', 'completed'];
109
110 if (!in_array($currentStep, $validStages)) {
111 return $this->sendError([
112 'message' => 'Invalid stage. Please start the migration again.'
113 ]);
114 }
115
116 if ($currentStep == 'group_members') {
117 return $this->syncGroupMembers($status);
118 }
119
120 if ($currentStep == 'posts') {
121 return $this->syncPostsAndComments($status);
122 }
123
124 if ($currentStep == 'users') {
125 return $this->syncUsers($status);
126 }
127
128 return $this->getCurrentStatus();
129 }
130
131 protected function syncUsers($status)
132 {
133 if ($this->isTimeLimitExceeded(10)) {
134 return $this->getCurrentStatus();
135 }
136
137 $lastUserId = Arr::get($status, 'last_migrated_user_id', 0);
138 $usersIds = fluentCommunityApp('db')->table('bp_xprofile_data')
139 ->groupBy('user_id')
140 ->select(['user_id'])
141 ->when($lastUserId, function ($q) use ($lastUserId) {
142 $q->where('user_id', '>', $lastUserId);
143 })
144 ->orderBy('user_id', 'ASC')
145 ->limit(100)
146 ->get()
147 ->pluck('user_id')
148 ->toArray();
149
150 if (!$usersIds) {
151 $status['current_stage'] = 'completed';
152 $this->updateCurrentStatus($status, false);
153 return $this->getCurrentStatus();
154 }
155
156 $users = User::whereIn('id', $usersIds)->get();
157
158 if ($users->isEmpty()) {
159 $status['current_stage'] = 'completed';
160 $this->updateCurrentStatus($status, false);
161 return $this->getCurrentStatus();
162 }
163
164 $lastUserId = null;
165
166 foreach ($users as $user) {
167 $lastUserId = $user->ID;
168 BPMigratorHelper::syncUser($user);
169 }
170
171 do_action('fluent_community/after_sync_bp_users', $users);
172
173 $status['last_migrated_user_id'] = $lastUserId;
174 $this->updateCurrentStatus($status, false);
175
176 return $this->syncUsers($status);
177 }
178
179 protected function syncGroupMembers($status)
180 {
181 if ($this->isTimeLimitExceeded(10)) {
182 return $this->getCurrentStatus();
183 }
184
185 $lastMemberId = Arr::get($status, 'last_migrated_member_id', 0);
186
187 $groupMemberEntries = fluentCommunityApp('db')->table('bp_groups_members')
188 ->when($lastMemberId, function ($q) use ($lastMemberId) {
189 $q->where('id', '>', $lastMemberId);
190 })
191 ->orderBy('id', 'ASC')
192 ->limit(100)
193 ->get();
194
195 if ($groupMemberEntries->isEmpty()) {
196 $status['current_stage'] = 'posts';
197 $this->updateCurrentStatus($status, false);
198 return $this->getCurrentStatus();
199 }
200
201 foreach ($groupMemberEntries as $entry) {
202 $spaceId = Arr::get($status['migrated_groups'], $entry->group_id);
203 if (!$spaceId) {
204 continue;
205 }
206
207 $role = 'member';
208 if ($entry->is_admin == 1) {
209 $role = 'admin';
210 } else if ($entry->is_mod == 1) {
211 $role = 'moderator';
212 }
213
214 $entryData = [
215 'space_id' => $spaceId,
216 'user_id' => $entry->user_id,
217 'status' => 'active',
218 'role' => $role,
219 'created_at' => $entry->date_modified,
220 ];
221
222 if (!Helper::isUserInSpace($entryData['user_id'], $entryData['space_id'])) {
223 fluentCommunityApp('db')->table('fcom_space_user')->insert($entryData);
224 }
225
226 $status['last_migrated_member_id'] = $entry->id;
227 $status = $this->updateCurrentStatus($status, false);
228 }
229
230 return $this->syncGroupMembers($status);
231 }
232
233 protected function syncPostsAndComments($status)
234 {
235 if ($this->isTimeLimitExceeded(10)) {
236 return $this->getCurrentStatus();
237 }
238
239 $lastPostId = Arr::get($status, 'last_activity_id', 0);
240
241 $isBuddyBoss = BPMigratorHelper::isBuddyBoss();
242
243 $posts = fluentCommunityApp('db')->table('bp_activity')
244 ->where('type', 'activity_update')
245 ->when($isBuddyBoss, function ($q) {
246 $q->whereNotIn('privacy', ['media', 'onlyme']);
247 })
248 ->when($lastPostId, function ($q) use ($lastPostId) {
249 $q->where('id', '>', $lastPostId);
250 })
251 ->orderBy('id', 'ASC')
252 ->limit(40)
253 ->get();
254
255 if ($posts->isEmpty()) {
256 $status['current_stage'] = 'users';
257 $this->updateCurrentStatus($status, false);
258 return $this->getCurrentStatus();
259 }
260
261 foreach ($posts as $post) {
262 $status['last_activity_id'] = $post->id;
263 $status = $this->updateCurrentStatus($status, false);
264
265 if (fluentCommunityApp('db')->table('bp_activity_meta')->where('activity_id', $post->id)->where('meta_key', '_fcom_feed_id')->exists()) {
266 continue;
267 }
268
269 $feed = BPMigratorHelper::migratePost($post, Arr::get($status['migrated_groups'], $post->item_id, NULL));
270
271 if ($feed) {
272 fluentCommunityApp('db')->table('bp_activity_meta')
273 ->insert([
274 'activity_id' => $post->id,
275 'meta_key' => '_fcom_feed_id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
276 'meta_value' => $feed->id // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
277 ]);
278 }
279 }
280
281 return $this->syncPostsAndComments($status);
282 }
283
284 protected function migrateGroups($groups)
285 {
286 $createdMaps = [];
287 foreach ($groups as $group) {
288 $createdSpace = BPMigratorHelper::migrateGroupData($group);
289 if ($createdSpace) {
290 $createdMaps[$group->id] = $createdSpace->id;
291 }
292 }
293
294 update_option('_bp_fcom_group_maps', $createdMaps);
295
296 return $createdMaps;
297 }
298
299 private function isTimeLimitExceeded($offset = 10)
300 {
301 $timeLimit = $this->timeLimit - $offset;
302 $currentTime = time();
303 $timeElapsed = $currentTime - $this->startTimeStamp;
304
305 return $timeElapsed >= $timeLimit;
306 }
307
308 private function getCurrentStatus()
309 {
310 $defaults = [
311 'migrated_groups' => [],
312 'last_activity_id' => 0,
313 'migrated_posts_count' => 0,
314 'last_migrated_user_id' => 0,
315 'last_migrated_member_id' => 0,
316 'current_stage' => 'groups',
317 ];
318
319 $status = (array)get_option('_fcom_bp_migrations_status', $defaults);
320
321 $status = wp_parse_args($status, $defaults);
322
323 return $status;
324 }
325
326 private function updateCurrentStatus($newData, $resync = true)
327 {
328 if ($resync) {
329 $status = $this->getCurrentStatus();
330 $newData = wp_parse_args($newData, $status);
331 }
332
333 $newData = Arr::only($newData, [
334 'migrated_groups',
335 'last_activity_id',
336 'last_migrated_member_id',
337 'migrated_posts_count',
338 'last_migrated_user_id',
339 'current_stage'
340 ]);
341
342 update_option('_fcom_bp_migrations_status', $newData, false);
343
344 return $newData;
345 }
346
347 private function deleteCurrentData()
348 {
349 BPMigratorHelper::deleteCurrentData();
350 }
351 }
352