apdm 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +223 -0
- data/Rakefile +1 -0
- data/apdm.gemspec +34 -0
- data/bin/apdm +6 -0
- data/features/ad_tech.feature +11 -0
- data/features/step_definitions/ad_tech_steps.rb +19 -0
- data/features/support/env.rb +5 -0
- data/fixtures/approvals/ad_tech_loader_scripts.approved.txt +42 -0
- data/fixtures/approvals/ad_tech_placeholders.approved.txt +6 -0
- data/lib/apdm.rb +24 -0
- data/lib/apdm/ad_tech.rb +96 -0
- data/lib/apdm/ad_tech/ad_loader.rb +67 -0
- data/lib/apdm/ad_tech/ads.csv +475 -0
- data/lib/apdm/ad_tech/data.rb +47 -0
- data/lib/apdm/channel.rb +87 -0
- data/lib/apdm/channels.rb +569 -0
- data/lib/apdm/credentials.rb +26 -0
- data/lib/apdm/design_elements.rb +60 -0
- data/lib/apdm/design_elements/api.rb +75 -0
- data/lib/apdm/feed.rb +65 -0
- data/lib/apdm/issues.rb +14 -0
- data/lib/apdm/issues/aasavis.rb +51 -0
- data/lib/apdm/issues/amta.rb +253 -0
- data/lib/apdm/issues/an.rb +302 -0
- data/lib/apdm/issues/auraavis.rb +154 -0
- data/lib/apdm/issues/austagderblad.rb +154 -0
- data/lib/apdm/issues/avisa-hordaland.rb +154 -0
- data/lib/apdm/issues/avisa-valdres.rb +177 -0
- data/lib/apdm/issues/ba.rb +352 -0
- data/lib/apdm/issues/bladet.rb +154 -0
- data/lib/apdm/issues/blv.rb +254 -0
- data/lib/apdm/issues/bygdeposten.rb +154 -0
- data/lib/apdm/issues/demokraten.rb +154 -0
- data/lib/apdm/issues/eikerbladet.rb +409 -0
- data/lib/apdm/issues/enebakkavis.rb +51 -0
- data/lib/apdm/issues/etl.rb +79 -0
- data/lib/apdm/issues/eub.rb +254 -0
- data/lib/apdm/issues/finnmarkdagblad.rb +302 -0
- data/lib/apdm/issues/finnmarken.rb +302 -0
- data/lib/apdm/issues/firda.rb +302 -0
- data/lib/apdm/issues/firdaposten.rb +153 -0
- data/lib/apdm/issues/fremover.rb +304 -0
- data/lib/apdm/issues/gd.rb +304 -0
- data/lib/apdm/issues/glomdalen.rb +302 -0
- data/lib/apdm/issues/ha-halden.rb +302 -0
- data/lib/apdm/issues/hadeland.rb +251 -0
- data/lib/apdm/issues/hardanger-folkeblad.rb +151 -0
- data/lib/apdm/issues/helgeland-arbeiderblad.rb +304 -0
- data/lib/apdm/issues/import.csv +12821 -0
- data/lib/apdm/issues/indre.rb +151 -0
- data/lib/apdm/issues/jarlsbergavis.rb +154 -0
- data/lib/apdm/issues/kvinnheringen.rb +202 -0
- data/lib/apdm/issues/lofot-tidende.rb +102 -0
- data/lib/apdm/issues/lofotposten.rb +304 -0
- data/lib/apdm/issues/mb.rb +103 -0
- data/lib/apdm/issues/namdalsavisa.rb +302 -0
- data/lib/apdm/issues/nordhordland.rb +103 -0
- data/lib/apdm/issues/nordlys.rb +304 -0
- data/lib/apdm/issues/oa.rb +302 -0
- data/lib/apdm/issues/op.rb +304 -0
- data/lib/apdm/issues/opdalingen.rb +150 -0
- data/lib/apdm/issues/oyene.rb +51 -0
- data/lib/apdm/issues/pd.rb +254 -0
- data/lib/apdm/issues/r-a.rb +152 -0
- data/lib/apdm/issues/ranablad.rb +304 -0
- data/lib/apdm/issues/rb.rb +302 -0
- data/lib/apdm/issues/retten.rb +151 -0
- data/lib/apdm/issues/ringblad.rb +304 -0
- data/lib/apdm/issues/rogalandsavis.rb +302 -0
- data/lib/apdm/issues/sa.rb +304 -0
- data/lib/apdm/issues/smaalenene.rb +304 -0
- data/lib/apdm/issues/sognavis.rb +254 -0
- data/lib/apdm/issues/ta.rb +304 -0
- data/lib/apdm/issues/tk.rb +304 -0
- data/lib/apdm/issues/tvedestrandsposten.rb +150 -0
- data/lib/apdm/issues/vestbyavis.rb +51 -0
- data/lib/apdm/local_paper_area.rb +21 -0
- data/lib/apdm/network.rb +49 -0
- data/lib/apdm/null_cache.rb +15 -0
- data/lib/apdm/origo.rb +46 -0
- data/lib/apdm/saxo.rb +58 -0
- data/lib/apdm/saxo/iptc.rb +69 -0
- data/lib/apdm/saxo/metadata.rb +36 -0
- data/lib/apdm/saxo/remote.rb +67 -0
- data/lib/apdm/sinatra.rb +85 -0
- data/lib/apdm/version.rb +3 -0
- data/lib/cli.rb +12 -0
- data/spec/ad_tech/ad_loader_spec.rb +27 -0
- data/spec/ad_tech/data_spec.rb +14 -0
- data/spec/ad_tech_spec.rb +70 -0
- data/spec/approvals_helper.rb +6 -0
- data/spec/channel_spec.rb +91 -0
- data/spec/channels_spec.rb +9 -0
- data/spec/credentials_integration_spec.rb +13 -0
- data/spec/credentials_spec.rb +34 -0
- data/spec/design_elements_spec.rb +132 -0
- data/spec/feed_spec.rb +49 -0
- data/spec/fixtures/ad_tech.csv +6 -0
- data/spec/fixtures/approvals/adtech/ad_loader.approved.txt +9 -0
- data/spec/fixtures/approvals/apdm_adtech/data/handles_artikkelboard.approved.txt +10 -0
- data/spec/fixtures/approvals/apdm_adtech/data/handles_bunnbanner.approved.txt +10 -0
- data/spec/fixtures/approvals/apdm_adtech/data/handles_skyskraper_1.approved.txt +10 -0
- data/spec/fixtures/approvals/apdm_adtech/data/handles_toppbanner.approved.txt +10 -0
- data/spec/fixtures/approvals/apdm_adtech/data/is_ok_with_new_bandwagon_data.approved.txt +10 -0
- data/spec/fixtures/approvals/apdm_adtech/data/loads_default_data.approved.txt +10 -0
- data/spec/fixtures/approvals/apdm_designelements/css/via_api.approved.txt +23 -0
- data/spec/fixtures/approvals/apdm_designelements/footer_html/via_api.approved.html +85 -0
- data/spec/fixtures/approvals/apdm_designelements/header_html/via_api.approved.html +40 -0
- data/spec/fixtures/approvals/apdm_designelements/tracking_scripts/api/keyword.approved.txt +54 -0
- data/spec/fixtures/approvals/apdm_designelements/tracking_scripts/api/placeholder.approved.txt +54 -0
- data/spec/fixtures/issues.csv +3 -0
- data/spec/fixtures/test.jpg +0 -0
- data/spec/fixtures/vcr_cassettes/apdm_credentials.yml +44 -0
- data/spec/fixtures/vcr_cassettes/css.yml +5588 -0
- data/spec/fixtures/vcr_cassettes/footer-html.yml +178 -0
- data/spec/fixtures/vcr_cassettes/header-html.yml +132 -0
- data/spec/fixtures/vcr_cassettes/origo_someone_credentials.yml +43 -0
- data/spec/fixtures/vcr_cassettes/origo_westerdal_credentials.yml +56 -0
- data/spec/fixtures/vcr_cassettes/site_stat.yml +172 -0
- data/spec/fixtures/vcr_cassettes/site_stat_custom_category.yml +172 -0
- data/spec/geo_spec.rb +10 -0
- data/spec/issues_etl_spec.rb +41 -0
- data/spec/mockcached.rb +36 -0
- data/spec/network_spec.rb +43 -0
- data/spec/null_cache_spec.rb +29 -0
- data/spec/origo_spec.rb +24 -0
- data/spec/saxo/iptc_spec.rb +105 -0
- data/spec/saxo/metadata_spec.rb +79 -0
- data/spec/saxo/remote_spec.rb +71 -0
- data/spec/saxo/saxo_spec.rb +82 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/vcr_helper.rb +6 -0
- data/test/fixtures/config-example.yml +6 -0
- data/test/saxo/acceptance_spec.rb +109 -0
- metadata +427 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
APDM::ISSUES['vestbyavis'] = [
|
2
|
+
Date.parse('2013-01-03'),
|
3
|
+
Date.parse('2013-01-10'),
|
4
|
+
Date.parse('2013-01-17'),
|
5
|
+
Date.parse('2013-01-24'),
|
6
|
+
Date.parse('2013-01-31'),
|
7
|
+
Date.parse('2013-02-07'),
|
8
|
+
Date.parse('2013-02-14'),
|
9
|
+
Date.parse('2013-02-21'),
|
10
|
+
Date.parse('2013-02-28'),
|
11
|
+
Date.parse('2013-03-07'),
|
12
|
+
Date.parse('2013-03-14'),
|
13
|
+
Date.parse('2013-03-21'),
|
14
|
+
Date.parse('2013-04-04'),
|
15
|
+
Date.parse('2013-04-11'),
|
16
|
+
Date.parse('2013-04-18'),
|
17
|
+
Date.parse('2013-04-25'),
|
18
|
+
Date.parse('2013-05-02'),
|
19
|
+
Date.parse('2013-05-16'),
|
20
|
+
Date.parse('2013-05-23'),
|
21
|
+
Date.parse('2013-05-30'),
|
22
|
+
Date.parse('2013-06-06'),
|
23
|
+
Date.parse('2013-06-13'),
|
24
|
+
Date.parse('2013-06-20'),
|
25
|
+
Date.parse('2013-06-27'),
|
26
|
+
Date.parse('2013-07-04'),
|
27
|
+
Date.parse('2013-07-11'),
|
28
|
+
Date.parse('2013-07-18'),
|
29
|
+
Date.parse('2013-07-25'),
|
30
|
+
Date.parse('2013-08-01'),
|
31
|
+
Date.parse('2013-08-08'),
|
32
|
+
Date.parse('2013-08-15'),
|
33
|
+
Date.parse('2013-08-22'),
|
34
|
+
Date.parse('2013-08-29'),
|
35
|
+
Date.parse('2013-09-05'),
|
36
|
+
Date.parse('2013-09-12'),
|
37
|
+
Date.parse('2013-09-19'),
|
38
|
+
Date.parse('2013-09-26'),
|
39
|
+
Date.parse('2013-10-03'),
|
40
|
+
Date.parse('2013-10-10'),
|
41
|
+
Date.parse('2013-10-17'),
|
42
|
+
Date.parse('2013-10-24'),
|
43
|
+
Date.parse('2013-10-31'),
|
44
|
+
Date.parse('2013-11-07'),
|
45
|
+
Date.parse('2013-11-14'),
|
46
|
+
Date.parse('2013-11-21'),
|
47
|
+
Date.parse('2013-11-28'),
|
48
|
+
Date.parse('2013-12-05'),
|
49
|
+
Date.parse('2013-12-12'),
|
50
|
+
Date.parse('2013-12-19')
|
51
|
+
]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rgeo'
|
2
|
+
require 'rgeo-geojson'
|
3
|
+
|
4
|
+
module APDM
|
5
|
+
class LocalPaperArea
|
6
|
+
|
7
|
+
attr_reader :feature, :factory
|
8
|
+
def initialize(geojson)
|
9
|
+
@factory = RGeo::Geographic.spherical_factory
|
10
|
+
@feature = RGeo::GeoJSON.decode(geojson, :json_parser => :json)
|
11
|
+
end
|
12
|
+
|
13
|
+
def contains?(lon, lat)
|
14
|
+
feature.contains? factory.point(lon, lat)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
EmptyGeoHash = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[]]]}"
|
19
|
+
|
20
|
+
end
|
21
|
+
|
data/lib/apdm/network.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
|
3
|
+
module APDM
|
4
|
+
|
5
|
+
class Network
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :channels
|
9
|
+
def initialize
|
10
|
+
@channels = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
@channels.each {|c| yield c}
|
15
|
+
end
|
16
|
+
|
17
|
+
def <<(channel)
|
18
|
+
@channels << channel
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_by_label(label)
|
22
|
+
find do |channel|
|
23
|
+
channel.label == label
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_by_ad_tech_id(id)
|
28
|
+
find do |channel|
|
29
|
+
channel.ad_tech_id == id.to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_by_url(url)
|
34
|
+
return nil unless (url && url[/\./])
|
35
|
+
label = url.gsub(/https?:\/\//, '')[/([^\.]+\.[^\.]+)$/, 1].gsub(/\.\w+$/, '')
|
36
|
+
find_by_label(label)
|
37
|
+
end
|
38
|
+
|
39
|
+
def random_production_channel
|
40
|
+
# used to display ads from a random channel
|
41
|
+
@channels.reject{|c| c.ad_tech_id.nil? || c.label == 'avisnavn' || c.label == 'moss-dagblad' }.sample
|
42
|
+
end
|
43
|
+
|
44
|
+
# DEPRECATED
|
45
|
+
def find_by_domain(url)
|
46
|
+
find_by_url(url)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/apdm/origo.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'curb'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# Hackish origo knowledge
|
5
|
+
module APDM
|
6
|
+
class Origo
|
7
|
+
|
8
|
+
# Found in the Origo console with
|
9
|
+
# Organization.find_by_title('A-pressen').children.map(&:id)
|
10
|
+
APRESSEN = [29, 34, 35, 39, 40, 42, 44, 47, 56, 64, 67, 69, 82, 94, 95, 99, 134, 139, 154, 155, 162, 232, 242, 264, 287, 317, 386, 401, 420, 433, 456, 462, 597, 12455, 12617, 12733, 12735, 12737, 12802, 12886, 13036, 13038, 13041, 13042]
|
11
|
+
|
12
|
+
BENGLER = [22]
|
13
|
+
|
14
|
+
ORGANIZATIONS = APRESSEN + BENGLER
|
15
|
+
|
16
|
+
def self.organization?(id)
|
17
|
+
ORGANIZATIONS.include?(id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.fetch_credentials(id)
|
21
|
+
api.fetch_credentials(id)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.api
|
25
|
+
@api ||= API.new
|
26
|
+
end
|
27
|
+
|
28
|
+
class API
|
29
|
+
# Credentials in Origo relate a person to an organization via a role.
|
30
|
+
# An 'authorized' role means that a human has actually
|
31
|
+
# eyeballed the credential and said: "Yeah, this is true."
|
32
|
+
# A 'privileged' role, gives the person god-like powers in the
|
33
|
+
# organization, but only works if actually authorized.
|
34
|
+
def fetch_credentials(id)
|
35
|
+
credentials = JSON.parse(Curl::Easy.http_get("#{url}#{id}").body_str)
|
36
|
+
credentials.select {|credential| Origo.organization?(credential["organization"]["id"]) }
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def url
|
41
|
+
"http://origo.no/-/api/v2/credential/find?api_key=49rgnfu9tdtovs1bn2k9xbdq141thogpjbll3bn460d559gk0o&include_organization=true&user_id="
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/apdm/saxo.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'net/ftp'
|
2
|
+
require 'open3'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
require "apdm/saxo/metadata"
|
7
|
+
require "apdm/saxo/iptc"
|
8
|
+
require "apdm/saxo/remote"
|
9
|
+
|
10
|
+
module APDM
|
11
|
+
class Saxo
|
12
|
+
class InvalidConfig < Exception; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_writer :logger
|
16
|
+
def logger
|
17
|
+
unless @logger
|
18
|
+
FileUtils.mkdir('log') unless File.exists?('log')
|
19
|
+
@logger = Logger.new('log/saxo.log')
|
20
|
+
end
|
21
|
+
@logger
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_accessor :server, :username, :password, :remote_dir
|
26
|
+
def initialize(options = {})
|
27
|
+
options.each {|k,v| validate(k, v)}
|
28
|
+
|
29
|
+
self.server = options[:server] || options['server']
|
30
|
+
self.username = options[:username] || options['username']
|
31
|
+
self.password = options[:password] || options['password']
|
32
|
+
self.remote_dir = (options[:remote_dir] || options['remote_dir']).upcase
|
33
|
+
end
|
34
|
+
|
35
|
+
def write(metadata)
|
36
|
+
Metadata.new(metadata)
|
37
|
+
end
|
38
|
+
|
39
|
+
def transfer(photo)
|
40
|
+
Remote.new(self, photo).transfer
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def validate(key, value)
|
45
|
+
if required?(key) && !valid?(value)
|
46
|
+
raise InvalidConfig.new("#{key} is required!")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def required?(key)
|
51
|
+
[:server, :username, :password, :remote_dir].include? key.to_sym
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid?(value)
|
55
|
+
!value.nil? && value != ""
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module APDM
|
2
|
+
class Saxo
|
3
|
+
class IPTC
|
4
|
+
|
5
|
+
attr_accessor :name, :path, :file, :source
|
6
|
+
def initialize(name, path, options = {})
|
7
|
+
self.source = options[:source]
|
8
|
+
self.name = name
|
9
|
+
self.path = path
|
10
|
+
self.file = "#{path.chomp('/')}/#{name}"
|
11
|
+
duplicate options[:file] if options[:file]
|
12
|
+
end
|
13
|
+
|
14
|
+
def duplicate(original)
|
15
|
+
FileUtils.cp(original, file)
|
16
|
+
end
|
17
|
+
|
18
|
+
def logger
|
19
|
+
APDM::Saxo.logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(data = {})
|
23
|
+
download if source
|
24
|
+
delete_metadata
|
25
|
+
write_metadata(data)
|
26
|
+
end
|
27
|
+
|
28
|
+
def download
|
29
|
+
logger.info "Downloading #{source}."
|
30
|
+
begin
|
31
|
+
File.open(file, "wb") do |f|
|
32
|
+
o = open(source)
|
33
|
+
r = o.read
|
34
|
+
f.write r
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
raise $!, "Problem downloading image with file: #{file} and source: #{source}. #{$!}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_metadata
|
42
|
+
logger.info "Deleting metadata on #{file}."
|
43
|
+
command = "exiv2 -d a delete #{file}"
|
44
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
45
|
+
if stderr.gets
|
46
|
+
logger.warn "Could not delete metadata: #{stderr.gets}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_metadata(data = {})
|
52
|
+
logger.info "Writing metadata to #{file}."
|
53
|
+
write_value('ObjectName', name)
|
54
|
+
data.each do |key, value|
|
55
|
+
write_value(key.to_s.capitalize, value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def write_value(key, value)
|
60
|
+
command = "exiv2 -M \"set Iptc.Application2.#{key} String #{value}\" #{file}"
|
61
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
62
|
+
if stderr.gets
|
63
|
+
logger.warn "Failed to write #{value} to #{key}: #{stderr.gets}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module APDM
|
3
|
+
class Saxo
|
4
|
+
class Metadata
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def sanitize(s)
|
8
|
+
s.gsub(/`/, "'").gsub(/´/, '\'').gsub(/"/, '\"').gsub('<3', ':heart:').gsub(/[<>]/, '').squeeze(' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_iso88591(utf8_string)
|
12
|
+
utf8_string.encode(Encoding::ISO_8859_1, Encoding::UTF_8, :undef => :replace)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :metadata
|
17
|
+
|
18
|
+
def initialize(data = {})
|
19
|
+
data = data.dup
|
20
|
+
self.metadata = data.each {|k,v| data[k] = convert(Metadata.sanitize(v))}
|
21
|
+
end
|
22
|
+
|
23
|
+
def to(name, path, options = {})
|
24
|
+
iptc = IPTC.new(name, path, options)
|
25
|
+
iptc.write(metadata)
|
26
|
+
iptc
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def convert(value)
|
32
|
+
Metadata.to_iso88591(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module APDM
|
2
|
+
|
3
|
+
class SaxoTransferError < StandardError; end
|
4
|
+
|
5
|
+
class Saxo
|
6
|
+
class Remote
|
7
|
+
|
8
|
+
attr_accessor :saxo, :photo, :local_size, :remote_size
|
9
|
+
def initialize(saxo, photo)
|
10
|
+
self.saxo = saxo
|
11
|
+
self.photo = photo
|
12
|
+
end
|
13
|
+
|
14
|
+
def logger
|
15
|
+
APDM::Saxo.logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def source
|
19
|
+
@source ||= photo.file
|
20
|
+
end
|
21
|
+
|
22
|
+
def destination
|
23
|
+
@destination ||= "#{saxo.remote_dir}/#{photo.name}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def transfer
|
27
|
+
logger.info("Begin transfer of #{source} to #{destination}")
|
28
|
+
Timeout.timeout(30) do
|
29
|
+
Net::FTP.open(saxo.server, saxo.username, saxo.password) do |ftp|
|
30
|
+
Timeout.timeout(20) do
|
31
|
+
upload(ftp)
|
32
|
+
end
|
33
|
+
Timeout.timeout(10) do
|
34
|
+
cleanup(ftp)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return true if transfer_succeeded?
|
39
|
+
|
40
|
+
raise SaxoTransferError("Upload failed [#{local_size}/#{remote_size}]. Source: #{source} -- destination: #{destination}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def upload(ftp)
|
44
|
+
ftp.passive = true
|
45
|
+
ftp.putbinaryfile(source, destination)
|
46
|
+
self.remote_size = ftp.size(destination)
|
47
|
+
end
|
48
|
+
|
49
|
+
def cleanup(ftp)
|
50
|
+
if transfer_succeeded?
|
51
|
+
File.delete(source)
|
52
|
+
else
|
53
|
+
ftp.delete(destination)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def transfer_succeeded?
|
58
|
+
local_size == remote_size
|
59
|
+
end
|
60
|
+
|
61
|
+
def local_size
|
62
|
+
@local_size ||= File.size(source)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/apdm/sinatra.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "apdm"
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module APDM
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
def current_channel
|
8
|
+
host = request.env['HTTP_X_FORWARDED_HOST'] || request.host
|
9
|
+
::APDM::Channel.find_by_domain(host) || ::APDM::Channel.find_by_domain("avisnavn.no")
|
10
|
+
end
|
11
|
+
|
12
|
+
def design_elements
|
13
|
+
@design_elements ||= ::APDM::DesignElements.new(current_channel.label, :api_key => self.settings.design_elements_api_key)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ad_tech
|
17
|
+
ad_tech_for(::APDM::CHANNELS.random_production_channel)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ad_tech_for(channel)
|
21
|
+
@ad_tech_for ||= {}
|
22
|
+
@ad_tech_for[channel.label] ||= ::APDM::AdTech.new(channel, :context_key => self.settings.ad_tech_context_prefix)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ad_tech_api_js
|
26
|
+
# This snippet is needed by the ad_tech scripts and should be included in the head tag of pages displaying ad_tech ads
|
27
|
+
# Note: its an extract of code found in apdm JavaScript as per august 2012 and may be cause future breakage
|
28
|
+
# It hurts but it works
|
29
|
+
<<-js
|
30
|
+
window.api = {"cookie": {
|
31
|
+
"del": function (name,path,domain){var cookie=name+"="+((path)?";path="+path:"");cookie+=((domain)?";domain="+domain:"");cookie+=";expires=Thu, 01-Jan-1970 00:00:01 GMT";if(this.get(name)){document.cookie=cookie;}},
|
32
|
+
"get": function (name){var dc=document.cookie;if(dc===""){return false;}},
|
33
|
+
"isOn": function (){this.set("apiCookiesOnCheck","true",365);return(this.get("apiCookiesOnCheck")=="true");},
|
34
|
+
"set": function (name,value,expires,path,domain,secure){var fDate=new Date();var exDate=fDate.getTime();exDate+=1000*3600*24*expires;fDate.setTime(exDate);name+="="+escape(value)+((expires)?"; expires="+fDate.toGMTString():"");name+=((path)?"; path="+path:"");name+=((domain)?"; domain="+domain:"");name+=((secure)?"; secure":"");document.cookie=name;}
|
35
|
+
}};
|
36
|
+
js
|
37
|
+
end
|
38
|
+
|
39
|
+
def design_elements_css_path
|
40
|
+
"#{request.script_name}/apdm-design-elements.css"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.registered(app)
|
45
|
+
app.get '/apdm-design-elements.css' do
|
46
|
+
headers('Content-Type' => 'text/css', 'X-Content-Type-Options' => 'nosniff')
|
47
|
+
design_elements.css
|
48
|
+
end
|
49
|
+
|
50
|
+
app.helpers(Sinatra::APDM::Helpers)
|
51
|
+
end
|
52
|
+
|
53
|
+
def apdm_configure(&blk)
|
54
|
+
self.instance_exec(&blk)
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_design_elements_api_key(api_key)
|
58
|
+
set :design_elements_api_key, api_key
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_ad_tech_context_prefix(context_prefix)
|
62
|
+
set :ad_tech_context_prefix, context_prefix
|
63
|
+
end
|
64
|
+
|
65
|
+
# Here be workarounds for the diabolical evil apdm proxy
|
66
|
+
def enable_apdm_proxy_workarounds
|
67
|
+
before do
|
68
|
+
# Enforce a trailing slash for root requests.
|
69
|
+
# i.e. /vis/bandwagon ==redirects to==> /vis/bandwagon/
|
70
|
+
# The evil apdm proxy sets cookies on path with trailing slash (e.g. /vis/bandwagon/)
|
71
|
+
# so a user entering /vis/bandwagon (without trailing slash) will loose its credentials. This is the workaround.
|
72
|
+
if request.path_info == '/' and not request.env['REQUEST_PATH'].match(/\/$/)
|
73
|
+
redirect request.env['REQUEST_PATH']+"/"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Cache headers required/recommended by the apdm proxy
|
79
|
+
def enable_apdm_cache_headers
|
80
|
+
before do
|
81
|
+
cache_control :private, :no_cache, :no_store, :must_revalidate
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|