mirror of
https://gh.wpcy.net/https://github.com/discourse/wp-discourse.git
synced 2026-05-23 03:20:46 +08:00
* Update and improve webhooks Changes: - Add email matching as an identification basis for Update Userdata webhook. - Standardise webhook data processing and responses. - Add get_discourse_webhook_data utility method. - Improve Webhook admin panel UX and descriptions. Misc: - Update phpcs usage * Fix php 5.6 and 7.0 syntax checks * Fix phpcs issues arising from update * Remove ineffective nbsp from admin page
423 lines
12 KiB
PHP
Vendored
423 lines
12 KiB
PHP
Vendored
<?php
|
|
/**
|
|
* Static utility functions for external use.
|
|
*
|
|
* @package WPDiscourse
|
|
*/
|
|
|
|
namespace WPDiscourse\Utilities;
|
|
|
|
use WPDiscourse\Utilities\PublicUtilities;
|
|
|
|
/**
|
|
* Class Utilities
|
|
*
|
|
* @package WPDiscourse
|
|
*/
|
|
class Utilities {
|
|
/**
|
|
* Public static alias for get_options.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function get_options() {
|
|
$utils = new PublicUtilities();
|
|
return $utils->get_options();
|
|
}
|
|
|
|
/**
|
|
* Public static alias for validate.
|
|
*
|
|
* @param array $response The response from `wp_remote_request`.
|
|
*
|
|
* @return int
|
|
*/
|
|
public static function validate( $response ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->validate( $response );
|
|
}
|
|
|
|
/**
|
|
* Public static alias for get_discourse_categories.
|
|
*
|
|
* @return \WP_Error|array
|
|
*/
|
|
public static function get_discourse_categories() {
|
|
$utils = new PublicUtilities();
|
|
return $utils->get_discourse_categories();
|
|
}
|
|
|
|
/**
|
|
* Public static alias for sync_sso.
|
|
*
|
|
* @param array $sso_params The sso params to sync.
|
|
* @param int $user_id The WordPress user's ID.
|
|
*
|
|
* @return int|string|\WP_Error
|
|
*/
|
|
public static function sync_sso_record( $sso_params, $user_id = null ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->sync_sso( $sso_params, $user_id );
|
|
}
|
|
|
|
/**
|
|
* Public static alias for get_discourse_user.
|
|
*
|
|
* @param int $user_id The WordPress user_id.
|
|
* @param bool $match_by_email Whether or not to attempt to get the user by their email address.
|
|
*
|
|
* @return array|mixed|object|\WP_Error
|
|
*/
|
|
public static function get_discourse_user( $user_id, $match_by_email = false ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->get_discourse_user( $user_id, $match_by_email );
|
|
}
|
|
|
|
/**
|
|
* Public static alias for get_discourse_user_by_email.
|
|
*
|
|
* @param string $email The email address to search for.
|
|
*
|
|
* @return object \WP_Error
|
|
*/
|
|
public static function get_discourse_user_by_email( $email ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->get_discourse_user_by_email( $email );
|
|
}
|
|
|
|
/**
|
|
* Public static alias for discourse_request.
|
|
*
|
|
* @param string $path Request path.
|
|
* @param array $args Request args.
|
|
*
|
|
* @return array|\WP_Error|void
|
|
*/
|
|
public static function discourse_request( $path, $args = array() ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->discourse_request( $path, $args );
|
|
}
|
|
|
|
/**
|
|
* Public static alias for get_sso_params.
|
|
*
|
|
* @param object $user The WordPress user.
|
|
* @param array $sso_options An optional array of extra SSO parameters.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function get_sso_params( $user, $sso_options = array() ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->get_sso_params( $user, $sso_options );
|
|
}
|
|
|
|
/**
|
|
* Get data from a request originating from a Discourse webhook.
|
|
*
|
|
* @param \WP_REST_Request $request The WP_REST_Request object.
|
|
* @param array $supported_events An optional array of supported events.
|
|
* @param string $logger_context An optional logger context.
|
|
*
|
|
* @return object|\WP_Error
|
|
*/
|
|
public static function get_discourse_webhook_data( $request, $supported_events = null, $logger_context = null ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->get_discourse_webhook_data( $request, $supported_events, $logger_context );
|
|
}
|
|
|
|
/**
|
|
* Verify that the request originated from a Discourse webhook and the secret keys match.
|
|
*
|
|
* @param \WP_REST_Request $request The WP_REST_Request object.
|
|
*
|
|
* @return \WP_Error|\WP_REST_Request
|
|
*/
|
|
public static function verify_discourse_webhook_request( $request ) {
|
|
$utils = new PublicUtilities();
|
|
return $utils->verify_discourse_webhook_request( $request );
|
|
}
|
|
|
|
/**
|
|
* Creates a Discourse user through the API.
|
|
*
|
|
* @param \WP_User $user The WordPress user.
|
|
* @param bool $require_activation Whether or not to require an activation email to be sent.
|
|
*
|
|
* @return int|\WP_Error
|
|
*/
|
|
public static function create_discourse_user( $user, $require_activation = true ) {
|
|
$utils = new PublicUtilities();
|
|
$api_credentials = $utils->get_api_credentials();
|
|
|
|
if ( is_wp_error( $api_credentials ) ) {
|
|
return new \WP_Error( 'wpdc_configuration_error', 'The Discourse Connection options are not properly configured.' );
|
|
}
|
|
|
|
if ( empty( $user ) || empty( $user->ID ) || is_wp_error( $user ) ) {
|
|
return new \WP_Error( 'wpdc_user_not_set_error', 'The Discourse user you are attempting to create does not exist on WordPress.' );
|
|
}
|
|
|
|
$require_activation = apply_filters( 'wpdc_auto_create_user_require_activation', $require_activation, $user );
|
|
$create_user_url = esc_url_raw( "{$api_credentials['url']}/users" );
|
|
$username = $user->user_login;
|
|
$name = $user->display_name;
|
|
$email = $user->user_email;
|
|
$password = wp_generate_password( 20 );
|
|
$body = array(
|
|
'name' => $name,
|
|
'email' => $email,
|
|
'password' => $password,
|
|
'username' => $username,
|
|
'active' => $require_activation ? 'false' : 'true',
|
|
'approved' => 'true',
|
|
);
|
|
|
|
$user_data = static::discourse_request(
|
|
$create_user_url, array(
|
|
'body' => $body,
|
|
'method' => 'POST',
|
|
)
|
|
);
|
|
|
|
if ( is_wp_error( $user_data ) ) {
|
|
return $user_data;
|
|
}
|
|
|
|
if ( empty( $user_data->success ) ) {
|
|
|
|
return new \WP_Error( 'wpdc_response_error', $user_data->message );
|
|
}
|
|
|
|
if ( isset( $user_data->user_id ) ) {
|
|
|
|
return $user_data->user_id;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
const GROUP_SCHEMA = array(
|
|
'id' => 'int',
|
|
'name' => 'text',
|
|
'full_name' => 'text',
|
|
'user_count' => 'int',
|
|
'mentionable_level' => 'int',
|
|
'messageable_level' => 'int',
|
|
'visibility_level' => 'int',
|
|
'primary_group' => 'bool',
|
|
'title' => 'text',
|
|
'grant_trust_level' => 'int',
|
|
'incoming_email' => 'text',
|
|
'has_messages' => 'bool',
|
|
'flair_url' => 'text',
|
|
'flair_bg_color' => 'text',
|
|
'flair_color' => 'text',
|
|
'bio_raw' => 'textarea',
|
|
'bio_cooked' => 'html',
|
|
'bio_excerpt' => 'html',
|
|
'public_admission' => 'bool',
|
|
'public_exit' => 'bool',
|
|
'allow_membership_requests' => 'bool',
|
|
'default_notification_level' => 'int',
|
|
'membership_request_template' => 'text',
|
|
'members_visibility_level' => 'int',
|
|
'publish_read_state' => 'bool',
|
|
);
|
|
|
|
/**
|
|
* Gets the non-automatic Discourse groups and saves them in a transient.
|
|
*
|
|
* The transient has an expiry time of 10 minutes.
|
|
*
|
|
* @return array|\WP_Error
|
|
*/
|
|
public static function get_discourse_groups() {
|
|
$groups = get_transient( 'wpdc_non_automatic_groups' );
|
|
if ( ! empty( $groups ) ) {
|
|
return $groups;
|
|
}
|
|
|
|
$path = '/groups';
|
|
$response = static::discourse_request( $path );
|
|
$discourse_page_size = 36;
|
|
|
|
if ( ! is_wp_error( $response ) && ! empty( $response->groups ) ) {
|
|
$groups = static::extract_groups( $response->groups );
|
|
$total_groups = $response->total_rows_groups;
|
|
$load_more_path = $response->load_more_groups;
|
|
|
|
if ( ( $total_groups > $discourse_page_size ) ) {
|
|
$last_page = ( ceil( $total_groups / $discourse_page_size ) ) - 1;
|
|
|
|
foreach ( range( 1, $last_page ) as $index ) {
|
|
if ( $load_more_path ) {
|
|
$response = static::discourse_request( $load_more_path );
|
|
$load_more_path = $response->load_more_groups;
|
|
|
|
if ( ! is_wp_error( $response ) && ! empty( $response->groups ) ) {
|
|
$groups = array_merge( $groups, static::extract_groups( $response->groups ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
set_transient( 'wpdc_non_automatic_groups', $groups, 10 * MINUTE_IN_SECONDS );
|
|
|
|
return $groups;
|
|
} else {
|
|
return new \WP_Error( 'wpdc_response_error', 'No groups were returned from Discourse.' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a user to a Discourse groups.
|
|
*
|
|
* @param int $user_id The user's ID.
|
|
* @param string $group_names A comma separated list of group names.
|
|
*
|
|
* @return int|string
|
|
*/
|
|
public static function add_user_to_discourse_group( $user_id, $group_names ) {
|
|
$options = self::get_options();
|
|
if ( empty( $options['enable-sso'] ) ) {
|
|
|
|
return new \WP_Error( 'wpdc_sso_error', 'The add_user_to_discourse_group function can only be used when DiscourseConnect is enabled.' );
|
|
}
|
|
$user = get_user_by( 'id', $user_id );
|
|
$sso_params = self::get_sso_params(
|
|
$user,
|
|
array(
|
|
'add_groups' => $group_names,
|
|
)
|
|
);
|
|
|
|
return static::sync_sso_record( $sso_params );
|
|
}
|
|
|
|
/**
|
|
* Removes a user from Discourse groups.
|
|
*
|
|
* @param int $user_id The user's ID.
|
|
* @param string $group_names A comma separated list of group names.
|
|
*
|
|
* @return int|string
|
|
*/
|
|
public static function remove_user_from_discourse_group( $user_id, $group_names ) {
|
|
$options = self::get_options();
|
|
if ( empty( $options['enable-sso'] ) ) {
|
|
|
|
return new \WP_Error( 'wpdc_sso_error', 'The remove_user_from_discourse_group function can only be used when DiscourseConnect is enabled.' );
|
|
}
|
|
$user = get_user_by( 'id', $user_id );
|
|
$sso_params = self::get_sso_params(
|
|
$user,
|
|
array(
|
|
'remove_groups' => $group_names,
|
|
)
|
|
);
|
|
|
|
return self::sync_sso_record( $sso_params );
|
|
}
|
|
|
|
/**
|
|
* Get the Discourse comment HTML so that it can be displayed without loading the comments template.
|
|
*
|
|
* @param int $post_id The post ID to display the comments for.
|
|
* @param bool $perform_sync Determines whether a comment sync is maybe performed when loading comments.
|
|
* @param bool $force_sync Determines whether comment sync cache is bypassed when loading comments.
|
|
* @param string $comment_type Type of comment display.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function get_discourse_comments( $post_id, $perform_sync = true, $force_sync = false, $comment_type = null ) {
|
|
$comment_formatter = new \WPDiscourse\DiscourseCommentFormatter\DiscourseCommentFormatter();
|
|
$comment_formatter->setup_options();
|
|
$comment_formatter->setup_logger();
|
|
|
|
return $comment_formatter->format( $post_id, $perform_sync, $force_sync, $comment_type );
|
|
}
|
|
|
|
/**
|
|
* Helper function for get_discourse_groups().
|
|
*
|
|
* @param array $raw_groups raw groups data array.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function extract_groups( $raw_groups ) {
|
|
return array_reduce(
|
|
$raw_groups,
|
|
function ( $result, $group ) {
|
|
if ( empty( $group->automatic ) ) {
|
|
$result[] = static::discourse_munge( $group, static::GROUP_SCHEMA );
|
|
}
|
|
return $result;
|
|
},
|
|
array()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Munge raw discourse data
|
|
*
|
|
* @param array $data Data to munge.
|
|
* @param schema $schema Schema to apply.
|
|
*
|
|
* @return object
|
|
*/
|
|
public static function discourse_munge( $data, $schema ) {
|
|
$result = (object) array();
|
|
|
|
foreach ( $data as $key => $value ) {
|
|
if ( isset( $schema[ $key ] ) ) {
|
|
if ( null !== $value ) {
|
|
switch ( $schema[ $key ] ) {
|
|
case 'int':
|
|
$result->{$key} = intval( $value );
|
|
break;
|
|
case 'bool':
|
|
$result->{$key} = true === $value;
|
|
break;
|
|
case 'text':
|
|
$result->{$key} = sanitize_text_field( $value );
|
|
break;
|
|
case 'textarea':
|
|
$result->{$key} = sanitize_textarea_field( $value );
|
|
break;
|
|
case 'html':
|
|
$result->{$key} = $value;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
$result->{$key} = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Publishes a post to a Discourse.
|
|
*
|
|
* @param string $post_id ID of the post to publish.
|
|
* @param array $options An optional array of options to pass to DiscoursePublish.
|
|
*
|
|
* @return void|\WP_Error;
|
|
*/
|
|
public static function publish_to_discourse( $post_id, $options = array() ) {
|
|
$post = get_post( $post_id );
|
|
|
|
if ( ! $post ) {
|
|
return new \WP_Error( 'wpdc_param_error', 'There is no WordPress post with the supplied id.' );
|
|
}
|
|
|
|
$email_notifier = new \WPDiscourse\EmailNotification\EmailNotification();
|
|
$publish = new \WPDiscourse\DiscoursePublish\DiscoursePublish( $email_notifier, false );
|
|
$publish->setup_options( $options );
|
|
$publish->setup_logger();
|
|
$publish->sync_to_discourse( $post_id, $post->post_title, $post->post_content );
|
|
}
|
|
}
|