maily_herald-webui 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +8 -8
  2. data/Gemfile +1 -3
  3. data/Gemfile.lock +179 -162
  4. data/README.md +33 -7
  5. data/Rakefile +1 -1
  6. data/app/assets/javascripts/maily_herald/webui/dispatches.coffee +1 -0
  7. data/app/assets/javascripts/maily_herald/webui/webui.coffee +22 -14
  8. data/app/assets/stylesheets/maily_herald/webui/webui.sass +23 -2
  9. data/app/controllers/maily_herald/webui/ad_hoc_mailings_controller.rb +33 -0
  10. data/app/controllers/maily_herald/webui/application_controller.rb +9 -5
  11. data/app/controllers/maily_herald/webui/dashboard_controller.rb +2 -2
  12. data/app/controllers/maily_herald/webui/dispatches_controller.rb +2 -2
  13. data/app/controllers/maily_herald/webui/lists_controller.rb +2 -2
  14. data/app/controllers/maily_herald/webui/mailings_controller.rb +20 -8
  15. data/app/controllers/maily_herald/webui/one_time_mailings_controller.rb +14 -11
  16. data/app/controllers/maily_herald/webui/periodical_mailings_controller.rb +1 -1
  17. data/app/controllers/maily_herald/webui/resources_controller.rb +10 -6
  18. data/app/controllers/maily_herald/webui/sequence_mailings_controller.rb +1 -1
  19. data/app/controllers/maily_herald/webui/sequences_controller.rb +6 -6
  20. data/app/controllers/maily_herald/webui/sessions_controller.rb +8 -4
  21. data/app/controllers/maily_herald/webui/subscriptions_controller.rb +4 -1
  22. data/app/helpers/maily_herald/webui/application_helper.rb +22 -2
  23. data/app/helpers/maily_herald/webui/dashboard_helper.rb +14 -0
  24. data/app/helpers/maily_herald/webui/lists_helper.rb +13 -0
  25. data/app/helpers/maily_herald/webui/logs_helper.rb +6 -1
  26. data/app/helpers/maily_herald/webui/mailings_helper.rb +50 -5
  27. data/app/helpers/maily_herald/webui/sequences_helper.rb +13 -0
  28. data/app/helpers/maily_herald/webui/subscribers_helper.rb +1 -1
  29. data/app/mailers/ad_hoc_mailer.rb +8 -0
  30. data/app/mailers/custom_one_time_mailer.rb +7 -0
  31. data/app/models/maily_herald/webui/settings.rb +70 -0
  32. data/app/views/layouts/maily_herald/webui/application.html.haml +6 -7
  33. data/app/views/maily_herald/webui/dashboard/index.html.haml +31 -17
  34. data/app/views/maily_herald/webui/dashboard/index.js.erb +6 -2
  35. data/app/views/maily_herald/webui/dispatches/_logs.html.haml +4 -0
  36. data/app/views/maily_herald/webui/dispatches/_schedules.html.haml +4 -0
  37. data/app/views/maily_herald/webui/dispatches/_subscribers.html.haml +13 -0
  38. data/app/views/maily_herald/webui/lists/_header.html.haml +0 -3
  39. data/app/views/maily_herald/webui/lists/_items.html.haml +1 -1
  40. data/app/views/maily_herald/webui/lists/{context_variables.html.haml → context_attributes.html.haml} +5 -2
  41. data/app/views/maily_herald/webui/lists/subscribe.js.erb +2 -2
  42. data/app/views/maily_herald/webui/lists/unsubscribe.js.erb +1 -1
  43. data/app/views/maily_herald/webui/logs/_items.html.haml +2 -2
  44. data/app/views/maily_herald/webui/logs/preview.html.haml +26 -1
  45. data/app/views/maily_herald/webui/mailings/_deliver.js.erb +1 -1
  46. data/app/views/maily_herald/webui/mailings/_details.html.haml +9 -6
  47. data/app/views/maily_herald/webui/mailings/_details_form.html.haml +4 -2
  48. data/app/views/maily_herald/webui/mailings/_form_one_time.html.haml +1 -0
  49. data/app/views/maily_herald/webui/mailings/_header.html.haml +3 -3
  50. data/app/views/maily_herald/webui/mailings/_template.html.haml +4 -3
  51. data/app/views/maily_herald/webui/resources/new.html.haml +1 -1
  52. data/app/views/maily_herald/webui/sequences/_header.html.haml +11 -6
  53. data/app/views/maily_herald/webui/sequences/_list.html.haml +1 -1
  54. data/app/views/maily_herald/webui/subscribers/_item.html.haml +4 -0
  55. data/app/views/maily_herald/webui/subscribers/_list.html.haml +2 -0
  56. data/app/views/maily_herald/webui/subscriptions/show.html.haml +5 -1
  57. data/config/locales/en.yml +51 -9
  58. data/config/routes.rb +13 -3
  59. data/lib/maily_herald/webui/form_builder.rb +7 -2
  60. data/lib/maily_herald/webui/menu_manager.rb +1 -0
  61. data/lib/maily_herald/webui/version.rb +1 -1
  62. data/maily_herald-webui.gemspec +2 -2
  63. data/spec/dummy/app/models/user.rb +2 -1
  64. data/spec/dummy/bin/spring +4 -7
  65. data/spec/dummy/config/application.rb +5 -2
  66. data/spec/dummy/config/environments/development.rb +5 -3
  67. data/spec/dummy/config/environments/test.rb +3 -1
  68. data/spec/dummy/config/initializers/maily_herald.rb +33 -34
  69. data/spec/dummy/config/maily_herald.yml +4 -0
  70. data/spec/dummy/config/sidekiq.yml +5 -0
  71. data/spec/dummy/db/migrate/20130723074347_create_users.rb +1 -0
  72. data/spec/dummy/db/migrate/20150602133024_create_maily_herald_tables.maily_herald.rb +54 -0
  73. data/spec/dummy/db/schema.rb +31 -34
  74. metadata +24 -14
  75. data/app/views/maily_herald/webui/dispatches/_entities.html.haml +0 -7
  76. data/spec/dummy/db/migrate/20140804152249_create_maily_herald_tables.maily_herald.rb +0 -68
  77. data/spec/dummy/db/migrate/20140804152250_create_lists.maily_herald.rb +0 -33
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MailyHerald Web UI
2
2
 
3
- Web interface for Ruby on Rails email marketing solution - [MailyHerald](https://github.com/Sology/maily_herald).
3
+ Web interface for [MailyHerald](https://github.com/Sology/maily_herald) - Ruby on Rails email marketing solution.
4
4
 
5
5
  ## Requirements
6
6
 
@@ -8,7 +8,7 @@ Both Ruby on Rails 3.2 and 4 are supported.
8
8
 
9
9
  ## Installation
10
10
 
11
- Simply just
11
+ Simply just run
12
12
 
13
13
  gem install maily_herald-webui
14
14
 
@@ -18,7 +18,7 @@ or put in your Gemfile
18
18
 
19
19
  ## Usage
20
20
 
21
- Mount WebUI in your application:
21
+ Mount the WebUI in your application:
22
22
 
23
23
  ```ruby
24
24
  # config/routes.rb
@@ -29,14 +29,14 @@ mount MailyHerald::Webui::Engine => "/maily_webui"
29
29
 
30
30
  ### Restricting access
31
31
 
32
- The simplest way to restrict access to Maily WebUI is to use Rails routing constraints:
32
+ The simplest way to restrict access to the Maily WebUI is to use Rails routing constraints:
33
33
 
34
34
  ```ruby
35
35
  # config/routes.rb
36
36
  mount MailyHerald::Webui::Engine => "/maily_webui", :constraints => MailyAccessConstraint.new
37
37
  ```
38
38
 
39
- Sample `MailyAccessConstraint` implementation might look like this:
39
+ A sample `MailyAccessConstraint` implementation might look like this:
40
40
 
41
41
  ```ruby
42
42
  class MailyAccessConstraint
@@ -48,11 +48,37 @@ class MailyAccessConstraint
48
48
  end
49
49
  ```
50
50
 
51
+ HTTP Basic auth can be used too:
52
+
53
+ ```ruby
54
+ # config/routes.rb
55
+ MailyHerald::Webui::Engine.middleware.use Rack::Auth::Basic do |username, password|
56
+ username == ENV["MAILY_USERNAME"] && password == ENV["MAILY_PASSWORD"]
57
+ end if Rails.env.production?
58
+
59
+ mount MailyHerald::Webui::Engine => "/maily_webui"
60
+ ```
61
+
62
+ ### Entity names
63
+
64
+ By default the WebUI displays entities (i.e. your users) using the `to_s` method. You can easily overwrite this method in your model to see your user names in the WebUI. Example below:
65
+
66
+ ```ruby
67
+ class User < ActiveRecord::Base
68
+
69
+ # ...
70
+
71
+ def to_s
72
+ "#{self.firstname} #{self.lastname}"
73
+ end
74
+ end
75
+ ```
76
+
51
77
  ## More Information
52
78
 
53
- * [Home Page](http://www.mailyherald.org)
79
+ * [Home Page](http://mailyherald.org)
54
80
  * [API Docs](http://www.rubydoc.info/gems/maily_herald)
55
- * Showcase (_coming soon_)
81
+ * [Showcase](http://showcase.sology.eu/maily_herald)
56
82
  * [Sample application](https://github.com/Sology/maily_testapp)
57
83
 
58
84
  For bug reports or feature requests see the [issues on Github](https://github.com/Sology/maily_herald-webui/issues).
data/Rakefile CHANGED
@@ -25,6 +25,6 @@ end
25
25
  APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
26
26
  load 'rails/tasks/engine.rake'
27
27
 
28
- load "sprockets/assets.rake"
28
+ #load "sprockets/assets.rake"
29
29
 
30
30
  Bundler::GemHelper.install_tasks
@@ -23,6 +23,7 @@ $.fn.handleDispatchForm = () ->
23
23
 
24
24
  if from_value == "default"
25
25
  from_field.hide()
26
+ from_field.val("")
26
27
  else if from_value == "specify"
27
28
  from_field.show()
28
29
 
@@ -13,14 +13,18 @@ $.rails.confirmed = (link) ->
13
13
  $.rails.showConfirmDialog = (link) ->
14
14
  message = link.attr 'data-confirm'
15
15
  link.popover('destroy')
16
+ editable = link.closest(".editable")
17
+ editable.addClass("force-visible")
16
18
 
17
19
  content = $("#popover-confirmation").clone().removeClass("fade")
18
20
  content.find(".popover-msg").html(message)
19
21
  content.find('.confirm').unbind "click"
20
22
  content.find('.confirm').click ->
21
23
  $.rails.confirmed(link)
24
+ editable.removeClass("force-visible")
22
25
  content.find('.cancel').click ->
23
26
  link.popover('hide')
27
+ editable.removeClass("force-visible")
24
28
 
25
29
  link.popover(content: content, html: true, trigger: 'manual', title: $("#popover-confirmation").data("title"))
26
30
  link.popover('show')
@@ -61,6 +65,10 @@ $('.btn-default a').click (e) ->
61
65
  keyChange()
62
66
  , 400)
63
67
 
68
+ $.fn.setup_form_inputs = (v) ->
69
+ $(this).find('input[type="radio"]:checked').parent().addClass 'radio-checked'
70
+ $(this).find('input[type="checkbox"]:checked').parent().addClass 'checkbox-checked'
71
+
64
72
  $.fn.editable = (v) ->
65
73
  if v == "cancel"
66
74
  if $(this).data("edit-bkp")
@@ -73,6 +81,7 @@ $.fn.editable = (v) ->
73
81
  children.detach()
74
82
  $(this).data("edit-bkp", children)
75
83
  $(this).html(v)
84
+ $(this).setup_form_inputs()
76
85
 
77
86
  $.fn.historyGraph = () ->
78
87
  createSeries = (obj) ->
@@ -101,6 +110,11 @@ $.fn.historyGraph = () ->
101
110
  renderer: "line"
102
111
  interpolation: "linear"
103
112
  series: [
113
+ {
114
+ color: "#c3a323"
115
+ data: skipped
116
+ name: "Skipped"
117
+ }
104
118
  {
105
119
  color: "#a94442"
106
120
  data: failed
@@ -111,11 +125,6 @@ $.fn.historyGraph = () ->
111
125
  data: delivered
112
126
  name: "Delivered"
113
127
  }
114
- {
115
- color: "#006f68"
116
- data: skipped
117
- name: "Skipped"
118
- }
119
128
  ]
120
129
  )
121
130
  x_axis = new Rickshaw.Graph.Axis.Time(graph: graph)
@@ -134,9 +143,9 @@ $.fn.historyGraph = () ->
134
143
  container.data("graph", graph)
135
144
  else
136
145
  graph = container.data("graph")
137
- graph.series[0]["data"] = failed
138
- graph.series[1]["data"] = delivered
139
- graph.series[2]["data"] = skipped
146
+ graph.series[0]["data"] = skipped
147
+ graph.series[1]["data"] = failed
148
+ graph.series[2]["data"] = delivered
140
149
  graph.update()
141
150
 
142
151
  $ ->
@@ -147,28 +156,27 @@ $ ->
147
156
  false
148
157
 
149
158
  $(document).tooltip
150
- selector: 'a[data-toggle=tooltip]'
159
+ selector: '*[data-toggle=tooltip]'
151
160
 
152
161
  $(document).on 'hidden.bs.modal', (e) ->
153
162
  $(e.target).removeData('bs.modal')
154
163
 
155
164
 
156
165
  # form ui
157
- $('input[type=radio]').on 'change', ->
166
+ $(document).on 'change', 'input[type=radio]', ->
158
167
  $("input[type=radio][name=#{$(this).attr("name")}]").each ->
159
168
  if $(this).is(":checked")
160
169
  $(this).parent().addClass("radio-checked")
161
170
  else
162
171
  $(this).parent().removeClass("radio-checked")
163
172
 
164
- $('input[type=checkbox]').on 'change', ->
173
+ $(document).on 'change', 'input[type=checkbox]', ->
165
174
  if $(this).is(":checked")
166
175
  $(this).parent().addClass("checkbox-checked")
167
176
  else
168
177
  $(this).parent().removeClass("checkbox-checked")
169
178
 
170
- $('input[type="radio"]:checked').parent().addClass 'radio-checked'
171
- $('input[type="checkbox"]:checked').parent().addClass 'checkbox-checked'
179
+ $(document).setup_form_inputs()
172
180
 
173
181
  $(".select-wrap").click ->
174
182
  $(this).toggleClass "select-btn"
@@ -181,7 +189,7 @@ $ ->
181
189
  target = $(e.target)
182
190
  target.addClass("disabled")
183
191
  target.bind "click", dummy
184
- if target.find("i.fa").length == 0
192
+ if target.find("i.fa, span.fa").length == 0
185
193
  target.prepend("<i class='fa fa-spinner fa-spin'></i> ")
186
194
 
187
195
  target.on "ajax:success", (e) ->
@@ -147,6 +147,9 @@ a.error
147
147
  color: #f00 !important
148
148
  i.fa:before
149
149
  content: "" !important
150
+ i.fa
151
+ -webkit-animation: none !important
152
+ animation: none !important
150
153
 
151
154
  em
152
155
  font-style: italic
@@ -168,9 +171,23 @@ pre
168
171
  max-height: 400px
169
172
  white-space: pre-wrap
170
173
 
174
+ abbr[title], abbr[data-original-title]
175
+ text-decoration: none
176
+
171
177
  .no-margin
172
178
  margin-bottom: 0
173
179
 
180
+ .dropdown.dropdown-settings
181
+ background: none
182
+ width: 40px
183
+ text-align: center
184
+ .dropdown-menu
185
+ min-width: 200px
186
+ border: 1px solid #ddd
187
+ &:before
188
+ right: 10px
189
+
190
+
174
191
  // Breadcrumbs
175
192
  .breadcrumb
176
193
  background: none
@@ -388,7 +405,7 @@ button i
388
405
  content: ''
389
406
  position: absolute
390
407
  top: -10px
391
- left: 50%
408
+ right: 10%
392
409
  margin-left: -5px
393
410
  width: 0
394
411
  height: 0
@@ -755,7 +772,7 @@ h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6
755
772
  margin-left: -22px
756
773
  .text-muted
757
774
  color: #aaa
758
- &:hover
775
+ &:hover, &.force-visible
759
776
  td.actions
760
777
  &:after
761
778
  display: none
@@ -782,11 +799,15 @@ h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6
782
799
  visibility: hidden
783
800
  &:first-child:before
784
801
  display: none
802
+ .smart-listing-controls
803
+ label
804
+ margin-top: 8px
785
805
 
786
806
  // Search
787
807
  .filter-search
788
808
  position: relative
789
809
  display: inline-block
810
+ vertical-align: top
790
811
  input[type='text']
791
812
  padding-right: 36px
792
813
  max-width: 200px
@@ -0,0 +1,33 @@
1
+ module MailyHerald
2
+ class Webui::AdHocMailingsController < Webui::MailingsController
3
+ add_breadcrumb :label_ad_hoc_mailing_plural, Proc.new{ ad_hoc_mailings_path }
4
+ set_menu_item :ad_hoc_mailings
5
+
6
+ def archived
7
+ add_breadcrumb view_context.tw("#{controller_name}.archived.label")
8
+
9
+ super
10
+ end
11
+
12
+ def show
13
+ super
14
+ end
15
+
16
+ def deliver
17
+ find_item
18
+
19
+ if params[:entity_id]
20
+ @e = @item.list.context.scope.find(params[:entity_id])
21
+ @item.schedule_delivery_to @e
22
+
23
+ render_containers ["schedules"]
24
+ render_update
25
+ else
26
+ @item.schedule_delivery_to_all
27
+
28
+ render_containers ["schedules"]
29
+ render_update
30
+ end
31
+ end
32
+ end
33
+ end
@@ -5,14 +5,18 @@ module MailyHerald
5
5
  include MailyHerald::Webui::MenuManager::ControllerExtensions
6
6
 
7
7
  helper SmartListing::Helper
8
- helper_method :expert_mode?, :work_mode
8
+ helper_method :settings
9
9
 
10
- def work_mode
11
- session[:work_mode].try(:to_sym) || :regular
10
+ def settings
11
+ Settings.new(cookies)
12
12
  end
13
13
 
14
- def expert_mode?
15
- work_mode == :expert
14
+ def log_scope
15
+ if settings.show_skipped?
16
+ MailyHerald::Log.all
17
+ else
18
+ MailyHerald::Log.not_skipped
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -22,7 +22,7 @@ module MailyHerald
22
22
  smart_listing_create(:logs, logs(:processed), :partial => "maily_herald/webui/logs/items", default_sort: {processing_at: "desc"})
23
23
  smart_listing_create(:scheduled_logs, MailyHerald::Log.scheduled, :partial => "maily_herald/webui/logs/items", default_sort: {processing_at: "asc"})
24
24
 
25
- @total_count = MailyHerald::Log.count
25
+ @total_count = log_scope.count
26
26
  @processed_count = logs(:processed).count
27
27
  @delivered_count = logs(:delivered).count
28
28
  @skipped_count = logs(:skipped).count
@@ -59,7 +59,7 @@ module MailyHerald
59
59
  def logs state, period = nil
60
60
  period ||= @period
61
61
 
62
- MailyHerald::Log.send(state).where("processing_at > (?)", @time - period)
62
+ log_scope.send(state).where("processing_at > (?)", @time - period)
63
63
  end
64
64
  end
65
65
  end
@@ -22,7 +22,7 @@ module MailyHerald
22
22
  def destroy
23
23
  @item.archive!
24
24
 
25
- render_containers ["details", "entities"]
25
+ render_containers ["details", "subscribers"]
26
26
  render_update
27
27
  end
28
28
 
@@ -35,7 +35,7 @@ module MailyHerald
35
35
  @item.disable!
36
36
  end
37
37
 
38
- render_containers ["details", "entities"]
38
+ render_containers ["details", "subscribers"]
39
39
  render_update
40
40
  end
41
41
  end
@@ -17,7 +17,7 @@ module MailyHerald
17
17
  @item.unsubscribe! @entity
18
18
  end
19
19
 
20
- def context_variables
20
+ def context_attributes
21
21
  @context = MailyHerald.context(params[:context])
22
22
 
23
23
  render layout: "maily_herald/webui/modal"
@@ -33,7 +33,7 @@ module MailyHerald
33
33
  scope.where("name like ? or title like ?", "%#{query}%", "%#{query}%")
34
34
  end
35
35
  spec.items_partial = "items"
36
- spec.params = [:name, :title]
36
+ spec.params = [:name, :title, :context_name]
37
37
  spec.update_containers = {
38
38
  "subscribers" => true,
39
39
  "opt_outs" => true,
@@ -38,10 +38,11 @@ module MailyHerald
38
38
  spec.params = [:title, :mailer_name, :list, :from, :conditions, :override_subscription, :subject, :template]
39
39
  spec.update_containers = {
40
40
  "template" => {editable: true},
41
- "entities" => true,
42
- "logs" => true
41
+ "subscribers" => true,
42
+ "logs" => true,
43
+ "schedules" => true
43
44
  }
44
- spec.containers_order = ["details", "template", "entities", "logs"]
45
+ spec.containers_order = ["details", "template", "subscribers", "logs", "schedules"]
45
46
  end
46
47
  end
47
48
 
@@ -54,11 +55,22 @@ module MailyHerald
54
55
  containers.each do |container|
55
56
  case container
56
57
  when "logs"
57
- @logs = smart_listing_create(:logs, @item.logs.processed, :partial => "maily_herald/webui/logs/items", default_sort: {processing_at: "desc"})
58
- when "entities"
59
- @entities = @item.list.subscribers
60
- @entities = @entities.merge(@item.list.context.scope_like(params[:entities_filter])) if params[:entities_filter]
61
- @entities = smart_listing_create(:entities, @entities, :partial => "maily_herald/webui/subscribers/list")
58
+ @logs = @item.logs.merge(log_scope).processed
59
+ @logs = @logs.merge(MailyHerald::Log.like_email(params[:logs_filter])) if params[:logs_filter]
60
+ @logs = smart_listing_create(:logs, @logs, :partial => "maily_herald/webui/logs/items", default_sort: {processing_at: "desc"})
61
+
62
+ when "schedules"
63
+ @schedules = @item.logs.scheduled
64
+ @schedules = @schedules.merge(MailyHerald::Log.like_email(params[:schedules_filter])) if params[:schedules_filter]
65
+ @schedules = smart_listing_create(:schedules, @schedules, :partial => "maily_herald/webui/logs/items", default_sort: {processing_at: "asc"})
66
+
67
+ when "subscribers"
68
+ @with_unmet_conditions = params[:with_unmet_conditions] == "1"
69
+
70
+ @subscribers = @item.list.subscribers
71
+ @subscribers = @subscribers.merge(@item.list.context.scope_like(params[:subscribers_filter])) if params[:subscribers_filter]
72
+ @subscribers = @subscribers.select{|e| @mailing.conditions_met?(e)} if @mailing.has_conditions? && params[:with_unmet_conditions] != "1"
73
+ @subscribers = smart_listing_create(:subscribers, @subscribers, :partial => "maily_herald/webui/subscribers/list", array: @mailing.has_conditions?)
62
74
  else
63
75
  yield(container) if block_given?
64
76
  end
@@ -13,20 +13,23 @@ module MailyHerald
13
13
  super
14
14
  end
15
15
 
16
- def deliver
17
- find_item
16
+ protected
18
17
 
19
- if params[:entity_id]
20
- @e = @item.list.context.scope.find(params[:entity_id])
21
- @item.deliver_to @e
18
+ def set_resource_spec
19
+ spec = super
20
+ spec.params.push(:start_at)
21
+ spec.update_containers["schedules"] = true
22
+ spec.containers_order = ["details", "template", "subscribers", "schedules", "logs"]
23
+ spec
24
+ end
22
25
 
23
- render_containers ["logs"]
24
- render_update
25
- else
26
- @item.run
27
- head :ok
26
+ def action_dependencies *containers
27
+ super do |container|
28
+ case container
29
+ when "schedules"
30
+ @schedules = smart_listing_create(:schedules, @item.logs.scheduled, :partial => "maily_herald/webui/logs/items", default_sort: {processing_at: "asc"})
31
+ end
28
32
  end
29
33
  end
30
-
31
34
  end
32
35
  end