diff --git a/admin/templates/html-keys-edit.php b/admin/templates/html-keys-edit.php index c83b95e..c4e2271 100644 --- a/admin/templates/html-keys-edit.php +++ b/admin/templates/html-keys-edit.php @@ -103,6 +103,80 @@

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

+ +

+ + + + + + + + +
+ +

+ + + + + + + + 'event_listing', + 'post_status' => 'publish', + 'posts_per_page' => -1, + 'orderby' => 'title', + 'order' => 'ASC', + )); + ?> + +

+ + @@ -141,6 +215,7 @@ value="1" > + diff --git a/admin/wpem-rest-api-admin.php b/admin/wpem-rest-api-admin.php index c1036d3..9b65159 100644 --- a/admin/wpem-rest-api-admin.php +++ b/admin/wpem-rest-api-admin.php @@ -111,7 +111,12 @@ public function update_api_key(){ $event_id = !empty( $_POST['event_id'] ) ? absint( $_POST['event_id'] ) : '' ; $date_expires = !empty( $_POST['date_expires'] ) ? date( 'Y-m-d H:i:s', strtotime( str_replace( '-', '/', $_POST['date_expires'] ) ) ) : null ; $restrict_check_in = isset( $_POST['restrict_check_in'] ) ? sanitize_text_field( $_POST['restrict_check_in'] ) : ''; - + $event_show_by = isset($_POST['event_show_by']) ? sanitize_text_field($_POST['event_show_by']) : 'loggedin'; + $select_events = isset($_POST['select_events']) ? maybe_serialize(array_map('absint', $_POST['select_events'])) : maybe_serialize(array()); + $mobile_menu = isset($_POST['mobile_menu']) ? array_map('sanitize_text_field', $_POST['mobile_menu']) : array(); + + update_user_meta($user_id, '_mobile_menu', $mobile_menu); + // Check if current user can edit other users. if( $user_id && ! current_user_can( 'edit_user', $user_id ) ) { if( get_current_user_id() !== $user_id ) { @@ -121,11 +126,13 @@ public function update_api_key(){ if( 0 < $key_id ) { $data = array( - 'user_id' => $user_id, - 'description' => $description, - 'permissions' => $permissions, - 'event_id' => $event_id, - 'date_expires' => $date_expires, + 'user_id' => $user_id, + 'description' => $description, + 'permissions' => $permissions, + 'event_id' => $event_id, + 'date_expires' => $date_expires, + 'event_show_by' => $event_show_by, + 'selected_events' => $select_events, ); $wpdb->update( @@ -138,6 +145,8 @@ public function update_api_key(){ '%s', '%d', '%s', + '%s', + '%s', ), array( '%d' ) ); @@ -146,6 +155,7 @@ public function update_api_key(){ $response['consumer_key'] = ''; $response['consumer_secret'] = ''; $response['message'] = __( 'API Key updated successfully.', 'wpem-rest-api' ); + $response['selected_events'] = maybe_unserialize($select_events); } else { $app_key = wp_rand(); $consumer_key = 'ck_' . sha1(wp_rand()); @@ -162,6 +172,8 @@ public function update_api_key(){ 'truncated_key' => substr($consumer_key, -7), 'date_created' => current_time( 'mysql' ) , 'date_expires' => $date_expires, + 'event_show_by' => $event_show_by, + 'selected_events' => $select_events, ); $wpdb->insert( $wpdb->prefix . 'wpem_rest_api_keys', @@ -177,6 +189,8 @@ public function update_api_key(){ '%s', '%s', '%s', + '%s', + '%s', ) ); $key_id = $wpdb->insert_id; @@ -186,6 +200,8 @@ public function update_api_key(){ $response['app_key'] = $app_key; $response['message'] = __( 'API Key generated successfully. Make sure to copy your new keys now as the secret key will be hidden once you leave this page.', 'wpem-rest-api' ); $response['revoke_url'] = '' . __('I have Copied the Keys', 'wpem-rest-api') . '

' . __('Revoke key', 'wpem-rest-api') . ''; + $response['event_show_by'] = $event_show_by; + $response['selected_events'] = maybe_unserialize($select_events); } } catch ( Exception $e ) { wp_send_json_error( array( 'message' => $e->getMessage() ) ); diff --git a/admin/wpem-rest-api-keys.php b/admin/wpem-rest-api-keys.php index 2917116..68d2868 100644 --- a/admin/wpem-rest-api-keys.php +++ b/admin/wpem-rest-api-keys.php @@ -143,7 +143,7 @@ private static function get_key_data( $key_id ){ $key = $wpdb->get_row( $wpdb->prepare( - "SELECT key_id, user_id, event_id, description, permissions, truncated_key, last_access, date_expires + "SELECT key_id, user_id, event_id, description, permissions, truncated_key, last_access, event_show_by, selected_events, date_expires FROM {$wpdb->prefix}wpem_rest_api_keys WHERE key_id = %d", $key_id diff --git a/admin/wpem-rest-api-settings.php b/admin/wpem-rest-api-settings.php index e3cffce..ddb204d 100644 --- a/admin/wpem-rest-api-settings.php +++ b/admin/wpem-rest-api-settings.php @@ -140,10 +140,9 @@ public function output() {
diff --git a/assets/js/admin.js b/assets/js/admin.js index b33d68d..35c3c8b 100644 --- a/assets/js/admin.js +++ b/assets/js/admin.js @@ -4,7 +4,8 @@ var WPEMRestAPIAdmin = (function () { jQuery("#update_api_key").on("click", WPEMRestAPIAdmin.actions.saveApiKey), jQuery("select#key_user").chosen(), jQuery("select#event_id").chosen(), - jQuery("input#date_expires").datepicker({ dateFormat: "yy-mm-dd" }), + jQuery("#select_events").chosen(); + jQuery("input#date_expires").datepicker({dateFormat: "yy-mm-dd",minDate: 0}), jQuery("table#app-branding-color-dark").hide(), jQuery(".wpem-app-branding-mode .app-branding-mode .wpem-light-mode").click(function () { jQuery(".wpem-app-branding-mode").removeClass("wpem-dark-mode").addClass("wpem-light-mode"), jQuery("table#app-branding-color").show(), jQuery("table#app-branding-color-dark").hide(); @@ -24,6 +25,40 @@ var WPEMRestAPIAdmin = (function () { }, 500)); }, }); + + // show events by radio button toggle + toggleEventsRow(); + jQuery('input[name="event_show_by"]').change(function() { + + toggleEventsRow(); + }); + + function toggleEventsRow() { + if (jQuery('input[name="event_show_by"]:checked').val() === 'selected') { + jQuery('#select-events-row').show(); + jQuery('#select_events').chosen('destroy').chosen(); + } else { + jQuery('#select-events-row').hide(); + } + } + jQuery('.wp_event_manager_upload_file_button').on('click', function(e){ + e.preventDefault(); + var button = jQuery(this); + var input = button.closest('.file_url').find('#wpem_rest_api_app_logo'); + console.log(input); + var custom_uploader = wp.media({ + title: 'Select or Upload Image', + button: { + text: 'Use this image' + }, + multiple: false + }) + .on('select', function() { + var attachment = custom_uploader.state().get('selection').first().toJSON(); + input.val(attachment.url); // Set image URL in input + }) + .open(); + }); }, actions: { saveApiKey: function (e) { @@ -44,6 +79,11 @@ var WPEMRestAPIAdmin = (function () { event_id: jQuery("#event_id").val(), date_expires: jQuery("#date_expires").val(), restrict_check_in: jQuery('input[name="restrict_check_in"]').attr("checked") ? 0 : 1, + event_show_by: jQuery('input[name="event_show_by"]:checked').val(), + select_events: jQuery('#select_events').val() || [], + mobile_menu: jQuery('input[name="mobile_menu[]"]:checked').map(function () { + return this.value; + }).get() }, beforeSend: function (e) {}, success: function (e) { @@ -55,11 +95,19 @@ var WPEMRestAPIAdmin = (function () { ? (jQuery("#api-keys-options", a.el).parent().remove(), jQuery("p.submit", a.el).empty().append(e.data.revoke_url), jQuery("#key-fields p.submit", a.el).before(wp.template("api-keys-template")({ consumer_key: e.data.consumer_key, consumer_secret: e.data.consumer_secret, app_key: e.data.app_key }))) - : (jQuery("#key_description", a.el).val(e.data.description), jQuery("#key_user", a.el).val(e.data.user_id), jQuery("#key_permissions", a.el).val(e.data.permissions))) + : (jQuery("#key_description", a.el).val(e.data.description), jQuery("#key_user", a.el).val(e.data.user_id), jQuery("#key_permissions", a.el).val(e.data.permissions),jQuery('input[name="event_show_by"][value="' + e.data.event_show_by + '"]').prop('checked', true), + jQuery('#select_events').val(e.data.selected_events).trigger('chosen:updated'))) : jQuery("h2, h3", a.el) .first() .append('

' + e.errorThrown + "

"); - }, + + if (e.data.mobile_menu) { + jQuery('input[name="mobile_menu[]"]').prop('checked', false); + e.data.mobile_menu.forEach(function (val) { + jQuery('input[name="mobile_menu[]"][value="' + val + '"]').prop('checked', true); + }); + } + }, error: function (e, t, n) { jQuery("h2, h3", a.el) .first() diff --git a/assets/js/admin.min.js b/assets/js/admin.min.js index 4a8907c..cb522e9 100644 --- a/assets/js/admin.min.js +++ b/assets/js/admin.min.js @@ -1 +1 @@ -var WPEMRestAPIAdmin={init:function(){var e;jQuery("#update_api_key").on("click",WPEMRestAPIAdmin.actions.saveApiKey),jQuery("select#key_user").chosen(),jQuery("select#event_id").chosen(),jQuery("input#date_expires").datepicker({dateFormat:"yy-mm-dd"}),jQuery("table#app-branding-color-dark").hide(),jQuery(".wpem-app-branding-mode .app-branding-mode .wpem-light-mode").click((function(){jQuery(".wpem-app-branding-mode").removeClass("wpem-dark-mode").addClass("wpem-light-mode"),jQuery("table#app-branding-color").show(),jQuery("table#app-branding-color-dark").hide()})),jQuery(".wpem-app-branding-mode .app-branding-mode .wpem-dark-mode").click((function(){jQuery("table#app-branding-color").hide(),jQuery("table#app-branding-color-dark").show(),jQuery(".wpem-app-branding-mode").removeClass("wpem-light-mode").addClass("wpem-dark-mode")})),jQuery("#update_app_branding").on("click",WPEMRestAPIAdmin.actions.saveAppBranding),jQuery(".wpem-colorpicker").wpColorPicker({defaultColor:!0,change:function(a,r){a.target,clearTimeout(e),e=setTimeout((function(){WPEMRestAPIAdmin.actions.changeBrightness(a,r.toString())}),500)}})},actions:{saveApiKey:function(e){e.preventDefault();var a=this;jQuery("#api_key_loader").show(),jQuery("#update_api_key").attr("disabled",!0),jQuery.ajax({type:"POST",url:wpem_rest_api_admin.ajaxUrl,data:{action:"save_rest_api_keys",security:wpem_rest_api_admin.save_api_nonce,key_id:jQuery("#key_id").val(),description:jQuery("#key_description").val(),user:jQuery("#key_user").val(),permissions:jQuery("#key_permissions").val(),event_id:jQuery("#event_id").val(),date_expires:jQuery("#date_expires").val(),restrict_check_in:jQuery('input[name="restrict_check_in"]').attr("checked")?0:1},beforeSend:function(e){},success:function(e){e.success?(jQuery("h2, h3",a.el).first().html('

'+e.data.message+"

"),0

'+e.errorThrown+"

")},error:function(e,r,n){jQuery("h2, h3",a.el).first().append('

'+n+"

")},complete:function(e,a){jQuery("#api_key_loader").hide(),jQuery("#update_api_key").attr("disabled",!1)}})},saveAppBranding:function(e){e.preventDefault();var a="",r=jQuery("#app-branding-color").is(":visible"),n=jQuery("#app-branding-color-dark").is(":visible");r?a="light":n&&(a="dark"),jQuery.ajax({type:"POST",url:wpem_rest_api_admin.ajaxUrl,data:{action:"save_app_branding",security:wpem_rest_api_admin.save_app_branding_nonce,wpem_primary_color:jQuery('input[name="wpem_primary_color"]').val(),wpem_success_color:jQuery('input[name="wpem_success_color"]').val(),wpem_info_color:jQuery('input[name="wpem_info_color"]').val(),wpem_warning_color:jQuery('input[name="wpem_warning_color"]').val(),wpem_danger_color:jQuery('input[name="wpem_danger_color"]').val(),wpem_primary_dark_color:jQuery('input[name="wpem_primary_dark_color"]').val(),wpem_success_dark_color:jQuery('input[name="wpem_success_dark_color"]').val(),wpem_info_dark_color:jQuery('input[name="wpem_info_dark_color"]').val(),wpem_warning_dark_color:jQuery('input[name="wpem_warning_dark_color"]').val(),wpem_danger_dark_color:jQuery('input[name="wpem_danger_dark_color"]').val(),active_mode:a},beforeSend:function(e){},success:function(e){jQuery(".wpem-branding-status").html('

'+e.data.message+"

"),jQuery(".update_app_branding_message").html('
Your preferred color for your app branding has been successfully saved.
'),"dark"==e.data.mode&&(jQuery("table#app-branding-color").hide(),jQuery("table#app-branding-color-dark").show())},error:function(e,a,r){jQuery(".wpem-branding-status").html('

'+r+"

"),jQuery(".update_app_branding_message").html('
Your preferred color for your app branding has not been successfully saved.
')},complete:function(e,a){}})},changeBrightness:function(e,a){var r=e.target.name,n=jQuery(e.target).parents("table").attr("id");jQuery.ajax({url:wpem_rest_api_admin.ajaxUrl,type:"POST",dataType:"HTML",data:{action:"change_brighness_color",color:a},success:function(e){const a=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'");jQuery("#"+n+" tbody tr td#"+r).html(a)}})}}};jQuery(document).ready((function(e){WPEMRestAPIAdmin.init()})); \ No newline at end of file +var WPEMRestAPIAdmin={init:function(){var e;function a(){"selected"===jQuery('input[name="event_show_by"]:checked').val()?(jQuery("#select-events-row").show(),jQuery("#select_events").chosen("destroy").chosen()):jQuery("#select-events-row").hide()}jQuery("#update_api_key").on("click",WPEMRestAPIAdmin.actions.saveApiKey),jQuery("select#key_user").chosen(),jQuery("select#event_id").chosen(),jQuery("#select_events").chosen(),jQuery("input#date_expires").datepicker({dateFormat:"yy-mm-dd",minDate:0}),jQuery("table#app-branding-color-dark").hide(),jQuery(".wpem-app-branding-mode .app-branding-mode .wpem-light-mode").click(function(){jQuery(".wpem-app-branding-mode").removeClass("wpem-dark-mode").addClass("wpem-light-mode"),jQuery("table#app-branding-color").show(),jQuery("table#app-branding-color-dark").hide()}),jQuery(".wpem-app-branding-mode .app-branding-mode .wpem-dark-mode").click(function(){jQuery("table#app-branding-color").hide(),jQuery("table#app-branding-color-dark").show(),jQuery(".wpem-app-branding-mode").removeClass("wpem-light-mode").addClass("wpem-dark-mode")}),jQuery("#update_app_branding").on("click",WPEMRestAPIAdmin.actions.saveAppBranding),jQuery(".wpem-colorpicker").wpColorPicker({defaultColor:!0,change:function(a,r){a.target,clearTimeout(e),e=setTimeout(function(){WPEMRestAPIAdmin.actions.changeBrightness(a,r.toString())},500)}}),a(),jQuery('input[name="event_show_by"]').change(function(){a()}),jQuery(".wp_event_manager_upload_file_button").on("click",function(e){e.preventDefault();var a=jQuery(this).closest(".file_url").find("#wpem_rest_api_app_logo");console.log(a);var r=wp.media({title:"Select or Upload Image",button:{text:"Use this image"},multiple:!1}).on("select",function(){var e=r.state().get("selection").first().toJSON();a.val(e.url)}).open()})},actions:{saveApiKey:function(e){e.preventDefault();var a=this;jQuery("#api_key_loader").show(),jQuery("#update_api_key").attr("disabled",!0),jQuery.ajax({type:"POST",url:wpem_rest_api_admin.ajaxUrl,data:{action:"save_rest_api_keys",security:wpem_rest_api_admin.save_api_nonce,key_id:jQuery("#key_id").val(),description:jQuery("#key_description").val(),user:jQuery("#key_user").val(),permissions:jQuery("#key_permissions").val(),event_id:jQuery("#event_id").val(),date_expires:jQuery("#date_expires").val(),restrict_check_in:jQuery('input[name="restrict_check_in"]').attr("checked")?0:1,event_show_by:jQuery('input[name="event_show_by"]:checked').val(),select_events:jQuery("#select_events").val()||[],mobile_menu:jQuery('input[name="mobile_menu[]"]:checked').map(function(){return this.value}).get()},beforeSend:function(e){},success:function(e){e.success?(jQuery("h2, h3",a.el).first().html('

'+e.data.message+"

"),0

'+e.errorThrown+"

"),e.data.mobile_menu&&(jQuery('input[name="mobile_menu[]"]').prop("checked",!1),e.data.mobile_menu.forEach(function(e){jQuery('input[name="mobile_menu[]"][value="'+e+'"]').prop("checked",!0)}))},error:function(e,r,n){jQuery("h2, h3",a.el).first().append('

'+n+"

")},complete:function(e,a){jQuery("#api_key_loader").hide(),jQuery("#update_api_key").attr("disabled",!1)}})},saveAppBranding:function(e){e.preventDefault();var a="",r=jQuery("#app-branding-color").is(":visible"),n=jQuery("#app-branding-color-dark").is(":visible");r?a="light":n&&(a="dark"),jQuery.ajax({type:"POST",url:wpem_rest_api_admin.ajaxUrl,data:{action:"save_app_branding",security:wpem_rest_api_admin.save_app_branding_nonce,wpem_primary_color:jQuery('input[name="wpem_primary_color"]').val(),wpem_success_color:jQuery('input[name="wpem_success_color"]').val(),wpem_info_color:jQuery('input[name="wpem_info_color"]').val(),wpem_warning_color:jQuery('input[name="wpem_warning_color"]').val(),wpem_danger_color:jQuery('input[name="wpem_danger_color"]').val(),wpem_primary_dark_color:jQuery('input[name="wpem_primary_dark_color"]').val(),wpem_success_dark_color:jQuery('input[name="wpem_success_dark_color"]').val(),wpem_info_dark_color:jQuery('input[name="wpem_info_dark_color"]').val(),wpem_warning_dark_color:jQuery('input[name="wpem_warning_dark_color"]').val(),wpem_danger_dark_color:jQuery('input[name="wpem_danger_dark_color"]').val(),active_mode:a},beforeSend:function(e){},success:function(e){jQuery(".wpem-branding-status").html('

'+e.data.message+"

"),jQuery(".update_app_branding_message").html('
Your preferred color for your app branding has been successfully saved.
'),"dark"==e.data.mode&&(jQuery("table#app-branding-color").hide(),jQuery("table#app-branding-color-dark").show())},error:function(e,a,r){jQuery(".wpem-branding-status").html('

'+r+"

"),jQuery(".update_app_branding_message").html('
Your preferred color for your app branding has not been successfully saved.
')},complete:function(e,a){}})},changeBrightness:function(e,a){var r=e.target.name,n=jQuery(e.target).parents("table").attr("id");jQuery.ajax({url:wpem_rest_api_admin.ajaxUrl,type:"POST",dataType:"HTML",data:{action:"change_brighness_color",color:a},success:function(e){const a=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'");jQuery("#"+n+" tbody tr td#"+r).html(a)}})}}};jQuery(document).ready(function(e){WPEMRestAPIAdmin.init()}); \ No newline at end of file diff --git a/includes/rest-api/wpem-rest-app-branding.php b/includes/wpem-rest-app-branding.php similarity index 100% rename from includes/rest-api/wpem-rest-app-branding.php rename to includes/wpem-rest-app-branding.php diff --git a/includes/rest-api/wpem-rest-authentication.php b/includes/wpem-rest-authentication.php similarity index 66% rename from includes/rest-api/wpem-rest-authentication.php rename to includes/wpem-rest-authentication.php index 388547e..c062aa5 100644 --- a/includes/rest-api/wpem-rest-authentication.php +++ b/includes/wpem-rest-authentication.php @@ -596,12 +596,12 @@ public function check_user_permissions( $result, $server, $request ) { */ public function register_routes() { register_rest_route( - 'wpem-auth', - '/appkey' , + 'wpem', + '/applogin' , array( array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'perform_app_key_authentication' ), + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'perform_user_authentication' ), 'permission_callback' => '__return_true' ), ) @@ -626,7 +626,7 @@ public function register_routes() { */ public function perform_login_authentication($request){ $params = $request->get_json_params(); - $username = isset($params['username']) ? sanitize_text_field($params['username']) : ''; + $username = isset($params['username']) ? trim($params['username']) : ''; $password = isset($params['password']) ? $params['password'] : ''; $response = array(); if( !empty( $username ) && !empty($password)){ @@ -659,7 +659,7 @@ public function perform_login_authentication($request){ $response_data['data'] = array( 'user_info' => $key_data, ); - return wp_send_json($response_data); + return $response_data; } } else{ return parent::prepare_error_for_response(400); @@ -671,34 +671,259 @@ public function perform_login_authentication($request){ * * @since 1.0.0 */ - public function perform_app_key_authentication( $request ){ - global $wpdb; - if( isset( $_GET['key'] ) && !empty( $_GET['key'] ) ){ - $app_key = sanitize_text_field( $_GET['key'] ); - - $key_data = $wpdb->get_row( - $wpdb->prepare( - " - SELECT key_id, app_key, user_id, permissions, consumer_key, consumer_secret, nonces, date_expires - FROM {$wpdb->prefix}wpem_rest_api_keys - WHERE app_key = %s - ", - $app_key - ) - ); - if( !empty($key_data->date_expires ) && strtotime( $key_data->date_expires ) >= strtotime( date('Y-m-d H:i:s') ) ){ - $key_data->expiry = false; - }else{ - $key_data->expiry = true; - } - if( empty( $key_data ) ) + public function perform_user_authentication($request) { + $params = $request->get_json_params(); + $username = isset($params['username']) ? trim($params['username']) : ''; + $password = isset($params['password']) ? $params['password'] : ''; + $response = array(); + + if (!empty($username) && !empty($password)) { + $user = wp_authenticate($username, $password); + if (is_wp_error($user)) { return parent::prepare_error_for_response(401); - $response_data = self::prepare_error_for_response( 200 ); - $response_data['data'] = array( - 'user_info' => $key_data, - ); - return wp_send_json($response_data); + } else { + global $wpdb; + + $user_id = $user->ID; + + $token = $this->wpem_generate_jwt_token($user->ID, $password); + $is_matchmaking = get_user_meta($user_id, '_matchmaking_profile', true); + $enable_matchmaking = get_option('enable_matchmaking', false) ? 1 : 0; + + $all_mobile_pages = array('dashboard', 'attendees', 'guest_list', 'orders', 'arrivals'); + $user_mobile_menu = get_user_meta($user_id, '_mobile_menu', true); + $user_mobile_menu = is_array($user_mobile_menu) ? $user_mobile_menu : []; + + $mobile_menu_status = array(); + foreach ($all_mobile_pages as $page) { + $mobile_menu_status[$page] = in_array($page, $user_mobile_menu) ? 1 : 0; + } + + // Get all user data from meta + $user_email = get_user_meta($user_id, 'user_email', true); + $first_name = get_user_meta($user_id, 'first_name', true); + $last_name = get_user_meta($user_id, 'last_name', true); + $user_login = get_user_meta($user_id, 'user_login', true); + + $data = array( + 'token' => $token, + 'user' => array( + 'user_id' => $user_id, + 'user_email' => $user_email, + 'first_name' => $first_name, + 'last_name' => $last_name, + 'username' => $user_login, + 'matchmaking_profile' => $is_matchmaking, + 'enable_matchmaking' => $enable_matchmaking, + 'mobile_menu' => $mobile_menu_status, + ) + ); + + if ($is_matchmaking && $enable_matchmaking) { + $user_meta = get_user_meta($user_id); + $organization_logo = get_user_meta( $user_id, '_organization_logo', true ); + $organization_logo = maybe_unserialize( $organization_logo ); + if (is_array($organization_logo)) { + $organization_logo = reset($organization_logo); // get first value in the array + } + $organization_logo = $organization_logo ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/organisation-icon.jpg'; + $meta = get_user_meta($user_id, '_available_for_meeting', true); + $meeting_available = ($meta !== '' && $meta !== null) ? ((int)$meta === 0 ? 0 : 1) : 1; + + $photo = get_wpem_user_profile_photo($user_id) ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + + // --- Skills --- + $skills_slugs = []; + $skills_arr = maybe_unserialize(isset($user_meta['_skills'][0]) ? $user_meta['_skills'][0] : []); + if (is_array($skills_arr)) { + foreach ($skills_arr as $skill) { + $term = get_term_by('slug', $skill, 'event_registration_skills'); + if (!$term) { + $term = get_term_by('name', $skill, 'event_registration_skills'); + } + if (!$term) { + $term = get_term_by('id', $skill, 'event_registration_skills'); + } + if ($term) { + $skills_slugs[] = $term->slug; + } + } + } + $skills_slugs = array_filter($skills_slugs); + $skills_serialized = serialize($skills_slugs); + + // --- Interests --- + $interests_slugs = []; + $interests_arr = maybe_unserialize(isset($user_meta['_interests'][0]) ? $user_meta['_interests'][0] : []); + if (is_array($interests_arr)) { + foreach ($interests_arr as $interest) { + $term = get_term_by('slug', $interest, 'event_registration_interests'); + if (!$term) { + $term = get_term_by('name', $interest, 'event_registration_interests'); + } + if (!$term) { + $term = get_term_by('id', $interest, 'event_registration_interests'); + } + if ($term) { + $interests_slugs[] = $term->slug; + } + } + } + + $interests_slugs = array_filter($interests_slugs); + $interests_serialized = serialize($interests_slugs); + $profession = get_user_meta($user_id, '_profession', true) ?: ''; + if (!empty($profession)) { + $term = get_term_by('name', $profession, 'event_registration_professions'); + if (!$term) { + $term = get_term_by('slug', $profession, 'event_registration_professions'); + } + $profession_slug = $term ? $term->slug : $profession; + } else { + $profession_slug = ''; + } + + // Get matchmaking data from user meta instead of custom table + $matchmaking_details = array( + 'attendeeId' => $user_id, + 'first_name' => $first_name, + 'last_name' => $last_name, + 'email' => $user->user_email, + 'display_name' => $user->display_name, + 'profile_photo' => $photo, + 'profession' => $profession_slug, + 'experience' => get_user_meta($user_id, '_experience', true) ?: '', + 'company_name' => get_user_meta($user_id, '_company_name', true) ?: '', + 'country' => get_user_meta($user_id, '_country', true) ?: '', + 'city' => get_user_meta($user_id, '_city', true) ?: '', + 'about' => get_user_meta($user_id, '_about', true) ?: '', + 'skills' => isset($user_meta['_skills'][0]) ? $user_meta['_skills'][0] : array(), + 'interests' => isset($user_meta['_interests'][0]) ? $user_meta['_interests'][0] : array(), + 'organization_name' => get_user_meta($user_id, '_organization_name', true) ?: '', + 'organization_logo' => $organization_logo, + 'organization_city' => get_user_meta($user_id, '_organization_city', true) ?: '', + 'organization_country' => get_user_meta($user_id, '_organization_country', true) ?: '', + 'organization_description' => get_user_meta($user_id, '_organization_description', true) ?: '', + 'message_notification' => get_user_meta($user_id, '_message_notification', true) ?: '', + 'approve_profile_status' => get_user_meta($user_id, '_approve_profile_status', true) ?: '', + 'matchmaking_profile' => isset($user_meta['_matchmaking_profile'][0]) ? (int)$user_meta['_matchmaking_profile'][0] : 0, + 'approve_profile_status' => isset($user_meta['_approve_profile_status'][0]) ? (int)$user_meta['_approve_profile_status'][0] : 0, + 'wpem_meeting_request_mode' => isset($user_meta['_wpem_meeting_request_mode'][0]) ? $user_meta['_wpem_meeting_request_mode'][0] : 'approval', + 'available_for_meeting' => (int)$meeting_available, + ); + + $data['user']['matchmaking_details'] = $matchmaking_details; + } + + // Keep the API key check logic unchanged + $key_data = $wpdb->get_row( + $wpdb->prepare( + "SELECT * FROM {$wpdb->prefix}wpem_rest_api_keys WHERE user_id = %s", + $user_id + ) + ); + + if (!empty($key_data)) { + if (!empty($key_data->date_expires) && strtotime($key_data->date_expires) >= strtotime(date('Y-m-d H:i:s'))) { + $key_data->expiry = false; + } else { + $key_data->expiry = true; + } + $data['organizer_info'] = $key_data; + } + + if (empty($key_data) && !get_user_meta($user_id, '_matchmaking_profile', true)) { + return parent::prepare_error_for_response(405); + } + + $response_data = parent::prepare_error_for_response(200); + $response_data['data'] = $data; + return $response_data; + } + } else { + return parent::prepare_error_for_response(400); + } + } + + /** + * This function will used to generate jwt token for individual user + * @since 1.0.9 + */ + public function wpem_generate_jwt_token($user_id, $password) { + $user = get_userdata($user_id); + if (!$user) return false; + + // Header and payload + $header = wpem_base64url_encode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'])); + + $payload = wpem_base64url_encode(json_encode([ + 'iss' => get_bloginfo('url'), + 'user' => [ + 'id' => $user->ID, + 'username' => $user->user_login, + 'password' => $password + ] + ])); + + // Signature + $signature = wpem_base64url_encode(hash_hmac('sha256', "$header.$payload", JWT_SECRET_KEY, true)); + + // Return standard JWT format + return $header . '.' . $payload . '.' . $signature; + } + + /** + * This function will used to check authentication while use the match making apis + * @since 1.1.0 + */ + public function check_authentication( $request ) { + $auth_header = $this->get_authorization_header(); + + if ( preg_match( '/Bearer\s(\S+)/', $auth_header, $matches ) ) { + $token = $matches[1]; + + return $this->validate_jwt_token($token); + } + + return new WP_Error( 'rest_forbidden', __( 'Missing or invalid authorization token.', 'textdomain' ), array( 'status' => 401 ) ); + } + /** + * This function will used to check validation of jwt token + * @since 1.1.0 + */ + private function validate_jwt_token($token) { + $parts = explode('.', $token); + if (count($parts) !== 3) { + return new WP_Error( 'rest_forbidden', __( 'Malformed token.', 'textdomain' ), array( 'status' => 401 ) ); } + + list($header_b64, $payload_b64, $signature_b64) = $parts; + + // Recalculate the signature + $expected_signature = wpem_base64url_encode( + hash_hmac('sha256', "$header_b64.$payload_b64", JWT_SECRET_KEY, true) + ); + + // Timing-attack-safe comparison + if (!hash_equals($expected_signature, $signature_b64)) { + return new WP_Error( 'rest_forbidden', __( 'Invalid token signature.', 'textdomain' ), [ 'status' => 401 ] ); + } + + // Decode payload + $payload_json = base64_decode(strtr($payload_b64, '-_', '+/')); + $payload = json_decode($payload_json, true); + + if (json_last_error() !== JSON_ERROR_NONE || !isset($payload['user']['id'])) { + return new WP_Error( 'rest_forbidden', __( 'Invalid token payload.', 'textdomain' ), [ 'status' => 401 ] ); + } + + // Optionally: check expiration + if (isset($payload['exp']) && time() > $payload['exp']) { + return new WP_Error( 'rest_forbidden', __( 'Token has expired.', 'textdomain' ), [ 'status' => 401 ] ); + } + // Return decoded payload if needed + return true; } + } -new WPEM_REST_Authentication(); \ No newline at end of file +new WPEM_REST_Authentication(); diff --git a/includes/rest-api/wpem-rest-conroller.php b/includes/wpem-rest-conroller.php similarity index 100% rename from includes/rest-api/wpem-rest-conroller.php rename to includes/wpem-rest-conroller.php diff --git a/includes/rest-api/wpem-rest-crud-controller.php b/includes/wpem-rest-crud-controller.php similarity index 86% rename from includes/rest-api/wpem-rest-crud-controller.php rename to includes/wpem-rest-crud-controller.php index 7b80211..e721667 100644 --- a/includes/rest-api/wpem-rest-crud-controller.php +++ b/includes/wpem-rest-crud-controller.php @@ -388,7 +388,7 @@ protected function get_objects( $query_args ) { * @param WP_REST_Request $request Full details about the request. * @return WP_Error|WP_REST_Response */ - public function get_items( $request ) { + /*public function get_items( $request ) { $auth_check = $this->wpem_check_authorized_user(); if($auth_check){ return self::prepare_error_for_response(405); @@ -426,7 +426,55 @@ public function get_items( $request ) { ); return wp_send_json($response_data); } - } + }*/ + + public function get_items( $request ) { + global $wpdb; + $auth_check = $this->wpem_check_authorized_user(); + if ($auth_check) { + return self::prepare_error_for_response(405); + } else { + /*$settings_row = $wpdb->get_row("SELECT event_show_by, selected_events FROM {$wpdb->prefix}wpem_rest_api_keys LIMIT 1", ARRAY_A); + + $event_show_by = isset($settings_row['event_show_by']) ? $settings_row['event_show_by'] : ''; + $selected_events = isset($settings_row['selected_events']) ? maybe_unserialize($settings_row['selected_events']) : [];*/ + + $query_args = $this->prepare_objects_query($request); + + /*if ($event_show_by === 'selected' && !empty($selected_events) && is_array($selected_events)) { + $query_args['post__in'] = array_map('intval', $selected_events); + $query_args['orderby'] = 'post__in'; + unset($query_args['author']); + }*/ + + $query_results = $this->get_objects($query_args); + + $objects = array(); + foreach ($query_results['objects'] as $object) { + $object_id = isset($object->ID) ? $object->ID : $object->get_id(); + + if (!wpem_rest_api_check_post_permissions($this->post_type, 'read', $object_id)) { + continue; + } + + $data = $this->prepare_object_for_response($object, $request); + $objects[] = $this->prepare_response_for_collection($data); + } + + $page = isset($query_args['paged']) ? (int) $query_args['paged'] : 1; + $total_pages = ceil($query_results['total'] / $query_args['posts_per_page']); + + $response_data = self::prepare_error_for_response(200); + $response_data['data'] = array( + 'total_post_count' => isset($query_results['total']) ? $query_results['total'] : null, + 'current_page' => $page, + 'last_page' => max(1, $total_pages), + 'total_pages' => $total_pages, + $this->rest_base => $objects, + ); + return wp_send_json($response_data); + } + } /** * Delete a single item. @@ -652,61 +700,82 @@ public function wpem_check_authorized_user() { // Get the authorization header global $wpdb; $headers = getallheaders(); - $auth_header = isset($headers['Authorization']) ? $headers['Authorization'] : ''; - - if(empty($auth_header)) { - $headers = apache_request_headers(); - // Ensure case insensitivity - $auth_header = ''; - foreach ($headers as $key => $value) { - if (strtolower($key) === 'authorization') { - $auth_header = $value; - break; - } - } + $token = ''; + + // First try standard header + if (isset($headers['Authorization'])) { + $token = trim(str_replace('Bearer', '', $headers['Authorization'])); + } + // Try for some server environments + elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) { + $token = trim(str_replace('Bearer', '', $_SERVER['HTTP_AUTHORIZATION'])); + } + // NGINX or fastcgi_pass may use this + elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $token = trim(str_replace('Bearer', '', $_SERVER['REDIRECT_HTTP_AUTHORIZATION'])); + } + if(empty($token)) { + return WPEM_REST_CRUD_Controller::prepare_error_for_response(405); } - // Check if authorization header is provided - if (!$auth_header) { + $user_data = self::wpem_validate_jwt_token($token); + if (!$user_data) { return self::prepare_error_for_response(405); } + $user = get_userdata($user_data['id']); - // Handle Basic Auth - if (strpos($auth_header, 'Basic ') === 0) { - $auth = base64_decode(substr($auth_header, 6)); - list($consumer_key, $consumer_secret) = explode(':', $auth); - // Validate the credentials - if ($consumer_key && $consumer_secret) { - $user_info = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wpem_rest_api_keys WHERE consumer_key = '$consumer_key' AND consumer_secret = '$consumer_secret'")); + if($user){ + if (!wp_check_password($user_data['password'], $user->user_pass, $user->ID)) { + return self::prepare_error_for_response(405); + } else { + $user_info = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wpem_rest_api_keys WHERE user_id = $user->ID ")); if($user_info){ - $user = get_userdata($user_info->user_id); - if($user){ - $date_expires = date('Y-m-d', strtotime($user_info->date_expires)); - if( $user_info->permissions == 'write'){ - return self::prepare_error_for_response(203); - } else if( $date_expires < date('Y-m-d') ){ - return self::prepare_error_for_response(503); - } else { - // Get ecosystem data - $ecosystem_info = get_wpem_rest_api_ecosystem_info(); - if( !is_array( $ecosystem_info ) ) { - return self::prepare_error_for_response(403, array("Plugin Name"=>$ecosystem_info)); - } - return false; - } + $date_expires = date('Y-m-d', strtotime($user_info->date_expires)); + if( $user_info->permissions == 'write'){ + return self::prepare_error_for_response(203); + } else if( $date_expires < date('Y-m-d') ){ + return self::prepare_error_for_response(503); } else { - return self::prepare_error_for_response(405); + return false; } } else { return self::prepare_error_for_response(405); } - } else { - return self::prepare_error_for_response(405); } } else { return self::prepare_error_for_response(405); } } + + /** + * This function is used to verify token sent in api header + * @since 1.0.9 + */ + public static function wpem_validate_jwt_token($token) { + $parts = explode('.', $token); + if (count($parts) !== 3) return false; + + list($header, $payload, $signature) = $parts; + + $expected_signature = wpem_base64url_encode( + hash_hmac('sha256', "$header.$payload", JWT_SECRET_KEY, true) + ); + + if (!hash_equals($expected_signature, $signature)) { + return false; + } + + $payload_json = wpem_base64url_decode($payload); + $payload_data = json_decode($payload_json, true); + if (json_last_error() !== JSON_ERROR_NONE || !isset($payload_data['user'])) { + return false; + } + + // Clean up keys (defensive) + $user = array_change_key_case(array_map('trim', $payload_data['user'])); + + return $user; + } /** * Prepares the error for the REST response. @@ -738,4 +807,4 @@ public static function prepare_error_for_response( $code, $data = array()) { return null; // Or handle the case where code 400 is not found } } -} +} \ No newline at end of file diff --git a/includes/rest-api/wpem-rest-ecosystem-controller.php b/includes/wpem-rest-ecosystem-controller.php similarity index 100% rename from includes/rest-api/wpem-rest-ecosystem-controller.php rename to includes/wpem-rest-ecosystem-controller.php diff --git a/includes/rest-api/wpem-rest-events-controller.php b/includes/wpem-rest-events-controller.php similarity index 90% rename from includes/rest-api/wpem-rest-events-controller.php rename to includes/wpem-rest-events-controller.php index bb4702b..74c459c 100644 --- a/includes/rest-api/wpem-rest-events-controller.php +++ b/includes/wpem-rest-events-controller.php @@ -204,7 +204,8 @@ public function prepare_object_for_response( $object, $request ) { */ protected function prepare_objects_query( $request ) { $args = parent::prepare_objects_query( $request ); - + // Get current user ID + $current_user_id = wpem_rest_get_current_user_id(); // Set post_status. if( isset( $request['status'] ) && $request['status'] !== 'any' ) { $args['post_status'] = $request['status']; @@ -237,10 +238,31 @@ protected function prepare_objects_query( $request ) { $args['tax_query'] = $tax_query; // WPCS: slow query ok. } - $args['author'] = get_current_user_id(); $args['post_type'] = $this->post_type; + // --- Event selection logic --- + if ($current_user_id) { + global $wpdb; + $settings_row = $wpdb->get_row( + $wpdb->prepare( + "SELECT event_show_by, selected_events FROM {$wpdb->prefix}wpem_rest_api_keys WHERE user_id = %d", + $current_user_id + ), + ARRAY_A + ); + $event_show_by = isset($settings_row['event_show_by']) ? $settings_row['event_show_by'] : ''; + $selected_events = isset($settings_row['selected_events']) ? maybe_unserialize($settings_row['selected_events']) : []; - return $args; + if ($event_show_by === 'selected' && !empty($selected_events) && is_array($selected_events)) { + $args['post__in'] = array_map('intval', $selected_events); + $args['orderby'] = 'post__in'; + unset($args['author']); + } else { + $args['author'] = $current_user_id; + } + } else { + $args['author'] = $current_user_id; + } + return $args; } /** @@ -305,7 +327,11 @@ protected function get_images( $event ) { protected function get_event_data( $event, $context = 'view' ) { $meta_data = get_post_meta( $event->ID ); foreach( $meta_data as $key => $value ) { - $meta_data[$key]= get_post_meta( $event->ID, $key, true ); + if('_event_start_time' == $key || '_event_end_time' == $key ) { + $time_format = WP_Event_Manager_Date_Time::get_timepicker_format(); + $meta_data[$key] = esc_attr(date_i18n($time_format, strtotime(get_post_meta( $event->ID, $key, true )))); + } else + $meta_data[$key]= get_post_meta( $event->ID, $key, true ); } $data = array( 'id' => $event->ID, @@ -894,6 +920,61 @@ public function get_event_texonomy( $texonomy = '' ) { } return $data; } + public function get_items( $request ) { + global $wpdb; + + $user_id = intval( $request['user_id'] ); + $auth_check = $this->wpem_check_authorized_user( $user_id ); + if ($auth_check) { + return parent::get_items($request); + } else { + $query_args = $this->prepare_objects_query($request); + + $settings_row = $wpdb->get_row( + $wpdb->prepare( + "SELECT event_show_by, selected_events FROM {$wpdb->prefix}wpem_rest_api_keys WHERE user_id = %d", + $user_id + ), + ARRAY_A + ); + + $event_show_by = isset($settings_row['event_show_by']) ? $settings_row['event_show_by'] : ''; + $selected_events = isset($settings_row['selected_events']) ? maybe_unserialize($settings_row['selected_events']) : []; + + if ($event_show_by === 'selected' && !empty($selected_events) && is_array($selected_events)) { + $query_args['post__in'] = array_map('intval', $selected_events); + $query_args['orderby'] = 'post__in'; + unset($query_args['author']); + } + + $query_results = parent::get_objects($query_args); + + $objects = array(); + foreach ($query_results['objects'] as $object) { + $object_id = isset($object->ID) ? $object->ID : $object->get_id(); + + if (!wpem_rest_api_check_post_permissions($this->post_type, 'read', $object_id)) { + continue; + } + + $data = $this->prepare_object_for_response($object, $request); + $objects[] = $this->prepare_response_for_collection($data); + } + + $page = isset($query_args['paged']) ? (int) $query_args['paged'] : 1; + $total_pages = ceil($query_results['total'] / $query_args['posts_per_page']); + + $response_data = self::prepare_error_for_response(200); + $response_data['data'] = array( + 'total_post_count' => isset($query_results['total']) ? $query_results['total'] : null, + 'current_page' => $page, + 'last_page' => max(1, $total_pages), + 'total_pages' => $total_pages, + $this->rest_base => $objects, + ); + return wp_send_json($response_data); + } + } } new WPEM_REST_Events_Controller(); \ No newline at end of file diff --git a/includes/wpem-rest-matchmaking-create-meetings.php b/includes/wpem-rest-matchmaking-create-meetings.php new file mode 100644 index 0000000..1a2de83 --- /dev/null +++ b/includes/wpem-rest-matchmaking-create-meetings.php @@ -0,0 +1,896 @@ +namespace, '/' . $this->rest_base, [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'create_meeting'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + 'args' => [ + 'user_id' => ['required' => true, 'type' => 'integer'], + 'event_id' => ['required' => true, 'type' => 'integer'], + 'meeting_date' => ['required' => true, 'type' => 'string'], + 'slot' => ['required' => true, 'type' => 'string'], + 'meeting_participants' => ['required' => true, 'type' => 'array'], + 'write_a_message' => ['required' => false, 'type' => 'string'], + ], + ]); + + register_rest_route($this->namespace, '/get-meetings', [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'get_user_meetings'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + ]); + + register_rest_route($this->namespace, '/cancel-meeting', [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'cancel_meeting'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + 'args' => [ + 'meeting_id' => ['required' => true, 'type' => 'integer'], + 'user_id' => ['required' => true, 'type' => 'integer'], + ], + ]); + + register_rest_route($this->namespace, '/update-meeting-status', [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'update_meeting_status'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + 'args' => [ + 'meeting_id' => ['required' => true, 'type' => 'integer'], + 'user_id' => ['required' => true, 'type' => 'integer'], + 'status' => ['required' => true, 'type' => 'integer', 'enum' => [0, 1]], + ], + ]); + register_rest_route($this->namespace, '/get-availability-slots', [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [$this, 'get_available_meeting_slots'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + 'args' => [ + 'user_id' => [ + 'required' => false, + 'type' => 'integer' + ] + ] + ]); + register_rest_route($this->namespace, '/update-availability-slots', [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'update_availability_slots_rest'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + 'args' => [ + 'availability_slots' => [ + 'required' => true, + 'type' => 'object' + ], + 'available_for_meeting' => [ + 'required' => false, + 'type' => 'boolean' + ], + 'user_id' => [ + 'required' => false, + 'type' => 'integer' + ] + ] + ]); + register_rest_route($this->namespace, '/common-availability-slots', [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'get_common_availability_slots'], + 'permission_callback' => [$auth_controller, 'check_authentication'], + 'args' => [ + 'event_id' => [ + 'required' => true, + 'type' => 'integer', + ], + 'user_ids' => [ + 'required' => true, + 'type' => 'array', + ], + 'date' => [ + 'required' => true, + 'type' => 'string', // expected in Y-m-d format + ], + ] + ]); + register_rest_route($this->namespace, '/matchmaking-settings', [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [$this, 'get_matchmaking_settings'], + 'permission_callback' => '__return_true', // if no auth needed + ]); + } + public function create_meeting(WP_REST_Request $request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + global $wpdb; + + $user_id = intval($request->get_param('user_id')); + $event_id = intval($request->get_param('event_id')); + $meeting_date = sanitize_text_field($request->get_param('meeting_date')); + $slot = sanitize_text_field($request->get_param('slot')); + $participants = $request->get_param('meeting_participants'); + $message = sanitize_textarea_field($request->get_param('write_a_message')); + + if ( + !$user_id || !get_userdata($user_id) || + empty($meeting_date) || empty($slot) || + empty($participants) || !is_array($participants) + ) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'Bad Request', + 'message' => 'Missing or invalid parameters.', + 'data' => [] + ], 400); + } + + // Filter out the user themselves from participant list + $participants = array_filter(array_map('intval', $participants), fn($pid) => $pid !== $user_id); + $participants = array_fill_keys($participants, -1); // -1 = pending + + $table = $wpdb->prefix . 'wpem_matchmaking_users_meetings'; + $inserted = $wpdb->insert($table, [ + 'user_id' => $user_id, + 'event_id' => $event_id, + 'participant_ids' => serialize($participants), + 'meeting_date' => $meeting_date, + 'meeting_start_time' => date("H:i", strtotime($slot)), // 24-hour + 'meeting_end_time' => date("H:i", strtotime($slot . " +1 hour")), // 24-hour + 'message' => $message, + 'meeting_status' => 0 + ], ['%d', '%d', '%s', '%s', '%s', '%s', '%s', '%d']); + + if (!$inserted) { + return new WP_REST_Response([ + 'code' => 500, + 'status' => 'Internal Server Error', + 'message' => 'Could not create meeting.', + 'data' => [] + ], 500); + } + + $meeting_id = $wpdb->insert_id; + $formatted_date = date("l, d F Y", strtotime($meeting_date)); + //$formatted_time = date("H:i", strtotime($slot)) ; // 24-hour + $start_time = date("H:i", strtotime($slot)); + $end_time = date("H:i", strtotime($slot . " +1 hour")); + + $formatted_time = $start_time . ' to ' . $end_time; + $sender_user = get_userdata($user_id); + + $participant_details = []; + + if (!empty($participants)) { + foreach (array_keys($participants) as $participant_id) { + $participant_user = get_userdata($participant_id); + if (!$participant_user) continue; + + $participant_meta = get_user_meta($participant_id); + + $participant_name = $participant_user->display_name ?? 'User'; + $participant_email = $participant_user->user_email ?? ''; + $profile_picture = $participant_meta['_profile_photo'][0] ?? EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + + // Get all profession terms [slug => name] + $profession_terms = get_event_registration_taxonomy_list('event_registration_professions'); + // Get saved profession value + $profession_value = $participant_meta['_profession'][0] ?? ''; + $profession_slug = $profession_value; + // If it's a name, convert to slug + if ($profession_value && !isset($profession_terms[$profession_value])) { + $found_slug = array_search($profession_value, $profession_terms); + if ($found_slug) { + $profession_slug = $found_slug; + } + } + $participant_details[] = [ + 'name' => $participant_name, + 'profession' => $profession_slug, + 'profile_photo' => esc_url($profile_picture) + ]; + + // Email to participant + $host_meta = get_user_meta($user_id); + $host_company = $host_meta['_company_name'][0] ?? ''; + $host_city = $host_meta['_city'][0] ?? ''; + $all_countries = wpem_get_all_countries(); + $host_country = $all_countries[$host_meta['_country'][0]] ?? ''; + $event_name = get_the_title($event_id) ?: ''; + $status_text = "Pending"; + $meeting_description = $message; + $company_name = $participant_meta['_company_name'][0] ?? ''; + $participant_city = $participant_meta['_city'][0] ?? ''; + $participant_country = $all_countries[$participant_meta['_country'][0]] ?? ''; + $profession = (object) ['name' => $participant_meta['_profession'][0] ?? '']; + + // Action buttons + $calendar_button = "Add to Calendar"; + $view_meeting_button = "View Meeting"; + + $subject = "{$sender_user->display_name} requested a meeting with you"; + + // Styled HTML email body + $body = sprintf( + wp_kses( + __( + "
+
+ +
+ New Meeting Request +
+ +
+

Hello %1\$s,

+

%2\$s has requested a meeting with you.

+ +

Meeting Information

+

Event: %3\$s

+

Date: %16\$s

+

Time: %4\$s

+ +

Host Details

+

Name: %2\$s
+ Company: %5\$s
+ City: %6\$s
+ Country: %7\$s

+ +

Receiver (You)

+

Name: %1\$s
+ Title: %8\$s
+ Organization: %9\$s
+ Location: %10\$s, %11\$s
+ Status: %12\$s

+ +

Message:
%13\$s

+ +
%14\$s %15\$s
+
+
+
", + 'wp-event-manager-registrations' + ), + [ + 'div' => ['style' => true], + 'p' => ['style' => true], + 'strong' => [], + 'br' => [], + 'h3' => ['style' => true], + 'h4' => ['style' => true], + 'a' => ['href' => true, 'target' => true, 'style' => true] + ] + ), + esc_html($participant_name), + esc_html($sender_user->display_name), + esc_html($event_name), + esc_html($formatted_time), + esc_html($host_company), + esc_html($host_city), + esc_html($host_country), + esc_html($profession->name ?? ''), + esc_html($company_name), + esc_html($participant_city), + esc_html($participant_country), + esc_html($status_text), + nl2br(esc_html($meeting_description)), + $calendar_button, + $view_meeting_button, + esc_html($formatted_date) + ); + + // Allow custom filter + $body = apply_filters( + 'wpem_registration_meeting_request_email_body', + $body, + $sender_user, + $participant_user, + $event_name, + $formatted_time, + $host_company, + $host_city, + $host_country, + $profession, + $company_name, + $participant_city, + $participant_country, + $status_text, + $meeting_description + ); + + wp_mail($participant_email, $subject, $body, ['Content-Type: text/html; charset=UTF-8']); + } + } + + // Update booked slot (same as before) + /*$slot_data = maybe_unserialize(get_user_meta($user_id, '_meeting_availability_slot', true)); + if (!is_array($slot_data)) { + $slot_data = []; + } + if (!isset($slot_data[$event_id])) { + $slot_data[$event_id] = []; + } + if (!isset($slot_data[$event_id][$meeting_date])) { + $slot_data[$event_id][$meeting_date] = []; + } + $slot_data[$event_id][$meeting_date][$slot] = 2; + update_user_meta($user_id, '_meeting_availability_slot', $slot_data);*/ + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Meeting created and styled emails sent!', + 'data' => [ + 'meeting_date' => $formatted_date, + 'time' => $formatted_time, + 'participants' => $participant_details, + 'message' => $message + ] + ], 200); + } + public function get_user_meetings(WP_REST_Request $request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + global $wpdb; + + $event_id = intval($request->get_param('event_id')); + $user_id = intval($request->get_param('user_id')); + + if (!$event_id || !$user_id) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'error', + 'message' => 'Missing event_id or user_id.', + 'data' => null + ], 400); + } + + $table = $wpdb->prefix . 'wpem_matchmaking_users_meetings'; + + // Fetch ALL meetings for this event + $all_meetings = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table WHERE event_id = %d", $event_id), ARRAY_A); + + if (empty($all_meetings)) { + return new WP_REST_Response([ + 'code' => 404, + 'status' => 'error', + 'message' => 'No meetings found for this event.', + 'data' => null + ], 404); + } + + $meeting_data = []; + + foreach ($all_meetings as $meeting) { + $participant_statuses = maybe_unserialize($meeting['participant_ids']); + if (!is_array($participant_statuses)) { + $participant_statuses = []; + } + + // Check if current user is host or in participant list + if ((int)$meeting['user_id'] !== $user_id && !array_key_exists($user_id, $participant_statuses)) { + continue; + } + + $participants_info = []; + foreach ($participant_statuses as $pid => $status) { + // Get all user data from user meta + $display_name = get_user_meta($pid, 'display_name', true); + if (empty($display_name)) { + $first_name = get_user_meta($pid, 'first_name', true); + $last_name = get_user_meta($pid, 'last_name', true); + $display_name = trim("$first_name $last_name"); + } + + // Get profile data from user meta (assuming these are stored as meta) + $profile_photo = get_wpem_user_profile_photo($pid) ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + $company_name = get_user_meta($pid, '_company_name', true); + $profession_terms = get_event_registration_taxonomy_list('event_registration_professions'); + $profession_value = get_user_meta($pid, '_profession', true); + $profession_slug = $profession_value; + if ($profession_value && !isset($profession_terms[$profession_value])) { + $found_slug = array_search($profession_value, $profession_terms); + if ($found_slug) { + $profession_slug = $found_slug; + } + } + $participants_info[] = [ + 'id' => (int)$pid, + 'status' => (int)$status, + 'name' => $display_name, + 'profile_photo' => $profile_photo, + 'profession' => $profession_slug, + 'company_name' => !empty($company_name) ? esc_html($company_name) : '', + ]; + } + + $host_id = (int)$meeting['user_id']; + // Get host data from user meta + $host_display_name = get_user_meta($host_id, 'display_name', true); + if (empty($host_display_name)) { + $first_name = get_user_meta($host_id, 'first_name', true); + $last_name = get_user_meta($host_id, 'last_name', true); + $host_display_name = trim("$first_name $last_name"); + } + + // Get host profile data from user meta + $host_profile_photo = get_wpem_user_profile_photo($host_id) ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + $host_profession_value = get_user_meta($host_id, '_profession', true); + $host_profession_slug = $host_profession_value; + if ($host_profession_value && !isset($profession_terms[$host_profession_value])) { + $found_slug = array_search($host_profession_value, $profession_terms); + if ($found_slug) { + $host_profession_slug = $found_slug; + } + } + $host_company_name = get_user_meta($host_id, '_company_name', true); + + $host_info = [ + 'id' => $host_id, + 'name' => $host_display_name, + 'profile_photo' => !empty($host_profile_photo) ? esc_url($host_profile_photo) : '', + 'profession' => $host_profession_slug, + 'company_name' => !empty($host_company_name) ? esc_html($host_company_name) : '', + ]; + + $meeting_data[] = [ + 'meeting_id' => (int)$meeting['id'], + 'meeting_date' => date_i18n('l, d F Y', strtotime($meeting['meeting_date'])), + 'start_time' => date_i18n('H:i', strtotime($meeting['meeting_start_time'])), + 'end_time' => date_i18n('H:i', strtotime($meeting['meeting_end_time'])), + 'message' => $meeting['message'], + 'host_info' => $host_info, + 'participants' => $participants_info, + 'meeting_status' => (int)$meeting['meeting_status'] + ]; + } + + if (empty($meeting_data)) { + return new WP_REST_Response([ + 'code' => 404, + 'status' => 'error', + 'message' => 'No meetings found for this user.', + 'data' => null + ], 404); + } + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Meetings retrieved successfully.', + 'data' => $meeting_data + ], 200); + } + public function cancel_meeting(WP_REST_Request $request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + global $wpdb; + + $meeting_id = intval($request->get_param('meeting_id')); + $user_id = intval($request->get_param('user_id')); + + if (!$meeting_id || !$user_id) { + return new WP_REST_Response(['code' => 400, 'status' => 'error', 'message' => 'Missing meeting_id or user_id.'], 400); + } + + $table = $wpdb->prefix . 'wpem_matchmaking_users_meetings'; + $meeting = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table WHERE id = %d", $meeting_id), ARRAY_A); + + if (!$meeting) { + return new WP_REST_Response(['code' => 404, 'status' => 'error', 'message' => 'Meeting not found.'], 404); + } + + if ((int)$meeting['user_id'] !== $user_id) { + return new WP_REST_Response(['code' => 403, 'status' => 'error', 'message' => 'Only the host can cancel the meeting.'], 403); + } + + $updated = $wpdb->update($table, ['meeting_status' => -1], ['id' => $meeting_id], ['%d'], ['%d']); + + if (!$updated) { + return new WP_REST_Response(['code' => 500, 'status' => 'error', 'message' => 'Failed to cancel meeting.'], 500); + } + + // Participant + host IDs + $participant_ids = maybe_unserialize($meeting['participant_ids']); + if (!is_array($participant_ids)) $participant_ids = []; + $participant_ids = array_keys($participant_ids); + $participant_ids[] = (int)$meeting['user_id']; + $participant_ids = array_unique($participant_ids); + + // === Availability reset === + $event_id = (int)$meeting['event_id']; + $meeting_date = $meeting['meeting_date']; + $start_time = date('H:i', strtotime($meeting['meeting_start_time'])); + + foreach ($participant_ids as $pid) { + $slot_data = maybe_unserialize(get_user_meta($pid, '_meeting_availability_slot', true)); + if (!is_array($slot_data)) { + $slot_data = []; + } + + if (!isset($slot_data[$event_id])) $slot_data[$event_id] = []; + if (!isset($slot_data[$event_id][$meeting_date])) $slot_data[$event_id][$meeting_date] = []; + + if (isset($slot_data[$event_id][$meeting_date][$start_time]) && $slot_data[$event_id][$meeting_date][$start_time] == 2) { + $slot_data[$event_id][$meeting_date][$start_time] = 1; + update_user_meta($pid, '_meeting_availability_slot', $slot_data); + } + } + + // Notify participants + foreach ($participant_ids as $pid) { + if ($pid == $user_id) continue; + + $user = get_userdata($pid); + if ($user) { + wp_mail( + $user->user_email, + 'Meeting Cancelled', + "

Hello {$user->display_name},

+

The meeting scheduled on {$meeting_date} has been cancelled.

", + ['Content-Type: text/html; charset=UTF-8'] + ); + } + } + + // Notify host + $host = get_userdata($user_id); + if ($host) { + wp_mail( + $host->user_email, + 'You Cancelled a Meeting', + "

Hello {$host->display_name},

+

You have cancelled the meeting scheduled on {$meeting_date}.

", + ['Content-Type: text/html; charset=UTF-8'] + ); + } + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Meeting cancelled successfully.', + 'data' => ['meeting_id' => $meeting_id], + ], 200); + } + public function update_meeting_status(WP_REST_Request $request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + global $wpdb; + + $meeting_id = intval($request->get_param('meeting_id')); + $user_id = intval($request->get_param('user_id')); + $new_status = intval($request->get_param('status')); + + if (!$meeting_id || !$user_id || !in_array($new_status, [0, 1], true)) { + return new WP_REST_Response(['code' => 400, 'message' => 'Invalid parameters.'], 400); + } + + $table = $wpdb->prefix . 'wpem_matchmaking_users_meetings'; + + $meeting = $wpdb->get_row($wpdb->prepare(" + SELECT participant_ids, event_id, meeting_date, meeting_start_time + FROM $table + WHERE id = %d", $meeting_id + )); + + if (!$meeting) { + return new WP_REST_Response(['code' => 404, 'message' => 'Meeting not found.'], 404); + } + + $participant_data = maybe_unserialize($meeting->participant_ids); + if (!is_array($participant_data)) { + $participant_data = []; + } + + if (!array_key_exists($user_id, $participant_data)) { + return new WP_REST_Response(['code' => 403, 'message' => 'You are not a participant of this meeting.'], 403); + } + + // If user is accepting, check for conflict in same slot + if ($new_status === 1) { + $event_id = $meeting->event_id; + $meeting_date = $meeting->meeting_date; + $slot = date('H:i', strtotime($meeting->meeting_start_time)); + + $conflicting_meeting = $wpdb->get_row($wpdb->prepare(" + SELECT id FROM $table + WHERE id != %d + AND event_id = %d + AND meeting_date = %s + AND meeting_start_time = %s + AND meeting_status != -1 + ", $meeting_id, $event_id, $meeting_date, $meeting->meeting_start_time)); + + if ($conflicting_meeting) { + $existing_participants = $wpdb->get_var($wpdb->prepare(" + SELECT participant_ids FROM $table WHERE id = %d + ", $conflicting_meeting->id)); + + $existing_participant_data = maybe_unserialize($existing_participants); + if (is_array($existing_participant_data) && isset($existing_participant_data[$user_id]) && $existing_participant_data[$user_id] == 1) { + return new WP_REST_Response([ + 'code' => 409, + 'message' => 'You already have a confirmed meeting scheduled at this time slot.', + ], 409); + } + } + } + + // Update this user's status + $participant_data[$user_id] = $new_status; + + // Determine overall meeting status + $meeting_status = (in_array(1, $participant_data, true)) ? 1 : 0; + + // Update meeting record + $updated = $wpdb->update( + $table, + [ + 'participant_ids' => maybe_serialize($participant_data), + 'meeting_status' => $meeting_status, + ], + ['id' => $meeting_id], + ['%s', '%d'], + ['%d'] + ); + + if ($updated === false) { + return new WP_REST_Response(['code' => 500, 'message' => 'Failed to update meeting status.'], 500); + } + + // Update availability slot for this user + /* $slot_data = maybe_unserialize(get_user_meta($user_id, '_meeting_availability_slot', true)); + if (!is_array($slot_data)) { + $slot_data = []; + } + + if (!isset($slot_data[$event_id])) { + $slot_data[$event_id] = []; + } + if (!isset($slot_data[$event_id][$meeting_date])) { + $slot_data[$event_id][$meeting_date] = []; + } + + $slot_data[$event_id][$meeting_date][date('H:i', strtotime($meeting->meeting_start_time))] = ($new_status === 1) ? 2 : 1; + + update_user_meta($user_id, '_meeting_availability_slot', $slot_data);*/ + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => $new_status ? 'Meeting accepted.' : 'Meeting declined.', + 'data' => [ + 'meeting_id' => $meeting_id, + 'participant_id' => $user_id, + 'participant_status' => $new_status, + 'meeting_status' => $meeting_status, + ] + ], 200); + } + + /** + * Get available meeting slots + * @param WP_REST_Request $request + * @return WP_REST_Response + * @since 1.1.0 + */ + public function get_available_meeting_slots(WP_REST_Request $request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + $user_id = intval($request->get_param('user_id')) ?: get_current_user_id(); + $default_slots = get_wpem_default_meeting_slots_for_user($user_id); + $meta = get_user_meta($user_id, '_available_for_meeting', true); + $meeting_available = ($meta !== '' && $meta !== null) ? ((int)$meta === 0 ? 0 : 1) : 1; + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Availability slots fetched successfully.', + 'data' => [ + 'available_for_meeting' => $meeting_available, + 'slots' => $default_slots + ] + ], 200); + } + public function update_availability_slots_rest(WP_REST_Request $request) { + $submitted_slots = $request->get_param('availability_slots'); // This is the "slots" array from GET + + $available_for_meeting = $request->get_param('available_for_meeting') ? 1 : 0; + $user_id = intval($request->get_param('user_id') ?: get_current_user_id()); + + if (!$user_id || !is_array($submitted_slots)) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'ERROR', + 'message' => 'Missing or invalid parameters.' + ], 400); + } + + // Save directly in the same structure + update_user_meta($user_id, '_meeting_availability_slot', $submitted_slots); + update_user_meta($user_id, '_available_for_meeting', $available_for_meeting); + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Availability updated successfully.', + 'data' => [ + 'available_for_meeting' => $available_for_meeting, + 'slots' => $submitted_slots + ] + ], 200); + } + public function get_common_availability_slots($request) { + global $wpdb; + + $event_id = intval($request->get_param('event_id')); + $user_ids = $request->get_param('user_ids'); + $date = sanitize_text_field($request->get_param('date')); + + if (!is_array($user_ids) || empty($user_ids) || !$event_id || !$date) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'ERROR', + 'message' => 'Invalid parameters.', + 'data' => [], + ], 400); + } + + $all_user_slots = []; + + // Step 1: Get available slots for each user (value === 1) + foreach ($user_ids as $user_id) { + $raw_data = get_wpem_default_meeting_slots_for_user($user_id, $date); + + $available_slots = array_keys(array_filter( + $raw_data, + fn($v) => $v == 1 + )); + + if (empty($available_slots)) { + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'No common slots found.', + 'data' => ['common_slots' => []], + ]); + } + + $all_user_slots[] = $available_slots; + } + + // Step 2: Find intersection of slots between all users + $common_slots = array_shift($all_user_slots); + foreach ($all_user_slots as $slots) { + $common_slots = array_intersect($common_slots, $slots); + } + + sort($common_slots); + + // Step 3: Find booked slots for given date + $table = $wpdb->prefix . 'wpem_matchmaking_users_meetings'; + $rows = $wpdb->get_results($wpdb->prepare( + "SELECT meeting_start_time, participant_ids, user_id + FROM {$table} + WHERE meeting_date = %s", + $date + ), ARRAY_A); + + $booked_slots = []; + foreach ($rows as $row) { + $meeting_time = date('H:i', strtotime($row['meeting_start_time'])); + $creator_id = intval($row['user_id']); + $participant_ids = maybe_unserialize($row['participant_ids']); + + if (!is_array($participant_ids)) { + $participant_ids = []; + } + + foreach ($user_ids as $u_id) { + $u_id = intval($u_id); + + // Condition 1: Creator is the user + if ($creator_id === $u_id) { + $booked_slots[] = $meeting_time; + break; + } + + // Condition 2: User is a participant with status 0 or 1 + if (isset($participant_ids[$u_id]) && in_array($participant_ids[$u_id], [0, 1], true)) { + $booked_slots[] = $meeting_time; + break; + } + } + } + + // Step 4: Build combined slot list + $combined_slots = []; + foreach ($common_slots as $slot) { + $combined_slots[] = [ + 'time' => $slot, + 'is_booked' => in_array($slot, $booked_slots, true), + ]; + } + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => count($combined_slots) ? 'Common availability slots retrieved successfully.' : 'No common slots found.', + 'data' => [ + 'event_id' => $event_id, + 'date' => $date, + 'common_slots' => $combined_slots, + ], + ], 200); + } + public function get_matchmaking_settings(WP_REST_Request $request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking is disabled.', + 'data' => null + ], 403); + } + + $settings = [ + 'request_mode' => get_option('wpem_meeting_request_mode'), + 'scheduling_mode' => get_option('wpem_meeting_scheduling_mode'), + 'attendee_limit' => get_option('wpem_meeting_attendee_limit'), + 'meeting_expiration' => get_option('wpem_meeting_expiration'), + 'enable_matchmaking' => get_option('enable_matchmaking'), + 'participant_activation' => get_option('participant_activation'), + ]; + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Matchmaking settings retrieved.', + 'data' => $settings + ], 200); + } +} + +new WPEM_REST_Create_Meeting_Controller(); \ No newline at end of file diff --git a/includes/wpem-rest-matchmaking-filter-users.php b/includes/wpem-rest-matchmaking-filter-users.php new file mode 100644 index 0000000..c99160d --- /dev/null +++ b/includes/wpem-rest-matchmaking-filter-users.php @@ -0,0 +1,420 @@ +namespace, '/' . $this->rest_base, array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array($this, 'handle_filter_users'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'profession' => array('required' => false, 'type' => 'string'), + 'company_name' => array('required' => false, 'type' => 'string'), + 'country' => array('required' => false, 'type' => 'array'), + 'city' => array('required' => false, 'type' => 'string'), + 'experience' => array('required' => false), + 'skills' => array('required' => false, 'type' => 'array'), + 'interests' => array('required' => false, 'type' => 'array'), + 'event_id' => array('required' => false, 'type' => 'integer'), + 'user_id' => array('required' => true, 'type' => 'integer'), + 'search' => array('required' => false, 'type' => 'string'), + 'per_page' => array('required' => false, 'type' => 'integer', 'default' => 5), + 'page' => array('required' => false, 'type' => 'integer', 'default' => 1), + + ), + )); + + // Your matches (with optional user_id param) + register_rest_route($this->namespace, '/your-matches', array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'handle_your_matches'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array('required' => true, 'type' => 'integer'), + ), + )); + } + + /** + * This function used to filter users + * @since 1.1.0 + */ + public function handle_your_matches($request) { + global $wpdb; + + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + $user_id = intval($request->get_param('user_id')); + + if (!$user_id) { + return new WP_REST_Response([ + 'code' => 401, + 'status' => 'Unauthorized', + 'message' => 'User Id not found' + ], 401); + } + + $table = $wpdb->prefix . 'wpem_matchmaking_users'; + $user_data = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table WHERE user_id = %d", $user_id), ARRAY_A); + + if (!$user_data) { + return new WP_REST_Response([ + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'Matchmaking profile not found for user' + ], 404); + } + + // Build a filter request based on user's profile + $filter_request = new WP_REST_Request('GET'); + $filter_request->set_param('profession', $user_data['profession']); + $filter_request->set_param('company_name', $user_data['company_name']); + $filter_request->set_param('country', [$user_data['country']]); + $filter_request->set_param('city', $user_data['city']); + + $exp = (int)$user_data['experience']; + $filter_request->set_param('experience', [ + 'min' => max(0, $exp - 2), + 'max' => $exp + 2 + ]); + + $skills = maybe_unserialize($user_data['skills']); + if (is_array($skills)) { + $filter_request->set_param('skills', $skills); + } + + $interests = maybe_unserialize($user_data['interests']); + if (is_array($interests)) { + $filter_request->set_param('interests', $interests); + } + + $search = sanitize_text_field($request->get_param('search')); + if (!empty($search)) { + $search_like = '%' . $wpdb->esc_like($search) . '%'; + + $search_conditions = [ + "city LIKE %s", + "country LIKE %s", + "profession LIKE %s", + "skills LIKE %s", + "interests LIKE %s", + "company_name LIKE %s" + ]; + + // First name / last name from wp_usermeta + $matching_user_ids = $wpdb->get_col($wpdb->prepare(" + SELECT DISTINCT user_id + FROM {$wpdb->usermeta} + WHERE (meta_key = 'first_name' OR meta_key = 'last_name') + AND meta_value LIKE %s + ", $search_like)); + + if (!empty($matching_user_ids)) { + $placeholders = implode(',', array_fill(0, count($matching_user_ids), '%d')); + $search_conditions[] = "user_id IN ($placeholders)"; + $query_params = array_merge($query_params, array_fill(0, count($search_conditions) - 1, $search_like), $matching_user_ids); + } else { + $query_params = array_merge($query_params, array_fill(0, count($search_conditions), $search_like)); + } + + $where_clauses[] = '(' . implode(' OR ', $search_conditions) . ')'; + } + + // Reuse the filter handler + $response = $this->handle_filter_users($filter_request); + + // Exclude the user from their own matches + if ($response instanceof WP_REST_Response) { + $data = $response->get_data(); + + // Exclude self + $filtered = array_filter($data['data'], function ($item) use ($user_id) { + return $item['user_id'] != $user_id; + }); + + // Add first_name and last_name + foreach ($filtered as &$row) { + $row['first_name'] = get_user_meta($row['user_id'], 'first_name', true); + $row['last_name'] = get_user_meta($row['user_id'], 'last_name', true); + } + + $data['data'] = array_values($filtered); + $response->set_data($data); + } + + return $response; + } + + /** + * This function used to filter users + * @since 1.1.0 + * @param $request + * @return WP_REST_Response + */ + public function handle_filter_users($request) { + global $wpdb; + + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ], 403); + } + + $event_id = intval($request->get_param('event_id')); + $user_id = intval($request->get_param('user_id')); + + // Step 1: Validate registration + $registered_user_ids = []; + if ($event_id && $user_id) { + $registration_query = new WP_Query([ + 'post_type' => 'event_registration', + 'posts_per_page' => -1, + 'fields' => 'ids', + 'post_author' => $user_id, + ]); + + $has_registration = false; + foreach ($registration_query->posts as $registration_id) { + if (wp_get_post_parent_id($registration_id) == $event_id) { + $has_registration = true; + break; + } + } + + if (!$has_registration) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Forbidden', + 'message' => 'You are not registered for this event.', + 'data' => [] + ], 403); + } + + // Collect all registered users for this event + $attendee_query = new WP_Query([ + 'post_type' => 'event_registration', + 'posts_per_page' => -1, + 'fields' => 'ids' + ]); + + foreach ($attendee_query->posts as $registration_id) { + if (wp_get_post_parent_id($registration_id) == $event_id) { + $uid = intval(get_post_field('post_author', $registration_id)); + if ($uid && !in_array($uid, $registered_user_ids)) { + $registered_user_ids[] = $uid; + } + } + } + } + + if (empty($registered_user_ids)) { + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'No attendees found for this event.', + 'data' => [] + ], 200); + } + + // Step 2: Build user data + $profession_terms = get_event_registration_taxonomy_list('event_registration_professions'); // [slug => name] + $skills_terms = get_event_registration_taxonomy_list('event_registration_skills'); + $interests_terms = get_event_registration_taxonomy_list('event_registration_interests'); + + $users_data = []; + foreach ($registered_user_ids as $uid) { + if ($uid == $user_id) continue; + if (!get_user_meta($uid, '_matchmaking_profile', true)) continue; + + $photo = get_wpem_user_profile_photo($uid) ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + + // Normalize organization logo + $organization_logo = get_user_meta($uid, '_organization_logo', true); + $organization_logo = maybe_unserialize($organization_logo); + if (is_array($organization_logo)) { + $organization_logo = reset($organization_logo); + } + $organization_logo = $organization_logo ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/organisation-icon.jpg'; + // Profession + $profession_value = get_user_meta($uid, '_profession', true); + $profession_slug = $profession_value; + if ($profession_value && !isset($profession_terms[$profession_value])) { + $found_slug = array_search($profession_value, $profession_terms); + if ($found_slug) { + $profession_slug = $found_slug; + } + } + + // --- Skills --- + $skills_slugs = []; + $skills_arr = maybe_unserialize(get_user_meta($uid, '_skills', true)); + if (is_array($skills_arr)) { + foreach ($skills_arr as $skill) { + $term = get_term_by('slug', $skill, 'event_registration_skills'); + if (!$term) { + $term = get_term_by('name', $skill, 'event_registration_skills'); + } + if (!$term) { + $term = get_term_by('id', $skill, 'event_registration_skills'); + } + if ($term) { + $skills_slugs[] = $term->slug; + } + } + } + $skills_slugs = array_filter($skills_slugs); // remove blanks + $skills_serialized = serialize($skills_slugs); + + // --- Interests --- + $interests_slugs = []; + $interests_arr = maybe_unserialize(get_user_meta($uid, '_interests', true)); + if (is_array($interests_arr)) { + foreach ($interests_arr as $interest) { + $term = get_term_by('slug', $interest, 'event_registration_interests'); + if (!$term) { + $term = get_term_by('name', $interest, 'event_registration_interests'); + } + if (!$term) { + $term = get_term_by('id', $interest, 'event_registration_interests'); + } + if ($term) { + $interests_slugs[] = $term->slug; + } + } + } + $interests_slugs = array_filter($interests_slugs); + $interests_serialized = serialize($interests_slugs); + + $countries = wpem_get_all_countries(); + $country_value = get_user_meta($uid, '_country', true); + $country_code = ''; + if ($country_value) { + if (isset($countries[$country_value])) { + $country_code = $country_value; + } else { + $country_code = array_search($country_value, $countries); + } + } + // Get organization country value from user meta + $org_country_value = get_user_meta($uid, '_organization_country', true); + $org_country_code = ''; + if ($org_country_value) { + if (isset($countries[$org_country_value])) { + $org_country_code = $org_country_value; + } else { + $org_country_code = array_search($org_country_value, $countries); + } + } + $users_data[] = [ + 'user_id' => $uid, + 'display_name' => get_the_author_meta('display_name', $uid), + 'first_name' => get_user_meta($uid, 'first_name', true), + 'last_name' => get_user_meta($uid, 'last_name', true), + 'email' => get_userdata($uid)->user_email, + 'matchmaking_profile' => get_user_meta($uid, '_matchmaking_profile', true), + 'profile_photo' => $photo, + 'profession' => $profession_slug, + 'experience' => get_user_meta($uid, '_experience', true), + 'company_name' => get_user_meta($uid, '_company_name', true), + 'country' => $country_code, + 'city' => get_user_meta($uid, '_city', true), + 'about' => get_user_meta($uid, '_about', true), + 'skills' => $skills_serialized, + 'interests' => $interests_serialized, + 'message_notification' => get_user_meta($uid, '_message_notification', true), + 'organization_name' => get_user_meta($uid, '_organization_name', true), + 'organization_logo' => $organization_logo, + 'organization_country' => $org_country_code, + 'organization_city' => get_user_meta($uid, '_organization_city', true), + 'organization_description'=> get_user_meta($uid, '_organization_description', true), + 'organization_website' => get_user_meta($uid, '_organization_website', true), + 'available_for_meeting' => get_user_meta($uid, '_available_for_meeting', true), + 'approve_profile_status'=> get_user_meta($uid, '_approve_profile_status', true), + ]; + } + + // Step 3: Apply filters + $profession = sanitize_text_field($request->get_param('profession')); + $country = $request->get_param('country'); + $skills = $request->get_param('skills'); + $interests = $request->get_param('interests'); + $search = sanitize_text_field($request->get_param('search')); + + $filtered_users = array_filter($users_data, function($user) use ($profession, $country, $skills, $interests, $search) { + if ($profession && strtolower($user['profession']) !== strtolower($profession)) { + return false; + } + if (!empty($country) && is_array($country) && !in_array($user['country'], $country)) { + return false; + } + if (!empty($skills) && is_array($skills)) { + if (!array_intersect($skills, $user['skills'])) { + return false; + } + } + if (!empty($interests) && is_array($interests)) { + if (!array_intersect($interests, $user['interests'])) { + return false; + } + } + if ($search) { + $haystack_parts = []; + foreach ($user as $key => $val) { + if (is_array($val)) { + $haystack_parts = array_merge($haystack_parts, $val); + } else { + $haystack_parts[] = $val; + } + } + $haystack = strtolower(implode(' ', $haystack_parts)); + if (strpos($haystack, strtolower($search)) === false) { + return false; + } + } + return true; + }); + + // Step 4: Pagination + $per_page = max(1, (int) $request->get_param('per_page')); + $page = max(1, (int) $request->get_param('page')); + $total = count($filtered_users); + $offset = ($page - 1) * $per_page; + $paged_users = array_slice($filtered_users, $offset, $per_page); + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Users retrieved successfully.', + 'data' => [ + 'total_post_count' => $total, + 'current_page' => $page, + 'last_page' => ceil($total / $per_page), + 'total_pages' => ceil($total / $per_page), + 'users' => array_values($paged_users), + ], + ], 200); + } +} +new WPEM_REST_Filter_Users_Controller(); diff --git a/includes/wpem-rest-matchmaking-get-texonomy.php b/includes/wpem-rest-matchmaking-get-texonomy.php new file mode 100644 index 0000000..0bf22f2 --- /dev/null +++ b/includes/wpem-rest-matchmaking-get-texonomy.php @@ -0,0 +1,86 @@ +namespace, + '/' . $this->rest_base, + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'get_taxonomy_terms'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'taxonomy' => array( + 'required' => true, + 'type' => 'string', + 'description' => 'Taxonomy name (e.g., category, post_tag, custom_taxonomy).', + ) + ), + ) + ); + } + + public function get_taxonomy_terms($request) { + // Check if matchmaking is enabled + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response(array( + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ), 403); + } + + $taxonomy = sanitize_text_field($request->get_param('taxonomy')); + + if (!taxonomy_exists($taxonomy)) { + return new WP_REST_Response(array( + 'code' => 400, + 'status' => 'Bad Request', + 'message' => 'Invalid taxonomy.', + 'data' => null + ), 400); + } + + $terms = get_terms(array( + 'taxonomy' => $taxonomy, + 'hide_empty' => false, + )); + + if (is_wp_error($terms)) { + return new WP_REST_Response(array( + 'code' => 500, + 'status' => 'Server Error', + 'message' => 'Failed to fetch terms.', + 'data' => null + ), 500); + } + + $term_list = array_map(array($this, 'format_term_data'), $terms); + + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'Taxonomy terms retrieved successfully.', + 'data' => $term_list + ), 200); + } + + private function format_term_data($term) { + return array( + 'id' => $term->term_id, + 'name' => html_entity_decode($term->name, ENT_QUOTES, 'UTF-8'), + 'slug' => $term->slug, + ); + } +} + +new WPEM_REST_Taxonomy_List_Controller(); diff --git a/includes/wpem-rest-matchmaking-profile.php b/includes/wpem-rest-matchmaking-profile.php new file mode 100644 index 0000000..6931a01 --- /dev/null +++ b/includes/wpem-rest-matchmaking-profile.php @@ -0,0 +1,544 @@ +namespace, + '/attendee-profile', + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'get_attendee_profile'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'attendeeId' => array( + 'required' => false, + 'type' => 'integer', + ) + ), + ) + ); + + register_rest_route( + $this->namespace, + '/attendee-profile/update', + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array($this, 'update_attendee_profile'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array( + 'required' => true, + 'type' => 'integer', + ), + ), + ) + ); + + register_rest_route( + $this->namespace, + '/upload-user-file', + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array($this, 'upload_user_file'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array( + 'required' => true, + 'type' => 'integer', + ), + ), + ) + ); + } + + public function get_attendee_profile($request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response(array( + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ), 403); + } + + $attendee_id = $request->get_param('attendeeId'); + $countries = wpem_get_all_countries(); + if ($attendee_id) { + // Check if user exists + $user = get_user_by('ID', $attendee_id); + if (!$user) { + return new WP_REST_Response(array( + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'Attendee not found.', + 'data' => null + ), 404); + } + + // Get all user meta + $user_meta = get_user_meta($attendee_id); + $photo = get_wpem_user_profile_photo($attendee_id) ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + $organization_logo = get_user_meta( $attendee_id, '_organization_logo', true ); + $organization_logo = maybe_unserialize( $organization_logo ); + if (is_array($organization_logo)) { + $organization_logo = reset($organization_logo); // get first value in the array + } + $organization_logo = $organization_logo ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/organisation-icon.jpg'; + $country_value = isset($user_meta['_country'][0]) ? sanitize_text_field($user_meta['_country'][0]) : ''; + $country_code = ''; + if ($country_value) { + if (isset($countries[$country_value])) { + $country_code = $country_value; + } else { + $country_code = array_search($country_value, $countries); + } + } + // Get organization country value from user meta + $org_country_value = isset($user_meta['_organization_country'][0]) ? sanitize_text_field($user_meta['_organization_country'][0]) : ''; + $org_country_code = ''; + if ($org_country_value) { + if (isset($countries[$org_country_value])) { + $org_country_code = $org_country_value; + } else { + $org_country_code = array_search($org_country_value, $countries); + } + } + $meta = get_user_meta($attendee_id, '_available_for_meeting', true); + $meeting_available = ($meta !== '' && $meta !== null) ? ((int)$meta === 0 ? 0 : 1) : 1; + // Get all profession terms [slug => name] + $professions = get_event_registration_taxonomy_list('event_registration_professions'); + + // Get saved profession value + $profession_value = isset($user_meta['_profession'][0]) ? sanitize_text_field($user_meta['_profession'][0]) : ''; + $profession_slug = $profession_value; + + // If it's a name, convert to slug + if ($profession_value && !isset($professions[$profession_value])) { + $found_slug = array_search($profession_value, $professions); + if ($found_slug) { + $profession_slug = $found_slug; + } + } + $skills_slugs = []; + $skills_arr = maybe_unserialize($user_meta['_skills'][0]); + if (is_array($skills_arr)) { + foreach ($skills_arr as $skill) { + $term = get_term_by('slug', $skill, 'event_registration_skills'); + if (!$term) { + $term = get_term_by('name', $skill, 'event_registration_skills'); + } + if (!$term) { + $term = get_term_by('id', $skill, 'event_registration_skills'); + } + if ($term) { + $skills_slugs[] = $term->slug; + } + } + } + $skills_slugs = array_filter($skills_slugs); // remove blanks + $skills_serialized = serialize($skills_slugs); + + // --- Interests --- + $interests_slugs = []; + $interests_arr = maybe_unserialize($user_meta['_interests'][0]); + if (is_array($interests_arr)) { + foreach ($interests_arr as $interest) { + $term = get_term_by('slug', $interest, 'event_registration_interests'); + if (!$term) { + $term = get_term_by('name', $interest, 'event_registration_interests'); + } + if (!$term) { + $term = get_term_by('id', $interest, 'event_registration_interests'); + } + if ($term) { + $interests_slugs[] = $term->slug; + } + } + } + $interests_slugs = array_filter($interests_slugs); + $interests_serialized = serialize($interests_slugs); + + // Format the profile data + $profile = array( + 'user_id' => $attendee_id, + 'display_name' => $user->display_name, + 'first_name' => isset($user_meta['first_name'][0]) ? sanitize_text_field($user_meta['first_name'][0]) : '', + 'last_name' => isset($user_meta['last_name'][0]) ? sanitize_text_field($user_meta['last_name'][0]) : '', + 'email' => $user->user_email, + 'matchmaking_profile' => isset($user_meta['_matchmaking_profile'][0]) ? (int)$user_meta['_matchmaking_profile'][0] : 0, + 'profile_photo' => $photo, + 'profession' => $profession_slug, + 'experience' => isset($user_meta['_experience'][0]) ? (float)$user_meta['_experience'][0] : 0, + 'company_name' => isset($user_meta['_company_name'][0]) ? sanitize_text_field($user_meta['_company_name'][0]) : '', + 'country' => $country_code, + 'city' => isset($user_meta['_city'][0]) ? sanitize_text_field($user_meta['_city'][0]) : '', + 'about' => isset($user_meta['_about'][0]) ? sanitize_textarea_field($user_meta['_about'][0]) : '', + //'skills' => maybe_serialize($skills_slugs), + //'interests' => maybe_serialize($interests_slugs), + 'skills' => $skills_serialized, + 'interests' => $interests_serialized, + 'message_notification' => isset($user_meta['_message_notification'][0]) ? (int)$user_meta['_message_notification'][0] : 0, + 'organization_name' => isset($user_meta['_organization_name'][0]) ? sanitize_text_field($user_meta['_organization_name'][0]) : '', + 'organization_logo' => $organization_logo, + 'organization_country' => $org_country_code, + 'organization_city' => isset($user_meta['_organization_city'][0]) ? sanitize_text_field($user_meta['_organization_city'][0]) : '', + 'organization_description' => isset($user_meta['_organization_description'][0]) ? sanitize_textarea_field($user_meta['_organization_description'][0]) : '', + 'organization_website' => isset($user_meta['_organization_website'][0]) ? sanitize_text_field($user_meta['_organization_website'][0]) : '', + 'approve_profile_status' => isset($user_meta['_approve_profile_status'][0]) ? (int)$user_meta['_approve_profile_status'][0] : 0, + 'wpem_meeting_request_mode' => isset($user_meta['_wpem_meeting_request_mode'][0]) ? $user_meta['_wpem_meeting_request_mode'][0] : 'approval', + 'available_for_meeting' => (int)$meeting_available, + ); + + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'Profile retrieved successfully.', + 'data' => $profile + ), 200); + } else { + // Get all users with matchmaking profiles + $args = array( + 'meta_key' => '_matchmaking_profile', + 'meta_value' => '1', + 'meta_compare' => '=' + ); + $users = get_users($args); + + $profiles = array(); + foreach ($users as $user) { + $user_meta = get_user_meta($user->ID); + $photo = get_wpem_user_profile_photo($user->ID) ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/user-profile-photo.png'; + $organization_logo = get_user_meta( $user->ID, '_organization_logo', true ); + $organization_logo = maybe_unserialize( $organization_logo ); + if (is_array($organization_logo)) { + $organization_logo = reset($organization_logo); + } + $organization_logo = $organization_logo ?: EVENT_MANAGER_REGISTRATIONS_PLUGIN_URL . '/assets/images/organisation-icon.jpg'; + $country_value = isset($user_meta['_country'][0]) ? sanitize_text_field($user_meta['_country'][0]) : ''; + $country_code = ''; + if ($country_value) { + if (isset($countries[$country_value])) { + $country_code = $country_value; + } else { + $country_code = array_search($country_value, $countries); + } + } + $org_country_value = isset($user_meta['_organization_country'][0]) ? sanitize_text_field($user_meta['_organization_country'][0]) : ''; + $org_country_code = ''; + if ($org_country_value) { + if (isset($countries[$org_country_value])) { + $org_country_code = $org_country_value; + } else { + $org_country_code = array_search($org_country_value, $countries); + } + } + $meta = get_user_meta($user->ID, '_available_for_meeting', true); + $meeting_available = ($meta !== '' && $meta !== null) ? ((int)$meta === 0 ? 0 : 1) : 1; + // Profession slug logic + $professions = get_event_registration_taxonomy_list('event_registration_professions'); + $profession_value = isset($user_meta['_profession'][0]) ? sanitize_text_field($user_meta['_profession'][0]) : ''; + $profession_slug = $profession_value; + if ($profession_value && !isset($professions[$profession_value])) { + $found_slug = array_search($profession_value, $professions); + if ($found_slug) { + $profession_slug = $found_slug; + } + } + $skills_slugs = []; + $skills_arr = maybe_unserialize($user_meta['_skills'][0]); + if (is_array($skills_arr)) { + foreach ($skills_arr as $skill) { + $term = get_term_by('slug', $skill, 'event_registration_skills'); + if (!$term) { + $term = get_term_by('name', $skill, 'event_registration_skills'); + } + if (!$term) { + $term = get_term_by('id', $skill, 'event_registration_skills'); + } + if ($term) { + $skills_slugs[] = $term->slug; + } + } + } + $skills_slugs = array_filter($skills_slugs); // remove blanks + $skills_serialized = serialize($skills_slugs); + + // --- Interests --- + $interests_slugs = []; + $interests_arr = maybe_unserialize($user_meta['_interests'][0]); + if (is_array($interests_arr)) { + foreach ($interests_arr as $interest) { + $term = get_term_by('slug', $interest, 'event_registration_interests'); + if (!$term) { + $term = get_term_by('name', $interest, 'event_registration_interests'); + } + if (!$term) { + $term = get_term_by('id', $interest, 'event_registration_interests'); + } + if ($term) { + $interests_slugs[] = $term->slug; + } + } + } + $interests_slugs = array_filter($interests_slugs); + $interests_serialized = serialize($interests_slugs); + + $profiles[] = array( + 'user_id' => $user->ID, + 'display_name' => $user->display_name, + 'first_name' => isset($user_meta['first_name'][0]) ? sanitize_text_field($user_meta['first_name'][0]) : '', + 'last_name' => isset($user_meta['last_name'][0]) ? sanitize_text_field($user_meta['last_name'][0]) : '', + 'email' => $user->user_email, + 'matchmaking_profile' => isset($user_meta['_matchmaking_profile'][0]) ? (int)$user_meta['_matchmaking_profile'][0] : 0, + 'profile_photo' => $photo, + 'profession' => $profession_slug , + 'experience' => isset($user_meta['_experience'][0]) ? (float)$user_meta['_experience'][0] : 0, + 'company_name' => isset($user_meta['_company_name'][0]) ? sanitize_text_field($user_meta['_company_name'][0]) : '', + 'country' => $country_code, + 'city' => isset($user_meta['_city'][0]) ? sanitize_text_field($user_meta['_city'][0]) : '', + 'about' => isset($user_meta['_about'][0]) ? sanitize_textarea_field($user_meta['_about'][0]) : '', + 'skills' => $skills_serialized, + 'interests' => $interests_serialized, + 'message_notification' => isset($user_meta['_message_notification'][0]) ? (int)$user_meta['_message_notification'][0] : 0, + 'organization_name' => isset($user_meta['_organization_name'][0]) ? sanitize_text_field($user_meta['_organization_name'][0]) : '', + 'organization_logo' => $organization_logo, + 'organization_country' => $org_country_code, + 'organization_city' => isset($user_meta['_organization_city'][0]) ? sanitize_text_field($user_meta['_organization_city'][0]) : '', + 'organization_description' => isset($user_meta['_organization_description'][0]) ? sanitize_textarea_field($user_meta['_organization_description'][0]) : '', + 'organization_website' => isset($user_meta['_organization_website'][0]) ? sanitize_text_field($user_meta['_organization_website'][0]) : '', + 'approve_profile_status' => isset($user_meta['_approve_profile_status'][0]) ? (int)$user_meta['_approve_profile_status'][0] : 0, + 'wpem_meeting_request_mode' => isset($user_meta['_wpem_meeting_request_mode'][0]) ? $user_meta['_wpem_meeting_request_mode'][0] : 'approval', + 'available_for_meeting' => (int)$meeting_available, + ); + } + + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'All profiles retrieved successfully.', + 'data' => $profiles + ), 200); + } + } + /** + * Update profile including handling file upload from device for profile_photo + */ + public function update_attendee_profile($request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.' + ], 403); + } + + $user_id = $request->get_param('user_id'); + $user = get_user_by('id', $user_id); + + if (!$user) { + return new WP_REST_Response([ + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'User not found.' + ], 404); + } + + // List of all meta fields we can update + $meta_fields = [ + 'profession', 'experience', 'company_name', 'country', + 'city', 'about', 'skills', 'interests', 'organization_name', + 'organization_logo', 'organization_city', 'organization_country', + 'organization_description', 'organization_website', 'message_notification', 'matchmaking_profile' + ]; + + // Handle normal meta fields + + foreach ($meta_fields as $field) { + if ($request->get_param($field) !== null) { + $value = $request->get_param($field); + + // For skills and interests, always save as serialized array + if (in_array($field, ['skills', 'interests'])) { + // Ensure value is always an array + if (!is_array($value)) { + $value = [$value]; + } + $value = array_filter($value, function($v) { + return $v !== null && $v !== ''; + }); + $value = array_values($value); // reindex after filtering + + // Save as serialized array (produces a:2:{i:0;s:...;i:1;s:...;} format) + if (!empty($value)) { + update_user_meta($user_id, '_' . $field, $value); + } else { + update_user_meta($user_id, '_' . $field, ''); + } + } else { + // For other fields + if (is_array($value)) { + $value = array_filter($value, function($v) { + return $v !== null && $v !== ''; + }); + $value = array_values($value); // reindex after filtering + } + if (!empty($value)) { + update_user_meta($user_id, '_' . $field, $value); + } else { + update_user_meta($user_id, '_' . $field, ''); // cleanup if blank + } + } + } + } + + // Handle profile_photo file upload + if (!empty($_FILES['profile_photo']) && $_FILES['profile_photo']['error'] === UPLOAD_ERR_OK) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + $upload_overrides = ['test_form' => false]; + $movefile = wp_handle_upload($_FILES['profile_photo'], $upload_overrides); + + if (isset($movefile['url'])) { + update_user_meta($user_id, '_profile_photo', esc_url_raw($movefile['url'])); + + } else { + return new WP_REST_Response([ + 'code' => 500, + 'status' => 'Error', + 'message' => 'Profile photo upload failed.' + ], 500); + } + } elseif ($request->get_param('profile_photo')) { + update_user_meta($user_id, '_profile_photo', esc_url_raw($request->get_param('profile_photo'))); + + } + + // Handle organization_logo file upload + if (!empty($_FILES['organization_logo']) && $_FILES['organization_logo']['error'] === UPLOAD_ERR_OK) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + $upload_overrides = ['test_form' => false]; + $movefile = wp_handle_upload($_FILES['organization_logo'], $upload_overrides); + + if (isset($movefile['url'])) { + update_user_meta($user_id, '_organization_logo', esc_url_raw($movefile['url'])); + } else { + return new WP_REST_Response([ + 'code' => 500, + 'status' => 'Error', + 'message' => 'Organization logo upload failed.' + ], 500); + } + } elseif ($request->get_param('organization_logo')) { + update_user_meta($user_id, '_organization_logo', esc_url_raw($request->get_param('organization_logo'))); + } + + // Update basic WP user fields + if ($request->get_param('first_name')) { + update_user_meta($user_id, 'first_name', sanitize_text_field($request->get_param('first_name'))); + } + + if ($request->get_param('last_name')) { + update_user_meta($user_id, 'last_name', sanitize_text_field($request->get_param('last_name'))); + } + + if ($request->get_param('email')) { + $email = sanitize_email($request->get_param('email')); + $email_exists = email_exists($email); + + if ($email_exists && $email_exists != $user_id) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'Error', + 'message' => 'Email already in use.' + ], 400); + } + + $result = wp_update_user([ + 'ID' => $user_id, + 'user_email' => $email + ]); + + if (is_wp_error($result)) { + return new WP_REST_Response([ + 'code' => 500, + 'status' => 'Error', + 'message' => $result->get_error_message() + ], 500); + } + } + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Profile updated successfully.' + ], 200); + } + + public function upload_user_file($request) { + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.' + ], 403); + } + + $user_id = $request->get_param('user_id'); + $user = get_user_by('id', $user_id); + + if (!$user) { + return new WP_REST_Response([ + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'User not found.' + ], 404); + } + + if (empty($_FILES['file'])) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'Error', + 'message' => 'No file uploaded.' + ], 400); + } + + require_once ABSPATH . 'wp-admin/includes/file.php'; + + $file = $_FILES['file']; + $upload_overrides = ['test_form' => false]; + $movefile = wp_handle_upload($file, $upload_overrides); + + if (!isset($movefile['url'])) { + return new WP_REST_Response([ + 'code' => 500, + 'status' => 'Error', + 'message' => 'File upload failed.' + ], 500); + } + + $file_url = esc_url_raw($movefile['url']); + + // Update both profile photo meta fields + update_user_meta($user_id, '_profile_photo', $file_url); + + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'File uploaded and stored successfully.', + 'data' => [ + 'profile_photo' => $file_url, + 'meta_updated' => true + ] + ], 200); + } + +} +new WPEM_REST_MatchMaking_Profile_Controller(); \ No newline at end of file diff --git a/includes/wpem-rest-matchmaking-user-messages.php b/includes/wpem-rest-matchmaking-user-messages.php new file mode 100644 index 0000000..495c82c --- /dev/null +++ b/includes/wpem-rest-matchmaking-user-messages.php @@ -0,0 +1,391 @@ +namespace, '/' . $this->rest_base, array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array($this, 'handle_send_message'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'senderId' => array('required' => true), + 'receiverId' => array('required' => true), + 'message' => array('required' => false), + 'image' => array('required' => false), + ), + )); + + register_rest_route($this->namespace, '/get-messages', array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'handle_get_messages'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'senderId' => array('required' => true, 'type' => 'integer'), + 'receiverId' => array('required' => true, 'type' => 'integer'), + 'page' => array('required' => false, 'type' => 'integer', 'default' => 1), + 'per_page' => array('required' => false, 'type' => 'integer', 'default' => 20), + ), + )); + // Get conversation list endpoint + register_rest_route($this->namespace, '/get-conversation-list', array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'handle_get_conversation_list'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array('required' => true, 'type' => 'integer'), + 'event_ids' => array('required' => true, 'type' => 'array', 'items' => array('type' => 'integer')), + 'paged' => array('required' => false, 'type' => 'integer', 'default' => 1), + 'per_page' => array('required' => false, 'type' => 'integer', 'default' => 10), + ), + )); + } + public function handle_send_message($request) { + global $wpdb; + + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + ], 403); + } + + $sender_id = intval($request->get_param('senderId')); + $receiver_id = intval($request->get_param('receiverId')); + $text_message = sanitize_textarea_field($request->get_param('message')); + + // Get minimal user objects just for email addresses + $sender_user = get_user_by('id', $sender_id); + $receiver_user = get_user_by('id', $receiver_id); + + if (!$sender_user || !$receiver_user) { + return new WP_REST_Response([ + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'Sender or Receiver not found.', + ], 404); + } + + // Get other user data from meta + $sender_first = get_user_meta($sender_id, 'first_name', true); + $sender_last = get_user_meta($sender_id, 'last_name', true); + $sender_display_name = trim("$sender_first $sender_last"); + + $receiver_first = get_user_meta($receiver_id, 'first_name', true); + $receiver_last = get_user_meta($receiver_id, 'last_name', true); + $receiver_display_name = trim("$receiver_first $receiver_last"); + + // Get notification preferences + $sender_notify = get_user_meta($sender_id, '_message_notification', true); + $receiver_notify = get_user_meta($receiver_id, '_message_notification', true); + + if ($sender_notify != 1 || $receiver_notify != 1) { + return new WP_REST_Response([ + 'code' => 403, + 'status' => 'Forbidden', + 'message' => 'Both sender and receiver must have message notifications enabled.', + ], 403); + } + + $image_url = ''; + if (!empty($_FILES['image']['tmp_name'])) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + $uploaded = wp_handle_upload($_FILES['image'], ['test_form' => false]); + if (!isset($uploaded['error'])) { + $image_url = esc_url_raw($uploaded['url']); + } + } + + $final_message = ''; + if ($text_message && $image_url) { + $final_message = $text_message . "\n\n" . $image_url; + } elseif ($text_message) { + $final_message = $text_message; + } elseif ($image_url) { + $final_message = $image_url; + } else { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'Bad Request', + 'message' => 'Either message or image is required.', + ], 400); + } + + // Insert into DB + $table = $wpdb->prefix . 'wpem_matchmaking_users_messages'; + $first_message_id = $wpdb->get_var($wpdb->prepare( + "SELECT id FROM $table + WHERE (sender_id = %d AND receiver_id = %d) + OR (sender_id = %d AND receiver_id = %d) + ORDER BY created_at ASC LIMIT 1", + $sender_id, $receiver_id, + $receiver_id, $sender_id + )); + $parent_id = $first_message_id ?: 0; + + $wpdb->insert($table, [ + 'parent_id' => $parent_id, + 'sender_id' => $sender_id, + 'receiver_id' => $receiver_id, + 'message' => $final_message, + 'created_at' => current_time('mysql') + ], ['%d', '%d', '%d', '%s', '%s']); + + $insert_id = $wpdb->insert_id; + + // --- EMAIL SECTION --- + $headers = ['Content-Type: text/html; charset=UTF-8']; + + // Build email body for receiver (your format) + $receiver_body = "Hello, this is a message from {$sender_first}

"; + $receiver_body .= "First Name: {$sender_first}
"; + $receiver_body .= "Last Name: {$sender_last}
"; + $receiver_body .= "Message:
" . nl2br(esc_html($text_message)) . "

"; + if ($image_url) { + $receiver_body .= "

Attachment

"; + } + $receiver_body .= "Thank you."; + + wp_mail( + $receiver_user->user_email, + 'New Message from ' . $sender_first, + $receiver_body, + $headers + ); + + // Build confirmation email for sender + $sender_body = "Hello, this is a confirmation of your message to {$receiver_first}

"; + $sender_body .= "First Name: {$sender_first}
"; + $sender_body .= "Last Name: {$sender_last}
"; + $sender_body .= "Message:
" . nl2br(esc_html($text_message)) . "

"; + if ($image_url) { + $sender_body .= "

Attachment

"; + } + $sender_body .= "Thank you."; + + wp_mail( + $sender_user->user_email, + 'Your Message to ' . $receiver_first, + $sender_body, + $headers + ); + + // --- END EMAIL SECTION --- + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Message sent successfully.', + 'data' => [ + 'id' => $insert_id, + 'parent_id' => $parent_id, + 'sender_id' => $sender_id, + 'receiver_id'=> $receiver_id, + 'message' => $text_message ?: null, + 'image' => $image_url ?: null, + 'created_at' => current_time('mysql'), + ] + ], 200); + } + public function handle_get_messages($request) { + global $wpdb; + + if (!get_option('enable_matchmaking', false)) { + return new WP_REST_Response(array( + 'code' => 403, + 'status' => 'Disabled', + 'message' => 'Matchmaking functionality is not enabled.', + 'data' => null + ), 403); + } + + $sender_id = intval($request->get_param('senderId')); + $receiver_id = intval($request->get_param('receiverId')); + $page = max(1, intval($request->get_param('page'))); + $per_page = max(1, intval($request->get_param('per_page'))); + + if (!$sender_id || !$receiver_id) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'Bad Request', + 'message' => 'senderId and receiverId are required.', + 'data' => null + ], 400); + } + + $offset = ($page - 1) * $per_page; + $table = $wpdb->prefix . 'wpem_matchmaking_users_messages'; + + // Get total message count + $total_messages = $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM $table + WHERE (sender_id = %d AND receiver_id = %d) + OR (sender_id = %d AND receiver_id = %d)", + $sender_id, $receiver_id, $receiver_id, $sender_id + )); + + // Get paginated messages + $messages = $wpdb->get_results($wpdb->prepare( + "SELECT * FROM $table + WHERE (sender_id = %d AND receiver_id = %d) + OR (sender_id = %d AND receiver_id = %d) + ORDER BY created_at DESC + LIMIT %d OFFSET %d", + $sender_id, $receiver_id, $receiver_id, $sender_id, + $per_page, $offset + ), ARRAY_A); + // Separate text and image + foreach ($messages as &$msg) { + // Break message into lines + $parts = preg_split("/\n+/", trim($msg['message'])); + $text_parts = []; + + foreach ($parts as $part) { + $part = trim($part); + if (filter_var($part, FILTER_VALIDATE_URL) && preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $part)) { + $msg['image'] = $part; + } elseif (!empty($part)) { + $text_parts[] = $part; + } + } + + // Replace message with text only + $msg['message'] = implode(' ', $text_parts); + } + + $total_pages = ceil($total_messages / $per_page); + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Messages retrieved successfully.', + 'data' => [ + 'total_page_count' => intval($total_messages), + 'current_page' => $page, + 'last_page' => $total_pages, + 'total_pages' => $total_pages, + 'messages' => array_filter($messages, function ($msg) { + unset($msg['image']); + return $msg; + }), + ] + ], 200); + } + public function handle_get_conversation_list($request) { + global $wpdb; + + $user_id = intval($request->get_param('user_id')); + $paged = max(1, intval($request->get_param('paged'))); + $per_page = max(1, intval($request->get_param('per_page'))); + + if (empty($user_id)) { + return new WP_REST_Response([ + 'code' => 400, + 'status' => 'Bad Request', + 'message' => 'user_id is required.', + ], 400); + } + + $messages_tbl = $wpdb->prefix . 'wpem_matchmaking_users_messages'; + + /** + * Step 1: Get all unique conversation partners + */ + $conversation_user_ids = $wpdb->get_col($wpdb->prepare(" + SELECT DISTINCT other_user FROM ( + SELECT receiver_id AS other_user FROM $messages_tbl WHERE sender_id = %d + UNION + SELECT sender_id AS other_user FROM $messages_tbl WHERE receiver_id = %d + ) AS temp + WHERE other_user != %d + ", $user_id, $user_id, $user_id)); + + if (empty($conversation_user_ids)) { + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'No conversation history found.', + 'data' => [ + 'total_users' => 0, + 'current_page' => $paged, + 'last_page' => 0, + 'users' => [] + ] + ], 200); + } + + /** + * Step 2: Pagination + */ + $total_count = count($conversation_user_ids); + $last_page = ceil($total_count / $per_page); + $offset = ($paged - 1) * $per_page; + $paginated_ids = array_slice($conversation_user_ids, $offset, $per_page); + + /** + * Step 3: Build conversation list with last message + */ + $results = []; + foreach ($paginated_ids as $partner_id) { + // Get last message between the two users + $last_message_row = $wpdb->get_row($wpdb->prepare(" + SELECT message, created_at + FROM $messages_tbl + WHERE (sender_id = %d AND receiver_id = %d) + OR (sender_id = %d AND receiver_id = %d) + ORDER BY created_at DESC + LIMIT 1 + ", $user_id, $partner_id, $partner_id, $user_id)); + + // Build display name + $display_name = get_user_meta($partner_id, 'display_name', true); + if (empty($display_name)) { + $first_name = get_user_meta($partner_id, 'first_name', true); + $last_name = get_user_meta($partner_id, 'last_name', true); + $display_name = trim("$first_name $last_name"); + } + + $is_image = 0; + if ($last_message_row && preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $last_message_row->message)) { + $is_image = 1; + } + $photo = get_wpem_user_profile_photo($partner_id); + $results[] = [ + 'user_id' => (int) $partner_id, + 'first_name' => get_user_meta($partner_id, 'first_name', true), + 'last_name' => get_user_meta($partner_id, 'last_name', true), + 'display_name' => $display_name, + 'profile_photo' => $photo, + 'profession' => get_user_meta($partner_id, '_profession', true), + 'company_name' => get_user_meta($partner_id, '_company_name', true), + 'last_message' => $last_message_row ? $last_message_row->message : null, + 'message_time' => $last_message_row ? date('Y-m-d H:i:s', strtotime($last_message_row->created_at)) : null, + 'last_message_is_image' => $is_image, + ]; + } + + return new WP_REST_Response([ + 'code' => 200, + 'status' => 'OK', + 'message' => 'Conversation list retrieved successfully.', + 'data' => [ + 'total_users' => $total_count, + 'current_page' => $paged, + 'per_page' => $per_page, + 'last_page' => $last_page, + 'users' => $results + ] + ], 200); + } +} + +new WPEM_REST_Send_Message_Controller(); diff --git a/includes/wpem-rest-matchmaking-user-registred-events.php b/includes/wpem-rest-matchmaking-user-registred-events.php new file mode 100644 index 0000000..d7ef37d --- /dev/null +++ b/includes/wpem-rest-matchmaking-user-registred-events.php @@ -0,0 +1,104 @@ +namespace, + '/' . $this->rest_base, + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'get_user_registered_events'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array( + 'required' => true, + 'type' => 'integer', + 'description' => 'User ID to fetch registered events for.' + ) + ) + ) + ); + } + + public function get_user_registered_events($request) { + $target_user_id = intval($request->get_param('user_id')); + + // Get user's email from ID + $user_info = get_userdata($target_user_id); + if (!$user_info) { + return new WP_REST_Response(array( + 'code' => 404, + 'status' => 'ERROR', + 'message' => 'User not found.', + 'data' => [] + ), 404); + } + + $user_email = $user_info->user_email; + + // Get all event registrations where attendee email matches + $args = array( + 'post_type' => 'event_registration', + 'posts_per_page' => -1, + 'meta_query' => array( + array( + 'key' => '_attendee_email', + 'value' => $user_email, + 'compare' => '=' + ) + ) + ); + + $query = new WP_Query($args); + + $event_ids = array(); + foreach ($query->posts as $registration_post) { + $event_id = wp_get_post_parent_id($registration_post->ID); + if (!empty($event_id) && !in_array($event_id, $event_ids)) { + $event_ids[] = (int) $event_id; + } + } + + if (empty($event_ids)) { + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'No registered events found.', + 'data' => [] + ), 200); + } + + $events = array(); + foreach ($event_ids as $event_id) { + $post = get_post($event_id); + if ($post && $post->post_type === 'event_listing') { + $events[] = array( + 'event_id' => $event_id, + 'title' => get_the_title($event_id), + 'status' => $post->post_status, + 'start_date' => get_post_meta($event_id, '_event_start_date', true), + 'end_date' => get_post_meta($event_id, '_event_end_date', true), + 'location' => get_post_meta($event_id, '_event_location', true), + 'banner' => get_post_meta($event_id, '_event_banner', true), + ); + } + } + + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'Events retrieved successfully.', + 'data' => $events + ), 200); + } +} + +new WPEM_REST_User_Registered_Events_Controller(); diff --git a/includes/wpem-rest-matchmaking-user-settings.php b/includes/wpem-rest-matchmaking-user-settings.php new file mode 100644 index 0000000..4c2419c --- /dev/null +++ b/includes/wpem-rest-matchmaking-user-settings.php @@ -0,0 +1,198 @@ +namespace, + '/matchmaking-attendee-settings', + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array($this, 'get_matchmaking_attendee_settings'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array( + 'required' => false, + 'type' => 'integer' + ), + 'event_id' => array( + 'required' => false, + 'type' => 'integer' + ) + ), + ) + ); + + // POST - Update settings + register_rest_route( + $this->namespace, + '/update-matchmaking-attendee-settings', + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array($this, 'update_matchmaking_attendee_settings'), + 'permission_callback' => array($auth_controller, 'check_authentication'), + 'args' => array( + 'user_id' => array( + 'required' => false, + 'type' => 'integer' + ), + 'enable_matchmaking' => array( + 'required' => false, + 'type' => 'integer' + ), + 'message_notification' => array( + 'required' => false, + 'type' => 'integer' + ), + 'meeting_request_mode' => array( + 'required' => false, + 'type' => 'string' + ), + 'event_participation' => array( + 'required' => false, + 'type' => 'array' + ) + ), + ) + ); + } + + public function get_matchmaking_attendee_settings($request) { + $user_id = $request->get_param('user_id') ?: get_current_user_id(); + $event_id = (int) $request->get_param('event_id'); + + $user = get_user_by('id', $user_id); + if (!$user) { + return new WP_REST_Response(array( + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'User not found.', + 'data' => null + ), 404); + } + + $user_event_participation = []; + + if ($event_id) { + // Get registrations for specific event + $registration_post_ids = get_posts([ + 'post_type' => 'event_registration', + 'posts_per_page' => -1, + 'post_status' => 'any', + 'author' => $user_id, + 'post_parent' => $event_id, + 'fields' => 'ids', + ]); + + if (!empty($registration_post_ids)) { + $create_matchmaking = (int) get_post_meta($registration_post_ids[0], '_create_matchmaking', true); + $user_event_participation[] = [ + 'event_id' => $event_id, + 'create_matchmaking' => $create_matchmaking + ]; + } + } else { + // Get all registrations for this user + $user_registrations = get_posts([ + 'post_type' => 'event_registration', + 'posts_per_page' => -1, + 'post_status' => 'any', + 'author' => $user_id, + 'fields' => 'ids', + ]); + + foreach ($user_registrations as $registration_id) { + $parent_event_id = (int) get_post_field('post_parent', $registration_id); + if (!$parent_event_id) { + continue; + } + $create_matchmaking = (int) get_post_meta($registration_id, '_create_matchmaking', true); + $user_event_participation[] = [ + 'event_id' => $parent_event_id, + 'create_matchmaking' => $create_matchmaking + ]; + } + } + + $settings = array( + 'enable_matchmaking' => (int) get_user_meta($user_id, '_matchmaking_profile', true)[0], + 'message_notification' => (int) get_user_meta($user_id, '_message_notification', true), + 'event_participation' => $user_event_participation, + 'meeting_request_mode' => get_user_meta($user_id, '_wpem_meeting_request_mode', true) ?: 'approval' + ); + + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'Settings retrieved successfully.', + 'data' => $settings + ), 200); + } + + public function update_matchmaking_attendee_settings($request) { + $user_id = $request->get_param('user_id') ?: get_current_user_id(); + $user = get_user_by('id', $user_id); + + if (!$user) { + return new WP_REST_Response(array( + 'code' => 404, + 'status' => 'Not Found', + 'message' => 'User not found.', + 'data' => null + ), 404); + } + + // Update user meta + if (!is_null($request->get_param('enable_matchmaking'))) { + update_user_meta($user_id, '_matchmaking_profile', (int) $request->get_param('enable_matchmaking')); + } + if (!is_null($request->get_param('message_notification'))) { + update_user_meta($user_id, '_message_notification', (int) $request->get_param('message_notification')); + } + if (!is_null($request->get_param('meeting_request_mode'))) { + update_user_meta($user_id, '_wpem_meeting_request_mode', sanitize_text_field($request->get_param('meeting_request_mode'))); + } + + // Update event participation settings + $event_participation = $request->get_param('event_participation'); + if (is_array($event_participation)) { + foreach ($event_participation as $event) { + if (!isset($event['event_id'])) { + continue; + } + $eid = (int) $event['event_id']; + $value = isset($event['create_matchmaking']) ? (int) $event['create_matchmaking'] : 0; + + $registration_post_ids = get_posts([ + 'post_type' => 'event_registration', + 'posts_per_page' => -1, + 'post_status' => 'any', + 'author' => $user_id, + 'post_parent' => $eid, + 'fields' => 'ids', + ]); + + foreach ($registration_post_ids as $registration_post_id) { + update_post_meta($registration_post_id, '_create_matchmaking', $value); + } + } + } + + return new WP_REST_Response(array( + 'code' => 200, + 'status' => 'OK', + 'message' => 'Settings updated successfully.', + ), 200); + } +} + +new WPEM_REST_Attendee_Settings_Controller(); diff --git a/includes/rest-api/wpem-rest-organizers-controller.php b/includes/wpem-rest-organizers-controller.php similarity index 100% rename from includes/rest-api/wpem-rest-organizers-controller.php rename to includes/wpem-rest-organizers-controller.php diff --git a/includes/rest-api/wpem-rest-posts-conroller.php b/includes/wpem-rest-posts-conroller.php similarity index 100% rename from includes/rest-api/wpem-rest-posts-conroller.php rename to includes/wpem-rest-posts-conroller.php diff --git a/includes/rest-api/wpem-rest-venues-controller.php b/includes/wpem-rest-venues-controller.php similarity index 100% rename from includes/rest-api/wpem-rest-venues-controller.php rename to includes/wpem-rest-venues-controller.php diff --git a/readme.txt b/readme.txt index 214cc2b..d2b77c7 100755 --- a/readme.txt +++ b/readme.txt @@ -1,11 +1,11 @@ -=== WPEM - REST API === +=== WP Event Manager - REST API === Contributors: wpeventmanager,ashokdudhat,krinay Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=55FRYATTFLA5N Tags: event manager, Event, events, event manager api , listings -Requires at least: 6.0.1 -Tested up to: 6.7 -Stable tag: 1.0.8 +Requires at least: 6.5.1 +Tested up to: 6.8 +Stable tag: 1.1.0 Requires PHP: 8.0.0 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -119,6 +119,26 @@ If you wish to be notified of new postings on your site you can use a plugin suc == Changelog == + += 1.1.0 [ 19th August 2025 ] = + +Fixed : Change the Plugin name +Fixed : After password change the user will auto logout from mobile app +Fixed : Without Active license some section of the app will not work +Added : Match making functionality + += 1.0.10 [ 09th May 2025 ] = + +Fixed: All events are shown even from other organizers + += 1.0.9 [ 02nd May 2025 ] = + +Fixed: API response time is improved to make APIs faster +Fixed: API requests are now protected with authorization +Fixed: The data loading time in the attendee section became faster +Fixed: The manual check-in process of attendees became faster +Fixed: Initiated multiple bug fixes and code improvements + = 1.0.8 [ 27th March 2025 ] = Fixed : Password with some special character, user not able to loggedin in app. diff --git a/wpem-rest-api-functions.php b/wpem-rest-api-functions.php index 07c2ac3..a3096fa 100644 --- a/wpem-rest-api-functions.php +++ b/wpem-rest-api-functions.php @@ -277,6 +277,7 @@ function get_wpem_rest_api_ecosystem_info(){ 'wp-event-manager-sell-tickets' => 'WP Event Manager Sell Tickets', 'wp-event-manager-registrations' => 'WP Event Manager Registrations', 'wpem-guests' => 'WP Event Manager Guests', + 'wpem-speaker-schedule' => 'WP Event Manager Speaker & Schedule' ) ); // Get ecosystem data @@ -393,73 +394,39 @@ function get_wpem_event_users() { } } -if( !function_exists( 'wpem_rest_check_user_data' ) ) { - +if( !function_exists( 'wpem_rest_get_current_user_id' ) ) { /** - * This function is used to check user information + * This function is used to check user is exist or not. + * @since 1.0.1 */ - function wpem_rest_check_user_data() { + function wpem_rest_get_current_user_id(){ // Get the authorization header - global $wpdb; $headers = getallheaders(); - $auth_header = isset($headers['Authorization']) ? $headers['Authorization'] : ''; - - if(empty($auth_header)) { - $headers = apache_request_headers(); - // Ensure case insensitivity - $auth_header = ''; - foreach ($headers as $key => $value) { - if (strtolower($key) === 'authorization') { - $auth_header = $value; - break; - } - } + $token = ''; + + // First try standard header + if (isset($headers['Authorization'])) { + $token = trim(str_replace('Bearer', '', $headers['Authorization'])); + } + // Try for some server environments + elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) { + $token = trim(str_replace('Bearer', '', $_SERVER['HTTP_AUTHORIZATION'])); + } + // NGINX or fastcgi_pass may use this + elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $token = trim(str_replace('Bearer', '', $_SERVER['REDIRECT_HTTP_AUTHORIZATION'])); } - // Check if authorization header is provided - if (!$auth_header) { + if(empty($token)) { return WPEM_REST_CRUD_Controller::prepare_error_for_response(401); } - // Handle Basic Auth - if (strpos($auth_header, 'Basic ') === 0) { - $auth = base64_decode(substr($auth_header, 6)); - list($consumer_key, $consumer_secret) = explode(':', $auth); - // Validate the credentials - if ($consumer_key && $consumer_secret) { - $app_key = $wpdb->get_var($wpdb->prepare("SELECT app_key FROM {$wpdb->prefix}wpem_rest_api_keys WHERE consumer_key = '$consumer_key'")); - if($app_key){ - return $app_key; - } else{ - return true; - } - } else { - return true; - } - } else { - return true; + $user_data = WPEM_REST_CRUD_Controller::wpem_validate_jwt_token($token); + if (!$user_data) { + return WPEM_REST_CRUD_Controller::prepare_error_for_response(405); } - } -} -if( !function_exists( 'wpem_rest_get_current_user_id' ) ) { - /** - * This function is used to check user is exist or not. - * @since 1.0.1 - */ - function wpem_rest_get_current_user_id(){ - global $wpdb; - $get_user_id = wpem_rest_check_user_data(); - // Check if $get_userid is a WP_REST_Response object - if (is_a($get_user_id, 'WP_REST_Response')) { - // Extract the data from the response - $get_user_id = $get_user_id->get_data(); - } - $user_id = $wpdb->get_var($wpdb->prepare("SELECT user_id FROM {$wpdb->prefix}wpem_rest_api_keys WHERE app_key = '$get_user_id'")); - if ($user_id) { - return $user_id; - } else { - return false; - } + $user_id = $user_data['id']; + return $user_id; } } @@ -490,4 +457,21 @@ function check_wpem_plugin_activation($plugin_domain) { } } } +} + +/** + * This function will used to generate base64url_encode + * @since 1.0.9 + */ +function wpem_base64url_encode($data) { + return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); +} + +function wpem_base64url_decode($data) { + $remainder = strlen($data) % 4; + if ($remainder) { + $padlen = 4 - $remainder; + $data .= str_repeat('=', $padlen); + } + return base64_decode(strtr($data, '-_', '+/')); } \ No newline at end of file diff --git a/wpem-rest-api.php b/wpem-rest-api.php index 3f44570..8d423f6 100644 --- a/wpem-rest-api.php +++ b/wpem-rest-api.php @@ -1,6 +1,6 @@ prefix . 'wpem_rest_api_keys'; + $columns = $wpdb->get_col("DESC {$table_name}", 0); + + // Add event_show_by column if it doesn't exist + if (!in_array('event_show_by', $columns)) { + $wpdb->query("ALTER TABLE {$table_name} ADD COLUMN event_show_by varchar(20) NULL DEFAULT 'loggedin'"); + } + + // Add selected_events column if it doesn't exist + if (!in_array('selected_events', $columns)) { + $wpdb->query("ALTER TABLE {$table_name} ADD COLUMN selected_events longtext NULL"); + } update_option( 'wpem_rest_api_version', WPEM_REST_API_VERSION ); @@ -153,4 +183,4 @@ function wpem_rest_api_pre_check_before_installing_event_rest_api() { return false; } } -add_action( 'admin_notices', 'wpem_rest_api_pre_check_before_installing_event_rest_api' ); +add_action( 'admin_notices', 'wpem_rest_api_pre_check_before_installing_event_rest_api' ); \ No newline at end of file