slack_neuralyzer 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f34f12786efe803fc3109712824067b26c27e228
4
+ data.tar.gz: 9e84e469278787d33e1438b8306110ce7c2b0c41
5
+ SHA512:
6
+ metadata.gz: 9d2c9932289e8bdbbee6e12318eaf4192b8466eac8fe6f9037acfe764a530c8a1bd1c823d1841c23302f16c39a7edb45d740f3a9978bf93b55a38316c85c267b
7
+ data.tar.gz: d88b648cc1f468161e75477b37c6265a44b72a2b02ac7c929299f7a61f72c2ce18e596621b37379f712cf38d16a1b2c5c1ab55cba369d659e88b534cb025bcba
@@ -0,0 +1,16 @@
1
+ engines:
2
+ rubocop:
3
+ enabled: true
4
+ duplication:
5
+ enabled: true
6
+ config:
7
+ languages:
8
+ - ruby
9
+ ratings:
10
+ paths:
11
+ - lib/**
12
+ - "**.rb"
13
+ exclude_paths:
14
+ - spec/**/*
15
+ - topic/**/*
16
+ - "**/vendor/**/*"
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.3
5
+ before_install: gem install bundler -v 1.11.2
6
+ script: bundle exec rspec --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in slack_neuralyzer.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Leon Ji
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,216 @@
1
+ # Slack Neuralyzer
2
+
3
+ [![Build Status](https://travis-ci.org/mgleon08/slack_neuralyzer.svg?branch=master)](https://travis-ci.org/mgleon08/slack_neuralyzer)
4
+ [![Coverage Status](https://coveralls.io/repos/github/mgleon08/slack_neuralyzer/badge.svg?branch=master)](https://coveralls.io/github/mgleon08/slack_neuralyzer?branch=master)
5
+ [![Code Climate](https://codeclimate.com/github/mgleon08/slack_neuralyzer/badges/gpa.svg)](https://codeclimate.com/github/mgleon08/slack_neuralyzer)
6
+ [![security](https://hakiri.io/github/mgleon08/slack_neuralyzer/master.svg)](https://hakiri.io/github/mgleon08/slack_neuralyzer/master)
7
+ [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mgleon08/slack_neuralyzer/blob/master/LICENSE.txt)
8
+
9
+ Slack Neuralyzer is a ruby gem for bulk delete messages and files on Slack channels.
10
+
11
+ The easiest way to clean up messages and files on Slack.
12
+
13
+ ![](https://media.giphy.com/media/65NO1TrKrJUT6/giphy.gif)
14
+
15
+ ## Installation
16
+
17
+ ```
18
+ $ gem install slack_neuralyzer
19
+ ```
20
+
21
+ ## Slack token
22
+
23
+ <a href='https://api.slack.com/web' target='_blank'><img src='screenshots/general_test_token.png' alt='general_test_token' width = '20%' /></a>
24
+
25
+ ##Getting Started
26
+
27
+ ![](screenshots/slack_neuralyzer_demo.gif)
28
+
29
+ ### Show all channel names
30
+
31
+ `slack_neuralyzer -t <TOKEN> -s`
32
+
33
+ ```ruby
34
+ All user direct:
35
+ 001. leon
36
+ 002. slackbot
37
+ 003. cleanerbot
38
+
39
+ All channels (public):
40
+ 001. general
41
+ 002. random
42
+
43
+ All groups (private):
44
+ 001. private_channel
45
+
46
+ All multiparty direct:
47
+ 001. mpdm-leon--cleanerbot-1
48
+ 002. mpdm-leon--slackbot-1
49
+ ```
50
+
51
+ ### Delete message(s)
52
+
53
+ >Rerun below command and use `-e | --execute` to actually delete the message(s).
54
+
55
+ * Channel
56
+
57
+ `-C | --channel` `-D | --direct` `-G | --group` `-M | --mpdirect`
58
+
59
+ ```ruby
60
+ # Delete all user messages in general channel
61
+ slack_neuralyzer -t <TOKEN> -m -C general -u all
62
+
63
+ # Delete all user messages in leon direct channel
64
+ slack_neuralyzer -t <TOKEN> -m -D leon -u all
65
+
66
+ # Delete all user messages in private_channel groups channel
67
+ slack_neuralyzer -t <TOKEN> -m -G private_channel -u all
68
+
69
+ # Delete all user messages in mpdm-leon--cleanerbot-1 multiparty direct channel
70
+ # (can `use slack_neuralyzer -t <TOKEN> -s` to see mpdirect channle name)
71
+ slack_neuralyzer -t <TOKEN> -m -M mpdm-leon--cleanerbot-1 -u all
72
+ ```
73
+
74
+ * Specific user
75
+
76
+ `-u | --user`
77
+
78
+ ```ruby
79
+ # Delete leon messages in general channel
80
+ slack_neuralyzer -t <TOKEN> -m -C general -u leon
81
+
82
+ # if you want to specific all users, you can type 'all'
83
+ slack_neuralyzer -t <TOKEN> -m -C general -u all
84
+ ```
85
+
86
+ * Specific Bot
87
+
88
+ `-b | --bot`
89
+
90
+ ```ruby
91
+ # Delete bots messages in general channel
92
+ slack_neuralyzer -t <TOKEN> -m -C general -b cleanerbot
93
+
94
+ # if you want to specific all bots, you can type 'all' (not bot users)
95
+ slack_neuralyzer -t <TOKEN> -m -C general -b all
96
+ ```
97
+
98
+ * Delete message(s) between two dates
99
+
100
+ `-A | --after` `-B | --before`
101
+
102
+ ```ruby
103
+ # Delete all user messages in general channel at 20160101 to 20161212
104
+ slack_neuralyzer -t <TOKEN> -m -C general -u all -A 20160101 -B 20161212
105
+ ```
106
+
107
+ * Delete message(s) with specified text
108
+
109
+ `-R | --regex`
110
+
111
+ ```ruby
112
+ # Delete all user messages with hello string in general channel
113
+ slack_neuralyzer -t <TOKEN> -m -C general -u all -R hello
114
+ ```
115
+
116
+ ### Delete file(s)
117
+
118
+ > File types: all, spaces, snippets, images, gdocs, docs, zips, pdfs
119
+
120
+ >Rerun below command and use `-e | --execute` to actually delete the message(s).
121
+
122
+ * Channel
123
+
124
+ `-C | --channel` `-D | --direct` `-G | --group` `-M | --mpdirect`
125
+
126
+ ```ruby
127
+ # Delete all user upload all type file in general channel
128
+ slack_neuralyzer -t <TOKEN> -f all -C general -u all
129
+
130
+ # Delete leon upload all images file in leon direct channel
131
+ slack_neuralyzer -t <TOKEN> -f images -D leon -u leon
132
+
133
+ # Delete all user upload all pdfs file in private_channel groups channel
134
+ slack_neuralyzer -t <TOKEN> -f pdfs -G private_channel -u all
135
+
136
+ # Delete all user upload all zips file in mpdm-leon--cleanerbot-1 multiparty direct channel
137
+ # (can `use slack_neuralyzer -t <TOKEN> -s` to see mpdirect channle name)
138
+ slack_neuralyzer -t <TOKEN> -f zips -M mpdm-leon--cleanerbot-1 -u all
139
+ ```
140
+
141
+ * Specific user and file type
142
+
143
+ `-u | --user` `-f | --file`
144
+
145
+ ```ruby
146
+ # Delete leon upload images file in general channel
147
+ slack_neuralyzer -t <TOKEN> -f images -C general -u leon
148
+ ```
149
+
150
+ * Delete file between two dates
151
+
152
+ `-A | --after` `-B | --before`
153
+
154
+ ```ruby
155
+ # Delete all user upload all type file in general channel at 20160101 to 20161212
156
+ slack_neuralyzer -t <TOKEN> -f all -C general -u all -A 20160101 -B 20161212
157
+ ```
158
+
159
+ ### Generate log file
160
+
161
+ `-l | --log`
162
+
163
+ ```ruby
164
+ # Generate a log file in the current directory in ./slack_neuralyzer/YYYY-MM-DDTHH:MM:SS
165
+ slack_neuralyzer -t <TOKEN> -m -C general -u all -A 20160101 -B 20161212 -l
166
+ ```
167
+
168
+
169
+ ### Rate
170
+
171
+ `-r | --rate`
172
+
173
+ ```ruby
174
+ # Delay between API calls in seconds (default:0.05)
175
+ slack_neuralyzer -t <TOKEN> -m -C general -u all -r 0.01
176
+ ```
177
+
178
+
179
+ ### Help
180
+
181
+ `-h | --help`
182
+
183
+ ```
184
+ usage:
185
+ slack_neuralyzer [options]
186
+ See https://github.com/mgleon08/slack_neuralyzer for more information.
187
+
188
+ options:
189
+ -t, --token TOKEN Slack API token (https://api.slack.com/web)
190
+ -s, --show Show all users, channels, groups and multiparty direct names
191
+ -m, --message Specifies that the delete object is messages
192
+ -f, --file TYPE Specifies that the delete object is files of a certain type (Type: all, spaces, snippets, images, gdocs, docs, zips, pdfs)
193
+ -C, --channel CHANNEL Public channel name (e.g., general, random)
194
+ -D, --direct DIRECT Direct messages channel name (e.g., leon)
195
+ -G, --group GROUP Private groups channel name
196
+ -M, --mpdirect MPDIRECT Multiparty direct messages channel name (e.g., mpdm-leon--bot-1 [--show option to see name])
197
+ -u, --user USER Delete messages/files from the specific user (if you want to specific all users, you can type 'all')
198
+ -b, --bot BOT Delete messages from the specific bot (not bot users, if you want to specific all bots, you can type 'all')
199
+ -A, --after DATE Delete messages/files after than this time (YYYYMMDD)
200
+ -B, --before DATE Delete messages/files before than this time (YYYYMMDD)
201
+ -R, --regex TEXT Delete messages with specified text (regular expression)
202
+ -e, --execute Execute the delete task
203
+ -l, --log Generate a log file in the current directory
204
+ -r, --rate RATE Delay between API calls in seconds (default:0.1)
205
+ -v, --version Show the SlackNeuralyzer version
206
+ -h, --help Show this message
207
+ ```
208
+
209
+ ## Contributing
210
+
211
+ Bug reports and pull requests are welcome on GitHub at [`https://github.com/mgleon08/slack_neuralyzer/pulls`](https://github.com/mgleon08/slack_neuralyzer/pulls)
212
+
213
+ ## Copyright & License
214
+
215
+ * Copyright (c) 2016 Leon Ji. See [LICENSE.txt](https://github.com/mgleon08/slack_neuralyzer/blob/master/LICENSE.txt) for further details.
216
+ * The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "slack_neuralyzer"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/slack_neuralyzer'
3
+
4
+ begin
5
+ args = SlackNeuralyzer::ArgsParser.new(ARGV)
6
+ logger = SlackNeuralyzer::Logger.default(args.log)
7
+ dict = SlackNeuralyzer::Dict.new(args.token)
8
+ cli = SlackNeuralyzer::Cli.new(args, dict, logger)
9
+ cli.run
10
+ rescue => e
11
+ $stderr.puts e.message
12
+ exit
13
+ end
@@ -0,0 +1,9 @@
1
+ module SlackApi
2
+ module Errors
3
+ class NotFoundError < StandardError
4
+ def initialize(message)
5
+ super("SlackAPI: #{message}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module SlackApi
2
+ module Errors
3
+ class ResponseError < StandardError
4
+ def initialize(message)
5
+ super("SlackAPI: #{message}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ require 'slack'
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+
3
+ require 'optparse'
4
+ require 'time'
5
+ require 'colorize'
6
+ require 'logger'
7
+
8
+ require 'slack_api/slack_api'
9
+ require 'slack_api/errors/not_found'
10
+ require 'slack_api/errors/response'
11
+
12
+ require 'slack_neuralyzer/logger'
13
+ require 'slack_neuralyzer/multi_io'
14
+
15
+ require 'slack_neuralyzer/helper'
16
+ require 'slack_neuralyzer/colorizable'
17
+ require 'slack_neuralyzer/args_parser'
18
+ require 'slack_neuralyzer/dict'
19
+ require 'slack_neuralyzer/cli'
20
+ require 'slack_neuralyzer/cleaner/base'
21
+ require 'slack_neuralyzer/cleaner/messages'
22
+ require 'slack_neuralyzer/cleaner/files'
23
+ require 'slack_neuralyzer/errors/mutually_exclusive_arguments'
24
+ require 'slack_neuralyzer/errors/required_arguments'
25
+
26
+ require 'slack_neuralyzer/version'
@@ -0,0 +1,98 @@
1
+ module SlackNeuralyzer
2
+ class ArgsParser
3
+ attr_accessor :token, :show, :message, :file, :channel, :direct,
4
+ :group, :mpdirect, :user, :bot, :after, :before,
5
+ :execute, :log, :rate, :regex
6
+
7
+ def initialize(args)
8
+ @args = args
9
+ init_arg_groups
10
+ parse_args
11
+ validates_mutex_args
12
+ validates_required_args
13
+ end
14
+
15
+ def init_arg_groups
16
+ @arg_groups = {
17
+ 'required': [
18
+ [:token],
19
+ [:message, :file],
20
+ [:channel, :direct, :group, :mpdirect],
21
+ [:user, :bot]
22
+ ],
23
+ 'mutex': [
24
+ [:message, :file],
25
+ [:channel, :direct, :group, :mpdirect],
26
+ [:file, :bot],
27
+ [:file, :regex]
28
+ ]
29
+ }
30
+ end
31
+
32
+ def rate_limit
33
+ rate || 0.05
34
+ end
35
+
36
+ private
37
+
38
+ def parse_args
39
+ opts = OptionParser.new
40
+ opts.banner = usage_msg
41
+ opts.separator ''
42
+ opts.separator 'options:'
43
+ opts.on('-t', '--token TOKEN', 'Slack API token (https://api.slack.com/web)') { |token| self.token = token }
44
+ opts.on('-s', '--show', 'Show all users, channels, groups and multiparty direct names') { self.show = true }
45
+
46
+ opts.on('-m', '--message', 'Specifies that the delete object is messages') { self.message = true }
47
+ opts.on('-f', '--file TYPE', "Specifies that the delete object is files of a certain type (Type: all, spaces, snippets, images, gdocs, docs, zips, pdfs)") { |file| self.file = file }
48
+
49
+ opts.on('-C', '--channel CHANNEL', 'Public channel name (e.g., general, random)') { |channel| self.channel = channel }
50
+ opts.on('-D', '--direct DIRECT', 'Direct messages channel name (e.g., leon)') { |direct| self.direct = direct }
51
+ opts.on('-G', '--group GROUP', 'Private groups channel name') { |group| self.group = group }
52
+ opts.on('-M', '--mpdirect MPDIRECT', 'Multiparty direct messages channel name (e.g., mpdm-leon--bot-1 [--show option to see name])') { |mpdirect| self.mpdirect = mpdirect }
53
+
54
+ opts.on('-u', '--user USER', "Delete messages/files from the specific user (if you want to specific all users, you can type 'all')") { |user| self.user = user }
55
+ opts.on('-b', '--bot BOT', "Delete messages from the specific bot (not bot users, if you want to specific all bots, you can type 'all')") { |bot| self.bot = bot }
56
+
57
+ opts.on('-A', '--after DATE', 'Delete messages/files after than this time (YYYYMMDD)') { |after| self.after = after }
58
+ opts.on('-B', '--before DATE', 'Delete messages/files before than this time (YYYYMMDD)') { |before| self.before = before }
59
+
60
+ opts.on('-R', '--regex TEXT', 'Delete messages with specified text (regular expression)') { |regex| self.regex = regex }
61
+
62
+ opts.on('-e', '--execute', 'Execute the delete task') { self.execute = true }
63
+ opts.on('-l', '--log', 'Generate a log file in the current directory') { self.log = true }
64
+ opts.on('-r', '--rate RATE', Float, 'Delay between API calls in seconds (default:0.1)') { |rate| self.rate = rate }
65
+ opts.on('-v', '--version', 'Show the SlackNeuralyzer version') { puts("slack_neuralyzer #{SlackNeuralyzer::VERSION}"); exit }
66
+ opts.on('-h', '--help', 'Show this message') { puts(opts); exit }
67
+ opts.parse!(@args)
68
+ end
69
+
70
+ def usage_msg
71
+ <<-USAGE.freeze
72
+ usage:
73
+ slack_neuralyzer [options]
74
+ See https://github.com/mgleon08/slack_neuralyzer for more information.
75
+ USAGE
76
+ end
77
+
78
+ def validates_required_args
79
+ @arg_groups[:required].each do |opts|
80
+ filters = opts.select{ |opt| !self.public_send(opt).nil? }
81
+ raise SlackNeuralyzer::Errors::RequiredArgumentsError.new(double_dash(opts).join(', ')) if filters.empty?
82
+ return unless self.show.nil?
83
+ end
84
+ end
85
+
86
+ def validates_mutex_args
87
+ @arg_groups[:mutex].each do |opts|
88
+ return unless self.show.nil?
89
+ filters = opts.select{ |opt| !self.public_send(opt).nil? }
90
+ raise SlackNeuralyzer::Errors::MutuallyExclusiveArgumentsError.new(double_dash(filters).join(', ')) if filters.size > 1
91
+ end
92
+ end
93
+
94
+ def double_dash(arrays)
95
+ arrays.map{ |array| array.to_s.prepend('--') }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,73 @@
1
+ module SlackNeuralyzer
2
+ module Cleaner
3
+ class Base
4
+ include Helper
5
+ include Colorizable
6
+ attr_reader :args, :dict, :channel_type, :logger
7
+
8
+ def initialize(args, dict, logger)
9
+ @args = args
10
+ @dict = dict
11
+ @logger = logger
12
+ reset_counter
13
+ parse_to_ts(args.after, args.before)
14
+ end
15
+
16
+ private
17
+
18
+ def get_user_id
19
+ user_id = args.user == 'all' ? -1 : dict.find_user_id(args.user)
20
+ raise SlackApi::Errors::NotFoundError, "#{args.user} not found." unless args.bot || user_id
21
+ user_id
22
+ end
23
+
24
+ def get_channel_id
25
+ if args.channel
26
+ @channel_type = 'channel'
27
+ channel_id = dict.find_channel_id(args.channel)
28
+ elsif args.direct
29
+ @channel_type = 'direct'
30
+ user_id = dict.find_user_id(args.direct)
31
+ channel_id = dict.find_im_id(user_id)
32
+ elsif args.group
33
+ @channel_type = 'group'
34
+ channel_id = dict.find_group_id(args.group)
35
+ elsif args.mpdirect
36
+ @channel_type = 'mpdirect'
37
+ channel_id = dict.find_mpim_id(args.mpdirect)
38
+ end
39
+ raise SlackApi::Errors::NotFoundError, "#{current_channel} not found." unless channel_id
40
+ channel_id
41
+ end
42
+
43
+ def current_channel
44
+ light_green("#{args.public_send(channel_type)} #{channel_type}")
45
+ end
46
+
47
+ def time_format(time)
48
+ light_cyan("[#{parse_to_date(time)}]")
49
+ end
50
+
51
+ def delete_format
52
+ args.execute ? '(delete) '.light_red : ''
53
+ end
54
+
55
+ def not_have_any(type)
56
+ logger.info "#{current_channel} does not have any #{type}(s)"
57
+ exit
58
+ end
59
+
60
+ def finish_text(type)
61
+ text = "\n#{light_green(counter)} #{type}(s) in #{current_channel} "
62
+ if args.execute.nil? && counter.nonzero?
63
+ text << 'will be deleted.'
64
+ text << light_red("\nNow, you can rerun the command and use `-e | --execute` to actually delete the #{type}(s).")
65
+ else
66
+ text << 'have been deleted.'
67
+ end
68
+ text << light_blue("\nThe log file has been generated in the current directory") if args.log
69
+ text
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,41 @@
1
+ module SlackNeuralyzer
2
+ module Cleaner
3
+ class Files < Base
4
+ def clean
5
+ user_id = get_user_id
6
+ channel_id = get_channel_id
7
+ clean_channel_file(channel_id, user_id)
8
+ end
9
+
10
+ private
11
+
12
+ def clean_channel_file(channel_id, user_id)
13
+ page, total_page = 0, nil
14
+ until page == total_page
15
+ page += 1
16
+ res = Slack.files_list(page: page, channel: channel_id, types: args.file, ts_from: start_time, ts_to: end_time)
17
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
18
+ total_page = res['paging']['pages']
19
+ not_have_any('file') if total_page.zero?
20
+ res['files'].each do |file|
21
+ if args.user && (file['user'] == user_id || user_id == -1)
22
+ delete_file(file)
23
+ end
24
+ end
25
+ end
26
+
27
+ logger.info finish_text('file')
28
+ end
29
+
30
+ def delete_file(file)
31
+ file_time = time_format(file['timestamp'])
32
+ file_url = light_magenta("(#{file['permalink']})")
33
+ delete = delete_format
34
+ Slack.files_delete(file: file['id']) if args.execute
35
+ logger.info "#{delete}#{file_time} #{dict.find_user_name(file['user'])}: #{file['name']} #{file_url}"
36
+ increase_counter
37
+ sleep(args.rate_limit)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,83 @@
1
+ module SlackNeuralyzer
2
+ module Cleaner
3
+ class Messages < Base
4
+ def clean
5
+ user_id = get_user_id
6
+ channel_id = get_channel_id
7
+ end_point = get_history_end_point
8
+ clean_channel_messages(channel_id, user_id, end_point)
9
+ end
10
+
11
+ private
12
+
13
+ def clean_channel_messages(channel_id, user_id, end_point)
14
+ has_more = true
15
+
16
+ while has_more
17
+ res = Slack.public_send(end_point, channel: channel_id, oldest: start_time, latest: end_time)
18
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
19
+ has_more = res['has_more']
20
+ messages = res['messages']
21
+ not_have_any('message') if messages.empty?
22
+
23
+ messages.each do |msg|
24
+ @end_time = msg['ts']
25
+ dict.scan_user_id_to_transform(msg['text'])
26
+ next unless msg['type'] == 'message'
27
+ next if args.regex && !match_regex(msg['text'])
28
+
29
+ if args.user && user_msg?(msg, user_id)
30
+ name = dict.find_user_name(msg['user'])
31
+ delete_message(channel_id, msg, name)
32
+ end
33
+
34
+ next unless args.bot && bot_msg?(msg)
35
+
36
+ name = dict.find_bot_name(msg['bot_id'])
37
+ if args.bot == name || args.bot == 'all'
38
+ delete_message(channel_id, msg, name)
39
+ end
40
+ end
41
+ end
42
+
43
+ logger.info finish_text('message')
44
+ end
45
+
46
+ def user_msg?(msg, user_id)
47
+ !bot_msg?(msg) && (msg['user'] == user_id || user_id == -1)
48
+ end
49
+
50
+ def bot_msg?(msg)
51
+ msg['subtype'] == 'bot_message'
52
+ end
53
+
54
+ def delete_message(channel_id, msg, name)
55
+ Slack.chat_delete(channel: channel_id, ts: msg['ts']) if args.execute
56
+ logger.info "#{delete_format}#{time_format(msg['ts'])} #{name}: #{msg['text']}"
57
+ increase_counter
58
+ sleep(args.rate_limit)
59
+ end
60
+
61
+ def get_history_end_point
62
+ if args.channel
63
+ :channels_history
64
+ elsif args.direct
65
+ :im_history
66
+ elsif args.group
67
+ :groups_history
68
+ elsif args.mpdirect
69
+ :mpim_history
70
+ end
71
+ end
72
+
73
+ def match_regex(text)
74
+ match_word = text.scan(/#{args.regex}/).flatten
75
+ return false if match_word.empty?
76
+ match_word.uniq.each do |word|
77
+ text.gsub!(/#{word}/, light_magenta(word.to_s))
78
+ end
79
+ text
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,23 @@
1
+ module SlackNeuralyzer
2
+ class Cli
3
+ attr_reader :args, :dict, :logger
4
+
5
+ def initialize(args, dict, logger)
6
+ @args = args
7
+ @dict = dict
8
+ @logger = logger
9
+ end
10
+
11
+ def run
12
+ logger.info "Running slack_neuralyzer v#{SlackNeuralyzer::VERSION}\n"
13
+ sleep(1)
14
+ if args.show
15
+ puts dict.show_all_channels
16
+ elsif args.message
17
+ Cleaner::Messages.new(args, dict, logger).clean
18
+ elsif args.file
19
+ Cleaner::Files.new(args, dict, logger).clean
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module SlackNeuralyzer
2
+ module Colorizable
3
+ [
4
+ :light_green,
5
+ :light_cyan,
6
+ :light_red,
7
+ :light_blue,
8
+ :light_yellow,
9
+ :light_magenta
10
+ ].each do |color|
11
+ define_method(color) do |text|
12
+ text.to_s.public_send(color)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,118 @@
1
+ module SlackNeuralyzer
2
+ class Dict
3
+ include Colorizable
4
+ attr_reader :channels, :ims, :groups, :mpims, :users, :bots
5
+
6
+ def initialize(token)
7
+ Slack.token = token
8
+ @users = {}
9
+ @channels = {}
10
+ @groups = {}
11
+ @ims = {}
12
+ @mpims = {}
13
+ @bots = {}
14
+ init_all_dict
15
+ end
16
+
17
+ def show_all_channels
18
+ text = ''
19
+ text << light_blue("All user direct:\n")
20
+ text << list_names(users)
21
+ text << light_blue("\nAll channels (public):\n")
22
+ text << list_names(channels)
23
+ text << light_blue("\nAll groups (private):\n")
24
+ text << list_names(groups)
25
+ text << light_blue("\nAll multiparty direct:\n")
26
+ text << list_names(mpims)
27
+ end
28
+
29
+ [:channel, :im, :group, :mpim, :user].each do |channel|
30
+ define_method("find_#{channel}_id".to_sym) do |name|
31
+ public_send("#{channel}s").key(name)
32
+ end
33
+
34
+ define_method("find_#{channel}_name".to_sym) do |name|
35
+ public_send("#{channel}s").invert.key(name)
36
+ end
37
+ end
38
+
39
+ def scan_user_id_to_transform(text)
40
+ return text if text.nil?
41
+ scan_id = text.scan(/<@(?<bot>[[:alnum:][:punct:]]*)>/i).flatten
42
+ if scan_id.any?
43
+ scan_id.uniq.each do |id|
44
+ name = find_user_name(id)
45
+ text.gsub!(/<@#{id}>/, light_yellow("@#{name}"))
46
+ end
47
+ end
48
+ text
49
+ end
50
+
51
+ def find_bot_name(bot_id)
52
+ build_bot_name(bot_id) unless bots.invert.key(bot_id)
53
+ bots.invert.key(bot_id)
54
+ end
55
+
56
+ def build_bot_name(bot_id)
57
+ res = Slack.bots_info(bot: bot_id)
58
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
59
+ @bots[bot_id] = res['bot']['name']
60
+ end
61
+
62
+ private
63
+
64
+ def init_all_dict
65
+ init_users_dict
66
+ init_channels_dict
67
+ init_groups_dict
68
+ init_ims_dict
69
+ init_mpims_dict
70
+ end
71
+
72
+ def init_users_dict
73
+ res = Slack.users_list
74
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
75
+ members = res['members']
76
+ members.each { |member| @users[member['id']] = member['name'] }
77
+ end
78
+
79
+ def init_channels_dict
80
+ res = Slack.channels_list
81
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
82
+ channels = res['channels']
83
+ channels.each { |channel| @channels[channel['id']] = channel['name'] }
84
+ end
85
+
86
+ def init_groups_dict
87
+ res = Slack.groups_list
88
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
89
+ groups = res['groups']
90
+ groups.each do |group|
91
+ next if group['is_mpim'] != false
92
+ @groups[group['id']] = group['name']
93
+ end
94
+ end
95
+
96
+ def init_ims_dict
97
+ res = Slack.im_list
98
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
99
+ ims = res['ims']
100
+ ims.each { |im| @ims[im['id']] = im['user'] }
101
+ end
102
+
103
+ def init_mpims_dict
104
+ res = Slack.mpim_list
105
+ raise SlackApi::Errors::ResponseError, res['error'] unless res['ok']
106
+ mpims = res['groups']
107
+ mpims.each { |mpim| @mpims[mpim['id']] = mpim['name'] }
108
+ end
109
+
110
+ def list_names(names)
111
+ ''.tap do |text|
112
+ names.values.each.with_index(1) do |name, index|
113
+ text << " #{index.to_s.rjust(3, '0')}. #{name}\n"
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,9 @@
1
+ module SlackNeuralyzer
2
+ module Errors
3
+ class MutuallyExclusiveArgumentsError < StandardError
4
+ def initialize(message)
5
+ super("These arguments can not be required together: #{message}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module SlackNeuralyzer
2
+ module Errors
3
+ class RequiredArgumentsError < StandardError
4
+ def initialize(message)
5
+ super("Must required one of these arguments: #{message}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module SlackNeuralyzer
2
+ module Helper
3
+ attr_reader :counter, :start_time, :end_time
4
+
5
+ def parse_to_ts(start_time, end_time)
6
+ end_time ||= Time.now.to_s
7
+ @start_time = Time.parse(start_time).to_f if start_time
8
+ @end_time = Time.parse(end_time).to_f
9
+ end
10
+
11
+ def parse_to_date(ts)
12
+ Time.at(ts.to_f).strftime('%Y-%m-%d %H:%M')
13
+ end
14
+
15
+ def reset_counter
16
+ @counter = 0
17
+ end
18
+
19
+ def increase_counter
20
+ @counter += 1
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module SlackNeuralyzer
2
+ class Logger < ::Logger
3
+ class << self
4
+ def default(log)
5
+ io = [STDOUT]
6
+ io << log_file if log
7
+ logger = Logger.new(MultiIO.new(*io))
8
+ logger.level = Logger::INFO
9
+ logger.formatter = proc do |_severity, _datetime, _progname, msg|
10
+ "#{msg}\n"
11
+ end
12
+ logger
13
+ end
14
+
15
+ def log_file
16
+ time = Time.now.strftime('%Y-%m-%dT%H:%M:%S')
17
+ FileUtils.mkdir_p('./slack_neuralyzer')
18
+ log_file = File.open("./slack_neuralyzer/#{time}.log", 'a')
19
+ log_file
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ module SlackNeuralyzer
2
+ class MultiIO
3
+ def initialize(*targets)
4
+ @targets = targets
5
+ @shell_colors = {
6
+ light_red: '\\e\\[0;91;49m',
7
+ light_green: '\\e\\[0;92;49m',
8
+ light_yellow: '\\e\\[0;93;49m',
9
+ light_blue: '\\e\\[0;94;49m',
10
+ light_magenta: '\\e\\[0;95;49m',
11
+ light_cyan: '\\e\\[0;96;49m',
12
+ out_put: '\\e\\[0m'
13
+ }
14
+ end
15
+
16
+ def write(args)
17
+ @targets.each do |target|
18
+ pretty_file_text(args) if target.is_a? File
19
+ target.write(args)
20
+ end
21
+ end
22
+
23
+ def close
24
+ @targets.each(&:close)
25
+ end
26
+
27
+ def pretty_file_text(args)
28
+ @shell_colors.values.each do |color|
29
+ args.gsub!(/#{color}/, '')
30
+ end
31
+ args
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module SlackNeuralyzer
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'slack_neuralyzer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "slack_neuralyzer"
8
+ spec.version = SlackNeuralyzer::VERSION
9
+ spec.authors = ["Leon Ji"]
10
+ spec.email = ["mgleon08@gmail.com"]
11
+
12
+ spec.summary = %q{The easiest way to clean up messages and files on Slack.}
13
+ spec.description = %q{This is a ruby gem for bulk delete messages and files on Slack channels.}
14
+ spec.homepage = "https://github.com/mgleon08/slack_neuralyzer"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.require_paths = ["lib"]
20
+ spec.executables = ["slack_neuralyzer"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "coveralls", "~> 0.8.1"
26
+ spec.add_runtime_dependency "slack-api", "~> 1.2"
27
+ spec.add_runtime_dependency "colorize", "~> 0.8"
28
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slack_neuralyzer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Leon Ji
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: coveralls
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.8.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.8.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: slack-api
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: colorize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.8'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.8'
97
+ description: This is a ruby gem for bulk delete messages and files on Slack channels.
98
+ email:
99
+ - mgleon08@gmail.com
100
+ executables:
101
+ - slack_neuralyzer
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".codeclimate.yml"
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - ".travis.yml"
109
+ - Gemfile
110
+ - LICENSE.txt
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - bin/slack_neuralyzer
116
+ - lib/slack_api/errors/not_found.rb
117
+ - lib/slack_api/errors/response.rb
118
+ - lib/slack_api/slack_api.rb
119
+ - lib/slack_neuralyzer.rb
120
+ - lib/slack_neuralyzer/args_parser.rb
121
+ - lib/slack_neuralyzer/cleaner/base.rb
122
+ - lib/slack_neuralyzer/cleaner/files.rb
123
+ - lib/slack_neuralyzer/cleaner/messages.rb
124
+ - lib/slack_neuralyzer/cli.rb
125
+ - lib/slack_neuralyzer/colorizable.rb
126
+ - lib/slack_neuralyzer/dict.rb
127
+ - lib/slack_neuralyzer/errors/mutually_exclusive_arguments.rb
128
+ - lib/slack_neuralyzer/errors/required_arguments.rb
129
+ - lib/slack_neuralyzer/helper.rb
130
+ - lib/slack_neuralyzer/logger.rb
131
+ - lib/slack_neuralyzer/multi_io.rb
132
+ - lib/slack_neuralyzer/version.rb
133
+ - screenshots/general_test_token.png
134
+ - screenshots/neuralyzer.gif
135
+ - screenshots/slack_neuralyzer_demo.gif
136
+ - slack_neuralyzer.gemspec
137
+ homepage: https://github.com/mgleon08/slack_neuralyzer
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.4.8
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: The easiest way to clean up messages and files on Slack.
161
+ test_files: []