8889841cAbstract.php000064400000000507150513455650007033 0ustar00service = tribe( 'events-aggregator.service' ); } } Requests.php000064400000003160150513455650007101 0ustar00 $x_ea_site ]; } /** * Retrieve the raw response from the HTTP request using the GET method. * * @param string $url Site URL to retrieve. * @param array $args Optional. Request arguments. Default empty array. * * @return array|WP_Error */ public function get( $url, $args = [] ) { $site_headers = $this->get_site_headers(); if ( empty( $args['headers'] ) ) { $args['headers'] = $site_headers; } else { $args['headers'] = array_merge( $args['headers'], $site_headers ); } $response = wp_remote_get( $url, $args ); return $response; } /** * Retrieve the raw response from the HTTP request using the POST method. * * @since 4.6.2 * * @param string $url Site URL to retrieve. * @param array $args Optional. Request arguments. Default empty array. * * @return array|WP_Error */ public function post( $url, $args = [] ) { $site_headers = $this->get_site_headers(); if ( empty( $args['headers'] ) ) { $args['headers'] = $site_headers; } else { $args['headers'] = array_merge( $args['headers'], $site_headers ); } $response = wp_remote_post( $url, $args ); return $response; } } Import.php000064400000014252150513455650006544 0ustar00 'post_title', 'description' => 'post_content', 'start_date' => 'EventStartDate', 'start_hour' => 'EventStartHour', 'start_minute' => 'EventStartMinute', 'start_meridian' => 'EventStartMeridian', 'end_date' => 'EventEndDate', 'end_hour' => 'EventEndHour', 'end_minute' => 'EventEndMinute', 'end_meridian' => 'EventEndMeridian', 'url' => 'EventURL', 'parent_id' => 'parent_id', 'uid' => 'uid', 'dev_start' => 'dev_start', 'dev_end' => 'dev_end', 'all_day' => 'EventAllDay', 'timezone' => 'EventTimezone', 'recurrence' => 'recurrence', 'categories' => 'categories', 'currency_symbol' => 'EventCurrencySymbol', 'currency_position' => 'EventCurrencyPosition', 'cost' => 'EventCost', ]; public $organizer_field_map = [ 'organizer' => 'Organizer', 'phone' => 'Phone', 'website' => 'Website', 'email' => 'Email', ]; public $venue_field_map = [ 'venue' => 'Venue', 'address' => 'Address', 'city' => 'City', 'stateprovince' => 'StateProvince', 'country' => 'Country', 'zip' => 'Zip', 'phone' => 'Phone', 'overwrite_coordinates' => 'OverwriteCoords', 'latitude' => 'Lat', 'longitude' => 'Lng', ]; public function __construct() { parent::__construct(); } /** * Gets the status (and possibly the results) of an import * * @param string $import_id Event Aggregator import id * * @return stdClass|WP_Error A class containing the service response or a WP_Error if the service could not be reached. */ public function get( $import_id, $data = [] ) { $response = $this->service->get_import( $import_id, $data ); if ( is_wp_error( $response ) ) { /** @var WP_Error $response */ if ( 'core:aggregator:http_request-limit' === $response->get_error_code() ) { $response = (object) [ 'status' => 'queued', 'message_code' => 'queued', 'message' => tribe( 'events-aggregator.service' )->get_service_message( 'queued' ), 'data' => (object) [ 'import_id' => $import_id, ], ]; } return $response; } // let's try to use the localized version of the message if available if ( ! empty( $response->message_code ) ) { $default = ! empty( $response->message ) ? $response->message : $this->service->get_unknown_message(); $message_args = is_array( $response->data ) ? $response->data : []; $response->message = $this->service->get_service_message( $response->message_code, $message_args, $default ); } if ( 'success_import-complete' !== $response->message_code ) { return $response; } $events = []; foreach ( $response->data->events as $event ) { $events[] = $this->translate_json_to_event( $event ); } return $events; } /** * Creates an import * * @param array $args Array of arguments for event creation * * @return stdClass|WP_Error */ public function create( $args ) { return $this->service->post_import( $args ); } /** * Update the details of an existing import into EA server. * * @since 5.1.5 * * @param $import_id string The ID of the import to be updated. * @param $args array An key, value array representing the values to update on the EA server. * * @return object|stdClass|string|WP_Error Response from EA server. */ public function update( $import_id, $args ) { return $this->service->update_import( $import_id, $args ); } /** * Translates event JSON to the-events-calendar Event array format * * @param object $json Event data in Event Aggregator format * * @return array */ public function translate_json_to_event( $json ) { if ( empty( $json->title ) || empty( $json->start_date ) || empty( $json->start_hour ) || empty( $json->start_minute ) || empty( $json->end_date ) || empty( $json->end_hour ) || empty( $json->end_minute ) ) { return tribe_error( 'core:aggregator:invalid-event-json' ); } $event = []; $event['post_type'] = Tribe__Events__Main::POSTTYPE; $event['post_status'] = tribe( 'events-aggregator.settings' )->default_post_status( $json->origin ); // translate json key/value pairs to event array key/value pairs foreach ( get_object_vars( $json ) as $key => $value ) { // venues and organizers are a bit more complex. We'll handle those later if ( 'venue' === $key || 'organizer' === $key ) { continue; } if ( isset( $this->event_field_map[ $key ] ) ) { $key = $this->event_field_map[ $key ]; } $event[ $key ] = $value; } if ( ! empty( $json->venue ) ) { $event['Venue'] = []; if ( ! is_array( $json->venue ) ) { $json->venue = [ $json->venue ]; } foreach ( $json->venue as $venue ) { $venue_data = []; if ( empty( $venue->venue ) ) { continue; } foreach ( get_object_vars( $venue ) as $key => $value ) { if ( isset( $this->venue_field_map[ $key ] ) ) { $key = $this->venue_field_map[ $key ]; } $venue_data[ $key ] = $value; } $event['Venue'][] = $venue_data; } } if ( ! empty( $json->organizer ) ) { $event['Organizer'] = []; if ( ! is_array( $json->organizer ) ) { $json->organizer = [ $json->organizer ]; } foreach ( $json->organizer as $organizer ) { $organizer_data = []; if ( empty( $organizer->organizer ) ) { continue; } foreach ( get_object_vars( $organizer ) as $key => $value ) { if ( isset( $this->organizer_field_map[ $key ] ) ) { $key = $this->organizer_field_map[ $key ]; } $organizer_data[ $key ] = $value; } $event['Organizer'][] = $organizer_data; } } $show_map_setting = tribe( 'events-aggregator.settings' )->default_map( $json->origin ); $event['EventShowMap'] = $show_map_setting; $event['EventShowMapLink'] = $show_map_setting; return $event; } } Image.php000064400000011637150513455650006320 0ustar00 'attachment', 'post_status' => 'any', // Fetch the first only 'posts_per_page' => 1, // We only need the ID 'fields' => 'ids', 'meta_query' => [ [ 'key' => $tribe_aggregator_meta_key, 'value' => $image_id, ], ], ] ); $upload_dir = wp_upload_dir(); $file = new stdClass; // if the file has already been added to the filesystem, don't create a duplicate...re-use it if ( $query->have_posts() ) { $attachment = reset( $query->posts ); $attachment_meta = wp_get_attachment_metadata( $attachment ); $file->post_id = (int) $attachment; $file->filename = basename( $attachment_meta['file'] ); $file->path = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . $attachment_meta['file']; // Fetch the Extension for this filename $filetype = wp_check_filetype( $file->filename, null ); $file->extension = $filetype['ext']; $file->status = 'skipped'; return $file; } // fetch an image $response = $this->service->get_image( $image_id, $record ); if ( is_wp_error( $response ) ) { return $response; } // Get Headers and Body $headers = wp_remote_retrieve_headers( $response ); $body = wp_remote_retrieve_body( $response ); $is_invalid_image = empty( $headers['content-type'] ) && empty( $headers['content-disposition'] ) ; // Baild if we don't have Content type or Disposition if ( $is_invalid_image ) { return new WP_Error( 'invalid-file-headers', $body ); } // if the response isn't an image then we need to bail if ( ! preg_match( '/image/', $headers['content-type'] ) ) { /** * @todo See a way for Tribe__Errors to handle overwriting */ return new WP_Error( 'invalid-image', $body ); } // Fetch the Extension (it's safe because it comes from our service) $extension = str_replace( 'image/', '', $headers['content-type'] ); // Removed Query String if ( false !== strpos( $extension, '?' ) ) { $parts = explode( '?', $extension ); $extension = reset( $parts ); } if ( preg_match( '/filename="([^"]+)"/', $headers['content-disposition'], $matches ) && ! empty( $matches[1] ) ) { $filename = $matches[1]; // Removed Query String if ( false !== strpos( $filename, '?' ) ) { $parts = explode( '?', $filename ); $filename = reset( $parts ); } } else { $filename = md5( $body ) . '.' . $extension; } // Clean the Filename $filename = sanitize_file_name( $filename ); // get the file type $filetype = wp_check_filetype( basename( $filename ), null ); // save the file to the filesystem in the upload directory somewhere $upload_results = wp_upload_bits( $filename, null, $body ); // if the file path isn't set, all hope is lost if ( empty( $upload_results['file'] ) ) { return tribe_error( 'core:aggregator:invalid-image-path' ); } // create attachment args $attachment = [ 'guid' => $upload_dir['url'] . '/' . $filename, 'post_title' => preg_replace( '/\.[^.]+$/', '', $filename ), 'post_content' => '', 'post_status' => 'inherit', 'post_mime_type' => $filetype['type'], ]; // insert the attachment if ( ! $attachment_id = wp_insert_attachment( $attachment, $upload_results['file'] ) ) { return tribe_error( 'core:aggregator:attachment-error' ); } if ( is_wp_error( $attachment_id ) ) { return $attachment_id; } // Generate attachment metadata $attachment_meta = wp_generate_attachment_metadata( $attachment_id, $upload_results['file'] ); wp_update_attachment_metadata( $attachment_id, $attachment_meta ); // add our own custom meta field so the image is findable update_post_meta( $attachment_id, $tribe_aggregator_meta_key, $image_id ); $file->post_id = (int) $attachment_id; $file->filename = $filename; $file->path = $upload_results['file']; $file->extension = $extension; $file->status = 'created'; return $file; } } Origins.php000064400000016776150513455650006721 0ustar00origins = [ 'csv' => (object) [ 'id' => 'csv', 'name' => __( 'CSV File', 'the-events-calendar' ), 'disabled' => false, ], 'eventbrite' => (object) [ 'id' => 'eventbrite', 'name' => __( 'Eventbrite', 'the-events-calendar' ), 'disabled' => true, 'upsell' => true, ], 'gcal' => (object) [ 'id' => 'gcal', 'name' => __( 'Google Calendar', 'the-events-calendar' ), 'disabled' => true, 'upsell' => true, ], 'ical' => (object) [ 'id' => 'ical', 'name' => __( 'iCalendar', 'the-events-calendar' ), 'disabled' => true, 'upsell' => true, ], 'ics' => (object) [ 'id' => 'ics', 'name' => __( 'ICS File', 'the-events-calendar' ), 'disabled' => true, 'upsell' => true, ], 'meetup' => (object) [ 'id' => 'meetup', 'name' => __( 'Meetup', 'the-events-calendar' ), 'disabled' => true, 'upsell' => true, ], 'url' => (object) [ 'id' => 'url', 'name' => __( 'Other URL', 'the-events-calendar' ), 'disabled' => true, 'upsell' => true, ], ]; $this->is_ea_disabled = tribe_get_option( 'tribe_aggregator_disable', false ); } /** * Get event-aggregator origins * * @return array */ public function get() { if ( tribe( 'events-aggregator.main' )->is_service_active() ) { $this->enable_service_origins(); } $origins = $this->origins; $origins = array_filter( $origins, [ $this, 'is_origin_available' ] ); /** * The origins (sources) that EA can import from * * @param array $origins The origins */ $origins = apply_filters( 'tribe_aggregator_origins', $origins ); return $origins; } /** * Get event-aggregator origins from the service or cache * * @return array */ private function enable_service_origins() { $cached_origins = get_transient( "{$this->cache_group}_origins" ); $cached_version = ! empty( $cached_origins->version ) ? $cached_origins->version : '1.0.0'; if ( $cached_origins && version_compare( $cached_version, static::VERSION, '=' ) ) { $this->origins = $cached_origins; return $this->origins; } $service_origins = $this->fetch_origin_data(); if ( is_wp_error( $service_origins ) ) { return $this->origins; } if ( empty( $service_origins->origin ) ) { return $this->origins; } // enable the options for any that come back from the Service foreach ( $service_origins->origin as $origin ) { if ( ! empty( $this->origins[ $origin->id ] ) ) { $this->origins[ $origin->id ]->disabled = false; } } // use the specified expiration if available if ( isset( $this->origins->expiration ) ) { $expiration = $this->origins->expiration; unset( $this->origins->expiration ); } else { $expiration = 6 * HOUR_IN_SECONDS; } set_transient( "{$this->cache_group}_origins", $this->origins, $expiration ); return $this->origins; } /** * Fetches origin data from the service and sets necessary transients */ private function fetch_origin_data() { $request_cached = tribe_get_var( 'events-aggregator.origins-data' ); if ( empty( $request_cached ) ) { // Try to see if we have a lock in place. $lock = get_transient( "{$this->cache_group}_fetch_lock" ); } if ( ! empty( $lock ) ) { return $request_cached; } list( $origin_data, $error ) = $this->service->get_origins( true ); $origin_data = (object) $origin_data; $version = ! empty( $origin_data->version ) ? $origin_data->version : '1.0.0'; if ( empty( $error ) ) { // Refresh some accessory transients and embed the version in them. $oauth_data = $origin_data->oauth; $limit_data = $origin_data->limit; $oauth_data->version = $limit_data->version = $version; set_transient( "{$this->cache_group}_origin_oauth", $oauth_data, 6 * HOUR_IN_SECONDS ); set_transient( "{$this->cache_group}_origin_limit", $limit_data, 6 * HOUR_IN_SECONDS ); } elseif ( 403 == wp_remote_retrieve_response_code( $error ) ) { // Store the origins data for 5' only. $origin_data->expiration = 300; // And avoid bugging the service for 5'. set_transient( "{$this->cache_group}_fetch_lock", $origin_data, 300 ); } tribe_set_var( 'events-aggregator.origins-data', $origin_data ); return $origin_data; } /** * Returns whether oauth for a given origin is enabled. * * The OAuth status for the origin is enabled on EA Service side. * * @param string $origin The origin to check the OAuth status for. * * @return boolean Whether OAuth is enabled for the origin or not. */ public function is_oauth_enabled( $origin ) { if ( 'eventbrite' !== $origin && ! tribe( 'events-aggregator.main' )->is_service_active() ) { return false; } if ( 'eventbrite' === $origin && class_exists( 'Tribe__Events__Tickets__Eventbrite__Main' ) ) { return true; } $oauth = $this->get_data( 'oauth' ); return ! empty( $oauth->{$origin} ) && (bool) $oauth->{$origin}; } /** * Get origin limit values for an operation. * * @param string $type Type of operation limit to retrieve; defaults to `import`. * * @return int The numeric limit (how many times) applied to the operation. */ public function get_limit( $type = 'import' ) { $limits = $this->get_data( 'limit' ); return ! empty( $limits->{$type} ) ? (int) $limits->{$type} : false; } public function get_name( $id ) { $this->get(); if ( empty( $this->origins[ $id ] ) ) { return __( 'Event Aggregator', 'the-events-calendar' ); } return $this->origins[ $id ]->name; } /** * Whether an origin is available or not in respect to the user possibility * to disable EA functions. * * @param stdClass|string $origin The origin to check for availability as an object * or a slug. * * @return bool */ public function is_origin_available( $origin ) { if ( is_object( $origin ) ) { $origin = $origin->id; } return $this->is_ea_disabled ? in_array( $origin, $this->available_when_disabled ) : true; } /** * Gets the data for an internal Origins data key. * * The result might be cached from a previous request. * * @since 4.9.6 * * @param string|null $key The key to fetch the data for. * * @return mixed|object|bool The data associated with the key if any and available, `false` otherwise. */ public function get_data( $key ) { if ( null === $key ) { return $this->fetch_origin_data(); } $data = get_transient( "{$this->cache_group}_origin_{$key}" ); $cached_version = isset( $data->version ) ? $data->version : '1.0.0'; if ( ! version_compare( $cached_version, static::VERSION, '=' ) ) { $origin_data = $this->fetch_origin_data(); $data = ! empty( $origin_data->{$key} ) ? $origin_data->{$key} : false; } return $data; } }