diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 69b5bb8..cb3e7a2 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2022-07-16 22:35:08 UTC using RuboCop version 1.31.2. +# on 2024-01-07 14:34:02 UTC using RuboCop version 1.31.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -153,6 +153,14 @@ Style/OptionalBooleanParameter: Exclude: - 'slack-strava/models/team.rb' +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. +# AllowedMethods: present?, blank?, presence, try, try! +Style/SafeNavigation: + Exclude: + - 'slack-strava/models/user_activity.rb' + # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). Style/SlicingWithRange: @@ -169,7 +177,7 @@ Style/StringConcatenation: - 'slack-strava/models/team.rb' - 'tasks/db.rake' -# Offense count: 131 +# Offense count: 139 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, IgnoredPatterns. # URISchemes: http, https diff --git a/CHANGELOG.md b/CHANGELOG.md index f77f6cc..39c81b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### Changelog +* 2024/01/07: Add Title, Description, Url, User, Athlete and Date field options - [@dblock](https://github.com/dblock). * 2023/01/21: Upgrade to Ruby 2.7.7 - [@dblock](https://github.com/dblock). * 2022/07/16: Fix [#112](https://github.com/dblock/slack-strava/issues/112), handle archived channels - [@dblock](https://github.com/dblock). * 2022/07/16: [#137](https://github.com/dblock/slack-strava/issues/137), add `set units imperial` and `set units metric` - [@dblock](https://github.com/dblock). diff --git a/slack-strava/models/activity_fields.rb b/slack-strava/models/activity_fields.rb index 2530686..b2d9d10 100644 --- a/slack-strava/models/activity_fields.rb +++ b/slack-strava/models/activity_fields.rb @@ -19,7 +19,21 @@ class ActivityFields define :CALORIES, 'Calories' define :WEATHER, 'Weather' - DEFAULT_VALUES = ['Type', 'Distance', 'Time', 'Moving Time', 'Elapsed Time', 'Pace', 'Speed', 'Elevation', 'Weather'].freeze + define :TITLE, 'Title' + define :DESCRIPTION, 'Description' + define :URL, 'Url' + define :USER, 'User' + define :ATHLETE, 'Athlete' + define :DATE, 'Date' + + HEADER_VALUES = %w[ + Title Description Url User Athlete Date + ].freeze + + DEFAULT_VALUES = [ + 'Title', 'Description', 'Url', 'User', 'Athlete', 'Date', + 'Type', 'Distance', 'Time', 'Moving Time', 'Elapsed Time', 'Pace', 'Speed', 'Elevation', 'Weather' + ].freeze def self.parse_s(values) return unless values @@ -29,6 +43,7 @@ def self.parse_s(values) values.scan(/[\w\s']+/).map do |v| v = v.strip title = v.titleize + title = ActivityFields::PR_COUNT if title == 'Pr Count' # HACK: titleize if value?(title) fields << title else diff --git a/slack-strava/models/activity_methods.rb b/slack-strava/models/activity_methods.rb index 7e89881..b0185e6 100644 --- a/slack-strava/models/activity_methods.rb +++ b/slack-strava/models/activity_methods.rb @@ -256,6 +256,21 @@ def time_in_hours_s(time) ].compact.join end + def display_field?(name) + activity_fields = team.activity_fields + + case activity_fields + when ['All'] + true + when ['Default'] + ActivityFields::DEFAULT_VALUES.include?(name) + when ['None'] + ActivityFields::HEADER_VALUES.include?(name) + else + activity_fields.include?(name) + end + end + def slack_fields activity_fields = team.activity_fields diff --git a/slack-strava/models/user_activity.rb b/slack-strava/models/user_activity.rb index e66869a..7e37ca2 100644 --- a/slack-strava/models/user_activity.rb +++ b/slack-strava/models/user_activity.rb @@ -84,11 +84,39 @@ def self.create_from_strava!(user, response) def to_slack_attachment result = {} - fallback_fields = [distance_s, moving_time_in_hours_s, pace_s].compact.join(' ') - result[:fallback] = ["#{name} via #{user.slack_mention}", fallback_fields].compact.join(', ') - result[:title] = name - result[:title_link] = strava_url - result[:text] = ["<@#{user.user_name}> on #{start_date_local_s}", description].compact.join("\n\n") + + if display_field?(ActivityFields::TITLE) && display_field?(ActivityFields::URL) + result[:title] = name || strava_id + result[:title_link] = strava_url + elsif display_field?(ActivityFields::TITLE) + result[:title] = name || strava_id + elsif display_field?(ActivityFields::URL) + result[:title] = strava_id + result[:title_link] = strava_url + end + + result_fallback = [ + display_field?(ActivityFields::TITLE) ? name : nil, + display_field?(ActivityFields::USER) ? "via #{user.slack_mention}" : nil, + display_field?(ActivityFields::DISTANCE) ? distance_s : nil, + display_field?(ActivityFields::MOVING_TIME) ? moving_time_in_hours_s : nil, + display_field?(ActivityFields::PACE) ? pace_s : nil + ].compact.join(' ') + + result[:fallback] = result_fallback.blank? ? strava_id : result_fallback + + result_text = [ + if display_field?(ActivityFields::USER) || display_field?(ActivityFields::DATE) + [ + display_field?(ActivityFields::USER) ? "<@#{user.user_name}>" : nil, + display_field?(ActivityFields::DATE) ? start_date_local_s : nil + ].compact.join(' on ') + end, + display_field?(ActivityFields::DESCRIPTION) ? description : nil + ].compact.join("\n\n") + + result[:text] = result_text unless result_text.blank? + if map if team.maps == 'full' result[:image_url] = map.proxy_image_url @@ -96,8 +124,10 @@ def to_slack_attachment result[:thumb_url] = map.proxy_image_url end end - result[:fields] = slack_fields - result.merge!(user.athlete.to_slack) if user.athlete + + result_fields = slack_fields + result[:fields] = result_fields if result_fields && result_fields.any? + result.merge!(user.athlete.to_slack) if user.athlete && display_field?(ActivityFields::ATHLETE) result end diff --git a/spec/fabricators/user_activity_fabricator.rb b/spec/fabricators/user_activity_fabricator.rb index 14b2165..2b6cf76 100644 --- a/spec/fabricators/user_activity_fabricator.rb +++ b/spec/fabricators/user_activity_fabricator.rb @@ -3,6 +3,7 @@ user { Fabricate.build(:user) } type 'Run' name { Faker::Internet.user_name } + description 'Great run!' start_date { DateTime.parse('2018-02-20T18:02:13Z') } start_date_local { DateTime.parse('2018-02-20T10:02:13Z') } distance 22_539.6 diff --git a/spec/models/activity_fields_spec.rb b/spec/models/activity_fields_spec.rb index 290e4ad..a819c61 100644 --- a/spec/models/activity_fields_spec.rb +++ b/spec/models/activity_fields_spec.rb @@ -30,10 +30,10 @@ expect(ActivityFields.parse_s('elapsed time, Elapsed Time, Time')).to eq([ActivityFields::ELAPSED_TIME, ActivityFields::TIME]) end it 'raise an error on an invalid value' do - expect { ActivityFields.parse_s('invalid, elapsed time') }.to raise_error SlackStrava::Error, 'Invalid field: invalid, possible values are Default, All, None, Type, Distance, Time, Moving Time, Elapsed Time, Pace, Speed, Elevation, Max Speed, Heart Rate, Max Heart Rate, PR Count, Calories and Weather.' + expect { ActivityFields.parse_s('invalid, elapsed time') }.to raise_error SlackStrava::Error, 'Invalid field: invalid, possible values are Default, All, None, Type, Distance, Time, Moving Time, Elapsed Time, Pace, Speed, Elevation, Max Speed, Heart Rate, Max Heart Rate, PR Count, Calories, Weather, Title, Description, Url, User, Athlete and Date.' end it 'raise an error on invalid fields' do - expect { ActivityFields.parse_s('invalid, elapsed time, whatever') }.to raise_error SlackStrava::Error, 'Invalid fields: invalid and whatever, possible values are Default, All, None, Type, Distance, Time, Moving Time, Elapsed Time, Pace, Speed, Elevation, Max Speed, Heart Rate, Max Heart Rate, PR Count, Calories and Weather.' + expect { ActivityFields.parse_s('invalid, elapsed time, whatever') }.to raise_error SlackStrava::Error, 'Invalid fields: invalid and whatever, possible values are Default, All, None, Type, Distance, Time, Moving Time, Elapsed Time, Pace, Speed, Elevation, Max Speed, Heart Rate, Max Heart Rate, PR Count, Calories, Weather, Title, Description, Url, User, Athlete and Date.' end end end diff --git a/spec/models/user_activity_spec.rb b/spec/models/user_activity_spec.rb index 3c853f2..897cb2f 100644 --- a/spec/models/user_activity_spec.rb +++ b/spec/models/user_activity_spec.rb @@ -137,10 +137,10 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 14.01mi 2h6m26s 9m02s/mi", + fallback: "#{activity.name} via #{activity.user.slack_mention} 14.01mi 2h6m26s 9m02s/mi", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", - text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", fields: [ { title: 'Type', value: 'Run 🏃', short: true }, @@ -167,10 +167,10 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 14.01mi 2h6m26s 9m02s/mi", + fallback: "#{activity.name} via #{activity.user.slack_mention} 14.01mi 2h6m26s 9m02s/mi", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", - text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", fields: [ { title: 'Type', value: 'Run 🏃', short: true }, @@ -195,6 +195,153 @@ ) end end + context 'with none fields' do + before do + team.activity_fields = ['None'] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: "#{activity.name} via #{activity.user.slack_mention}", + title: activity.name, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", + author_name: user.athlete.name, + author_link: user.athlete.strava_url, + author_icon: user.athlete.profile_medium + } + ] + ) + end + end + context 'with all header fields' do + before do + team.activity_fields = %w[Title Url User Description Date Athlete] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: "#{activity.name} via #{activity.user.slack_mention}", + title: activity.name, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", + author_name: user.athlete.name, + author_link: user.athlete.strava_url, + author_icon: user.athlete.profile_medium + } + ] + ) + end + end + context 'without athlete' do + before do + team.activity_fields = %w[Title Url User Description Date] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: "#{activity.name} via #{activity.user.slack_mention}", + title: activity.name, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png" + } + ] + ) + end + end + context 'without user' do + before do + team.activity_fields = %w[Title Url Description Date] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: activity.name, + title: activity.name, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + text: "Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png" + } + ] + ) + end + end + context 'without description' do + before do + team.activity_fields = %w[Title Url User Date] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: "#{activity.name} via #{activity.user.slack_mention}", + title: activity.name, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png" + } + ] + ) + end + end + context 'without date' do + before do + team.activity_fields = %w[Title Url Description] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: activity.name, + title: activity.name, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + text: 'Great run!', + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png" + } + ] + ) + end + end + context 'without url' do + before do + team.activity_fields = %w[Title] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: activity.name, + title: activity.name, + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png" + } + ] + ) + end + end + context 'without title' do + before do + team.activity_fields = %w[Url] + end + it 'to_slack' do + expect(activity.to_slack).to eq( + attachments: [ + { + fallback: activity.strava_id, + title: activity.strava_id, + title_link: "https://www.strava.com/activities/#{activity.strava_id}", + image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png" + } + ] + ) + end + end context 'without an athlete' do before do user.athlete.destroy @@ -203,10 +350,10 @@ expect(activity.reload.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 14.01mi 2h6m26s 9m02s/mi", + fallback: "#{activity.name} via #{activity.user.slack_mention} 14.01mi 2h6m26s 9m02s/mi", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", - text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", fields: [ { title: 'Type', value: 'Run 🏃', short: true }, @@ -231,10 +378,10 @@ expect(activity.reload.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 14.01mi 2h6m26s", + fallback: "#{activity.name} via #{activity.user.slack_mention} 14.01mi 2h6m26s", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", - text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", fields: [ { title: 'Type', value: 'Run 🏃', short: true }, @@ -261,10 +408,10 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 22.54km 2h6m26s 5m37s/km", + fallback: "#{activity.name} via #{activity.user.slack_mention} 22.54km 2h6m26s 5m37s/km", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", - text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", fields: [ { title: 'Type', value: 'Run 🏃', short: true }, @@ -292,10 +439,10 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 14.01mi 22.54km 2h6m26s 9m02s/mi 5m37s/km", + fallback: "#{activity.name} via #{activity.user.slack_mention} 14.01mi 22.54km 2h6m26s 9m02s/mi 5m37s/km", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", - text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", + text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM\n\nGreat run!", image_url: "https://slava.playplay.io/api/maps/#{activity.map.id}.png", fields: [ { title: 'Type', value: 'Run 🏃', short: true }, @@ -323,7 +470,7 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 2050yd 37m 1m48s/100yd", + fallback: "#{activity.name} via #{activity.user.slack_mention} 2050yd 37m 1m48s/100yd", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", @@ -350,7 +497,7 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 1874m 37m 1m58s/100m", + fallback: "#{activity.name} via #{activity.user.slack_mention} 1874m 37m 1m58s/100m", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", @@ -377,7 +524,7 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 2050yd 1874m 37m 1m48s/100yd 1m58s/100m", + fallback: "#{activity.name} via #{activity.user.slack_mention} 2050yd 1874m 37m 1m48s/100yd 1m58s/100m", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", @@ -404,7 +551,7 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 28.1km 1h10m7s 2m30s/km", + fallback: "#{activity.name} via #{activity.user.slack_mention} 28.1km 1h10m7s 2m30s/km", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", @@ -432,7 +579,7 @@ expect(activity.to_slack).to eq( attachments: [ { - fallback: "#{activity.name} via #{activity.user.slack_mention}, 17.46mi 28.1km 1h10m7s 4m01s/mi 2m30s/km", + fallback: "#{activity.name} via #{activity.user.slack_mention} 17.46mi 28.1km 1h10m7s 4m01s/mi 2m30s/km", title: activity.name, title_link: "https://www.strava.com/activities/#{activity.strava_id}", text: "<@#{activity.user.user_name}> on Tuesday, February 20, 2018 at 10:02 AM", diff --git a/spec/slack-strava/commands/set_spec.rb b/spec/slack-strava/commands/set_spec.rb index e168e59..dc22fb1 100644 --- a/spec/slack-strava/commands/set_spec.rb +++ b/spec/slack-strava/commands/set_spec.rb @@ -274,10 +274,30 @@ end it 'sets to invalid fields' do expect(message: "#{SlackRubyBot.config.user} set fields Time, Foo, Bar").to respond_with_slack_message( - 'Invalid fields: Foo and Bar, possible values are Default, All, None, Type, Distance, Time, Moving Time, Elapsed Time, Pace, Speed, Elevation, Max Speed, Heart Rate, Max Heart Rate, PR Count, Calories and Weather.' + 'Invalid fields: Foo and Bar, possible values are Default, All, None, Type, Distance, Time, Moving Time, Elapsed Time, Pace, Speed, Elevation, Max Speed, Heart Rate, Max Heart Rate, PR Count, Calories, Weather, Title, Description, Url, User, Athlete and Date.' ) expect(team.reload.activity_fields).to eq ['Default'] end + context 'some' do + it 'sets fields to some' do + expect(message: "#{SlackRubyBot.config.user} set fields Title, Url, PR Count, Elapsed Time").to respond_with_slack_message( + "Activity fields for team #{team.name} are now *Title, Url, PR Count and Elapsed Time*." + ) + expect(team.reload.activity_fields).to eq(['Title', 'Url', 'PR Count', 'Elapsed Time']) + end + end + context 'each field' do + (ActivityFields.values - [ActivityFields::ALL, ActivityFields::DEFAULT, ActivityFields::NONE]).each do |field| + context field do + it "sets fields to #{field}" do + expect(message: "#{SlackRubyBot.config.user} set fields #{field}").to respond_with_slack_message( + "Activity fields for team #{team.name} are now *#{field}*." + ) + expect(team.reload.activity_fields).to eq([field]) + end + end + end + end end context 'not as a team admin' do let(:user) { Fabricate(:user, team: team) }