eventify 0.9.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 +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +11 -0
- data/Gemfile +16 -0
- data/Guardfile +12 -0
- data/LICENSE +22 -0
- data/README.md +67 -0
- data/Rakefile +10 -0
- data/eventify.gemspec +31 -0
- data/lib/eventify.rb +38 -0
- data/lib/eventify/configuration.rb +31 -0
- data/lib/eventify/database.rb +56 -0
- data/lib/eventify/mail.rb +37 -0
- data/lib/eventify/provider/base.rb +51 -0
- data/lib/eventify/provider/fbi.rb +17 -0
- data/lib/eventify/provider/piletilevi.rb +31 -0
- data/lib/eventify/provider/ticketpro.rb +15 -0
- data/lib/eventify/scheduler.rb +31 -0
- data/lib/eventify/version.rb +3 -0
- data/spec/eventify/configuration_spec.rb +46 -0
- data/spec/eventify/database_spec.rb +142 -0
- data/spec/eventify/mail_spec.rb +33 -0
- data/spec/eventify/provider/base_spec.rb +145 -0
- data/spec/eventify/provider/fbi_spec.rb +25 -0
- data/spec/eventify/provider/piletilevi_spec.rb +36 -0
- data/spec/eventify/provider/ticketpro_spec.rb +25 -0
- data/spec/eventify/scheduler_spec.rb +14 -0
- data/spec/eventify_spec.rb +150 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/fbi.html +802 -0
- data/spec/support/piletilevi-empty.xml +10 -0
- data/spec/support/piletilevi-music.xml +51 -0
- data/spec/support/piletilevi-news.xml +17 -0
- data/spec/support/ticketpro.xml +38 -0
- metadata +219 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1794610fc1c068a4f1d74d56f75bfab3ace97d6c
|
4
|
+
data.tar.gz: bbec3e34aeb04c91cc38316ef61abe58013af376
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2ad9d63a20ebdca21135cafa59fc54facab5a2b0c365aac974a10b65a9051136d5f4aa32b40152a29bc1cbd363dcaa144a4f3084234f6fa7a052656bb0b88c3f
|
7
|
+
data.tar.gz: c44b7b19adc7f91199b5cd9051dc0502c8883b2eb164428ec6bc935a6d853026d6c619e118ce2c1864b11df0ecd6fd70aa04b2f7d7995bce83f837cb7ce789d2
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "rufus-scheduler"
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem "guard"
|
7
|
+
gem "guard-rspec"
|
8
|
+
gem "guard-bundler"
|
9
|
+
gem "wdm", platform: :mingw
|
10
|
+
gem "win32console", platform: :mingw
|
11
|
+
gem "ruby_gntp"
|
12
|
+
end
|
13
|
+
|
14
|
+
gemspec
|
15
|
+
|
16
|
+
gem "coveralls", :require => false
|
data/Guardfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
notification :ruby_gntp
|
2
|
+
#interactor :off
|
3
|
+
|
4
|
+
guard 'rspec', version: 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
9
|
+
|
10
|
+
guard 'bundler' do
|
11
|
+
watch('Gemfile')
|
12
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jarmo Pertman
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Eventify
|
2
|
+
[](http://badge.fury.io/rb/eventify)
|
3
|
+
[](http://travis-ci.org/jarmo/eventify)
|
4
|
+
[](https://coveralls.io/r/jarmo/eventify)
|
5
|
+
[](https://gemnasium.com/jarmo/eventify)
|
6
|
+
[](https://codeclimate.com/github/jarmo/eventify)
|
7
|
+
|
8
|
+
Are you tired of missing some cool events because you just didn't know them
|
9
|
+
happening? Are you tired of not getting good sitting places because you heard
|
10
|
+
of some event too late?
|
11
|
+
|
12
|
+
If the answer was yes to either of these questions then Eventify can help you!
|
13
|
+
|
14
|
+
Eventify will notify you about upcoming events from different
|
15
|
+
providers/organizers.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
$ gem install eventify
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Create configuration file:
|
24
|
+
|
25
|
+
$ ruby -reventify -e "Eventify::Configuration.new.save"
|
26
|
+
|
27
|
+
Edit configuration settings by adding your e-mail into `subscribers` list:
|
28
|
+
|
29
|
+
$ vi ~/.eventify/config.yaml
|
30
|
+
|
31
|
+
Run it from command line and add it into `cron`:
|
32
|
+
|
33
|
+
$ ruby -reventify -e "Eventify.new.process_new_events"
|
34
|
+
|
35
|
+
## Supported Providers
|
36
|
+
|
37
|
+
The following providers are currently supported:
|
38
|
+
|
39
|
+
* [FBI](http://fbi.ee)
|
40
|
+
* [Piletilevi](http://www.piletilevi.ee/)
|
41
|
+
* [Ticketpro](http://www.ticketpro.ee/)
|
42
|
+
|
43
|
+
## Adding New Providers
|
44
|
+
|
45
|
+
Adding new providers is easy. You just need to create a class with one method
|
46
|
+
satisfying the contract:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require "eventify"
|
50
|
+
|
51
|
+
class MyCustomProvider < Eventify::Provider::Base
|
52
|
+
def self.fetch
|
53
|
+
# fetch some atom feed
|
54
|
+
rss = SimpleRSS.parse open("http://example.org/rss.xml")
|
55
|
+
rss.entries.map { |entry| new id: entry.guid, title: entry.title, link: entry.link, date: entry.pubDate }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# use that provider with Eventify
|
60
|
+
eventify = Eventify.new
|
61
|
+
eventify.providers = [MyCustomProvider]
|
62
|
+
eventify.process_new_events
|
63
|
+
```
|
64
|
+
|
65
|
+
## License
|
66
|
+
|
67
|
+
See [LICENSE](https://github.com/jarmo/eventify/blob/master/LICENSE).
|
data/Rakefile
ADDED
data/eventify.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'eventify/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "eventify"
|
8
|
+
spec.version = Eventify::VERSION
|
9
|
+
spec.authors = ["Jarmo Pertman"]
|
10
|
+
spec.email = ["jarmo.p@gmail.com"]
|
11
|
+
spec.description = %q{Get notifications about upcoming events from different providers/organizers.}
|
12
|
+
spec.summary = %q{Get notifications about upcoming events from different providers/organizers.}
|
13
|
+
spec.homepage = "https://github.com/jarmo/eventify"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "simple-rss"
|
22
|
+
spec.add_dependency "nokogiri"
|
23
|
+
spec.add_dependency "sqlite3"
|
24
|
+
spec.add_dependency "mail"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
spec.add_development_dependency "webmock"
|
30
|
+
spec.add_development_dependency "yard"
|
31
|
+
end
|
data/lib/eventify.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path("eventify/version", __dir__)
|
2
|
+
require File.expand_path("eventify/configuration", __dir__)
|
3
|
+
require File.expand_path("eventify/provider/base", __dir__)
|
4
|
+
require File.expand_path("eventify/provider/fbi", __dir__)
|
5
|
+
require File.expand_path("eventify/provider/piletilevi", __dir__)
|
6
|
+
require File.expand_path("eventify/provider/ticketpro", __dir__)
|
7
|
+
require File.expand_path("eventify/database", __dir__)
|
8
|
+
require File.expand_path("eventify/mail", __dir__)
|
9
|
+
|
10
|
+
class Eventify
|
11
|
+
attr_reader :configuration
|
12
|
+
|
13
|
+
def initialize(configuration=Eventify::Configuration.new)
|
14
|
+
@configuration = configuration
|
15
|
+
end
|
16
|
+
|
17
|
+
def all_events
|
18
|
+
@all_events ||= providers.flat_map(&:fetch).uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
def new_events
|
22
|
+
@new_events ||= all_events.reject(&:exists?)
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_new_events
|
26
|
+
all_new_events = new_events
|
27
|
+
return if all_new_events.empty?
|
28
|
+
|
29
|
+
Eventify::Mail.deliver all_new_events, @configuration
|
30
|
+
all_new_events.each(&:save)
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_writer :providers
|
34
|
+
|
35
|
+
def providers
|
36
|
+
@providers ||= [Eventify::Provider::Piletilevi, Eventify::Provider::Ticketpro, Eventify::Provider::FBI]
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
class Eventify::Configuration
|
4
|
+
PATH = File.expand_path("~/.eventify/config.yaml")
|
5
|
+
|
6
|
+
def initialize(configuration = {})
|
7
|
+
@configuration = default_configuration.merge(load).merge(configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
def save
|
11
|
+
File.open(PATH, "w") { |f| f.write YAML.dump(@configuration) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
@configuration[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def default_configuration
|
21
|
+
{
|
22
|
+
subscribers: ["user@example.org"],
|
23
|
+
mail: Mail.delivery_method.settings
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def load
|
28
|
+
YAML.load(File.read(PATH)) rescue {}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "sqlite3"
|
2
|
+
|
3
|
+
class Eventify::Database
|
4
|
+
PATH = File.expand_path("~/.eventify/events.sqlite3", __dir__)
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def exists?(event)
|
8
|
+
results = sqlite.execute "select 1 from event where id=? and provider=? and link=?", event.id, event.provider, event.link
|
9
|
+
!results.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def save(event)
|
13
|
+
sqlite.execute "insert into event values(?, ?, ?, ?, ?)",
|
14
|
+
event.id,
|
15
|
+
event.provider,
|
16
|
+
event.title,
|
17
|
+
event.link,
|
18
|
+
event.date.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def events
|
22
|
+
translated_events = []
|
23
|
+
sqlite.execute("select * from event") do |event|
|
24
|
+
translated_events << const_get(event["provider"]).new(
|
25
|
+
id: event["id"],
|
26
|
+
title: event["title"],
|
27
|
+
link: event["link"],
|
28
|
+
date: Time.parse(event["date"])
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
translated_events
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def sqlite
|
38
|
+
@sqlite ||= begin
|
39
|
+
FileUtils.mkdir_p File.dirname(PATH)
|
40
|
+
database = SQLite3::Database.new PATH
|
41
|
+
database.results_as_hash = true
|
42
|
+
|
43
|
+
database.execute "create table if not exists event(
|
44
|
+
id text,
|
45
|
+
provider text,
|
46
|
+
title text,
|
47
|
+
link text,
|
48
|
+
date text,
|
49
|
+
primary key (id, provider, link)
|
50
|
+
)"
|
51
|
+
|
52
|
+
database
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "mail"
|
2
|
+
|
3
|
+
class Eventify::Mail
|
4
|
+
class << self
|
5
|
+
def deliver(new_events, configuration)
|
6
|
+
formatted_events = format(new_events)
|
7
|
+
|
8
|
+
configuration[:subscribers].each do |subscriber|
|
9
|
+
::Mail.deliver do
|
10
|
+
delivery_method :smtp, configuration[:mail]
|
11
|
+
|
12
|
+
content_type "text/plain; charset=utf-8"
|
13
|
+
|
14
|
+
to subscriber
|
15
|
+
from "no-reply@eventify.io"
|
16
|
+
subject "Event Rumours"
|
17
|
+
body formatted_events
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def format(events)
|
23
|
+
header = "There are some rumours going on about #{events.size} possible awesome events:"
|
24
|
+
|
25
|
+
formatted_events = events.sort.reduce([header, ""]) do |memo, event|
|
26
|
+
memo << "* #{event.title}".force_encoding("UTF-8")
|
27
|
+
memo << " #{event.link}"
|
28
|
+
memo << ""
|
29
|
+
end
|
30
|
+
|
31
|
+
footer = "Your Humble Servant,\nEventify"
|
32
|
+
|
33
|
+
formatted_events << footer
|
34
|
+
formatted_events.join("\n")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Eventify
|
2
|
+
module Provider
|
3
|
+
class Base
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def fetch
|
8
|
+
raise NotImplementedError
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :id, :title, :link, :date
|
13
|
+
|
14
|
+
def initialize(event)
|
15
|
+
@id = event[:id] or raise MissingAttributeError.new("id is missing")
|
16
|
+
@title = event[:title] or raise MissingAttributeError.new("title is missing")
|
17
|
+
@link = event[:link] or raise MissingAttributeError.new("link is missing")
|
18
|
+
@date = event[:date]
|
19
|
+
end
|
20
|
+
|
21
|
+
def provider
|
22
|
+
@provider ||= self.class.name
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
Database.save self
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def exists?
|
31
|
+
Database.exists? self
|
32
|
+
end
|
33
|
+
|
34
|
+
def ==(other)
|
35
|
+
id == other.id && provider == other.provider
|
36
|
+
end
|
37
|
+
|
38
|
+
alias_method :eql?, :==
|
39
|
+
|
40
|
+
def hash
|
41
|
+
"#{id}-#{provider}-#{link}".hash
|
42
|
+
end
|
43
|
+
|
44
|
+
def <=>(other)
|
45
|
+
title <=> other.title
|
46
|
+
end
|
47
|
+
|
48
|
+
MissingAttributeError = Class.new(RuntimeError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
module Eventify::Provider
|
5
|
+
class FBI < Base
|
6
|
+
URL = "http://www.fbi.ee/"
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def fetch
|
10
|
+
doc = Nokogiri::HTML(open(URL))
|
11
|
+
doc.search(".article-list li h2 a").map do |a|
|
12
|
+
new id: a["href"], title: a.content, link: a["href"], date: Time.now
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "simple-rss"
|
2
|
+
require "open-uri"
|
3
|
+
|
4
|
+
module Eventify::Provider
|
5
|
+
class Piletilevi < Base
|
6
|
+
# http://www.piletilevi.ee/est/uldinfo/rss
|
7
|
+
URLS = [
|
8
|
+
"http://www.piletilevi.ee/news.rss.php?path=est/uudised",
|
9
|
+
"http://www.piletilevi.ee/news.rss.php?path=est/teatriuudised",
|
10
|
+
"http://www.piletilevi.ee/news.rss.php?path=est/muudatused",
|
11
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/muusika",
|
12
|
+
# 404?
|
13
|
+
#"http://www.piletilevi.ee/category.rss.php?path=est/piletid/teater_-_kunst",
|
14
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/kogupere",
|
15
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/sport",
|
16
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/festival",
|
17
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/film",
|
18
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/kinkekaardid",
|
19
|
+
"http://www.piletilevi.ee/category.rss.php?path=est/piletid/varia"
|
20
|
+
]
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def fetch
|
24
|
+
URLS.each.reduce([]) do |memo, url|
|
25
|
+
rss = SimpleRSS.parse open(url)
|
26
|
+
memo + rss.entries.map { |entry| new id: entry.guid, title: entry.title, link: entry.link, date: entry.pubDate }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|