thecore_api 1.1.7

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 (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>.