]> git.sesse.net Git - skvidarsync/blobdiff - bin/sync.pl
Split out create_reaction_log() into its own function.
[skvidarsync] / bin / sync.pl
index 3f07537389ce496e1655b2df1e0104f6baa95256..aecc86dae67333f0f396e31033fe00f16e41536a 100644 (file)
@@ -157,6 +157,65 @@ sub get_spreadsheet_with_title {
        return (undef, undef);
 }
 
+# Make a mapping of lowercase name -> list of [canonical name, row number, column number]
+sub find_where_each_name_is {
+       my $json = shift;
+
+       my %seen_names = ();
+       my $rows = $json->{'sheets'}[0]{'data'}[0]{'rowData'};
+       my $rowno = 4;
+       for my $row (@$rows) {
+               my $colno = 0;
+               for my $val (@{$row->{'values'}}) {
+                       my $name = get_spreadsheet_name($val);
+                       if (defined($name)) {
+                               push @{$seen_names{lc $name}}, [$name, $rowno, $colno];
+                       }
+                       ++$colno;
+               }
+               ++$rowno;
+       }
+
+       return %seen_names;
+}
+# Add the reaction log. (This only takes into account the last change
+# for each user; earlier ones are irrelevant and don't count. But it
+# doesn't deduplicate across reactions. Meh.)
+sub create_reaction_log {
+       my ($dbh, $invitation_ts, $slack_userid_to_real_name, $slack_userid_to_slack_name) = @_;
+
+       my $q = $dbh->prepare('select userid,event_type,reaction,to_char(event_ts,\'YYYY-mm-dd HH24:MI\') as event_ts from ( select distinct on (channel,ts,userid,reaction) userid,event_type,reaction,timestamptz \'1970-01-01 utc\' + event_ts::float * interval \'1 second\' as event_ts from reaction_log where channel=? and ts=? and reaction in (\'heart\',\'open_mouth\') order by channel,ts,userid,reaction,event_ts desc ) t1 where event_ts > current_timestamp - interval \'8 hours\' order by event_ts desc limit 50');
+       $q->execute($config::invitation_channel, $invitation_ts);
+       my @recent_changes = ();
+       while (my $ref = $q->fetchrow_hashref) {
+               my $msg = $ref->{'event_ts'};
+               if ($ref->{'event_type'} eq 'reaction_added') {
+                       $msg .= ' +';
+               } else {
+                       $msg .= ' –';
+               }
+               if ($ref->{'reaction'} eq 'open_mouth') {
+                       $msg .= '😮';
+               } else {
+                       $msg .= '❤️';
+               }
+               $msg .= ' ';
+               if (exists($slack_userid_to_real_name->{$ref->{'userid'}})) {
+                       $msg .= $slack_userid_to_real_name->{$ref->{'userid'}};
+               } elsif (exists($slack_userid_to_slack_name->{$ref->{'userid'}})) {
+                       $msg .= $slack_userid_to_slack_name->{$ref->{'userid'}} . ' (fant ikke regneark-navn)';
+               } else {
+                       # Should only happen if we didn't see the initial reaction_add, only reaction_remove.
+                       $msg .= $ref->{'userid'} . ' (fant ikke Slack-navn)';
+               }
+               push @recent_changes, { values => [{ userEnteredValue => { stringValue => $msg } }] };
+       }
+       while (scalar @recent_changes < 50) {
+               push @recent_changes, { values => [{ userEnteredValue => { stringValue => '' } }] };
+       }
+       return @recent_changes;
+}
+
 skv_log("Siste sync startet: " . POSIX::ctime(time));
 
 # Initialize the handles we need for communication.
@@ -195,28 +254,14 @@ my $response = $ua->get('https://sheets.googleapis.com/v4/spreadsheets/' . $conf
 );
 my $main_sheet_json = JSON::XS::decode_json($response->decoded_content);
 
-# Duplicate detection
-my %seen_names = ();
-{
-       my $main_sheet_rows = $main_sheet_json->{'sheets'}[0]{'data'}[0]{'rowData'};
-       my $rowno = 4;
-       for my $row (@$main_sheet_rows) {
-               my $colno = 0;
-               for my $val (@{$row->{'values'}}) {
-                       my $name = get_spreadsheet_name($val);
-                       if (defined($name)) {
-                               push @{$seen_names{lc $name}}, [$name, $rowno, $colno];
-                       }
-                       ++$colno;
-               }
-               ++$rowno;
-       }
-       for my $name (sort keys %seen_names) {
-               my $seen = $seen_names{$name};
-               if (scalar @$seen >= 2) {
-                       my $exemplar = $seen->[0][0];
-                       skv_log("Duplikat: $exemplar (" . format_cell_names_for_seen($seen) . ")");
-               }
+my %seen_names = find_where_each_name_is($main_sheet_json);
+
+# Find duplicates.
+for my $name (sort keys %seen_names) {
+       my $seen = $seen_names{$name};
+       if (scalar @$seen >= 2) {
+               my $exemplar = $seen->[0][0];
+               skv_log("Duplikat: $exemplar (" . format_cell_names_for_seen($seen) . ")");
        }
 }
 
@@ -224,7 +269,6 @@ my %seen_names = ();
 my %slack_userid_to_real_name = ();
 my %slack_userid_to_slack_name = ();
 my %slack_userid_to_row = ();
-my %real_name_to_slack_userid = ();
 $response = $ua->get('https://sheets.googleapis.com/v4/spreadsheets/' . $config::sheet_id . '?key=' . $config::gsheets_api_key . '&ranges=Slack-mapping!A5:C5000&fields=sheets/data/rowData/values/userEnteredValue',
        Authorization => 'Bearer ' . $token
 );
@@ -240,7 +284,6 @@ for my $row (@$mapping_sheet_rows) {
        $slack_userid_to_slack_name{$slack_id} = $slack_name;
        next if (!defined($real_name));
        $slack_userid_to_real_name{$slack_id} = $real_name;
-       $real_name_to_slack_userid{$real_name} = $slack_id;
 }
 
 # See which ones we don't have a mapping for, and look them up in Slack.
@@ -331,6 +374,7 @@ for my $userid (@attending_userids) {
 
        # See if we can find them in the spreadsheet.
        if (!exists($seen_names{lc $real_name})) {
+               # TODO: Perhaps move this logic further down, for consistency?
                skv_log("$slack_name ($userid) er påmeldt på Slack, og er mappet til $real_name, men var ikke i noen gruppe.");
        } else {
                my $seen = $seen_names{lc $real_name};
@@ -373,20 +417,25 @@ for my $real_name (keys %want_names) {
 }
 for my $real_name (keys %have_names) {
        next if (exists($want_names{$real_name}));
-       skv_log("Fjerner at $real_name skal på trening.");
-       push @diffs, [
-               $real_name,
-               {
-                       backgroundColor => {
-                               red => 1,
-                               green => 1,
-                               blue => 1,
-                               alpha => 0
+       if (!exists($seen_names{lc $real_name})) {
+               # TODO: This can somehow come if we try to add someone who's not in the sheet, too?
+               skv_log("Ønsket å fjerne at $real_name skulle på trening, men de var ikke i regnearket lenger.");
+       } else {
+               skv_log("Fjerner at $real_name skal på trening.");
+               push @diffs, [
+                       $real_name,
+                       {
+                               backgroundColor => {
+                                       red => 1,
+                                       green => 1,
+                                       blue => 1,
+                                       alpha => 0
+                               }
                        }
-               }
-       ];
-       $dbh->do('DELETE FROM applied WHERE channel=? AND ts=? AND name=?', undef,
-               $config::invitation_channel, $invitation_ts, $real_name);
+               ];
+               $dbh->do('DELETE FROM applied WHERE channel=? AND ts=? AND name=?', undef,
+                       $config::invitation_channel, $invitation_ts, $real_name);
+       }
 }
 
 my @yellow_updates = ();
@@ -396,68 +445,31 @@ if (scalar @diffs > 0) {
                my $real_name = $diff->[0];
 
                # See if we can find them in the spreadsheet.
-               if (!exists($seen_names{lc $real_name})) {
-                       # This can only happen on deletes; we don't add such cases to the positive diff.
-                       # FIXME we'd still delete them from the database.
-                       skv_log("Ønsket å fjerne at $real_name skulle på trening, men de var ikke i regnearket lenger.");
-               } else {
-                       my $seen = $seen_names{lc $real_name};
-                       die if (scalar @$seen > 1);
-                       my $rowno = $seen->[0][1];
-                       my $colno = $seen->[0][2];
-                       push @yellow_updates, {
-                               updateCells => {
-                                       rows => [{
-                                               values => [{
-                                                       userEnteredFormat => $diff->[1]
-                                               }]
-                                       }],
-                                       fields => 'userEnteredFormat.backgroundColor',
-                                       range => {
-                                               sheetId => $tab_id,
-                                               startRowIndex => $rowno,
-                                               endRowIndex => $rowno + 1,
-                                               startColumnIndex => $colno,
-                                               endColumnIndex => $colno + 1
-                                       }
+               my $seen = $seen_names{lc $real_name};
+               die if (!defined($seen) || scalar @$seen > 1);
+               my $rowno = $seen->[0][1];
+               my $colno = $seen->[0][2];
+               push @yellow_updates, {
+                       updateCells => {
+                               rows => [{
+                                       values => [{
+                                               userEnteredFormat => $diff->[1]
+                                       }]
+                               }],
+                               fields => 'userEnteredFormat.backgroundColor',
+                               range => {
+                                       sheetId => $tab_id,
+                                       startRowIndex => $rowno,
+                                       endRowIndex => $rowno + 1,
+                                       startColumnIndex => $colno,
+                                       endColumnIndex => $colno + 1
                                }
-                       };
-               }
+                       }
+               };
        }
 }
 
-# Add the reaction log. (This only takes into account the last change
-# for each user; earlier ones are irrelevant and don't count. But it
-# doesn't deduplicate across reactions. Meh.)
-$q = $dbh->prepare('select userid,event_type,reaction,to_char(event_ts,\'YYYY-mm-dd HH24:MI\') as event_ts from ( select distinct on (channel,ts,userid,reaction) userid,event_type,reaction,timestamptz \'1970-01-01 utc\' + event_ts::float * interval \'1 second\' as event_ts from reaction_log where channel=? and ts=? and reaction in (\'heart\',\'open_mouth\') order by channel,ts,userid,reaction,event_ts desc ) t1 where event_ts > current_timestamp - interval \'8 hours\' order by event_ts desc limit 50');
-$q->execute($config::invitation_channel, $invitation_ts);
-my @recent_changes = ();
-while (my $ref = $q->fetchrow_hashref) {
-       my $msg = $ref->{'event_ts'};
-       if ($ref->{'event_type'} eq 'reaction_added') {
-               $msg .= ' +';
-       } else {
-               $msg .= ' –';
-       }
-       if ($ref->{'reaction'} eq 'open_mouth') {
-               $msg .= '😮';
-       } else {
-               $msg .= '❤️';
-       }
-       $msg .= ' ';
-       if (exists($slack_userid_to_real_name{$ref->{'userid'}})) {
-               $msg .= $slack_userid_to_real_name{$ref->{'userid'}};
-       } elsif (exists($slack_userid_to_slack_name{$ref->{'userid'}})) {
-               $msg .= $slack_userid_to_slack_name{$ref->{'userid'}} . ' (fant ikke regneark-navn)';
-       } else {
-               # Should only happen if we didn't see the initial reaction_add, only reaction_remove.
-               $msg .= $ref->{'userid'} . ' (fant ikke Slack-navn)';
-       }
-       push @recent_changes, { values => [{ userEnteredValue => { stringValue => $msg } }] };
-}
-while (scalar @recent_changes < 50) {
-       push @recent_changes, { values => [{ userEnteredValue => { stringValue => '' } }] };
-}
+my @recent_changes = create_reaction_log($dbh, $invitation_ts, \%slack_userid_to_real_name, \%slack_userid_to_slack_name);
 push @yellow_updates, {
        updateCells => {
                rows => \@recent_changes,