brutalismbot 0.6.1 → 1.0.0.beta.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|