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.
Files changed (93) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +0 -10
  3. data/README.md +94 -3
  4. data/Rakefile +1 -7
  5. data/app/assets/images/crowdblog/logo.png +0 -0
  6. data/app/assets/javascripts/crowdblog/models/post.js.coffee +4 -9
  7. data/app/assets/javascripts/crowdblog/views/attachment_view.js.coffee +12 -0
  8. data/app/assets/javascripts/crowdblog/views/post_form_view.js.coffee +21 -0
  9. data/app/assets/javascripts/crowdblog/views/post_view.js.coffee +52 -0
  10. data/app/assets/javascripts/crowdblog.js +7 -11
  11. data/app/assets/stylesheets/crowdblog/posts.css.scss +26 -5
  12. data/app/assets/stylesheets/crowdblog.css +0 -1
  13. data/app/controllers/crowdblog/application_controller.rb +13 -0
  14. data/app/controllers/crowdblog/assets_controller.rb +2 -2
  15. data/app/controllers/crowdblog/authors_controller.rb +2 -2
  16. data/app/controllers/crowdblog/devise/sessions_controller.rb +3 -0
  17. data/app/controllers/crowdblog/posts_controller.rb +37 -16
  18. data/app/models/crowdblog/asset.rb +0 -1
  19. data/app/models/crowdblog/post.rb +15 -5
  20. data/app/models/crowdblog/user.rb +9 -1
  21. data/app/views/crowdblog/application/_navbar.html.slim +11 -0
  22. data/app/views/crowdblog/application/_notices.html.slim +6 -0
  23. data/app/views/crowdblog/authors/index.html.slim +2 -2
  24. data/app/views/crowdblog/devise/_links.erb +25 -0
  25. data/app/views/crowdblog/devise/sessions/new.html.erb +21 -0
  26. data/app/views/crowdblog/posts/_form.html.slim +31 -0
  27. data/app/views/crowdblog/posts/_post.html.slim +13 -0
  28. data/app/views/crowdblog/posts/edit.html.slim +14 -0
  29. data/app/views/crowdblog/posts/index.html.slim +12 -10
  30. data/app/views/crowdblog/posts/new.html.slim +12 -0
  31. data/app/views/crowdblog/posts/update.json.jbuilder +2 -0
  32. data/app/views/layouts/crowdblog/application.html.slim +20 -0
  33. data/config/initializers/date_formats.rb +1 -0
  34. data/config/initializers/devise.rb +16 -0
  35. data/config/locales/devise.en.yml +57 -0
  36. data/config/routes.rb +1 -0
  37. data/crowdblog.gemspec +4 -12
  38. data/db/migrate/20120215232711_create_crowdblog_users.rb +23 -0
  39. data/db/migrate/20120217213920_create_crowdblog_posts.rb +17 -0
  40. data/db/migrate/20120219071614_create_crowdblog_assets.rb +10 -0
  41. data/lib/crowdblog/devise/failure_app.rb +9 -0
  42. data/lib/crowdblog/rspec/crowdblog_shared_examples.rb +108 -0
  43. data/lib/crowdblog/rspec.rb +1 -0
  44. data/lib/crowdblog/version.rb +1 -1
  45. data/lib/crowdblog.rb +10 -0
  46. data/spec/dummy/app/controllers/application_controller.rb +0 -16
  47. data/spec/dummy/app/views/home/show.html.slim +1 -1
  48. data/spec/dummy/config/application.rb +0 -10
  49. data/spec/dummy/config/initializers/devise.rb +0 -7
  50. data/spec/dummy/config/routes.rb +1 -8
  51. data/spec/dummy/db/schema.rb +11 -11
  52. data/spec/dummy/db/seed.rb +6 -0
  53. data/spec/integration/crowdblog_spec.rb +5 -0
  54. data/spec/models/post_spec.rb +3 -3
  55. data/spec/models/user_spec.rb +25 -1
  56. data/spec/spec_helper.rb +17 -1
  57. data/vendor/assets/javascripts/backbone_rails_sync.js +69 -0
  58. data/vendor/assets/javascripts/uploader/jquery.html5uploader.js +148 -0
  59. metadata +40 -183
  60. data/Gemfile.lock +0 -280
  61. data/app/assets/javascripts/crowdblog/posts_main.js.coffee +0 -42
  62. data/app/assets/javascripts/crowdblog/templates/posts/attachment.jst.eco.slim +0 -1
  63. data/app/assets/javascripts/crowdblog/templates/posts/edit.jst.eco.slim +0 -36
  64. data/app/assets/javascripts/crowdblog/templates/posts/index.jst.eco.slim +0 -14
  65. data/app/assets/javascripts/crowdblog/templates/posts/post.jst.eco.slim +0 -14
  66. data/app/assets/javascripts/crowdblog/views/posts/attachment_view.js.coffee +0 -8
  67. data/app/assets/javascripts/crowdblog/views/posts/edit_post_view.js.coffee +0 -46
  68. data/app/assets/javascripts/crowdblog/views/posts/index.js.coffee +0 -28
  69. data/app/assets/javascripts/crowdblog/views/posts/post_view.js.coffee +0 -57
  70. data/app/assets/javascripts/crowdblog/xhr_fix.js.coffee +0 -4
  71. data/app/controllers/crowdblog/controller.rb +0 -10
  72. data/app/views/layouts/crowdblog/crowdblog.html.slim +0 -26
  73. data/db/migrate/20120215232711_create_users.rb +0 -10
  74. data/db/migrate/20120216154516_add_devise_to_users.rb +0 -56
  75. data/db/migrate/20120217213920_create_posts.rb +0 -13
  76. data/db/migrate/20120219014520_add_author_to_posts.rb +0 -6
  77. data/db/migrate/20120219040607_add_state_to_post.rb +0 -7
  78. data/db/migrate/20120219071614_create_assets.rb +0 -10
  79. data/db/migrate/20120219234253_add_alias_to_users.rb +0 -6
  80. data/db/migrate/20120229160314_add_review_fields_to_post.rb +0 -6
  81. data/features/posts/listing.feature +0 -32
  82. data/features/posts/manage.feature +0 -36
  83. data/features/posts/publish.feature +0 -17
  84. data/features/step_definitions/global_steps.rb +0 -23
  85. data/features/step_definitions/navigation_steps.rb +0 -45
  86. data/features/step_definitions/posts_steps.rb +0 -138
  87. data/features/step_definitions/review_steps.rb +0 -27
  88. data/features/support/env.rb +0 -76
  89. data/spec/dummy/app/models/user.rb +0 -17
  90. data/spec/fabricators/posts_fabricator.rb +0 -21
  91. data/spec/fabricators/users_fabricator.rb +0 -19
  92. data/vendor/assets/javascripts/swfobject.js +0 -4
  93. data/vendor/assets/swf/uploadify.swf +0 -0
data/.gitignore CHANGED
@@ -10,3 +10,5 @@ spec/dummy/tmp/
10
10
  spec/dummy/.sass-cache
11
11
 
12
12
  .sass-cache
13
+
14
+ Gemfile.lock
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
  [![Build Status](https://secure.travis-ci.org/crowdint/crowdblog.png?branch=master)](http://travis-ci.org/crowdint/crowdblog)
@@ -7,4 +6,96 @@ CI:
7
6
  Code Climate:
8
7
  [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/crowdint/crowdblog)
9
8
 
10
- **This project rocks!**
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(:spec)
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
- PostsApp.Post = Backbone.Model.extend
2
- url: ->
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
- PostsApp.PostCollection = Backbone.Collection.extend
9
- model: PostsApp.Post
4
+ url: ->
5
+ 'posts/' + @id
10
6
 
11
- url: '/admin/posts'
@@ -0,0 +1,12 @@
1
+ class Crowdblog.Views.AttachmentView extends Backbone.View
2
+ tagName: 'div'
3
+
4
+ className: 'attachment'
5
+
6
+ template:
7
+ _.template("![image alt](<%= attachment.url %>)")
8
+
9
+ render: ->
10
+ @$el.html @template($.parseJSON(@options))
11
+ @
12
+
@@ -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 'underscore'
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/models
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.PostsApp = {};
10
+ window.Crowdblog = {};
11
+ window.Crowdblog.Models = {};
12
+ window.Crowdblog.Views = {};
13
+
@@ -1,13 +1,34 @@
1
1
  /* Edit post */
2
- #post_preview {
3
- position: relative;
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
+ }
@@ -1,6 +1,5 @@
1
1
  /*
2
2
  *
3
- *= require twitter/bootstrap
4
3
  *= require_self
5
4
  *= require_tree ./crowdblog
6
5
  *
@@ -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 < Controller
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['Filedata']
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 < Controller
2
+ class AuthorsController < Crowdblog::ApplicationController
3
3
 
4
4
  def index
5
- @authors = User.includes(:authored_posts).sort {|a,b| b.authored_posts.count <=> a.authored_posts.count}
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
@@ -0,0 +1,3 @@
1
+ class Crowdblog::Devise::SessionsController < Devise::SessionsController
2
+ layout 'crowdblog/application'
3
+ end
@@ -1,28 +1,36 @@
1
- module Crowdblog
2
- class PostsController < Controller
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).all_posts_json
8
- respond_to do |format|
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(params[:post])
23
+ @post = Post.new(post_params)
16
24
  @post.author = current_user
17
25
  @post.regenerate_permalink
18
- @post.save
19
- respond_with @post
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 = Post.scoped_for(current_user).find(params[:id])
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(params[:transition], current_user) if params[:transition]
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
- respond_with @post
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 Asset < ActiveRecord::Base
3
- self.table_name = :assets
4
3
  belongs_to :post
5
4
 
6
5
  mount_uploader :attachment, AttachmentUploader
@@ -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
- validates :title, length: { minimum: 5, maximum: 90 }
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? ? Post : user.authored_posts
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,6 @@
1
+ - if flash[:notice]
2
+ .alert.alert-success
3
+ = flash[:notice]
4
+ - if flash[:alert]
5
+ .alert
6
+ = flash[:alert]
@@ -14,5 +14,5 @@ table.table.table-striped
14
14
  th= image_tag author.gravatar_url
15
15
  td= author.name
16
16
  td= author.email
17
- td= author.authored_posts.count
18
- td= author.last_post_at
17
+ td= author.published_posts.size
18
+ td= author.last_published_at
@@ -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= "![image alt](#{asset.attachment_url})"
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"