comfy_blog 0.0.0

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 (78) hide show
  1. data/Gemfile +11 -0
  2. data/LICENSE +20 -0
  3. data/README.md +23 -0
  4. data/Rakefile +21 -0
  5. data/VERSION +1 -0
  6. data/app/assets/images/rails.png +0 -0
  7. data/app/assets/javascripts/application.js +8 -0
  8. data/app/assets/stylesheets/comfy_blog/admin.css +57 -0
  9. data/app/assets/stylesheets/comfy_blog/application.css +73 -0
  10. data/app/assets/stylesheets/comfy_blog/reset.css +1 -0
  11. data/app/controllers/application_controller.rb +5 -0
  12. data/app/controllers/blog/admin/base_controller.rb +3 -0
  13. data/app/controllers/blog/admin/comments_controller.rb +34 -0
  14. data/app/controllers/blog/admin/posts_controller.rb +57 -0
  15. data/app/controllers/blog/posts_controller.rb +33 -0
  16. data/app/helpers/blog/application_helper.rb +16 -0
  17. data/app/models/.gitkeep +0 -0
  18. data/app/models/blog/comment.rb +21 -0
  19. data/app/models/blog/post.rb +81 -0
  20. data/app/models/blog/tag.rb +25 -0
  21. data/app/models/blog/tagging.rb +22 -0
  22. data/app/views/blog/admin/_html_head.html.erb +1 -0
  23. data/app/views/blog/admin/_navigation.html.erb +1 -0
  24. data/app/views/blog/admin/comments/_comment.html.erb +22 -0
  25. data/app/views/blog/admin/comments/destroy.js.erb +3 -0
  26. data/app/views/blog/admin/comments/index.html.erb +10 -0
  27. data/app/views/blog/admin/comments/publish.js.erb +1 -0
  28. data/app/views/blog/admin/posts/_form.html.erb +24 -0
  29. data/app/views/blog/admin/posts/_post.html.erb +21 -0
  30. data/app/views/blog/admin/posts/edit.html.erb +5 -0
  31. data/app/views/blog/admin/posts/index.html.erb +9 -0
  32. data/app/views/blog/admin/posts/new.html.erb +5 -0
  33. data/app/views/blog/posts/_post.html.erb +18 -0
  34. data/app/views/blog/posts/index.html.erb +5 -0
  35. data/app/views/blog/posts/show.html.erb +1 -0
  36. data/app/views/layouts/application.html.erb +17 -0
  37. data/comfy_blog.gemspec +125 -0
  38. data/config.ru +4 -0
  39. data/config/application.rb +48 -0
  40. data/config/boot.rb +6 -0
  41. data/config/database.yml +25 -0
  42. data/config/environment.rb +5 -0
  43. data/config/environments/development.rb +33 -0
  44. data/config/environments/production.rb +51 -0
  45. data/config/environments/test.rb +42 -0
  46. data/config/initializers/comfy_blog.rb +18 -0
  47. data/config/initializers/secret_token.rb +3 -0
  48. data/config/initializers/wrap_parameters.rb +14 -0
  49. data/config/locales/en.yml +5 -0
  50. data/config/routes.rb +29 -0
  51. data/db/migrate/01_create_comfy_blog.rb +55 -0
  52. data/db/schema.rb +63 -0
  53. data/db/seeds.rb +7 -0
  54. data/lib/comfy_blog.rb +26 -0
  55. data/lib/comfy_blog/configuration.rb +33 -0
  56. data/lib/comfy_blog/core_ext/string.rb +8 -0
  57. data/lib/comfy_blog/engine.rb +20 -0
  58. data/lib/comfy_blog/form_builder.rb +50 -0
  59. data/lib/generators/README +10 -0
  60. data/lib/generators/blog_generator.rb +31 -0
  61. data/script/rails +6 -0
  62. data/test/fixtures/.gitkeep +0 -0
  63. data/test/fixtures/blog/comments.yml +6 -0
  64. data/test/fixtures/blog/posts.yml +8 -0
  65. data/test/fixtures/blog/taggings.yml +7 -0
  66. data/test/fixtures/blog/tags.yml +9 -0
  67. data/test/functional/.gitkeep +0 -0
  68. data/test/functional/blog/admin/comments_controller_test.rb +38 -0
  69. data/test/functional/blog/admin/posts_controller_test.rb +100 -0
  70. data/test/functional/blog/posts_controller_test.rb +93 -0
  71. data/test/test_helper.rb +40 -0
  72. data/test/unit/.gitkeep +0 -0
  73. data/test/unit/comment_test.rb +34 -0
  74. data/test/unit/configuration_test.rb +19 -0
  75. data/test/unit/post_test.rb +121 -0
  76. data/test/unit/tag_test.rb +44 -0
  77. data/test/unit/tagging_test.rb +30 -0
  78. metadata +172 -0
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '>=3.1.0'
4
+ gem 'will_paginate', '~>3.0.2'
5
+ gem 'rails_autolink', '~>1.0.4'
6
+ gem 'jquery-rails', '>=1.0.0'
7
+
8
+ group :test do
9
+ gem 'sqlite3'
10
+ gem 'jeweler'
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Oleg Khabarov, The Working Group
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,23 @@
1
+ # ComfyBlog
2
+
3
+ ComfyBlog is an simple blog management engine for Rails 3.1 apps. As a bonus it integrates seamlessly with [ComfortableMexicanSofa](https://github.com/comfy/comfortable-mexican-sofa) CMS Engine
4
+
5
+ ## Installation
6
+
7
+ Add gem definition to your Gemfile:
8
+
9
+ gem 'comfy_blog'
10
+
11
+ Then from the Rails project's root run:
12
+
13
+ bundle install
14
+ rails g blog
15
+ rake db:migrate
16
+
17
+ ## Usage
18
+
19
+ TODO
20
+
21
+ Sofa Blog is released under the [MIT license](https://github.com/comfy/comfy-blog/raw/master/LICENSE)
22
+
23
+ Copyright 2011 Oleg Khabarov, [The Working Group Inc](http://www.twg.ca)
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../config/application', __FILE__)
2
+ require 'rubygems'
3
+ require 'rake'
4
+
5
+ ComfyBlog::Application.load_tasks
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = 'comfy_blog'
11
+ gem.homepage = 'http://github.com/comfy/comfy-blog'
12
+ gem.license = 'MIT'
13
+ gem.summary = 'ComfyBlog is a blog engine for Rails 3.1 apps (and ComfortableMexicanSofa)'
14
+ gem.description = ''
15
+ gem.email = 'oleg@twg.ca'
16
+ gem.authors = ['Oleg Khabarov', 'The Working Group Inc.']
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,8 @@
1
+ // This is a manifest file that'll be compiled into including all the files listed below.
2
+ // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
+ // be included in the compiled file accessible from http://example.com/assets/application.js
4
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
+ // the compiled file.
6
+ //
7
+ //= require jquery
8
+ //= require jquery_ujs
@@ -0,0 +1,57 @@
1
+ /* === List items === */
2
+ ul.list.posts li .item .label,
3
+ ul.list.comments li .item .label {
4
+ margin-left: 0px ! important;
5
+ }
6
+ ul.list.comments li .item .label .sublabel em {
7
+ margin-left: 5px;
8
+ }
9
+ ul.list.comments li .item .content {
10
+ font-size: 11px;
11
+ font-weight: normal;
12
+ margin: 5px 0px 0 35px;
13
+ }
14
+
15
+ /* === Tags === */
16
+ span.tag {
17
+ font-size: 10px;
18
+ padding: 1px 5px;
19
+ background-color: #d5d5d5;
20
+ border-radius: 2px;
21
+ -moz-border-radius: 2px;
22
+ }
23
+
24
+
25
+ /* === Autocomplete === */
26
+ .ac_results {
27
+ padding: 0px;
28
+ border: 1px solid #999;
29
+ background-color: white;
30
+ overflow: hidden;
31
+ z-index: 99999;
32
+ color: #666;
33
+ }
34
+ .ac_results ul {
35
+ width: 100%;
36
+ list-style-position: outside;
37
+ list-style: none;
38
+ padding: 0;
39
+ margin: 0;
40
+ }
41
+ .ac_results ul li {
42
+ margin: 0px;
43
+ padding: 2px 5px;
44
+ cursor: default;
45
+ display: block;
46
+ font-size: 12px;
47
+ line-height: 16px;
48
+ overflow: hidden;
49
+ }
50
+
51
+ .ac_odd {
52
+ background-color: #eee;
53
+ }
54
+ .ac_over {
55
+ background-color: #C4EAF6;
56
+ color: #000;
57
+ }
@@ -0,0 +1,73 @@
1
+ /*
2
+ = require ./reset
3
+ = require_self
4
+ */
5
+
6
+ body {
7
+ padding: 25px;
8
+ font: 13px/18px Arial, sans-serif;
9
+ }
10
+ h1 {
11
+ font: bold 26px/34px Arial, sans-serif;
12
+ margin-bottom: 15px;
13
+ }
14
+ h2 {
15
+ font: bold 18px/20px Arial, sans-serif;
16
+ margin-bottom: 10px;
17
+ }
18
+ a {
19
+ color: #3875D7;
20
+ text-decoration: none;
21
+ }
22
+ a:hover {
23
+ text-decoration: underline;
24
+ }
25
+ table.formatted td,
26
+ table.formatted th {
27
+ padding: 2px 5px;
28
+ border-bottom: 1px dotted #ccc;
29
+ }
30
+ table.formatted th {
31
+ background-color: #666;
32
+ color: #fff;
33
+ }
34
+ table.formatted td img {
35
+ float: left;
36
+ padding: 2px;
37
+ margin-right: 2px;
38
+ }
39
+ table.formatted td .sublabel {
40
+ font-size: 11px;
41
+ line-height: 11px;
42
+ color: #888;
43
+ }
44
+
45
+ .form_element {
46
+ overflow: hidden;
47
+ margin-bottom: 5px;
48
+ }
49
+ .form_element .label {
50
+ width: 125px;
51
+ float: left;
52
+ text-align: right;
53
+ }
54
+ .form_element .value,
55
+ .form_element .errors {
56
+ margin-left: 135px;
57
+ }
58
+ .form_element .value input[type='text'],
59
+ .form_element .value textarea {
60
+ width: 400px;
61
+ }
62
+
63
+ .jcrop-holder {
64
+ margin-bottom: 15px;
65
+ }
66
+
67
+ .flash{
68
+ border: 2px solid #ccc;
69
+ padding: 10px;
70
+ margin-bottom: 15px;
71
+ text-align: center;
72
+ }
73
+
@@ -0,0 +1 @@
1
+ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+
4
+ layout 'application'
5
+ end
@@ -0,0 +1,3 @@
1
+ class Blog::Admin::BaseController < ComfyBlog.config.admin_controller.to_s.constantize
2
+ # ...
3
+ end
@@ -0,0 +1,34 @@
1
+ class Blog::Admin::CommentsController < Blog::Admin::BaseController
2
+
3
+ before_filter :load_post, :only => [:index]
4
+ before_filter :load_comment, :only => [:destroy, :publish]
5
+
6
+ def index
7
+ @comments = @post ? @post.comments : Blog::Comment.all
8
+ end
9
+
10
+ def destroy
11
+ @comment.destroy
12
+ end
13
+
14
+ def publish
15
+ @comment.update_attribute(:is_published, true)
16
+ end
17
+
18
+ protected
19
+
20
+ def load_post
21
+ return unless params[:post_id]
22
+ @post = Blog::Post.find(params[:post_id])
23
+ rescue ActiveRecord::RecordNotFound
24
+ flash[:error] = 'Blog Post not found'
25
+ redirect_to :action => :index
26
+ end
27
+
28
+ def load_comment
29
+ @comment = Blog::Comment.find(params[:id])
30
+ rescue ActiveRecord::RecordNotFound
31
+ # ... do nothing
32
+ end
33
+
34
+ end
@@ -0,0 +1,57 @@
1
+ class Blog::Admin::PostsController < Blog::Admin::BaseController
2
+
3
+ before_filter :build_post, :only => [:new, :create]
4
+ before_filter :load_post, :only => [:edit, :update, :destroy]
5
+
6
+ def index
7
+ @posts = Blog::Post.paginate :page => params[:page]
8
+ end
9
+
10
+ def new
11
+ render
12
+ end
13
+
14
+ def create
15
+ @post.save!
16
+ flash.now[:notice] = 'Blog Post created'
17
+ render :action => :new
18
+
19
+ rescue ActiveRecord::RecordInvalid
20
+ flash.now[:error] = 'Failed to create Blog Post'
21
+ render :action => :new
22
+ end
23
+
24
+ def edit
25
+ render
26
+ end
27
+
28
+ def update
29
+ @post.update_attributes!(params[:post])
30
+ flash.now[:notice] = 'Blog Post updated'
31
+ render :action => :edit
32
+
33
+ rescue ActiveRecord::RecordInvalid
34
+ flash.now[:error] = 'Failed to update Blog Post'
35
+ render :action => :edit
36
+ end
37
+
38
+ def destroy
39
+ @post.destroy
40
+ flash[:notice] = 'Blog Post removed'
41
+ redirect_to :action => :index
42
+ end
43
+
44
+ protected
45
+
46
+ def load_post
47
+ @post = Blog::Post.find(params[:id])
48
+ rescue ActiveRecord::RecordNotFound
49
+ flash[:error] = 'Blog Post not found'
50
+ redirect_to :action => :index
51
+ end
52
+
53
+ def build_post
54
+ @post = Blog::Post.new(params[:post])
55
+ end
56
+
57
+ end
@@ -0,0 +1,33 @@
1
+ class Blog::PostsController < ApplicationController
2
+
3
+ layout ComfyBlog.config.public_layout
4
+
5
+ def index
6
+ scope = if params[:tag]
7
+ Blog::Post.published.tagged_with(params[:tag])
8
+ elsif params[:category]
9
+ Blog::Post.published.categorized_as(params[:category])
10
+ elsif params[:year]
11
+ scope = Blog::Post.published.for_year(params[:year])
12
+ params[:month] ? scope.for_month(params[:month]) : scope
13
+ else
14
+ Blog::Post.published
15
+ end
16
+
17
+ @posts = scope.paginate :per_page => ComfyBlog.config.posts_per_page, :page => params[:page]
18
+ end
19
+
20
+ def show
21
+ @post = if params[:slug] && params[:year] && params[:month]
22
+ Blog::Post.published.find_by_year_and_year_and_slug!(params[:year], params[:month], params[:slug])
23
+ else
24
+ Blog::Post.published.find(params[:id])
25
+ end
26
+ rescue ActiveRecord::RecordNotFound
27
+ if defined? ComfortableMexicanSofa
28
+ render :cms_page => '/404', :status => 404
29
+ else
30
+ render :text => 'Post not found', :status => 404
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ module Blog::ApplicationHelper
2
+
3
+ def comfy_blog_form_for(record_or_name_or_array, *args, &proc)
4
+ options = args.extract_options!
5
+ form_for(
6
+ record_or_name_or_array,
7
+ *(args << options.merge(:builder => ComfyBlog.config.form_builder.to_s.constantize)),
8
+ &proc
9
+ )
10
+ end
11
+
12
+ def blog_post_path(post)
13
+
14
+ end
15
+
16
+ end
File without changes
@@ -0,0 +1,21 @@
1
+ class Blog::Comment < ActiveRecord::Base
2
+
3
+ set_table_name :blog_comments
4
+
5
+ attr_accessible :author,
6
+ :email,
7
+ :content
8
+
9
+ # -- Relationships --------------------------------------------------------
10
+ belongs_to :post
11
+
12
+ # -- Validations ----------------------------------------------------------
13
+ validates :post_id, :content, :author, :email,
14
+ :presence => true
15
+ validates :email,
16
+ :format => { :with => /^([\w.%-+]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i }
17
+
18
+ # -- Scopes ---------------------------------------------------------------
19
+ scope :published, where(:is_published => true)
20
+
21
+ end
@@ -0,0 +1,81 @@
1
+ class Blog::Post < ActiveRecord::Base
2
+
3
+ set_table_name :blog_posts
4
+
5
+ # -- Attributes -----------------------------------------------------------
6
+ attr_accessor :tag_names,
7
+ :category_ids
8
+
9
+ # -- Relationships --------------------------------------------------------
10
+ has_many :comments, :dependent => :destroy
11
+ has_many :taggings, :dependent => :destroy
12
+ has_many :tags, :through => :taggings
13
+
14
+ # -- Validations ----------------------------------------------------------
15
+ validates :title, :slug, :year, :month, :content,
16
+ :presence => true
17
+ validates :slug,
18
+ :uniqueness => { :scope => [:year, :month] }
19
+
20
+ # -- Scopes ---------------------------------------------------------------
21
+ default_scope order('created_at DESC')
22
+
23
+ scope :published, where(:is_published => true)
24
+ scope :for_year, lambda { |year|
25
+ where(:year => year)
26
+ }
27
+ scope :for_month, lambda { |month|
28
+ where(:month => month)
29
+ }
30
+ scope :tagged_with, lambda { |tag|
31
+ joins(:tags).where('blog_tags.name' => tag, 'blog_tags.is_category' => false)
32
+ }
33
+ scope :categorized_as, lambda { |tag|
34
+ joins(:tags).where('blog_tags.name' => tag, 'blog_tags.is_category' => true)
35
+ }
36
+
37
+ # -- Callbacks ------------------------------------------------------------
38
+ before_validation :set_slug,
39
+ :set_date
40
+ after_save :sync_tags,
41
+ :sync_categories
42
+
43
+ # -- Instance Methods -----------------------------------------------------
44
+ def tag_names(reload = false)
45
+ @tag_names = nil if reload
46
+ @tag_names ||= self.tags.tags.collect(&:name).join(', ')
47
+ end
48
+
49
+ protected
50
+
51
+ def set_slug
52
+ self.slug ||= self.title.to_s.slugify
53
+ end
54
+
55
+ def set_date
56
+ self.year ||= Time.zone.now.year
57
+ self.month ||= Time.zone.now.month
58
+ end
59
+
60
+ def sync_tags
61
+ return unless tag_names
62
+ self.taggings.for_tags.destroy_all
63
+ self.tag_names.split(',').map{ |t| t.strip }.uniq.each do |tag_name|
64
+ self.tags << Blog::Tag.find_or_create_by_name(tag_name)
65
+ end
66
+ end
67
+
68
+ def sync_categories
69
+ (self.category_ids || {}).each do |category_id, flag|
70
+ case flag.to_i
71
+ when 1
72
+ if category = Blog::Tag.categories.find_by_id(category_id)
73
+ category.taggings.create(:post => self)
74
+ end
75
+ when 0
76
+ self.taggings.for_categories.where(:tag_id => category_id).destroy_all
77
+ end
78
+ end
79
+ end
80
+
81
+ end