| | |
| | | <?php |
| | | namespace JVBase\rest\routes; |
| | | |
| | | use JVBase\Instance; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\managers\CustomTable; |
| | | use JVBase\managers\Emails; |
| | | use JVBase\managers\Favourites; |
| | | use JVBase\managers\NotificationManager; |
| | | use JVBase\managers\queue\Queue; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\rest\PermissionHandler; |
| | | use JVBase\rest\Response; |
| | |
| | | |
| | | class FavouritesRoutes extends Rest |
| | | { |
| | | use Instance; |
| | | protected array $valid_types; |
| | | protected Cache $listsCache; |
| | | protected Cache $sharedListsCache; |
| | |
| | | $this->cacheName = 'favourites'; |
| | | $this->cacheTtl = HOUR_IN_SECONDS; |
| | | parent::__construct(); |
| | | $this->cache = Cache::for($this->cacheName)->user(); |
| | | |
| | | // Set up cache connections |
| | | $this->cache->connect('post')->connect('user')->connect('taxonomy')->user(); |
| | | $this->listsCache = Cache::for('lists')->connect('favourites', true)->user(); |
| | | $this->sharedListsCache = Cache::for('sharedLists')->connect('favourites', true)->user(); |
| | | $this->favouritesCache = Cache::for('allFavourites')->connect('favourites', true)->user(); |
| | | $this->listsCache = Cache::for('fav_lists')->user(); |
| | | $this->sharedListsCache = Cache::for('fav_shared_list')->user(); |
| | | $this->favouritesCache = Cache::for('allFavourites')->user(); |
| | | |
| | | $this->valid_types = array_merge(Registrar::getRegistered('post'), Registrar::getRegistered('term')); |
| | | |
| | | // Initialize CustomTable instances |
| | | $this->favourites = CustomTable::for('favourites'); |
| | | $this->lists = CustomTable::for('favourites_lists'); |
| | | $this->listItems = CustomTable::for('favourites_list_items'); |
| | | $this->listShares = CustomTable::for('favourites_list_shares'); |
| | | |
| | | // Register hooks |
| | | add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3); |
| | | add_action('before_delete_post', [$this, 'cleanupPostFavourites']); |
| | | add_action('delete_term', [$this, 'cleanupTermFavourites'], 10, 3); |
| | | add_action('jvbUserRegistered', [$this, 'maybeAcceptListInvite'], 10, 3); |
| | | add_action('jvb_cleanupOrphanedFavourites', [$this, 'cleanupOrphanedFavourites']); |
| | | } |
| | | |
| | | public function registerRoutes(): void |
| | |
| | | Route::for('favourites') |
| | | ->get([$this, 'getFavourites']) |
| | | ->args([ |
| | | 'user' => 'integer|required', |
| | | 'type' => 'string', |
| | | 'include_all' => 'boolean', |
| | | ]) |
| | |
| | | ->rateLimit(30) |
| | | ->post([$this, 'handleFavourite']) |
| | | ->args([ |
| | | 'user' => 'integer|required', |
| | | 'action' => 'string|required|enum:add,remove,toggle,batch,note', |
| | | 'type' => 'string', |
| | | 'target_id' => 'integer', |
| | |
| | | ->rateLimit(30) |
| | | ->post([$this, 'handleList']) |
| | | ->args([ |
| | | 'user' => 'integer|required', |
| | | 'id' => 'string|required', |
| | | 'action' => 'string|required|enum:create,update,delete,share,unshare,add_items,remove_items', |
| | | 'list_id' => 'integer', |
| | |
| | | // Favourite counts |
| | | Route::for('favourites/counts') |
| | | ->get([$this, 'getFavouriteCounts']) |
| | | ->args(['user' => 'integer|required']) |
| | | ->auth(PermissionHandler::combine(['user', ['actionNonce' => 'favourites-']])) |
| | | ->register(); |
| | | } |
| | |
| | | */ |
| | | public function getFavourites(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $user_id = absint($request->get_param('user')); |
| | | $user_id = get_current_user_id(); |
| | | |
| | | if (!$this->userCheck($user_id)) { |
| | | if (!$user_id) { |
| | | return $this->unauthorized(); |
| | | } |
| | | |
| | | $args = $this->buildParams($request); |
| | | $key = $this->cache->generateKey($args); |
| | | $result = $this->cache->remember( |
| | | $args, |
| | | function() use ($user_id, $args) { |
| | | return Favourites::getInstance()->getFavourites($args); |
| | | } |
| | | ); |
| | | |
| | | // Check cache headers |
| | | $cache_check = $this->checkHeaders($request, $key); |
| | | if ($cache_check) { |
| | | return $cache_check; |
| | | } |
| | | $result = JVB()->favourites()->getFavourites($args); |
| | | $result['items'] = $this->formatItems($result['items']); |
| | | |
| | | return $this->addCacheHeaders(Response::success($result)); |
| | | $response = [ |
| | | 'items' => $this->formatItems($result['items']) |
| | | ]; |
| | | return Response::success($response); |
| | | } |
| | | |
| | | |
| | |
| | | public function handleFavourite(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $params = $request->get_params(); |
| | | $user_id = absint($params['user']??0); |
| | | $user_id = get_current_user_id(); |
| | | |
| | | if (!$this->userCheck($user_id)) { |
| | | return $this->unauthorized(); |
| | | } |
| | | $action = strtolower(sanitize_text_field($params['action'])); |
| | | $action = in_array($action, ['add', 'remove']) ? $action : false; |
| | | $action = in_array($action, ['add', 'remove', 'toggle', 'batch', 'notes']) ? $action : false; |
| | | if (!$action) { |
| | | return $this->error('Invalid favourite action'); |
| | | } |
| | | $target_id = absint($params['target_id']??0); |
| | | if ($target_id === 0) { |
| | | return $this->error('Invalid target id'); |
| | | } |
| | | |
| | | $type = sanitize_text_field($params['type']??''); |
| | | if (empty($type)) { |
| | | return $this->error('No type provided'); |
| | | } |
| | | |
| | | $result = JVB()->favourites()->toggleFavourite( |
| | | $action === 'add', |
| | | $user_id, |
| | | $target_id, |
| | | $type |
| | | ); |
| | | $target_id = absint($params['target_id']??0); |
| | | if ($action !== 'batch' && $target_id === 0) { |
| | | return $this->error('Invalid target id'); |
| | | } |
| | | |
| | | $favourites = Favourites::getInstance(); |
| | | $result = false; |
| | | switch ($action) { |
| | | case 'notes': |
| | | $note = sanitize_text_field($params['note']??''); |
| | | $result = $favourites->addNoteFromTarget($user_id, $target_id, $type, $note); |
| | | break; |
| | | case 'toggle': |
| | | $isFavourited = $favourites->hasFavourited($user_id, $target_id, $type); |
| | | $result = $favourites->toggleFavourite(!$isFavourited, $user_id, $target_id, $type); |
| | | break; |
| | | case 'add': |
| | | $result = $favourites->favourite($user_id, $target_id, $type); |
| | | break; |
| | | case 'remove': |
| | | $result = $favourites->unfavourite($user_id, $target_id, $type); |
| | | break; |
| | | case 'batch': |
| | | $items = $params['items']??[]; |
| | | $items = array_filter($items, function ($item) { |
| | | $keys = ['target_id', 'type', 'action']; |
| | | foreach ($keys as $key) { |
| | | if (!array_key_exists($key, $item)) { |
| | | return false; |
| | | } |
| | | if (empty($item[$key])) { |
| | | return false; |
| | | } |
| | | } |
| | | if (!in_array($item['action'], ['add', 'remove'])) { |
| | | return false; |
| | | } |
| | | return true; |
| | | }); |
| | | if (empty($items)) { |
| | | $result = $this->success(['message' => 'No items to update']); |
| | | } else { |
| | | $result = $favourites->batchToggleFavourites($user_id, $items); |
| | | } |
| | | break; |
| | | } |
| | | |
| | | if ($result) { |
| | | return $this->success(); |
| | | return $this->success(is_bool($result) ? [] : ['result' => $result]); |
| | | } |
| | | return $this->error('Something went wrong'); |
| | | } |
| | |
| | | */ |
| | | public function getLists(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $params = $request->get_params(); |
| | | $user_id = absint($params['user']); |
| | | |
| | | if (!$this->userCheck($user_id)) { |
| | | return $this->unauthorized(); |
| | | } |
| | | $user_id = get_current_user_id(); |
| | | |
| | | $args = $this->buildParams($request); |
| | | $args['per_page'] = 20; |
| | |
| | | $args['where']['id'] = sanitize_text_field($listId); |
| | | } |
| | | |
| | | $key = $this->listsCache->generateKey($args); |
| | | |
| | | // Check cache headers |
| | | $cache_check = $this->checkHeaders($request, $key); |
| | | if ($cache_check) { |
| | | return $cache_check; |
| | | } |
| | | |
| | | $includeShares = !empty($request->get_param('include_shares')); |
| | | |
| | | $response = !empty($listId) |
| | | ? JVB()->favourites()->getListDetails($listId, $user_id) |
| | | : JVB()->favourites()->getAvailableLists($args, $includeShares); |
| | | ? Favourites::getInstance()->getListDetails($listId, $user_id) |
| | | : Favourites::getInstance()->getAvailableLists($args, $includeShares); |
| | | |
| | | return $this->addCacheHeaders(Response::success($response)); |
| | | return Response::success($response); |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | public function getFavouriteCounts(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $user_id = absint($request->get_param('user')); |
| | | |
| | | if (!$this->userCheck($user_id)) { |
| | | return $this->unauthorized(); |
| | | } |
| | | $user_id = get_current_user_id(); |
| | | |
| | | $key = "counts_{$user_id}"; |
| | | |
| | | $counts = $this->cache->remember($key, function() use ($user_id) { |
| | | try { |
| | | // Get counts grouped by type using raw query |
| | | $results = $this->favourites->queryResults( |
| | | "SELECT type, COUNT(*) as count FROM {table} WHERE user_id = %d GROUP BY type", |
| | | [$user_id], |
| | | OBJECT_K |
| | | ); |
| | | |
| | | $all_counts = array_fill_keys( |
| | | array_map(fn($type) => str_replace(BASE, '', $type), array_keys($this->valid_types)), |
| | | 0 |
| | | ); |
| | | |
| | | foreach ($results as $type => $data) { |
| | | $type_key = str_replace(BASE, '', $type); |
| | | $all_counts[$type_key] = (int)$data->count; |
| | | } |
| | | |
| | | return $all_counts; |
| | | |
| | | } catch (Exception $e) { |
| | | $this->logError('getFavouriteCounts', [ |
| | | 'error' => $e->getMessage(), |
| | | 'user_id' => $user_id |
| | | ]); |
| | | |
| | | return array_fill_keys(array_keys($this->valid_types), 0); |
| | | } |
| | | }); |
| | | $counts = Favourites::getInstance()->getFavouriteCounts($user_id); |
| | | |
| | | return Response::success(['counts' => $counts]); |
| | | } |
| | | |
| | | /** |
| | | * Process favourite operations using transactions |
| | | */ |
| | | public function processOperation($result, object $operation, array $data) |
| | | { |
| | | $action_map = [ |
| | | 'favourite_add' => 'addFavourite', |
| | | 'favourite_remove' => 'removeFavourite', |
| | | 'favourite_batch' => 'batchFavourites', |
| | | 'favourite_note' => 'processNote', |
| | | 'favourite_list_create' => 'createList', |
| | | 'favourite_list_update' => 'updateList', |
| | | 'favourite_list_delete' => 'deleteList', |
| | | 'favourite_list_add_items' => 'addToList', |
| | | 'favourite_list_remove_items' => 'removeFromList', |
| | | 'favourite_list_share' => 'shareList', |
| | | 'favourite_list_unshare' => 'unshareList', |
| | | ]; |
| | | |
| | | if (!isset($action_map[$operation->type])) { |
| | | return $result; |
| | | } |
| | | |
| | | try { |
| | | $method = $action_map[$operation->type]; |
| | | $response = $this->$method($operation->user_id, $data); |
| | | |
| | | // Clear cache on success |
| | | if ($response['success'] ?? false) { |
| | | Cache::invalidateItem('favourites', $operation->user_id); |
| | | $this->listsCache->flush(); |
| | | $this->sharedListsCache->flush(); |
| | | } |
| | | |
| | | return $response; |
| | | } catch (Exception $e) { |
| | | $this->logError('processOperation', [ |
| | | 'error' => $e->getMessage(), |
| | | 'operation_id' => $operation->id, |
| | | 'type' => $operation->type |
| | | ]); |
| | | |
| | | return [ |
| | | 'success' => false, |
| | | 'result' => $e->getMessage() |
| | | ]; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Add a favourite using findOrCreate pattern |
| | | */ |
| | | protected function addFavourite(int $user_id, array $data): array |
| | | { |
| | | $type = $data['type']; |
| | | $target_id = $data['target_id']; |
| | | |
| | | if (!str_starts_with($type, BASE)) { |
| | | $type = BASE . $type; |
| | | } |
| | | |
| | | if (!isset($this->valid_types[$type])) { |
| | | return ['success' => false, 'result' => 'Invalid type']; |
| | | } |
| | | |
| | | // Use findOrCreate pattern |
| | | $result = $this->favourites->findOrCreate([ |
| | | 'user_id' => $user_id, |
| | | 'type' => $type, |
| | | 'target_id' => $target_id |
| | | ]); |
| | | |
| | | if ((bool)$result) { |
| | | $this->updateFavouriteCount($type, $target_id); |
| | | $this->maybeNotifyOwner($type, $target_id, $user_id); |
| | | } |
| | | |
| | | return [ |
| | | 'success' => true, |
| | | 'result' => [ |
| | | 'action' => $result['created'] ? 'added' : 'already_exists', |
| | | 'favourite_id' => $result['id'], |
| | | 'count' => $this->getFavouriteCount($type, $target_id) |
| | | ] |
| | | ]; |
| | | } |
| | | |
| | | /** |
| | | * Remove a favourite |
| | | */ |
| | | protected function removeFavourite(int $user_id, array $data): array |
| | | { |
| | | $type = $data['type']; |
| | | $target_id = $data['target_id']; |
| | | |
| | | if (!str_starts_with($type, BASE)) { |
| | | $type = BASE . $type; |
| | | } |
| | | |
| | | $deleted = $this->favourites->where([ |
| | | 'user_id' => $user_id, |
| | | 'type' => $type, |
| | | 'target_id' => $target_id |
| | | ])->deleteResults(); |
| | | |
| | | if ($deleted) { |
| | | $this->updateFavouriteCount($type, $target_id); |
| | | $this->removeRelatedNotifications($type, $target_id, $user_id); |
| | | } |
| | | |
| | | return [ |
| | | 'success' => true, |
| | | 'result' => [ |
| | | 'action' => $deleted ? 'removed' : 'not_found', |
| | | 'count' => $this->getFavouriteCount($type, $target_id) |
| | | ] |
| | | ]; |
| | | } |
| | | |
| | | /** |
| | | * Batch favourites using transaction |
| | | */ |
| | | protected function batchFavourites(int $user_id, array $data): array |
| | |
| | | $items = $data['items'] ?? []; |
| | | |
| | | if (empty($items)) { |
| | | return ['success' => false, 'result' => 'No items provided']; |
| | | return $this->success(['result' => 'No items provided']); |
| | | } |
| | | |
| | | return $this->favourites->transaction(function($table) use ($user_id, $items) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Clean up favourites when a post is deleted |
| | | */ |
| | | public function cleanupPostFavourites(int $post_id): void |
| | | { |
| | | try { |
| | | $type = get_post_type($post_id); |
| | | if (!$type) return; |
| | | |
| | | $type = BASE . $type; |
| | | |
| | | // Delete using fluent interface |
| | | $this->favourites->where([ |
| | | 'type' => $type, |
| | | 'target_id' => $post_id |
| | | ])->deleteResults(); |
| | | |
| | | $this->listItems->where([ |
| | | 'item_type' => $type, |
| | | 'item_id' => $post_id |
| | | ])->deleteResults(); |
| | | |
| | | } catch (Exception $e) { |
| | | $this->logError('cleanupPostFavourites', [ |
| | | 'error' => $e->getMessage(), |
| | | 'post_id' => $post_id |
| | | ]); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Clean up favourites when a term is deleted |
| | | */ |
| | | public function cleanupTermFavourites(int $term_id, int $tt_id, string $taxonomy): void |
| | | { |
| | | try { |
| | | if (!isset($this->valid_types[$taxonomy])) { |
| | | return; |
| | | } |
| | | |
| | | // Delete using fluent interface |
| | | $this->favourites->where([ |
| | | 'type' => $taxonomy, |
| | | 'target_id' => $term_id |
| | | ])->deleteResults(); |
| | | |
| | | $this->listItems->where([ |
| | | 'item_type' => $taxonomy, |
| | | 'item_id' => $term_id |
| | | ])->deleteResults(); |
| | | |
| | | } catch (Exception $e) { |
| | | $this->logError('cleanupTermFavourites', [ |
| | | 'error' => $e->getMessage(), |
| | | 'term_id' => $term_id, |
| | | 'taxonomy' => $taxonomy |
| | | ]); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Cleanup orphaned favourites using CustomTable query method |
| | | */ |
| | | public function cleanupOrphanedFavourites(): bool |
| | | { |
| | | try { |
| | | // Delete favourites for non-existent users |
| | | $this->favourites->query( |
| | | "DELETE f FROM {table} f |
| | | LEFT JOIN {$GLOBALS['wpdb']->users} u ON f.user_id = u.ID |
| | | WHERE u.ID IS NULL" |
| | | ); |
| | | |
| | | // Delete favourites for non-existent posts |
| | | $post_types = array_filter( |
| | | array_keys($this->valid_types), |
| | | fn($type) => $this->valid_types[$type]['table'] === 'post' |
| | | ); |
| | | |
| | | foreach ($post_types as $type) { |
| | | $this->favourites->query( |
| | | "DELETE f FROM {table} f |
| | | LEFT JOIN {$GLOBALS['wpdb']->posts} p ON f.target_id = p.ID |
| | | WHERE f.type = %s AND p.ID IS NULL", |
| | | [$type] |
| | | ); |
| | | } |
| | | |
| | | return true; |
| | | |
| | | } catch (Exception $e) { |
| | | $this->logError('cleanupOrphanedFavourites', [ |
| | | 'error' => $e->getMessage() |
| | | ]); |
| | | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Helper methods |
| | | */ |
| | | protected function buildParams(WP_REST_Request $request): array |
| | | { |
| | | $data = $request->get_params(); |
| | | |
| | | $where = ['user_id' => absint($data['user'])]; |
| | | $userID = get_current_user_id(); |
| | | if(!$userID) { |
| | | return []; |
| | | } |
| | | $where = ['user_id' => $userID]; |
| | | if (!empty($data['content']) && $data['content'] !== 'all') { |
| | | $where['type'] = BASE . $data['content']; |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Notify content owner of new favourite if configured |
| | | * |
| | | * @param string $type Content type |
| | | * @param int $target_id Content ID |
| | | * @param int $user_id User who favourited |
| | | * @return void |
| | | */ |
| | | protected function maybeNotifyOwner(string $type, int $target_id, int $user_id): void |
| | | { |
| | | try { |
| | | $owner_id = $this->getContentOwner($type, $target_id); |
| | | |
| | | if ($owner_id && $owner_id !== $user_id) { |
| | | JVB()->notification()->addNotification( |
| | | $owner_id, |
| | | 'new_favourite', |
| | | [ |
| | | 'user_id' => $user_id, |
| | | 'type' => $type, |
| | | 'target_id' => $target_id |
| | | ] |
| | | ); |
| | | } |
| | | } catch (Exception $e) { |
| | | // Silent fail - notifications are non-critical |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Remove any existing notifications about a favorite action |
| | | * |
| | | * @param int $user_id User who removed the favorite |
| | | * @param string $type Content type |
| | | * @param int $target_id Content ID |
| | | * @return void |
| | | */ |
| | | protected function removeRelatedNotifications(int $user_id, string $type, int $target_id):void |
| | | { |
| | | try { |
| | | // Get the content owner(s) |
| | | $owner_ids = $this->getContentOwner($type, $target_id); |
| | | if (!$owner_ids) { |
| | | return; |
| | | } |
| | | |
| | | $owner_ids = (is_array($owner_ids)) ? $owner_ids : [$owner_ids]; |
| | | |
| | | foreach ($owner_ids as $owner_id) { |
| | | // Skip if owner is the same as the user who unfavorited |
| | | if ($owner_id === $user_id) { |
| | | continue; |
| | | } |
| | | |
| | | global $wpdb; |
| | | $notifications_table = $wpdb->prefix . BASE . 'notifications'; |
| | | |
| | | // Find recent (within last 30 days) new_favourite notifications from this user for this content |
| | | $notifications = $wpdb->get_results($wpdb->prepare( |
| | | "SELECT id FROM {$notifications_table} |
| | | WHERE owner_id = %d |
| | | AND action_user_id = %d |
| | | AND type = 'new_favourite' |
| | | AND target_id = %d |
| | | AND target_type = %s |
| | | AND created_at > DATE_SUB(%s, INTERVAL 30 DAY)", |
| | | $owner_id, |
| | | $user_id, |
| | | $target_id, |
| | | $type, |
| | | current_time('mysql') |
| | | )); |
| | | |
| | | if (empty($notifications)) { |
| | | continue; |
| | | } |
| | | |
| | | // Delete the notifications |
| | | foreach ($notifications as $notification) { |
| | | $wpdb->delete( |
| | | $notifications_table, |
| | | ['id' => $notification->id], |
| | | ['%d'] |
| | | ); |
| | | } |
| | | |
| | | // Invalidate notification cache for this user |
| | | // if (method_exists(JVB()->notification(), 'clearNotificationCache')) { |
| | | // JVB()->notification()->clearNotificationCache($owner_id); |
| | | // } |
| | | } |
| | | } catch (Exception $e) { |
| | | // Log but continue |
| | | JVB()->error()->log( |
| | | 'favourites', |
| | | 'Error removing related notifications: ' . $e->getMessage(), |
| | | ['type' => $type, 'target_id' => $target_id, 'user_id' => $user_id], |
| | | 'warning' |
| | | ); |
| | | } |
| | | } |
| | | |
| | | public function maybeAcceptListInvite(int $user_id, string $email, array $data):void |
| | | { |
| | | if (array_key_exists('list_token', $data) && !empty($data['list_token'])) { |
| | | $this->acceptListInvitation($data['list_token'], $email); |
| | | Favourites::getInstance()->acceptListShare($data['list_token'], $user_id); |
| | | } |
| | | } |
| | | |
| | |
| | | protected function getListDetails(int $list_id, int $user_id): array |
| | | { |
| | | // Check access - either owner or has share |
| | | $is_owner = JVB()->favourites()->userOwnsList($list_id, $user_id); |
| | | $is_shared = JVB()->favourites()->userCanViewList($list_id, $user_id); |
| | | $is_owner = Favourites::getInstance()->userOwnsList($list_id, $user_id); |
| | | $is_shared = Favourites::getInstance()->userCanViewList($list_id, $user_id); |
| | | |
| | | |
| | | if (!$is_owner && !$is_shared) { |
| | |
| | | ]; |
| | | } |
| | | |
| | | $list = JVB()->favourites()->getListDetails($list_id, $user_id); |
| | | $list = Favourites::getInstance()->getListDetails($list_id, $user_id); |
| | | |
| | | if (empty($list)) { |
| | | return [ |
| | |
| | | // Get list items |
| | | $items = $this->listItems |
| | | ->where(['list_id' => $list_id]) |
| | | ->orderBy('added_at', 'DESC') |
| | | ->orderBy('added_at') |
| | | ->getResults(); |
| | | |
| | | // Format items - convert to favourite-like objects |
| | |
| | | |
| | | // Get shared users if owner |
| | | $shared_users = []; |
| | | $is_owner = false;//TODO |
| | | if ($is_owner) { |
| | | $shares = $this->listShares |
| | | ->where(['list_id' => $list_id]) |
| | | ->orderBy('created_at', 'DESC') |
| | | ->orderBy('created_at') |
| | | ->getResults(); |
| | | |
| | | foreach ($shares as $share_item) { |
| | |
| | | $shared_users[] = $shared_user; |
| | | } |
| | | } |
| | | |
| | | $list = []; //TODO: check this |
| | | return [ |
| | | 'success' => true, |
| | | 'list' => [ |
| | |
| | | ]); |
| | | |
| | | // Send notification |
| | | JVB()->notification()->addNotification( |
| | | $share_user->ID, |
| | | 'list_shared', |
| | | $user_id, |
| | | sprintf('%s shared a favorites list with you: "%s"', $owner_name, $list->name), |
| | | $list_id, |
| | | 'favourites_list', |
| | | [ |
| | | 'list_id' => $list_id, |
| | | 'list_name' => $list->name, |
| | | 'permission_type' => $permission_type |
| | | ] |
| | | ); |
| | | // TODO This should be handled by the Favourites:: manager |
| | | // NotificationManager::getInstance()->addNotification( |
| | | // $share_user->ID, |
| | | // 'list_shared', |
| | | // $user_id, |
| | | // sprintf('%s shared a favorites list with you: "%s"', $owner_name, $list->name), |
| | | // $list_id, |
| | | // 'favourites_list', |
| | | // [ |
| | | // 'list_id' => $list_id, |
| | | // 'list_name' => $list->name, |
| | | // 'permission_type' => $permission_type |
| | | // ] |
| | | // ); |
| | | |
| | | return [ |
| | | 'success' => true, |
| | |
| | | $list = $this->lists->where(['id' => $list_id])->first(); |
| | | |
| | | if ($list) { |
| | | JVB()->notification()->addNotification( |
| | | NotificationManager::getInstance()->addNotification( |
| | | $existing_share->user_id, |
| | | 'list_share_revoked', |
| | | $user_id, |
| | |
| | | $invite_url |
| | | ); |
| | | |
| | | return JVB()->email()->sendEmail($email, $subject, $message); |
| | | return Emails::getInstance()->sendEmail($email, $subject, $message); |
| | | } |
| | | |
| | | /** |
| | |
| | | $user = get_userdata($user_id); |
| | | $display_name = $user ? $user->display_name : $email; |
| | | |
| | | JVB()->notification()->addNotification( |
| | | NotificationManager::getInstance()->addNotification( |
| | | $list->user_id, |
| | | 'list_share_accepted', |
| | | $user_id, |
| | |
| | | // For posts |
| | | if (str_contains($type, 'post') || in_array($type, array_keys($this->valid_types))) { |
| | | $post = get_post($target_id); |
| | | return $post ? $post->post_author : null; |
| | | return $post?->post_author; |
| | | } |
| | | |
| | | // For terms (shops, etc.) |
| | |
| | | */ |
| | | public function handleList(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $user_id = absint($request->get_param('user')); |
| | | $user_id = get_current_user_id(); |
| | | $operation_id = sanitize_text_field($request->get_param('id')); |
| | | $action = sanitize_text_field($request->get_param('action')); |
| | | |
| | |
| | | }; |
| | | |
| | | if (!$operation_type) { |
| | | return $this->error('Invalid action', 'invalid_action', 400); |
| | | return $this->error('Invalid action', 'invalid_action'); |
| | | } |
| | | |
| | | JVB()->queue()->queueOperation( |
| | | Queue::getInstance()->queueOperation( |
| | | $operation_type, |
| | | $user_id, |
| | | $data, |