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.
Files changed (32) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +4 -3
  3. data/app/controllers/cadenero/v1/account/sessions_controller.rb +3 -1
  4. data/app/controllers/cadenero/v1/account/users_controller.rb +8 -2
  5. data/app/controllers/cadenero/v1/accounts_controller.rb +13 -1
  6. data/app/extenders/middleware/robustness.rb +19 -0
  7. data/app/models/cadenero/member.rb +1 -0
  8. data/app/models/cadenero/user.rb +2 -0
  9. data/app/models/cadenero/v1/account.rb +16 -1
  10. data/app/serializers/cadenero/account_serializer.rb +1 -0
  11. data/app/serializers/cadenero/user_serializer.rb +1 -0
  12. data/config/initializers/apartment.rb +4 -1
  13. data/config/initializers/warden/strategies/password.rb +1 -1
  14. data/config/routes.rb +1 -0
  15. data/lib/cadenero/constraints/subdomain_required.rb +2 -0
  16. data/lib/cadenero/engine.rb +1 -1
  17. data/lib/cadenero/testing_support/subdomain_helpers.rb +15 -0
  18. data/lib/cadenero/version.rb +1 -1
  19. data/lib/cadenero.rb +2 -0
  20. data/lib/generators/cadenero/install_generator.rb +17 -0
  21. data/spec/dummy/log/development.log +209 -0
  22. data/spec/dummy/log/test.log +26783 -5135
  23. data/spec/dummy/tmp/ember-rails/ember.js +1693 -676
  24. data/spec/features/users/sign_in_spec.rb +13 -3
  25. data/spec/models/cadenero/account_spec.rb +31 -1
  26. data/spec/spec_helper.rb +1 -0
  27. metadata +11 -44
  28. data/app/helpers/cadenero/application_helper.rb +0 -4
  29. data/app/helpers/cadenero/v1/accounts_helper.rb +0 -4
  30. data/app/helpers/cadenero/v1/users_helper.rb +0 -4
  31. data/spec/features/cadenero/account_spec.rb +0 -23
  32. 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 [![Agiltec Logo](https://launchrock-assets.s3.amazonaws.com/logo-files/Gpujzv
6
6
  [![Code Climate](https://codeclimate.com/github/AgilTec/cadenero.png)](https://codeclimate.com/github/AgilTec/cadenero)
7
7
  [![Coverage Status](https://coveralls.io/repos/AgilTec/cadenero/badge.png?branch=master)](https://coveralls.io/r/AgilTec/cadenero?branch=master)
8
8
  [![Dependency Status](https://gemnasium.com/AgilTec/cadenero.png)](https://gemnasium.com/AgilTec/cadenero)
9
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/AgilTec/cadenero/trend.png)](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.a3'
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
- - [ ] Documatation for all the code
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
- # COntroller for managing sessions for the API if you are using the :password Strategy
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/sign_up",
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: 422
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
@@ -1,4 +1,5 @@
1
1
  module Cadenero
2
+ # Defines that a Cadenero::User is member of an Cadenero::V1::Account
2
3
  class Member < ActiveRecord::Base
3
4
  belongs_to :account, :class_name => "Cadenero::V1::Account"
4
5
  belongs_to :user, :class_name => "Cadenero::User"
@@ -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 accout and assign the provided [Cadenero::User] as owner to the account
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,5 @@
1
1
  module Cadenero
2
+ # JSON Serializaer for the Cadenero::V1::Account Model
2
3
  class AccountSerializer < ActiveModel::Serializer
3
4
  embed :ids
4
5
  attributes :id, :name, :subdomain, :authentication_token
@@ -1,4 +1,5 @@
1
1
  module Cadenero
2
+ # JSON Serializaer for the Cadenero::User Model
2
3
  class UserSerializer < ActiveModel::Serializer
3
4
  embed :ids
4
5
  attributes :id, :email, :auth_token
@@ -1,4 +1,7 @@
1
- Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'
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.find_by_subdomain(subdomain)
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
@@ -1,5 +1,7 @@
1
1
  module Cadenero
2
+ # Constraints for the routes
2
3
  module Constraints
4
+ # For the routes require that a subdomain is defined
3
5
  class SubdomainRequired
4
6
  def self.matches?(request)
5
7
  request.subdomain.present? && request.subdomain != "www"
@@ -1,6 +1,6 @@
1
1
  require 'warden'
2
2
  module Cadenero
3
-
3
+ # Defines Cadenero as a Rails Engine using the passworf strategy as default for Warden
4
4
  class Engine < ::Rails::Engine
5
5
  isolate_namespace Cadenero
6
6
  config.middleware.use Warden::Manager do |manager|
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Cadenero
2
- VERSION = "0.0.2.a3"
2
+ VERSION = "0.0.2.b1" # Current VERSION of Cadenero
3
3
  end
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]