apdm 0.0.15

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.
Files changed (139) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +4 -0
  5. data/README.md +223 -0
  6. data/Rakefile +1 -0
  7. data/apdm.gemspec +34 -0
  8. data/bin/apdm +6 -0
  9. data/features/ad_tech.feature +11 -0
  10. data/features/step_definitions/ad_tech_steps.rb +19 -0
  11. data/features/support/env.rb +5 -0
  12. data/fixtures/approvals/ad_tech_loader_scripts.approved.txt +42 -0
  13. data/fixtures/approvals/ad_tech_placeholders.approved.txt +6 -0
  14. data/lib/apdm.rb +24 -0
  15. data/lib/apdm/ad_tech.rb +96 -0
  16. data/lib/apdm/ad_tech/ad_loader.rb +67 -0
  17. data/lib/apdm/ad_tech/ads.csv +475 -0
  18. data/lib/apdm/ad_tech/data.rb +47 -0
  19. data/lib/apdm/channel.rb +87 -0
  20. data/lib/apdm/channels.rb +569 -0
  21. data/lib/apdm/credentials.rb +26 -0
  22. data/lib/apdm/design_elements.rb +60 -0
  23. data/lib/apdm/design_elements/api.rb +75 -0
  24. data/lib/apdm/feed.rb +65 -0
  25. data/lib/apdm/issues.rb +14 -0
  26. data/lib/apdm/issues/aasavis.rb +51 -0
  27. data/lib/apdm/issues/amta.rb +253 -0
  28. data/lib/apdm/issues/an.rb +302 -0
  29. data/lib/apdm/issues/auraavis.rb +154 -0
  30. data/lib/apdm/issues/austagderblad.rb +154 -0
  31. data/lib/apdm/issues/avisa-hordaland.rb +154 -0
  32. data/lib/apdm/issues/avisa-valdres.rb +177 -0
  33. data/lib/apdm/issues/ba.rb +352 -0
  34. data/lib/apdm/issues/bladet.rb +154 -0
  35. data/lib/apdm/issues/blv.rb +254 -0
  36. data/lib/apdm/issues/bygdeposten.rb +154 -0
  37. data/lib/apdm/issues/demokraten.rb +154 -0
  38. data/lib/apdm/issues/eikerbladet.rb +409 -0
  39. data/lib/apdm/issues/enebakkavis.rb +51 -0
  40. data/lib/apdm/issues/etl.rb +79 -0
  41. data/lib/apdm/issues/eub.rb +254 -0
  42. data/lib/apdm/issues/finnmarkdagblad.rb +302 -0
  43. data/lib/apdm/issues/finnmarken.rb +302 -0
  44. data/lib/apdm/issues/firda.rb +302 -0
  45. data/lib/apdm/issues/firdaposten.rb +153 -0
  46. data/lib/apdm/issues/fremover.rb +304 -0
  47. data/lib/apdm/issues/gd.rb +304 -0
  48. data/lib/apdm/issues/glomdalen.rb +302 -0
  49. data/lib/apdm/issues/ha-halden.rb +302 -0
  50. data/lib/apdm/issues/hadeland.rb +251 -0
  51. data/lib/apdm/issues/hardanger-folkeblad.rb +151 -0
  52. data/lib/apdm/issues/helgeland-arbeiderblad.rb +304 -0
  53. data/lib/apdm/issues/import.csv +12821 -0
  54. data/lib/apdm/issues/indre.rb +151 -0
  55. data/lib/apdm/issues/jarlsbergavis.rb +154 -0
  56. data/lib/apdm/issues/kvinnheringen.rb +202 -0
  57. data/lib/apdm/issues/lofot-tidende.rb +102 -0
  58. data/lib/apdm/issues/lofotposten.rb +304 -0
  59. data/lib/apdm/issues/mb.rb +103 -0
  60. data/lib/apdm/issues/namdalsavisa.rb +302 -0
  61. data/lib/apdm/issues/nordhordland.rb +103 -0
  62. data/lib/apdm/issues/nordlys.rb +304 -0
  63. data/lib/apdm/issues/oa.rb +302 -0
  64. data/lib/apdm/issues/op.rb +304 -0
  65. data/lib/apdm/issues/opdalingen.rb +150 -0
  66. data/lib/apdm/issues/oyene.rb +51 -0
  67. data/lib/apdm/issues/pd.rb +254 -0
  68. data/lib/apdm/issues/r-a.rb +152 -0
  69. data/lib/apdm/issues/ranablad.rb +304 -0
  70. data/lib/apdm/issues/rb.rb +302 -0
  71. data/lib/apdm/issues/retten.rb +151 -0
  72. data/lib/apdm/issues/ringblad.rb +304 -0
  73. data/lib/apdm/issues/rogalandsavis.rb +302 -0
  74. data/lib/apdm/issues/sa.rb +304 -0
  75. data/lib/apdm/issues/smaalenene.rb +304 -0
  76. data/lib/apdm/issues/sognavis.rb +254 -0
  77. data/lib/apdm/issues/ta.rb +304 -0
  78. data/lib/apdm/issues/tk.rb +304 -0
  79. data/lib/apdm/issues/tvedestrandsposten.rb +150 -0
  80. data/lib/apdm/issues/vestbyavis.rb +51 -0
  81. data/lib/apdm/local_paper_area.rb +21 -0
  82. data/lib/apdm/network.rb +49 -0
  83. data/lib/apdm/null_cache.rb +15 -0
  84. data/lib/apdm/origo.rb +46 -0
  85. data/lib/apdm/saxo.rb +58 -0
  86. data/lib/apdm/saxo/iptc.rb +69 -0
  87. data/lib/apdm/saxo/metadata.rb +36 -0
  88. data/lib/apdm/saxo/remote.rb +67 -0
  89. data/lib/apdm/sinatra.rb +85 -0
  90. data/lib/apdm/version.rb +3 -0
  91. data/lib/cli.rb +12 -0
  92. data/spec/ad_tech/ad_loader_spec.rb +27 -0
  93. data/spec/ad_tech/data_spec.rb +14 -0
  94. data/spec/ad_tech_spec.rb +70 -0
  95. data/spec/approvals_helper.rb +6 -0
  96. data/spec/channel_spec.rb +91 -0
  97. data/spec/channels_spec.rb +9 -0
  98. data/spec/credentials_integration_spec.rb +13 -0
  99. data/spec/credentials_spec.rb +34 -0
  100. data/spec/design_elements_spec.rb +132 -0
  101. data/spec/feed_spec.rb +49 -0
  102. data/spec/fixtures/ad_tech.csv +6 -0
  103. data/spec/fixtures/approvals/adtech/ad_loader.approved.txt +9 -0
  104. data/spec/fixtures/approvals/apdm_adtech/data/handles_artikkelboard.approved.txt +10 -0
  105. data/spec/fixtures/approvals/apdm_adtech/data/handles_bunnbanner.approved.txt +10 -0
  106. data/spec/fixtures/approvals/apdm_adtech/data/handles_skyskraper_1.approved.txt +10 -0
  107. data/spec/fixtures/approvals/apdm_adtech/data/handles_toppbanner.approved.txt +10 -0
  108. data/spec/fixtures/approvals/apdm_adtech/data/is_ok_with_new_bandwagon_data.approved.txt +10 -0
  109. data/spec/fixtures/approvals/apdm_adtech/data/loads_default_data.approved.txt +10 -0
  110. data/spec/fixtures/approvals/apdm_designelements/css/via_api.approved.txt +23 -0
  111. data/spec/fixtures/approvals/apdm_designelements/footer_html/via_api.approved.html +85 -0
  112. data/spec/fixtures/approvals/apdm_designelements/header_html/via_api.approved.html +40 -0
  113. data/spec/fixtures/approvals/apdm_designelements/tracking_scripts/api/keyword.approved.txt +54 -0
  114. data/spec/fixtures/approvals/apdm_designelements/tracking_scripts/api/placeholder.approved.txt +54 -0
  115. data/spec/fixtures/issues.csv +3 -0
  116. data/spec/fixtures/test.jpg +0 -0
  117. data/spec/fixtures/vcr_cassettes/apdm_credentials.yml +44 -0
  118. data/spec/fixtures/vcr_cassettes/css.yml +5588 -0
  119. data/spec/fixtures/vcr_cassettes/footer-html.yml +178 -0
  120. data/spec/fixtures/vcr_cassettes/header-html.yml +132 -0
  121. data/spec/fixtures/vcr_cassettes/origo_someone_credentials.yml +43 -0
  122. data/spec/fixtures/vcr_cassettes/origo_westerdal_credentials.yml +56 -0
  123. data/spec/fixtures/vcr_cassettes/site_stat.yml +172 -0
  124. data/spec/fixtures/vcr_cassettes/site_stat_custom_category.yml +172 -0
  125. data/spec/geo_spec.rb +10 -0
  126. data/spec/issues_etl_spec.rb +41 -0
  127. data/spec/mockcached.rb +36 -0
  128. data/spec/network_spec.rb +43 -0
  129. data/spec/null_cache_spec.rb +29 -0
  130. data/spec/origo_spec.rb +24 -0
  131. data/spec/saxo/iptc_spec.rb +105 -0
  132. data/spec/saxo/metadata_spec.rb +79 -0
  133. data/spec/saxo/remote_spec.rb +71 -0
  134. data/spec/saxo/saxo_spec.rb +82 -0
  135. data/spec/spec_helper.rb +22 -0
  136. data/spec/vcr_helper.rb +6 -0
  137. data/test/fixtures/config-example.yml +6 -0
  138. data/test/saxo/acceptance_spec.rb +109 -0
  139. 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
+
@@ -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
@@ -0,0 +1,15 @@
1
+ module APDM
2
+ class NullCache
3
+ def set(*args)
4
+ # Elegantly does exactly nothing.
5
+ end
6
+
7
+ def get(*args)
8
+ # Nothing is cached; nothing to get.
9
+ end
10
+
11
+ def delete(*args)
12
+ # It's already gone.
13
+ end
14
+ end
15
+ end
@@ -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
@@ -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
@@ -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