Files
beep/includes/class-follows.php
T
Krystie b882092f5d Snapshot: Krystie uncommitted edits on sami-ahmed.net as of 2026-05-20 14:56 PT
These changes were applied DIRECTLY to the production cPanel server via
Fileman/save_file_content API calls between ~10:30 PT and 14:44 PT today.
None of them were committed or pushed at the time, violating the
Software → Repo rule (CLAUDE.md, added 2026-05-18).

Captured by Claude (VSCode-side) at Sami request so the changes can be
reviewed/cherry-picked instead of being silently lost.

Notable concerns:
- class-beep.php shrank from 3387 → 1395 bytes (likely truncation, not edit)
- beep.css shrank from 35431 → 22948 bytes (-12.5 KB; ~half the file gone)
- class-replies.php shrank from 8793 → 6406 bytes
- 3 new files (class-magic-links.php, class-follows.php, create_poll_tables.php)
  were created server-only with no repo presence

Source: live cPanel snapshot at /tmp/beep-snapshot-2026-05-20/
2026-05-20 15:12:41 -07:00

208 lines
6.8 KiB
PHP

<?php
/**
* Beep Follow System — class-follows.php
*
* REST endpoints for following/unfollowing users.
*/
if (!defined('ABSPATH')) exit;
class Beep_Follows {
const REST_NAMESPACE = 'beep/v1';
public function register_routes() {
// Follow a user: POST /beep/v1/follow/<user_id>
register_rest_route(self::REST_NAMESPACE, '/follow/(?P<user_id>\d+)', [
'methods' => 'POST',
'callback' => [$this, 'follow_user'],
'permission_callback' => [$this, 'require_login'],
]);
// Unfollow a user: DELETE /beep/v1/follow/<user_id>
register_rest_route(self::REST_NAMESPACE, '/follow/(?P<user_id>\d+)', [
'methods' => 'DELETE',
'callback' => [$this, 'unfollow_user'],
'permission_callback' => [$this, 'require_login'],
]);
// Check follow status: GET /beep/v1/follow/<user_id>
register_rest_route(self::REST_NAMESPACE, '/follow/(?P<user_id>\d+)', [
'methods' => 'GET',
'callback' => [$this, 'check_follow'],
'permission_callback' => '__return_true',
]);
// Get users I'm following: GET /beep/v1/following
register_rest_route(self::REST_NAMESPACE, '/following', [
'methods' => 'GET',
'callback' => [$this, 'get_following'],
'permission_callback' => [$this, 'require_login'],
]);
// Get my followers: GET /beep/v1/followers
register_rest_route(self::REST_NAMESPACE, '/followers', [
'methods' => 'GET',
'callback' => [$this, 'get_followers'],
'permission_callback' => [$this, 'require_login'],
]);
}
public function require_login() {
return is_user_logged_in() ? true : new WP_Error('rest_not_logged_in', 'You must be logged in', ['status' => 401]);
}
public function follow_user($request) {
$user_id = intval($request->get_param('user_id'));
$follower_id = get_current_user_id();
if ($user_id === $follower_id) {
return new WP_Error('rest_cannot_follow_self', 'You cannot follow yourself', ['status' => 400]);
}
$target = get_userdata($user_id);
if (!$target) {
return new WP_Error('rest_user_not_found', 'User not found', ['status' => 404]);
}
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
$existing = $wpdb->get_row($wpdb->prepare(
"SELECT ID FROM `$table` WHERE follower_id = %d AND following_id = %d",
$follower_id, $user_id
));
if ($existing) {
return ['status' => 'following', 'user_id' => $user_id, 'display_name' => $target->display_name];
}
$wpdb->insert($table, [
'follower_id' => $follower_id,
'following_id' => $user_id,
], ['%d', '%d']);
return ['status' => 'following', 'user_id' => $user_id, 'display_name' => $target->display_name];
}
public function unfollow_user($request) {
$user_id = intval($request->get_param('user_id'));
$follower_id = get_current_user_id();
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
$wpdb->delete($table, [
'follower_id' => $follower_id,
'following_id' => $user_id,
], ['%d', '%d']);
return ['status' => 'unfollowed', 'user_id' => $user_id];
}
public function check_follow($request) {
$user_id = intval($request->get_param('user_id'));
$current_user = get_current_user_id();
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
$is_following = false;
if ($current_user) {
$is_following = (bool) $wpdb->get_var($wpdb->prepare(
"SELECT ID FROM `$table` WHERE follower_id = %d AND following_id = %d",
$current_user, $user_id
));
}
$target = get_userdata($user_id);
if (!$target) {
return new WP_Error('rest_user_not_found', 'User not found', ['status' => 404]);
}
$follower_count = intval($wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `$table` WHERE following_id = %d", $user_id
)));
$following_count = intval($wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `$table` WHERE follower_id = %d", $user_id
)));
return [
'is_following' => $is_following,
'user_id' => $user_id,
'display_name' => $target->display_name,
'user_login' => $target->user_login,
'follower_count' => $follower_count,
'following_count' => $following_count,
];
}
public function get_following($request) {
$user_id = get_current_user_id();
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
$following = $wpdb->get_results($wpdb->prepare(
"SELECT u.ID, u.display_name, u.user_login, f.created_at
FROM `$table` f
JOIN {$wpdb->users} u ON u.ID = f.following_id
WHERE f.follower_id = %d
ORDER BY f.created_at DESC",
$user_id
), ARRAY_A);
return ['following' => $following, 'count' => count($following)];
}
public function get_followers($request) {
$user_id = get_current_user_id();
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
$followers = $wpdb->get_results($wpdb->prepare(
"SELECT u.ID, u.display_name, u.user_login, f.created_at
FROM `$table` f
JOIN {$wpdb->users} u ON u.ID = f.follower_id
WHERE f.following_id = %d
ORDER BY f.created_at DESC",
$user_id
), ARRAY_A);
return ['followers' => $followers, 'count' => count($followers)];
}
public static function is_following($follower_id, $following_id) {
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
return (bool) $wpdb->get_var($wpdb->prepare(
"SELECT ID FROM `$table` WHERE follower_id = %d AND following_id = %d",
$follower_id, $following_id
));
}
public static function get_follower_count($user_id) {
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
return intval($wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `$table` WHERE following_id = %d", $user_id
)));
}
public static function get_following_count($user_id) {
global $wpdb;
$table = $wpdb->prefix . 'beep_follows';
return intval($wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `$table` WHERE follower_id = %d", $user_id
)));
}
}
// Bootstrap — register routes
add_action('rest_api_init', function() {
$f = new Beep_Follows();
$f->register_routes();
});