advert_selector 1.0.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.
Files changed (151) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +132 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/advert_selector/application.js +15 -0
  5. data/app/assets/stylesheets/advert_selector/application.css +29 -0
  6. data/app/controllers/advert_selector/application_controller.rb +26 -0
  7. data/app/controllers/advert_selector/banners_controller.rb +122 -0
  8. data/app/controllers/advert_selector/main_controller.rb +13 -0
  9. data/app/controllers/advert_selector/placements_controller.rb +89 -0
  10. data/app/helpers/advert_selector/application_helper.rb +155 -0
  11. data/app/models/advert_selector/banner.rb +107 -0
  12. data/app/models/advert_selector/helper_item.rb +21 -0
  13. data/app/models/advert_selector/placement.rb +58 -0
  14. data/app/views/advert_selector/banners/_form.html.erb +42 -0
  15. data/app/views/advert_selector/banners/edit.html.erb +29 -0
  16. data/app/views/advert_selector/banners/index.html.erb +38 -0
  17. data/app/views/advert_selector/banners/new.html.erb +5 -0
  18. data/app/views/advert_selector/banners/show.html.erb +50 -0
  19. data/app/views/advert_selector/helper_items/_form.html.erb +37 -0
  20. data/app/views/advert_selector/helper_items/edit.html.erb +6 -0
  21. data/app/views/advert_selector/helper_items/index.html.erb +31 -0
  22. data/app/views/advert_selector/helper_items/new.html.erb +5 -0
  23. data/app/views/advert_selector/helper_items/show.html.erb +30 -0
  24. data/app/views/advert_selector/main/index.html.erb +20 -0
  25. data/app/views/advert_selector/placements/_form.html.erb +40 -0
  26. data/app/views/advert_selector/placements/edit.html.erb +6 -0
  27. data/app/views/advert_selector/placements/index.html.erb +25 -0
  28. data/app/views/advert_selector/placements/new.html.erb +5 -0
  29. data/app/views/advert_selector/placements/show.html.erb +20 -0
  30. data/app/views/layouts/advert_selector/application.html.erb +89 -0
  31. data/config/routes.rb +17 -0
  32. data/db/migrate/20120924165938_create_advert_selector_placements.rb +11 -0
  33. data/db/migrate/20120925122858_create_advert_selector_banners.rb +23 -0
  34. data/db/migrate/20120926132649_create_advert_selector_helper_items.rb +18 -0
  35. data/lib/advert_selector.rb +26 -0
  36. data/lib/advert_selector/engine.rb +18 -0
  37. data/lib/advert_selector/errors_cache.rb +21 -0
  38. data/lib/advert_selector/version.rb +3 -0
  39. data/lib/tasks/advert_selector_tasks.rake +4 -0
  40. data/test/advert_selector_test.rb +7 -0
  41. data/test/dummy/README.rdoc +261 -0
  42. data/test/dummy/Rakefile +7 -0
  43. data/test/dummy/app/assets/javascripts/application.js +15 -0
  44. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  45. data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
  46. data/test/dummy/app/controllers/application_controller.rb +4 -0
  47. data/test/dummy/app/controllers/examples_controller.rb +4 -0
  48. data/test/dummy/app/helpers/advert_selector_helper.rb +23 -0
  49. data/test/dummy/app/helpers/application_helper.rb +2 -0
  50. data/test/dummy/app/views/examples/index.html.erb +34 -0
  51. data/test/dummy/app/views/layouts/application.html.erb +20 -0
  52. data/test/dummy/config.ru +4 -0
  53. data/test/dummy/config/application.rb +59 -0
  54. data/test/dummy/config/boot.rb +10 -0
  55. data/test/dummy/config/database.yml +25 -0
  56. data/test/dummy/config/environment.rb +5 -0
  57. data/test/dummy/config/environments/development.rb +37 -0
  58. data/test/dummy/config/environments/production.rb +67 -0
  59. data/test/dummy/config/environments/test.rb +37 -0
  60. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  61. data/test/dummy/config/initializers/inflections.rb +15 -0
  62. data/test/dummy/config/initializers/mime_types.rb +5 -0
  63. data/test/dummy/config/initializers/secret_token.rb +7 -0
  64. data/test/dummy/config/initializers/session_store.rb +8 -0
  65. data/test/dummy/config/initializers/silence_assets.rb +20 -0
  66. data/test/dummy/config/initializers/simple_form.rb +178 -0
  67. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  68. data/test/dummy/config/locales/en.yml +5 -0
  69. data/test/dummy/config/locales/simple_form.en.yml +26 -0
  70. data/test/dummy/config/routes.rb +8 -0
  71. data/test/dummy/db/development.sqlite3 +0 -0
  72. data/test/dummy/db/migrate/20120928114159_create_advert_selector_placements.advert_selector.rb +12 -0
  73. data/test/dummy/db/migrate/20120928114160_create_advert_selector_banners.advert_selector.rb +24 -0
  74. data/test/dummy/db/migrate/20120928114161_create_advert_selector_helper_items.advert_selector.rb +19 -0
  75. data/test/dummy/db/schema.rb +53 -0
  76. data/test/dummy/db/test.sqlite3 +0 -0
  77. data/test/dummy/lib/templates/erb/scaffold/_form.html.erb +13 -0
  78. data/test/dummy/log/development.log +11516 -0
  79. data/test/dummy/log/test.log +66467 -0
  80. data/test/dummy/public/404.html +26 -0
  81. data/test/dummy/public/422.html +26 -0
  82. data/test/dummy/public/500.html +25 -0
  83. data/test/dummy/public/favicon.ico +0 -0
  84. data/test/dummy/script/rails +6 -0
  85. data/test/dummy/test/unit/helpers/examples_helper_test.rb +4 -0
  86. data/test/dummy/tmp/cache/88F/B60/AdvertSelectorBanner_2 +0 -0
  87. data/test/dummy/tmp/cache/943/570/advert_selector_errors +0 -0
  88. data/test/dummy/tmp/cache/A2C/760/AdvertSelectorBanner_207249520 +0 -0
  89. data/test/dummy/tmp/cache/A3E/CF0/AdvertSelectorBanner_394627963 +0 -0
  90. data/test/dummy/tmp/cache/A3F/BF0/AdvertSelectorBanner_814558298 +0 -0
  91. data/test/dummy/tmp/cache/A40/C00/AdvertSelectorBanner_814558299 +0 -0
  92. data/test/dummy/tmp/cache/assets/C57/D40/sprockets%2F4f1a95218761045e0b23975e889644aa +0 -0
  93. data/test/dummy/tmp/cache/assets/C5F/E80/sprockets%2F01c5361554f26407988a43647d88c5fe +0 -0
  94. data/test/dummy/tmp/cache/assets/C75/2E0/sprockets%2F23135a6eb5317973d290438c359a3c0a +0 -0
  95. data/test/dummy/tmp/cache/assets/C77/A40/sprockets%2F3b3d6c1426796a7024c7d3f42c283026 +0 -0
  96. data/test/dummy/tmp/cache/assets/C86/C20/sprockets%2Ffe1477ea429411b3b581466c928b6860 +0 -0
  97. data/test/dummy/tmp/cache/assets/C8C/B80/sprockets%2F371bf96e99717688ed7313a0c53f4212 +0 -0
  98. data/test/dummy/tmp/cache/assets/CBA/C70/sprockets%2F26288ca60ed05d24b8189328e4df9373 +0 -0
  99. data/test/dummy/tmp/cache/assets/CD1/A90/sprockets%2F433a791e2f93c0d8391aaa62203943ca +0 -0
  100. data/test/dummy/tmp/cache/assets/CD3/DE0/sprockets%2F0406286714c3c0abfcb4573336f7e33c +0 -0
  101. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  102. data/test/dummy/tmp/cache/assets/CD9/E80/sprockets%2F9052578aacc61253aa3854fa03b4895d +0 -0
  103. data/test/dummy/tmp/cache/assets/CEB/040/sprockets%2F644677c3bb57b6ed6b675229cfe54305 +0 -0
  104. data/test/dummy/tmp/cache/assets/CF0/1D0/sprockets%2F6fc757c2c8329244ca95d6909865bbc2 +0 -0
  105. data/test/dummy/tmp/cache/assets/CF2/EF0/sprockets%2F30ffd128655c9f04e88fba233248e997 +0 -0
  106. data/test/dummy/tmp/cache/assets/CF7/B60/sprockets%2F2c2a2af94201088a2a815ba90b8d344c +0 -0
  107. data/test/dummy/tmp/cache/assets/D05/4D0/sprockets%2F2d14560f81284bfb61fc0e187a803f1d +0 -0
  108. data/test/dummy/tmp/cache/assets/D0E/380/sprockets%2Ff27b6f5008c5a7324a7d8a382f21e7f2 +0 -0
  109. data/test/dummy/tmp/cache/assets/D19/820/sprockets%2Fccd0e907b49615494cc88c43a4781a9c +0 -0
  110. data/test/dummy/tmp/cache/assets/D28/910/sprockets%2F79b8a6fa551206c9996cfe98b80492cb +0 -0
  111. data/test/dummy/tmp/cache/assets/D2D/C20/sprockets%2Ff7d7fd5892b198e1588dd7d90a29a717 +0 -0
  112. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  113. data/test/dummy/tmp/cache/assets/D36/570/sprockets%2Fadfccb7c2436e006496eae16d6901523 +0 -0
  114. data/test/dummy/tmp/cache/assets/D40/110/sprockets%2Fbc5fcd75a352287c59787234ccbb11a8 +0 -0
  115. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  116. data/test/dummy/tmp/cache/assets/D50/030/sprockets%2F90296cd1ff74af449206b4fbd57cc995 +0 -0
  117. data/test/dummy/tmp/cache/assets/D50/BD0/sprockets%2F9c4832ce629b45b57ed8a55fbc717a86 +0 -0
  118. data/test/dummy/tmp/cache/assets/D55/240/sprockets%2F4b378a9f8c71e387569adfd712a26ce9 +0 -0
  119. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  120. data/test/dummy/tmp/cache/assets/D68/0A0/sprockets%2F17a08f579f5d1585bbd0c6ce2bac4351 +0 -0
  121. data/test/dummy/tmp/cache/assets/D68/220/sprockets%2F701db0b265a7c593768caebb904de9a1 +0 -0
  122. data/test/dummy/tmp/cache/assets/D6A/EF0/sprockets%2F2eb65cc490ad96cc38604918b0caeb90 +0 -0
  123. data/test/dummy/tmp/cache/assets/D6F/040/sprockets%2Fbd56a4cbc86673dbf2242fb85571bf61 +0 -0
  124. data/test/dummy/tmp/cache/assets/D70/540/sprockets%2Ffb1dbed4c6b15bc994454964bd455a43 +0 -0
  125. data/test/dummy/tmp/cache/assets/D83/400/sprockets%2Fc5adb5e35a83a7e10361f02afa42d4c1 +0 -0
  126. data/test/dummy/tmp/cache/assets/D88/7F0/sprockets%2Fe3b83e01d5f51e442ec9c11b40cca81a +0 -0
  127. data/test/dummy/tmp/cache/assets/DA3/080/sprockets%2Ffb77a66783db0b5812e3fdbabe4608f6 +0 -0
  128. data/test/dummy/tmp/cache/assets/DCE/810/sprockets%2F6eeb2d90a03c9de3ce8f5f30acf58118 +0 -0
  129. data/test/dummy/tmp/cache/assets/DCE/D50/sprockets%2F2232ec55b4deca5e8120ced9bd79ef54 +0 -0
  130. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  131. data/test/dummy/tmp/cache/assets/DF1/360/sprockets%2F23acf8b0d41e15db4d6ac2729f3eed1d +0 -0
  132. data/test/dummy/tmp/cache/assets/DF5/B00/sprockets%2Ff93edea94ff32d205acd8cdc4532b12b +0 -0
  133. data/test/dummy/tmp/cache/assets/DFB/9A0/sprockets%2Fb9a29f57d1ebf045452ed6cbd62eae1d +0 -0
  134. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  135. data/test/dummy/tmp/cache/assets/E53/3C0/sprockets%2Fcd0f7cae0b53d5ff22db8bf547d6a1bc +0 -0
  136. data/test/fixtures/advert_selector/banners.yml +38 -0
  137. data/test/fixtures/advert_selector/helper_items.yml +28 -0
  138. data/test/fixtures/advert_selector/placements.yml +17 -0
  139. data/test/functional/advert_selector/banners_controller_test.rb +64 -0
  140. data/test/functional/advert_selector/main_controller_test.rb +30 -0
  141. data/test/functional/advert_selector/placements_controller_test.rb +58 -0
  142. data/test/functional/examples_controller_test.rb +13 -0
  143. data/test/integration/banner_shows_test.rb +154 -0
  144. data/test/integration/navigation_test.rb +10 -0
  145. data/test/test_helper.rb +43 -0
  146. data/test/unit/advert_selector/banner_test.rb +160 -0
  147. data/test/unit/advert_selector/helper_item_test.rb +9 -0
  148. data/test/unit/advert_selector/placement_test.rb +50 -0
  149. data/test/unit/helpers/advert_selector/banners_helper_test.rb +6 -0
  150. data/test/unit/helpers/advert_selector/placements_helper_test.rb +6 -0
  151. metadata +425 -0
@@ -0,0 +1,155 @@
1
+ module AdvertSelector
2
+ module ApplicationHelper
3
+
4
+ def advert_selector_initialize(available_placements = :all)
5
+ Rails.logger.tagged('AdvertSelector') do
6
+
7
+ Rails.logger.debug("AdvertSelection initialized")
8
+
9
+ @advert_selector_banners_selected = []
10
+
11
+ if params[:advert_selector_force]
12
+ $advert_selector_banners_load_time = nil # reload everything
13
+ if banner = Banner.find_by_id(params[:advert_selector_force])
14
+ advert_selector_banner_force(banner)
15
+ end
16
+ end
17
+
18
+ advert_selector_banners.each do |banner|
19
+ if available_placements == :all || available_placements.include?(banner.placement.name_sym)
20
+ advert_selector_banner_try(banner)
21
+ end
22
+ end
23
+
24
+ Rails.logger.debug("AdvertSelection finished")
25
+ end
26
+ ""
27
+ end
28
+
29
+ def advert_selector_force_test_infos
30
+ if @advert_selector_force_banner_infos
31
+ content_tag :div, :id => "advert_selector_info", :class => 'alert alert-info', :style => "position: fixed; bottom: 5px;" do
32
+ content_tag(:strong) { "AdvertSelectorInfos for HelperItems:<br/>".html_safe } +
33
+ content_tag(:ul) {
34
+ @advert_selector_force_banner_infos.to_a.collect{|k, v| content_tag(:li){"#{k} : #{h(v)}".html_safe} }.join("\n").html_safe
35
+ }
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+
42
+ def advert_selector_banner_try(banner)
43
+
44
+ if banner.show_now_basics? &&
45
+ advert_selector_placement_free?(banner.placement) &&
46
+ advert_selector_placement_once_per_session_ok?(banner.placement) &&
47
+ advert_selector_banner_frequency_ok?(banner)
48
+
49
+ banner.helper_items.each do |hi|
50
+ if hi.content_for?
51
+ content_for hi.name_sym, hi.content.html_safe
52
+ else
53
+ return unless send("advert_selector_#{hi.name}", hi)
54
+ end
55
+ end
56
+
57
+ advert_selector_placement_once_per_session_shown(banner.placement)
58
+ advert_selector_banner_frequency_shown(banner)
59
+
60
+ banner.add_one_viewcount unless request.user_agent =~ /bot/i
61
+
62
+ @advert_selector_banners_selected.push(banner)
63
+
64
+ Rails.logger.info("Showing banner #{banner.name} in placement #{banner.placement.name}")
65
+ end
66
+
67
+ rescue => e
68
+ begin
69
+ str = "Error with banner #{banner.name} in placement #{banner.placement.name}.\n#{Time.now.iso8601} - #{request.url} - #{params.inspect}\n#{e.inspect}\n\n#{e.backtrace.first(10).join("\n")}"
70
+
71
+ AdvertSelector::ErrorsCache.add(str)
72
+ Rails.logger.error(str)
73
+ rescue => e
74
+ Rails.logger.error("ERROR INSIDE ERROR with #{banner.name} in placement #{banner.placement.name} : #{e.inspect}")
75
+ end
76
+ end
77
+
78
+ def advert_selector_banner_force(banner)
79
+ @advert_selector_force_banner_infos = []
80
+ @advert_selector_force_banner_infos.push [:show_now_basics_times_not_used, banner.show_now_basics?(false)]
81
+ @advert_selector_force_banner_infos.push [:show_now_basics_with_times, banner.show_now_basics?]
82
+ @advert_selector_force_banner_infos.push [:placement_free, advert_selector_placement_free?(banner.placement)]
83
+ @advert_selector_force_banner_infos.push [:placement_once_per_session, advert_selector_placement_once_per_session_ok?(banner.placement)]
84
+ @advert_selector_force_banner_infos.push [:frequency, advert_selector_banner_frequency_ok?(banner)]
85
+ banner.helper_items.each do |hi|
86
+ @advert_selector_force_banner_infos.push [hi.name_sym,
87
+ if hi.content_for?
88
+ content_for hi.name_sym, hi.content.html_safe
89
+ content_for(hi.name_sym).first(20)
90
+ else
91
+ send("advert_selector_#{hi.name}", hi)
92
+ end]
93
+ end
94
+
95
+ @advert_selector_banners_selected.push(banner)
96
+ Rails.logger.info("ForceShowing banner #{banner.name} in placement #{banner.placement.name}")
97
+
98
+ end
99
+
100
+ def advert_selector_placement_free?(placement)
101
+ !placement.conflicting_with?(@advert_selector_banners_selected.collect{|b| b.placement.name_sym})
102
+ end
103
+
104
+ def advert_selector_placement_once_per_session_ok?(placement)
105
+ !( placement.only_once_per_session? && session[:advert_selector_session_shown] &&
106
+ session[:advert_selector_session_shown].include?(placement.name) )
107
+ end
108
+ def advert_selector_placement_once_per_session_shown(placement)
109
+ if placement.only_once_per_session?
110
+ session[:advert_selector_session_shown] = [] if session[:advert_selector_session_shown].nil?
111
+ session[:advert_selector_session_shown].push(placement.name)
112
+ end
113
+ end
114
+
115
+ def advert_selector_banner_frequency_cookie(banner)
116
+ val, time = cookies["ad_#{banner.id}"].to_s.split(",")
117
+ [val.to_i, time]
118
+ end
119
+ def advert_selector_banner_frequency_ok?(banner)
120
+ !banner.has_frequency? || advert_selector_banner_frequency_cookie(banner).first < banner.frequency
121
+ end
122
+ def advert_selector_banner_frequency_shown(banner)
123
+ return true unless banner.has_frequency?
124
+
125
+ val, time = advert_selector_banner_frequency_cookie(banner)
126
+ time = time.blank? ? 1.week.from_now : Time.parse(time)
127
+ val += 1
128
+ cookies["ad_#{banner.id}"] = {:domain => :all, :expires => time, :value => [val, time.iso8601].join(",") }
129
+ end
130
+
131
+ ##########################################################
132
+
133
+ def advert_selector_request_params_include?(placement)
134
+ key, val = placement.content.to_s.split("=")
135
+ return params[key] == val
136
+ end
137
+
138
+
139
+ ##########################################################
140
+
141
+ $advert_selector_banners = []
142
+ $advert_selector_banners_load_time = nil
143
+ def advert_selector_banners
144
+ if $advert_selector_banners_load_time.nil? || $advert_selector_banners_load_time < 10.minutes.ago || Rails.env.development?
145
+ Rails.logger.info("AdvertSelection fetching banners and placements")
146
+ $advert_selector_banners_load_time = Time.now
147
+
148
+ $advert_selector_banners = Banner.find_current
149
+ end
150
+
151
+ $advert_selector_banners
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,107 @@
1
+ module AdvertSelector
2
+ class Banner < ActiveRecord::Base
3
+ attr_accessible :comment, :confirmed, :start_time, :end_time,
4
+ :frequency, :name, :placement_id, :target_view_count, :priority,
5
+ :fast_mode, :helper_items_attributes
6
+
7
+ belongs_to :placement, :inverse_of => :banners
8
+
9
+ has_many :helper_items, :order => "position", :dependent => :destroy
10
+ accepts_nested_attributes_for :helper_items
11
+
12
+ scope :find_future, lambda {
13
+ order('priority desc').
14
+ where('end_time > ? OR end_time IS NULL', Time.now).
15
+ includes(:placement, :helper_items)
16
+ }
17
+ scope :find_current, lambda {
18
+ find_future.
19
+ where('start_time < ? OR start_time IS NULL', 1.hour.from_now).
20
+ where('target_view_count IS NULL OR target_view_count > running_view_count')
21
+ }
22
+
23
+ # todo validates
24
+ # validate placement
25
+
26
+ def name_sym
27
+ @name_sym ||= name.downcase.to_sym
28
+ end
29
+
30
+ def has_frequency?
31
+ !frequency.nil? && frequency > 0
32
+ end
33
+
34
+ def show_today_has_viewcounts?(current_view_count = nil)
35
+ return true if target_view_count.nil? || fast_mode?
36
+
37
+ current_view_count = running_view_count if current_view_count.nil?
38
+
39
+ return false if current_view_count >= target_view_count
40
+
41
+ @show_now_today_target ||=
42
+ if target_view_count.nil? || end_time.nil? || end_time < 24.hours.from_now
43
+ true
44
+ else
45
+ #view_count_remaining = target_view_count - current_view_count
46
+
47
+ total_days = ((end_time - start_time)/1.day).round
48
+ daily_view_count = target_view_count/total_days
49
+
50
+ days_ending_today = ((Time.now.end_of_day - start_time)/1.day).round
51
+ days_ending_today * daily_view_count
52
+ end
53
+
54
+ @show_now_today_target == true || current_view_count < @show_now_today_target
55
+ end
56
+
57
+ def show_now_basics?(use_time_limits = true)
58
+ confirmed? &&
59
+ (!use_time_limits || start_time.nil? || start_time < Time.now) &&
60
+ (!use_time_limits || end_time.nil? || Time.now < end_time) &&
61
+ show_today_has_viewcounts?
62
+ end
63
+
64
+ def reload
65
+ super
66
+ reset_cache
67
+ end
68
+
69
+ def cache_key
70
+ "AdvertSelectorBanner_#{id}"
71
+ end
72
+
73
+ def running_view_count
74
+ counter = Rails.cache.read(cache_key).to_i
75
+ counter = 0 if $advert_selector_avoid_cache
76
+ counter = self[:running_view_count] if counter < self[:running_view_count]
77
+ counter
78
+ end
79
+
80
+ def reset_cache
81
+ Rails.cache.write(cache_key, nil, :expires_in => 2.weeks)
82
+ @show_now_today_target = nil
83
+ @name_sym = nil
84
+ end
85
+
86
+ def add_one_viewcount
87
+ unless self.target_view_count.nil?
88
+
89
+ counter = running_view_count + 1
90
+ Rails.cache.write(cache_key, counter, :expires_in => 2.weeks)
91
+ self[:running_view_count] = counter
92
+
93
+ since_update = running_view_count_change.last - running_view_count_change.first
94
+ self.save if since_update >= 500 || counter >= target_view_count
95
+ end
96
+ end
97
+
98
+ after_save :after_save_destroy_empty_helpers
99
+ def after_save_destroy_empty_helpers
100
+ helper_items.each do |hi|
101
+ hi.destroy if hi.blank?
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,21 @@
1
+ module AdvertSelector
2
+ class HelperItem < ActiveRecord::Base
3
+ attr_accessible :master_id, :master_type, :name, :position, :content_for, :content
4
+
5
+ #belongs_to :master, :polymorphic => true
6
+ #acts_as_list :scope => [:master_id, :master_type]
7
+
8
+ belongs_to :banner, :class_name => 'AdvertSelector::Banner'
9
+ acts_as_list :scope => :banner_id
10
+
11
+
12
+ def name_sym
13
+ @name_sym ||= name.downcase.to_sym
14
+ end
15
+
16
+ def blank?
17
+ name.blank?
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ module AdvertSelector
2
+ class Placement < ActiveRecord::Base
3
+ attr_accessible :conflicting_placements_array, :name, :comment, :request_delay, :only_once_per_session
4
+
5
+ has_many :banners, :inverse_of => :placement
6
+
7
+ scope :by_name, lambda {|name| where("LOWER(name) = ?", name.to_s.downcase)}
8
+
9
+ def name_sym
10
+ @name_sym ||= name.to_s.downcase.to_sym unless name.blank?
11
+ end
12
+
13
+
14
+ def conflicting_with?(placement_syms)
15
+ placement_syms = [placement_syms.name_sym] if placement_syms.is_a?(Placement)
16
+ placement_syms = placement_syms.collect{|plac| plac.name_sym} if placement_syms.first.is_a?(Placement)
17
+
18
+ !(placement_syms & conflicting_placements).empty?
19
+ end
20
+
21
+ def self.conflicting_placements(string)
22
+ string.to_s.split(/[ ,]/).collect{|name| name.strip}.reject{|name| name.blank?}.collect{|name| name.to_sym}.sort_by{|sym| sym.to_s}.uniq
23
+ end
24
+
25
+ def conflicting_placements
26
+ @conflicting_placements ||= ([self.name_sym] + Placement.conflicting_placements(conflicting_placements_array))
27
+ end
28
+
29
+ def conflicting_placements_array=(string)
30
+ string = string.join(",") if string.is_a?(Array)
31
+ arr = Placement.conflicting_placements( string )
32
+ arr.delete(name_sym)
33
+ self[:conflicting_placements_array] = arr.join(",")
34
+ end
35
+
36
+ after_save :after_save_update_conflicting_placements_info
37
+ def after_save_update_conflicting_placements_info
38
+ if conflicting_placements_array_changed?
39
+ saved_org = Placement.conflicting_placements(conflicting_placements_array_change.first)
40
+ saved_new = Placement.conflicting_placements(conflicting_placements_array_change.last)
41
+
42
+ (saved_org-saved_new).each do |name|
43
+ if placement = Placement.by_name(name).first
44
+ placement.conflicting_placements_array = placement.conflicting_placements.reject{|var| var == name_sym}
45
+ placement.save if placement.conflicting_placements_array_changed?
46
+ end
47
+ end
48
+ saved_new.each do |name|
49
+ if placement = Placement.where(:name => name).first
50
+ placement.conflicting_placements_array = placement.conflicting_placements.push(name_sym)
51
+ placement.save if placement.conflicting_placements_array_changed?
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,42 @@
1
+ <%= simple_form_for(@banner, :html => {:class => 'form-horizontal'}) do |f| %>
2
+ <%= f.error_notification %>
3
+
4
+ <div class="row">
5
+ <div class="span5">
6
+
7
+ <%= f.input :name %>
8
+
9
+ <%= f.input :start_time, :as => 'string', :input_html => {:value => (@banner.start_time ? @banner.start_time.iso8601 : '')} %>
10
+ <%= f.input :end_time, :as => 'string', :input_html => {:value => (@banner.end_time ? @banner.end_time.iso8601 : '')} %>
11
+ <%= f.input :priority %>
12
+ <%= f.input :target_view_count %>
13
+ <%= f.input :fast_mode %>
14
+ <%= f.input :frequency %>
15
+ <%= f.input :comment, :input_html => {:rows => 5} %>
16
+ <%= f.input :confirmed, :label_html => {:style => ((@banner.new_record? || @banner.confirmed?) ? '' : 'color: red; font-weight: bold')} %>
17
+ <%= f.association :placement %>
18
+
19
+ </div>
20
+
21
+ <div class="span4">
22
+ <% @banner.helper_items.build
23
+ @banner.helper_items.build if @banner.helper_items.size < 2
24
+ %>
25
+ <%= f.fields_for :helper_items do |f_hi| %>
26
+ <fieldset style="margin-bottom: 20px; border-bottom: 1px solid lightgray;">
27
+ <%= f_hi.input :name, :label => 'HelperItem Name' %>
28
+ <%= f_hi.input :content_for %>
29
+ <%= f_hi.input :position %>
30
+ <%= f_hi.input :content, :input_html => {:rows => (f_hi.object.content_for? ? 5 : 1) } %>
31
+ </fieldset>
32
+ <% end %>
33
+ </div>
34
+
35
+ </div>
36
+
37
+ <div class="form-actions">
38
+ <%= f.button :submit %>
39
+ </div>
40
+
41
+
42
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <h1>Banner <%= @banner.name %> <small> - <%= link_to('Duplicate banner', new_banner_url(:duplicate_id => @banner.id)) %></small></h1>
2
+
3
+ <% unless @banner.target_view_count.nil? %>
4
+ <strong>Current view count:</strong> <%= @banner.running_view_count %> / <%= @banner.target_view_count %>
5
+ &nbsp;&nbsp;|&nbsp;&nbsp;
6
+ <% end %>
7
+
8
+ <br/>
9
+
10
+ Test banner in url :
11
+
12
+ <input type="text" name="test_url" id="test_url" style="width: 500px;" value="<%= AdvertSelector.default_banner_test_url + "advert_selector_force=#{@banner.id}" %>">
13
+ <button class="btn btn-info" type="button" onclick="window.open(document.getElementById('test_url').value)">Test</button>
14
+
15
+ <hr/>
16
+
17
+ <%= render 'form' %>
18
+
19
+
20
+ <hr/>
21
+
22
+ <%= simple_form_for(@banner, :url => update_running_view_count_banner_url(@banner), :html => {:class => 'form-inline'}) do |f| %>
23
+
24
+ <strong>Running view count:</strong>
25
+ <input class="numeric integer optional" id="banner_running_view_count" name="banner[running_view_count]" step="1" value="<%= @banner.running_view_count %>" type="number">
26
+
27
+ <%= f.button :submit, 'Change running view count' %>
28
+
29
+ <% end %>
@@ -0,0 +1,38 @@
1
+ <h1>Listing banners</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Name</th>
6
+ <th>Start time</th>
7
+ <th>End time</th>
8
+ <th>Target view count</th>
9
+ <th>Frequency</th>
10
+ <th>Delay requests</th>
11
+ <th>Comment</th>
12
+ <th>Confirmed</th>
13
+ <th>Placement</th>
14
+ <th></th>
15
+ <th></th>
16
+ <th></th>
17
+ </tr>
18
+
19
+ <% @banners.each do |banner| %>
20
+ <tr>
21
+ <td><%= banner.name %></td>
22
+ <td><%= banner.start_time %></td>
23
+ <td><%= banner.end_time %></td>
24
+ <td><%= banner.target_view_count %></td>
25
+ <td><%= banner.frequency %></td>
26
+ <td><%= banner.comment %></td>
27
+ <td><%= banner.confirmed %></td>
28
+ <td><%= banner.placement_id %></td>
29
+ <td><%= link_to 'Show', banner %></td>
30
+ <td><%= link_to 'Edit', edit_banner_path(banner) %></td>
31
+ <td><%= link_to 'Destroy', banner, :method => :delete, :data => { :confirm => 'Are you sure?' } %></td>
32
+ </tr>
33
+ <% end %>
34
+ </table>
35
+
36
+ <br />
37
+
38
+ <%= link_to 'New Banner', new_banner_path %>