notify_me 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 270fa941da8f9e238d0ffaf8949e76c89c008e66
4
+ data.tar.gz: 115f8bcb85cc68c61ef4ed575ad2017d7af0ca60
5
+ SHA512:
6
+ metadata.gz: 745493d1165414e1c054566d0ca464c0c231b826fc45eb70451f992f97e8d049db8e9c19c7dea82062967a977552c1e2b730462715f92091a5978e0a3cdc0483
7
+ data.tar.gz: b360dbe5cfe10c20188962a1f0fb37ccc2ca7fe0525671686e979ce4a9af1196ef0b847648a39df06eb223070d982cd368ed07c422fb4f80de005febb51fe096
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ spec/internal/db/*sqlite
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Sam Clopton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Notify Me
2
+ This is a gem that provides simple and generic notifications that can have 0
3
+ or more actions associated with them.
4
+
5
+ ## Usage:
6
+ ``` ruby
7
+ class User < ActiveRecord::Base
8
+ has_many_notifications
9
+ ...
10
+ end
11
+
12
+ class Task < ActiveRecord::Base
13
+ ...
14
+ end
15
+
16
+ class TaskSwap < ActiveRecord::Base
17
+ belongs_to :from, class_name: "User"
18
+ belongs_to :to, class_name: "User"
19
+ belongs_to :task
20
+
21
+ def accept_swap(action)
22
+ ...
23
+ end
24
+
25
+ def reject_swap(action)
26
+ ...
27
+ end
28
+ end
29
+ ```
30
+
31
+ A user wants to request a task swap
32
+
33
+ ``` ruby
34
+ swap_task = SwapTask.create(...)
35
+ notification = NotifyMe::Notification.create(message: "John Doe would like to swap tasks with you")
36
+ user.notifications << notification
37
+
38
+ notification.actions.create(notification: notification, commandable: swap_task, commandable_action: "accept_swap", name: "Accept")
39
+ notification.actions.create(notification: notification, commandable: swap_task, commandable_action: "reject_swap", name: "Reject")
40
+ ```
41
+
42
+ Likely in some controller somewhere
43
+
44
+ ``` ruby
45
+ action = Action.find(params[:id])
46
+ action.run_action() # if this was the action created above, this would call swap_task.accept_swap(action)
47
+ ```
48
+
49
+
50
+ ## Notification
51
+ * belongs_to :notifyable
52
+ * has_many :actions
53
+ * message - String
54
+ * message_details - String
55
+ * categories - String
56
+
57
+ ## Action
58
+ * belongs_to :notification
59
+ * belongs_to :commandable
60
+ * can either be an instance
61
+ * or a class (set the :commandable_type String to the class name -- I.E. "User")
62
+ * commandable_action - String
63
+ * must either be
64
+ * an action on the instance
65
+ * or an action on the class
66
+ * response_identifier - String
67
+ * not required, but if it is provided it must be unique
68
+ * has_been_processed - Boolean
69
+ * set to true after the action is processed.
70
+ * name - String
71
+ * say you want a name to display in a UI, use this field here
@@ -0,0 +1,65 @@
1
+ class NotifyMe::Action < ActiveRecord::Base
2
+ self.table_name = "notify_me_actions"
3
+
4
+ belongs_to :notification
5
+ belongs_to :commandable, :polymorphic => true
6
+
7
+ validates :notification, :presence => true
8
+ validates :commandable_type, :presence => true
9
+ validates :commandable_action, :presence => true
10
+ validate :validate_uniqness_of_unprocessed_identifiers
11
+ validate :validate_pressence_of_action
12
+
13
+ def validate_uniqness_of_unprocessed_identifiers
14
+ if self.response_identifier != nil
15
+ if NotifyMe::Action.where("response_identifier = ? AND has_been_processed = ?",
16
+ self.response_identifier, false).count > 0
17
+ errors.add(:base, "The response_identifier is not unique among unprocessed actions")
18
+ end
19
+ end
20
+ end
21
+
22
+ def validate_pressence_of_action
23
+ if self.commandable
24
+ unless self.commandable.respond_to?(self.commandable_action)
25
+ errors.add(:base, "The commandable action #{self.commandable_action} does not exist on the commandable instance")
26
+ end
27
+ else
28
+ begin
29
+ unless self.commandable_type.constantize.respond_to?(self.commandable_action)
30
+ errors.add(:base, "The commandable action #{self.commandable_action} does not exist on the commandable_type constant")
31
+ end
32
+ rescue NameError
33
+ errors.add(:base, "The commandable_type does not refer to a valid constant")
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.process_by_identifier(identifier, *args)
39
+ action = self.where("response_identifier = ? AND has_been_processed = ?",
40
+ identifier, false).first
41
+
42
+ if action
43
+ {:action => action, :rval => action.run_action(*args)}
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def run_command(*args)
50
+ if self.commandable
51
+ self.commandable.send(self.commandable_action, self, *args)
52
+ else
53
+ self.commandable_type.constantize.send(self.commandable_action, self, *args)
54
+ end
55
+ end
56
+
57
+ def run_action(*args)
58
+ rval = run_command(*args)
59
+
60
+ self.has_been_processed = true
61
+ self.save!
62
+
63
+ return rval
64
+ end
65
+ end
@@ -0,0 +1,8 @@
1
+ class NotifyMe::Notification < ActiveRecord::Base
2
+ self.table_name = "notify_me_notifications"
3
+
4
+ has_many :actions, :class_name => 'NotifyMe::Action'
5
+ belongs_to :notifyable, :polymorphic => true
6
+
7
+ validates :message, :presence => true
8
+ end
data/config.ru ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+ run Combustion::Application
@@ -0,0 +1,43 @@
1
+ class NotificationTables < ActiveRecord::Migration
2
+ def up
3
+ create_table :notify_me_notifications do |t|
4
+ t.integer :notifyable_id
5
+ t.string :notifyable_type
6
+
7
+ t.string :message
8
+ t.string :message_details
9
+ t.boolean :has_been_viewed, :required => true, :default => false
10
+ t.string :categories
11
+ end
12
+
13
+ add_index :notify_me_notifications, [:notifyable_id, :notifyable_type],
14
+ :name => 'index_notifications_on_note_id_and_note_type'
15
+ add_index :notify_me_notifications, [:notifyable_id, :notifyable_type, :categories],
16
+ :name => 'index_notifications_on_note_id_and_note_type_and_categories'
17
+
18
+ create_table :notify_me_actions do |t|
19
+ t.integer :notification_id
20
+ t.integer :commandable_id
21
+ t.string :commandable_type
22
+ t.string :commandable_action
23
+ t.string :response_identifier
24
+ t.boolean :has_been_processed, :required => true, :default => false
25
+ end
26
+
27
+ add_index :notify_me_actions, :notification_id
28
+ add_index :notify_me_actions, :response_identifier
29
+ add_index :notify_me_actions, [:notification_id, :response_identifier],
30
+ :name => 'index_notifications_on_note_id_and_resp_ident'
31
+ add_index :notify_me_actions, [:commandable_id, :commandable_type, :notification_id],
32
+ :name => "index_actions_on_comm_id_and_comm_type_and_note_id"
33
+ add_index :notify_me_actions, [:commandable_id, :commandable_type, :response_identifier],
34
+ :name => "index_actions_on_comm_id_and_comm_type_and_resp_ident"
35
+ add_index :notify_me_actions, [:commandable_id, :commandable_type, :notification_id, :response_identifier],
36
+ :unique => true, :name => 'unique_actions'
37
+ end
38
+
39
+ def down
40
+ drop_table :notify_me_notifications
41
+ drop_table :notify_me_actions
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ class ActionName < ActiveRecord::Migration
2
+ def up
3
+ add_column :notify_me_actions, :name, :string
4
+ end
5
+
6
+ def down
7
+ remove_column :notify_me_actions, :name
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ class TimeStamps < ActiveRecord::Migration
2
+ def up
3
+ add_column :notify_me_actions, :created_at, :datetime
4
+ add_column :notify_me_actions, :updated_at, :datetime
5
+ add_column :notify_me_notifications, :created_at, :datetime
6
+ add_column :notify_me_notifications, :updated_at, :datetime
7
+ end
8
+
9
+ def down
10
+ remove_column :notify_me_actions, :created_at
11
+ remove_column :notify_me_actions, :updated_at
12
+ remove_column :notify_me_notifications, :created_at
13
+ remove_column :notify_me_notifications, :updated_at
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ require 'active_support/concern'
2
+
3
+ module NotifyMe::ActiveRecord
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def has_many_notifications
8
+ has_many :notifications, :as => :notifyable, :class_name => 'NotifyMe::Notification'
9
+ has_many :actions, :class_name => 'NotifyMe::Action', :through => :notifications
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_support/configurable'
2
+
3
+ module NotifyMe
4
+ def self.configure(&block)
5
+ yield @config ||= NotifyMe::Configuration.new
6
+ end
7
+
8
+ def self.config
9
+ @config
10
+ end
11
+
12
+ class Configuration
13
+ include ActiveSupport::Configurable
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails/engine'
2
+
3
+ class NotifyMe::Engine < Rails::Engine
4
+ engine_name :notify_me
5
+
6
+ ActiveSupport.on_load :active_record do
7
+ include NotifyMe::ActiveRecord
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module NotifyMe
2
+ VERSION = '0.0.3'
3
+ end
data/lib/notify_me.rb ADDED
@@ -0,0 +1,6 @@
1
+ module NotifyMe
2
+ #
3
+ end
4
+
5
+ require 'notify_me/active_record'
6
+ require 'notify_me/engine'
data/notify_me.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'notify_me/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'notify_me'
9
+ s.version = NotifyMe::VERSION
10
+ s.authors = ['Sam Clopton']
11
+ s.email = ['samsinite@gmail.com']
12
+ s.homepage = 'https://github.com/samsinite/notify_me'
13
+ s.summary = 'Notfy Me'
14
+ s.description = 'This friendly library gives you generic notifications in your Rails app.'
15
+ s.license = 'MIT'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_runtime_dependency 'activerecord', '>= 3.2.0'
22
+ s.add_development_dependency 'combustion', '~> 0.5.1'
23
+ s.add_development_dependency 'rspec-rails', '~> 2.13'
24
+ s.add_development_dependency 'sqlite3', '~> 1.3.7'
25
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe NotifyMe::Action do
4
+ let(:user) { User.create(username: "Test") }
5
+ let(:message_notification) { NotifyMe::Notification.create(message: "This is a test msg") }
6
+
7
+ it "can belong to a notification" do
8
+ action = NotifyMe::Action.new(:notification => message_notification,
9
+ :commandable => user,
10
+ :commandable_action => "view_notification")
11
+ action.should be_valid
12
+ end
13
+
14
+ it "must belong to a notification" do
15
+ action = NotifyMe::Action.new(:commandable => user,
16
+ :commandable_action => "view_notification")
17
+ action.should_not be_valid
18
+ end
19
+
20
+ it "can belong to a commandable instance" do
21
+ action = NotifyMe::Action.new(:notification => message_notification,
22
+ :commandable => user,
23
+ :commandable_action => "view_notification")
24
+
25
+ action.should be_valid
26
+ end
27
+
28
+ it "can belong to a commandable constant" do
29
+ action = NotifyMe::Action.new(:notification => message_notification,
30
+ :commandable_type => "User",
31
+ :commandable_action => "do_something")
32
+
33
+ action.should be_valid
34
+ end
35
+
36
+ it "must belong to a existing commandable instance or a commandable constant" do
37
+ action = NotifyMe::Action.new(:notification => message_notification)
38
+
39
+ action.should_not be_valid
40
+ end
41
+
42
+ it "if it belongs to a commandable instance, it must belong to an existing instance" do
43
+ action = NotifyMe::Action.new(:notification => message_notification,
44
+ :commandable_type => "User",
45
+ :commandable_id => 2,
46
+ :commandable_action => "view_notification")
47
+
48
+ action.should_not be_valid
49
+ end
50
+
51
+ it "if it belongs to a valid commandable instance, it must be able to process the action" do
52
+ action = NotifyMe::Action.new(:notification => message_notification,
53
+ :commandable_type => "User",
54
+ :commandable_id => 1,
55
+ :commandable_action => "fail_please")
56
+
57
+ action.should_not be_valid
58
+ end
59
+
60
+ it "if it belongs to a valid commandable constant, it must be able to process the action" do
61
+ action = NotifyMe::Action.new(:notification => message_notification,
62
+ :commandable_type => "User",
63
+ :commandable_action => "fail_please")
64
+
65
+ action.should_not be_valid
66
+ end
67
+ end
68
+
69
+ describe "Adding and removing actions" do
70
+ let(:user) { User.create(username: "Test") }
71
+ let(:message_notification) { NotifyMe::Notification.create(:message => "This is a test msg") }
72
+
73
+ it "stores new actions" do
74
+ action = message_notification.actions.create(:notification => message_notification,
75
+ :commandable => user,
76
+ :commandable_action => "view_notification")
77
+
78
+ message_notification.actions.reload.should == [action]
79
+ end
80
+
81
+ it "removes existing actions" do
82
+ action = message_notification.actions.create(:notification => message_notification,
83
+ :commandable => user,
84
+ :commandable_action => "view_notification")
85
+ message_notification.actions.delete action
86
+
87
+ user.notifications.reload.should == []
88
+ end
89
+ end
90
+
91
+ describe "Processing actions" do
92
+ let(:user) { User.create(username: "Test") }
93
+ let(:message_notification) { NotifyMe::Notification.create(:message => "This is a test msg") }
94
+
95
+ it "runs existing actions" do
96
+ action = message_notification.actions.create(:notification => message_notification,
97
+ :commandable => user,
98
+ :commandable_action => "view_notification")
99
+ action.run_action
100
+
101
+ message_notification.has_been_viewed.should be_true
102
+ end
103
+
104
+ it "marks ran actions as processed" do
105
+ action = message_notification.actions.create(:notification => message_notification,
106
+ :commandable => user,
107
+ :commandable_action => "view_notification")
108
+ action.run_action
109
+
110
+ action.has_been_processed.should be_true
111
+ end
112
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Adding and removing notifications" do
4
+ let(:user) { User.create(username: "Test") }
5
+ let(:message_notification) { NotifyMe::Notification.create(:message => "This is a test msg")}
6
+
7
+ it "stores new notifications" do
8
+ user.notifications << message_notification
9
+
10
+ user.notifications.reload.should == [message_notification]
11
+ end
12
+
13
+ it "removes existing notifications" do
14
+ user.notifications << message_notification
15
+ user.notifications.delete message_notification
16
+
17
+ user.notifications.reload.should == []
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ class User < ActiveRecord::Base
2
+ has_many_notifications
3
+
4
+ def view_notification(action)
5
+ action.notification.has_been_viewed = true
6
+ action.notification.save!
7
+
8
+ true
9
+ end
10
+
11
+ def self.do_something(action)
12
+ puts "TADA!"
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/combustion_test.sqlite
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :users, :force => true do |t|
3
+ t.string :username
4
+ t.timestamps
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'combustion'
4
+
5
+ Bundler.require :default, :development
6
+
7
+ Combustion.initialize! :active_record
8
+
9
+ require 'rspec/rails'
10
+
11
+ RSpec.configure do |config|
12
+ config.use_transactional_fixtures = true
13
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: notify_me
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Sam Clopton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: combustion
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.5.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.13'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.7
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.7
69
+ description: This friendly library gives you generic notifications in your Rails app.
70
+ email:
71
+ - samsinite@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENCE
79
+ - README.md
80
+ - app/models/notify_me/action.rb
81
+ - app/models/notify_me/notification.rb
82
+ - config.ru
83
+ - db/migrate/1_notification_tables.rb
84
+ - db/migrate/2_action_name.rb
85
+ - db/migrate/3_timestamps.rb
86
+ - lib/notify_me.rb
87
+ - lib/notify_me/active_record.rb
88
+ - lib/notify_me/config.rb
89
+ - lib/notify_me/engine.rb
90
+ - lib/notify_me/version.rb
91
+ - notify_me.gemspec
92
+ - spec/acceptance/actions_spec.rb
93
+ - spec/acceptance/notifications_spec.rb
94
+ - spec/internal/app/models/user.rb
95
+ - spec/internal/config/database.yml
96
+ - spec/internal/db/schema.rb
97
+ - spec/internal/log/.gitignore
98
+ - spec/spec_helper.rb
99
+ homepage: https://github.com/samsinite/notify_me
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.0.3
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: Notfy Me
123
+ test_files: []