postablr 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.
Files changed (82) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +22 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/postablr/application.js +15 -0
  5. data/app/assets/javascripts/postablr/blog.js +2 -0
  6. data/app/assets/javascripts/postablr/entries.js +2 -0
  7. data/app/assets/stylesheets/postablr/application.css +13 -0
  8. data/app/assets/stylesheets/postablr/blog.css +4 -0
  9. data/app/assets/stylesheets/postablr/entries.css +4 -0
  10. data/app/controllers/postablr/application_controller.rb +4 -0
  11. data/app/controllers/postablr/blog_controller.rb +21 -0
  12. data/app/controllers/postablr/entries_controller.rb +43 -0
  13. data/app/helpers/postablr/application_helper.rb +4 -0
  14. data/app/helpers/postablr/blog_helper.rb +27 -0
  15. data/app/helpers/postablr/entries_helper.rb +4 -0
  16. data/app/helpers/postablr/truncate_html_helper.rb +52 -0
  17. data/app/models/postablr/ar_publish.rb +172 -0
  18. data/app/models/postablr/entry.rb +37 -0
  19. data/app/models/postablr/entry/audio.rb +23 -0
  20. data/app/models/postablr/entry/image.rb +17 -0
  21. data/app/models/postablr/entry/link.rb +8 -0
  22. data/app/models/postablr/entry/post.rb +8 -0
  23. data/app/models/postablr/entry/quote.rb +7 -0
  24. data/app/models/postablr/entry/video.rb +29 -0
  25. data/app/uploaders/entry_audio_uploader.rb +55 -0
  26. data/app/uploaders/entry_photo_uploader.rb +42 -0
  27. data/app/views/layouts/postablr/application.html.erb +14 -0
  28. data/app/views/postablr/blog/_entry_display.haml +3 -0
  29. data/app/views/postablr/blog/comments/_comment.haml +10 -0
  30. data/app/views/postablr/blog/comments/_form.haml +6 -0
  31. data/app/views/postablr/blog/comments/create.js.haml +5 -0
  32. data/app/views/postablr/blog/comments/new.html.haml +0 -0
  33. data/app/views/postablr/blog/comments/new.js.haml +2 -0
  34. data/app/views/postablr/blog/entries/show.haml +39 -0
  35. data/app/views/postablr/blog/show.html.haml +46 -0
  36. data/app/views/postablr/blog/show/_aside.haml +19 -0
  37. data/app/views/postablr/blog/show/_audio.haml +13 -0
  38. data/app/views/postablr/blog/show/_image.haml +13 -0
  39. data/app/views/postablr/blog/show/_link.haml +11 -0
  40. data/app/views/postablr/blog/show/_post.haml +14 -0
  41. data/app/views/postablr/blog/show/_quote.haml +12 -0
  42. data/app/views/postablr/blog/show/_video.haml +16 -0
  43. data/app/views/postablr/entries/_entries_menu.haml +14 -0
  44. data/app/views/postablr/entries/_entry.haml +4 -0
  45. data/app/views/postablr/entries/_form.haml +58 -0
  46. data/app/views/postablr/entries/edit.haml +1 -0
  47. data/app/views/postablr/entries/fields/_audio.haml +4 -0
  48. data/app/views/postablr/entries/fields/_image.haml +2 -0
  49. data/app/views/postablr/entries/fields/_link.haml +3 -0
  50. data/app/views/postablr/entries/fields/_post.haml +3 -0
  51. data/app/views/postablr/entries/fields/_quote.haml +3 -0
  52. data/app/views/postablr/entries/fields/_video.haml +2 -0
  53. data/app/views/postablr/entries/index.html.haml +11 -0
  54. data/app/views/postablr/entries/index.js.haml +2 -0
  55. data/app/views/postablr/entries/list/_audio.haml +14 -0
  56. data/app/views/postablr/entries/list/_image.haml +12 -0
  57. data/app/views/postablr/entries/list/_link.haml +11 -0
  58. data/app/views/postablr/entries/list/_post.haml +14 -0
  59. data/app/views/postablr/entries/list/_quote.haml +11 -0
  60. data/app/views/postablr/entries/list/_video.haml +17 -0
  61. data/app/views/postablr/entries/new.html.haml +2 -0
  62. data/app/views/postablr/entries/show.html.haml +5 -0
  63. data/config/routes.rb +20 -0
  64. data/db/migrate/20121222195404_create_postablr_entries.rb +18 -0
  65. data/db/migrate/20121222195417_create_postablr_entry_videos.rb +16 -0
  66. data/db/migrate/20121222200141_create_postablr_entry_quotes.rb +10 -0
  67. data/db/migrate/20121222200237_create_postablr_entry_posts.rb +10 -0
  68. data/db/migrate/20121222200303_create_postablr_entry_links.rb +10 -0
  69. data/db/migrate/20121222200402_create_postablr_entry_images.rb +12 -0
  70. data/db/migrate/20121222200810_create_postablr_entry_audios.rb +12 -0
  71. data/lib/postablr.rb +4 -0
  72. data/lib/postablr/engine.rb +11 -0
  73. data/lib/postablr/version.rb +3 -0
  74. data/lib/tasks/postablr_tasks.rake +4 -0
  75. data/test/factories/postablr_entries.rb +16 -0
  76. data/test/factories/postablr_entry_audios.rb +9 -0
  77. data/test/factories/postablr_entry_images.rb +10 -0
  78. data/test/factories/postablr_entry_links.rb +8 -0
  79. data/test/factories/postablr_entry_posts.rb +9 -0
  80. data/test/factories/postablr_entry_quotes.rb +8 -0
  81. data/test/factories/postablr_entry_videos.rb +14 -0
  82. metadata +358 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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.
@@ -0,0 +1,22 @@
1
+ # Postablr
2
+
3
+ Postablr is a mountable blog engine for rails 3
4
+
5
+ but is a work in progress, don´t use in production!
6
+
7
+ ## Niceties
8
+
9
+ + Devise compatible
10
+ + Tumblr style for post types (image, text, video, quote)
11
+ + Sanitize html
12
+
13
+ + TODO
14
+ + tagging support - depend on acts_as_taggable_on
15
+ + Rich text editor support
16
+ + blogs support if many blogs in site
17
+
18
+ # instalation
19
+
20
+ gem install postablr
21
+
22
+ rake postablr:install:migrations
@@ -0,0 +1,40 @@
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 = 'Postablr'
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 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -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,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -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
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ module Postablr
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,21 @@
1
+ require_dependency "postablr/application_controller"
2
+
3
+ module Postablr
4
+ class BlogController < ApplicationController
5
+
6
+ def show
7
+ @entries = Postablr::Entry.includes(:postable).published.order("postablr_entries.postable_type.created_at desc").page(params[:page]).per(6)
8
+ end
9
+
10
+ def filter
11
+ @entries = Postablr::Entry.includes(:postable).published.where("postablr_entries.postable_type =?", "Entry::#{params[:filter].capitalize}").order("postablr_entries.created_at desc").page(params[:page]).per(6)
12
+ render :show
13
+ end
14
+
15
+ def tags_get
16
+ @q = params[:tag]
17
+ @tags = ActsAsTaggableOn::Tag.where{( name =~ "#{@q}%")}
18
+ render :json=> @tags.collect{ |tag| {"caption"=> tag.name, "value"=>tag.id.to_s } }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ require_dependency "postablr/application_controller"
2
+
3
+ module Postablr
4
+ class EntriesController < ApplicationController
5
+
6
+ before_filter :authenticate_user!
7
+
8
+ inherit_resources
9
+
10
+ respond_to :js
11
+
12
+ def new
13
+ @entry = current_user.entries.new
14
+ @entry.postable = "Postablr::Entry::#{params[:type].capitalize}".constantize.send(:new)
15
+ end
16
+
17
+ def create
18
+ @entry = current_user.entries.new(params[:entry].except("postable_attributes"))
19
+ @entry.tag_list = ActsAsTaggableOn::Tag.find(params[:tag_list_input]).map(&:name) unless params[:tag_list_input].blank?
20
+ @entry.postable = "Postablr::Entry::#{params[:type].capitalize}".constantize.new(params[:entry][:postable_attributes])
21
+ create!{
22
+ if @entry.errors.blank?
23
+ entry_url(@entry)
24
+ end
25
+ }
26
+ end
27
+
28
+ def update
29
+ @entry = current_user.entries.find(params[:post_id])
30
+ @entry.tag_list = ActsAsTaggableOn::Tag.find(params[:tag_list_input]).map(&:name) unless params[:tag_list_input].blank?
31
+ update!{ entry_url(@entry) if @entry.errors.blank? }
32
+ end
33
+
34
+ protected
35
+ def begin_of_association_chain
36
+ current_user
37
+ end
38
+
39
+ def collection
40
+ @entries ||= end_of_association_chain.order("created_at desc") #.page(params[:page]).per(6)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ module Postablr
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ module Postablr
2
+ module BlogHelper
3
+ def sanitize_clean(html, truncate = false, link=nil)
4
+ unless truncate
5
+ Sanitize.clean(html, Sanitize::Config::RESTRICTED)
6
+ else
7
+ truncate_html(clean_html( html ), truncate , link )
8
+ end
9
+ end
10
+
11
+ def sanitize_strict(html, truncate = false, link=nil)
12
+ unless truncate
13
+ Sanitize.clean(html, Sanitize::Config::RESTRICTED)
14
+ else
15
+ truncate_html(Sanitize.clean(html, Sanitize::Config::RESTRICTED), truncate , link )
16
+ end
17
+ end
18
+
19
+ def clean_html(html)
20
+ Sanitize.clean(html, Sanitize::Config::BASIC)
21
+ end
22
+
23
+ def sanitize_relaxed(html)
24
+ Sanitize.clean(html, Sanitize::Config::RELAXED)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module Postablr
2
+ module EntriesHelper
3
+ end
4
+ end
@@ -0,0 +1,52 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require "rubygems"
3
+ require "nokogiri"
4
+
5
+ module Postablr::TruncateHtmlHelper
6
+
7
+ def truncate_html(text, max_length = 10, ellipsis = "...")
8
+ doc = Nokogiri::HTML::DocumentFragment.parse text
9
+ # remove syntax highlighting
10
+ doc.css("div.CodeRay").each do |node|
11
+ node.remove
12
+ end
13
+ content_length = doc.inner_text.length
14
+ if content_length > max_length
15
+ doc = doc.truncate(max_length)
16
+ more = Nokogiri::HTML::DocumentFragment.parse ellipsis
17
+ doc.children.last.add_child(more.children)
18
+ doc.to_html.html_safe
19
+ else
20
+ text.to_s
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ module NokogiriTruncator
27
+ module NodeWithChildren
28
+ def truncate(max_length)
29
+ return self if inner_text.length <= max_length
30
+ truncated_node = self.dup
31
+ truncated_node.children.remove
32
+
33
+ self.children.each do |node|
34
+ remaining_length = max_length - truncated_node.inner_text.length
35
+ break if remaining_length <= 0
36
+ truncated_node.add_child node.truncate(remaining_length)
37
+ end
38
+ truncated_node
39
+ end
40
+ end
41
+
42
+ module TextNode
43
+ def truncate(max_length)
44
+ Nokogiri::XML::Text.new(content[0..(max_length - 1)], parent)
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ Nokogiri::HTML::DocumentFragment.send(:include, NokogiriTruncator::NodeWithChildren)
51
+ Nokogiri::XML::Element.send(:include, NokogiriTruncator::NodeWithChildren)
52
+ Nokogiri::XML::Text.send(:include, NokogiriTruncator::TextNode)
@@ -0,0 +1,172 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # extracted from https://github.com/ismasan/ar_publish_control
3
+ module Postablr
4
+ module ArPublish
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ #extend ClassMethods
10
+ @statuses = [:published, :draft, :upcoming, :expired]
11
+
12
+ after_initialize :fill_default_publish
13
+ end
14
+
15
+ module ClassMethods
16
+ # == Configuration options
17
+ #
18
+ # Right now this plugin has only one configuration option. Models with no publication dates
19
+ # are by default published, not unpublished. If you want to hide your model when it has no
20
+ # explicit publication date set, you can turn off this behaviour with the
21
+ # +publish_by_default+ (defaults to <tt>true</tt>) option like so:
22
+ #
23
+ # class Post < ActiveRecord::Base
24
+ # publish_control :publish_by_default => false
25
+ # end
26
+ #
27
+ # == Database Schema
28
+ #
29
+ # The model that you're publishing needs to have two special date attributes:
30
+ #
31
+ # * publish_at
32
+ # * unpublish_at
33
+ #
34
+ # These attributes have no further requirements or required validations; they
35
+ # just need to be <tt>datetime</tt>-columns.
36
+ #
37
+ # You can use a migration like this to add these columns to your model:
38
+ #
39
+ # class AddPublicationDatesToPosts < ActiveRecord::Migration
40
+ # def self.up
41
+ # add_column :posts, :publish_at, :datetime
42
+ # add_column :posts, :unpublish_at, :datetime
43
+ # end
44
+ #
45
+ # def self.down
46
+ # remove_column :posts, :publish_at
47
+ # remove_column :posts, :unpublish_at
48
+ # end
49
+ # end
50
+ #
51
+ def publish_control(options = { :publish_by_default => true })
52
+ # don't allow multiple calls
53
+ #return if self.included_modules.include?(ArPublishControl::Publishable::InstanceMethods)
54
+ #send :include, ArPublishControl::Publishable::InstanceMethods
55
+
56
+ scope :published, lambda{{:conditions => published_conditions}}
57
+ scope :unpublished, lambda{{:conditions => unpublished_conditions}}
58
+ scope :upcoming, lambda{{:conditions => upcoming_conditions}}
59
+ scope :expired, lambda {{:conditions => expired_conditions}}
60
+ scope :draft, :conditions => {:is_published => false}
61
+
62
+ scope :published_only, lambda {|*args|
63
+ bool = (args.first.nil? ? true : (args.first)) # nil = true by default
64
+ bool ? {:conditions => published_conditions} : {}
65
+ }
66
+
67
+ validate :validate_publish_date_consistency
68
+ before_create :publish_by_default if options[:publish_by_default]
69
+ end
70
+
71
+ # Takes a block whose containing SQL queries are limited to
72
+ # published objects. You can pass a boolean flag indicating
73
+ # whether this scope should be applied or not--for example,
74
+ # you might want to disable it when the user is an administrator.
75
+ # By default the scope is applied.
76
+ #
77
+ # Example usage:
78
+ #
79
+ # Post.published_only(!logged_in?)
80
+ # @post.comments.published_only(!logged_in?)
81
+ #
82
+
83
+ protected
84
+
85
+ # returns a string for use in SQL to filter the query to unpublished results only
86
+ # Meant for internal use only
87
+ def unpublished_conditions
88
+ t = Time.now
89
+ ["(#{table_name}.is_published = ? OR #{table_name}.publish_at > ?) OR (#{table_name}.unpublish_at IS NOT NULL AND #{table_name}.unpublish_at < ?)",false,t,t]
90
+ end
91
+
92
+ # return a string for use in SQL to filter the query to published results only
93
+ # Meant for internal use only
94
+ def published_conditions
95
+ t = Time.now
96
+ ["(#{table_name}.is_published = ? AND #{table_name}.publish_at <= ?) AND (#{table_name}.unpublish_at IS NULL OR #{table_name}.unpublish_at > ?)",true,t,t]
97
+ end
98
+
99
+ def upcoming_conditions
100
+ t = Time.now
101
+ ["(#{table_name}.is_published = ? AND #{table_name}.publish_at > ?)",true,t]
102
+ end
103
+
104
+ def expired_conditions
105
+ t = Time.now
106
+ ["(#{table_name}.unpublish_at IS NOT NULL AND #{table_name}.unpublish_at < ?)",t]
107
+ end
108
+ end
109
+
110
+
111
+ def fill_default_publish
112
+ self.publish_at = Time.now if self.publish_at.nil?
113
+ end
114
+
115
+ # ActiveRecrod callback fired on +before_create+ to make
116
+ # sure a new object always gets a publication date; if
117
+ # none is supplied it defaults to the creation date.
118
+ def publish_by_default
119
+ self.is_published = true if is_published.nil?
120
+ end
121
+
122
+ # Validate that unpublish_at is greater than publish_at
123
+ # publish_at must not be nil
124
+ def validate_publish_date_consistency
125
+ if unpublish_at && publish_at && unpublish_at <= publish_at
126
+ errors.add(:unpublish_at,"should be greater than publication date or empty")
127
+ end
128
+ end
129
+
130
+ # Return whether the current object is published or not
131
+ def published?
132
+ (is_published? && (publish_at <=> Time.now) <= 0) && (unpublish_at.nil? || (unpublish_at <=> Time.now) >= 0)
133
+ end
134
+
135
+ def upcoming?
136
+ (is_published? && publish_at > Time.now)
137
+ end
138
+
139
+ def expired?
140
+ (!unpublish_at.nil? && unpublish_at < Time.now)
141
+ end
142
+
143
+ # Indefinitely publish the current object right now
144
+ def publish
145
+ return if published?
146
+ self.is_published = true
147
+ self.publish_at = Time.now
148
+ self.unpublish_at = nil
149
+ end
150
+
151
+ # Same as publish, but immediatly saves the object.
152
+ # Raises an error when saving fails.
153
+ def publish!
154
+ publish
155
+ save!
156
+ end
157
+
158
+ # Immediatly unpublish the current object
159
+ def unpublish
160
+ return unless published?
161
+ self.is_published = false
162
+ end
163
+
164
+ # Same as unpublish, but immediatly saves the object.
165
+ # Raises an error when saving files.
166
+ def unpublish!
167
+ unpublish
168
+ save!
169
+ end
170
+
171
+ end
172
+ end