WordPress.org

Making WordPress.org

Changeset 9108


Ignore:
Timestamp:
08/17/2019 12:50:17 AM (5 weeks ago)
Author:
coreymckrill
Message:

Events API: Update logic for pinning regional camps

  • Pinning now has three phases of two weeks each. First phase is global, second is regional, third is just within the country where the event is being held.
  • The pinning process is abstracted to work with any regional camp definition, which includes the necessary data about the event and a start date for the promotion.
  • Regional camp definitions have been added for WCUS, WCEU, and WC Asia. Only WCUS is currently complete, as it is the next pending event.
  • Unit tests also updated and passing to reflect this new functionality.
Location:
sites/trunk/api.wordpress.org/public_html/events/1.0
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/api.wordpress.org/public_html/events/1.0/index.php

    r7932 r9108  
    165165
    166166        $events = get_events( $event_args );
    167         $events = maybe_add_wp15_promo( $events, $_SERVER['HTTP_USER_AGENT'], time() );
    168         $events = add_regional_wordcamps( $events, $_SERVER['HTTP_USER_AGENT'] );
     167
     168        //$events = maybe_add_wp15_promo( $events, $_SERVER['HTTP_USER_AGENT'], time() );
     169
     170        $events = maybe_add_regional_wordcamps(
     171            $events,
     172            get_regional_wordcamp_data(),
     173            $_SERVER['HTTP_USER_AGENT'],
     174            time(),
     175            $location
     176        );
    169177
    170178        // Internal location data cannot be exposed in the response, see get_location().
     
    177185    }
    178186
    179     return compact( 'error', 'location', 'events' );
    180 
     187    $sandboxed = ( defined( 'WPORG_SANDBOXED' ) ) ? WPORG_SANDBOXED : null;
     188
     189    return compact( 'sandboxed', 'error', 'location', 'events' );
    181190}
    182191
     
    916925
    917926/**
    918  * Add regional WordCamps to the Events Widget in Core for extra promotion.
     927 * The data for upcoming regional WordCamps.
     928 *
     929 * Externalizing this makes it easier to test the `maybe_add_regional_wordcamps` function.
     930 *
     931 * @return array
     932 */
     933function get_regional_wordcamp_data() {
     934    return array(
     935        // WordCamp Asia.
     936        'asia'   => array(
     937            'promo_start'        => 0, // todo
     938            'regional_countries' => array(
     939                // todo
     940            ),
     941            'event'              => array(
     942                'type'       => 'wordcamp',
     943                'title'      => 'WordCamp Asia',
     944                'url'        => 'https://2020.asia.wordcamp.org/',
     945                'meetup'     => '',
     946                'meetup_url' => '',
     947                'date'       => '2020-02-21 00:00:00',
     948                'location'   => array(
     949                    'location'  => 'Bangkok, Thailand',
     950                    'country'   => 'TH',
     951                    'latitude'  => 13.7248934,
     952                    'longitude' => 100.492683,
     953                ),
     954            ),
     955        ),
     956        // WordCamp Europe.
     957        'europe' => array(
     958            'promo_start'        => 0, // todo
     959            'regional_countries' => array(
     960                // todo
     961            ),
     962            'event'              => array(
     963                'type'       => 'wordcamp',
     964                'title'      => 'WordCamp Europe',
     965                'url'        => 'https://2020.europe.wordcamp.org/',
     966                'meetup'     => '',
     967                'meetup_url' => '',
     968                'date'       => '', // todo
     969                'location' => array(
     970                    'location'  => 'Porto, Portugal',
     971                    'country'   => 'PT',
     972                    'latitude'  => 41.1622022,
     973                    'longitude' => -8.6570588,
     974                ),
     975            ),
     976        ),
     977        // WordCamp US.
     978        'us'     => array(
     979            'promo_start'        => strtotime( '2019-08-16 00:00:00' ),
     980            'regional_countries' => array(
     981                'us', 'ca', 'bz', 'cr', 'sv', 'gt', 'hn', 'mx', 'ni', 'pa',
     982                'ar', 'bo', 'br', 'cl', 'co', 'ec', 'gf', 'gy', 'py', 'pe',
     983                'sr', 'uy', 've', 'ag', 'aw', 'bs', 'bb', 'ky', 'cu', 'dm',
     984                'do', 'gd', 'ht', 'jm', 'kn', 'lc', 'vc', 'tt',
     985            ),
     986            'event'              => array(
     987                'type'       => 'wordcamp',
     988                'title'      => 'WordCamp US',
     989                'url'        => 'https://2019.us.wordcamp.org/',
     990                'meetup'     => '',
     991                'meetup_url' => '',
     992                'date'       => '2019-11-01 00:00:00',
     993                'location'   => array(
     994                    'location'  => 'St. Louis, MO, USA',
     995                    'country'   => 'US',
     996                    'latitude'  => 38.6532135,
     997                    'longitude' => -90.3136733,
     998                ),
     999            ),
     1000        ),
     1001    );
     1002}
     1003
     1004/**
     1005 * Add time- and location-relevant regional WordCamps to the Events Widget in Core.
    9191006 *
    9201007 * @param array  $local_events
     1008 * @param array  $region_data
    9211009 * @param string $user_agent
     1010 * @param int    $current_time
     1011 * @param array  $location
    9221012 *
    9231013 * @return array
    9241014 */
    925 function add_regional_wordcamps( $local_events, $user_agent ) {
    926     $time               = time();
    927     $regional_wordcamps = array();
    928 
     1015function maybe_add_regional_wordcamps( $local_events, $region_data, $user_agent, $current_time, $location ) {
    9291016    if ( ! is_client_core( $user_agent ) ) {
    9301017        return $local_events;
    9311018    }
    9321019
    933     if ( $time > strtotime( 'November 7th, 2018' ) && $time < strtotime( 'December 10th, 2018' ) ) {
    934         $regional_wordcamps[] = array(
    935             'type'       => 'wordcamp',
    936             'title'      => 'WordCamp US',
    937             'url'        => 'https://2018.us.wordcamp.org/',
    938             'meetup'     => '',
    939             'meetup_url' => '',
    940             'date'       => '2018-12-07 00:00:00',
    941 
    942             'location' => array(
    943                 'location'  => 'Nashville, TN, USA',
    944                 'country'   => 'US',
    945                 'latitude'  => 36.1566085,
    946                 'longitude' => -86.7784909,
    947             )
    948         );
    949     }
    950 
    951     if ( $time > strtotime( 'May 20th, 2019' ) && $time < strtotime( 'June 23rd, 2019' ) ) {
    952         $regional_wordcamps[] = array(
    953             'type'       => 'wordcamp',
    954             'title'      => 'WordCamp Europe',
    955             'url'        => 'https://2019.europe.wordcamp.org/',
    956             'meetup'     => '',
    957             'meetup_url' => '',
    958             'date'       => '2019-06-20 00:00:00',
    959 
    960             'location' => array(
    961                 'location'  => 'Berlin, Germany',
    962                 'country'   => 'DE',
    963                 'latitude'  => 52.50697,
    964                 'longitude' => 13.2843064,
    965             )
    966         );
     1020    $regional_wordcamps = array();
     1021
     1022    foreach ( $region_data as $region => $data ) {
     1023        if ( empty( $data['promo_start'] ) ) {
     1024            continue;
     1025        }
     1026
     1027        $start = $data['promo_start'];
     1028
     1029        /**
     1030         * The targeted area of the regional camp promotion "zooms in" over the course of 6 weeks.
     1031         */
     1032        if ( is_within_date_range( $current_time, $start, strtotime( '+ 2 weeks', $start ) ) ) {
     1033            // Phase 1: Show worldwide for first two weeks.
     1034            $regional_wordcamps[] = $data['event'];
     1035        } elseif ( is_within_date_range( $current_time, strtotime( '+ 2 weeks', $start ), strtotime( '+ 4 weeks', $start ) ) ) {
     1036            // Phase 2: Show within regional countries for next two weeks.
     1037            if ( ! empty( $location['country'] ) && in_array( strtolower( $location['country'] ), $data['regional_countries'], true ) ) {
     1038                $regional_wordcamps[] = $data['event'];
     1039            }
     1040        } elseif ( is_within_date_range( $current_time, strtotime( '+ 4 weeks', $start ), strtotime( '+ 6 weeks', $start ) ) ) {
     1041            // Phase 3: Show only within the event country for the last two weeks.
     1042            if ( ! empty( $location['country'] ) && strtolower( $data['event']['location']['country'] ) === strtolower( $location['country'] ) ) {
     1043                $regional_wordcamps[] = $data['event'];
     1044            }
     1045        }
    9671046    }
    9681047
     
    9721051     */
    9731052    foreach ( $regional_wordcamps as $regional_event ) {
    974         foreach ( $local_events as $local_key => $local_event ) {
     1053        $local_events = array_filter( $local_events, function( $local_event ) use ( $regional_event ) {
    9751054            if ( parse_url( $regional_event['url'], PHP_URL_HOST ) === parse_url( $local_event['url'], PHP_URL_HOST ) ) {
    976                 unset( $local_events[ $local_key ] );
     1055                return false;
    9771056            }
    978         }
     1057
     1058            return true;
     1059        } );
    9791060    }
    9801061
    9811062    return array_merge( $regional_wordcamps, $local_events );
     1063}
     1064
     1065/**
     1066 * Determine if a given Unix timestamp is within a date range.
     1067 *
     1068 * @param int    $time        A Unix timestamp.
     1069 * @param string $range_start A date/time string compatible with strtotime.
     1070 * @param string $range_end   A date/time string compatible with strtotime.
     1071 *
     1072 * @return bool
     1073 */
     1074function is_within_date_range( $time, $range_start, $range_end ) {
     1075    if ( ! is_int( $range_start ) ) {
     1076        $range_start = strtotime( $range_start );
     1077    }
     1078
     1079    if ( ! is_int( $range_end ) ) {
     1080        $range_end = strtotime( $range_end );
     1081    }
     1082
     1083    return $time > $range_start && $time < $range_end;
    9821084}
    9831085
  • sites/trunk/api.wordpress.org/public_html/events/1.0/tests/test-index.php

    r7188 r9108  
    2222    $tests_failed += test_get_events();
    2323    $tests_failed += test_get_events_country_restriction();
    24     $tests_failed += test_add_regional_wordcamps();
     24    $tests_failed += test_maybe_add_regional_wordcamps();
    2525    $tests_failed += test_maybe_add_wp15_promo();
    2626    $tests_failed += test_build_response();
     
    732732
    733733        /*
    734          * Only the IPv4 address is given
     734         * Only the IPv4 address is given.
     735         *
     736         * Note that IP locations change frequently, so some of these expected results will inevitably become outdated
     737         * and cause tests to fail.
    735738         *
    736739         * See https://awebanalysis.com/en/ipv4-directory/
     
    750753            'input' => array( 'ip' => '86.108.55.28' ),
    751754            'expected' => array(
    752                 'description' => 'amman',
    753                 'latitude'    => '31.955',
    754                 'longitude'   => '35.945',
     755                'description' => 'hakama',
     756                'latitude'    => '32.594',
     757                'longitude'   => '35.884',
    755758                'country'     => 'JO',
    756759                'internal'    => true,
     
    761764            'input' => array( 'ip' => '80.95.186.144' ),
    762765            'expected' => array(
    763                 'description' => 'belfast',
    764                 'latitude'    => '54.583',
    765                 'longitude'   => '-5.933',
     766                'description' => 'antrim',
     767                'latitude'    => '54.700',
     768                'longitude'   => '-6.200',
    766769                'country'     => 'GB',
    767770                'internal'    => true,
     
    772775            'input' => array( 'ip' => '189.147.186.0' ),
    773776            'expected' => array(
    774                 'description' => 'cuauhtemoc',
    775                 'latitude'    => '19.417',
    776                 'longitude'   => '-99.157',
     777                'description' => 'mexico city',
     778                'latitude'    => '19.428',
     779                'longitude'   => '-99.128',
    777780                'country'     => 'MX',
    778781                'internal'    => true,
     
    803806
    804807        /*
    805          * Only an IPv6 address is given
     808         * Only an IPv6 address is given.
     809         *
     810         * Note that IP locations change frequently, so some of these expected results will inevitably become outdated
     811         * and cause tests to fail.
    806812         *
    807813         * See https://www.google.com/intl/en/ipv6/statistics.html#tab=per-country-ipv6-adoption&tab=per-country-ipv6-adoption
     
    867873            'input'    => array( 'ip' => '2001:1388:6643:2736:10f1:897c:428c:1b3b' ),
    868874            'expected' => array(
    869                 'description' => 'ayacucho',
    870                 'latitude'    => '-13.158',
    871                 'longitude'   => '-74.224',
     875                'description' => 'lima',
     876                'latitude'    => '-12.043',
     877                'longitude'   => '-77.028',
    872878                'country'     => 'PE',
    873879                'internal'    => true,
     
    11621168 * @return int
    11631169 */
    1164 function test_add_regional_wordcamps() {
     1170function test_maybe_add_regional_wordcamps() {
    11651171    $failed = 0;
    11661172
     
    11731179    ) );
    11741180
     1181    $region_data = array(
     1182        'us' => array(
     1183            'promo_start'        => strtotime( '2019-08-16 00:00:00' ),
     1184            'regional_countries' => array(
     1185                'us', 'ca', 'bz', 'cr', 'sv', 'gt', 'hn', 'mx', 'ni', 'pa',
     1186                'ar', 'bo', 'br', 'cl', 'co', 'ec', 'gf', 'gy', 'py', 'pe',
     1187                'sr', 'uy', 've', 'ag', 'aw', 'bs', 'bb', 'ky', 'cu', 'dm',
     1188                'do', 'gd', 'ht', 'jm', 'kn', 'lc', 'vc', 'tt',
     1189            ),
     1190            'event'              => array(
     1191                'type'       => 'wordcamp',
     1192                'title'      => 'WordCamp US',
     1193                'url'        => 'https://2019.us.wordcamp.org/',
     1194                'meetup'     => '',
     1195                'meetup_url' => '',
     1196                'date'       => '2019-11-01 00:00:00',
     1197                'location'   => array(
     1198                    'location'  => 'St. Louis, MO, USA',
     1199                    'country'   => 'US',
     1200                    'latitude'  => 38.6532135,
     1201                    'longitude' => -90.3136733,
     1202                ),
     1203            ),
     1204        ),
     1205    );
     1206
     1207    $core_user_agent  = 'WordPress/5.2; https://example.org';
     1208    $other_user_agent = 'Smith';
     1209
     1210    $time_before_promo         = strtotime( '2019-08-15 00:00:00' );
     1211    $time_during_promo_phase_1 = strtotime( '+ 1 day', $region_data['us']['promo_start'] );
     1212    $time_during_promo_phase_2 = strtotime( '+ 2 weeks + 1 day', $region_data['us']['promo_start'] );
     1213    $time_during_promo_phase_3 = strtotime( '+ 4 weeks + 1 day', $region_data['us']['promo_start'] );
     1214    $time_after_promo          = strtotime( '+ 6 weeks + 1 day', $region_data['us']['promo_start'] );
     1215
     1216    $location_country_within_region = array(
     1217        'country' => 'us',
     1218    );
     1219
     1220    $location_country_outside_region = array(
     1221        'country' => 'es',
     1222    );
     1223
     1224    $location_ip_only = array(
     1225        'ip' => '8.8.8.8',
     1226    );
     1227
    11751228    // Make sure there's at least one event, otherwise there could be false positives.
    11761229    if ( ! $local_events ) {
     
    11781231    }
    11791232
    1180     printf( "\n\nRunning %d add_regional_wordcamps() tests\n", 2 );
    1181 
    1182     // Test that no changes were made if the user agent isn't Core.
    1183     $events_no_user_agent = add_regional_wordcamps( $local_events, '' );
    1184 
    1185     if ( $events_no_user_agent !== $local_events ) {
    1186         $failed++;
    1187         output_results( 'no-user-agent', false, $local_events, $events_no_user_agent );
     1233    printf( "\n\nRunning %d add_regional_wordcamps() tests\n", 13 );
     1234
     1235    $tests_expect_no_changes = array();
     1236    $tests_expect_changes    = array();
     1237
     1238    // No regional camps should be added if before the promo start date or after the promo window is past (6 weeks).
     1239    $tests_expect_no_changes['before-promo'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_before_promo, $location_country_within_region );
     1240    $tests_expect_no_changes['before-promo'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_after_promo, $location_country_within_region );
     1241
     1242    // Regional camp should be added if it's within phase 1 of the promo, regardless of location.
     1243    $tests_expect_changes['promo-phase-1-within-region'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_1, $location_country_within_region );
     1244    $tests_expect_changes['promo-phase-1-outside-region'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_1, $location_country_outside_region );
     1245
     1246    // Regional camp should only be added during phase 2 of promo if location is within region.
     1247    $tests_expect_changes['promo-phase-2-within-region'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_2, $location_country_within_region );
     1248    $tests_expect_no_changes['promo-phase-2-outside-region'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_2, $location_country_outside_region );
     1249    $tests_expect_no_changes['promo-phase-2-ip-only'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_2, $location_ip_only );
     1250
     1251    // Regional camp should only be added during phase 3 of promo if location is within event country.
     1252    $tests_expect_changes['promo-phase-3-within-event-country'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_3, $location_country_within_region );
     1253    $tests_expect_no_changes['promo-phase-3-outside-event-country'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_3, $location_country_outside_region );
     1254    $tests_expect_no_changes['promo-phase-3-ip-only'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_3, $location_ip_only );
     1255
     1256    // Regional camp should only be added if the user agent is Core.
     1257    $tests_expect_no_changes['other-user-agent'] = maybe_add_regional_wordcamps( $local_events, $region_data, $other_user_agent, $time_during_promo_phase_1, $location_country_within_region );
     1258    $tests_expect_changes['core-user-agent'] = maybe_add_regional_wordcamps( $local_events, $region_data, $core_user_agent, $time_during_promo_phase_1, $location_country_within_region );
     1259
     1260    // There should only be one entry for an event, even if the local event array already contains the regional event.
     1261    $tests_expect_no_changes['duplicate-event'] = maybe_add_regional_wordcamps( array( $region_data['us']['event'] ), $region_data, $core_user_agent, $time_during_promo_phase_1, $location_country_within_region );
     1262
     1263    foreach ( $tests_expect_no_changes as $name => $result ) {
     1264        switch ( $name ) {
     1265            case 'duplicate-event':
     1266                if ( $result !== array( $region_data['us']['event'] ) ) {
     1267                    $failed++;
     1268                    output_results( $name, false, array( $region_data['us']['event'] ), $result );
     1269                }
     1270                break;
     1271            default:
     1272                if ( $result !== $local_events ) {
     1273                    $failed++;
     1274                    output_results( $name, false, $local_events, $result );
     1275                }
     1276                break;
     1277        }
    11881278    }
    11891279
    1190     /*
    1191      * Test that local events were unharmed if the user agent is Core.
    1192      *
    1193      * There isn't an easy way to mock time(), so this doesn't test that the events were added
    1194      * correctly. It just makes sure that local events weren't removed.
    1195      */
    1196     $events_core_user_agent = add_regional_wordcamps( $local_events, 'WordPress/4.9; https://example.org' );
    1197 
    1198     if (
    1199         count( $events_core_user_agent ) < count( $local_events ) ||
    1200         ! in_array( $local_events[0], $events_core_user_agent, true )
    1201     ) {
    1202         $failed++;
    1203         output_results( 'core-user-agent', false, 'local events were not affected', $events_core_user_agent );
     1280    $unchanged_count = count( $local_events );
     1281    $expected_count  = $unchanged_count + 1;
     1282
     1283    foreach ( $tests_expect_changes as $name => $result ) {
     1284        $actual_count = count( $result );
     1285
     1286        if ( $actual_count !== $expected_count ) {
     1287            $failed++;
     1288            output_results( $name, false, $expected_count, $actual_count );
     1289        }
    12041290    }
    12051291
Note: See TracChangeset for help on using the changeset viewer.