diff --git a/run_migrations.php b/run_migrations.php new file mode 100644 index 00000000..c14a4db9 --- /dev/null +++ b/run_migrations.php @@ -0,0 +1,107 @@ +query("SHOW TABLES LIKE 'membership_links'"); +if ($checkTable->num_rows > 0) { + echo "✓ membership_links table already exists\n"; +} else { + echo "Creating membership_links table...\n"; + + $createLink = $conn->query(" + CREATE TABLE IF NOT EXISTS `membership_links` ( + `link_id` INT AUTO_INCREMENT PRIMARY KEY, + `primary_user_id` INT NOT NULL, + `secondary_user_id` INT NOT NULL, + `relationship` VARCHAR(50) NOT NULL DEFAULT 'spouse', + `linked_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT `fk_membership_links_primary` FOREIGN KEY (`primary_user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `fk_membership_links_secondary` FOREIGN KEY (`secondary_user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + + INDEX `idx_primary_user` (`primary_user_id`), + INDEX `idx_secondary_user` (`secondary_user_id`), + + UNIQUE KEY `unique_link` (`primary_user_id`, `secondary_user_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci + "); + + if ($createLink) { + echo "✓ membership_links table created successfully\n"; + } else { + echo "✗ Error creating membership_links table: " . $conn->error . "\n"; + } +} + +// Check if membership_permissions table exists +$checkTable = $conn->query("SHOW TABLES LIKE 'membership_permissions'"); +if ($checkTable->num_rows > 0) { + echo "✓ membership_permissions table already exists\n"; +} else { + echo "Creating membership_permissions table...\n"; + + $createPerm = $conn->query(" + CREATE TABLE IF NOT EXISTS `membership_permissions` ( + `permission_id` INT AUTO_INCREMENT PRIMARY KEY, + `link_id` INT NOT NULL, + `permission_name` VARCHAR(100) NOT NULL, + `granted_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT `fk_membership_permissions_link` FOREIGN KEY (`link_id`) + REFERENCES `membership_links`(`link_id`) ON DELETE CASCADE ON UPDATE CASCADE, + + INDEX `idx_link` (`link_id`), + + UNIQUE KEY `unique_permission` (`link_id`, `permission_name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci + "); + + if ($createPerm) { + echo "✓ membership_permissions table created successfully\n"; + } else { + echo "✗ Error creating membership_permissions table: " . $conn->error . "\n"; + } +} + +// Create or replace the view +echo "\nCreating linked_membership_users view...\n"; +$createView = $conn->query(" + CREATE OR REPLACE VIEW `linked_membership_users` AS + SELECT + primary_user_id, + secondary_user_id, + relationship, + linked_at + FROM membership_links + UNION ALL + SELECT + primary_user_id, + primary_user_id as secondary_user_id, + 'primary' as relationship, + linked_at + FROM membership_links +"); + +if ($createView) { + echo "✓ View created successfully\n"; +} else { + echo "✗ Error creating view: " . $conn->error . "\n"; +} + +$conn->close(); +echo "\n✓ Migration completed successfully!\n"; +?> diff --git a/src/config/functions.php b/src/config/functions.php index 60157785..679ebc99 100644 --- a/src/config/functions.php +++ b/src/config/functions.php @@ -2924,17 +2924,25 @@ function linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $re $conn = openDatabaseConnection(); if ($conn === null) { + error_log("linkSecondaryUserToMembership: Database connection failed"); return ['success' => false, 'message' => 'Database connection failed']; } + error_log("linkSecondaryUserToMembership: primary=$primary_user_id, secondary=$secondary_user_id, relationship=$relationship"); + // Validation: primary and secondary user IDs must be different if ($primary_user_id === $secondary_user_id) { + error_log("linkSecondaryUserToMembership: Cannot link user to themselves"); return ['success' => false, 'message' => 'Cannot link user to themselves']; } // Validation: primary user must have active membership - if (!getUserMemberStatus($primary_user_id)) { + $memberStatus = getUserMemberStatus($primary_user_id); + error_log("linkSecondaryUserToMembership: Primary user member status = " . ($memberStatus ? 'true' : 'false')); + + if (!$memberStatus) { $conn->close(); + error_log("linkSecondaryUserToMembership: Primary user does not have active membership"); return ['success' => false, 'message' => 'Primary user does not have active membership']; } @@ -2947,6 +2955,7 @@ function linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $re if ($userResult->num_rows === 0) { $conn->close(); + error_log("linkSecondaryUserToMembership: Secondary user does not exist"); return ['success' => false, 'message' => 'Secondary user does not exist']; } @@ -2959,12 +2968,14 @@ function linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $re if ($existingResult->num_rows > 0) { $conn->close(); + error_log("linkSecondaryUserToMembership: Users are already linked"); return ['success' => false, 'message' => 'Users are already linked']; } try { // Start transaction $conn->begin_transaction(); + error_log("linkSecondaryUserToMembership: Starting transaction"); // Insert link $insertLink = $conn->prepare(" @@ -2972,8 +2983,13 @@ function linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $re VALUES (?, ?, ?, NOW(), NOW()) "); $insertLink->bind_param("iis", $primary_user_id, $secondary_user_id, $relationship); - $insertLink->execute(); + + if (!$insertLink->execute()) { + throw new Exception("Failed to insert link: " . $insertLink->error); + } + $linkId = $conn->insert_id; + error_log("linkSecondaryUserToMembership: Link created with ID = $linkId"); $insertLink->close(); // Grant default permissions to secondary user @@ -2991,17 +3007,24 @@ function linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $re VALUES (?, ?, NOW()) "); $insertPerm->bind_param("is", $linkId, $permission); - $insertPerm->execute(); + + if (!$insertPerm->execute()) { + throw new Exception("Failed to insert permission: " . $insertPerm->error); + } + + error_log("linkSecondaryUserToMembership: Permission '$permission' granted"); $insertPerm->close(); } // Commit transaction $conn->commit(); + error_log("linkSecondaryUserToMembership: Transaction committed successfully"); $conn->close(); return ['success' => true, 'message' => 'User successfully linked to membership', 'link_id' => $linkId]; } catch (Exception $e) { + error_log("linkSecondaryUserToMembership: Exception - " . $e->getMessage()); $conn->rollback(); $conn->close(); return ['success' => false, 'message' => 'Failed to create link: ' . $e->getMessage()]; @@ -3157,3 +3180,4 @@ function unlinkSecondaryUser($link_id, $primary_user_id) return ['success' => false, 'message' => 'Failed to remove link: ' . $e->getMessage()]; } } + diff --git a/src/pages/memberships/membership_details.php b/src/pages/memberships/membership_details.php index 85544346..8cc8b853 100644 --- a/src/pages/memberships/membership_details.php +++ b/src/pages/memberships/membership_details.php @@ -217,8 +217,237 @@ if (empty($application['id_number'])) { } ?> + +
+
+
+
+
+ +

Main Member

+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ + +

Spouse / Life Partner / Other Details

+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ + +

Children's Names

+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+ + +

Address

+
+
+
+ + +
+
+
+
+ + +
+
+
+ + +

Interests and Hobbies

+
+
+
+ +
+
+
+ + +

Primary Vehicle

+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+

Secondary Vehicle

+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + -
+

Linked Accounts (Family & Partners)

Link additional family members or partners to your membership to give them access to member benefits.

@@ -238,7 +467,7 @@ if (empty($application['id_number'])) {

- • +

@@ -260,7 +489,7 @@ if (empty($application['id_number'])) {

Add Linked Account

- +
@@ -277,240 +506,16 @@ if (empty($application['id_number'])) {
-
-
-
-
-
- -

Main Member

-
-
-
- - -
-
-
-
- - -
-
- -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- - -

Spouse / Life Partner / Other Details

-
-
-
- - -
-
-
-
- - -
-
- -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- - -

Children's Names

-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- -
- - -

Address

-
-
-
- - -
-
-
-
- - -
-
-
- - -

Interests and Hobbies

-
-
-
- -
-
-
- - -

Primary Vehicle

-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-

Secondary Vehicle

-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
+
@@ -696,4 +701,4 @@ if (empty($application['id_number'])) { }); - + \ No newline at end of file diff --git a/src/processors/link_membership_user.php b/src/processors/link_membership_user.php index 7b45b66d..dac18e3a 100644 --- a/src/processors/link_membership_user.php +++ b/src/processors/link_membership_user.php @@ -7,46 +7,86 @@ require_once($rootPath . '/src/config/functions.php'); header('Content-Type: application/json'); +// Log incoming request +error_log("Link membership user request received. Method: " . $_SERVER['REQUEST_METHOD']); +error_log("POST data: " . json_encode($_POST)); +error_log("Session user_id: " . ($_SESSION['user_id'] ?? 'NOT SET')); + if (!isset($_SESSION['user_id']) || $_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(403); + error_log("Forbidden: No session or wrong method"); exit(json_encode(['success' => false, 'message' => 'Forbidden'])); } // Validate CSRF token -if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) { +if (!isset($_POST['csrf_token'])) { http_response_code(400); - exit(json_encode(['success' => false, 'message' => 'Invalid request'])); + error_log("No CSRF token provided"); + exit(json_encode(['success' => false, 'message' => 'CSRF token missing'])); +} + +if (!validateCSRFToken($_POST['csrf_token'])) { + http_response_code(400); + error_log("Invalid CSRF token: " . $_POST['csrf_token']); + error_log("Available tokens: " . json_encode($_SESSION['csrf_tokens'] ?? [])); + exit(json_encode(['success' => false, 'message' => 'Invalid CSRF token'])); } $primary_user_id = intval($_SESSION['user_id']); $secondary_email = trim($_POST['secondary_email'] ?? ''); $relationship = trim($_POST['relationship'] ?? 'spouse'); +error_log("Processing link: primary=$primary_user_id, secondary_email=$secondary_email, relationship=$relationship"); + if (empty($secondary_email)) { http_response_code(400); + error_log("Secondary email is empty"); exit(json_encode(['success' => false, 'message' => 'Secondary user email is required'])); } // Get the secondary user by email $conn = openDatabaseConnection(); +if (!$conn) { + http_response_code(500); + error_log("Failed to open database connection"); + exit(json_encode(['success' => false, 'message' => 'Database connection failed'])); +} + $userQuery = $conn->prepare("SELECT user_id FROM users WHERE email = ?"); +if (!$userQuery) { + http_response_code(500); + error_log("Prepare statement failed: " . $conn->error); + $conn->close(); + exit(json_encode(['success' => false, 'message' => 'Database error'])); +} + $userQuery->bind_param("s", $secondary_email); -$userQuery->execute(); +if (!$userQuery->execute()) { + http_response_code(500); + error_log("Query execution failed: " . $userQuery->error); + $userQuery->close(); + $conn->close(); + exit(json_encode(['success' => false, 'message' => 'Database error'])); +} + $userResult = $userQuery->get_result(); $userQuery->close(); if ($userResult->num_rows === 0) { $conn->close(); + error_log("User not found with email: $secondary_email"); http_response_code(404); exit(json_encode(['success' => false, 'message' => 'User with that email not found'])); } $user = $userResult->fetch_assoc(); $secondary_user_id = $user['user_id']; +error_log("Found secondary user: $secondary_user_id"); $conn->close(); // Use the linking function from functions.php $result = linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $relationship); +error_log("Link result: " . json_encode($result)); http_response_code($result['success'] ? 200 : 400); echo json_encode([ @@ -55,3 +95,4 @@ echo json_encode([ 'link_id' => $result['link_id'] ?? null ]); ?> +