feature_box 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +1 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +107 -0
- data/app/assets/javascripts/feature_box/application.js +39 -0
- data/app/assets/stylesheets/feature_box/application.css.scss +133 -0
- data/app/assets/stylesheets/feature_box/comments.css.scss +41 -0
- data/app/assets/stylesheets/feature_box/mixins.css.scss +37 -0
- data/app/assets/stylesheets/feature_box/suggestions.css.scss +110 -0
- data/app/controllers/feature_box/application_controller.rb +37 -0
- data/app/controllers/feature_box/categories_controller.rb +43 -0
- data/app/controllers/feature_box/comments_controller.rb +46 -0
- data/app/controllers/feature_box/devise/passwords_controller.rb +4 -0
- data/app/controllers/feature_box/devise/redirects.rb +21 -0
- data/app/controllers/feature_box/devise/registrations_controller.rb +4 -0
- data/app/controllers/feature_box/devise/sessions_controller.rb +4 -0
- data/app/controllers/feature_box/home_controller.rb +8 -0
- data/app/controllers/feature_box/suggestions_controller.rb +161 -0
- data/app/controllers/feature_box/users_controller.rb +32 -0
- data/app/helpers/feature_box/application_helper.rb +40 -0
- data/app/mailers/feature_box/devise/mailer.rb +3 -0
- data/app/models/feature_box/ability.rb +25 -0
- data/app/models/feature_box/category.rb +15 -0
- data/app/models/feature_box/comment.rb +15 -0
- data/app/models/feature_box/suggestion.rb +113 -0
- data/app/models/feature_box/user.rb +61 -0
- data/app/models/feature_box/vote.rb +6 -0
- data/app/views/feature_box/categories/_form.html.haml +14 -0
- data/app/views/feature_box/categories/edit.html.haml +3 -0
- data/app/views/feature_box/categories/index.html.haml +26 -0
- data/app/views/feature_box/categories/new.html.haml +3 -0
- data/app/views/feature_box/comments/_comment.html.haml +9 -0
- data/app/views/feature_box/comments/_new.html.haml +9 -0
- data/app/views/feature_box/comments/edit.html.haml +17 -0
- data/app/views/feature_box/comments/index.html.haml +8 -0
- data/app/views/feature_box/devise/_links.html.haml +9 -0
- data/app/views/feature_box/devise/confirmations/new.html.haml +7 -0
- data/app/views/feature_box/devise/mailer/confirmation_instructions.html.haml +4 -0
- data/app/views/feature_box/devise/mailer/reset_password_instructions.html.haml +6 -0
- data/app/views/feature_box/devise/mailer/unlock_instructions.html.haml +5 -0
- data/app/views/feature_box/devise/passwords/edit.html.haml +7 -0
- data/app/views/feature_box/devise/passwords/new.html.haml +5 -0
- data/app/views/feature_box/devise/registrations/edit.html.haml +16 -0
- data/app/views/feature_box/devise/registrations/new.html.haml +8 -0
- data/app/views/feature_box/devise/sessions/new.html.haml +8 -0
- data/app/views/feature_box/shared/_pages_nav.html.haml +6 -0
- data/app/views/feature_box/suggestions/_form.html.haml +30 -0
- data/app/views/feature_box/suggestions/_order_nav.html.haml +6 -0
- data/app/views/feature_box/suggestions/_search.html.haml +4 -0
- data/app/views/feature_box/suggestions/_suggestion.html.haml +31 -0
- data/app/views/feature_box/suggestions/edit.html.haml +3 -0
- data/app/views/feature_box/suggestions/index.html.haml +27 -0
- data/app/views/feature_box/suggestions/new.html.haml +6 -0
- data/app/views/feature_box/suggestions/show.html.haml +2 -0
- data/app/views/feature_box/users/edit.html.haml +14 -0
- data/app/views/feature_box/users/index.html.haml +24 -0
- data/app/views/layouts/feature_box/application.html.haml +81 -0
- data/config/initializers/devise.rb +3 -0
- data/config/routes.rb +35 -0
- data/db/seeds.rb +11 -0
- data/lib/feature_box.rb +72 -0
- data/lib/feature_box/engine.rb +5 -0
- data/lib/feature_box/helpers.rb +49 -0
- data/lib/feature_box/version.rb +3 -0
- data/lib/generators/feature_box/existing_generator.rb +26 -0
- data/lib/generators/feature_box/generator_base.rb +47 -0
- data/lib/generators/feature_box/initializer_generator.rb +14 -0
- data/lib/generators/feature_box/migrations_generator.rb +25 -0
- data/lib/generators/feature_box/standalone_generator.rb +27 -0
- data/lib/generators/feature_box/templates/initializers/initializer.rb +32 -0
- data/lib/generators/feature_box/templates/initializers/new_devise_initializer.rb +8 -0
- data/lib/generators/feature_box/templates/migrations/00_create_feature_box_suggestions.rb +15 -0
- data/lib/generators/feature_box/templates/migrations/01_create_feature_box_categories.rb +9 -0
- data/lib/generators/feature_box/templates/migrations/02_create_feature_box_comments.rb +13 -0
- data/lib/generators/feature_box/templates/migrations/03_create_feature_box_votes.rb +12 -0
- data/lib/generators/feature_box/templates/migrations/04_create_feature_box_users.rb +10 -0
- data/lib/generators/feature_box/templates/migrations/05_add_devise_to_feature_box_users.rb +50 -0
- data/lib/generators/feature_box/templates/migrations/06_add_type_to_{model_name}.rb +5 -0
- data/lib/generators/feature_box/views_generator.rb +14 -0
- data/lib/tasks/feature_box_tasks.rake +9 -0
- data/test/existing-template/application.html.erb +40 -0
- data/test/existing-template/application_helper.rb +11 -0
- data/test/existing-template/index.html.erb +1 -0
- data/test/run-all-tests.sh +7 -0
- data/test/template.rb +29 -0
- data/vendor/assets/stylesheets/bootstrap.min.css +689 -0
- metadata +250 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
|
3
|
+
class ApplicationController < ActionController::Base
|
4
|
+
|
5
|
+
protect_from_forgery
|
6
|
+
before_filter :retrieve_vars
|
7
|
+
#check_authorization
|
8
|
+
|
9
|
+
rescue_from CanCan::AccessDenied do |exception|
|
10
|
+
redirect_to root_path, :alert => exception.message
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_ability
|
14
|
+
FeatureBox::Ability.new(current_user)
|
15
|
+
end
|
16
|
+
|
17
|
+
def pages_helper(&code)
|
18
|
+
@current_page = (params[:page]==nil)?0:(params[:page].to_i)
|
19
|
+
@current_page = @current_page<1?1:@current_page
|
20
|
+
limit = Settings.max_suggestions_on_page
|
21
|
+
offset=@current_page*limit-limit
|
22
|
+
offset=offset<0?0:offset
|
23
|
+
|
24
|
+
code.call limit, offset
|
25
|
+
|
26
|
+
@last_page = (@total / limit.to_f).ceil
|
27
|
+
end
|
28
|
+
|
29
|
+
def retrieve_vars
|
30
|
+
@categories = Array [Category.default] + Category.all
|
31
|
+
end
|
32
|
+
|
33
|
+
include FeatureBox::Helpers
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
class CategoriesController < FeatureBox::ApplicationController
|
3
|
+
load_and_authorize_resource
|
4
|
+
|
5
|
+
def index
|
6
|
+
pages_helper do |limit,offset|
|
7
|
+
@real_categories = Category.limit(limit).offset(offset)
|
8
|
+
@total = Category.count
|
9
|
+
@offset = offset
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def new
|
14
|
+
end
|
15
|
+
|
16
|
+
def edit
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
@category.name = params[:category][:name]
|
21
|
+
if @category.save
|
22
|
+
redirect_to categories_path, notice: 'Category was successfully created.'
|
23
|
+
else
|
24
|
+
render action: "new"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
@category.name = params[:category][:name]
|
30
|
+
if @category.save
|
31
|
+
redirect_to categories_path, notice: 'Category was successfully updated.'
|
32
|
+
else
|
33
|
+
render action: "edit"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy
|
38
|
+
@category.destroy
|
39
|
+
redirect_to categories_path, notice: 'Category was successfully deleted.'
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
class CommentsController < FeatureBox::ApplicationController
|
3
|
+
|
4
|
+
load_and_authorize_resource
|
5
|
+
|
6
|
+
|
7
|
+
def create
|
8
|
+
suggestion =Suggestion.find(params["suggestion_id"])
|
9
|
+
@comment.text = params["comment"]["text"]
|
10
|
+
@comment.user = current_user
|
11
|
+
@comment.suggestion = suggestion
|
12
|
+
if @comment.save
|
13
|
+
redirect_to suggestion, notice: 'Comment was successfully added.'
|
14
|
+
else
|
15
|
+
redirect_to suggestion, :flash => {
|
16
|
+
#TODO: it can be anything, not only empty comment
|
17
|
+
:error => 'Comment cannot be empty'
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def edit
|
23
|
+
end
|
24
|
+
|
25
|
+
def show
|
26
|
+
redirect_to @comment.suggestion
|
27
|
+
end
|
28
|
+
|
29
|
+
def update
|
30
|
+
@comment.text = params[:comment][:text]
|
31
|
+
if @comment.save
|
32
|
+
redirect_to @comment.suggestion, notice: 'Comment was successfully updated.'
|
33
|
+
else
|
34
|
+
render action: "edit"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy
|
39
|
+
@comment.destroy
|
40
|
+
redirect_to @comment.suggestion, notice: 'Comment was successfully deleted.'
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
module Devise
|
3
|
+
module Redirects
|
4
|
+
def after_sign_in_path_for resource_or_scope
|
5
|
+
feature_box.root_path
|
6
|
+
end
|
7
|
+
def after_sign_out_path_for resource_or_scope
|
8
|
+
feature_box.root_path
|
9
|
+
end
|
10
|
+
def after_sign_up_path_for resource_or_scope
|
11
|
+
feature_box.root_path
|
12
|
+
end
|
13
|
+
def signed_in_root_path resource_or_scope
|
14
|
+
feature_box.root_path
|
15
|
+
end
|
16
|
+
def self.included m
|
17
|
+
m.skip_authorization_check
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
class SuggestionsController < FeatureBox::ApplicationController
|
3
|
+
load_and_authorize_resource :except => [:my_suggestions, :my_comments, :my_votes, :search, :create, :vote]
|
4
|
+
|
5
|
+
def index
|
6
|
+
authorize! :read, Suggestion
|
7
|
+
|
8
|
+
redirect = get_and_validate_params
|
9
|
+
if redirect != false
|
10
|
+
return redirect
|
11
|
+
end
|
12
|
+
|
13
|
+
pages_helper do |limit, offset|
|
14
|
+
@suggestions, @total = Suggestion.find_those_with(
|
15
|
+
:category =>@active_category,
|
16
|
+
:order_type =>@active_order_type,
|
17
|
+
:limit => limit,
|
18
|
+
:offset => offset
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
@show_search=true
|
23
|
+
@show_nav_bar=true
|
24
|
+
end
|
25
|
+
|
26
|
+
def search
|
27
|
+
authorize! :read, Suggestion
|
28
|
+
q="%"+params[:q].to_s+"%"
|
29
|
+
limit=Settings.max_suggestions_on_page;
|
30
|
+
@suggestions = Suggestion.where("title LIKE ? OR description LIKE ?",q,q).order("created_at DESC").limit(limit)
|
31
|
+
@show_search=true
|
32
|
+
render action: "index"
|
33
|
+
end
|
34
|
+
|
35
|
+
def my_suggestions
|
36
|
+
impact_helper :suggestions
|
37
|
+
end
|
38
|
+
|
39
|
+
def my_votes
|
40
|
+
impact_helper :votes
|
41
|
+
end
|
42
|
+
|
43
|
+
def my_comments
|
44
|
+
impact_helper :comments
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def vote #json method
|
49
|
+
@suggestion = Suggestion.find(params[:id])
|
50
|
+
authorize! :create, Vote
|
51
|
+
if !user_signed_in?
|
52
|
+
{
|
53
|
+
:error=>"Sign in to vote"
|
54
|
+
}
|
55
|
+
elsif can?(:read, @suggestion)
|
56
|
+
@suggestion.vote current_user
|
57
|
+
votes=@suggestion.user_votes current_user
|
58
|
+
render :json => {
|
59
|
+
:total_votes=>@suggestion.votes.size,
|
60
|
+
:user_votes=>votes,
|
61
|
+
:votes_left=>current_user.votes_left
|
62
|
+
}
|
63
|
+
else
|
64
|
+
render :json => {
|
65
|
+
:error=>"You are not allowed to vote"
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
def show
|
72
|
+
@active_category = @suggestion.category
|
73
|
+
pages_helper do |limit, offset|
|
74
|
+
@comments = @suggestion.comments.order("created_at DESC").limit(limit).offset(offset)
|
75
|
+
@total = @suggestion.comments.order("created_at DESC").size
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def new
|
80
|
+
if current_user.votes_left<=0 then
|
81
|
+
return redirect_to suggestions_listing_path, :flash => {
|
82
|
+
:error => 'You need at least one vote to add suggestions'
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def edit
|
88
|
+
end
|
89
|
+
|
90
|
+
def create
|
91
|
+
@suggestion = Suggestion.new
|
92
|
+
authorize! :create, @suggestion
|
93
|
+
if current_user.votes_left<=0 then
|
94
|
+
return redirect_to suggestions_listing_path, :flash => {
|
95
|
+
:error => 'You need at least one vote to add suggestions'
|
96
|
+
}
|
97
|
+
end
|
98
|
+
@suggestion.title = params[:suggestion][:title]
|
99
|
+
@suggestion.description = params[:suggestion][:description]
|
100
|
+
@suggestion.category_id = params[:suggestion][:category_id]
|
101
|
+
if current_user.admin?
|
102
|
+
@suggestion.status = params[:suggestion][:status]
|
103
|
+
end
|
104
|
+
@suggestion.user = current_user
|
105
|
+
if @suggestion.save
|
106
|
+
redirect_to @suggestion, notice: 'Suggestion was successfully created.'
|
107
|
+
else
|
108
|
+
render action: "new"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def update
|
113
|
+
@suggestion.title = params[:suggestion][:title]
|
114
|
+
@suggestion.description = params[:suggestion][:description]
|
115
|
+
@suggestion.category_id = params[:suggestion][:category_id]
|
116
|
+
if current_user.admin?
|
117
|
+
@suggestion.status = params[:suggestion][:status]
|
118
|
+
end
|
119
|
+
if @suggestion.save
|
120
|
+
redirect_to @suggestion, notice: 'Suggestion was successfully updated.'
|
121
|
+
else
|
122
|
+
render action: "edit"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def destroy
|
127
|
+
@suggestion.destroy
|
128
|
+
redirect_to suggestions_listing_url, notice: 'Suggestion was successfully deleted.'
|
129
|
+
end
|
130
|
+
|
131
|
+
private #helper methods
|
132
|
+
|
133
|
+
# helper for my_votes, my_suggestions, my_comments
|
134
|
+
def impact_helper type_of_impact
|
135
|
+
authorize! :read_protected, Suggestion
|
136
|
+
|
137
|
+
pages_helper do |limit, offset|
|
138
|
+
@suggestions, @total = Suggestion.find_my type_of_impact, :user => current_user, :limit => limit, :offset => offset
|
139
|
+
end
|
140
|
+
|
141
|
+
@show_nav_bar=true
|
142
|
+
render action: "index"
|
143
|
+
end
|
144
|
+
|
145
|
+
def get_and_validate_params
|
146
|
+
|
147
|
+
@active_category = Category.find_by_name(params[:category]) || if Category.default.name == params[:category] then Category.default end
|
148
|
+
@active_order_type = ["newest","most_popular","in_progress","complete"].include?(params[:order])?(params[:order].to_sym):(nil)
|
149
|
+
|
150
|
+
if(@active_category == nil && @active_order_type == nil)
|
151
|
+
return redirect_to suggestions_listing_path(:category=>Category.default.name, :order=>:newest), :flash => flash
|
152
|
+
elsif(@active_category == nil)
|
153
|
+
return redirect_to suggestions_listing_path(:category=>Category.default.name), :flash => flash
|
154
|
+
elsif(@active_order_type == nil)
|
155
|
+
return redirect_to suggestions_listing_path(:order=>:newest), :flash => flash
|
156
|
+
end
|
157
|
+
|
158
|
+
return false
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
class UsersController < FeatureBox::ApplicationController
|
3
|
+
load_and_authorize_resource
|
4
|
+
def index
|
5
|
+
pages_helper do |limit,offset|
|
6
|
+
@users = User.limit(limit).offset(offset)
|
7
|
+
@total = User.count
|
8
|
+
@offset = offset
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def edit
|
13
|
+
end
|
14
|
+
|
15
|
+
def update
|
16
|
+
@user.name = params[:user][:name]
|
17
|
+
@user.email = params[:user][:email]
|
18
|
+
if @user.save
|
19
|
+
redirect_to users_path, notice: 'User info was successfully updated.'
|
20
|
+
else
|
21
|
+
render action: "edit"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def destroy
|
26
|
+
@user.destroy
|
27
|
+
redirect_to users_path, notice: 'User was successfully deleted.'
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
module ApplicationHelper
|
3
|
+
|
4
|
+
def generate_form_element form, name, element
|
5
|
+
if name == nil then
|
6
|
+
raw '<div class="control-group"><div class="controls">'+element+'</div></div>'
|
7
|
+
else
|
8
|
+
raw '<div class="control-group">'+form.label(name, :class=>"control-label")+'<div class="controls">'+element+'</div></div>'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def multiline text
|
13
|
+
raw h(text).gsub(/\n/, '<br/>')
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def devise_error_messages_any?
|
18
|
+
if respond_to? :resource
|
19
|
+
return !resource.errors.empty?
|
20
|
+
else
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def devise_error_messages!
|
26
|
+
resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join.html_safe
|
27
|
+
end
|
28
|
+
|
29
|
+
def devise_router_name
|
30
|
+
if controller.class.name =~ /FeatureBox::Devise/
|
31
|
+
feature_box
|
32
|
+
else
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
include FeatureBox::Helpers
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module FeatureBox
|
2
|
+
class Ability
|
3
|
+
|
4
|
+
include CanCan::Ability
|
5
|
+
|
6
|
+
def initialize(user)
|
7
|
+
user ||= FeatureBox::User.new # guest user (not logged in)
|
8
|
+
if user.admin?
|
9
|
+
can :read, :all
|
10
|
+
can :read_protected, :all # read_protected is for signed in users only
|
11
|
+
can :create, :all
|
12
|
+
can :update, :all
|
13
|
+
can :destroy, :all
|
14
|
+
elsif user.id # registered user
|
15
|
+
can :read, [Suggestion, Comment]
|
16
|
+
can :read_protected, [Suggestion, Comment]
|
17
|
+
can :update, [Suggestion, Comment], :user_id => user.id
|
18
|
+
can :destroy, [Suggestion, Comment], :user_id => user.id
|
19
|
+
can :create, [Suggestion, Comment, Vote]
|
20
|
+
else
|
21
|
+
can :read, [Suggestion, Comment]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|