disclosure 0.0.1

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright 2013 Josh McArthur
2
+
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = Disclosure
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Disclosure'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rspec/core/rake_task'
31
+
32
+ RSpec::Core::RakeTask.new(:spec)
33
+
34
+ task :default => :spec
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ module Disclosure
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Disclosure
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,18 @@
1
+ module Disclosure
2
+ class EmailReactor < ActionMailer::Base
3
+ default Disclosure.configuration.email_reactor_defaults
4
+
5
+ def react!(model, action, rule)
6
+ self.notification(model, action, rule).deliver
7
+ end
8
+
9
+ def notification(model, action, rule)
10
+ mail(
11
+ :to => rule.owner.email,
12
+ :subject => t("disclosure.email_reactor.#{rule.notifier_class}.#{action}.subject"),
13
+ :template_path => "disclosure/email/#{rule.notifier_class}",
14
+ :template_name => "action"
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,74 @@
1
+ module Disclosure
2
+ class Rule < ActiveRecord::Base
3
+ belongs_to :owner, :class_name => Disclosure.configuration.owner_class
4
+
5
+ validates :notifier_class, :inclusion => {
6
+ :in => proc { Disclosure.configuration.notifier_classes.map(&:name) }
7
+ }
8
+
9
+ validates :reactor_class, :inclusion => {
10
+ :in => proc { Disclosure.configuration.reactor_classes.map(&:name) }
11
+ }
12
+
13
+ validates :action, :uniqueness => {
14
+ :scope => [:owner_id, :notifier_class]
15
+ }
16
+
17
+ validate :action_in_notifier_actions
18
+
19
+ # Public: Find the notifier class instance from the
20
+ # class name (string) that is saved in the model table.
21
+ #
22
+ # Returns the notifier class or nil
23
+ def notifier
24
+ Disclosure.configuration.notifier_classes.select do |nc|
25
+ nc.name == self.notifier_class
26
+ end.first
27
+ end
28
+
29
+ # Public: Find the reactor class instance from the
30
+ # class name (string) that is saved in the model table.
31
+ #
32
+ # Returns the reactor class or nil
33
+ def reactor
34
+ Disclosure.configuration.reactor_classes.select do |rc|
35
+ rc.name == self.reactor_class
36
+ end.first
37
+ end
38
+
39
+ # Public: Tell the reactor for this rule that it should now react to a change.
40
+ #
41
+ # Passes along the instance of the model that changed, the action that occurred,
42
+ # and the owner of the rule
43
+ #
44
+ # model - The model instance that changed
45
+ #
46
+ # Returns truthy value if the reactor returned successfully, and false if not.
47
+ # Depending on the reactor, may raise exceptions - for example, Net::SMTP errors
48
+ # if sending email.
49
+ def react!(model)
50
+ reactor.react!(model, action, owner)
51
+ end
52
+
53
+ private
54
+
55
+ # Private: Ensure that the configured action is within the
56
+ # actions recorded against the notifier.
57
+ #
58
+ # For example, an Issue may notify actions such as:
59
+ # * created
60
+ # * closed
61
+ #
62
+ # While a Project may only notify creating and updating actions
63
+ #
64
+ # Returns true if the action is valid, or false if not
65
+ def action_in_notifier_actions
66
+ unless notifier && notifier.notifiable_actions.include?(self.action)
67
+ errors.add(:action, :not_in_notifiable_actions)
68
+ return false
69
+ end
70
+
71
+ return true
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Disclosure</title>
5
+ <%= stylesheet_link_tag "disclosure/application", :media => "all" %>
6
+ <%= javascript_include_tag "disclosure/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,9 @@
1
+ Disclosure::Engine.routes.draw do
2
+ # This engine has no routes, as it is more of a backend system for you to use
3
+ # in your own application as you need.
4
+ #
5
+ # If you would like to make your notification rules content-editable, that's really easy!
6
+ # Just add your own controller where you need it, and have it manage all the
7
+ # Disclosure::Rule models in your database!
8
+
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreateDisclosureRules < ActiveRecord::Migration
2
+ def change
3
+ create_table :disclosure_rules do |t|
4
+ t.belongs_to :owner
5
+ t.string :notifier_class
6
+ t.string :reactor_class
7
+ t.string :action
8
+
9
+ t.timestamps
10
+ end
11
+ add_index :disclosure_rules, :owner_id
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ class Disclosure::Configuration
2
+ attr_accessor :owner_class, :notifier_classes, :reactor_classes, :email_reactor_defaults
3
+
4
+ def initialize
5
+ self.owner_class = "User"
6
+ self.reactor_classes = []
7
+ self.notifier_classes = []
8
+ self.email_reactor_defaults = {:from => "please-change-me@localhost"}
9
+ end
10
+
11
+ end
@@ -0,0 +1,15 @@
1
+ module Disclosure
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Disclosure
4
+
5
+ initializer 'disclosure.subscribe_to_model_events' do
6
+ ActiveSupport::Notifications.subscribe "disclosure.model_saved" do |name, start, finish, id, payload|
7
+ Disclosure.react_to!(payload[:model])
8
+ end
9
+ end
10
+
11
+ initializer 'disclosure.extend_model_classes' do
12
+ Disclosure.bootstrap!
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ class Disclosure::NotifiableActionsNotDefined < RuntimeError
2
+ end
3
+
4
+ class Disclosure::ActionMethodNotDefined < RuntimeError
5
+ end
@@ -0,0 +1,3 @@
1
+ module Disclosure
2
+ VERSION = "0.0.1"
3
+ end
data/lib/disclosure.rb ADDED
@@ -0,0 +1,58 @@
1
+ require "disclosure/engine"
2
+ require 'disclosure/exceptions'
3
+ require "disclosure/configuration"
4
+
5
+ module Disclosure
6
+ class << self
7
+ attr_accessor :configuration
8
+ end
9
+
10
+ def self.bootstrap!
11
+ Disclosure.configuration.notifier_classes.each do |klass|
12
+ if !klass.methods.include?(:notifiable_actions)
13
+ klass.class_eval do
14
+ class << self
15
+ def notifiable_actions
16
+ raise Disclosure::NotifiableActionsNotDefined.new("Notifiable actions must be defined in #{self.name}.")
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ # We don't use an else here, because we may have *just* added
23
+ # the method - it's not a if this, else that - we may need to do both
24
+ if klass.methods.include?(:notifiable_actions)
25
+ # If notifiable actions has just been defined, it will raise an exception
26
+ (klass.notifiable_actions rescue []).each do |action|
27
+ unless klass.instance_methods.include?(:"#{action}?")
28
+ klass.define_method(:"#{action}?") do
29
+ raise Disclosure::ActionMethodNotDefined.new("#{action}? must be defined in #{klass}.")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.react_to!(model)
38
+ unless Disclosure.configuration.notifier_classes.include?(model.class)
39
+ return nil
40
+ end
41
+
42
+ Disclosure::Rule.where(
43
+ :notifier_class => model.class.name,
44
+ :owner_id => model.send("#{Disclosure.configuration.owner_class.underscore}_id")
45
+ ).each do |rule|
46
+ next if !model.send("#{rule.action}?")
47
+ rule.react!(model)
48
+ end
49
+ end
50
+
51
+ def self.configuration
52
+ @configuration ||= Configuration.new
53
+ end
54
+
55
+ def self.configure
56
+ yield(configuration) if block_given?
57
+ end
58
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :disclosure do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: disclosure
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh McArthur
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.12
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.12
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec-rails
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: sqlite3
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: A Rails engine to allow you to easily set up rules and events for when
63
+ each user should receive notifications - great for adding configurable notifications.
64
+ email:
65
+ - joshua.mcarthur+disclosure@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - app/assets/javascripts/disclosure/application.js
71
+ - app/assets/stylesheets/disclosure/application.css
72
+ - app/controllers/disclosure/application_controller.rb
73
+ - app/helpers/disclosure/application_helper.rb
74
+ - app/mailers/disclosure/email_reactor.rb
75
+ - app/models/disclosure/rule.rb
76
+ - app/views/layouts/disclosure/application.html.erb
77
+ - config/routes.rb
78
+ - db/migrate/20130331060054_create_disclosure_rules.rb
79
+ - lib/disclosure/configuration.rb
80
+ - lib/disclosure/engine.rb
81
+ - lib/disclosure/exceptions.rb
82
+ - lib/disclosure/version.rb
83
+ - lib/disclosure.rb
84
+ - lib/tasks/disclosure_tasks.rake
85
+ - MIT-LICENSE
86
+ - Rakefile
87
+ - README.rdoc
88
+ homepage: https://github.com/joshmcarthur/disclosure
89
+ licenses: []
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ segments:
101
+ - 0
102
+ hash: -1278575994465868298
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ segments:
110
+ - 0
111
+ hash: -1278575994465868298
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 1.8.23
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: A Rails engine to allow you to easily set up rules and events for notificaitons.
118
+ test_files: []