brutalismbot 0.6.1 → 1.0.0.beta.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/lib/brutalismbot/base.rb +21 -0
- data/lib/brutalismbot/client.rb +46 -0
- data/lib/brutalismbot/logger.rb +16 -0
- data/lib/brutalismbot/posts/client.rb +58 -0
- data/lib/brutalismbot/posts/stub.rb +28 -0
- data/lib/brutalismbot/reddit/client.rb +24 -0
- data/lib/brutalismbot/reddit/post.rb +111 -0
- data/lib/brutalismbot/reddit/resource.rb +42 -0
- data/lib/brutalismbot/reddit/stub.rb +43 -0
- data/lib/brutalismbot/s3/client.rb +24 -0
- data/lib/brutalismbot/s3/prefix.rb +31 -0
- data/lib/brutalismbot/slack/auth.rb +44 -0
- data/lib/brutalismbot/slack/client.rb +49 -0
- data/lib/brutalismbot/slack/stub.rb +56 -0
- data/lib/brutalismbot/stub.rb +19 -0
- data/lib/brutalismbot/twitter/client.rb +37 -0
- data/lib/brutalismbot/version.rb +1 -1
- data/lib/brutalismbot.rb +3 -30
- metadata +48 -8
- data/lib/brutalismbot/auth.rb +0 -57
- data/lib/brutalismbot/post.rb +0 -102
- data/lib/brutalismbot/r.rb +0 -54
- data/lib/brutalismbot/s3.rb +0 -181
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bebc26a610a2e90743db822c2915c0a5d66a1f1137b9f96013af498e3a8754a1
|
4
|
+
data.tar.gz: a82a2358a5171bc37ff84fdee8535c4136ddf2a47e4a902f789bbad1d3fe4a67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9d9b9da0b23ae47ca6f4e4263064d5e8560c714b75dd3eaafce89503106408f6fc8273dc82628f3adc53eaf9527c92bf5e7e6e2c3b9eae60dab537d1336b166
|
7
|
+
data.tar.gz: 2a6035ffe8aa7836314bc3141cc6135e135f19af3c858f3c3477819467140bc6fd8e3c48ad42b7c49d02069baadc82290176b96713054e5963606fb3b7c3b4e3
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Brutalismbot
|
5
|
+
module Parser
|
6
|
+
def parse(source, opts = {})
|
7
|
+
new JSON.parse(source, opts)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Base
|
12
|
+
extend Forwardable
|
13
|
+
extend Parser
|
14
|
+
|
15
|
+
def_delegators :@item, :[], :dig, :fetch, :to_h, :to_json
|
16
|
+
|
17
|
+
def initialize(item = {})
|
18
|
+
@item = JSON.parse(item.to_json)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "brutalismbot/posts/client"
|
2
|
+
require "brutalismbot/reddit/client"
|
3
|
+
require "brutalismbot/slack/client"
|
4
|
+
require "brutalismbot/twitter/client"
|
5
|
+
|
6
|
+
module Brutalismbot
|
7
|
+
class Client
|
8
|
+
attr_reader :posts, :reddit, :slack, :twitter
|
9
|
+
|
10
|
+
def initialize(posts:nil, reddit:nil, slack:nil, twitter:nil)
|
11
|
+
@posts = posts || Posts::Client.new
|
12
|
+
@reddit = reddit || Reddit::Client.new
|
13
|
+
@slack = slack || Slack::Client.new
|
14
|
+
@twitter = twitter || Twitter::Client.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def lag_time
|
18
|
+
lag = ENV["BRUTALISMBOT_LAG_TIME"].to_s
|
19
|
+
lag.empty? ? 7200 : lag.to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
def pull(min_time:nil, max_time:nil, dryrun:nil)
|
23
|
+
# Get time window for new posts
|
24
|
+
min_time ||= @posts.max_time
|
25
|
+
max_time ||= Time.now.utc.to_i - lag_time
|
26
|
+
|
27
|
+
# Get posts
|
28
|
+
posts = @reddit.list(:new)
|
29
|
+
posts = posts.select{|post| post.created_between?(min_time, max_time) }
|
30
|
+
posts = posts.sort{|a,b| a.created_utc <=> b.created_utc }
|
31
|
+
|
32
|
+
# Persist posts
|
33
|
+
posts.each{|post| @posts.push(post, dryrun: dryrun) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def push(post, dryrun:nil)
|
37
|
+
# Push to Twitter
|
38
|
+
@twitter.push(post, dryrun: dryrun)
|
39
|
+
|
40
|
+
# Push to Slack
|
41
|
+
@slack.push(post, dryrun: dryrun)
|
42
|
+
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Brutalismbot
|
4
|
+
module Logger
|
5
|
+
def logger
|
6
|
+
# @@logger ||= ::Logger.new(File::NULL)
|
7
|
+
@@logger ||= ::Logger.new(STDOUT, formatter: -> (*x) { "#{x.last}\n" })
|
8
|
+
end
|
9
|
+
|
10
|
+
def logger=(logger)
|
11
|
+
@@logger = logger
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
extend Logger
|
16
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "aws-sdk-s3"
|
2
|
+
|
3
|
+
require "brutalismbot/logger"
|
4
|
+
require "brutalismbot/s3/client"
|
5
|
+
require "brutalismbot/s3/prefix"
|
6
|
+
require "brutalismbot/reddit/post"
|
7
|
+
|
8
|
+
module Brutalismbot
|
9
|
+
module Posts
|
10
|
+
class Client < S3::Client
|
11
|
+
def initialize(bucket:nil, prefix:nil, client:nil)
|
12
|
+
bucket ||= ENV["POSTS_S3_BUCKET"] || "brutalismbot"
|
13
|
+
prefix ||= ENV["POSTS_S3_PREFIX"] || "data/v1/posts/"
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def key_for(post)
|
18
|
+
File.join(@prefix, post.path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def last
|
22
|
+
Reddit::Post.parse(max_key.get.body.read)
|
23
|
+
end
|
24
|
+
|
25
|
+
def list(options = {})
|
26
|
+
super(options) do |object|
|
27
|
+
Brutalismbot.logger.info("GET s3://#{@bucket.name}/#{object.key}")
|
28
|
+
Reddit::Post.parse(object.get.body.read)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def max_key
|
33
|
+
# Dig for max key
|
34
|
+
prefix = Time.now.utc.strftime("#{@prefix}year=%Y/month=%Y-%m/day=%Y-%m-%d/")
|
35
|
+
Brutalismbot.logger.info("GET s3://#{@bucket.name}/#{prefix}*")
|
36
|
+
|
37
|
+
# Go up a level in prefix if no keys found
|
38
|
+
until (keys = @bucket.objects(prefix: prefix)).any?
|
39
|
+
prefix = prefix.split(/[^\/]+\/\z/).first
|
40
|
+
Brutalismbot.logger.info("GET s3://#{@bucket.name}/#{prefix}*")
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return max by key
|
44
|
+
keys.max{|a,b| a.key <=> b.key }
|
45
|
+
end
|
46
|
+
|
47
|
+
def max_time
|
48
|
+
max_key.key[/(\d+).json\z/, -1].to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
def push(post, dryrun:nil)
|
52
|
+
key = key_for(post)
|
53
|
+
Brutalismbot.logger.info("PUT #{"DRYRUN " if dryrun}s3://#{@bucket.name}/#{key}")
|
54
|
+
@bucket.put_object(key: key, body: post.to_json) unless dryrun
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "brutalismbot/reddit/post"
|
2
|
+
|
3
|
+
module Brutalismbot
|
4
|
+
module Posts
|
5
|
+
class Client
|
6
|
+
class << self
|
7
|
+
def stub(&block)
|
8
|
+
client = new(prefix: "data/test/posts/")
|
9
|
+
client.instance_variable_set(:@stubbed, true)
|
10
|
+
|
11
|
+
block = -> { [Reddit::Post.stub] } unless block_given?
|
12
|
+
items = block.call.map{|x| [client.key_for(x), x.to_h] }.to_h
|
13
|
+
|
14
|
+
client.client.stub_responses :list_objects, -> (context) do
|
15
|
+
keys = items.keys.select{|x| x.start_with? context.params[:prefix] }
|
16
|
+
{contents: keys.map{|x| {key:x} }}
|
17
|
+
end
|
18
|
+
|
19
|
+
client.client.stub_responses :get_object, -> (context) do
|
20
|
+
{body: StringIO.new(items.fetch(context.params[:key]).to_json)}
|
21
|
+
end
|
22
|
+
|
23
|
+
client
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "aws-sdk-s3"
|
2
|
+
|
3
|
+
require "brutalismbot/version"
|
4
|
+
require "brutalismbot/reddit/resource"
|
5
|
+
|
6
|
+
module Brutalismbot
|
7
|
+
module Reddit
|
8
|
+
class Client
|
9
|
+
attr_reader :endpoint, :user_agent
|
10
|
+
|
11
|
+
def initialize(endpoint:nil, user_agent:nil)
|
12
|
+
@endpoint = endpoint || ENV["REDDIT_ENDPOINT"] || "https://www.reddit.com/r/brutalism"
|
13
|
+
@user_agent = user_agent || ENV["REDDIT_USER_AGENT"] || "Brutalismbot v#{Brutalismbot::VERSION}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def list(resource, options = {})
|
17
|
+
url = File.join(@endpoint, "#{resource}.json")
|
18
|
+
qry = URI.encode_www_form(options)
|
19
|
+
uri = "#{url}?#{qry}"
|
20
|
+
Resource.new(uri: uri, user_agent: @user_agent)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
require "brutalismbot/base"
|
5
|
+
|
6
|
+
module Brutalismbot
|
7
|
+
module Reddit
|
8
|
+
class Post < Base
|
9
|
+
def created_after?(time = nil)
|
10
|
+
time.nil? || created_utc.to_i > time.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def created_before?(time = nil)
|
14
|
+
time.nil? || created_utc.to_i < time.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def created_between?(start, stop)
|
18
|
+
created_after?(start) && created_before?(stop)
|
19
|
+
end
|
20
|
+
|
21
|
+
def created_utc
|
22
|
+
Time.at(data["created_utc"].to_i).utc
|
23
|
+
end
|
24
|
+
|
25
|
+
def fullname
|
26
|
+
"#{kind}_#{id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def data
|
30
|
+
@item.fetch("data", {})
|
31
|
+
end
|
32
|
+
|
33
|
+
def id
|
34
|
+
data["id"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def kind
|
38
|
+
@item["kind"]
|
39
|
+
end
|
40
|
+
|
41
|
+
def path
|
42
|
+
created_utc.strftime("year=%Y/month=%Y-%m/day=%Y-%m-%d/%s.json")
|
43
|
+
end
|
44
|
+
|
45
|
+
def permalink
|
46
|
+
"https://reddit.com#{data["permalink"]}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def title
|
50
|
+
CGI.unescapeHTML(data["title"])
|
51
|
+
end
|
52
|
+
|
53
|
+
def url
|
54
|
+
images = data.dig("preview", "images") || {}
|
55
|
+
source = images.map{|x| x["source"] }.compact.max do |a,b|
|
56
|
+
a.slice("width", "height").values <=> b.slice("width", "height").values
|
57
|
+
end
|
58
|
+
CGI.unescapeHTML(source.dig("url"))
|
59
|
+
rescue NoMethodError
|
60
|
+
data["media_metadata"]&.values&.first&.dig("s", "u")
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_slack
|
64
|
+
{
|
65
|
+
blocks: unless url.nil?
|
66
|
+
[
|
67
|
+
{
|
68
|
+
type: "image",
|
69
|
+
title: {
|
70
|
+
type: "plain_text",
|
71
|
+
text: "/r/brutalism",
|
72
|
+
emoji: true,
|
73
|
+
},
|
74
|
+
image_url: url,
|
75
|
+
alt_text: title,
|
76
|
+
},
|
77
|
+
{
|
78
|
+
type: "context",
|
79
|
+
elements: [
|
80
|
+
{
|
81
|
+
type: "mrkdwn",
|
82
|
+
text: "<#{permalink}|#{title}>",
|
83
|
+
},
|
84
|
+
],
|
85
|
+
},
|
86
|
+
]
|
87
|
+
else
|
88
|
+
[
|
89
|
+
{
|
90
|
+
type: "section",
|
91
|
+
text: {
|
92
|
+
type: "mrkdwn",
|
93
|
+
text: "<#{permalink}|#{title}>",
|
94
|
+
},
|
95
|
+
accessory: {
|
96
|
+
type: "image",
|
97
|
+
image_url: "https://brutalismbot.com/logo-red-ppl.png",
|
98
|
+
alt_text: "/r/brutalism"
|
99
|
+
}
|
100
|
+
}
|
101
|
+
]
|
102
|
+
end
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_twitter
|
107
|
+
[title, permalink].join("\n")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "net/http"
|
2
|
+
|
3
|
+
require "brutalismbot/logger"
|
4
|
+
require "brutalismbot/reddit/post"
|
5
|
+
|
6
|
+
module Brutalismbot
|
7
|
+
module Reddit
|
8
|
+
class Resource
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
attr_reader :uri, :user_agent
|
12
|
+
|
13
|
+
def initialize(uri:nil, user_agent:nil)
|
14
|
+
@uri = uri || "https://www.reddit.com/r/brutalism/new.json"
|
15
|
+
@user_agent = user_agent || "Brutalismbot v#{Brutalismbot::VERSION}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def each
|
19
|
+
Brutalismbot.logger.info("GET #{@uri}")
|
20
|
+
uri = URI.parse(@uri)
|
21
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
|
22
|
+
request = Net::HTTP::Get.new(uri, "user-agent" => @user_agent)
|
23
|
+
response = JSON.parse(http.request(request).body)
|
24
|
+
children = response.dig("data", "children") || []
|
25
|
+
children.each do |child|
|
26
|
+
post = Post.new(child)
|
27
|
+
Brutalismbot.logger.warn("NO PHOTO URL for #{post.permalink}") if post.url.nil?
|
28
|
+
yield post
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def all
|
34
|
+
to_a
|
35
|
+
end
|
36
|
+
|
37
|
+
def last
|
38
|
+
to_a.last
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module Brutalismbot
|
4
|
+
module Reddit
|
5
|
+
class Post
|
6
|
+
class << self
|
7
|
+
def stub(created_utc:nil, post_id:nil, permalink_id:nil, image_id:nil)
|
8
|
+
created_utc ||= Time.now.utc - rand(86400) - 86400
|
9
|
+
post_id ||= SecureRandom.alphanumeric(6).downcase
|
10
|
+
permalink_id ||= SecureRandom.alphanumeric.downcase
|
11
|
+
image_id ||= SecureRandom.alphanumeric
|
12
|
+
new(
|
13
|
+
kind: "t3",
|
14
|
+
data: {
|
15
|
+
id: post_id,
|
16
|
+
created_utc: created_utc.to_i,
|
17
|
+
permalink: "/r/brutalism/comments/#{permalink_id}/test/",
|
18
|
+
title: "Post to /r/brutalism",
|
19
|
+
preview: {
|
20
|
+
images: [
|
21
|
+
{
|
22
|
+
source: {
|
23
|
+
url: "https://preview.redd.it/#{image_id}.jpg",
|
24
|
+
width: 1000,
|
25
|
+
height: 1000,
|
26
|
+
},
|
27
|
+
},
|
28
|
+
{
|
29
|
+
source: {
|
30
|
+
url: "https://preview.redd.it/small.jpg",
|
31
|
+
width: 500,
|
32
|
+
height: 500,
|
33
|
+
}
|
34
|
+
}
|
35
|
+
],
|
36
|
+
},
|
37
|
+
},
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "aws-sdk-s3"
|
2
|
+
|
3
|
+
module Brutalismbot
|
4
|
+
module S3
|
5
|
+
class Client
|
6
|
+
attr_reader :bucket, :prefix, :client
|
7
|
+
|
8
|
+
def initialize(bucket:nil, prefix:nil, client:nil)
|
9
|
+
bucket ||= ENV["S3_BUCKET"] || "brutalismbot"
|
10
|
+
prefix ||= ENV["S3_PREFIX"] || "data/v1/"
|
11
|
+
client ||= Aws::S3::Client.new
|
12
|
+
@bucket = Aws::S3::Bucket.new(name: bucket, client: client)
|
13
|
+
@client = client
|
14
|
+
@prefix = prefix
|
15
|
+
end
|
16
|
+
|
17
|
+
def list(options = {}, &block)
|
18
|
+
Brutalismbot.logger.info("LIST s3://#{@bucket.name}/#{@prefix}*")
|
19
|
+
prefix = @bucket.objects({prefix: @prefix}.merge(options))
|
20
|
+
Prefix.new(prefix, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "aws-sdk-s3"
|
2
|
+
|
3
|
+
require "brutalismbot/logger"
|
4
|
+
require "brutalismbot/s3/client"
|
5
|
+
|
6
|
+
module Brutalismbot
|
7
|
+
module S3
|
8
|
+
class Prefix
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def initialize(prefix, &block)
|
12
|
+
@prefix = prefix
|
13
|
+
@block = block if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def each
|
17
|
+
@prefix.each do |object|
|
18
|
+
yield @block.nil? ? object : @block.call(object)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def all
|
23
|
+
to_a
|
24
|
+
end
|
25
|
+
|
26
|
+
def last
|
27
|
+
to_a.last
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "json"
|
3
|
+
require "net/http"
|
4
|
+
|
5
|
+
require "brutalismbot/logger"
|
6
|
+
require "brutalismbot/base"
|
7
|
+
|
8
|
+
module Brutalismbot
|
9
|
+
module Slack
|
10
|
+
class Auth < Base
|
11
|
+
def channel_id
|
12
|
+
@item.dig("incoming_webhook", "channel_id")
|
13
|
+
end
|
14
|
+
|
15
|
+
def team_id
|
16
|
+
@item.dig("team_id")
|
17
|
+
end
|
18
|
+
|
19
|
+
def webhook_url
|
20
|
+
@item.dig("incoming_webhook", "url")
|
21
|
+
end
|
22
|
+
|
23
|
+
def path
|
24
|
+
File.join("team=#{team_id}", "channel=#{channel_id}", "oauth.json")
|
25
|
+
end
|
26
|
+
|
27
|
+
def push(post, dryrun:nil)
|
28
|
+
body = post.to_slack.to_json
|
29
|
+
uri = URI.parse(webhook_url)
|
30
|
+
Brutalismbot.logger.info("POST #{"DRYRUN " if dryrun}#{uri}")
|
31
|
+
unless dryrun
|
32
|
+
ssl = uri.scheme == "https"
|
33
|
+
req = Net::HTTP::Post.new(uri, "content-type" => "application/json")
|
34
|
+
req.body = body
|
35
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: ssl) do |http|
|
36
|
+
http.request(req)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
Net::HTTPOK.new("1.1", "204", "ok")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "aws-sdk-s3"
|
2
|
+
|
3
|
+
require "brutalismbot/logger"
|
4
|
+
require "brutalismbot/s3/client"
|
5
|
+
require "brutalismbot/s3/prefix"
|
6
|
+
require "brutalismbot/slack/auth"
|
7
|
+
|
8
|
+
module Brutalismbot
|
9
|
+
module Slack
|
10
|
+
class Client < S3::Client
|
11
|
+
def initialize(bucket:nil, prefix:nil, client:nil)
|
12
|
+
bucket ||= ENV["SLACK_S3_BUCKET"] || "brutalismbot"
|
13
|
+
prefix ||= ENV["SLACK_S3_PREFIX"] || "data/v1/auths/"
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def install(auth, dryrun:nil)
|
18
|
+
key = key_for(auth)
|
19
|
+
Brutalismbot.logger.info("PUT #{"DRYRUN " if dryrun}s3://#{@bucket.name}/#{key}")
|
20
|
+
@bucket.put_object(key: key, body: auth.to_json) unless dryrun
|
21
|
+
end
|
22
|
+
|
23
|
+
def key_for(auth)
|
24
|
+
File.join(@prefix, auth.path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def list(options = {})
|
28
|
+
super(options) do |object|
|
29
|
+
Brutalismbot.logger.info("GET s3://#{@bucket.name}/#{object.key}")
|
30
|
+
Auth.parse(object.get.body.read)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def push(post, dryrun:nil)
|
35
|
+
list.map do |auth|
|
36
|
+
key = key_for(auth)
|
37
|
+
Brutalismbot.logger.info("PUSH #{"DRYRUN " if dryrun}s3://#{@bucket.name}/#{key}")
|
38
|
+
auth.push(post, dryrun: dryrun)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def uninstall(auth, dryrun:nil)
|
43
|
+
key = key_for(auth)
|
44
|
+
Brutalismbot.logger.info("DELETE #{"DRYRUN " if dryrun}s3://#{@bucket.name}/#{key}")
|
45
|
+
@bucket.delete_objects(delete: {objects: [{key: key}]}) unless dryrun
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module Brutalismbot
|
4
|
+
module Slack
|
5
|
+
class Client
|
6
|
+
class << self
|
7
|
+
def stub(&block)
|
8
|
+
client = new(prefix: "data/test/auths/")
|
9
|
+
client.instance_variable_set(:@stubbed, true)
|
10
|
+
|
11
|
+
block = -> { [Auth.stub] } unless block_given?
|
12
|
+
items = block.call.map{|x| [client.key_for(x), x.to_h] }.to_h
|
13
|
+
|
14
|
+
client.client.stub_responses :list_objects, -> (context) do
|
15
|
+
{contents: items.keys.map{|x| {key:x} }}
|
16
|
+
end
|
17
|
+
|
18
|
+
client.client.stub_responses :get_object, -> (context) do
|
19
|
+
{body: StringIO.new(items.fetch(context.params[:key]).to_json)}
|
20
|
+
end
|
21
|
+
|
22
|
+
client
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Auth
|
28
|
+
class << self
|
29
|
+
def stub(bot_id:nil, channel_id:nil, team_id:nil, user_id:nil)
|
30
|
+
bot_id ||= "B#{SecureRandom.alphanumeric(8).upcase}"
|
31
|
+
channel_id ||= "C#{SecureRandom.alphanumeric(8).upcase}"
|
32
|
+
team_id ||= "T#{SecureRandom.alphanumeric(8).upcase}"
|
33
|
+
user_id ||= "U#{SecureRandom.alphanumeric(8).upcase}"
|
34
|
+
new(
|
35
|
+
ok: true,
|
36
|
+
access_token: "<token>",
|
37
|
+
scope: "identify,incoming-webhook",
|
38
|
+
user_id: user_id,
|
39
|
+
team_name: "My Team",
|
40
|
+
team_id: team_id,
|
41
|
+
incoming_webhook: {
|
42
|
+
channel: "#brutalism",
|
43
|
+
channel_id: channel_id,
|
44
|
+
configuration_url: "https://my-team.slack.com/services/#{bot_id}",
|
45
|
+
url: "https://hooks.slack.com/services/#{team_id}/#{bot_id}/1234567890abcdef12345678",
|
46
|
+
},
|
47
|
+
scopes: [
|
48
|
+
"identify",
|
49
|
+
"incoming-webhook",
|
50
|
+
],
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "brutalismbot"
|
2
|
+
require "brutalismbot/posts/stub"
|
3
|
+
require "brutalismbot/reddit/stub"
|
4
|
+
require "brutalismbot/slack/stub"
|
5
|
+
|
6
|
+
Aws.config.update(stub_responses: true)
|
7
|
+
|
8
|
+
module Brutalismbot
|
9
|
+
class Client
|
10
|
+
class << self
|
11
|
+
def stub
|
12
|
+
new(
|
13
|
+
posts: Posts::Client.stub,
|
14
|
+
slack: Slack::Client.stub,
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require "tempfile"
|
3
|
+
|
4
|
+
require "twitter"
|
5
|
+
|
6
|
+
require "brutalismbot/logger"
|
7
|
+
|
8
|
+
module Brutalismbot
|
9
|
+
module Twitter
|
10
|
+
class Client
|
11
|
+
attr_reader :client
|
12
|
+
|
13
|
+
def initialize(client:nil)
|
14
|
+
@client = client || ::Twitter::REST::Client.new do |config|
|
15
|
+
config.access_token = ENV["TWITTER_ACCESS_TOKEN"]
|
16
|
+
config.access_token_secret = ENV["TWITTER_ACCESS_TOKEN_SECRET"]
|
17
|
+
config.consumer_key = ENV["TWITTER_CONSUMER_KEY"]
|
18
|
+
config.consumer_secret = ENV["TWITTER_CONSUMER_SECRET"]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def push(post, dryrun:nil)
|
23
|
+
Brutalismbot.logger.info("PUSH #{"DRYRUN " if dryrun}twitter://@brutalismbot")
|
24
|
+
status = post.to_twitter
|
25
|
+
if post.url.nil?
|
26
|
+
@client.update(status) unless dryrun
|
27
|
+
else
|
28
|
+
uri = URI.parse(post.url)
|
29
|
+
Brutalismbot.logger.info("GET #{uri}")
|
30
|
+
uri.open do |media|
|
31
|
+
@client.update_with_media(status, media) unless dryrun
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/brutalismbot/version.rb
CHANGED
data/lib/brutalismbot.rb
CHANGED
@@ -1,34 +1,7 @@
|
|
1
|
-
require "logger"
|
2
|
-
require "securerandom"
|
3
|
-
require "net/https"
|
4
|
-
|
5
|
-
require "brutalismbot/auth"
|
6
|
-
require "brutalismbot/post"
|
7
|
-
require "brutalismbot/r"
|
8
1
|
require "brutalismbot/version"
|
2
|
+
require "brutalismbot/logger"
|
3
|
+
require "brutalismbot/client"
|
9
4
|
|
10
5
|
module Brutalismbot
|
11
|
-
class
|
12
|
-
@@config = {}
|
13
|
-
@@logger = Logger.new File::NULL
|
14
|
-
|
15
|
-
def config
|
16
|
-
@@config
|
17
|
-
end
|
18
|
-
|
19
|
-
def config=(config)
|
20
|
-
@@config = config || {}
|
21
|
-
end
|
22
|
-
|
23
|
-
def logger
|
24
|
-
config[:logger] || @@logger
|
25
|
-
end
|
26
|
-
|
27
|
-
def logger=(logger)
|
28
|
-
config[:logger] = logger
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class Error < StandardError
|
33
|
-
end
|
6
|
+
class Error < StandardError; end
|
34
7
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brutalismbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.beta.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Mancevice
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: twitter
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.2'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: aws-sdk-s3
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,20 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dotenv
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.7'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: pry
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,10 +147,22 @@ files:
|
|
119
147
|
- LICENSE.txt
|
120
148
|
- README.md
|
121
149
|
- lib/brutalismbot.rb
|
122
|
-
- lib/brutalismbot/
|
123
|
-
- lib/brutalismbot/
|
124
|
-
- lib/brutalismbot/
|
125
|
-
- lib/brutalismbot/
|
150
|
+
- lib/brutalismbot/base.rb
|
151
|
+
- lib/brutalismbot/client.rb
|
152
|
+
- lib/brutalismbot/logger.rb
|
153
|
+
- lib/brutalismbot/posts/client.rb
|
154
|
+
- lib/brutalismbot/posts/stub.rb
|
155
|
+
- lib/brutalismbot/reddit/client.rb
|
156
|
+
- lib/brutalismbot/reddit/post.rb
|
157
|
+
- lib/brutalismbot/reddit/resource.rb
|
158
|
+
- lib/brutalismbot/reddit/stub.rb
|
159
|
+
- lib/brutalismbot/s3/client.rb
|
160
|
+
- lib/brutalismbot/s3/prefix.rb
|
161
|
+
- lib/brutalismbot/slack/auth.rb
|
162
|
+
- lib/brutalismbot/slack/client.rb
|
163
|
+
- lib/brutalismbot/slack/stub.rb
|
164
|
+
- lib/brutalismbot/stub.rb
|
165
|
+
- lib/brutalismbot/twitter/client.rb
|
126
166
|
- lib/brutalismbot/version.rb
|
127
167
|
homepage: https://brutalismbot.com
|
128
168
|
licenses:
|
@@ -139,9 +179,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
179
|
version: '0'
|
140
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
181
|
requirements:
|
142
|
-
- - "
|
182
|
+
- - ">"
|
143
183
|
- !ruby/object:Gem::Version
|
144
|
-
version:
|
184
|
+
version: 1.3.1
|
145
185
|
requirements: []
|
146
186
|
rubygems_version: 3.0.3
|
147
187
|
signing_key:
|
data/lib/brutalismbot/auth.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
module Brutalismbot
|
2
|
-
class Auth < Hash
|
3
|
-
def channel_id
|
4
|
-
dig "incoming_webhook", "channel_id"
|
5
|
-
end
|
6
|
-
|
7
|
-
def post(body:, dryrun:nil)
|
8
|
-
uri = URI.parse webhook_url
|
9
|
-
ssl = uri.scheme == "https"
|
10
|
-
req = Net::HTTP::Post.new uri, "content-type" => "application/json"
|
11
|
-
req.body = body
|
12
|
-
Brutalismbot.logger.info "POST #{dryrun ? "DRYRUN " : ""}#{uri}"
|
13
|
-
if dryrun
|
14
|
-
Net::HTTPOK.new "1.1", "204", "ok"
|
15
|
-
else
|
16
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: ssl) do |http|
|
17
|
-
http.request req
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def team_id
|
23
|
-
dig "team_id"
|
24
|
-
end
|
25
|
-
|
26
|
-
def webhook_url
|
27
|
-
dig "incoming_webhook", "url"
|
28
|
-
end
|
29
|
-
|
30
|
-
class << self
|
31
|
-
def stub
|
32
|
-
bot_id = "B#{SecureRandom.alphanumeric(8).upcase}"
|
33
|
-
channel_id = "C#{SecureRandom.alphanumeric(8).upcase}"
|
34
|
-
team_id = "T#{SecureRandom.alphanumeric(8).upcase}"
|
35
|
-
user_id = "U#{SecureRandom.alphanumeric(8).upcase}"
|
36
|
-
Auth[{
|
37
|
-
"ok" => true,
|
38
|
-
"access_token" => "<token>",
|
39
|
-
"scope" => "identify,incoming-webhook",
|
40
|
-
"user_id" => user_id,
|
41
|
-
"team_name" => "My Team",
|
42
|
-
"team_id" => team_id,
|
43
|
-
"incoming_webhook" => {
|
44
|
-
"channel" => "#brutalism",
|
45
|
-
"channel_id" => channel_id,
|
46
|
-
"configuration_url" => "https://my-team.slack.com/services/#{bot_id}",
|
47
|
-
"url" => "https://hooks.slack.com/services/#{team_id}/#{bot_id}/1234567890abcdef12345678",
|
48
|
-
},
|
49
|
-
"scopes" => [
|
50
|
-
"identify",
|
51
|
-
"incoming-webhook",
|
52
|
-
],
|
53
|
-
}]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/lib/brutalismbot/post.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
module Brutalismbot
|
2
|
-
class Post < Hash
|
3
|
-
def created_after?(time = nil)
|
4
|
-
time.nil? || created_utc.to_i > time.to_i
|
5
|
-
end
|
6
|
-
|
7
|
-
def created_before?(time = nil)
|
8
|
-
time.nil? || created_utc.to_i < time.to_i
|
9
|
-
end
|
10
|
-
|
11
|
-
def created_between?(start, stop)
|
12
|
-
created_after?(start) && created_before?(stop)
|
13
|
-
end
|
14
|
-
|
15
|
-
def created_utc
|
16
|
-
Time.at(dig("data", "created_utc").to_i).utc
|
17
|
-
end
|
18
|
-
|
19
|
-
def fullname
|
20
|
-
"#{kind}_#{id}"
|
21
|
-
end
|
22
|
-
|
23
|
-
def id
|
24
|
-
dig "data", "id"
|
25
|
-
end
|
26
|
-
|
27
|
-
def kind
|
28
|
-
dig "kind"
|
29
|
-
end
|
30
|
-
|
31
|
-
def permalink
|
32
|
-
dig "data", "permalink"
|
33
|
-
end
|
34
|
-
|
35
|
-
def title
|
36
|
-
dig "data", "title"
|
37
|
-
end
|
38
|
-
|
39
|
-
def to_slack
|
40
|
-
{
|
41
|
-
blocks: [
|
42
|
-
{
|
43
|
-
type: "image",
|
44
|
-
title: {
|
45
|
-
type: "plain_text",
|
46
|
-
text: "/r/brutalism",
|
47
|
-
emoji: true,
|
48
|
-
},
|
49
|
-
image_url: url,
|
50
|
-
alt_text: title,
|
51
|
-
},
|
52
|
-
{
|
53
|
-
type: "context",
|
54
|
-
elements: [
|
55
|
-
{
|
56
|
-
type: "mrkdwn",
|
57
|
-
text: "<https://reddit.com#{permalink}|#{title}>",
|
58
|
-
},
|
59
|
-
],
|
60
|
-
},
|
61
|
-
],
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
def url
|
66
|
-
images = dig "data", "preview", "images"
|
67
|
-
source = images.map{|x| x["source"] }.compact.max do |a,b|
|
68
|
-
a.slice("width", "height").values <=> b.slice("width", "height").values
|
69
|
-
end
|
70
|
-
CGI.unescapeHTML source.dig("url")
|
71
|
-
rescue NoMethodError
|
72
|
-
dig("data", "media_metadata")&.values&.first&.dig("s", "u")
|
73
|
-
end
|
74
|
-
|
75
|
-
class << self
|
76
|
-
def stub
|
77
|
-
created_utc = Time.now.utc - rand(86400) - 86400
|
78
|
-
post_id = SecureRandom.alphanumeric(6).downcase
|
79
|
-
permalink_id = SecureRandom.alphanumeric.downcase
|
80
|
-
image_id = SecureRandom.alphanumeric
|
81
|
-
Post[{
|
82
|
-
"kind" => "t3",
|
83
|
-
"data" => {
|
84
|
-
"id" => post_id,
|
85
|
-
"created_utc" => created_utc.to_i,
|
86
|
-
"permalink" => "/r/brutalism/comments/#{permalink_id}/test/",
|
87
|
-
"title" => "Post to /r/brutalism",
|
88
|
-
"preview" => {
|
89
|
-
"images" => [
|
90
|
-
{
|
91
|
-
"source" => {
|
92
|
-
"url" => "https://preview.redd.it/#{image_id}.jpg",
|
93
|
-
}
|
94
|
-
}
|
95
|
-
]
|
96
|
-
}
|
97
|
-
}
|
98
|
-
}]
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/lib/brutalismbot/r.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
module Brutalismbot
|
2
|
-
module R
|
3
|
-
class PostCollection
|
4
|
-
include Enumerable
|
5
|
-
|
6
|
-
def initialize(uri:, user_agent:)
|
7
|
-
@uri = uri
|
8
|
-
@ssl = uri.scheme == "https"
|
9
|
-
@user_agent = user_agent
|
10
|
-
end
|
11
|
-
|
12
|
-
def each
|
13
|
-
Brutalismbot.logger.info "GET #{@uri}"
|
14
|
-
Net::HTTP.start(@uri.host, @uri.port, use_ssl: @ssl) do |http|
|
15
|
-
request = Net::HTTP::Get.new @uri, "user-agent" => @user_agent
|
16
|
-
response = JSON.parse http.request(request).body
|
17
|
-
children = response.dig("data", "children") || []
|
18
|
-
children.each{|x| yield Post[x] }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def all
|
23
|
-
to_a
|
24
|
-
end
|
25
|
-
|
26
|
-
def last
|
27
|
-
to_a.last
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class Subreddit
|
32
|
-
attr_reader :endpoint, :user_agent
|
33
|
-
|
34
|
-
def initialize(endpoint:nil, user_agent:nil)
|
35
|
-
@endpoint = endpoint
|
36
|
-
@user_agent = user_agent || "Brutalismbot #{VERSION}"
|
37
|
-
end
|
38
|
-
|
39
|
-
def posts(resource, params = {})
|
40
|
-
url = File.join @endpoint, "#{resource}.json"
|
41
|
-
qry = URI.encode_www_form params
|
42
|
-
uri = URI.parse "#{url}?#{qry}"
|
43
|
-
PostCollection.new uri: uri, user_agent: @user_agent
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class Brutalism < Subreddit
|
48
|
-
def initialize(endpoint:nil, user_agent:nil)
|
49
|
-
endpoint ||= "https://www.reddit.com/r/brutalism"
|
50
|
-
super
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/lib/brutalismbot/s3.rb
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
require "aws-sdk-s3"
|
2
|
-
|
3
|
-
require "brutalismbot"
|
4
|
-
|
5
|
-
module Brutalismbot
|
6
|
-
module S3
|
7
|
-
class Prefix
|
8
|
-
include Enumerable
|
9
|
-
|
10
|
-
attr_reader :prefix, :client
|
11
|
-
|
12
|
-
def initialize(bucket:nil, prefix:nil, client:nil, stub_responses:nil)
|
13
|
-
@bucket = bucket || "brutalismbot"
|
14
|
-
@prefix = prefix || "data/v1/"
|
15
|
-
@client = client || Aws::S3::Client.new(stub_responses: stub_responses || false)
|
16
|
-
if stub_responses
|
17
|
-
@auths = 3.times.map{ Auth.stub }
|
18
|
-
@posts = 3.times.map{ Post.stub }.sort{|a,b| a.created_utc <=> b.created_utc }
|
19
|
-
@client.stub_responses :delete_object
|
20
|
-
@client.stub_responses :list_objects, -> (context) { stub_list_objects context }
|
21
|
-
@client.stub_responses :get_object, -> (context) { stub_get_object context }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def each
|
26
|
-
bucket.objects(prefix: @prefix).each{|x| yield x }
|
27
|
-
end
|
28
|
-
|
29
|
-
def all
|
30
|
-
to_a
|
31
|
-
end
|
32
|
-
|
33
|
-
def bucket(options = {})
|
34
|
-
options[:name] ||= @bucket
|
35
|
-
options[:client] ||= @client
|
36
|
-
Aws::S3::Bucket.new options
|
37
|
-
end
|
38
|
-
|
39
|
-
def delete(object)
|
40
|
-
key = key_for object
|
41
|
-
Brutalismbot.logger.info "DELETE #{"DRYRUN " if stubbed?}s3://#{@bucket}/#{key}"
|
42
|
-
bucket.delete_objects delete: {objects: [{key: key}]}
|
43
|
-
end
|
44
|
-
|
45
|
-
def put(object)
|
46
|
-
key = key_for object
|
47
|
-
Brutalismbot.logger.info "PUT #{"DRYRUN " if stubbed?}s3://#{@bucket}/#{key}"
|
48
|
-
bucket.put_object key: key, body: object.to_json
|
49
|
-
end
|
50
|
-
|
51
|
-
def stubbed?
|
52
|
-
@client.config.stub_responses
|
53
|
-
end
|
54
|
-
|
55
|
-
def stub_list_objects(context)
|
56
|
-
{
|
57
|
-
contents: if context.params[:prefix] =~ /auths\//
|
58
|
-
@auths.map do |auth|
|
59
|
-
File.join(
|
60
|
-
@prefix,
|
61
|
-
"auths",
|
62
|
-
"team=#{auth.team_id}",
|
63
|
-
"channel=#{auth.channel_id}",
|
64
|
-
"oauth.json",
|
65
|
-
)
|
66
|
-
end
|
67
|
-
elsif context.params[:prefix] =~ /posts\//
|
68
|
-
@posts.map do |post|
|
69
|
-
File.join(
|
70
|
-
@prefix,
|
71
|
-
"posts",
|
72
|
-
post.created_utc.strftime("year=%Y/month=%Y-%m/day=%Y-%m-%d/%s.json"),
|
73
|
-
)
|
74
|
-
end
|
75
|
-
end.select do |key|
|
76
|
-
key.start_with? context.params[:prefix]
|
77
|
-
end.map do |key|
|
78
|
-
{
|
79
|
-
key: key
|
80
|
-
}
|
81
|
-
end
|
82
|
-
}
|
83
|
-
end
|
84
|
-
|
85
|
-
def stub_get_object(context)
|
86
|
-
{
|
87
|
-
body: if context.params[:key] =~ /auths\//
|
88
|
-
@auths.select do |auth|
|
89
|
-
File.join(
|
90
|
-
@prefix,
|
91
|
-
"auths",
|
92
|
-
"team=#{auth.team_id}",
|
93
|
-
"channel=#{auth.channel_id}",
|
94
|
-
"oauth.json",
|
95
|
-
) == context.params[:key]
|
96
|
-
end.first
|
97
|
-
elsif context.params[:key] =~ /posts\//
|
98
|
-
@posts.select do |post|
|
99
|
-
File.join(
|
100
|
-
@prefix,
|
101
|
-
"posts",
|
102
|
-
post.created_utc.strftime("year=%Y/month=%Y-%m/day=%Y-%m-%d/%s.json"),
|
103
|
-
) == context.params[:key]
|
104
|
-
end.first
|
105
|
-
end.to_json
|
106
|
-
}
|
107
|
-
end
|
108
|
-
|
109
|
-
def subreddit(endpoint:nil, user_agent:nil)
|
110
|
-
R::Brutalism.new endpoint:endpoint, user_agent: user_agent
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
class Client < Prefix
|
115
|
-
def auths
|
116
|
-
prefix = File.join @prefix, "auths/"
|
117
|
-
AuthCollection.new bucket: @bucket, prefix: prefix, client: @client
|
118
|
-
end
|
119
|
-
|
120
|
-
def posts
|
121
|
-
prefix = File.join @prefix, "posts/"
|
122
|
-
PostCollection.new bucket: @bucket, prefix: prefix, client: @client
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
class AuthCollection < Prefix
|
127
|
-
def each
|
128
|
-
super{|x| yield Auth[JSON.parse x.get.body.read] }
|
129
|
-
end
|
130
|
-
|
131
|
-
def key_for(auth)
|
132
|
-
File.join @prefix, "team=#{auth.team_id}/channel=#{auth.channel_id}/oauth.json"
|
133
|
-
end
|
134
|
-
|
135
|
-
def mirror(post, options = {})
|
136
|
-
options[:body] = post.to_slack.to_json
|
137
|
-
map{|x| x.post options }
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
class PostCollection < Prefix
|
142
|
-
def each
|
143
|
-
super{|x| yield Post[JSON.parse x.get.body.read] }
|
144
|
-
end
|
145
|
-
|
146
|
-
def key_for(post)
|
147
|
-
File.join @prefix, post.created_utc.strftime("year=%Y/month=%Y-%m/day=%Y-%m-%d/%s.json")
|
148
|
-
end
|
149
|
-
|
150
|
-
def last
|
151
|
-
Post[JSON.parse max_key.get.body.read]
|
152
|
-
end
|
153
|
-
|
154
|
-
def max_key
|
155
|
-
# Dig for max key
|
156
|
-
prefix = Time.now.utc.strftime "#{@prefix}year=%Y/month=%Y-%m/day=%Y-%m-%d/"
|
157
|
-
Brutalismbot.logger.info "GET s3://#{@bucket}/#{prefix}*"
|
158
|
-
|
159
|
-
# Go up a level in prefix if no keys found
|
160
|
-
until (keys = bucket.objects(prefix: prefix)).any?
|
161
|
-
prefix = prefix.split(/[^\/]+\/\z/).first
|
162
|
-
Brutalismbot.logger.info "GET s3://#{@bucket}/#{prefix}*"
|
163
|
-
end
|
164
|
-
|
165
|
-
# Return max by key
|
166
|
-
keys.max{|a,b| a.key <=> b.key }
|
167
|
-
end
|
168
|
-
|
169
|
-
def max_time
|
170
|
-
max_key.key.match(/(\d+).json\z/).to_a.last.to_i
|
171
|
-
end
|
172
|
-
|
173
|
-
def pull(min_time:nil, max_time:nil, endpoint:nil, user_agent:nil)
|
174
|
-
posts = subreddit(endpoint: endpoint, user_agent: user_agent).posts(:new)
|
175
|
-
posts = posts.select{|x| x.created_between?(min_time, max_time) }
|
176
|
-
posts = posts.sort{|a,b| a.created_utc <=> b.created_utc }
|
177
|
-
posts.map{|x| put x }
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|