ApiConnectionsController.php
3 months ago
EmailsController.php
3 months ago
MembershipsController.php
3 months ago
PagesController.php
3 months ago
SectionsController.php
3 months ago
StatisticsController.php
3 months ago
UsersController.php
3 months ago
MembershipsController.php
388 lines
| 1 | <?php |
| 2 | |
| 3 | namespace FapiMember\Api\V2\Endpoints; |
| 4 | |
| 5 | use FapiMember\Api\V2\ApiController; |
| 6 | use FapiMember\Container\Container; |
| 7 | use FapiMember\FapiMemberPlugin; |
| 8 | use FapiMember\Library\SmartEmailing\Types\BoolType; |
| 9 | use FapiMember\Library\SmartEmailing\Types\IntType; |
| 10 | use FapiMember\Library\SmartEmailing\Types\StringType; |
| 11 | use FapiMember\Model\Enums\Alert; |
| 12 | use FapiMember\Model\Enums\Format; |
| 13 | use FapiMember\Model\Enums\Keys\OptionKey; |
| 14 | use FapiMember\Model\Enums\Types\RequestMethodType; |
| 15 | use FapiMember\Model\Membership; |
| 16 | use FapiMember\Repository\LevelRepository; |
| 17 | use FapiMember\Repository\MembershipRepository; |
| 18 | use FapiMember\Repository\PageRepository; |
| 19 | use FapiMember\Service\ApiService; |
| 20 | use FapiMember\Service\EmailService; |
| 21 | use FapiMember\Service\LevelService; |
| 22 | use FapiMember\Service\MembershipService; |
| 23 | use FapiMember\Service\RedirectService; |
| 24 | use FapiMember\Service\UserService; |
| 25 | use FapiMember\Utils\DateTimeHelper; |
| 26 | use Throwable; |
| 27 | use WP_REST_Request; |
| 28 | |
| 29 | class MembershipsController |
| 30 | { |
| 31 | private MembershipRepository $membershipRepository; |
| 32 | private LevelRepository $levelRepository; |
| 33 | private PageRepository $pageRepository; |
| 34 | private MembershipService $membershipService; |
| 35 | private RedirectService $redirectService; |
| 36 | private EmailService $emailService; |
| 37 | private UserService $userService; |
| 38 | private LevelService $levelService; |
| 39 | private ApiService $apiService; |
| 40 | private ApiController $apiController; |
| 41 | |
| 42 | public function __construct() |
| 43 | { |
| 44 | $this->membershipRepository = Container::get(MembershipRepository::class); |
| 45 | $this->levelRepository = Container::get(LevelRepository::class); |
| 46 | $this->pageRepository = Container::get(PageRepository::class); |
| 47 | $this->membershipService = Container::get(MembershipService::class); |
| 48 | $this->redirectService = Container::get(RedirectService::class); |
| 49 | $this->emailService = Container::get(EmailService::class); |
| 50 | $this->userService = Container::get(UserService::class); |
| 51 | $this->levelService = Container::get(LevelService::class); |
| 52 | $this->apiController = Container::get(ApiController::class); |
| 53 | $this->apiService = Container::get(ApiService::class); |
| 54 | } |
| 55 | |
| 56 | public function list(): array |
| 57 | { |
| 58 | $membershipsByUsers = $this->membershipRepository->getAll(); |
| 59 | $membershipData = []; |
| 60 | |
| 61 | foreach ($membershipsByUsers as $membershipsByUser) { |
| 62 | foreach ($membershipsByUser as $membership) { |
| 63 | $membershipData[] = $membership->toArray(); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | return $membershipData; |
| 68 | } |
| 69 | |
| 70 | public function getAllForUser(WP_REST_Request $request): array |
| 71 | { |
| 72 | $this->apiController->checkRequestMethod($request, RequestMethodType::POST); |
| 73 | $body = json_decode($request->get_body(), true); |
| 74 | |
| 75 | $userId = $this->apiController->extractParam($body, 'user_id', IntType::class); |
| 76 | |
| 77 | $memberships = $this->membershipRepository->getActiveByUserId($userId); |
| 78 | |
| 79 | $membershipData = []; |
| 80 | |
| 81 | foreach ($memberships as $membership) { |
| 82 | $membershipData[] = $membership->toArray(); |
| 83 | } |
| 84 | |
| 85 | return $membershipData; |
| 86 | } |
| 87 | |
| 88 | public function updateAllForUser(WP_REST_Request $request): void |
| 89 | { |
| 90 | $this->apiController->checkRequestMethod($request, RequestMethodType::POST); |
| 91 | $body = json_decode($request->get_body(), true); |
| 92 | |
| 93 | $userId = $this->apiController->extractParam($body, 'user_id', IntType::class); |
| 94 | |
| 95 | if (isset($body['memberships']) && is_array($body['memberships'])) { |
| 96 | $membershipsData = $body['memberships']; |
| 97 | } else { |
| 98 | $this->apiController->invalidParameterError('memberships'); |
| 99 | } |
| 100 | |
| 101 | $memberships = []; |
| 102 | |
| 103 | foreach ($membershipsData as $membershipData) { |
| 104 | $membershipData['user_id'] = $userId; |
| 105 | $memberships[] = new Membership($membershipData); |
| 106 | } |
| 107 | |
| 108 | try { |
| 109 | $this->membershipService->saveAll($userId, $memberships); |
| 110 | } catch (Throwable) { |
| 111 | $this->apiController->callbackError([ |
| 112 | 'class'=> self::class, |
| 113 | 'description' => "Failed to save memberships.", |
| 114 | ]); |
| 115 | } |
| 116 | |
| 117 | $savedMemberships = $this->membershipService->getActiveByUserIdAndUpdate($userId); |
| 118 | |
| 119 | foreach ($savedMemberships as $savedMembership) { |
| 120 | foreach ($memberships as $membership) { |
| 121 | if ( |
| 122 | $membership->getLevelId() === $savedMembership->getLevelId() |
| 123 | ) { |
| 124 | if ($membership->getRegistered()->format(Format::DATE_TIME) !== $savedMembership->getRegistered()->format(Format::DATE_TIME)) { |
| 125 | $this->apiController->callbackResponse([], Alert::MEMBERSHIP_REGISTERED_EXTENDED); |
| 126 | } |
| 127 | |
| 128 | if ($membership->getUntil()?->format(Format::DATE_TIME) !== $savedMembership->getUntil()?->format(Format::DATE_TIME)) { |
| 129 | $this->apiController->callbackResponse([], Alert::MEMBERSHIP_UNTIL_EXTENDED); |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | $this->apiController->callbackResponse([], Alert::SETTINGS_SAVED); |
| 136 | } |
| 137 | |
| 138 | public function createMultiple(WP_REST_Request $request): void |
| 139 | { |
| 140 | $this->apiController->checkRequestMethod($request, RequestMethodType::POST); |
| 141 | $rows = json_decode($request->get_body(), true); |
| 142 | |
| 143 | foreach ($rows as $row) { |
| 144 | if (isset($row['email']) && $row['email'] !== null && $row['email'] !== '') { |
| 145 | $this->create($row, true); |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | public function create(array $body, bool $creatingMultiple = false): void |
| 151 | { |
| 152 | if (!isset($body['level'])) { |
| 153 | $this->apiController->callbackError([ |
| 154 | 'class'=> self::class, |
| 155 | 'description' => 'Level parameter missing in get params.', |
| 156 | ], Alert::IMPORT_FAILED); |
| 157 | } |
| 158 | |
| 159 | if (is_array($body['level'])) { |
| 160 | $levelIds = []; |
| 161 | |
| 162 | foreach ($body['level'] as $level) { |
| 163 | $levelIds[] = (int) $level; |
| 164 | } |
| 165 | } else { |
| 166 | $levelIds = [(int) $body['level']]; |
| 167 | } |
| 168 | |
| 169 | $token = $this->apiController->extractParamOrNull($body, 'token', StringType::class); |
| 170 | $voucher = $this->apiController->extractParamOrNull($body, 'voucher', IntType::class); |
| 171 | $id = $this->apiController->extractParamOrNull($body, 'id', IntType::class); |
| 172 | |
| 173 | $debug = $this->apiController->extractParamOrNull($body, 'debug', BoolType::class); |
| 174 | $sendEmail = $this->apiController->extractParamOrNull($body, 'send_email', BoolType::class); |
| 175 | $days = $this->apiController->extractParamOrNull($body, 'days', IntType::class); |
| 176 | |
| 177 | $registeredValue = $this->apiController->extractParamOrNull($body, 'registered', StringType::class); |
| 178 | $registered = DateTimeHelper::createOrNull($registeredValue, Format::DATE_TIME_BASIC) |
| 179 | ?? DateTimeHelper::createOrNull($registeredValue, Format::DATE); |
| 180 | |
| 181 | $until = DateTimeHelper::createOrNull( |
| 182 | $this->apiController->extractParamOrNull($body, 'until', StringType::class), |
| 183 | Format::DATE, |
| 184 | ); |
| 185 | |
| 186 | try { |
| 187 | foreach ($levelIds as $levelId) { |
| 188 | $level = $this->levelRepository->getLevelById($levelId); |
| 189 | |
| 190 | if ($level === null) { |
| 191 | $this->apiController->callbackError([ |
| 192 | 'class' => self::class, |
| 193 | 'description' => sprintf( |
| 194 | 'Section or level with ID %s, does not exist.', |
| 195 | $levelId, |
| 196 | ), |
| 197 | ], Alert::IMPORT_LEVEL_ID_DOESNT_EXIST); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | if ($voucher !== null) { |
| 202 | $userData = $this->emailService->getEmailFromValidVoucher($body); |
| 203 | } elseif ($id !== null) { |
| 204 | $userData = $this->emailService->getEmailFromPaidInvoice($body); |
| 205 | } elseif ($token !== null) { |
| 206 | $userData = $this->emailService->getEmailFromBodyWithValidToken($body); |
| 207 | } else { |
| 208 | $this->apiController->callbackError([ |
| 209 | 'class' => self::class, |
| 210 | 'description' => 'Invalid notification received. Missing voucher, id or token.', |
| 211 | ], Alert::MISSING_EMAIL); |
| 212 | } |
| 213 | |
| 214 | if (!is_email($userData['email'])) { |
| 215 | $this->apiController->callbackError([ |
| 216 | 'class' => self::class, |
| 217 | 'description' => 'Invalid email provided. Email given: ' . $userData['email'], |
| 218 | ], Alert::INVALID_EMAIL); |
| 219 | } |
| 220 | |
| 221 | if ($id !== null && $days !== null) { |
| 222 | $invoice = $this->apiService->getInvoice($id); |
| 223 | $repaymentNumber = $invoice['repayment_number'] ?? 1; |
| 224 | $repaymentInvoices = $this->apiService->getAllInvoicesInRepayment($id); |
| 225 | $highestRepayment = 1; |
| 226 | |
| 227 | if ($repaymentNumber !== 0 && $repaymentNumber !== null) { |
| 228 | foreach ($repaymentInvoices as $repaymentInvoice) { |
| 229 | if ( |
| 230 | isset($repaymentInvoice['repayment_number']) && |
| 231 | $repaymentInvoice['repayment_number'] > $highestRepayment |
| 232 | ) { |
| 233 | $highestRepayment = $repaymentInvoice['repayment_number']; |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | $repaymentDays = intdiv($days, $highestRepayment); |
| 238 | |
| 239 | if ($repaymentNumber === 1) { |
| 240 | $repaymentDays += $days % $highestRepayment; |
| 241 | } |
| 242 | |
| 243 | $days = $repaymentDays; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | $props = []; |
| 248 | $user = $this->userService->getOrCreateUser($userData, $props); |
| 249 | |
| 250 | if ($user === null) { |
| 251 | $this->apiController->callbackError([ |
| 252 | 'class' => self::class, |
| 253 | 'description' => 'Failed to create user.', |
| 254 | ], Alert::IMPORT_FAILED); |
| 255 | } |
| 256 | |
| 257 | foreach ($levelIds as $levelId) { |
| 258 | if ($registered === null) { |
| 259 | $props = $this->membershipService->createOrProlongMembershipByDays( |
| 260 | $user->getId(), |
| 261 | $levelId, |
| 262 | $days, |
| 263 | ) + $props; |
| 264 | } else { |
| 265 | $props = $this->membershipService->createOrUpdateMembership( |
| 266 | $user->getId(), |
| 267 | $levelId, |
| 268 | $registered, |
| 269 | $until, |
| 270 | ) + $props; |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | $wasUserCreatedNow = isset($props['new_user']) && $props['new_user'] === true; |
| 275 | $newToMembership = $props['oldMembership'] === null; |
| 276 | $levels = $this->levelRepository->getLevelsByIds($levelIds); |
| 277 | |
| 278 | if ($sendEmail === true || $sendEmail === null) { |
| 279 | $emailsToSend = $this->emailService->findEmailsToSend($levels, $wasUserCreatedNow, $newToMembership); |
| 280 | |
| 281 | foreach ($emailsToSend as $emailToSend) { |
| 282 | [$type, $level] = $emailToSend; |
| 283 | |
| 284 | $this->emailService->sendEmail($user->getEmail(), $type, $level->getId(), $props); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | } catch (Throwable $exception) { |
| 289 | $actualToken = get_option(OptionKey::TOKEN, null); |
| 290 | |
| 291 | if ( |
| 292 | $actualToken === $token && |
| 293 | $debug === true |
| 294 | ) { |
| 295 | wp_send_json_error($exception->getMessage()); |
| 296 | } else { |
| 297 | $this->apiController->callbackError([ |
| 298 | 'class' => self::class, |
| 299 | 'description' => 'An internal error occurred.', |
| 300 | ]); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | if (!$creatingMultiple) { |
| 305 | wp_send_json_success([FapiMemberPlugin::FAPI_MEMBER_PLUGIN_VERSION_KEY => FAPI_MEMBER_PLUGIN_VERSION]); |
| 306 | die; |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | public function unlockLevelForLoggedInUser(WP_REST_Request $request): void |
| 311 | { |
| 312 | $this->apiController->checkRequestMethod($request, RequestMethodType::GET); |
| 313 | $params = $request->get_params(); |
| 314 | |
| 315 | $levelId = $this->apiController->extractParamOrNull($params, 'level_id', IntType::class); |
| 316 | $pageId = $this->apiController->extractParamOrNull($params, 'page_id', IntType::class); |
| 317 | |
| 318 | if ($levelId === null) { |
| 319 | $this->redirectService->redirectToNoAccessPage($levelId); |
| 320 | } |
| 321 | |
| 322 | $userId = get_current_user_id(); |
| 323 | |
| 324 | if ($userId <= 0) { |
| 325 | $this->redirectService->redirectToNoAccessPage($levelId); |
| 326 | } |
| 327 | |
| 328 | $level = $this->levelRepository->getLevelById($levelId); |
| 329 | |
| 330 | if ($level === null || !$this->levelRepository->isButtonUnlock($levelId)) { |
| 331 | $this->redirectService->redirectToNoAccessPage($levelId); |
| 332 | } |
| 333 | |
| 334 | $memberships = $this->membershipRepository->getActiveByUserId($userId); |
| 335 | $ownsParent = false; |
| 336 | |
| 337 | foreach ($memberships as $membership) { |
| 338 | if ($membership->getLevelId() === $level->getParentId()){ |
| 339 | $ownsParent = true; |
| 340 | break; |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | if ($ownsParent === false) { |
| 345 | $this->redirectService->redirectToNoAccessPage($levelId); |
| 346 | } |
| 347 | |
| 348 | $this->membershipService->saveOne(new Membership([ |
| 349 | 'level_id' => $levelId, |
| 350 | 'user_id' => $userId, |
| 351 | 'registered' => DateTimeHelper::getNow()->format(Format::DATE_TIME), |
| 352 | 'is_unlimited' => true, |
| 353 | ])); |
| 354 | |
| 355 | if ($pageId === null) { |
| 356 | $pageId = $level->getAfterLoginPageId() |
| 357 | ?? $this->pageRepository->getCommonDashboardPageId(); |
| 358 | |
| 359 | if ($pageId === null) { |
| 360 | wp_redirect(home_url()); |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | wp_redirect(home_url() . '/?page_id=' . $pageId); |
| 365 | } |
| 366 | |
| 367 | public function getUnlockDate(WP_REST_Request $request): string|null |
| 368 | { |
| 369 | $this->apiController->checkRequestMethod($request, RequestMethodType::POST); |
| 370 | $body = json_decode($request->get_body(), true); |
| 371 | $userId = get_current_user_id(); |
| 372 | $levelId = $this->apiController->extractParam($body, 'level_id', IntType::class); |
| 373 | $registrationDate = $this->apiController->extractParamOrNull($body, 'registration_date', StringType::class); |
| 374 | $registrationDate = DateTimeHelper::createOrNull($registrationDate, Format::DATE); |
| 375 | |
| 376 | try { |
| 377 | return $this->membershipService |
| 378 | ->getUnlockDate($levelId, $userId, $registrationDate)?->format(Format::DATE_TIME); |
| 379 | } catch (Throwable) { |
| 380 | $this->apiController->callbackError([ |
| 381 | 'class'=> self::class, |
| 382 | 'description' => "Failed to get unlock date", |
| 383 | ]); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | } |
| 388 |