slk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -1
- data/README.md +5 -5
- data/bin/slk +3 -3
- data/lib/{slack_cli → slk}/api/activity.rb +10 -11
- data/lib/{slack_cli → slk}/api/bots.rb +5 -4
- data/lib/slk/api/client.rb +51 -0
- data/lib/{slack_cli → slk}/api/conversations.rb +14 -13
- data/lib/slk/api/dnd.rb +41 -0
- data/lib/{slack_cli → slk}/api/emoji.rb +4 -3
- data/lib/{slack_cli → slk}/api/threads.rb +13 -12
- data/lib/{slack_cli → slk}/api/usergroups.rb +2 -1
- data/lib/slk/api/users.rb +105 -0
- data/lib/slk/cli.rb +157 -0
- data/lib/slk/commands/activity.rb +152 -0
- data/lib/{slack_cli → slk}/commands/base.rb +67 -41
- data/lib/slk/commands/cache.rb +141 -0
- data/lib/slk/commands/catchup.rb +411 -0
- data/lib/slk/commands/config.rb +114 -0
- data/lib/slk/commands/dnd.rb +172 -0
- data/lib/slk/commands/emoji.rb +352 -0
- data/lib/slk/commands/help.rb +97 -0
- data/lib/slk/commands/messages.rb +299 -0
- data/lib/slk/commands/presence.rb +109 -0
- data/lib/slk/commands/preset.rb +231 -0
- data/lib/slk/commands/status.rb +223 -0
- data/lib/slk/commands/thread.rb +72 -0
- data/lib/slk/commands/unread.rb +305 -0
- data/lib/slk/commands/workspaces.rb +168 -0
- data/lib/slk/formatters/activity_formatter.rb +148 -0
- data/lib/slk/formatters/attachment_formatter.rb +65 -0
- data/lib/slk/formatters/block_formatter.rb +57 -0
- data/lib/{slack_cli → slk}/formatters/duration_formatter.rb +6 -5
- data/lib/slk/formatters/emoji_replacer.rb +141 -0
- data/lib/slk/formatters/json_message_formatter.rb +95 -0
- data/lib/slk/formatters/mention_replacer.rb +158 -0
- data/lib/slk/formatters/message_formatter.rb +174 -0
- data/lib/{slack_cli → slk}/formatters/output.rb +7 -6
- data/lib/slk/formatters/reaction_formatter.rb +87 -0
- data/lib/{slack_cli → slk}/models/channel.rb +12 -10
- data/lib/slk/models/duration.rb +94 -0
- data/lib/slk/models/message.rb +242 -0
- data/lib/slk/models/preset.rb +78 -0
- data/lib/{slack_cli → slk}/models/reaction.rb +6 -6
- data/lib/{slack_cli → slk}/models/status.rb +6 -6
- data/lib/slk/models/user.rb +55 -0
- data/lib/slk/models/workspace.rb +54 -0
- data/lib/{slack_cli → slk}/runner.rb +22 -19
- data/lib/slk/services/activity_enricher.rb +124 -0
- data/lib/slk/services/api_client.rb +145 -0
- data/lib/{slack_cli → slk}/services/cache_store.rb +20 -17
- data/lib/{slack_cli → slk}/services/configuration.rb +9 -8
- data/lib/slk/services/emoji_downloader.rb +103 -0
- data/lib/slk/services/emoji_searcher.rb +72 -0
- data/lib/{slack_cli → slk}/services/encryption.rb +11 -14
- data/lib/slk/services/gemoji_sync.rb +97 -0
- data/lib/{slack_cli → slk}/services/preset_store.rb +34 -33
- data/lib/slk/services/reaction_enricher.rb +82 -0
- data/lib/slk/services/setup_wizard.rb +131 -0
- data/lib/slk/services/target_resolver.rb +108 -0
- data/lib/{slack_cli → slk}/services/token_store.rb +11 -10
- data/lib/slk/services/unread_marker.rb +101 -0
- data/lib/{slack_cli → slk}/support/error_logger.rb +2 -1
- data/lib/{slack_cli → slk}/support/help_formatter.rb +36 -44
- data/lib/{slack_cli → slk}/support/inline_images.rb +28 -19
- data/lib/slk/support/interactive_prompt.rb +29 -0
- data/lib/{slack_cli → slk}/support/slack_url_parser.rb +15 -17
- data/lib/slk/support/text_wrapper.rb +57 -0
- data/lib/slk/support/user_resolver.rb +141 -0
- data/lib/{slack_cli → slk}/support/xdg_paths.rb +6 -5
- data/lib/slk/version.rb +5 -0
- data/lib/slk.rb +112 -0
- metadata +80 -59
- data/lib/slack_cli/api/client.rb +0 -49
- data/lib/slack_cli/api/dnd.rb +0 -40
- data/lib/slack_cli/api/users.rb +0 -101
- data/lib/slack_cli/cli.rb +0 -118
- data/lib/slack_cli/commands/activity.rb +0 -292
- data/lib/slack_cli/commands/cache.rb +0 -116
- data/lib/slack_cli/commands/catchup.rb +0 -484
- data/lib/slack_cli/commands/config.rb +0 -159
- data/lib/slack_cli/commands/dnd.rb +0 -143
- data/lib/slack_cli/commands/emoji.rb +0 -412
- data/lib/slack_cli/commands/help.rb +0 -76
- data/lib/slack_cli/commands/messages.rb +0 -317
- data/lib/slack_cli/commands/presence.rb +0 -107
- data/lib/slack_cli/commands/preset.rb +0 -239
- data/lib/slack_cli/commands/status.rb +0 -194
- data/lib/slack_cli/commands/thread.rb +0 -62
- data/lib/slack_cli/commands/unread.rb +0 -312
- data/lib/slack_cli/commands/workspaces.rb +0 -151
- data/lib/slack_cli/formatters/emoji_replacer.rb +0 -143
- data/lib/slack_cli/formatters/mention_replacer.rb +0 -154
- data/lib/slack_cli/formatters/message_formatter.rb +0 -429
- data/lib/slack_cli/models/duration.rb +0 -85
- data/lib/slack_cli/models/message.rb +0 -217
- data/lib/slack_cli/models/preset.rb +0 -73
- data/lib/slack_cli/models/user.rb +0 -56
- data/lib/slack_cli/models/workspace.rb +0 -52
- data/lib/slack_cli/services/api_client.rb +0 -149
- data/lib/slack_cli/services/reaction_enricher.rb +0 -87
- data/lib/slack_cli/support/user_resolver.rb +0 -114
- data/lib/slack_cli/version.rb +0 -5
- data/lib/slack_cli.rb +0 -91
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../support/help_formatter'
|
|
4
|
+
|
|
5
|
+
module Slk
|
|
6
|
+
module Commands
|
|
7
|
+
# Displays recent activity feed items (reactions, mentions, threads)
|
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
|
9
|
+
class Activity < Base
|
|
10
|
+
def execute
|
|
11
|
+
result = validate_options
|
|
12
|
+
return result if result
|
|
13
|
+
|
|
14
|
+
workspace = target_workspaces.first
|
|
15
|
+
fetch_and_display_activity(workspace)
|
|
16
|
+
rescue ApiError => e
|
|
17
|
+
error("Failed to fetch activity: #{e.message}")
|
|
18
|
+
1
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def fetch_and_display_activity(workspace)
|
|
24
|
+
api = runner.activity_api(workspace.name)
|
|
25
|
+
response = api.feed(limit: @options[:limit], types: activity_types)
|
|
26
|
+
|
|
27
|
+
return error_result(response) unless response['ok']
|
|
28
|
+
|
|
29
|
+
display_activity(workspace, response['items'] || [])
|
|
30
|
+
0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def error_result(response)
|
|
34
|
+
error("Failed to fetch activity: #{response['error']}")
|
|
35
|
+
1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def display_activity(workspace, items)
|
|
39
|
+
if @options[:json]
|
|
40
|
+
output_json(enricher(workspace).enrich_all(items, workspace))
|
|
41
|
+
else
|
|
42
|
+
formatter(workspace).display_all(items, workspace, options: display_options(workspace))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
protected
|
|
47
|
+
|
|
48
|
+
def default_options
|
|
49
|
+
super.merge(
|
|
50
|
+
limit: 20,
|
|
51
|
+
filter: :all,
|
|
52
|
+
show_messages: false
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def handle_option(arg, args, remaining)
|
|
57
|
+
case arg
|
|
58
|
+
when '-n', '--limit' then @options[:limit] = args.shift.to_i
|
|
59
|
+
when '--reactions' then @options[:filter] = :reactions
|
|
60
|
+
when '--mentions' then @options[:filter] = :mentions
|
|
61
|
+
when '--threads' then @options[:filter] = :threads
|
|
62
|
+
when '--show-messages', '-m' then @options[:show_messages] = true
|
|
63
|
+
else super
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def help_text
|
|
68
|
+
help = Support::HelpFormatter.new('slk activity [options]')
|
|
69
|
+
help.description('Show recent activity from the activity feed.')
|
|
70
|
+
add_options_section(help)
|
|
71
|
+
help.render
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def add_options_section(help)
|
|
75
|
+
help.section('OPTIONS') do |s|
|
|
76
|
+
s.option('-n, --limit N', 'Number of items (default: 20, max: 50)')
|
|
77
|
+
s.option('--reactions', 'Show only reaction activity')
|
|
78
|
+
s.option('--mentions', 'Show only mentions')
|
|
79
|
+
s.option('--threads', 'Show only thread replies')
|
|
80
|
+
s.option('-m, --show-messages', 'Show the message content for each activity')
|
|
81
|
+
add_common_options(s)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def add_common_options(section)
|
|
86
|
+
section.option('--json', 'Output as JSON')
|
|
87
|
+
section.option('-w, --workspace', 'Specify workspace')
|
|
88
|
+
section.option('-v, --verbose', 'Show debug information')
|
|
89
|
+
section.option('-q, --quiet', 'Suppress output')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def activity_types
|
|
95
|
+
case @options[:filter]
|
|
96
|
+
when :reactions
|
|
97
|
+
'message_reaction'
|
|
98
|
+
when :mentions
|
|
99
|
+
'at_user,at_user_group,at_channel,at_everyone'
|
|
100
|
+
when :threads
|
|
101
|
+
'thread_v2'
|
|
102
|
+
else
|
|
103
|
+
# All activity types that the Slack web UI uses
|
|
104
|
+
'thread_v2,message_reaction,bot_dm_bundle,at_user,at_user_group,at_channel,at_everyone'
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def enricher(workspace)
|
|
109
|
+
Services::ActivityEnricher.new(
|
|
110
|
+
cache_store: cache_store,
|
|
111
|
+
conversations_api: runner.conversations_api(workspace.name),
|
|
112
|
+
on_debug: ->(msg) { debug(msg) }
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def formatter(workspace)
|
|
117
|
+
Formatters::ActivityFormatter.new(
|
|
118
|
+
output: output,
|
|
119
|
+
enricher: enricher(workspace),
|
|
120
|
+
emoji_replacer: runner.emoji_replacer,
|
|
121
|
+
mention_replacer: runner.mention_replacer,
|
|
122
|
+
on_debug: ->(msg) { debug(msg) }
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def display_options(_workspace)
|
|
127
|
+
{
|
|
128
|
+
show_messages: @options[:show_messages],
|
|
129
|
+
fetch_message: ->(ws, channel_id, message_ts) { fetch_message(ws, channel_id, message_ts) }
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def fetch_message(workspace, channel_id, message_ts)
|
|
134
|
+
response = fetch_message_history(workspace, channel_id, message_ts)
|
|
135
|
+
return nil unless response['ok'] && response['messages']&.any?
|
|
136
|
+
|
|
137
|
+
response['messages'].find { |msg| msg['ts'] == message_ts }
|
|
138
|
+
rescue ApiError => e
|
|
139
|
+
debug("Could not fetch message #{message_ts} from #{channel_id}: #{e.message}")
|
|
140
|
+
nil
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def fetch_message_history(workspace, channel_id, message_ts)
|
|
144
|
+
api = runner.conversations_api(workspace.name)
|
|
145
|
+
oldest_ts = (message_ts.to_f - 1).to_s
|
|
146
|
+
latest_ts = (message_ts.to_f + 1).to_s
|
|
147
|
+
api.history(channel: channel_id, limit: 10, oldest: oldest_ts, latest: latest_ts)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
# rubocop:enable Metrics/ClassLength
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module Slk
|
|
4
4
|
module Commands
|
|
5
|
+
# Base class for all CLI commands with option parsing and output helpers
|
|
6
|
+
# rubocop:disable Metrics/ClassLength
|
|
5
7
|
class Base
|
|
6
8
|
attr_reader :runner, :options, :positional_args
|
|
7
9
|
|
|
@@ -12,7 +14,7 @@ module SlackCli
|
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def execute
|
|
15
|
-
raise NotImplementedError,
|
|
17
|
+
raise NotImplementedError, 'Subclass must implement #execute'
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
protected
|
|
@@ -26,14 +28,15 @@ module SlackCli
|
|
|
26
28
|
def api_client = runner.api_client
|
|
27
29
|
|
|
28
30
|
def default_options
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
base_options.merge(formatting_options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def base_options
|
|
35
|
+
{ workspace: nil, all: false, verbose: false, quiet: false, json: false, width: default_width }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def formatting_options
|
|
39
|
+
{ no_emoji: false, no_reactions: false, no_names: false, reaction_names: false, reaction_timestamps: false }
|
|
37
40
|
end
|
|
38
41
|
|
|
39
42
|
# Default wrap width: 72 for interactive terminals, nil (no wrap) otherwise
|
|
@@ -48,39 +51,47 @@ module SlackCli
|
|
|
48
51
|
|
|
49
52
|
while args.any?
|
|
50
53
|
arg = args.shift
|
|
54
|
+
next remaining << arg unless arg.start_with?('-')
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
when "-w", "--workspace"
|
|
54
|
-
@options[:workspace] = args.shift
|
|
55
|
-
when "--width"
|
|
56
|
-
value = args.shift
|
|
57
|
-
@options[:width] = value == '0' ? nil : value.to_i
|
|
58
|
-
when "--no-wrap"
|
|
59
|
-
@options[:width] = nil
|
|
60
|
-
when "--all"
|
|
61
|
-
@options[:all] = true
|
|
62
|
-
when "-v", "--verbose"
|
|
63
|
-
@options[:verbose] = true
|
|
64
|
-
when "-q", "--quiet"
|
|
65
|
-
@options[:quiet] = true
|
|
66
|
-
when "--json"
|
|
67
|
-
@options[:json] = true
|
|
68
|
-
when "-h", "--help"
|
|
69
|
-
@options[:help] = true
|
|
70
|
-
when /^-/
|
|
71
|
-
# Let subclass handle unknown options
|
|
72
|
-
handle_option(arg, args, remaining)
|
|
73
|
-
else
|
|
74
|
-
remaining << arg
|
|
75
|
-
end
|
|
56
|
+
parse_single_option(arg, args, remaining)
|
|
76
57
|
end
|
|
77
58
|
|
|
78
59
|
remaining
|
|
79
60
|
end
|
|
80
61
|
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
65
|
+
def parse_single_option(arg, args, remaining)
|
|
66
|
+
case arg
|
|
67
|
+
when '-w', '--workspace' then @options[:workspace] = args.shift
|
|
68
|
+
when '--width' then parse_width_option(args)
|
|
69
|
+
when '--no-wrap' then @options[:width] = nil
|
|
70
|
+
when '--all' then @options[:all] = true
|
|
71
|
+
when '-v', '--verbose' then @options[:verbose] = true
|
|
72
|
+
when '-q', '--quiet' then @options[:quiet] = true
|
|
73
|
+
when '--json' then @options[:json] = true
|
|
74
|
+
when '-h', '--help' then @options[:help] = true
|
|
75
|
+
when '--no-emoji' then @options[:no_emoji] = true
|
|
76
|
+
when '--no-reactions' then @options[:no_reactions] = true
|
|
77
|
+
when '--no-names' then @options[:no_names] = true
|
|
78
|
+
when '--reaction-names' then @options[:reaction_names] = true
|
|
79
|
+
when '--reaction-timestamps' then @options[:reaction_timestamps] = true
|
|
80
|
+
else handle_option(arg, args, remaining)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
84
|
+
|
|
85
|
+
def parse_width_option(args)
|
|
86
|
+
value = args.shift
|
|
87
|
+
@options[:width] = value == '0' ? nil : value.to_i
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
protected
|
|
91
|
+
|
|
81
92
|
# Override in subclass to handle command-specific options
|
|
82
93
|
# Return true if option was handled, false to raise unknown option error
|
|
83
|
-
def handle_option(arg,
|
|
94
|
+
def handle_option(arg, _args, _remaining) # rubocop:disable Naming/PredicateMethod
|
|
84
95
|
# By default, unknown options are errors
|
|
85
96
|
# Subclasses can override and return true to accept the option,
|
|
86
97
|
# or call super to get this error behavior
|
|
@@ -94,13 +105,13 @@ module SlackCli
|
|
|
94
105
|
return nil if @unknown_options.nil? || @unknown_options.empty?
|
|
95
106
|
|
|
96
107
|
error("Unknown option: #{@unknown_options.first}")
|
|
97
|
-
error(
|
|
108
|
+
error('Run with --help for available options.')
|
|
98
109
|
1
|
|
99
110
|
end
|
|
100
111
|
|
|
101
112
|
# Returns true if there are unknown options
|
|
102
|
-
def
|
|
103
|
-
@unknown_options
|
|
113
|
+
def unknown_options?
|
|
114
|
+
@unknown_options&.any?
|
|
104
115
|
end
|
|
105
116
|
|
|
106
117
|
# Get workspaces to operate on based on options
|
|
@@ -128,13 +139,13 @@ module SlackCli
|
|
|
128
139
|
# Returns exit code if should return early, nil otherwise
|
|
129
140
|
def validate_options
|
|
130
141
|
return show_help if show_help?
|
|
131
|
-
return check_unknown_options if
|
|
142
|
+
return check_unknown_options if unknown_options?
|
|
132
143
|
|
|
133
144
|
nil
|
|
134
145
|
end
|
|
135
146
|
|
|
136
147
|
def help_text
|
|
137
|
-
|
|
148
|
+
'No help available for this command.'
|
|
138
149
|
end
|
|
139
150
|
|
|
140
151
|
# Output helpers
|
|
@@ -152,13 +163,14 @@ module SlackCli
|
|
|
152
163
|
|
|
153
164
|
def error(message)
|
|
154
165
|
output.error(message)
|
|
166
|
+
1
|
|
155
167
|
end
|
|
156
168
|
|
|
157
169
|
def debug(message)
|
|
158
170
|
output.debug(message) if @options[:verbose]
|
|
159
171
|
end
|
|
160
172
|
|
|
161
|
-
def puts(message =
|
|
173
|
+
def puts(message = '')
|
|
162
174
|
output.puts(message) unless @options[:quiet]
|
|
163
175
|
end
|
|
164
176
|
|
|
@@ -170,6 +182,20 @@ module SlackCli
|
|
|
170
182
|
def output_json(data)
|
|
171
183
|
output.puts(JSON.pretty_generate(data))
|
|
172
184
|
end
|
|
185
|
+
|
|
186
|
+
# Build format options hash for message formatting
|
|
187
|
+
# Subclasses can override to add command-specific options
|
|
188
|
+
def format_options
|
|
189
|
+
{
|
|
190
|
+
no_emoji: @options[:no_emoji],
|
|
191
|
+
no_reactions: @options[:no_reactions],
|
|
192
|
+
no_names: @options[:no_names],
|
|
193
|
+
reaction_names: @options[:reaction_names],
|
|
194
|
+
reaction_timestamps: @options[:reaction_timestamps],
|
|
195
|
+
width: @options[:width]
|
|
196
|
+
}
|
|
197
|
+
end
|
|
173
198
|
end
|
|
199
|
+
# rubocop:enable Metrics/ClassLength
|
|
174
200
|
end
|
|
175
201
|
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../support/help_formatter'
|
|
4
|
+
|
|
5
|
+
module Slk
|
|
6
|
+
module Commands
|
|
7
|
+
# Manages user and channel name cache
|
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
|
9
|
+
class Cache < Base
|
|
10
|
+
def execute
|
|
11
|
+
result = validate_options
|
|
12
|
+
return result if result
|
|
13
|
+
|
|
14
|
+
dispatch_action
|
|
15
|
+
rescue ApiError => e
|
|
16
|
+
error("Failed: #{e.message}")
|
|
17
|
+
1
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def dispatch_action
|
|
23
|
+
case positional_args
|
|
24
|
+
in ['status' | 'info'] | [] then show_status
|
|
25
|
+
in ['clear', *rest] then clear_cache(rest.first)
|
|
26
|
+
in ['populate' | 'refresh', *rest] then populate_cache(rest.first)
|
|
27
|
+
else unknown_action
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def unknown_action
|
|
32
|
+
error("Unknown action: #{positional_args.first}")
|
|
33
|
+
1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
protected
|
|
37
|
+
|
|
38
|
+
def help_text
|
|
39
|
+
help = Support::HelpFormatter.new('slk cache <action> [workspace]')
|
|
40
|
+
help.description('Manage user and channel cache.')
|
|
41
|
+
add_actions_section(help)
|
|
42
|
+
add_options_section(help)
|
|
43
|
+
help.render
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_actions_section(help)
|
|
47
|
+
help.section('ACTIONS') do |s|
|
|
48
|
+
s.action('status', 'Show cache status')
|
|
49
|
+
s.action('clear [ws]', 'Clear cache (all or specific workspace)')
|
|
50
|
+
s.action('populate [ws]', 'Populate user cache from API')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def add_options_section(help)
|
|
55
|
+
help.section('OPTIONS') do |s|
|
|
56
|
+
s.option('-w, --workspace', 'Specify workspace')
|
|
57
|
+
s.option('-q, --quiet', 'Suppress output')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def show_status
|
|
64
|
+
target_workspaces.each { |workspace| display_workspace_status(workspace) }
|
|
65
|
+
0
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def display_workspace_status(workspace)
|
|
69
|
+
puts output.bold(workspace.name) if target_workspaces.size > 1
|
|
70
|
+
display_cache_counts(workspace)
|
|
71
|
+
display_cache_file_status(workspace)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def display_cache_counts(workspace)
|
|
75
|
+
user_count = cache_store.user_cache_size(workspace.name)
|
|
76
|
+
channel_count = cache_store.channel_cache_size(workspace.name)
|
|
77
|
+
puts " Users cached: #{user_count}"
|
|
78
|
+
puts " Channels cached: #{channel_count}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def display_cache_file_status(workspace)
|
|
82
|
+
if cache_store.user_cache_file_exists?(workspace.name)
|
|
83
|
+
puts " User cache: #{output.green('present')}"
|
|
84
|
+
else
|
|
85
|
+
puts " User cache: #{output.yellow('not populated')}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def clear_cache(workspace_name)
|
|
90
|
+
if workspace_name
|
|
91
|
+
cache_store.clear_user_cache(workspace_name)
|
|
92
|
+
cache_store.clear_channel_cache(workspace_name)
|
|
93
|
+
success("Cleared cache for #{workspace_name}")
|
|
94
|
+
else
|
|
95
|
+
cache_store.clear_user_cache
|
|
96
|
+
cache_store.clear_channel_cache
|
|
97
|
+
success('Cleared all caches')
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def populate_cache(workspace_name)
|
|
104
|
+
workspaces = workspace_name ? [runner.workspace(workspace_name)] : target_workspaces
|
|
105
|
+
workspaces.each { |workspace| populate_workspace_cache(workspace) }
|
|
106
|
+
0
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def populate_workspace_cache(workspace)
|
|
110
|
+
puts "Populating user cache for #{workspace.name}..."
|
|
111
|
+
all_users = fetch_all_users(workspace)
|
|
112
|
+
count = cache_store.populate_user_cache(workspace.name, all_users)
|
|
113
|
+
puts
|
|
114
|
+
success("Cached #{count} users for #{workspace.name}")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def fetch_all_users(workspace)
|
|
118
|
+
api = runner.users_api(workspace.name)
|
|
119
|
+
all_users = []
|
|
120
|
+
cursor = nil
|
|
121
|
+
|
|
122
|
+
loop do
|
|
123
|
+
response, cursor = fetch_users_page(api, cursor)
|
|
124
|
+
all_users.concat(response)
|
|
125
|
+
break if cursor.nil? || cursor.empty?
|
|
126
|
+
|
|
127
|
+
print '.'
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
all_users
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def fetch_users_page(api, cursor)
|
|
134
|
+
response = api.list(cursor: cursor)
|
|
135
|
+
users = (response['members'] || []).map { |m| Models::User.from_api(m) }
|
|
136
|
+
[users, response.dig('response_metadata', 'next_cursor')]
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
# rubocop:enable Metrics/ClassLength
|
|
140
|
+
end
|
|
141
|
+
end
|