Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial pfeeds commit

  • Loading branch information...
commit 38aeba725cd6704fb9ff30df5008f184a5ba76c3 1 parent 632a6d7
Russell authored
Showing with 1,066 additions and 52 deletions.
  1. +5 −0 app/models/pfeeds/user_commented.rb
  2. +5 −0 app/views/pfeeds/_user_commented.html.erb
  3. +18 −0 db/migrate/20100609190538_create_pfeed_items.rb
  4. +15 −0 db/migrate/20100609190539_create_pfeed_deliveries.rb
  5. +71 −52 db/schema.rb
  6. +20 −0 vendor/plugins/inflectionist/MIT-LICENSE
  7. +37 −0 vendor/plugins/inflectionist/README
  8. +23 −0 vendor/plugins/inflectionist/Rakefile
  9. +6 −0 vendor/plugins/inflectionist/init.rb
  10. +1 −0  vendor/plugins/inflectionist/install.rb
  11. +39 −0 vendor/plugins/inflectionist/lib/inflectionist.rb
  12. +21 −0 vendor/plugins/inflectionist/lib/inflections.rb
  13. +24 −0 vendor/plugins/inflectionist/lib/string_ext.rb
  14. +4 −0 vendor/plugins/inflectionist/tasks/inflectionist_tasks.rake
  15. +8 −0 vendor/plugins/inflectionist/test/inflectionist_test.rb
  16. +3 −0  vendor/plugins/inflectionist/test/test_helper.rb
  17. +1 −0  vendor/plugins/inflectionist/uninstall.rb
  18. +20 −0 vendor/plugins/pfeed/MIT-LICENSE
  19. +104 −0 vendor/plugins/pfeed/README.markdown
  20. +23 −0 vendor/plugins/pfeed/Rakefile
  21. +4 −0 vendor/plugins/pfeed/app/models/pfeed_delivery.rb
  22. +172 −0 vendor/plugins/pfeed/app/models/pfeed_item.rb
  23. +15 −0 vendor/plugins/pfeed/app/models/pfeeds/user_updated_attribute.rb
  24. +3 −0  vendor/plugins/pfeed/app/views/pfeeds/_pfeed.html.erb
  25. +3 −0  vendor/plugins/pfeed/app/views/pfeeds/_pfeed_item.html.erb
  26. +4 −0 vendor/plugins/pfeed/app/views/pfeeds/_user_updated_attribute.html.erb
  27. +18 −0 vendor/plugins/pfeed/db/migrate/0000_create_pfeed_items.rb
  28. +15 −0 vendor/plugins/pfeed/db/migrate/0001_create_pfeed_deliveries.rb
  29. +2 −0  vendor/plugins/pfeed/generators/pfeed_customization/USAGE
  30. +26 −0 vendor/plugins/pfeed/generators/pfeed_customization/pfeed_customization_generator.rb
  31. +5 −0 vendor/plugins/pfeed/generators/pfeed_customization/templates/pfeed_model.rb
  32. +5 −0 vendor/plugins/pfeed/generators/pfeed_customization/templates/pfeed_view.html.erb
  33. +18 −0 vendor/plugins/pfeed/init.rb
  34. +1 −0  vendor/plugins/pfeed/install.rb
  35. +102 −0 vendor/plugins/pfeed/lib/pfeed.rb
  36. +21 −0 vendor/plugins/pfeed/lib/pfeed_utils.rb
  37. +54 −0 vendor/plugins/pfeed/tasks/pfeed.rake
  38. +75 −0 vendor/plugins/pfeed/test/lib/pfeed_test.rb
  39. +11 −0 vendor/plugins/pfeed/test/lib/pfeed_utils_test.rb
  40. +63 −0 vendor/plugins/pfeed/test/test_helper.rb
  41. +1 −0  vendor/plugins/pfeed/uninstall.rb
View
5 app/models/pfeeds/user_commented.rb
@@ -0,0 +1,5 @@
+class Pfeeds::UserCommented < PfeedItem
+ def pack_data(method_name,method_name_in_past_tense,returned_result,*args_supplied_to_method,&block_supplied_to_method)
+ super
+ end
+ end
View
5 app/views/pfeeds/_user_commented.html.erb
@@ -0,0 +1,5 @@
+<%= user_commented.guess_identification(user_commented.originator)%>
+
+<%= user_commented.data[:action_string] %>
+
+about <%= time_ago_in_words(user_commented.created_at) %> ago
View
18 db/migrate/20100609190538_create_pfeed_items.rb
@@ -0,0 +1,18 @@
+class CreatePfeedItems < ActiveRecord::Migration
+ def self.up
+ create_table :pfeed_items do |t|
+ t.string :type
+ t.integer :originator_id
+ t.string :originator_type
+ t.integer :participant_id
+ t.string :participant_type
+ t.text :data
+ t.datetime :expiry
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :pfeed_items
+ end
+end
View
15 db/migrate/20100609190539_create_pfeed_deliveries.rb
@@ -0,0 +1,15 @@
+class CreatePfeedDeliveries < ActiveRecord::Migration
+ def self.up
+
+ create_table :pfeed_deliveries do |t|
+ t.integer :pfeed_receiver_id
+ t.string :pfeed_receiver_type
+ t.integer :pfeed_item_id
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :pfeed_deliveries
+ end
+end
View
123 db/schema.rb
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20100608230348) do
+ActiveRecord::Schema.define(:version => 20100609190539) do
create_table "announcements", :force => true do |t|
t.string "prefix"
@@ -23,15 +23,15 @@
end
create_table "answers", :force => true do |t|
- t.integer "question_id", :default => 0
- t.integer "user_id", :limit => 8, :default => 0
- t.text "answer"
- t.integer "votes_tally", :default => 0
- t.integer "comments_count", :default => 0
+ t.integer "question_id", :default => 0
+ t.integer "user_id", :limit => 8, :default => 0
+ t.text "answer", :limit => 2147483647
+ t.integer "votes_tally", :default => 0
+ t.integer "comments_count", :default => 0
t.datetime "created_at"
t.datetime "updated_at"
- t.boolean "is_blocked", :default => false
- t.boolean "is_featured", :default => false
+ t.boolean "is_blocked", :default => false
+ t.boolean "is_featured", :default => false
t.datetime "featured_at"
end
@@ -67,34 +67,35 @@
add_index "audios", ["user_id"], :name => "index_audios_on_user_id"
create_table "cards", :force => true do |t|
- t.string "name"
- t.string "short_caption"
- t.text "long_caption"
- t.integer "points", :default => 0
- t.string "slug_name"
- t.boolean "not_sendable", :default => false
- t.boolean "is_featured", :default => false
+ t.string "name", :default => ""
+ t.string "short_caption", :default => ""
+ t.text "long_caption", :limit => 2147483647
+ t.integer "points", :default => 0
+ t.string "slug_name", :limit => 25, :default => ""
+ t.boolean "not_sendable", :default => false
+ t.datetime "created_at", :null => false
+ t.datetime "available_at", :null => false
+ t.boolean "is_featured", :default => false
t.datetime "updated_at"
- t.integer "sent_count", :default => 0
- t.datetime "created_at"
+ t.integer "sent_count", :default => 0
end
create_table "comments", :force => true do |t|
- t.integer "commentid", :default => 0
- t.integer "commentable_id", :default => 0
- t.integer "contentid", :default => 0
- t.text "comments"
- t.string "postedByName", :default => ""
- t.integer "postedById", :default => 0
- t.integer "user_id", :default => 0
+ t.integer "commentid", :default => 0
+ t.integer "commentable_id", :default => 0
+ t.integer "contentid", :default => 0
+ t.text "comments", :limit => 2147483647
+ t.string "postedByName", :default => ""
+ t.integer "postedById", :default => 0
+ t.integer "user_id", :default => 0
t.datetime "created_at"
- t.boolean "is_blocked", :default => false
- t.integer "videoid", :default => 0
+ t.boolean "is_blocked", :default => false
+ t.integer "videoid", :default => 0
t.datetime "updated_at"
t.string "commentable_type"
- t.integer "flags_count", :default => 0
- t.integer "votes_tally", :default => 0
- t.boolean "is_featured", :default => false
+ t.integer "flags_count", :default => 0
+ t.integer "votes_tally", :default => 0
+ t.boolean "is_featured", :default => false
t.datetime "featured_at"
end
@@ -158,7 +159,6 @@
add_index "contents", ["contentid"], :name => "contentid"
add_index "contents", ["story_type"], :name => "index_contents_on_story_type"
add_index "contents", ["title"], :name => "relatedItems"
- add_index "contents", ["title"], :name => "relatedText"
create_table "dashboard_messages", :force => true do |t|
t.string "message"
@@ -351,32 +351,51 @@
add_index "metadatas", ["metadatable_type", "metadatable_id"], :name => "index_metadatas_on_metadatable_type_and_metadatable_id"
create_table "newswires", :force => true do |t|
- t.string "title", :default => ""
- t.text "caption"
- t.string "source", :limit => 150, :default => ""
- t.string "url", :default => ""
+ t.string "title", :default => ""
+ t.text "caption", :limit => 2147483647
+ t.string "source", :limit => 150, :default => ""
+ t.string "url", :default => ""
t.datetime "created_at"
- t.integer "wireid", :default => 0
- t.string "feedType", :default => "wire"
- t.string "mediaUrl", :default => ""
- t.string "imageUrl", :default => ""
- t.text "embed"
- t.integer "feed_id", :default => 0
+ t.integer "wireid", :default => 0
+ t.string "feedType", :default => "wire"
+ t.string "mediaUrl", :default => ""
+ t.string "imageUrl", :default => ""
+ t.text "embed", :limit => 2147483647
+ t.integer "feed_id", :default => 0
t.datetime "updated_at"
- t.boolean "published", :default => false
+ t.boolean "published", :default => false
end
- add_index "newswires", ["feed_id"], :name => "feedid"
add_index "newswires", ["title"], :name => "index_newswires_on_title"
+ create_table "pfeed_deliveries", :force => true do |t|
+ t.integer "pfeed_receiver_id"
+ t.string "pfeed_receiver_type"
+ t.integer "pfeed_item_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "pfeed_items", :force => true do |t|
+ t.string "type"
+ t.integer "originator_id"
+ t.string "originator_type"
+ t.integer "participant_id"
+ t.string "participant_type"
+ t.text "data"
+ t.datetime "expiry"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "questions", :force => true do |t|
t.integer "user_id", :limit => 8, :default => 0
t.string "question", :default => ""
t.text "details"
t.integer "votes_tally", :default => 0
t.integer "comments_count", :default => 0
- t.datetime "created_at"
t.integer "answers_count", :default => 0
+ t.datetime "created_at"
t.datetime "updated_at"
t.boolean "is_blocked", :default => false
t.boolean "is_featured", :default => false
@@ -497,15 +516,15 @@
add_index "translations", ["locale_id", "key", "pluralization_index"], :name => "index_translations_on_locale_id_and_key_and_pluralization_index"
create_table "user_profiles", :force => true do |t|
- t.integer "user_id", :limit => 8, :null => false
- t.integer "facebook_user_id", :limit => 8, :default => 0
- t.boolean "isAppAuthorized", :default => false
- t.datetime "born_at"
- t.timestamp "created_at", :null => false
- t.datetime "updated_at"
- t.text "bio"
- t.integer "referred_by_user_id", :limit => 8, :default => 0
- t.boolean "comment_notifications", :default => false
+ t.integer "user_id", :limit => 8, :null => false
+ t.integer "facebook_user_id", :limit => 8, :default => 0
+ t.boolean "isAppAuthorized", :default => false
+ t.datetime "born_at"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at"
+ t.text "bio", :limit => 2147483647
+ t.integer "referred_by_user_id", :limit => 8, :default => 0
+ t.boolean "comment_notifications", :default => false
end
add_index "user_profiles", ["user_id"], :name => "index_user_infos_on_user_id", :unique => true
View
20 vendor/plugins/inflectionist/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 [name of plugin creator]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
37 vendor/plugins/inflectionist/README
@@ -0,0 +1,37 @@
+Inflectionist
+=============
+
+The old school ActiveSupport's inflections allowed you to pluralize, singularize , humanize etc. And when you wanted little more complex linguistic processing , you found nothing. Here comes Inflectionist for your rescue. It is an extension to ActiveSupport inflections available in form of a rails plugin. For now, this will allow you to find simple past tense of any given word.
+
+
+
+Example
+=======
+ With this plugin installed in your rails app, you will be able to perform operations on strings this way...
+
+ "create".to_past_tense => "created"
+ "buy".to_past_tense => "bought"
+ "fight".to_past_tense => "fought"
+ "market".to_past_tense => "marketed"
+ "animate".to_past_tense => "animated"
+ "fluctuate".to_past_tense => "fluctuated"
+ "tag".to_past_tense => "tagged"
+ "feel".to_past_tense => "felt"
+
+
+Installation
+============
+
+ script/plugin install git://github.com/parolkar/inflectionist.git
+
+
+
+Goals & TODO
+============
+1.) Implement past to present tense conversion
+2.) Implement more complex linguistic processing
+3.) Add more inflections
+
+
+
+Copyright (c) 2009 Er Abhishek Parolkar, released under the MIT license
View
23 vendor/plugins/inflectionist/Rakefile
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the inflectionist plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the inflectionist plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'Inflectionist'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
View
6 vendor/plugins/inflectionist/init.rb
@@ -0,0 +1,6 @@
+# Author: Er Abhishek Parolkar
+
+require File.dirname(__FILE__) + '/lib/inflectionist'
+require File.dirname(__FILE__) + '/lib/inflections'
+require File.dirname(__FILE__) + '/lib/string_ext'
+ActiveSupport::Inflector.send(:extend, ParolkarInnovationLab::Inflectionist)
View
1  vendor/plugins/inflectionist/install.rb
@@ -0,0 +1 @@
+# Install hook code here
View
39 vendor/plugins/inflectionist/lib/inflectionist.rb
@@ -0,0 +1,39 @@
+#Copyright (c) 2009 Er Abhishek Parolkar, released under the MIT license
+module ParolkarInnovationLab
+ module Inflectionist
+
+ def past_tensed(word)
+ result = word.to_s.dup
+
+ if word.empty? || inflections.uncountables.include?(result.downcase)
+ result
+ else
+ inflections.past_tenses.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
+ result
+ end
+ end
+ end
+end
+
+
+
+ ActiveSupport::Inflector::Inflections.instance.instance_eval do # Keep in mind Inflections is a singleton, so what makes more sense is to inject our methods at run time to the instance
+
+ def past_tenses # a attr_reader
+ @past_tenses
+ end
+ def past_tense(rule, replacement)
+ @past_tenses = [] if !@past_tenses
+ @uncountables.delete(rule) if rule.is_a?(String)
+ @uncountables.delete(replacement)
+ @past_tenses.insert(0, [rule, replacement])
+ end
+
+ end
+
+
+
+
+
+
+
View
21 vendor/plugins/inflectionist/lib/inflections.rb
@@ -0,0 +1,21 @@
+# this is where we define all the inflections for functionalities added by inflectionist plugin
+
+ActiveSupport::Inflector.inflections do |inflect|
+ inflect.past_tense /^(.*)$/,'\1ed'
+ inflect.past_tense /e$/,'ed'
+ inflect.past_tense /t$/,'ted'
+ inflect.past_tense /g$/,'gged'
+ inflect.past_tense /ight$/,'ought'
+ inflect.past_tense "buy",'bought'
+ inflect.past_tense "sell",'sold'
+ inflect.past_tense "is",'was'
+ inflect.past_tense "are",'were'
+ inflect.past_tense "teach",'taught'
+ inflect.past_tense "feel",'felt'
+ inflect.past_tense "light",'lit'
+ inflect.past_tense "find",'found'
+
+
+
+
+end
View
24 vendor/plugins/inflectionist/lib/string_ext.rb
@@ -0,0 +1,24 @@
+
+
+# in case active_support/inflector is required without the rest of active_support
+require 'active_support/inflections'
+require 'active_support/core_ext/string/inflections'
+require 'active_support/inflector' unless defined?(ActiveSupport::Inflector)
+
+module ActiveSupport
+ module CoreExtensions
+ module String #:nodoc:
+ module Inflections
+ def past_tensed
+ Inflector.past_tensed(self)
+ end
+ def to_past_tense
+ past_tensed
+ end
+ end
+ end
+ end
+end
+
+String.send :include, ActiveSupport::CoreExtensions::String::Inflections # this is required for above changes to take effect
+
View
4 vendor/plugins/inflectionist/tasks/inflectionist_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :inflectionist do
+# # Task goes here
+# end
View
8 vendor/plugins/inflectionist/test/inflectionist_test.rb
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class InflectionistTest < ActiveSupport::TestCase
+ # Replace this with your real tests.
+ test "the truth" do
+ assert true
+ end
+end
View
3  vendor/plugins/inflectionist/test/test_helper.rb
@@ -0,0 +1,3 @@
+require 'rubygems'
+require 'active_support'
+require 'active_support/test_case'
View
1  vendor/plugins/inflectionist/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
View
20 vendor/plugins/pfeed/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Er Abhishek Parolkar ( abhishek [at] parolkar.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
104 vendor/plugins/pfeed/README.markdown
@@ -0,0 +1,104 @@
+Pfeed
+======
+
+You need Pfeed when you want to automagically create fancy logs / activity updates in your rails app, asynchronously.
+
+
+### What's so magical here?
+Lets assume you have a model that looks like
+
+<pre>
+<code>
+ class User < ActiveRecord::Base
+ has_many :friends
+ has_one :company
+ def buy(x)
+ ...
+ end
+
+ def sell(x)
+ ...
+ end
+
+ def find_friends
+ ...
+ end
+ end
+</code>
+</pre>
+
+Now lets add two lines at bottom of model definition
+
+<pre>
+<code>
+ emits_pfeeds :on => [:buy,:sell,:find_friends,:update_attribute] , :for => [:itself , :friends] # Note: if feed needs to be received by all users , you could use :for => [:all_in_its_class]
+ receives_pfeed
+</code>
+</pre>
+
+
+And you perform regular operations, like this
+
+<pre>
+<code>
+ u1 = User.first
+ u1.buy(10)
+ u1.sell(5)
+ u2 = User.last
+ list = u2.find_friends
+ u2.update_attribute(:nick_name, "alice")
+ u2.buy (1)
+</code>
+</pre>
+your application now emits feed without any other additional piece of code, and feed will look like this in view.
+<pre><code>
+ parolkar sold item about 6 minutes ago
+ parolkar bought item about 4 minutes ago
+ foo found friends about 2 minutes ago
+ foo updated attribute nick name about 2 minutes ago
+ alice bought item about 2 minutes ago
+</code></pre>
+
+Isn't it magical? that it guesses the identity of model object (parolkar or foo in this case) and methods being called are treated as verbs to form a simple past tense.
+
+Even more, each feed can be customized and skinned the way you want. You can easily extend the functionality to suit your requirements.
+
+If all this excites you, check out the tutorials [here](http://wiki.github.com/parolkar/pfeed "pfeed's Wiki") or explore some more advanced techniques [here](http://wiki.github.com/parolkar/pfeed/customizing-the-pfeed-item "pfeed customisation techniques")
+
+
+## Performance
+
+*How efficient is feed generation and delivery?*
+
+ If your app has mechanisms for asynchronous processing, like delayed_job , pfeed plugin will automatically figure out how to schedule the delivery in the queue so that your request loop remains efficient and workers can perform deliveries. [Find out more](http://wiki.github.com/parolkar/pfeed/pfeed-delivery-as-background-job "pfeed delivery as background job")
+
+## More Details
+
+*What is feed?*
+Feed is the collection of activity logs which is generated while you perform actions on model objects.
+
+*Whats so special?, Why should I bother about it?*
+
+Imagine you want to create admin console for your app to monitor functional activities in your web apps ,i.e how users are using different parts of application. You will need to think of mechanism to capture the logs and then display in some logical manner.
+
+OR
+
+Imagine you are building an app like facebook and you want to capture all activity user is performing and display it to her friends/group member/admin , Its a whole new feature whose implementation will force you to dig into design of your app and see where all the logs get generated and then to whom all the logs are going to be published.
+
+What if I give you a generalized information model which will allow you to create such feature by keeping it completely isolated from your existing logic? and What if it is really scalable enough?
+
+(more content to come here...)
+
+
+## Installation
+
+<pre>
+<code>
+ $ script/plugin install git://github.com/parolkar/pfeed.git
+ $ rake pfeed:setup
+</code>
+</pre>
+
+
+
+Copyright (c) 2009 [Abhishek Parolkar] abhishek[at]parolkar.com , released under the MIT license
View
23 vendor/plugins/pfeed/Rakefile
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the has_profile_items plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the has_profile_items plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'HasProfileItems'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
View
4 vendor/plugins/pfeed/app/models/pfeed_delivery.rb
@@ -0,0 +1,4 @@
+class PfeedDelivery < ActiveRecord::Base
+ belongs_to :pfeed_receiver, :polymorphic => true
+ belongs_to :pfeed_item
+end
View
172 vendor/plugins/pfeed/app/models/pfeed_item.rb
@@ -0,0 +1,172 @@
+class PfeedItem < ActiveRecord::Base
+
+ serialize :data, Hash
+ serialize :participants, Array
+
+ belongs_to :originator, :polymorphic => true
+ belongs_to :participant, :polymorphic => true
+
+ has_many :pfeed_deliveries, :dependent => :destroy
+
+ attr_accessor :temp_references # this is an temporary Hash to hold references to temporary Objects
+
+ def self.log(ar_obj,method_name,method_name_in_past_tense,returned_result,*args_supplied_to_method,&block_supplied_to_method)
+
+ #puts "#{ar_obj.class.to_s},#{method_name},#{method_name_in_past_tense},#{returned_result},#{args_supplied_to_method.length}"
+
+ # optional :if => :test, or :unless => :test
+ if if_cond = ar_obj.pfeed_options[:if]
+ return unless ar_obj.send(if_cond)
+ elsif unless_cond = ar_obj.pfeed_options[:unless]
+ return if ar_obj.send(unless_cond)
+ end
+
+ raise ArgumentError, "originator object must to be saved" if ar_obj.new_record?
+
+ temp_references = Hash.new
+ temp_references[:originator] = ar_obj
+ temp_references[:participant] = nil
+ temp_references[:participant] = args_supplied_to_method[0] if args_supplied_to_method && args_supplied_to_method.length >= 1 && args_supplied_to_method[0].class.superclass.to_s == "ActiveRecord::Base"
+
+ pfeed_class_name = "#{ar_obj.class.to_s.underscore}_#{method_name_in_past_tense}".camelize # may be I could use .classify
+ constructor_options = { :originator_id => temp_references[:originator].id , :originator_type => temp_references[:originator].class.to_s , :participant_id => (temp_references[:participant] ? temp_references[:participant].id : nil) , :participant_type => (temp_references[:participant] ? temp_references[:participant].class.to_s : nil) } # there is a reason why I didnt use {:originator => temp_references[:originator]} , if originator is new record it might get saved here un intentionally
+
+
+ p_item = new_pfeed_item(pfeed_class_name, constructor_options, temp_references)
+ p_item.pack_data(method_name,method_name_in_past_tense,returned_result,*args_supplied_to_method,&block_supplied_to_method)
+
+
+ p_item.save!
+ #puts "Trying to deliver to #{ar_obj} #{ar_obj.pfeed_audience_hash[method_name.to_sym]}"
+ p_item.attempt_delivery(ar_obj,ar_obj.pfeed_audience_hash[method_name.to_sym]) # attempting the delivery of the feed
+ end
+
+ @@dj = (defined? Delayed) == "constant" && (instance_methods.include? 'send_later') #this means Delayed_job exists , so make use of asynchronous delivery of pfeed
+
+ def attempt_delivery (ar_obj,method_name_arr)
+ return if method_name_arr.empty?
+
+ if @@dj
+ send_later(:deliver,ar_obj,method_name_arr)
+ else # regular instant delivery
+ send(:deliver,ar_obj,method_name_arr)
+ end
+ end
+
+ def deliver(ar_obj,method_name_arr)
+ method_name_arr.map { |method_name|
+ ar_obj.send(method_name)
+ }.flatten.uniq.map {|o| deliver_to(o) }.compact
+ end
+
+ def deliver_to(result_obj)
+ return nil unless result_obj != nil && begin
+ result_obj.is_pfeed_receiver
+ rescue NoMethodError
+ raise NoMethodError, "you must use the receives_pfeed macro for class: #{result_obj.class}"
+ end
+
+ if !result_obj.new_record?
+ delivery = PfeedDelivery.new
+ delivery.pfeed_item = self
+ delivery.pfeed_receiver = result_obj
+ delivery.save!
+ end
+
+ return result_obj
+ end
+
+ def accessible?
+ true
+ end
+
+ def view_template_name
+ "#{self.class.to_s.underscore}".split("/").last
+ end
+
+ def audience
+ # return list of objects to whom feed gets delivered
+ end
+
+ def pack_data(method_name,method_name_in_past_tense,returned_result,*args_supplied_to_method,&block_supplied_to_method)
+ self.data = {} if ! self.data
+ action_string = method_name_in_past_tense.humanize.downcase
+ hash_to_be_merged = {:action_string => action_string, :originator_identity => guess_identification(originator)}
+
+ if current_user = Thread.current[:current_user]
+ hash_to_be_merged.merge!(:current_user_identity => guess_identification(current_user))
+ end
+
+ self.data.merge! hash_to_be_merged
+ end
+
+ IDENTIFICATIONS = {}
+ def guess_identification(ar_obj)
+ if identifier = ar_obj.respond_to?(:pfeed_options) && ar_obj.pfeed_options[:identified_by]
+ return ar_obj.send(identifier)
+ end
+
+ if attribute = IDENTIFICATIONS[ar_obj.class]
+ if (identi = ar_obj.read_attribute(attribute)).blank?
+ identi = ar_obj.send(attribute) rescue nil
+ end
+ return identi if identi
+ end
+
+ possible_attributes = ["username","login","name","company_name","first_name","last_name","login_name","login_id","given_name","nick_name","nick","short_name"]
+
+ possible_attributes = self.data[:config][:identifications] + possible_attributes if self.data[:config] && self.data[:config][:identifications] && self.data[:config][:identifications].is_a?(Array)
+ matched_name = ar_obj.attribute_names & possible_attributes # intersection of two sets
+
+ identi = nil
+ matched_name.each do |attribute|
+ result = ar_obj.read_attribute(attribute)
+ next unless result.present? && result.kind_of?(String)
+ IDENTIFICATIONS[ar_obj.class] = attribute
+ identi = result
+ break
+ end
+
+ if identi.blank?
+ possible_attributes.each do |attribute|
+ next unless ar_obj.respond_to? attribute
+ result = ar_obj.send(attribute) rescue nil
+ next unless result.present? && result.kind_of?(String)
+ IDENTIFICATIONS[ar_obj.class] = attribute
+ identi = result
+ break
+ end
+ end
+
+ identi = "#{ar_obj.class.to_s}(\##{ar_obj.id})" if identi.blank?
+ identi
+ end
+
+ # look for custom pfeed class, with or withour Pfeed:: prefix
+ CUSTOM_CLASSES = {}
+ def self.new_pfeed_item(pfeed_class_name, constructor_options, temp_references)
+ if (klass = CUSTOM_CLASSES[pfeed_class_name]).nil?
+ retried = false
+ begin
+ #puts "Attempting to create object of #{pfeed_class_name} "
+ klass = pfeed_class_name.constantize
+ (CUSTOM_CLASSES[pfeed_class_name] = klass).new(
+ constructor_options.merge(:temp_references => temp_references))
+ rescue NameError
+ unless retried
+ CUSTOM_CLASSES[pfeed_class_name] = false
+ retried = true
+ pfeed_class_name = "Pfeeds::"+pfeed_class_name
+ retry
+ end
+ PfeedItem.new(constructor_options)
+ end
+ else
+ if !klass
+ PfeedItem.new(constructor_options)
+ else
+ klass.new(constructor_options)
+ end
+ end
+ end
+end
View
15 vendor/plugins/pfeed/app/models/pfeeds/user_updated_attribute.rb
@@ -0,0 +1,15 @@
+=begin
+class Pfeeds::UserUpdatedAttribute < PfeedItem
+
+ def pack_data(method_name,method_name_in_past_tense,returned_result,*args_supplied_to_method,&block_supplied_to_method)
+ super
+ self.data = {} if ! self.data
+ attribute_name = args_supplied_to_method[0].to_s.humanize
+ hash_to_be_merged = {:attribute_name => attribute_name}
+
+ self.data.merge! hash_to_be_merged
+ end
+
+end
+=end
+
View
3  vendor/plugins/pfeed/app/views/pfeeds/_pfeed.html.erb
@@ -0,0 +1,3 @@
+<li class="pfeed_container">
+ <%= pfeed_content(pfeed) %>
+</li>
View
3  vendor/plugins/pfeed/app/views/pfeeds/_pfeed_item.html.erb
@@ -0,0 +1,3 @@
+<%= pfeed_item.guess_identification(pfeed_item.originator) -%>
+ <%= pfeed_item.data[:action_string] -%>
+ about <%= time_ago_in_words(pfeed_item.created_at) -%> ago
View
4 vendor/plugins/pfeed/app/views/pfeeds/_user_updated_attribute.html.erb
@@ -0,0 +1,4 @@
+
+<font color="blue"><%= user_updated_attribute.guess_identification(user_updated_attribute.originator) %></font>
+<%= user_updated_attribute.data[:action_string] %> <%= user_updated_attribute.data[:attribute_name] %>
+about <%= time_ago_in_words(user_updated_attribute.created_at) %> ago
View
18 vendor/plugins/pfeed/db/migrate/0000_create_pfeed_items.rb
@@ -0,0 +1,18 @@
+class CreatePfeedItems < ActiveRecord::Migration
+ def self.up
+ create_table :pfeed_items do |t|
+ t.string :type
+ t.integer :originator_id
+ t.string :originator_type
+ t.integer :participant_id
+ t.string :participant_type
+ t.text :data
+ t.datetime :expiry
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :pfeed_items
+ end
+end
View
15 vendor/plugins/pfeed/db/migrate/0001_create_pfeed_deliveries.rb
@@ -0,0 +1,15 @@
+class CreatePfeedDeliveries < ActiveRecord::Migration
+ def self.up
+
+ create_table :pfeed_deliveries do |t|
+ t.integer :pfeed_receiver_id
+ t.string :pfeed_receiver_type
+ t.integer :pfeed_item_id
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :pfeed_deliveries
+ end
+end
View
2  vendor/plugins/pfeed/generators/pfeed_customization/USAGE
@@ -0,0 +1,2 @@
+Description:
+ Creates a Pfeed model and view for customizing pfeed output
View
26 vendor/plugins/pfeed/generators/pfeed_customization/pfeed_customization_generator.rb
@@ -0,0 +1,26 @@
+class PfeedCustomizationGenerator < Rails::Generator::Base
+ attr_reader :past_classname
+ attr_reader :past_varname
+
+ def initialize(args, other = {})
+ super
+ @model, @current_action = args
+ @past_action = ParolkarInnovationLab::SocialNet::PfeedUtils.attempt_pass_tense(@current_action)
+ @past = @model.downcase + '_' + @past_action
+ @past_classname = @model.capitalize + @past_action.capitalize
+ @past_varname = @model.downcase + '_' + @past_action.downcase
+ @model_filename = @past + '.rb'
+ @view_filename = '_' + @past + '.html.erb'
+ end
+
+
+ def manifest
+ record do |m|
+ m.directory('app/models/pfeeds')
+ m.directory('app/views/pfeeds')
+ m.template('pfeed_model.rb', "app/models/pfeeds/#{@model_filename}")
+ m.template('pfeed_view.html.erb', "app/views/pfeeds/#{@view_filename}")
+ end
+ end
+
+end
View
5 vendor/plugins/pfeed/generators/pfeed_customization/templates/pfeed_model.rb
@@ -0,0 +1,5 @@
+class Pfeeds::<%= past_classname %> < PfeedItem
+ def pack_data(method_name,method_name_in_past_tense,returned_result,*args_supplied_to_method,&block_supplied_to_method)
+ super
+ end
+ end
View
5 vendor/plugins/pfeed/generators/pfeed_customization/templates/pfeed_view.html.erb
@@ -0,0 +1,5 @@
+<%%= <%= past_varname %>.guess_identification(<%= past_varname %>.originator)%>
+
+<%%= <%= past_varname %>.data[:action_string] %>
+
+about <%%= time_ago_in_words(<%= past_varname %>.created_at) %> ago
View
18 vendor/plugins/pfeed/init.rb
@@ -0,0 +1,18 @@
+# Author: Er Abhishek Parolkar
+
+require File.dirname(__FILE__) + '/lib/pfeed'
+require File.dirname(__FILE__) + '/lib/pfeed_utils'
+ActiveRecord::Base.send(:include, ParolkarInnovationLab::SocialNet)
+
+ActionController::Base.helper do
+ def pfeed_content(pfeed)
+ controller.send('render_to_string',
+ :partial => "pfeeds/#{pfeed.view_template_name}.html.erb", :locals => {:object => pfeed})
+ end
+
+ def pfeed_item_url(pfeed_item)
+ # same as: polymorphic_url pfeed_item.originator
+ # but no need to query the database
+ send(pfeed_item.originator_type.underscore + '_url', pfeed_item.originator_id)
+ end
+end
View
1  vendor/plugins/pfeed/install.rb
@@ -0,0 +1 @@
+# Install hook code here
View
102 vendor/plugins/pfeed/lib/pfeed.rb
@@ -0,0 +1,102 @@
+#snippet: https://gist.github.com/89e92409ca9016d2d919
+
+module ParolkarInnovationLab
+ module SocialNet
+ def self.included(base)
+ base.extend ParolkarInnovationLab::SocialNet::ClassMethods
+ end
+
+ module ClassMethods
+
+ def emits_pfeeds arg_hash # {:on => [] , :for => [:itself , :all_in_its_class], :identified_by => :name, :if => :passes_test?}
+ arg_hash.assert_valid_keys(:on,:for,:if,:unless,:identified_by)
+ [:on, :for].each do |argument|
+ raise ArgumentError, "Expected an argument: #{argument}" if !arg_hash[argument]
+ end
+
+ include ParolkarInnovationLab::SocialNet::InstanceMethods
+
+ method_name_array = [*arg_hash[:on]]
+ class_inheritable_hash :pfeed_audience_hash
+
+ method_name_array.each{|method_name| register_pfeed_audience(method_name,[*arg_hash[:for]].compact) }
+
+ class_inheritable_hash :pfeed_options
+ write_inheritable_hash :pfeed_options, arg_hash.slice(:if,:unless,:identified_by)
+
+
+
+ method_name_array.each { |method_name|
+ method, symbol = method_name.to_s.split /(\!|\?)/
+ symbol = '' if symbol.nil?
+
+ method_to_define = method + '_with_pfeed' + symbol
+ method_to_be_called = method + '_without_pfeed' + symbol
+ eval %[
+
+ module ::ParolkarInnovationLab::SocialNet::PfeedTemp::#{self.to_s}
+ def #{method_to_define}(*a, &b)
+ returned_result = #{method_to_be_called}(*a , &b)
+ method_name_in_past_tense = "#{ParolkarInnovationLab::SocialNet::PfeedUtils.attempt_pass_tense(method)}"
+ PfeedItem.log(self,"#{method_name}",method_name_in_past_tense,returned_result,*a,&b)
+ returned_result
+ end
+ end
+ ]
+
+ }
+
+ #TODO : Pfeed.log(self,"#{method_name}",method_name_in_past_tense,returned_result,*a,*b) : this is to be done in a different thread in bg to boost performance & also needs exception handling such that parent call never breaks
+
+ include "::ParolkarInnovationLab::SocialNet::PfeedTemp::#{self.to_s}".constantize # why this? because "define_method((method + '_with_pfeed' + symbol).to_sym) do |*a , &b|" generates syntax error in ruby < 1.8.7
+
+ method_name_array.each { |method_name|
+ method, symbol = method_name.to_s.split /(\!|\?)/
+ symbol = '' if symbol.nil?
+ alias_method_chain (method + symbol), :pfeed
+ }
+
+ has_many :pfeed_items , :as => :originator , :dependent => :destroy #when originator is deleted the pfeed_items gets destroyed too
+
+
+ end
+
+ def receives_pfeed
+ has_many :pfeed_deliveries , :as => :pfeed_receiver
+ has_many :pfeed_inbox, :class_name => 'PfeedItem', :foreign_key => "pfeed_item_id" , :through => :pfeed_deliveries , :source => :pfeed_item
+
+ write_inheritable_attribute(:is_pfeed_receiver,true)
+ class_inheritable_reader :is_pfeed_receiver
+ end
+
+ def register_pfeed_audience(method_name,audience_arr)
+ write_inheritable_hash(:pfeed_audience_hash, { method_name.to_sym => audience_arr }) # this does a merge
+ end
+ end
+
+ module PfeedTemp
+ # Required for temporarily injecting new methods
+ end
+ module InstanceMethods
+
+ def itself
+ self
+ end
+ def all_in_its_class
+ self.class.find :all
+ end
+
+ def pfeed_recent_item_timestamp
+ self.pfeed_deliveries.last.created_at
+ rescue
+ nil
+ end
+
+ private
+ #let private methods come here
+ end
+ end
+end
+
+
+
View
21 vendor/plugins/pfeed/lib/pfeed_utils.rb
@@ -0,0 +1,21 @@
+module ParolkarInnovationLab
+ module SocialNet
+ module PfeedUtils
+ extend self
+ def attempt_pass_tense str_obj
+ #What can it do?
+ # it can automagically transform
+ # "addFriend" => "added_friend"
+ # "fightWithFriend" => "faught_with_friend"
+ # "buy_item" => "baught_item"
+ #the magic trick "abhishekParolkar hu hu".underscore.parameterize.underscore.to_s
+ str = str_obj.dup
+ str = str.underscore.parameterize.underscore.to_s
+ str_arr = str.split("_")
+ str_arr[0] = str_arr[0].to_past_tense # this is from infectionist ( script/plugin install git://github.com/parolkar/inflectionist.git )
+ str = str_arr.join("_")
+ end
+ end
+ end
+end
+
View
54 vendor/plugins/pfeed/tasks/pfeed.rake
@@ -0,0 +1,54 @@
+namespace :pfeed do
+
+ desc 'Sets up parolkar\'s pfeed plugin '
+ task :setup do
+ root = "#{Rails.root}"
+ raise 'pfeed plugin was only tested on unix & windows' if ! Rake.application.unix? && ! Rake.application.windows?
+
+ if ! File.exists?("#{root}/vendor/plugins/inflectionist")
+ puts "Inflectionist plugin is required by pfeed, while you dont seem to have it installed \n Attempting to install..."
+ system "#{root}/script/plugin install git://github.com/parolkar/inflectionist.git "
+ end
+
+ raise '...something went wrong please install http://github.com/parolkar/inflectionist first!' if ! File.exists?("#{root}/vendor/plugins/inflectionist")
+
+
+ files_to_be_copied = [
+ {:source => "/vendor/plugins/pfeed/db/migrate/0000_create_pfeed_items.rb", :target => "/db/migrate/#{migration_timestamp}_create_pfeed_items.rb" },
+ {:source => "/vendor/plugins/pfeed/db/migrate/0001_create_pfeed_deliveries.rb", :target => "/db/migrate/#{migration_timestamp}_create_pfeed_deliveries.rb" }
+ ]
+
+
+ FileUtils.mkdir_p("#{root}/db/migrate") unless File.exists?("#{root}/db/migrate")
+ files_to_be_copied.each {|ftbc|
+ FileUtils.cp_r(root+ftbc[:source], root+ftbc[:target]) #:force => true)
+ puts "Created : #{ftbc[:target]}"
+ }
+
+ puts "Running \"rake db:migrate\" for you..."
+ Rake::Task["db:migrate"].invoke
+
+
+
+ welcome_screen
+
+ end
+
+ def migration_timestamp
+ sleep (1)
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
+
+ end
+
+ def welcome_screen
+
+ mesg = <<HERE
+Congratulations for setting the plugin!
+
+
+HERE
+
+ puts mesg
+ end
+
+end
View
75 vendor/plugins/pfeed/test/lib/pfeed_test.rb
@@ -0,0 +1,75 @@
+require 'test_helper'
+
+load_schema
+
+def pfeed
+ PfeedItem.find_by_originator_id(topic.id)
+end
+
+class Emitter < ActiveRecord::Base
+ def if_false_ping; end
+ def if_false; false end
+ def if_true_ping; end
+ def if_true; true end
+ def if_true_and_identified_ping; end
+
+ def unless_false_ping; end
+ def unless_false; false end
+ def unless_true_ping; end
+ def unless_true; true end
+
+ # for testing :identified_by
+ def custom_identifier; "my custom name" end
+
+ receives_pfeed
+end
+
+context 'an emitter not satisfying an if or unless condition' do
+ setup do
+ Emitter.class_eval do
+ emits_pfeeds :on => :if_false_ping, :if => :if_false, :for => :itself
+ emits_pfeeds :on => :unless_true_ping, :unless => :unless_true, :for => :itself
+ end
+ Emitter.new.if_false_ping
+ Emitter.new.unless_true_ping
+ end
+ should("not create a pfeed item") { PfeedItem.all.empty? }
+end
+
+context 'an emitter satisfying an if condition' do
+ setup do
+ Emitter.class_eval do
+ emits_pfeeds :on => :if_true_ping, :if => :if_true, :for => :itself
+ end
+ returning(Emitter.create!(:name => 'bob')) do |e|
+ e.if_true_ping
+ end
+ end
+ should("create a pfeed item") { !PfeedItem.all.empty? }
+ should("guess the name") { pfeed.data[:originator_identity] }.equals('bob')
+end
+
+context 'an emitter satisfying an unless condition' do
+ setup do
+ Emitter.class_eval do
+ emits_pfeeds :on => :unless_false_ping, :unless => :unless_false, :for => :itself
+ end
+ e = Emitter.create!
+ e.unless_false_ping
+ end
+ should("create a pfeed item") { !PfeedItem.all.empty? }
+end
+
+context 'an emitter satisfying an identified_by condition' do
+ setup do
+ Emitter.class_eval do
+ emits_pfeeds :on => :if_true_and_identified_ping, :for => :itself, :identified_by => :custom_identifier
+ end
+ returning(Emitter.create!(:name => 'bob')) do |e|
+ e.if_true_ping
+ end
+ end
+ should("create a pfeed item") { !PfeedItem.all.empty? }
+ should("guess the name") { pfeed.data[:originator_identity] }.equals('my custom name')
+end
+
View
11 vendor/plugins/pfeed/test/lib/pfeed_utils_test.rb
@@ -0,0 +1,11 @@
+require 'test_helper'
+
+context 'attempting past tense' do
+ def _(verb, past_tense)
+ asserts('') {ParolkarInnovationLab::SocialNet::PfeedUtils.attempt_pass_tense(verb)}.equals(past_tense)
+ end
+
+ _ "addFriend", "added_friend"
+ _ "fightWithFriend", "fought_with_friend"
+ _ "buy_item", "bought_item"
+end
View
63 vendor/plugins/pfeed/test/test_helper.rb
@@ -0,0 +1,63 @@
+ENV['RAILS_ENV'] = 'test'
+
+require 'rubygems'
+require 'active_record'
+require 'action_controller'
+require 'active_support'
+
+def __DIR__
+ File.dirname(__FILE__)
+end
+require "#{__DIR__}/../init"
+
+require 'riot'
+
+# ?
+class String
+ unless methods.include? 'normalize'
+ def normalize *args
+ self
+ end
+ end
+end
+
+begin # infletionist dependency
+ require "#{__DIR__}/../../inflectionist/init"
+rescue LoadError
+ puts "\n\n\nplease install the inflectionist plugin\n\n\n"
+ exit(1)
+end
+
+
+def load_schema
+ Dir["#{__DIR__}/../app/models/**/*.rb"].each { |f| require f }
+
+ ActiveRecord::Base.establish_connection(
+ :adapter => "sqlite3",
+ :database => ":memory:"
+ )
+
+ ActiveRecord::Schema.define do
+ create_table "emitters", :force => true do |t|
+ t.string 'name'
+ end
+
+ create_table "pfeed_items", :force => true do |t|
+ t.string "type"
+ t.integer "originator_id"
+ t.string "originator_type"
+ t.integer "participant_id"
+ t.string "participant_type"
+ t.text "data"
+ t.datetime 'expiry'
+ t.timestamps
+ end
+
+ create_table "pfeed_deliveries", :force => true do |t|
+ t.integer :pfeed_receiver_id
+ t.integer :pfeed_receiver_type
+ t.integer :pfeed_item_id
+ t.timestamps
+ end
+ end
+end
View
1  vendor/plugins/pfeed/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
Please sign in to comment.
Something went wrong with that request. Please try again.