georgia_mailer 0.1.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +3 -11
  4. data/app/assets/javascripts/georgia_mailer/components/message_table.js.coffee +32 -26
  5. data/app/assets/stylesheets/georgia_mailer/application.css.scss +1 -0
  6. data/app/assets/stylesheets/georgia_mailer/components/_button.scss +4 -0
  7. data/app/assets/stylesheets/georgia_mailer/{modules → components}/_message.scss +4 -7
  8. data/app/assets/stylesheets/georgia_mailer/modules/_categories.scss +17 -0
  9. data/app/assets/stylesheets/georgia_mailer/modules/_messages.scss +7 -0
  10. data/app/controllers/georgia/mailer/messages_controller.rb +38 -0
  11. data/app/controllers/georgia/messages_controller.rb +71 -36
  12. data/app/decorators/georgia/mailer/message_decorator.rb +23 -0
  13. data/app/helpers/georgia/messages_helper.rb +1 -1
  14. data/app/mailers/georgia/mailer/notifier.rb +20 -0
  15. data/app/models/georgia/mailer/message.rb +54 -0
  16. data/app/policies/georgia/mailer/mailer_policy.rb +52 -0
  17. data/app/presenters/georgia/mailer/message_actions_presenter.rb +42 -0
  18. data/app/searches/georgia/mailer/message_search.rb +7 -0
  19. data/app/services/georgia/mailer/spam_check.rb +19 -0
  20. data/app/views/georgia/header/_messages.html.erb +1 -1
  21. data/app/views/georgia/{georgia_mailer → mailer}/messages/_message.html.erb +2 -0
  22. data/app/views/{georgia_mailer → georgia/mailer}/messages/create.js.erb +0 -0
  23. data/app/views/{georgia_mailer → georgia/mailer}/notifier/new_message_notification.html.erb +10 -3
  24. data/app/views/georgia/messages/destroy.js.erb +4 -0
  25. data/app/views/georgia/messages/ham.js.erb +7 -0
  26. data/app/views/georgia/messages/search.html.erb +55 -37
  27. data/app/views/georgia/messages/show.html.erb +8 -8
  28. data/app/views/georgia/messages/spam.js.erb +7 -0
  29. data/app/views/public_activity/georgia_mailer_message/_create.html.erb +17 -0
  30. data/app/workers/georgia/mailer/destroy_all_spam_worker.rb +18 -0
  31. data/app/workers/georgia/mailer/email_delivery_worker.rb +21 -0
  32. data/app/workers/georgia/mailer/spam_worker.rb +20 -0
  33. data/config/routes.rb +3 -3
  34. data/lib/generators/georgia/mailer/install/install_generator.rb +24 -0
  35. data/lib/georgia/mailer/engine.rb +12 -0
  36. data/lib/georgia/mailer/version.rb +5 -0
  37. data/lib/georgia_mailer.rb +20 -7
  38. data/lib/tasks/georgia_mailer_tasks.rake +17 -17
  39. metadata +54 -47
  40. data/app/controllers/georgia_mailer/messages_controller.rb +0 -35
  41. data/app/decorators/georgia_mailer/message_decorator.rb +0 -21
  42. data/app/mailers/georgia_mailer/notifier.rb +0 -18
  43. data/app/models/georgia_mailer/message.rb +0 -32
  44. data/app/presenters/georgia_mailer/message_actions_presenter.rb +0 -53
  45. data/app/services/georgia_mailer/spam_check.rb +0 -17
  46. data/app/workers/georgia_mailer/email_delivery_worker.rb +0 -19
  47. data/app/workers/georgia_mailer/spam_worker.rb +0 -18
  48. data/lib/generators/georgia_mailer/install/install_generator.rb +0 -23
  49. data/lib/georgia/indexer/extensions/solr_adapter/georgia_mailer/message.rb +0 -44
  50. data/lib/georgia/indexer/extensions/tire_adapter/georgia_mailer/message.rb +0 -46
  51. data/lib/georgia_mailer/engine.rb +0 -10
  52. data/lib/georgia_mailer/version.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6aafa57ea78d8babbab38651552c658541092a45
4
- data.tar.gz: f7d0608941ff2db9476c12ec484d19358126ce19
3
+ metadata.gz: 7f893d6dbc6b8bac397826c8a7dbf28b15423b8e
4
+ data.tar.gz: a76f6eb928d97f65df463684027791dcee62bfe4
5
5
  SHA512:
6
- metadata.gz: 0fe796c554d3f1c6e1113cc46786141f2cf58c37d56d0d7c2cd3c56d6aec271900044d91d5d64b587745eab5f22d5482ac247ce538ff46dd35b6dc3ccb5db5a5
7
- data.tar.gz: 970f5f117b2f7c3350888beb19b78ce2979964b08156b19b62cf4d049e136ac9e58b2eb16b0ec6bb9f70cd6b51c0cea433f5a899156c7b7142bad63aa41601c0
6
+ metadata.gz: 594e8787b0b2350a5390020e488716beb50bb140afeff5ab4364ebae6a49026c512c4ed33209bc65bb6f6b8df5674903bace4f4ed89cbfb768edc492ce31328d
7
+ data.tar.gz: 9e64674780aeaf658e8576ff4bcb71b5eb07dba10bc2bb840bcb1fa7cab964f5968032e13a5fc1fde9ce384ef429bdc61009996f84af96b30401df49fe42771d
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2014 Motion Eleven
1
+ Copyright (c) 2012-2014
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -10,21 +10,13 @@ The install generator will add missing migrations and automatically migrate your
10
10
  If you selected ElasticSearch as your indexer with Tire, your index will be created.
11
11
  Finally, it will mount the engine in your routes.rb file under '/mailer'
12
12
 
13
- rails generate georgia_mailer:install
13
+ rails generate georgia:mailer:install
14
14
 
15
15
  ### Heroku
16
16
 
17
- Add Redis addon for Sidekiq
17
+ Generate Georgia::Mailer::Message index:
18
18
 
19
- heroku addons:add redistogo
20
-
21
- Generate GeorgiaMailer::Message index:
22
-
23
- heroku run rake environment tire:import CLASS=GeorgiaMailer::Message FORCE=true
24
-
25
- Add sidekiq to your Procfile:
26
-
27
- worker: bundle exec sidekiq
19
+ heroku run rake environment georgia:mailer:create_indices
28
20
 
29
21
  ### Spam filtering
30
22
 
@@ -1,36 +1,49 @@
1
- class @MessagesTable
2
-
3
- constructor: (element) ->
4
- @element = $(element)
5
- @checkboxes = @element.find("input:checkbox")
6
- @deleteBtn = @element.find('.js-delete')
7
- @spamBtn = @element.find('.js-spam')
8
- @hamBtn = @element.find('.js-ham')
1
+ class @MessagesTable extends @Table
2
+
3
+ constructor: (element, checkboxable) ->
4
+ super(element, checkboxable)
5
+ @deleteBtn = @element.find('.js-delete')
6
+ @spamBtn = @element.find('.js-spam')
7
+ @hamBtn = @element.find('.js-ham')
9
8
  @setBindings()
10
9
 
11
10
  setBindings: () =>
12
- @checkboxes.on('change', @update)
13
11
  @deleteBtn.on('click', @delete)
14
12
  @spamBtn.on('click', @spam)
15
13
  @hamBtn.on('click', @ham)
16
14
 
17
- update: () =>
18
- if @getChecked().length then @enableActions() else @disableActions()
19
-
20
15
  delete: (event) =>
21
16
  @stopEvent(event)
22
17
  $.ajax(
23
18
  url: "/admin/messages/#{@getIds()}"
24
19
  type: 'DELETE'
25
- )
20
+ dataType: "JSON"
21
+ success: @removeMessages
22
+ ).always(@notify)
26
23
 
27
- spam: (event) ->
24
+ spam: (event) =>
28
25
  @stopEvent(event)
29
- # TODO: send event to controller
26
+ $.ajax(
27
+ type: "POST"
28
+ dataType: "JSON"
29
+ url: "/admin/messages/#{@getIds()}/spam"
30
+ success: @removeMessages
31
+ ).always(@notify)
30
32
 
31
- ham: (event) ->
33
+ ham: (event) =>
32
34
  @stopEvent(event)
33
- # TODO: send event to controller
35
+ $.ajax(
36
+ type: "POST"
37
+ dataType: "JSON"
38
+ url: "/admin/messages/#{@getIds()}/ham"
39
+ success: @removeMessages
40
+ ).always(@notify)
41
+
42
+ removeMessages: () =>
43
+ $.each @getIds(), (i, message_id) => @removeMessage(message_id)
44
+
45
+ removeMessage: (message_id) ->
46
+ $("tr#message_#{message_id}").remove();
34
47
 
35
48
  enableActions: () =>
36
49
  @spamBtn.removeClass('disabled').addClass('btn-warning')
@@ -42,17 +55,10 @@ class @MessagesTable
42
55
  @hamBtn.addClass('disabled').removeClass('btn-warning')
43
56
  @deleteBtn.addClass('disabled').removeClass('btn-danger')
44
57
 
45
- stopEvent: (event) ->
46
- event.stopPropagation()
47
- event.preventDefault()
48
-
49
- getChecked: () => @element.find("input:checkbox:checked[data-checkbox='child']")
50
- getId: (c) => $(c).data('id')
51
- getIds: () => $.map(@getChecked(), (c) => @getId(c))
52
-
53
58
  $.fn.actsAsMessagesTable = () ->
54
59
  @each ->
55
- new MessagesTable($(this))
60
+ checkboxable = new Checkboxable($(this))
61
+ new MessagesTable($(this), checkboxable)
56
62
 
57
63
  jQuery ->
58
64
  $("table.messages.js-checkboxable").each ->
@@ -1,3 +1,4 @@
1
1
  @import "settings/*";
2
2
  @import "mixins/*";
3
+ @import "components/*";
3
4
  @import "modules/*";
@@ -0,0 +1,4 @@
1
+ #messages.georgia .btn-sm {
2
+ padding: 6px 9px;
3
+ margin-right: 10px;
4
+ }
@@ -25,13 +25,10 @@
25
25
  border-top: 1px solid #cbcbcb;
26
26
  border-bottom: 1px solid #cbcbcb;
27
27
  }
28
- .message-status {
29
- width: 1px;
30
- border-right: 3px solid;
31
- padding: 0 !important;
32
- margin: 0;
33
- &.spam { border-color: $red; }
34
- &.clean { border-color: $green; }
28
+
29
+ td.status {
30
+ &.spam { border-right: 3px solid $red; }
31
+ &.clean { border-right: 3px solid $green; }
35
32
  }
36
33
 
37
34
  .message-name span {
@@ -0,0 +1,17 @@
1
+ .inbox-categories {
2
+ border-top: 1px solid #ddd;
3
+ margin-top: 52px;
4
+ padding-top: 5px;
5
+ }
6
+
7
+ .inbox-category-link {
8
+ display: block;
9
+ padding: 5px 5px 5px 10px;
10
+ margin-top: 5px;
11
+ &.active {
12
+ font-weight: bold;
13
+ color: #FFF;
14
+ background-color: #2c3e50;
15
+ &:hover { text-decoration: none; }
16
+ }
17
+ }
@@ -0,0 +1,7 @@
1
+ th.messages-destroy-spam {
2
+ text-align: center;
3
+ a {
4
+ font-weight: normal;
5
+ font-size: 0.9em;
6
+ }
7
+ }
@@ -0,0 +1,38 @@
1
+ module Georgia
2
+ module Mailer
3
+ class MessagesController < ::ApplicationController
4
+
5
+ def create
6
+ @message = Message.new(message_params)
7
+ if @message.save
8
+ Georgia::CreateActivity.new(@message, :create).call
9
+ EmailDeliveryWorker.new.async.later(60, @message.id)
10
+ SpamWorker.new.async.perform(@message.id)
11
+ respond_to do |format|
12
+ format.html { redirect_to :back, notice: 'Message delivered successfully' }
13
+ format.js { render layout: false }
14
+ end
15
+ else
16
+ respond_to do |format|
17
+ format.html { redirect_to :back, alert: 'Oups. Something went wrong.' }
18
+ format.js { render layout: false }
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def message_params
26
+ @message_params = {}
27
+ params[:message].each do |key, value|
28
+ @message_params[key] = value.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
29
+ end
30
+ @message_params[:referrer] = request.referrer
31
+ @message_params[:user_ip] = request.remote_ip
32
+ @message_params[:user_agent] = request.user_agent
33
+ @message_params
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -1,63 +1,78 @@
1
1
  module Georgia
2
- class MessagesController < ::Georgia::ApplicationController
2
+ class MessagesController < Georgia::ApplicationController
3
3
 
4
- load_and_authorize_resource class: GeorgiaMailer::Message
5
-
6
- before_filter :prepare_search, only: [:search, :show, :spam, :ham]
7
4
 
5
+ def show
6
+ begin
7
+ @message = Georgia::Mailer::Message.find(params[:id]).decorate
8
+ authorize @message
9
+ rescue ActiveRecord::RecordNotFound
10
+ authorize Georgia::Mailer::Message
11
+ redirect_to search_messages_path, alert: 'This message could not be found.'
12
+ end
13
+ end
8
14
 
9
15
  def index
16
+ authorize Georgia::Mailer::Message
10
17
  redirect_to georgia.search_messages_path
11
18
  end
12
19
 
13
20
  def search
21
+ authorize Georgia::Mailer::Message
22
+ search_definition = Georgia::Mailer::MessageSearch.new(params).definition
23
+ @search = Georgia::Mailer::Message.search(search_definition).page(params[:page])
24
+ @messages = Georgia::Mailer::MessageDecorator.decorate_collection(@search.records)
14
25
  end
15
26
 
16
- # Destroy multiple assets
17
27
  def destroy
18
- ids = params[:id].split(',')
19
- if @messages = GeorgiaMailer::Message.destroy(ids)
20
- respond_to do |format|
21
- format.html {
22
- redirect_to georgia.search_messages_path, notice: 'Messages successfully deleted.'
23
- }
24
- format.js { render layout: false }
25
- end
28
+ set_messages
29
+ authorize @messages
30
+ messages_count = @messages.length
31
+ if @messages.destroy_all
32
+ render_success("#{'Message'.pluralize(messages_count)} successfully deleted.")
26
33
  else
27
- respond_to do |format|
28
- format.html {redirect_to georgia.search_messages_path, alert: 'Oups. Something went wrong.'}
29
- format.js {head :internal_server_error}
30
- end
34
+ render_error('Oups. Something went wrong.')
31
35
  end
32
36
  end
33
37
 
34
- def show
35
- @message = GeorgiaMailer::Message.find(params[:id]).decorate
38
+ def destroy_all_spam
39
+ authorize Georgia::Mailer::Message
40
+ Georgia::Mailer::DestroyAllSpamWorker.new.async.perform
41
+ redirect_to search_messages_path(s: true), notice: 'Busy purging all spam messages.'
36
42
  end
37
43
 
38
44
  def spam
39
- @message = GeorgiaMailer::Message.find(params[:id])
40
- if @message.spam!
41
- @message.update_attribute(:spam, true)
42
- redirect_to :back, notice: 'Message successfully marked as spam.'
43
- else
44
- redirect_to :back, alert: 'Oups. Something went wrong.'
45
+ set_messages
46
+ authorize @messages
47
+ begin
48
+ if !@messages.map(&:report_spam).include?(false)
49
+ render_success("#{'Message'.pluralize(@messages.length)} successfully reported as spam.")
50
+ else
51
+ render_error('Oups. Something went wrong.')
52
+ end
53
+ rescue Rakismet::Undefined => ex
54
+ render_error(ex.message)
45
55
  end
46
56
  end
47
57
 
48
58
  def ham
49
- @message = GeorgiaMailer::Message.find(params[:id])
50
- if @message.ham! == false
51
- @message.update_attribute(:spam, false)
52
- redirect_to :back, notice: 'Message successfully marked as ham.'
53
- else
54
- redirect_to :back, alert: 'Oups. Something went wrong.'
59
+ set_messages
60
+ authorize @messages
61
+ begin
62
+ if !@messages.map(&:move_to_inbox).include?(false)
63
+ render_success("#{'Message'.pluralize(@messages.length)} successfully moved to your inbox.")
64
+ else
65
+ render_error('Oups. Something went wrong.')
66
+ end
67
+ rescue => ex
68
+ render_error(ex.message)
55
69
  end
56
70
  end
57
71
 
58
72
  def resend_notification
59
- @message = GeorgiaMailer::Message.find(params[:id])
60
- if GeorgiaMailer::Notifier.new_message_notification(@message, message_path(@message, only_path: false)).deliver
73
+ @message = Georgia::Mailer::Message.find(params[:id])
74
+ authorize @message
75
+ if Georgia::Mailer::Notifier.new_message_notification(@message).deliver
61
76
  redirect_to :back, notice: 'Notification successfully sent.'
62
77
  else
63
78
  redirect_to :back, alert: 'Oups. Something went wrong. Message could not be delivered.'
@@ -66,9 +81,29 @@ module Georgia
66
81
 
67
82
  private
68
83
 
69
- def prepare_search
70
- @search = ::Georgia::Indexer.search(GeorgiaMailer::Message, params)
71
- @messages = GeorgiaMailer::MessageDecorator.decorate_collection(@search.results)
84
+ def set_messages
85
+ ids = params[:id].split(',')
86
+ @messages = Georgia::Mailer::Message.where(id: ids)
87
+ end
88
+
89
+ def render_success success_message
90
+ @status_message = success_message
91
+ @status = :notice
92
+ respond_to do |format|
93
+ format.html { redirect_to :back, notice: @status_message }
94
+ format.js { render layout: false }
95
+ format.json { render json: { ids: @messages.map(&:id), message: @status_message, status: @status } }
96
+ end
97
+ end
98
+
99
+ def render_error error_message
100
+ @status_message = error_message
101
+ @status = :alert
102
+ respond_to do |format|
103
+ format.html { redirect_to :back, alert: @status_message }
104
+ format.js { render layout: false }
105
+ format.json { render json: { message: @status_message, status: @status } }
106
+ end
72
107
  end
73
108
 
74
109
  end
@@ -0,0 +1,23 @@
1
+ module Georgia
2
+ module Mailer
3
+ class MessageDecorator < ::Georgia::ApplicationDecorator
4
+
5
+ def phone_or_none
6
+ phone.present? ? phone : h.content_tag(:span, 'no phone', class: 'muted')
7
+ end
8
+
9
+ def subject_truncated
10
+ h.truncate(h.strip_tags(subject), length: 60, separator: ' ').html_safe if subject.present?
11
+ end
12
+
13
+ def message_truncated
14
+ h.truncate(h.strip_tags(message), length: 200, separator: ' ').html_safe if message.present?
15
+ end
16
+
17
+ def name_or_anonymous
18
+ name || 'Anonymous'
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -2,7 +2,7 @@ module Georgia
2
2
  module MessagesHelper
3
3
 
4
4
  def message_actions_list(message)
5
- GeorgiaMailer::MessageActionsPresenter.new(self, message)
5
+ Mailer::MessageActionsPresenter.new(self, message)
6
6
  end
7
7
 
8
8
  end
@@ -0,0 +1,20 @@
1
+ module Georgia
2
+ module Mailer
3
+ class Notifier < ActionMailer::Base
4
+
5
+ def new_message_notification(message)
6
+ @message = MessageDecorator.decorate(message)
7
+ emails_to = Georgia::User.where(receives_notifications: true).map(&:email)
8
+ unless emails_to.empty?
9
+ mail(
10
+ from: "noreply@georgiacms.org",
11
+ to: "noreply@georgiacms.org",
12
+ bcc: emails_to,
13
+ subject: "New message from #{Georgia.title}"
14
+ )
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ module Georgia
2
+ module Mailer
3
+ class Message < ActiveRecord::Base
4
+
5
+ include Elasticsearch::Model
6
+ include Elasticsearch::Model::Callbacks
7
+
8
+ include PublicActivity::Common
9
+
10
+ delegate :url, :current_path, :size, :content_type, :filename, to: :attachment
11
+
12
+ validates :name, presence: true
13
+ validates :email, format: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
14
+ validates :message, presence: true
15
+
16
+ mount_uploader :attachment, Ckeditor::AttachmentFileUploader
17
+
18
+ # Anti Spam: check https://github.com/joshfrench/rakismet for more details
19
+ include Rakismet::Model
20
+ rakismet_attrs author: :name, author_email: :email, content: :message, comment_type: 'message'
21
+ # attr_accessible :user_ip, :user_agent, :referrer, :spam, :verified_at
22
+ attr_accessor :permalink, :author_url
23
+
24
+ scope :spam, -> { where(spam: true) }
25
+ scope :ham, -> { where(spam: false) }
26
+ scope :latest, -> { order("created_at DESC") }
27
+
28
+ def status
29
+ @status ||= spam ? 'spam' : 'clean'
30
+ end
31
+
32
+ def report_spam
33
+ if self.spam!
34
+ self.update_attribute(:spam, true)
35
+ else
36
+ false
37
+ end
38
+ end
39
+
40
+ def move_to_inbox
41
+ if !self.ham!
42
+ self.update_attribute(:spam, false)
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ def self.policy_class
49
+ Georgia::Mailer::MailerPolicy
50
+ end
51
+
52
+ end
53
+ end
54
+ end