correole 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2a600945ac9a19b338201ce5b6098c74cac2a1fa
4
- data.tar.gz: 2e1c5a6c6e7a765dd8b6c66ad54526fa38cd6e3f
2
+ SHA256:
3
+ metadata.gz: f8f2fe3a7de80d7791152fd8a3763666393e9126af594aa3f67b4cba3e468342
4
+ data.tar.gz: beb208a8c5f5798cd60f8ace8a62b7b949f1c363a2c85e8e2bc85267fb22de6d
5
5
  SHA512:
6
- metadata.gz: bf5ce5f7f5befad4c24719a8a32f79ff6f03fa39c8796879c094908807dadfcc773a029d59e10a963c8b5690324d3b0f81791cad8d6377c4ea0ed7a8004d2f44
7
- data.tar.gz: b81547d79a84dcf4acbfbce6a18c15accd2ac7feb39602b3e297d5ca0793477770c224662dec2c102622499140b7bb992f3c92436be73c44078d7e0237f66b32
6
+ metadata.gz: c3b3d63f74a0be04f81a0ccee3cb48d467f3920701e6cc3cd0bf8a1e516effc8a0c8cecb3c3725e8e0d410d987811a38267dd26702abf06d2d412311a6deddb2
7
+ data.tar.gz: 32bdbf7124e7aed3474111af567c7cb8b1390d92807764285af43efe19be0c562c2dc8079667edaf07a7a3dd2857a1559ecbd5276dbb52a1d5b0086957604691
@@ -12,6 +12,9 @@ Configuration.quiet = ARGV.second == '-q'
12
12
  case ARGV.first
13
13
  when 'send'
14
14
  Send.run!
15
+ when 'test'
16
+ Configuration.dry_run = true
17
+ Send.run!
15
18
  when 'purge'
16
19
  Purge.run!
17
20
  else
@@ -0,0 +1,75 @@
1
+ DEFAULT_ENV = 'production'
2
+ DEFAULT_CONFIG_FILE = 'config.yml'
3
+
4
+ ENV['RACK_ENV'] ||= DEFAULT_ENV
5
+ ENV['CONFIG_FILE'] ||= File.expand_path "../#{DEFAULT_CONFIG_FILE}", __FILE__
6
+
7
+ class Configuration
8
+
9
+ BOOLEAN_KEYS = [
10
+ 'QUIET',
11
+ 'DRY_RUN',
12
+ 'SMTP_TTLS'
13
+ ]
14
+ CONFIG_KEYS = [
15
+ 'DRY_RUN_EMAIL',
16
+ 'FEED',
17
+ 'UNSUBSCRIBE_URI',
18
+ 'CONFIRMATION_URI',
19
+ 'BASE_URI',
20
+ 'SUBJECT',
21
+ 'FROM',
22
+ 'HTML_TEMPLATE',
23
+ 'PLAIN_TEMPLATE',
24
+ 'SMTP_HOST',
25
+ 'SMTP_PORT',
26
+ 'SMTP_USER',
27
+ 'SMTP_PASS',
28
+ 'SMTP_AUTH',
29
+ ] + BOOLEAN_KEYS
30
+
31
+ class << self
32
+ CONFIG_KEYS.each do |k|
33
+ attr_accessor k.downcase.to_sym
34
+ end
35
+ end
36
+
37
+ def self.load!
38
+
39
+ YAML.load_file(ENV['CONFIG_FILE'])[ENV['RACK_ENV']].each_pair do |k, v|
40
+ ENV[k.upcase] ||= v.to_s rescue abort("Cannot load configuration key #{k}.")
41
+ end rescue qputs "Cannot load configuration file #{ENV['CONFIG_FILE']}. Using configuration given by environment."
42
+
43
+ CONFIG_KEYS.each do |k|
44
+ case k
45
+ when *BOOLEAN_KEYS
46
+ # Cannot store boolean values in ENV, thus this.
47
+ self.send("#{k.downcase}=".to_sym, ENV[k] == 'true')
48
+ when 'HTML_TEMPLATE', 'PLAIN_TEMPLATE'
49
+ file = File.expand_path "../#{ENV[k]}", __FILE__
50
+ template = File.read file rescue abort "Cannot load template #{ENV[k]}."
51
+ self.send("#{k.downcase}=".to_sym, template)
52
+ when 'SMTP_USER', 'SMTP_PASS'
53
+ # For user name and password, Mail interprets '' as an input.
54
+ # It doesn't do the same with nil.
55
+ self.send("#{k.downcase}=".to_sym, ENV[k] == '' ? nil : ENV[k])
56
+ else
57
+ self.send("#{k.downcase}=".to_sym, ENV[k])
58
+ end
59
+ end
60
+
61
+ Mail.defaults do
62
+ delivery_method :smtp,
63
+ address: Configuration.smtp_host,
64
+ port: Configuration.smtp_port,
65
+ user_name: Configuration.smtp_user,
66
+ password: Configuration.smtp_pass,
67
+ authentication: Configuration.smtp_auth,
68
+ enable_starttls_auto: Configuration.smtp_ttls
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ Configuration.load!
@@ -0,0 +1,10 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: test.db
4
+
5
+ development:
6
+ adapter: sqlite3
7
+ database: development.db
8
+
9
+ production:
10
+ adapter: postgresql
@@ -0,0 +1,13 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/activerecord'
3
+ require 'active_support/core_ext/hash'
4
+ require 'correole/qputs'
5
+ require 'correole/subscriber'
6
+ require 'correole/item'
7
+ require 'correole/feed'
8
+ require 'correole/api'
9
+ require 'correole/send'
10
+ require 'correole/purge'
11
+ require 'net/http'
12
+ require 'mail'
13
+ require 'configuration'
@@ -0,0 +1,21 @@
1
+ production: &prod
2
+ quiet: false
3
+ dry_run: false
4
+ dry_run_email: your.email@mail.com
5
+ base_uri: http://newsletter.ruslanledesma.com
6
+ feed: http://ruslanledesma.com/feed.xml
7
+ unsubscribe_uri: 'http://ruslanledesma.com/unsubscribe/?email=<%= recipient %>'
8
+ confirmation_uri: http://ruslanledesma.com/unsubscribed/
9
+ subject: '<%= title %>: newsletter for <%= date %>'
10
+ from: '<%= title %> <no-reply@ruslanledesma.com>'
11
+ html_template: production.html.erb
12
+ plain_template: production.txt.erb
13
+ smtp_host:
14
+ smtp_port:
15
+ smtp_user:
16
+ smtp_pass:
17
+ smtp_auth:
18
+ smtp_ttls:
19
+
20
+ development:
21
+ <<: *prod
@@ -0,0 +1,21 @@
1
+ <html>
2
+ <body>
3
+ <h1><%= title %></h1>
4
+ <h2>New posts</h2>
5
+ <ul>
6
+ <% for item in unsent_items %>
7
+ <li>
8
+ <h3>
9
+ <a href="<%= item.link %>"><%= item.title %></a>
10
+ </h3>
11
+ <% if item.pub_date -%>
12
+ <p><i><%= item.pub_date.to_date %></i></p>
13
+ <% end -%>
14
+ <p><%= item.description %></p>
15
+ </li>
16
+ <% end %>
17
+ </ul>
18
+
19
+ <a href="<%= unsubscribe_uri %>">Unsubscribe here.</a>
20
+ </body>
21
+ </html>
@@ -0,0 +1,13 @@
1
+ <%= title %>
2
+
3
+ New posts
4
+ <% for item in unsent_items %>
5
+ - <%= item.title %>
6
+ <% if item.pub_date -%>
7
+ <%= item.pub_date.to_date %>
8
+ <% end -%>
9
+ <%= item.link %>
10
+
11
+ <%= item.description %>
12
+ <% end %>
13
+ Unsubscribe here: <%= unsubscribe_uri %>
@@ -0,0 +1,18 @@
1
+ test:
2
+ quiet: true
3
+ dry_run: false
4
+ dry_run_email: test@mail.com
5
+ base_uri: http://test.ruslanledesma.com
6
+ feed: http://ruslanledesma.com/feed.xml # reset by env for end-to-end test
7
+ unsubscribe_uri: 'http://newsletter.ruslanledesma.com/unsubscribe/?email=<%= recipient %>'
8
+ confirmation_uri: http://newsletter.ruslanledesma.com/unsubscribed/
9
+ subject: 'Test <%= title %> - <%= date %>'
10
+ from: '<%= title %> <no-reply@ruslanledesma.com>'
11
+ html_template: test.html.erb
12
+ plain_template: test.txt.erb
13
+ smtp_host: localhost # reset by env for end-to-end test
14
+ smtp_port: 25 # reset by env for end-to-end test
15
+ smtp_user:
16
+ smtp_pass:
17
+ smtp_auth:
18
+ smtp_ttls: false
@@ -0,0 +1,21 @@
1
+ <html>
2
+ <body>
3
+ <h1><%= title %></h1>
4
+ <h2>Items</h2>
5
+ <ul>
6
+ <% for item in unsent_items %>
7
+ <li>
8
+ <% if item.pub_date -%>
9
+ <i><%= item.pub_date.to_date %></i>
10
+ <% end -%>
11
+ <h3>
12
+ <a href="<%= item.link %>"><%= item.title %></a>
13
+ </h3>
14
+ <p><%= item.description %></p>
15
+ </li>
16
+ <% end %>
17
+ </ul>
18
+
19
+ <a href="<%= unsubscribe_uri %>">Unsubscribe here.</a>
20
+ </body>
21
+ </html>
@@ -0,0 +1,13 @@
1
+ <%= title %>
2
+
3
+ Items
4
+ <% for item in unsent_items %>
5
+ - <%= item.title %>
6
+ <% if item.pub_date -%>
7
+ <%= item.pub_date.to_date %>
8
+ <% end -%>
9
+ <%= item.link %>
10
+
11
+ <%= item.description %>
12
+ <% end %>
13
+ Unsubscribe here: <%= unsubscribe_uri %>
@@ -0,0 +1,9 @@
1
+ class CreateDatabase < ActiveRecord::Migration
2
+ def change
3
+ create_table :subscribers do |t|
4
+ t.string :email, null: false
5
+ t.index :email, unique: true
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateItems < ActiveRecord::Migration
2
+ def change
3
+ create_table :items do |t|
4
+ t.string :title, null: false
5
+ t.string :description, null: false
6
+ t.string :link, null: false
7
+ t.timestamp :pub_date, null: true
8
+ t.index :link, unique: true
9
+ t.timestamps null: false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,122 @@
1
+ class Api < Sinatra::Base
2
+
3
+ UNSUBSCRIBE_PATH = '/unsubscribe'
4
+ SUBSCRIBERS_ALLOWED_METHODS = 'PUT, DELETE, OPTIONS'
5
+ SUBSCRIBERS_ALLOWED_ORIGIN = '*'
6
+ UNSUBSCRIBE_ALLOWED_METHODS = 'GET, OPTIONS'
7
+ UNSUBSCRIBE_ALLOWED_ORIGIN = '*'
8
+
9
+ set :server, :thin
10
+ enable :logging
11
+ disable :show_exceptions
12
+ # use ActiveRecord::ConnectionAdapters::ConnectionManagement
13
+
14
+ before do
15
+ content_type 'text/plain'
16
+ end
17
+
18
+ def subscribe(params)
19
+ response.headers['Access-Control-Allow-Origin'] = SUBSCRIBERS_ALLOWED_ORIGIN
20
+ s = Subscriber.new(email: params[:email])
21
+ return 400 if not s.valid?
22
+ begin
23
+ s.save
24
+ logger.info("Subscribed #{params[:email]}.")
25
+ rescue ActiveRecord::RecordNotUnique
26
+ logger.info("Already subscribed #{params[:email]}.")
27
+ Subscriber.find_by_email(params[:email]).touch
28
+ end
29
+ [201, "#{params[:email]}\n"]
30
+ end
31
+
32
+ def unsubscribe(params)
33
+ response.headers['Access-Control-Allow-Origin'] = UNSUBSCRIBE_ALLOWED_ORIGIN
34
+ s = Subscriber.new(email: params[:email])
35
+ return 400 if not s.valid?
36
+ s = Subscriber.find_by_email(params[:email])
37
+ if s != nil
38
+ s.delete
39
+ logger.info("Unsubscribed #{params[:email]}.")
40
+ else
41
+ logger.info("Tried to unsubscribe #{params[:email]} but address is not subscribed.")
42
+ end
43
+ "#{params[:email]}\n"
44
+ end
45
+
46
+ def subscribers_method_not_allowed
47
+ response.headers['Allow'] = SUBSCRIBERS_ALLOWED_METHODS
48
+ response.headers['Access-Control-Allow-Methods'] = SUBSCRIBERS_ALLOWED_METHODS
49
+ 405
50
+ end
51
+
52
+ def unsubscribe_method_not_allowed
53
+ response.headers['Allow'] = UNSUBSCRIBE_ALLOWED_METHODS
54
+ response.headers['Access-Control-Allow-Methods'] = UNSUBSCRIBE_ALLOWED_METHODS
55
+ 405
56
+ end
57
+
58
+ options '/subscribers/:email' do
59
+ response.headers['Allow'] = SUBSCRIBERS_ALLOWED_METHODS
60
+ response.headers['Access-Control-Allow-Methods'] = SUBSCRIBERS_ALLOWED_METHODS
61
+ response.headers['Access-Control-Allow-Origin'] = SUBSCRIBERS_ALLOWED_ORIGIN
62
+ 200
63
+ end
64
+
65
+ put '/subscribers/:email' do
66
+ subscribe(params)
67
+ end
68
+
69
+ delete '/subscribers/:email' do
70
+ unsubscribe(params)
71
+ end
72
+
73
+ [ :get,
74
+ :post,
75
+ :patch
76
+ ].each do |verb|
77
+ send verb, '/subscribers/:email' do
78
+ subscribers_method_not_allowed
79
+ end
80
+ end
81
+
82
+ options "#{UNSUBSCRIBE_PATH}/:email" do
83
+ response.headers['Allow'] = UNSUBSCRIBE_ALLOWED_METHODS
84
+ response.headers['Access-Control-Allow-Methods'] = UNSUBSCRIBE_ALLOWED_METHODS
85
+ response.headers['Access-Control-Allow-Origin'] = UNSUBSCRIBE_ALLOWED_ORIGIN
86
+ 200
87
+ end
88
+
89
+ get "#{UNSUBSCRIBE_PATH}/:email" do
90
+ r = unsubscribe(params)
91
+ return r if r.is_a? Integer
92
+ response.headers['Location'] = Configuration.confirmation_uri
93
+ [302, r]
94
+ end
95
+
96
+ [ :put,
97
+ :delete,
98
+ :post,
99
+ :patch
100
+ ].each do |verb|
101
+ send verb, "#{UNSUBSCRIBE_PATH}/:email" do
102
+ unsubscribe_method_not_allowed
103
+ end
104
+ end
105
+
106
+ not_found do
107
+ [404, "Not found\n"]
108
+ end
109
+
110
+ error 400 do
111
+ [400, "Bad request\n"]
112
+ end
113
+
114
+ error 405 do
115
+ [405, "Method not allowed\n"]
116
+ end
117
+
118
+ error 500 do
119
+ [500, "Internal server error\n"]
120
+ end
121
+
122
+ end
@@ -0,0 +1,37 @@
1
+ class Feed
2
+
3
+ def self.get
4
+ uri = URI Configuration.feed
5
+ xml = Net::HTTP.get uri
6
+ hash = Hash.from_xml xml
7
+ return {
8
+ :title => hash['rss']['channel']['title'],
9
+ :item => hash['rss']['channel']['item'].map { |i|
10
+ pub_date = nil
11
+ pub_date = Time.parse(i['pubDate']) if i.has_key? 'pubDate'
12
+ Item.new(title: i['title'],
13
+ description: i['description'],
14
+ link: i['link'],
15
+ pub_date: pub_date)
16
+ }
17
+ }
18
+ end
19
+
20
+ def self.split_items(feed)
21
+ split_feed = {
22
+ :title => feed[:title],
23
+ :unsent_item => [],
24
+ :sent_item => []
25
+ }
26
+ feed[:item].each do |i|
27
+ if Item.where(:link => i.link).any?
28
+ split_feed[:sent_item] << i
29
+ else
30
+ split_feed[:unsent_item] << i
31
+ end
32
+ end
33
+ return split_feed
34
+ end
35
+
36
+
37
+ end
@@ -0,0 +1,17 @@
1
+ class Item < ActiveRecord::Base
2
+ validates :title, presence: true
3
+ validates :description, presence: true
4
+ validates :link, presence: true, format: /http.+/
5
+
6
+ def ==(o)
7
+ return o.class == self.class &&
8
+ o.title == self.title &&
9
+ o.description == self.description &&
10
+ o.link == self.link &&
11
+ o.pub_date == self.pub_date &&
12
+ o.id == self.id &&
13
+ o.created_at == self.created_at &&
14
+ o.updated_at == self.updated_at
15
+ end
16
+
17
+ end
@@ -0,0 +1,18 @@
1
+ class Purge
2
+
3
+ def self.run!
4
+ qputs "Fetch feed from #{Configuration.feed}."
5
+ feed = Feed.get
6
+ unsent_items = Feed.split_items(feed)[:unsent_item]
7
+ if unsent_items.empty?
8
+ qputs 'There are no new items, exiting.'
9
+ return
10
+ end
11
+ qputs "There are #{unsent_items.length} new items. The items are the following."
12
+ unsent_items.each_with_index { |i, j| qputs "[#{j+1}] #{i.link}" }
13
+ qputs 'Purge the new items by remembering them.'
14
+ unsent_items.each { |i| i.save }
15
+ qputs 'Done.'
16
+ end
17
+
18
+ end
@@ -0,0 +1,3 @@
1
+ def qputs(s)
2
+ puts s if not Configuration.quiet
3
+ end
@@ -0,0 +1,91 @@
1
+ class Send
2
+
3
+ def self.run!
4
+ qputs "Fetch feed from #{Configuration.feed}."
5
+ feed = Feed.get
6
+ split_feed = Feed.split_items feed
7
+ if split_feed[:unsent_item].empty?
8
+ qputs 'There are no new items, exiting.'
9
+ return
10
+ end
11
+ qputs "There are #{split_feed[:unsent_item].length} new items. The items are the following."
12
+ split_feed[:unsent_item].each_with_index { |i, j| qputs "[#{j+1}] #{i.link}" }
13
+ html = compose_html split_feed
14
+ plain = compose_plain split_feed
15
+ rr = recipients
16
+ rr.each_with_index do |r, i|
17
+ html_r = personalize html, r.email
18
+ plain_r = personalize plain, r.email
19
+ qputs "[#{i+1}/#{rr.size}] Send newsletter to #{r.email}."
20
+ begin
21
+ send_out feed[:title], html_r, plain_r, r.email
22
+ rescue => exc
23
+ qputs "Could not send newsletter to #{r.email} for the following reason."
24
+ qputs exc.message
25
+ end
26
+ end
27
+ if not Configuration.dry_run
28
+ qputs 'Remember new items.'
29
+ split_feed[:unsent_item].each { |i| i.save }
30
+ end
31
+ qputs 'Done.'
32
+ end
33
+
34
+ private
35
+
36
+ def self.recipients
37
+ if Configuration.dry_run
38
+ s = Subscriber.new(email: Configuration.dry_run_email)
39
+ return [s].each
40
+ end
41
+ return Subscriber.find_each
42
+ end
43
+
44
+ def self.template_bindings(split_feed)
45
+ title = split_feed[:title]
46
+ title = '' if !title.is_a?(String)
47
+ unsent_items = split_feed[:unsent_item]
48
+ unsent_items = [] if !unsent_items.is_a?(Array)
49
+ sent_items = split_feed[:sent_item]
50
+ sent_items = [] if !sent_items.is_a?(Array)
51
+ unsubscribe_uri = Configuration.unsubscribe_uri
52
+ if false then unsubscribe_uri end # suppress unused variable warning
53
+ return binding
54
+ end
55
+
56
+ def self.compose_html(split_feed)
57
+ template = Configuration.html_template
58
+ bindings = template_bindings(split_feed)
59
+ return ERB.new(template, trim_mode: '-').result(bindings)
60
+ end
61
+
62
+ def self.compose_plain(split_feed)
63
+ template = Configuration.plain_template
64
+ bindings = template_bindings(split_feed)
65
+ return ERB.new(template, trim_mode: '-').result(bindings)
66
+ end
67
+
68
+ def self.personalize(message, recipient)
69
+ return ERB.new(message).result(binding)
70
+ end
71
+
72
+ def self.send_out(title, html, plain, recipient)
73
+ date = Date.today.strftime('%a, %d %b %Y')
74
+ if false then date end # suppress unused variable warning
75
+ Mail.deliver do
76
+ to recipient
77
+ from ERB.new(Configuration.from).result(binding)
78
+ subject ERB.new(Configuration.subject).result(binding)
79
+
80
+ text_part do
81
+ body plain
82
+ end
83
+
84
+ html_part do
85
+ content_type 'text/html; charset=UTF-8'
86
+ body html
87
+ end
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,3 @@
1
+ class Subscriber < ActiveRecord::Base
2
+ validates :email, presence: true, format: /.+@.+/
3
+ end
@@ -0,0 +1,4 @@
1
+ module Correole
2
+ VERSION = '0.0.6'
3
+ DATE = '2020-07-19'
4
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: correole
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Ledesma Garza
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-25 00:00:00.000000000 Z
11
+ date: 2020-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.4'
19
+ version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.4'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thin
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,42 +58,42 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '4.2'
61
+ version: '6.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '4.2'
68
+ version: '6.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activesupport
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '4.2'
75
+ version: '6.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '4.2'
82
+ version: '6.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: mail
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '2.6'
89
+ version: '2.7'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '2.6'
96
+ version: '2.7'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: pg
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -114,42 +114,42 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '1.3'
117
+ version: '1.4'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '1.3'
124
+ version: '1.4'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: minitest
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '5.9'
131
+ version: '5.14'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '5.9'
138
+ version: '5.14'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rack-test
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0.6'
145
+ version: '1.1'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0.6'
152
+ version: '1.1'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: mini-smtp-server
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: '11.2'
187
+ version: '13.0'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: '11.2'
194
+ version: '13.0'
195
195
  description: |
196
196
  Correole is a webservice that subscribes and unsubscribes readers from
197
197
  a newsletter.
@@ -202,6 +202,25 @@ extensions: []
202
202
  extra_rdoc_files: []
203
203
  files:
204
204
  - bin/correole
205
+ - config/configuration.rb
206
+ - config/database.yml
207
+ - config/dependencies.rb
208
+ - config/example.config.yml
209
+ - config/production.html.erb
210
+ - config/production.txt.erb
211
+ - config/test.config.yml
212
+ - config/test.html.erb
213
+ - config/test.txt.erb
214
+ - db/migrate/0001_create_database.rb
215
+ - db/migrate/0002_create_items.rb
216
+ - lib/correole/api.rb
217
+ - lib/correole/feed.rb
218
+ - lib/correole/item.rb
219
+ - lib/correole/purge.rb
220
+ - lib/correole/qputs.rb
221
+ - lib/correole/send.rb
222
+ - lib/correole/subscriber.rb
223
+ - lib/correole/version.rb
205
224
  homepage: http://ruslanledesma.com/
206
225
  licenses:
207
226
  - MIT
@@ -209,20 +228,20 @@ metadata: {}
209
228
  post_install_message:
210
229
  rdoc_options: []
211
230
  require_paths:
231
+ - config
212
232
  - lib
213
233
  required_ruby_version: !ruby/object:Gem::Requirement
214
234
  requirements:
215
235
  - - "~>"
216
236
  - !ruby/object:Gem::Version
217
- version: 2.3.1
237
+ version: 2.7.1
218
238
  required_rubygems_version: !ruby/object:Gem::Requirement
219
239
  requirements:
220
240
  - - ">="
221
241
  - !ruby/object:Gem::Version
222
242
  version: '0'
223
243
  requirements: []
224
- rubyforge_project:
225
- rubygems_version: 2.5.1
244
+ rubygems_version: 3.1.2
226
245
  signing_key:
227
246
  specification_version: 4
228
247
  summary: A newsletter webservice