PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / trunk
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses vtrunk
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 trunk, at Modules/Migrations/Http/Controllers/BPMigrationController.php

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