saucy 0.1.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.
- data/Gemfile +8 -0
- data/Gemfile.lock +106 -0
- data/README +9 -0
- data/app/controllers/accounts_controller.rb +57 -0
- data/app/controllers/invitations_controller.rb +36 -0
- data/app/controllers/memberships_controller.rb +9 -0
- data/app/controllers/permissions_controller.rb +17 -0
- data/app/controllers/plans_controller.rb +7 -0
- data/app/controllers/profiles_controller.rb +17 -0
- data/app/controllers/projects_controller.rb +56 -0
- data/app/models/account_membership.rb +8 -0
- data/app/models/invitation.rb +86 -0
- data/app/models/project_membership.rb +16 -0
- data/app/models/signup.rb +134 -0
- data/app/views/accounts/_account.html.erb +12 -0
- data/app/views/accounts/_blank_slate.html.erb +6 -0
- data/app/views/accounts/_projects.html.erb +12 -0
- data/app/views/accounts/_tab_bar.html.erb +8 -0
- data/app/views/accounts/edit.html.erb +17 -0
- data/app/views/accounts/index.html.erb +3 -0
- data/app/views/accounts/new.html.erb +26 -0
- data/app/views/invitation_mailer/invitation.text.erb +6 -0
- data/app/views/invitations/new.html.erb +11 -0
- data/app/views/invitations/show.html.erb +20 -0
- data/app/views/memberships/index.html.erb +16 -0
- data/app/views/permissions/edit.html.erb +15 -0
- data/app/views/plans/index.html.erb +3 -0
- data/app/views/profiles/_inputs.html.erb +6 -0
- data/app/views/profiles/edit.html.erb +35 -0
- data/app/views/projects/_form.html.erb +4 -0
- data/app/views/projects/edit.html.erb +18 -0
- data/app/views/projects/index.html.erb +13 -0
- data/app/views/projects/new.html.erb +11 -0
- data/config/routes.rb +18 -0
- data/features/run_features.feature +73 -0
- data/features/step_definitions/clearance_steps.rb +45 -0
- data/features/step_definitions/rails_steps.rb +70 -0
- data/features/support/env.rb +4 -0
- data/features/support/file.rb +11 -0
- data/lib/generators/saucy/base.rb +18 -0
- data/lib/generators/saucy/features/features_generator.rb +68 -0
- data/lib/generators/saucy/features/templates/factories.rb +55 -0
- data/lib/generators/saucy/features/templates/step_definitions/email_steps.rb +13 -0
- data/lib/generators/saucy/features/templates/step_definitions/factory_girl_steps.rb +1 -0
- data/lib/generators/saucy/features/templates/step_definitions/html_steps.rb +3 -0
- data/lib/generators/saucy/features/templates/step_definitions/project_steps.rb +4 -0
- data/lib/generators/saucy/features/templates/step_definitions/session_steps.rb +27 -0
- data/lib/generators/saucy/features/templates/step_definitions/user_steps.rb +54 -0
- data/lib/generators/saucy/install/install_generator.rb +36 -0
- data/lib/generators/saucy/install/templates/create_saucy_tables.rb +72 -0
- data/lib/generators/saucy/install/templates/models/account.rb +3 -0
- data/lib/generators/saucy/install/templates/models/invitation_mailer.rb +9 -0
- data/lib/generators/saucy/install/templates/models/plan.rb +3 -0
- data/lib/generators/saucy/install/templates/models/project.rb +3 -0
- data/lib/generators/saucy/views/views_generator.rb +23 -0
- data/lib/saucy.rb +7 -0
- data/lib/saucy/account.rb +50 -0
- data/lib/saucy/account_authorization.rb +34 -0
- data/lib/saucy/configuration.rb +12 -0
- data/lib/saucy/engine.rb +9 -0
- data/lib/saucy/layouts.rb +36 -0
- data/lib/saucy/plan.rb +11 -0
- data/lib/saucy/project.rb +39 -0
- data/lib/saucy/user.rb +37 -0
- data/spec/controllers/accounts_controller_spec.rb +204 -0
- data/spec/controllers/application_controller_spec.rb +27 -0
- data/spec/controllers/invitations_controller_spec.rb +155 -0
- data/spec/controllers/memberships_controller_spec.rb +33 -0
- data/spec/controllers/permissions_controller_spec.rb +69 -0
- data/spec/controllers/profiles_controller_spec.rb +43 -0
- data/spec/controllers/projects_controller_spec.rb +123 -0
- data/spec/layouts_spec.rb +21 -0
- data/spec/models/account_membership_spec.rb +13 -0
- data/spec/models/account_spec.rb +61 -0
- data/spec/models/invitation_spec.rb +160 -0
- data/spec/models/project_membership_spec.rb +26 -0
- data/spec/models/project_spec.rb +80 -0
- data/spec/models/signup_spec.rb +175 -0
- data/spec/models/user_spec.rb +96 -0
- data/spec/saucy_spec.rb +7 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/authentication_helpers.rb +71 -0
- data/spec/support/authorization_helpers.rb +56 -0
- data/spec/support/clearance_matchers.rb +55 -0
- data/spec/views/accounts/_account.html.erb_spec.rb +66 -0
- metadata +203 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
abstract (1.0.0)
|
5
|
+
actionmailer (3.0.3)
|
6
|
+
actionpack (= 3.0.3)
|
7
|
+
mail (~> 2.2.9)
|
8
|
+
actionpack (3.0.3)
|
9
|
+
activemodel (= 3.0.3)
|
10
|
+
activesupport (= 3.0.3)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
erubis (~> 2.6.6)
|
13
|
+
i18n (~> 0.4)
|
14
|
+
rack (~> 1.2.1)
|
15
|
+
rack-mount (~> 0.6.13)
|
16
|
+
rack-test (~> 0.5.6)
|
17
|
+
tzinfo (~> 0.3.23)
|
18
|
+
activemodel (3.0.3)
|
19
|
+
activesupport (= 3.0.3)
|
20
|
+
builder (~> 2.1.2)
|
21
|
+
i18n (~> 0.4)
|
22
|
+
activerecord (3.0.3)
|
23
|
+
activemodel (= 3.0.3)
|
24
|
+
activesupport (= 3.0.3)
|
25
|
+
arel (~> 2.0.2)
|
26
|
+
tzinfo (~> 0.3.23)
|
27
|
+
activeresource (3.0.3)
|
28
|
+
activemodel (= 3.0.3)
|
29
|
+
activesupport (= 3.0.3)
|
30
|
+
activesupport (3.0.3)
|
31
|
+
arel (2.0.6)
|
32
|
+
aruba (0.2.6)
|
33
|
+
background_process
|
34
|
+
cucumber (~> 0.9.4)
|
35
|
+
background_process (1.2)
|
36
|
+
builder (2.1.2)
|
37
|
+
cucumber (0.9.4)
|
38
|
+
builder (~> 2.1.2)
|
39
|
+
diff-lcs (~> 1.1.2)
|
40
|
+
gherkin (~> 2.2.9)
|
41
|
+
json (~> 1.4.6)
|
42
|
+
term-ansicolor (~> 1.0.5)
|
43
|
+
daemons (1.1.0)
|
44
|
+
diff-lcs (1.1.2)
|
45
|
+
erubis (2.6.6)
|
46
|
+
abstract (>= 1.0.0)
|
47
|
+
eventmachine (0.12.10)
|
48
|
+
gherkin (2.2.9)
|
49
|
+
json (~> 1.4.6)
|
50
|
+
term-ansicolor (~> 1.0.5)
|
51
|
+
i18n (0.5.0)
|
52
|
+
json (1.4.6)
|
53
|
+
mail (2.2.11)
|
54
|
+
activesupport (>= 2.3.6)
|
55
|
+
i18n (~> 0.5.0)
|
56
|
+
mime-types (~> 1.16)
|
57
|
+
treetop (~> 1.4.8)
|
58
|
+
mime-types (1.16)
|
59
|
+
polyglot (0.3.1)
|
60
|
+
rack (1.2.1)
|
61
|
+
rack-mount (0.6.13)
|
62
|
+
rack (>= 1.0.0)
|
63
|
+
rack-test (0.5.6)
|
64
|
+
rack (>= 1.0)
|
65
|
+
rails (3.0.3)
|
66
|
+
actionmailer (= 3.0.3)
|
67
|
+
actionpack (= 3.0.3)
|
68
|
+
activerecord (= 3.0.3)
|
69
|
+
activeresource (= 3.0.3)
|
70
|
+
activesupport (= 3.0.3)
|
71
|
+
bundler (~> 1.0)
|
72
|
+
railties (= 3.0.3)
|
73
|
+
railties (3.0.3)
|
74
|
+
actionpack (= 3.0.3)
|
75
|
+
activesupport (= 3.0.3)
|
76
|
+
rake (>= 0.8.7)
|
77
|
+
thor (~> 0.14.4)
|
78
|
+
rake (0.8.7)
|
79
|
+
rspec (2.2.0)
|
80
|
+
rspec-core (~> 2.2)
|
81
|
+
rspec-expectations (~> 2.2)
|
82
|
+
rspec-mocks (~> 2.2)
|
83
|
+
rspec-core (2.2.1)
|
84
|
+
rspec-expectations (2.2.0)
|
85
|
+
diff-lcs (~> 1.1.2)
|
86
|
+
rspec-mocks (2.2.0)
|
87
|
+
term-ansicolor (1.0.5)
|
88
|
+
thin (1.2.7)
|
89
|
+
daemons (>= 1.0.9)
|
90
|
+
eventmachine (>= 0.12.6)
|
91
|
+
rack (>= 1.0.0)
|
92
|
+
thor (0.14.6)
|
93
|
+
treetop (1.4.9)
|
94
|
+
polyglot (>= 0.3.1)
|
95
|
+
tzinfo (0.3.23)
|
96
|
+
|
97
|
+
PLATFORMS
|
98
|
+
ruby
|
99
|
+
|
100
|
+
DEPENDENCIES
|
101
|
+
aruba
|
102
|
+
cucumber
|
103
|
+
rails (>= 3.0.3)
|
104
|
+
rake
|
105
|
+
rspec
|
106
|
+
thin
|
data/README
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
class AccountsController < ApplicationController
|
2
|
+
skip_before_filter :authenticate, :only => [:new, :create]
|
3
|
+
before_filter :authorize_admin, :except => [:new, :create, :index]
|
4
|
+
layout Saucy::Layouts.to_proc
|
5
|
+
|
6
|
+
def new
|
7
|
+
@plan = Plan.find(params[:plan_id])
|
8
|
+
@signup = Signup.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
@signup = Signup.new(params[:signup])
|
13
|
+
@signup.user = current_user
|
14
|
+
if @signup.save
|
15
|
+
if @signup.email_confirmed?
|
16
|
+
flash[:success] = "Account was created."
|
17
|
+
sign_in @signup.user
|
18
|
+
redirect_to root_url
|
19
|
+
else
|
20
|
+
flash[:success] = "Account was created. Instructions for confirming your " +
|
21
|
+
"account have been sent to the email address you provided."
|
22
|
+
redirect_to sign_in_url
|
23
|
+
end
|
24
|
+
else
|
25
|
+
render :action => 'new'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def index
|
30
|
+
if current_user.projects.size == 1
|
31
|
+
flash.keep
|
32
|
+
redirect_to project_path(current_user.projects.first)
|
33
|
+
else
|
34
|
+
@accounts = current_user.accounts
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def edit
|
39
|
+
@account = current_account
|
40
|
+
end
|
41
|
+
|
42
|
+
def update
|
43
|
+
@account = current_account
|
44
|
+
if @account.update_attributes(params[:account])
|
45
|
+
flash[:success] = 'Account was updated.'
|
46
|
+
redirect_to edit_profile_url
|
47
|
+
else
|
48
|
+
render :action => :edit
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def current_account
|
55
|
+
Account.find_by_url!(params[:id])
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class InvitationsController < ApplicationController
|
2
|
+
before_filter :authorize_admin, :except => [:show, :update]
|
3
|
+
skip_before_filter :authenticate, :only => [:show, :update]
|
4
|
+
layout Saucy::Layouts.to_proc
|
5
|
+
|
6
|
+
def new
|
7
|
+
@invitation = Invitation.new
|
8
|
+
render
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
@invitation = Invitation.new(params[:invitation])
|
13
|
+
@invitation.account = current_account
|
14
|
+
if @invitation.save
|
15
|
+
flash[:success] = "User invited."
|
16
|
+
redirect_to account_memberships_url(current_account)
|
17
|
+
else
|
18
|
+
render :action => 'new'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def show
|
23
|
+
@invitation = Invitation.find(params[:id])
|
24
|
+
render
|
25
|
+
end
|
26
|
+
|
27
|
+
def update
|
28
|
+
@invitation = Invitation.find(params[:id])
|
29
|
+
if @invitation.accept(params[:invitation])
|
30
|
+
sign_in @invitation.user
|
31
|
+
redirect_to root_url
|
32
|
+
else
|
33
|
+
render :action => 'show'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class PermissionsController < ApplicationController
|
2
|
+
before_filter :authorize_admin
|
3
|
+
layout Saucy::Layouts.to_proc
|
4
|
+
|
5
|
+
def edit
|
6
|
+
@user = User.find(params[:user_id])
|
7
|
+
@projects = current_account.projects_by_name
|
8
|
+
render
|
9
|
+
end
|
10
|
+
|
11
|
+
def update
|
12
|
+
user = User.find(params[:user_id])
|
13
|
+
user.update_permissions_for(current_account, params[:permissions][:project_ids])
|
14
|
+
flash[:success] = "Permissions updated."
|
15
|
+
redirect_to account_memberships_url(current_account)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class ProfilesController < ApplicationController
|
2
|
+
layout Saucy::Layouts.to_proc
|
3
|
+
|
4
|
+
def edit
|
5
|
+
@user = current_user
|
6
|
+
end
|
7
|
+
|
8
|
+
def update
|
9
|
+
@user = current_user
|
10
|
+
if @user.update_attributes(params[:user])
|
11
|
+
flash[:notice] = "Your user account has been updated."
|
12
|
+
redirect_to edit_profile_url
|
13
|
+
else
|
14
|
+
render :action => :edit
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class ProjectsController < ApplicationController
|
2
|
+
before_filter :authorize_admin
|
3
|
+
layout Saucy::Layouts.to_proc
|
4
|
+
|
5
|
+
def new
|
6
|
+
@project = current_account.projects.build
|
7
|
+
render
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
@project = current_account.projects.build(params[:project])
|
12
|
+
if @project.save
|
13
|
+
flash[:notice] = "Project successfully created"
|
14
|
+
redirect_to edit_project_url(@project)
|
15
|
+
else
|
16
|
+
render :action => :new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def edit
|
21
|
+
@project = Project.find(params[:id])
|
22
|
+
render
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
@project = Project.find(params[:id])
|
27
|
+
if @project.update_attributes params[:project]
|
28
|
+
flash[:success] = 'Project was updated.'
|
29
|
+
redirect_to account_projects_url(current_account)
|
30
|
+
else
|
31
|
+
render :action => :edit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy
|
36
|
+
@project = Project.find(params[:id])
|
37
|
+
@project.destroy
|
38
|
+
flash[:success] = "Project has been deleted"
|
39
|
+
redirect_to account_projects_url(@project.account)
|
40
|
+
end
|
41
|
+
|
42
|
+
def index
|
43
|
+
@projects = current_account.projects
|
44
|
+
render
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def current_account
|
50
|
+
if params[:id]
|
51
|
+
Project.find(params[:id]).account
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class Invitation < ActiveRecord::Base
|
2
|
+
belongs_to :account
|
3
|
+
validates_presence_of :account_id
|
4
|
+
validates_presence_of :email
|
5
|
+
|
6
|
+
after_create :deliver_invitation
|
7
|
+
|
8
|
+
attr_accessor :new_user_name, :new_user_password,
|
9
|
+
:new_user_password_confirmation, :existing_user_password
|
10
|
+
attr_writer :new_user_email, :existing_user_email
|
11
|
+
attr_reader :user
|
12
|
+
attr_protected :account_id
|
13
|
+
|
14
|
+
validate :validate_accepting_user, :on => :update
|
15
|
+
|
16
|
+
def account_name
|
17
|
+
account.name
|
18
|
+
end
|
19
|
+
|
20
|
+
def accept(attributes)
|
21
|
+
self.attributes = attributes
|
22
|
+
@user = existing_user || new_user
|
23
|
+
if valid?
|
24
|
+
@user.save!
|
25
|
+
@user.account_memberships.create!(:account => account, :admin => admin)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def new_user_email
|
30
|
+
@new_user_email ||= email
|
31
|
+
end
|
32
|
+
|
33
|
+
def existing_user_email
|
34
|
+
@existing_user_email ||= email
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def deliver_invitation
|
40
|
+
InvitationMailer.invitation(self).deliver
|
41
|
+
end
|
42
|
+
|
43
|
+
def existing_user
|
44
|
+
if existing_user?
|
45
|
+
User.find_by_email(existing_user_email)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def existing_user?
|
50
|
+
existing_user_password.present?
|
51
|
+
end
|
52
|
+
|
53
|
+
def new_user
|
54
|
+
User.new(
|
55
|
+
:email => new_user_email,
|
56
|
+
:password => new_user_password,
|
57
|
+
:password_confirmation => new_user_password_confirmation,
|
58
|
+
:name => new_user_name
|
59
|
+
).tap do |user|
|
60
|
+
user.email_confirmed = true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_accepting_user
|
65
|
+
if existing_user?
|
66
|
+
validate_existing_user
|
67
|
+
else
|
68
|
+
validate_new_user
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate_new_user
|
73
|
+
user.valid?
|
74
|
+
user.errors.each do |field, message|
|
75
|
+
errors.add("new_user_#{field}", message)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def validate_existing_user
|
80
|
+
if existing_user.nil?
|
81
|
+
errors.add(:existing_user_email, "isn't signed up")
|
82
|
+
elsif !existing_user.authenticated?(existing_user_password)
|
83
|
+
errors.add(:existing_user_password, "is incorrect")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ProjectMembership < ActiveRecord::Base
|
2
|
+
attr_accessible :user, :project, :user_id, :project_id
|
3
|
+
|
4
|
+
belongs_to :user
|
5
|
+
belongs_to :project
|
6
|
+
|
7
|
+
validate :ensure_account_member
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def ensure_account_member
|
12
|
+
unless user.member_of?(project.account)
|
13
|
+
errors.add(:base, "This user is not a member of #{project.name}'s account")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|