crowdblog 0.0.16 → 0.1.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.
- data/.gitignore +2 -0
- data/Gemfile +0 -10
- data/README.md +94 -3
- data/Rakefile +1 -7
- data/app/assets/images/crowdblog/logo.png +0 -0
- data/app/assets/javascripts/crowdblog/models/post.js.coffee +4 -9
- data/app/assets/javascripts/crowdblog/views/attachment_view.js.coffee +12 -0
- data/app/assets/javascripts/crowdblog/views/post_form_view.js.coffee +21 -0
- data/app/assets/javascripts/crowdblog/views/post_view.js.coffee +52 -0
- data/app/assets/javascripts/crowdblog.js +7 -11
- data/app/assets/stylesheets/crowdblog/posts.css.scss +26 -5
- data/app/assets/stylesheets/crowdblog.css +0 -1
- data/app/controllers/crowdblog/application_controller.rb +13 -0
- data/app/controllers/crowdblog/assets_controller.rb +2 -2
- data/app/controllers/crowdblog/authors_controller.rb +2 -2
- data/app/controllers/crowdblog/devise/sessions_controller.rb +3 -0
- data/app/controllers/crowdblog/posts_controller.rb +37 -16
- data/app/models/crowdblog/asset.rb +0 -1
- data/app/models/crowdblog/post.rb +15 -5
- data/app/models/crowdblog/user.rb +9 -1
- data/app/views/crowdblog/application/_navbar.html.slim +11 -0
- data/app/views/crowdblog/application/_notices.html.slim +6 -0
- data/app/views/crowdblog/authors/index.html.slim +2 -2
- data/app/views/crowdblog/devise/_links.erb +25 -0
- data/app/views/crowdblog/devise/sessions/new.html.erb +21 -0
- data/app/views/crowdblog/posts/_form.html.slim +31 -0
- data/app/views/crowdblog/posts/_post.html.slim +13 -0
- data/app/views/crowdblog/posts/edit.html.slim +14 -0
- data/app/views/crowdblog/posts/index.html.slim +12 -10
- data/app/views/crowdblog/posts/new.html.slim +12 -0
- data/app/views/crowdblog/posts/update.json.jbuilder +2 -0
- data/app/views/layouts/crowdblog/application.html.slim +20 -0
- data/config/initializers/date_formats.rb +1 -0
- data/config/initializers/devise.rb +16 -0
- data/config/locales/devise.en.yml +57 -0
- data/config/routes.rb +1 -0
- data/crowdblog.gemspec +4 -12
- data/db/migrate/20120215232711_create_crowdblog_users.rb +23 -0
- data/db/migrate/20120217213920_create_crowdblog_posts.rb +17 -0
- data/db/migrate/20120219071614_create_crowdblog_assets.rb +10 -0
- data/lib/crowdblog/devise/failure_app.rb +9 -0
- data/lib/crowdblog/rspec/crowdblog_shared_examples.rb +108 -0
- data/lib/crowdblog/rspec.rb +1 -0
- data/lib/crowdblog/version.rb +1 -1
- data/lib/crowdblog.rb +10 -0
- data/spec/dummy/app/controllers/application_controller.rb +0 -16
- data/spec/dummy/app/views/home/show.html.slim +1 -1
- data/spec/dummy/config/application.rb +0 -10
- data/spec/dummy/config/initializers/devise.rb +0 -7
- data/spec/dummy/config/routes.rb +1 -8
- data/spec/dummy/db/schema.rb +11 -11
- data/spec/dummy/db/seed.rb +6 -0
- data/spec/integration/crowdblog_spec.rb +5 -0
- data/spec/models/post_spec.rb +3 -3
- data/spec/models/user_spec.rb +25 -1
- data/spec/spec_helper.rb +17 -1
- data/vendor/assets/javascripts/backbone_rails_sync.js +69 -0
- data/vendor/assets/javascripts/uploader/jquery.html5uploader.js +148 -0
- metadata +40 -183
- data/Gemfile.lock +0 -280
- data/app/assets/javascripts/crowdblog/posts_main.js.coffee +0 -42
- data/app/assets/javascripts/crowdblog/templates/posts/attachment.jst.eco.slim +0 -1
- data/app/assets/javascripts/crowdblog/templates/posts/edit.jst.eco.slim +0 -36
- data/app/assets/javascripts/crowdblog/templates/posts/index.jst.eco.slim +0 -14
- data/app/assets/javascripts/crowdblog/templates/posts/post.jst.eco.slim +0 -14
- data/app/assets/javascripts/crowdblog/views/posts/attachment_view.js.coffee +0 -8
- data/app/assets/javascripts/crowdblog/views/posts/edit_post_view.js.coffee +0 -46
- data/app/assets/javascripts/crowdblog/views/posts/index.js.coffee +0 -28
- data/app/assets/javascripts/crowdblog/views/posts/post_view.js.coffee +0 -57
- data/app/assets/javascripts/crowdblog/xhr_fix.js.coffee +0 -4
- data/app/controllers/crowdblog/controller.rb +0 -10
- data/app/views/layouts/crowdblog/crowdblog.html.slim +0 -26
- data/db/migrate/20120215232711_create_users.rb +0 -10
- data/db/migrate/20120216154516_add_devise_to_users.rb +0 -56
- data/db/migrate/20120217213920_create_posts.rb +0 -13
- data/db/migrate/20120219014520_add_author_to_posts.rb +0 -6
- data/db/migrate/20120219040607_add_state_to_post.rb +0 -7
- data/db/migrate/20120219071614_create_assets.rb +0 -10
- data/db/migrate/20120219234253_add_alias_to_users.rb +0 -6
- data/db/migrate/20120229160314_add_review_fields_to_post.rb +0 -6
- data/features/posts/listing.feature +0 -32
- data/features/posts/manage.feature +0 -36
- data/features/posts/publish.feature +0 -17
- data/features/step_definitions/global_steps.rb +0 -23
- data/features/step_definitions/navigation_steps.rb +0 -45
- data/features/step_definitions/posts_steps.rb +0 -138
- data/features/step_definitions/review_steps.rb +0 -27
- data/features/support/env.rb +0 -76
- data/spec/dummy/app/models/user.rb +0 -17
- data/spec/fabricators/posts_fabricator.rb +0 -21
- data/spec/fabricators/users_fabricator.rb +0 -19
- data/vendor/assets/javascripts/swfobject.js +0 -4
- data/vendor/assets/swf/uploadify.swf +0 -0
data/.gitignore
CHANGED
data/Gemfile
CHANGED
|
@@ -7,16 +7,6 @@ gemspec
|
|
|
7
7
|
|
|
8
8
|
# Gems used by the dummy application (needs to be here instead of the gemspec)
|
|
9
9
|
gem "jquery-rails"
|
|
10
|
-
gem 'backbone-rails'
|
|
11
|
-
gem 'carrierwave'
|
|
12
|
-
gem 'devise'
|
|
13
|
-
gem 'gravtastic'
|
|
14
|
-
gem 'less-rails-bootstrap'
|
|
15
|
-
gem 'redcarpet'
|
|
16
|
-
gem 'state_machine'
|
|
17
|
-
gem 'slim_assets'
|
|
18
|
-
gem 'slim-rails'
|
|
19
|
-
gem 'eco'
|
|
20
10
|
|
|
21
11
|
group :assets do
|
|
22
12
|
gem 'coffee-rails'
|
data/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
CrowdBlog
|
|
2
|
-
=======
|
|
1
|
+
# CrowdBlog
|
|
3
2
|
|
|
4
3
|
CI:
|
|
5
4
|
[](http://travis-ci.org/crowdint/crowdblog)
|
|
@@ -7,4 +6,96 @@ CI:
|
|
|
7
6
|
Code Climate:
|
|
8
7
|
[](https://codeclimate.com/github/crowdint/crowdblog)
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
Generic Blog engine, currently in use by [blog.crowdint.com](blog.crowdint.com)
|
|
10
|
+
and [crowdint.com/careers](crowdint.com/careers), among others.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Gemfile
|
|
15
|
+
|
|
16
|
+
gem 'crowdblog'
|
|
17
|
+
|
|
18
|
+
Bundle
|
|
19
|
+
|
|
20
|
+
bundle install
|
|
21
|
+
|
|
22
|
+
Copy migrations
|
|
23
|
+
|
|
24
|
+
rake crowdblog:install:migrations
|
|
25
|
+
|
|
26
|
+
Run them
|
|
27
|
+
|
|
28
|
+
rake db:migrate
|
|
29
|
+
|
|
30
|
+
Mount
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# routes.rb
|
|
34
|
+
#
|
|
35
|
+
|
|
36
|
+
mount Crowdblog::Engine => '/blog_admin'
|
|
37
|
+
|
|
38
|
+
Enjoy.
|
|
39
|
+
|
|
40
|
+
Your Rails App should implement the "client facing" pages. Read posts from the
|
|
41
|
+
Crowdblog::Post model.
|
|
42
|
+
|
|
43
|
+
### Authentication
|
|
44
|
+
|
|
45
|
+
The gem includes a very basic Devise implementation. We use it in combination
|
|
46
|
+
with [this gem](https://github.com/crowdint/crowdint_auth) to authenticate
|
|
47
|
+
via our Google Apps accounts.
|
|
48
|
+
|
|
49
|
+
Take a look [at this code](https://github.com/crowdint/blog.crowdint.com) as an implementation example.
|
|
50
|
+
|
|
51
|
+
## Testing: Use with caution
|
|
52
|
+
|
|
53
|
+
If you are using it as a 'vanilla' installation, that is, without a lot of
|
|
54
|
+
customizations, you can use some specs that are included with the gem to make
|
|
55
|
+
sure your blog behaves properly.
|
|
56
|
+
|
|
57
|
+
Add this on your spec_helper, right after you require `rspec/rails`:
|
|
58
|
+
|
|
59
|
+
require 'crowdblog/rspec'
|
|
60
|
+
require 'database_cleaner'
|
|
61
|
+
|
|
62
|
+
Your are going to need DatabaseCleaner to use truncation strategies for your
|
|
63
|
+
data. Add these lines to spec_helper.rb:
|
|
64
|
+
|
|
65
|
+
Rspec.configure do |config|
|
|
66
|
+
|
|
67
|
+
config.use_transactional_fixtures = false
|
|
68
|
+
|
|
69
|
+
config.before(:suite) do
|
|
70
|
+
DatabaseCleaner.strategy = :truncation
|
|
71
|
+
DatabaseCleaner.clean_with(:truncation)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
config.before(:each) do
|
|
75
|
+
DatabaseCleaner.start
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
config.after(:each) do
|
|
79
|
+
DatabaseCleaner.clean
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
Now, create a crowdblog spec:
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# spec/integration/crowdblog_spec.rb
|
|
87
|
+
#
|
|
88
|
+
require 'spec_helper'
|
|
89
|
+
|
|
90
|
+
describe "Crowdblog" do
|
|
91
|
+
it_behaves_like "a crowdblog"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
And run your specs. It should test Crowdblog properly.
|
|
95
|
+
|
|
96
|
+
[Crowd Interactive](http://www.crowdint.com) is a leading Ruby and Rails consultancy
|
|
97
|
+
firm based in Mexico currently doing business with startups in the United States.
|
|
98
|
+
We specialize in building and growing your existing development team, by adding
|
|
99
|
+
engineers onsite or offsite. We pick our clients carefully, as we only work with
|
|
100
|
+
companies we believe in. Find out more about us on our [website](http://www.crowdint.com).
|
|
101
|
+
|
data/Rakefile
CHANGED
|
@@ -26,10 +26,4 @@ load 'rails/tasks/engine.rake'
|
|
|
26
26
|
Bundler::GemHelper.install_tasks
|
|
27
27
|
|
|
28
28
|
require 'rspec/core/rake_task'
|
|
29
|
-
RSpec::Core::RakeTask.new(:
|
|
30
|
-
|
|
31
|
-
# Alias for Cucumber
|
|
32
|
-
task :cucumber => 'app:cucumber'
|
|
33
|
-
|
|
34
|
-
# RSpec and Cucumber by default
|
|
35
|
-
task :default => [:spec, :cucumber]
|
|
29
|
+
RSpec::Core::RakeTask.new(:default)
|
|
Binary file
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if this.id
|
|
4
|
-
'/admin/posts/' + this.id
|
|
5
|
-
else
|
|
6
|
-
'/admin/posts'
|
|
1
|
+
class Crowdblog.Models.Post extends Backbone.Model
|
|
2
|
+
paramRoot: 'post'
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
url: ->
|
|
5
|
+
'posts/' + @id
|
|
10
6
|
|
|
11
|
-
url: '/admin/posts'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Crowdblog.Views.PostFormView extends Backbone.View
|
|
2
|
+
el: 'form'
|
|
3
|
+
|
|
4
|
+
initialize: ->
|
|
5
|
+
@$el.find('#post_body').change(@updatePreview)
|
|
6
|
+
@updatePreview()
|
|
7
|
+
$('#uploader').html5Uploader
|
|
8
|
+
postUrl: 'assets'
|
|
9
|
+
name: 'attachment'
|
|
10
|
+
onSuccess: @onUploadSuccess
|
|
11
|
+
|
|
12
|
+
events:
|
|
13
|
+
'keyup #post_body' : 'updatePreview'
|
|
14
|
+
|
|
15
|
+
updatePreview: (e) ->
|
|
16
|
+
@$el.find('#post-preview .inner').html(markdown.toHTML($('#post_body').val()))
|
|
17
|
+
|
|
18
|
+
onUploadSuccess: (request, file, object) ->
|
|
19
|
+
attachmentView = new Crowdblog.Views.AttachmentView(object)
|
|
20
|
+
$('#assets').append attachmentView.render().el
|
|
21
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class Crowdblog.Views.PostView extends Backbone.View
|
|
2
|
+
events:
|
|
3
|
+
'click a.publish' : 'publishPost'
|
|
4
|
+
'click a.review' : 'markForReview'
|
|
5
|
+
|
|
6
|
+
initialize: ->
|
|
7
|
+
@model = new Crowdblog.Models.Post
|
|
8
|
+
ready_for_review: (@$el.attr('data-ready-for-review') == 'true')
|
|
9
|
+
|
|
10
|
+
@model.id = @postId()
|
|
11
|
+
@model.bind('change:ready_for_review', @paintReviewButton)
|
|
12
|
+
|
|
13
|
+
publishPost: (e) ->
|
|
14
|
+
e.preventDefault()
|
|
15
|
+
if @postIsPublished()
|
|
16
|
+
@model.save 'transition', 'draft', { success: @paintPostRow }
|
|
17
|
+
else
|
|
18
|
+
@model.save 'transition', 'publish', { success: @paintPostRow }
|
|
19
|
+
|
|
20
|
+
postId: ->
|
|
21
|
+
@$el.attr('data-post-id')
|
|
22
|
+
|
|
23
|
+
paintPostRow: =>
|
|
24
|
+
if @model.get('transition') == 'publish'
|
|
25
|
+
@$el.find('a.publish').removeClass('btn-danger')
|
|
26
|
+
@$el.find('a.publish').addClass('btn-success')
|
|
27
|
+
@$el.attr('data-state', 'published')
|
|
28
|
+
else
|
|
29
|
+
@$el.find('a.publish').removeClass('btn-success')
|
|
30
|
+
@$el.find('a.publish').addClass('btn-danger')
|
|
31
|
+
@$el.attr('data-state', 'drafted')
|
|
32
|
+
|
|
33
|
+
@$el.find('td.published-at').html(@model.get('published_at'))
|
|
34
|
+
|
|
35
|
+
postIsPublished: ->
|
|
36
|
+
@$el.attr('data-state') == 'published'
|
|
37
|
+
|
|
38
|
+
markForReview: (e) ->
|
|
39
|
+
e.preventDefault()
|
|
40
|
+
ready_for_review = @model.get('ready_for_review')
|
|
41
|
+
if ready_for_review
|
|
42
|
+
ready_for_review = false
|
|
43
|
+
else
|
|
44
|
+
ready_for_review = true
|
|
45
|
+
|
|
46
|
+
@model.save 'ready_for_review', ready_for_review
|
|
47
|
+
|
|
48
|
+
paintReviewButton: (post) =>
|
|
49
|
+
if post.get('ready_for_review')
|
|
50
|
+
@$el.find('a.review').addClass('btn-warning')
|
|
51
|
+
else
|
|
52
|
+
@$el.find('a.review').removeClass('btn-warning')
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*= require 'jquery'
|
|
3
2
|
*= require 'jquery_ujs'
|
|
4
|
-
*= require '
|
|
5
|
-
*= require 'backbone'
|
|
6
|
-
*= require 'swfobject'
|
|
7
|
-
*= require 'jquery.uploadify'
|
|
3
|
+
*= require 'backbone_rails_sync'
|
|
8
4
|
*= require 'markdown'
|
|
5
|
+
*= require 'uploader/jquery.html5uploader.js'
|
|
9
6
|
*= require_self
|
|
10
|
-
*= require_tree ./crowdblog
|
|
11
|
-
*= require_tree ./crowdblog/views
|
|
12
|
-
*= require_tree ./crowdblog/templates
|
|
13
|
-
*= require ./crowdblog/posts_main
|
|
14
|
-
*= require ./crowdblog/xhr_fix
|
|
7
|
+
*= require_tree ./crowdblog
|
|
15
8
|
*/
|
|
16
9
|
|
|
17
|
-
window.
|
|
10
|
+
window.Crowdblog = {};
|
|
11
|
+
window.Crowdblog.Models = {};
|
|
12
|
+
window.Crowdblog.Views = {};
|
|
13
|
+
|
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
/* Edit post */
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
top: 110px;
|
|
5
|
-
height: 550px;
|
|
2
|
+
#post-preview {
|
|
3
|
+
height: 420px;
|
|
6
4
|
overflow-y: scroll;
|
|
7
|
-
padding: 0 25px 0 10px;
|
|
8
5
|
background: #EBEBEB;
|
|
6
|
+
|
|
7
|
+
.inner {
|
|
8
|
+
padding: 5px;
|
|
9
|
+
}
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
form .clear {
|
|
12
13
|
clear: both;
|
|
13
14
|
}
|
|
15
|
+
|
|
16
|
+
.new-link {
|
|
17
|
+
padding: 5px 0 5px 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#uploader {
|
|
21
|
+
border: 3px #ebebeb dashed;
|
|
22
|
+
|
|
23
|
+
.inner {
|
|
24
|
+
padding: 20px;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#uploader:hover {
|
|
29
|
+
background-color: #ebebeb;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.form-box {
|
|
33
|
+
margin-top: 15px;
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Crowdblog
|
|
2
|
+
class ApplicationController < ActionController::Base
|
|
3
|
+
before_filter :authenticate_user!
|
|
4
|
+
|
|
5
|
+
def authentication_filter
|
|
6
|
+
authenticate_user!
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def after_sign_out_path_for(resource_or_scope)
|
|
10
|
+
crowdblog.new_user_session_path
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module Crowdblog
|
|
2
|
-
class AssetsController <
|
|
2
|
+
class AssetsController < Crowdblog::ApplicationController
|
|
3
3
|
# TODO: Skipping filters is the worst solution ever to this problem
|
|
4
4
|
# Someone should fix the uploadify.js thing
|
|
5
5
|
skip_before_filter :verify_authenticity_token, :only => :create
|
|
@@ -8,7 +8,7 @@ module Crowdblog
|
|
|
8
8
|
def create
|
|
9
9
|
@post = Post.find(params[:post_id])
|
|
10
10
|
asset = @post.assets.build
|
|
11
|
-
asset.attachment = params['
|
|
11
|
+
asset.attachment = params['attachment']
|
|
12
12
|
asset.save!
|
|
13
13
|
|
|
14
14
|
render json: asset
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module Crowdblog
|
|
2
|
-
class AuthorsController <
|
|
2
|
+
class AuthorsController < Crowdblog::ApplicationController
|
|
3
3
|
|
|
4
4
|
def index
|
|
5
|
-
@authors = User.includes(:
|
|
5
|
+
@authors = User.includes(:published_posts).sort {|a,b| b.published_posts.size <=> a.published_posts.size}
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
end
|
|
@@ -1,28 +1,36 @@
|
|
|
1
|
-
module
|
|
2
|
-
class PostsController <
|
|
1
|
+
module Crowdblog
|
|
2
|
+
class PostsController < Crowdblog::ApplicationController
|
|
3
|
+
before_filter :authenticate_user!
|
|
4
|
+
|
|
3
5
|
respond_to :html, :json
|
|
4
6
|
cache_sweeper :post_sweeper
|
|
5
7
|
|
|
8
|
+
before_filter :load_post, :only => [ :edit, :update, :destroy ]
|
|
9
|
+
|
|
10
|
+
def new
|
|
11
|
+
@post = Post.new
|
|
12
|
+
@post.author = current_user
|
|
13
|
+
@post.save!
|
|
14
|
+
redirect_to edit_post_path(@post)
|
|
15
|
+
end
|
|
16
|
+
|
|
6
17
|
def index
|
|
7
|
-
@posts = Post.scoped_for(current_user).
|
|
8
|
-
|
|
9
|
-
format.json { render json: @posts }
|
|
10
|
-
format.html
|
|
11
|
-
end
|
|
18
|
+
@posts = Post.scoped_for(current_user).for_admin_index
|
|
19
|
+
respond_with @posts
|
|
12
20
|
end
|
|
13
21
|
|
|
14
22
|
def create
|
|
15
|
-
@post = Post.new(
|
|
23
|
+
@post = Post.new(post_params)
|
|
16
24
|
@post.author = current_user
|
|
17
25
|
@post.regenerate_permalink
|
|
18
|
-
@post.save
|
|
19
|
-
|
|
26
|
+
if @post.save
|
|
27
|
+
respond_with @post, :location => crowdblog.posts_path
|
|
28
|
+
end
|
|
20
29
|
end
|
|
21
30
|
|
|
22
31
|
def destroy
|
|
23
|
-
@post = Post.scoped_for(current_user).find(params[:id])
|
|
24
32
|
@post.destroy
|
|
25
|
-
respond_with @post
|
|
33
|
+
respond_with @post, :location => crowdblog.posts_path
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
def show
|
|
@@ -32,17 +40,30 @@ module Crowdblog
|
|
|
32
40
|
end
|
|
33
41
|
end
|
|
34
42
|
|
|
43
|
+
def edit
|
|
44
|
+
end
|
|
45
|
+
|
|
35
46
|
def update
|
|
36
|
-
@post
|
|
37
|
-
@post.update_attributes(params[:post], updated_by: current_user)
|
|
47
|
+
@post.update_attributes(post_params, updated_by: current_user)
|
|
38
48
|
if @post.allowed_to_update_permalink?
|
|
39
49
|
@post.regenerate_permalink
|
|
40
50
|
@post.save!
|
|
41
51
|
end
|
|
42
52
|
|
|
43
|
-
@post.publish_if_allowed(
|
|
53
|
+
@post.publish_if_allowed(post_params[:transition], current_user) if post_params[:transition]
|
|
54
|
+
|
|
55
|
+
respond_with @post do |format|
|
|
56
|
+
format.html { redirect_to crowdblog.posts_path }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
def load_post
|
|
62
|
+
@post = Post.scoped_for(current_user).find(params[:id])
|
|
63
|
+
end
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
def post_params
|
|
66
|
+
params.require(:post).permit(:title, :body, :updated_by, :ready_for_review, :transition)
|
|
46
67
|
end
|
|
47
68
|
end
|
|
48
69
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module Crowdblog
|
|
2
2
|
class Post < ActiveRecord::Base
|
|
3
|
-
self.table_name = :posts
|
|
4
3
|
versioned
|
|
5
4
|
|
|
6
5
|
belongs_to :author, class_name: 'User'
|
|
@@ -13,9 +12,8 @@ module Crowdblog
|
|
|
13
12
|
|
|
14
13
|
delegate :year, to: :published_at
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
attr_accessible :title, :body, :updated_by, :ready_for_review
|
|
15
|
+
attr_accessor :transition
|
|
16
|
+
attr_accessible :title, :body, :updated_by, :ready_for_review, :transition
|
|
19
17
|
|
|
20
18
|
LEGACY_TITLE_REGEXP = /(\d+-\d+-\d+)-(.*)/
|
|
21
19
|
|
|
@@ -28,6 +26,10 @@ module Crowdblog
|
|
|
28
26
|
post.published_at ||= Time.now
|
|
29
27
|
end
|
|
30
28
|
|
|
29
|
+
before_transition on: :draft do |post, transition|
|
|
30
|
+
post.published_at = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
31
33
|
event :draft do
|
|
32
34
|
transition published: :drafted
|
|
33
35
|
end
|
|
@@ -66,7 +68,15 @@ module Crowdblog
|
|
|
66
68
|
end
|
|
67
69
|
|
|
68
70
|
def scoped_for(user)
|
|
69
|
-
user.is_publisher? ?
|
|
71
|
+
user.is_publisher? ? scoped : user.authored_posts
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def for_admin_index
|
|
75
|
+
ordered_by_state.order_by_publish_date
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def ordered_by_state
|
|
79
|
+
order(:state)
|
|
70
80
|
end
|
|
71
81
|
end
|
|
72
82
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
module Crowdblog
|
|
2
2
|
class User < ActiveRecord::Base
|
|
3
|
-
self.table_name = :users
|
|
4
3
|
include Gravtastic
|
|
5
4
|
|
|
6
5
|
has_many :authored_posts, inverse_of: :author, foreign_key: 'author_id', class_name: 'Post'
|
|
6
|
+
has_many :published_posts, inverse_of: :author, foreign_key: 'author_id', class_name: 'Post', conditions: ['state = ?', 'published'], order: 'published_at DESC'
|
|
7
7
|
has_one :last_post, class_name: 'Post', foreign_key: :author_id, conditions: ['state = ?', 'published'], order: 'published_at DESC, created_at DESC, id DESC'
|
|
8
8
|
|
|
9
9
|
gravtastic :gravatar_email
|
|
10
|
+
devise :database_authenticatable, :token_authenticatable, :trackable
|
|
10
11
|
|
|
12
|
+
validate :email, uniqueness: true
|
|
13
|
+
|
|
14
|
+
attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :is_publisher
|
|
11
15
|
|
|
12
16
|
# INSTANCE METHODS
|
|
13
17
|
def gravatar_email
|
|
@@ -18,6 +22,10 @@ module Crowdblog
|
|
|
18
22
|
last_post.try(:published_at)
|
|
19
23
|
end
|
|
20
24
|
|
|
25
|
+
def last_published_at
|
|
26
|
+
published_posts.first ? published_posts.first.published_at : nil
|
|
27
|
+
end
|
|
28
|
+
|
|
21
29
|
def publisher!
|
|
22
30
|
update_attribute(:is_publisher, true)
|
|
23
31
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.navbar
|
|
2
|
+
.navbar-inner
|
|
3
|
+
= link_to image_tag('crowdblog/logo.png', :width => 227, :height => 74), root_path, :class => 'brand'
|
|
4
|
+
- if current_user
|
|
5
|
+
ul.nav
|
|
6
|
+
li.brand= current_user.email
|
|
7
|
+
li= link_to 'Posts', posts_path
|
|
8
|
+
li= link_to 'Authors', authors_path
|
|
9
|
+
li= link_to 'Sign out', destroy_user_session_path
|
|
10
|
+
|
|
11
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<%- if controller_name != 'sessions' %>
|
|
2
|
+
<%= link_to "Sign in", new_session_path(resource_name) %><br />
|
|
3
|
+
<% end -%>
|
|
4
|
+
|
|
5
|
+
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
|
6
|
+
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
|
7
|
+
<% end -%>
|
|
8
|
+
|
|
9
|
+
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
|
|
10
|
+
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
|
11
|
+
<% end -%>
|
|
12
|
+
|
|
13
|
+
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
|
14
|
+
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
|
15
|
+
<% end -%>
|
|
16
|
+
|
|
17
|
+
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
|
18
|
+
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
|
19
|
+
<% end -%>
|
|
20
|
+
|
|
21
|
+
<%- if devise_mapping.omniauthable? %>
|
|
22
|
+
<%- resource_class.omniauth_providers.each do |provider| %>
|
|
23
|
+
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
|
|
24
|
+
<% end -%>
|
|
25
|
+
<% end -%>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<h2>Sign in</h2>
|
|
2
|
+
|
|
3
|
+
<div class="row">
|
|
4
|
+
<div class="span4">
|
|
5
|
+
<%= form_for(resource, :as => resource_name, :url => crowdblog.user_session_path) do |f| %>
|
|
6
|
+
<%= f.label :email %>
|
|
7
|
+
<%= f.email_field :email, :class => "span4" %>
|
|
8
|
+
|
|
9
|
+
<%= f.label :password %>
|
|
10
|
+
<%= f.password_field :password, :class => "span4" %>
|
|
11
|
+
|
|
12
|
+
<% if devise_mapping.rememberable? -%>
|
|
13
|
+
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
|
|
14
|
+
<% end -%>
|
|
15
|
+
|
|
16
|
+
<div class="form-actions"><%= f.submit "Sign in", :class => "btn btn-primary" %></div>
|
|
17
|
+
<% end %>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<%= render "crowdblog/devise/links" %>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
.row
|
|
2
|
+
.span12
|
|
3
|
+
.control-group.title
|
|
4
|
+
= f.label :title, :class => 'control-label'
|
|
5
|
+
.controls
|
|
6
|
+
= f.text_field :title, :class => "input-xlarge span5"
|
|
7
|
+
span.help-inline.title
|
|
8
|
+
|
|
9
|
+
.row
|
|
10
|
+
.control-group.body
|
|
11
|
+
.span12
|
|
12
|
+
= label_tag 'post_body', 'Body', class: 'control-label'
|
|
13
|
+
.controls.span5
|
|
14
|
+
= f.text_area :body, :class => "span5", :rows => 20
|
|
15
|
+
span.help-inline= link_to 'Markdown syntax', 'http://daringfireball.net/projects/markdown/syntax', target: '_BLANK'
|
|
16
|
+
|
|
17
|
+
#post-preview.span7
|
|
18
|
+
.inner
|
|
19
|
+
|
|
20
|
+
.row.form-box
|
|
21
|
+
.span5
|
|
22
|
+
#uploader
|
|
23
|
+
.inner Drop images...
|
|
24
|
+
|
|
25
|
+
.span7#assets
|
|
26
|
+
- f.object.assets.each do |asset|
|
|
27
|
+
.asset= ""
|
|
28
|
+
|
|
29
|
+
coffee:
|
|
30
|
+
$ ->
|
|
31
|
+
new Crowdblog.Views.PostFormView
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
= content_tag_for :tr, post, :"data-post-id" => post.id, :"data-state" => post.state, :"data-ready-for-review" => post.ready_for_review do
|
|
2
|
+
td= post.title
|
|
3
|
+
td= post.author_email
|
|
4
|
+
td.span2.published-at = post.published_at.try(:to_s, :crowdblog_short)
|
|
5
|
+
td.span1
|
|
6
|
+
- if current_user.is_publisher?
|
|
7
|
+
= link_to 'Publish', '#', :class => "btn btn-small publish #{(post.published? ? 'btn-success' : 'btn-danger')}"
|
|
8
|
+
td.span1
|
|
9
|
+
= link_to 'Review', '#', :class => "btn btn-small review #{(post.ready_for_review ? 'btn-warning' : '')}"
|
|
10
|
+
td.span1
|
|
11
|
+
= link_to 'Delete', crowdblog.post_path(post), :method => :delete, :confirm => 'Are you sure?', :class => "btn btn-small"
|
|
12
|
+
td.span1
|
|
13
|
+
= link_to 'Edit', crowdblog.edit_post_path(post), :class => "btn btn-small"
|