Making WordPress.org

Changeset 11927


Ignore:
Timestamp:
06/29/2022 09:38:19 PM (3 years ago)
Author:
iandunn
Message:

Profiles: Include links in Slack props messages.

Previously they were unintentionally stripped out, because Slack escapes them in brackets, like <http://example.org>. That caused them to get stripped out by handle_props_given() in wporg-profiles-activity-handler.php.

For example, https://wordpress.slack.com/archives/C0FRG66LR/p1655471187798639.

This refactors prepare_message() to use the structured message blocks, rather than the concatenated text. That makes it easier to un-escape each part of the message according to its type.

Location:
sites/trunk/common/includes/slack/props
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/common/includes/slack/props/lib.php

    r11789 r11927  
    4646    // This is Slack's unintuitive way of giving messages a unique ID :|
    4747    // https://api.slack.com/messaging/retrieving#individual_messages
    48     $message_id = sprintf( '%s-%s', $request->event->channel, $request->event->ts );
    49     $message    = prepare_message( $request->event->text, $recipient_users );
     48    $message_id    = sprintf( '%s-%s', $request->event->channel, $request->event->ts );
     49    $channel_names = map_slack_channel_ids_to_names( $request->event->text );
     50    $message       = prepare_message( $request->event->blocks[0]->elements[0]->elements, $recipient_users, $channel_names );
    5051
    5152    add_activity_to_profile( compact( 'giver_user', 'recipient_ids', 'url', 'message_id', 'message' ) );
     
    143144
    144145/**
     146 * Parse Slack channel names and IDs out of message.
     147 *
     148 * This avoids having to make an API call to Slack to fetch the channels, like their docs recommend.
     149 */
     150function map_slack_channel_ids_to_names( string $message ) : array {
     151    $map = array();
     152
     153    preg_match_all( '/<#(\w*\d*)\|([\w-]*)>/m', $message, $matches, PREG_SET_ORDER );
     154
     155    foreach ( $matches as $match ) {
     156        $map[ $match[1] ] = $match[2];
     157    }
     158
     159    return $map;
     160}
     161
     162
     163/**
     164 * Prepare message to be sent to the Profiles API.
     165 *
    145166 * Replace Slack IDs with w.org usernames, to better fit w.org profiles.
    146  */
    147 function prepare_message( string $original, array $user_map ) : string {
    148     $search  = array();
    149     $replace = array();
    150 
    151     foreach ( $user_map as $slack_id => $wporg_user ) {
    152         $search[]  = sprintf( '<@%s>', $slack_id );
    153         $replace[] = '@' . $wporg_user['user_login'];
    154     }
    155 
    156     return str_replace( $search, $replace, $original );
     167 * Un-escape URLs and other things Slack has escaped.
     168 */
     169function prepare_message( array $elements, array $user_map, array $channel_map ) : string {
     170    $prepared = '';
     171
     172    foreach ( $elements as $element ) {
     173        switch ( $element->type ) {
     174            case 'text':
     175                $prepared .= $element->text;
     176            break;
     177
     178            case 'link':
     179                $prepared .= $element->url;
     180            break;
     181
     182            case 'emoji':
     183                $prepared .= ":{$element->name}:";
     184            break;
     185
     186            case 'user':
     187                $prepared .= '@' . $user_map[ $element->user_id ]['user_login'];
     188            break;
     189
     190            case 'channel':
     191                $prepared .= '#' . $channel_map[ $element->channel_id ];
     192            break;
     193
     194            default:
     195                // Ignore
     196            break;
     197        }
     198    }
     199
     200    return $prepared;
    157201}
    158202
  • sites/trunk/common/includes/slack/props/tests/test-lib.php

    r11789 r11927  
    44use wpdbStub;
    55use PHPUnit\Framework\TestCase;
    6 use function Dotorg\Slack\Props\{ is_valid_props, get_recipient_slack_ids, map_slack_users_to_wporg, prepare_message };
     6use function Dotorg\Slack\Props\{ is_valid_props, get_recipient_slack_ids, map_slack_users_to_wporg, map_slack_channel_ids_to_names, prepare_message };
    77
    88/**
     
    105105
    106106        $valid_users = array(
    107                     'U02RR6SGY',
    108                     'U02RQHNND',
    109                     'U3KJ0TK4L',
    110                     'U4L99HZB6',
    111                     'U024MFP4L',
    112                     'U6R2E3Y9Y',
    113                     'U023GFZJ07L',
    114                     'U1E5RLU1L',
    115                 );
     107            'U02RR6SGY',
     108            'U02RQHNND',
     109            'U3KJ0TK4L',
     110            'U4L99HZB6',
     111            'U024MFP4L',
     112            'U6R2E3Y9Y',
     113            'U023GFZJ07L',
     114            'U1E5RLU1L',
     115        );
    116116
    117117        $mentioned_twice = json_decode( json_encode( $valid_request->event->blocks ) );
     
    244244
    245245    /**
     246     * @covers ::map_slack_channel_ids_to_names
     247     * @dataProvider data_map_slack_channel_ids_to_names
     248     * @group unit
     249     */
     250    public function test_map_slack_channel_ids_to_names( string $message, array $expected ) : void {
     251        $actual = map_slack_channel_ids_to_names( $message );
     252
     253        $this->assertSame( $expected, $actual );
     254    }
     255
     256    public function data_map_slack_channel_ids_to_names() : array {
     257        $cases = array(
     258            'none' => array(
     259                'message'  => 'thanks to <@U039G75HC> for great work on',
     260                'expected' => array(),
     261            ),
     262
     263            'single team' => array(
     264                'message'  => 'thanks to <@U02RR7CQY> for great work on the <#C037W5S7X|community-team>',
     265                'expected' => array(
     266                    'C037W5S7X' => 'community-team',
     267                ),
     268            ),
     269
     270            'multiple teams' => array(
     271                'message'  => 'thanks to <@U039G75HC> for great work in <#C037W5S7X|community-team> and <#C08M59V3P|meta-wordcamp>',
     272                'expected' => array(
     273                    'C037W5S7X' => 'community-team',
     274                    'C08M59V3P' => 'meta-wordcamp',
     275                ),
     276            ),
     277        );
     278
     279        return $cases;
     280    }
     281
     282    /**
    246283     * @covers ::prepare_message
    247284     * @dataProvider data_prepare_message
    248285     * @group unit
    249286     */
    250     public function test_prepare_message( string $text, array $user_map, string $expected ) : void {
    251         $actual = prepare_message( $text, $user_map );
     287    public function test_prepare_message( array $elements, array $user_map, array $channel_map, string $expected ) : void {
     288        $actual = prepare_message( $elements, $user_map, $channel_map );
    252289
    253290        $this->assertSame( $expected, $actual );
     
    259296        $cases = array(
    260297            'empty' => array(
    261                 'text'     => '',
    262                 'user_map' => array(),
    263                 'expected' => '',
     298                'elements'    => array(),
     299                'user_map'    => array(),
     300                'channel_map' => array(),
     301                'expected'    => '',
    264302            ),
    265303
    266304            'valid' => array(
    267                 'text' => $valid_request->event->text,
     305                'elements' => $valid_request->event->blocks[0]->elements[0]->elements,
     306
    268307                'user_map' => array(
    269308                    'U023GFZJ07L' => array(
     
    306345                    ),
    307346                ),
     347
     348                'channel_map' => array(),
    308349                'expected' => 'props to @Mamaduka for co-leading 5.9.3 RC 1, to @SergeyBiryukov for running mission control and to @davidbaumwald @pbiron @markjaquith @webcommsat @costdev @jeroenrotty for their help testing the release package :community: :wordpress:',
    309350            ),
     351
     352            'escaped elements' => array(
     353                'elements' => array(
     354                    (object) array(
     355                        'type' => 'text',
     356                        'text' => 'Props to ',
     357                    ),
     358                    (object) array(
     359                        'type'    => 'user',
     360                        'user_id' => 'U04F2C6V5',
     361                    ),
     362                    (object) array(
     363                        'type' => 'text',
     364                        'text' => ' for title fix in ',
     365                    ),
     366                    (object) array(
     367                        'type' => 'link',
     368                        'url'  => 'https://github.com/WordPress/wordpress.org/pull/73',
     369                    ),
     370                    (object) array(
     371                        'type' => 'text',
     372                        'text' => ', and to ',
     373                    ),
     374                    (object) array(
     375                        'type'    => 'user',
     376                        'user_id' => 'U84ST75AL',
     377                    ),
     378                    (object) array(
     379                        'type' => 'text',
     380                        'text' => ' for facilitating the ',
     381                    ),
     382                    (object) array(
     383                        'type'       => 'channel',
     384                        'channel_id' => 'C037W5S7X',
     385                    ),
     386                    (object) array(
     387                        'type' => 'text',
     388                        'text' => ' triage ',
     389                    ),
     390                    (object) array(
     391                        'type'    => 'emoji',
     392                        'name'    => 'thank-you',
     393                    ),
     394                    (object) array(
     395                        'type'    => 'emoji',
     396                        'name'    => 'pizza',
     397                        'unicode' => '1f355',
     398                    ),
     399                ),
     400
     401                'user_map' => array(
     402                    'U04F2C6V5' => array(
     403                        'user_login' => 'aurooba',
     404                    ),
     405                    'U84ST75AL' => array(
     406                        'user_login' => 'estelaris',
     407                    ),
     408                ),
     409
     410                'channel_map' => array(
     411                    'C037W5S7X' => 'docs',
     412                ),
     413
     414                'expected' => 'Props to @aurooba for title fix in https://github.com/WordPress/wordpress.org/pull/73, and to @estelaris for facilitating the #docs triage :thank-you::pizza:',
     415            ),
    310416        );
    311417
Note: See TracChangeset for help on using the changeset viewer.