cadenero 0.0.2.a3 → 0.0.2.b1
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.
- checksums.yaml +15 -0
- data/README.md +4 -3
- data/app/controllers/cadenero/v1/account/sessions_controller.rb +3 -1
- data/app/controllers/cadenero/v1/account/users_controller.rb +8 -2
- data/app/controllers/cadenero/v1/accounts_controller.rb +13 -1
- data/app/extenders/middleware/robustness.rb +19 -0
- data/app/models/cadenero/member.rb +1 -0
- data/app/models/cadenero/user.rb +2 -0
- data/app/models/cadenero/v1/account.rb +16 -1
- data/app/serializers/cadenero/account_serializer.rb +1 -0
- data/app/serializers/cadenero/user_serializer.rb +1 -0
- data/config/initializers/apartment.rb +4 -1
- data/config/initializers/warden/strategies/password.rb +1 -1
- data/config/routes.rb +1 -0
- data/lib/cadenero/constraints/subdomain_required.rb +2 -0
- data/lib/cadenero/engine.rb +1 -1
- data/lib/cadenero/testing_support/subdomain_helpers.rb +15 -0
- data/lib/cadenero/version.rb +1 -1
- data/lib/cadenero.rb +2 -0
- data/lib/generators/cadenero/install_generator.rb +17 -0
- data/spec/dummy/log/development.log +209 -0
- data/spec/dummy/log/test.log +26783 -5135
- data/spec/dummy/tmp/ember-rails/ember.js +1693 -676
- data/spec/features/users/sign_in_spec.rb +13 -3
- data/spec/models/cadenero/account_spec.rb +31 -1
- data/spec/spec_helper.rb +1 -0
- metadata +11 -44
- data/app/helpers/cadenero/application_helper.rb +0 -4
- data/app/helpers/cadenero/v1/accounts_helper.rb +0 -4
- data/app/helpers/cadenero/v1/users_helper.rb +0 -4
- data/spec/features/cadenero/account_spec.rb +0 -23
- data/spec/support/subdomain_helpers.rb +0 -8
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
N2Y4NzhjNmE2MmVlYTlkNjNjMWFlYzI4MTYwZTkwMTQyMDk1MzBjNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MWVkNDAwNjIwMDEwNjM2YWYzZmNiOTQxNTdkZGE2OTJjMmU5YjQ2Mg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Y2RiYTg0YTM0NzdiOGQwYWEzZWZjNGU3NGUwNzU5MjZhYmU0NjcxZTllY2I0
|
10
|
+
OWE2YTJkMmMzMDE0ZGFhNzY0N2YxMGQ1ZDg2Yjk1MWFiMjU0OGYzYjBlOTk4
|
11
|
+
ZWUzNmEyMjYwMDIyZmU0YjQ4MjgwM2I0NjcxZGIzOWFmYWE3OTA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjNlM2Y3YmEyZmQ2MjU0MzZlNmEwYzJlZTgwNGUxZTc3NWY5NGE1OGY4NjIy
|
14
|
+
NzYyOTlhYzAyOGFhMzhjZDBjN2M5NWExYjdkMDUyY2MxNTdiOTlkMGJmYjQ2
|
15
|
+
MzVjNzhjYTM4NzVjZjQzODdjYmU1ZDdlZDYyNWZjMWM5Yjg3NmE=
|
data/README.md
CHANGED
@@ -6,7 +6,6 @@ By [](https://codeclimate.com/github/AgilTec/cadenero)
|
7
7
|
[](https://coveralls.io/r/AgilTec/cadenero?branch=master)
|
8
8
|
[](https://gemnasium.com/AgilTec/cadenero)
|
9
|
-
[](https://bitdeli.com/free "Bitdeli Badge")
|
10
9
|
|
11
10
|
Authentication Engine for Rails.API multitenant RESTful APIs based on Warden. It:
|
12
11
|
* Is Racked based
|
@@ -28,7 +27,7 @@ Generate first your Rails.API app as usual using:
|
|
28
27
|
|
29
28
|
In the `Gemfile` add the following lines:
|
30
29
|
```ruby
|
31
|
-
gem 'cadenero', '~> 0.0.2.
|
30
|
+
gem 'cadenero', '~> 0.0.2.b1'
|
32
31
|
gem 'pg'
|
33
32
|
```
|
34
33
|
|
@@ -110,10 +109,12 @@ You can check them running:
|
|
110
109
|
```
|
111
110
|
rake routes
|
112
111
|
```
|
112
|
+
### Documentation
|
113
|
+
You can review the YARD docs in: http://rubydoc.info/github/AgilTec/cadenero/frames
|
113
114
|
|
114
115
|
### The Cadenero Task List
|
115
116
|
- [x] Specs for the code 100% Coverage using BDD with [Rspec](https://github.com/rspec/rspec) and [Capybara](https://github.com/jnicklas/capybara)
|
116
|
-
- [
|
117
|
+
- [x] Documatation for all the code
|
117
118
|
- [ ] Examples of use and demo
|
118
119
|
|
119
120
|
### Versions
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require_dependency "cadenero/application_controller"
|
2
|
-
#
|
2
|
+
#NameSpace for the V1 API in Cadenero
|
3
3
|
module Cadenero::V1
|
4
|
+
# Controller for managing sessions for the API if you are using the :password Strategy
|
4
5
|
class Account::SessionsController < Cadenero::ApplicationController
|
5
6
|
# create the session for the user using the password strategy and returning the user JSON
|
6
7
|
def create
|
@@ -13,6 +14,7 @@ module Cadenero::V1
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
17
|
+
# destroy the session for the user using params id
|
16
18
|
def delete
|
17
19
|
user = Cadenero::User.find_by_id(params[:id])
|
18
20
|
if user_signed_in?
|
@@ -7,21 +7,27 @@ require_dependency "cadenero/application_controller"
|
|
7
7
|
|
8
8
|
module Cadenero
|
9
9
|
module V1
|
10
|
+
# Controller for managing users for specific accounts
|
10
11
|
class Account::UsersController < Cadenero::ApplicationController
|
11
12
|
# Create a [Cadenero::User] based on the params sended by the client as a JSON with the user inrormation
|
12
13
|
#
|
13
14
|
# @example Posting the user data to be created in an account via the subdomain
|
14
|
-
# post "http://#{account.subdomain}.example.com/v1/
|
15
|
+
# post "http://#{account.subdomain}.example.com/v1/users",
|
15
16
|
# user: { email: "user@example.com", password: "password", password_confirmation: "password" }
|
16
17
|
#
|
17
18
|
# @return render JSON of [Cadenero::User] created and the status 201 Created: The request has been
|
18
|
-
# fulfilled and resulted in a new resource being created
|
19
|
+
# fulfilled and resulted in a new resource being created.
|
19
20
|
def create
|
20
21
|
account = Cadenero::V1::Account.where(subdomain: request.subdomain).first
|
21
22
|
@user = account.users.create(params[:user])
|
22
23
|
force_authentication!(@user)
|
23
24
|
render json: @user, status: :created
|
24
25
|
end
|
26
|
+
# Send as JSON the user that match the params[:user]
|
27
|
+
def show
|
28
|
+
@user = account.users.where(params[:user]).first
|
29
|
+
render json: @user, status: :ok
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -2,11 +2,23 @@ require_dependency "cadenero/application_controller"
|
|
2
2
|
|
3
3
|
module Cadenero
|
4
4
|
module V1
|
5
|
+
# Handles the Accounts for the multitenant. An account creates a subdomain in the server as a route
|
6
|
+
# the account has an owner that is the default admin for that account
|
5
7
|
class AccountsController < Cadenero::ApplicationController
|
8
|
+
# For API consistency provides the example for creating a new account
|
6
9
|
def new
|
7
10
|
errors = %Q{Please sign up. posting the account json data as {account: { name: "Testy", subdomain: "test", owner_attributes: {email: "testy@example.com", password: "changeme", password_confirmation: "changeme"} }} to /v1/accounts/sign_up}
|
8
|
-
render json: {errors: errors, links: "/v1/accounts/sign_up"}, status:
|
11
|
+
render json: {errors: errors, links: "/v1/accounts/sign_up"}, status: :unprocessable_entity
|
9
12
|
end
|
13
|
+
# Create a [Cadenero::V1::Account] based on the params sended by the client as a JSON with the account inrormation
|
14
|
+
#
|
15
|
+
# @example Posting the account data to be created in a subdomain
|
16
|
+
# post "http://www.example.com/v1/accounts",
|
17
|
+
# account: { name: "Testy", subdomain: "test",
|
18
|
+
# owner_attributes: {email: "testy@example.com", password: "changeme", password_confirmation: "changeme"} }
|
19
|
+
#
|
20
|
+
# @return render JSON of [Cadenero::V1::Account] created and the status 201 Created: The request has been
|
21
|
+
# fulfilled and resulted in a new resource being created.
|
10
22
|
def create
|
11
23
|
@account = Cadenero::V1::Account.create_with_owner(params[:account])
|
12
24
|
if @account.valid?
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Intercepts excpetion from the middlewares to handled those as JSON responses
|
2
|
+
class Robustness
|
3
|
+
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
# Rack API call for rescue from the exceptions
|
9
|
+
def call(env)
|
10
|
+
@app.call(env)
|
11
|
+
rescue Apartment::SchemaNotFound => ex
|
12
|
+
[422, { 'Content-Type' => 'application/json' }, [ {errors: {subdomain:["Invalid subdomain"]}}.to_json ] ] # suppose the message can be safely used
|
13
|
+
rescue SecurityError => ex
|
14
|
+
[403, { 'Content-Type' => 'application/json' }, [ ex.message ] ]
|
15
|
+
ensure
|
16
|
+
env['rack.errors'].write(ex.message) if ex
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/app/models/cadenero/user.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Cadenero
|
2
|
+
# Defines a user of one or more accounts for the multitenant Rails App
|
2
3
|
class User < ActiveRecord::Base
|
3
4
|
attr_accessible :email, :password, :password_confirmation
|
4
5
|
has_secure_password
|
@@ -6,6 +7,7 @@ module Cadenero
|
|
6
7
|
has_many :members, class_name: "Cadenero::Member"
|
7
8
|
has_many :memberships, through: :members, source: :account
|
8
9
|
|
10
|
+
# Obtain the authentication_token from the account to be use for the User
|
9
11
|
def auth_token
|
10
12
|
accounts[0].authentication_token if accounts[0]
|
11
13
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module Cadenero::V1
|
2
|
+
# Defines a subdomain with a default admin (owner) as a tenant in the Rails App
|
2
3
|
class Account < ActiveRecord::Base
|
3
4
|
belongs_to :owner, :class_name => "Cadenero::User"
|
4
5
|
has_many :members, :class_name => "Cadenero::Member"
|
@@ -9,7 +10,7 @@ module Cadenero::V1
|
|
9
10
|
validates :subdomain, :presence => true, :uniqueness => true
|
10
11
|
validates :owner, :presence => true
|
11
12
|
|
12
|
-
# Creates an
|
13
|
+
# Creates an account and assign the provided [Cadenero::User] as owner to the account
|
13
14
|
# @param [Hash] params list
|
14
15
|
# @example
|
15
16
|
# Example for the params JSON: {name: "Testy", subdomain: "test",
|
@@ -25,6 +26,20 @@ module Cadenero::V1
|
|
25
26
|
account
|
26
27
|
end
|
27
28
|
|
29
|
+
# Gets the account for the specified subdomain and guards errors
|
30
|
+
# @param [String] params subdomain
|
31
|
+
# @example
|
32
|
+
# get_by_subdomain("www")
|
33
|
+
# @return the [Cadenero::V1::Account] for that subdomain
|
34
|
+
def self.get_by_subdomain(subdomain)
|
35
|
+
account = find_by_subdomain(subdomain)
|
36
|
+
if account
|
37
|
+
account
|
38
|
+
else
|
39
|
+
raise Apartment::SchemaNotFound, "Subdomain is not valid"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
28
43
|
# Create a database schema using the subdomain
|
29
44
|
def create_schema
|
30
45
|
Apartment::Database.create(subdomain)
|
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
require File.expand_path('../../../app/extenders/middleware/robustness', __FILE__)
|
2
|
+
|
3
|
+
Rails.application.config.middleware.use(Robustness)
|
4
|
+
Rails.application.config.middleware.use(Apartment::Elevators::Subdomain)
|
2
5
|
|
3
6
|
|
4
7
|
Apartment.configure do |config|
|
@@ -17,7 +17,7 @@ Warden::Strategies.add(:password) do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def authenticate!
|
20
|
-
account = Cadenero::V1::Account.
|
20
|
+
account = Cadenero::V1::Account.get_by_subdomain(subdomain)
|
21
21
|
if account
|
22
22
|
u = account.users.find_by_email(json_params["user"]["email"])
|
23
23
|
if u.nil? || u.blank?
|
data/config/routes.rb
CHANGED
@@ -8,6 +8,7 @@ Cadenero::Engine.routes.draw do
|
|
8
8
|
post '/sessions', :to => "sessions#create", default: :json
|
9
9
|
delete '/sessions', :to => "sessions#delete", default: :json
|
10
10
|
post '/users', :to => "users#create", default: :json
|
11
|
+
get '/users', :to => "users#show", :as => :users, default: :json
|
11
12
|
end
|
12
13
|
end
|
13
14
|
post '/accounts', :to => "accounts#create", :as => :accounts, default: :json
|
data/lib/cadenero/engine.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Cadenero
|
2
|
+
# Helper Methods for testing
|
3
|
+
module TestingSupport
|
4
|
+
# RSpec Helper for subdomains
|
5
|
+
module SubdomainHelpers
|
6
|
+
# To be use for RSpec features for defining and account with a subdomain visible for Capybara
|
7
|
+
def within_account_subdomain
|
8
|
+
let(:subdomain_url) { "http://#{account.subdomain}.example.com" }
|
9
|
+
before { Capybara.default_host = subdomain_url }
|
10
|
+
after { Capybara.default_host = "http://example.com" }
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/cadenero/version.rb
CHANGED
data/lib/cadenero.rb
CHANGED
@@ -34,10 +34,12 @@ module Cadenero
|
|
34
34
|
:default_user_password
|
35
35
|
|
36
36
|
class << self
|
37
|
+
# @return the base path for the Cadenero named routes
|
37
38
|
def base_path
|
38
39
|
@@base_path ||= Rails.application.routes.named_routes[:cadenero].path
|
39
40
|
end
|
40
41
|
|
42
|
+
# defines which class will be used as User Class in Cadenero
|
41
43
|
def user_class
|
42
44
|
if @@user_class.is_a?(Class)
|
43
45
|
raise "You can no longer set Cadenero.user_class to be a class. Please use a string instead."
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'rails/generators'
|
2
2
|
module Cadenero
|
3
|
+
# Bootstrap Cadenero in a new Rails App
|
3
4
|
module Generators
|
5
|
+
# Cadenero generator to be used as `rails-api g cadenero:install`
|
4
6
|
class InstallGenerator < Rails::Generators::Base
|
5
7
|
class_option "user-class", :type => :string
|
6
8
|
class_option "default-account-name", :type => :string
|
@@ -13,6 +15,7 @@ module Cadenero
|
|
13
15
|
source_root File.expand_path("../install/templates", __FILE__)
|
14
16
|
desc "Used to install Cadenero"
|
15
17
|
|
18
|
+
# Copy the Cadenero Migrations in the New App
|
16
19
|
def install_migrations
|
17
20
|
puts "Copying over Cadenero migrations..."
|
18
21
|
Dir.chdir(Rails.root) do
|
@@ -20,12 +23,14 @@ module Cadenero
|
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
26
|
+
# Defines which class will be used as User Class for Cadenero
|
23
27
|
def determine_user_class
|
24
28
|
@user_class = options["user-class"].presence ||
|
25
29
|
ask("What will be the name for your user class? [User]").presence ||
|
26
30
|
'User'
|
27
31
|
end
|
28
32
|
|
33
|
+
# Defines which helper will be used as User Class Helper for Cadenero and inject that in the application_controller.rb
|
29
34
|
def determine_current_user_helper
|
30
35
|
current_user_helper = options["current-user-helper"].presence ||
|
31
36
|
ask("What will be the current_user helper called in your app? [current_user]").presence ||
|
@@ -47,30 +52,35 @@ module Cadenero
|
|
47
52
|
|
48
53
|
end
|
49
54
|
|
55
|
+
# Define which will be the Root Account for the Multitnant Rails App
|
50
56
|
def determine_default_account_name
|
51
57
|
Cadenero.default_account_name = options["default-account-name"].presence ||
|
52
58
|
ask("What will be the name for the default account? [Root Account]").presence ||
|
53
59
|
'Root Account'
|
54
60
|
end
|
55
61
|
|
62
|
+
# Define which will be the root subdomain for the Multitnant Rails App. (Default: www)
|
56
63
|
def determine_default_account_subdomain
|
57
64
|
Cadenero.default_account_subdomain = options["default-account-subdomain"].presence ||
|
58
65
|
ask("What will be the subdomain for the default account? [www]").presence ||
|
59
66
|
'www'
|
60
67
|
end
|
61
68
|
|
69
|
+
# Define which will be the root owner for the defaul accout Multitnant Rails App.
|
62
70
|
def determine_default_user_email
|
63
71
|
Cadenero.default_user_email = options["default-user-email"].presence ||
|
64
72
|
ask("What will be the email for the default user owner of the default account? [testy@example.com]").presence ||
|
65
73
|
'testy@example.com'
|
66
74
|
end
|
67
75
|
|
76
|
+
# Define which will be the password for the root owner for the defaul accout Multitnant Rails App.
|
68
77
|
def determine_default_user_password
|
69
78
|
Cadenero.default_user_password = options["default-user-password"].presence ||
|
70
79
|
ask("What will be the password for the default user owner of the default account? [change-me]").presence ||
|
71
80
|
'change-me'
|
72
81
|
end
|
73
82
|
|
83
|
+
# Create the Cadenero initilizar based on the Template.
|
74
84
|
def add_cadenero_initializer
|
75
85
|
path = "#{Rails.root}/config/initializers/cadenero.rb"
|
76
86
|
if File.exists?(path)
|
@@ -82,6 +92,7 @@ module Cadenero
|
|
82
92
|
end
|
83
93
|
end
|
84
94
|
|
95
|
+
# Run the Cadenero Migrations in the New App
|
85
96
|
def run_migrations
|
86
97
|
unless options["no-migrate"]
|
87
98
|
puts "Running rake db:migrate"
|
@@ -89,6 +100,7 @@ module Cadenero
|
|
89
100
|
end
|
90
101
|
end
|
91
102
|
|
103
|
+
# Seed the databas using the options selected as defaults
|
92
104
|
def seed_database
|
93
105
|
puts "default_account_name: #{Cadenero.default_account_name}"
|
94
106
|
puts "default_account_subdomain: #{Cadenero.default_account_subdomain}"
|
@@ -102,6 +114,7 @@ module Cadenero
|
|
102
114
|
end
|
103
115
|
end
|
104
116
|
|
117
|
+
# Injects the code in the `routes.rb` for mounting the Cadenero Engine
|
105
118
|
def mount_engine
|
106
119
|
puts "Mounting Cadenero::Engine at \"/\" in config/routes.rb..."
|
107
120
|
insert_into_file("#{Rails.root}/config/routes.rb", :after => /routes.draw.do\n/) do
|
@@ -115,6 +128,7 @@ module Cadenero
|
|
115
128
|
end
|
116
129
|
end
|
117
130
|
|
131
|
+
# Wrap-ups the installation giving appropiate messages
|
118
132
|
def finished
|
119
133
|
output = "\n\n" + ("*" * 53)
|
120
134
|
output += %Q{\nDone! Cadenero has been successfully installed. Yaaaaay! He will keep the intoxicated JSON's out
|
@@ -146,16 +160,19 @@ output += step("`rake db:migrate` was run, running all the migrations against yo
|
|
146
160
|
|
147
161
|
private
|
148
162
|
|
163
|
+
# Keep track of the step number for the installation process
|
149
164
|
def step(words)
|
150
165
|
@step ||= 0
|
151
166
|
@step += 1
|
152
167
|
"#{@step}) #{words}\n"
|
153
168
|
end
|
154
169
|
|
170
|
+
# @return the user_class
|
155
171
|
def user_class
|
156
172
|
@user_class
|
157
173
|
end
|
158
174
|
|
175
|
+
# keep track of the migration numbers
|
159
176
|
def next_migration_number
|
160
177
|
last_migration = Dir[Rails.root + "db/migrate/*.rb"].sort.last.split("/").last
|
161
178
|
current_migration_number = /^(\d+)_/.match(last_migration)[1]
|