thecore_api 1.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +37 -0
  4. data/app/controllers/api/v1/base_controller.rb +192 -0
  5. data/app/controllers/api/v1/info_controller.rb +40 -0
  6. data/app/controllers/api/v1/sessions_controller.rb +21 -0
  7. data/app/controllers/api/v1/users_controller.rb +15 -0
  8. data/config/initializers/wrap_parameters.rb +14 -0
  9. data/config/routes.rb +21 -0
  10. data/lib/tasks/thecore_api_tasks.rake +4 -0
  11. data/lib/thecore_api.rb +11 -0
  12. data/lib/thecore_api/engine.rb +18 -0
  13. data/lib/thecore_api/version.rb +3 -0
  14. data/test/dummy/README.rdoc +28 -0
  15. data/test/dummy/Rakefile +6 -0
  16. data/test/dummy/app/assets/javascripts/application.js +13 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  18. data/test/dummy/app/controllers/application_controller.rb +5 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  21. data/test/dummy/bin/bundle +3 -0
  22. data/test/dummy/bin/rails +4 -0
  23. data/test/dummy/bin/rake +4 -0
  24. data/test/dummy/bin/setup +29 -0
  25. data/test/dummy/config.ru +4 -0
  26. data/test/dummy/config/application.rb +26 -0
  27. data/test/dummy/config/boot.rb +5 -0
  28. data/test/dummy/config/database.yml +25 -0
  29. data/test/dummy/config/environment.rb +5 -0
  30. data/test/dummy/config/environments/development.rb +41 -0
  31. data/test/dummy/config/environments/production.rb +79 -0
  32. data/test/dummy/config/environments/test.rb +42 -0
  33. data/test/dummy/config/initializers/assets.rb +11 -0
  34. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  36. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  37. data/test/dummy/config/initializers/inflections.rb +16 -0
  38. data/test/dummy/config/initializers/mime_types.rb +4 -0
  39. data/test/dummy/config/initializers/session_store.rb +3 -0
  40. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  41. data/test/dummy/config/locales/en.yml +23 -0
  42. data/test/dummy/config/routes.rb +56 -0
  43. data/test/dummy/config/secrets.yml +22 -0
  44. data/test/dummy/public/404.html +67 -0
  45. data/test/dummy/public/422.html +67 -0
  46. data/test/dummy/public/500.html +66 -0
  47. data/test/dummy/public/favicon.ico +0 -0
  48. data/test/integration/navigation_test.rb +8 -0
  49. data/test/test_helper.rb +20 -0
  50. data/test/thecore_api_test.rb +7 -0
  51. metadata +200 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c3eeb066a19ef99dc62d57f971cd85863285dc5e
4
+ data.tar.gz: 65a10141e57a771479610214ae7f90f7084ca70e
5
+ SHA512:
6
+ metadata.gz: 66da97430ea31f832e402d9f9ec1eb610314660c380d0075a7576909d8e01e477e28f89b4f02cba058dae30404a54eed1a34fa501b630f484f949a18072d0434
7
+ data.tar.gz: 9c7619c6fbd0bf84c151b99915669c42341726935971474a2c9b13da15ee6a091c321eff2a95052f44cae65bc45334526341bfbd3baa9dcc632bd9f228f59f79
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Gabriele Tassoni
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ThecoreApi'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,192 @@
1
+ # https://labs.kollegorna.se/blog/2015/04/build-an-api-now/
2
+ class Api::V1::BaseController < ActionController::API
3
+ include CanCan::ControllerAdditions
4
+ #include Pundit
5
+ #check_authorization
6
+ #load_and_authorize_resource
7
+ # https://github.com/kollegorna/active_hash_relation
8
+ include ActiveHashRelation
9
+
10
+ # Prevent CSRF attacks by raising an exception.
11
+ # For APIs, you may want to use :null_session instead.
12
+ #protect_from_forgery with: :null_session
13
+
14
+ before_action :destroy_session
15
+
16
+ before_action :authenticate_user!
17
+ before_action :find_model, except: [ :version, :token ]
18
+ before_action :find_record, only: [ :show, :update, :destroy ]
19
+
20
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found!
21
+ rescue_from ActiveRecord::StatementInvalid, with: :unauthenticated!
22
+ rescue_from ActiveRecord::RecordInvalid, with: :invalid!
23
+ #rescue_from CanCan::AuthorizationNotPerformed, with: :unauthorized!
24
+ rescue_from CanCan::AccessDenied, with: :unauthorized!
25
+ #rescue_from Pundit::NotAuthorizedError, with: :unauthorized!
26
+
27
+ attr_accessor :current_user
28
+
29
+ def index
30
+ # find the records
31
+ @q = (@model.column_names.include?("user_id") ? @model.where(user_id: current_user.id) : @model).ransack(params[:q])
32
+ @records_all = @q.result(distinct: true)
33
+ @records = @records_all.page(params[:page]).per(params[:per])
34
+
35
+ # If there's the keyword pagination_info, then return a pagination info object
36
+ return render json: MultiJson.dump({
37
+ count: @records_all.count,
38
+ current_page_count: @records.count,
39
+ next_page: @records.next_page,
40
+ prev_page: @records.prev_page,
41
+ is_first_page: @records.first_page?,
42
+ is_last_page: @records.last_page?,
43
+ is_out_of_range: @records.out_of_range?,
44
+ pages_count: @records.total_pages,
45
+ current_page_number: @records.current_page
46
+ }) if !params[:pages_info].nil?
47
+ # If it's asked for page number, the paginate
48
+ return render json: MultiJson.dump(@records, @json_attrs || {}) if !params[:page].nil? # (@json_attrs || {})
49
+ # if you ask for count, then return a json object with just the number of objects
50
+ return render json: MultiJson.dump({count: @records_all.count}) if !params[:count].nil?
51
+ # Default
52
+ render json: MultiJson.dump(@records_all, @json_attrs || {}) #(@json_attrs || {})
53
+ end
54
+
55
+ # def count
56
+ # # find the records
57
+ # @q = (@model.column_names.include?("user_id") ? @model.where(user_id: current_user.id) : @model).ransack(params[:q])
58
+ # @records_all = @q.result(distinct: true)
59
+ # # if you ask for count, then return a json object with just the number of objects
60
+ # return render json: {count: @records_all.count}.to_json
61
+ # end
62
+
63
+ def search
64
+ index
65
+ render :index
66
+ end
67
+
68
+ def show
69
+ render json: @record.to_json(@json_attrs || {}), status: 200
70
+ end
71
+
72
+ def create
73
+ @record = @model.new(request_params)
74
+ @record.user_id = current_user.id if @model.column_names.include? "user_id"
75
+
76
+ @record.save!
77
+
78
+ render json: @record.to_json(@json_attrs || {}), status: 201
79
+ end
80
+
81
+ def update
82
+ @record.update_attributes(request_params)
83
+
84
+ render json: @record.to_json(@json_attrs || {}), status: 200
85
+ end
86
+
87
+ def destroy
88
+ unless @record.destroy
89
+ return api_error(status: 500)
90
+ end
91
+
92
+ head status: 204
93
+ end
94
+
95
+ protected
96
+
97
+ def destroy_session
98
+ request.session_options[:skip] = true
99
+ end
100
+
101
+ def unauthenticated!
102
+ response.headers['WWW-Authenticate'] = "Token realm=Application"
103
+ render json: { error: 'bad credentials' }, status: 401
104
+ end
105
+
106
+ def unauthorized!
107
+ render nothing: true, status: :forbidden
108
+ return
109
+ end
110
+
111
+ def invalid_credentials!
112
+ render json: { error: 'invalid credentials' }, status: 403
113
+ return
114
+ end
115
+
116
+ def unable!
117
+ render json: { error: 'you are not enabled to do so' }, status: 403
118
+ end
119
+
120
+ def invalid!
121
+ render json: { error: 'Some validation has failed' }, status: 422
122
+ end
123
+
124
+ def invalid_resource!(errors = [])
125
+ api_error(status: 422, errors: errors)
126
+ end
127
+
128
+ def not_found!
129
+ return api_error(status: 404, errors: 'Not found')
130
+ end
131
+
132
+ def api_error(status: 500, errors: [])
133
+ unless Rails.env.production?
134
+ puts errors.full_messages if errors.respond_to? :full_messages
135
+ end
136
+ head status: status and return if errors.empty?
137
+
138
+ # render json: jsonapi_format(errors).to_json, status: status
139
+ render json: errors.to_json, status: status
140
+ end
141
+
142
+ def paginate(resource)
143
+ resource = resource.page(params[:page] || 1)
144
+ if params[:per_page]
145
+ resource = resource.per_page(params[:per_page])
146
+ end
147
+
148
+ return resource
149
+ end
150
+
151
+ # expects pagination!
152
+ def meta_attributes(object)
153
+ {
154
+ current_page: object.current_page,
155
+ next_page: object.next_page,
156
+ prev_page: (object.previous_page rescue nil),
157
+ total_pages: object.total_pages,
158
+ total_count: (object.total_entries rescue nil)
159
+ }
160
+ end
161
+
162
+ def authenticate_user!
163
+ token, options = ActionController::HttpAuthentication::Token.token_and_options(request)
164
+
165
+ # puts "controller: #{controller_name}\naction: #{action_name}\ntoken: #{token}\noptions: #{options.inspect}\n\n"
166
+
167
+ user_email = options.blank?? nil : options[:email]
168
+ user = user_email && User.find_by(email: user_email)
169
+
170
+ if user && ActiveSupport::SecurityUtils.secure_compare(user.authentication_token, token)
171
+ @current_user = user
172
+ else
173
+ return unauthenticated!
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def find_record
180
+ # find the records
181
+ @record = @model.column_names.include?("user_id") ? @model.where(id: params[:id], user_id: current_user.id).first : @model.find(params[:id])
182
+ end
183
+
184
+ def find_model
185
+ # Find the name of the model from controller
186
+ @model = controller_path.classify.constantize rescue controller_name.classify.constantize
187
+ end
188
+
189
+ def request_params
190
+ params.require(controller_name.to_sym).permit!().delete_if{ |k,v| v.nil? }
191
+ end
192
+ end
@@ -0,0 +1,40 @@
1
+ class Api::V1::InfoController < Api::V1::BaseController
2
+ skip_before_action :authenticate_user!, only: [:version]
3
+
4
+ # api :GET, '/api/v1/info/version', "Just prints the APPVERSION."
5
+ # api!
6
+ def version
7
+ render json: {
8
+ version: APPVERSION
9
+ }.to_json, status: 200
10
+ end
11
+
12
+ # api :GET, '/api/v1/info/token', "Given auth credentials, in HTTP_BASIC form,
13
+ # it returns the AUTH_TOKEN, email and id of the user which performed the authentication."
14
+ # api!
15
+ def token
16
+ render json: {
17
+ token: @current_user.authentication_token,
18
+ email: @current_user.email,
19
+ roles: @current_user.roles,
20
+ admin: @current_user.admin,
21
+ third_party: @current_user.third_party,
22
+ id: @current_user.id
23
+ }.to_json, status: 200
24
+ end
25
+
26
+ private
27
+
28
+ # Method overridden because the first time I have to ask for the token
29
+ def authenticate_user!
30
+ username, password = ActionController::HttpAuthentication::Basic.user_name_and_password(request)
31
+ if username
32
+ user = User.find_by(username: username)
33
+ end
34
+ if user && user.valid_password?(password)
35
+ @current_user = user
36
+ else
37
+ return unauthenticated!
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ class Api::V1::SessionsController < Api::V1::BaseController
2
+ skip_before_action :authenticate_user!
3
+ def create
4
+ user = User.find_by(email: request_params[:email])
5
+ if user && user.authenticate(request_params[:password])
6
+ self.current_user = user
7
+ render(
8
+ json: Api::V1::SessionSerializer.new(user, root: false).to_json,
9
+ status: 201
10
+ )
11
+ else
12
+ return api_error(status: 401)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def request_params
19
+ params.require(:user).permit(:email, :password)
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ class Api::V1::UsersController < Api::V1::BaseController
2
+ load_and_authorize_resource
3
+
4
+ before_action :check_demoting
5
+
6
+ private
7
+
8
+ def check_demoting
9
+ render json: "You cannot demote yourself", status: 403 if (params[:id].to_i == current_user.id && (params[:users].keys.include?("admin") || params[:users].keys.include?("locked")))
10
+ end
11
+
12
+ def request_params
13
+ params.require(:users).permit(:email, :roles, :password, :password_confirmation, :username, :number_of_instances_purchased, :admin, :locked).delete_if{ |k,v| v.nil? }
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # This file contains settings for ActionController::ParamsWrapper which
4
+ # is enabled by default.
5
+
6
+ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
+ ActiveSupport.on_load(:action_controller) do
8
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9
+ end
10
+
11
+ # To enable root element in JSON for ActiveRecord objects.
12
+ # ActiveSupport.on_load(:active_record) do
13
+ # self.include_root_in_json = true
14
+ # end
@@ -0,0 +1,21 @@
1
+ require 'thecore'
2
+ require 'ransack'
3
+
4
+ Rails.application.routes.draw do
5
+ # REST API (Stateless)
6
+ namespace :api do
7
+ namespace :v1, defaults: { format: :json } do
8
+
9
+ resources :sessions, only: [:create]
10
+
11
+ namespace :info do
12
+ get :version
13
+ get :token
14
+ end
15
+
16
+ resources :users, only: [:index, :create, :show, :update, :destroy] do
17
+ match 'search' => 'users#search', via: [:get, :post], as: :search, on: :collection
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :thecore_api do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,11 @@
1
+ require 'thecore'
2
+ # require 'rails-api' integrated into rails 5.0
3
+ # require 'active_model_serializers'
4
+ require 'active_hash_relation'
5
+ require 'rack/cors'
6
+ require 'therubyracer'
7
+ require "thecore_api/engine"
8
+ require 'ransack'
9
+
10
+ module ThecoreApi
11
+ end
@@ -0,0 +1,18 @@
1
+ module ThecoreApi
2
+ class Engine < ::Rails::Engine
3
+ # appending migrations to the main app's ones
4
+ initializer :append_migrations do |app|
5
+ config.middleware.insert_before 0, "Rack::Cors" do
6
+ allow do
7
+ origins '*'
8
+ resource '*', :headers => :any, :methods => [:get, :post, :put, :patch, :delete, :options, :head]
9
+ end
10
+ end
11
+ unless app.root.to_s == root.to_s
12
+ config.paths["db/migrate"].expanded.each do |expanded_path|
13
+ app.config.paths["db/migrate"] << expanded_path
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module ThecoreApi
2
+ VERSION = "1.1.7".freeze
3
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.