resource_quotable 0.2.0

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 (66) hide show
  1. checksums.yaml +7 -0
  2. data/Changelog.md +17 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Rakefile +18 -0
  5. data/Readme.md +206 -0
  6. data/app/assets/config/resource_quotable_manifest.js +1 -0
  7. data/app/assets/stylesheets/resource_quotable/application.css +15 -0
  8. data/app/controllers/resource_quotable/application_controller.rb +15 -0
  9. data/app/controllers/resource_quotable/quota_controller.rb +106 -0
  10. data/app/controllers/resource_quotable/quotum_trackers_controller.rb +23 -0
  11. data/app/models/resource_quotable/application_record.rb +7 -0
  12. data/app/models/resource_quotable/quotum.rb +46 -0
  13. data/app/models/resource_quotable/quotum_tracker.rb +60 -0
  14. data/app/services/resource_quotable/action_services/base.rb +23 -0
  15. data/app/services/resource_quotable/action_services/check.rb +19 -0
  16. data/app/services/resource_quotable/action_services/check_multiple.rb +23 -0
  17. data/app/services/resource_quotable/action_services/increment.rb +18 -0
  18. data/app/services/resource_quotable/action_services/increment_multiple.rb +22 -0
  19. data/app/services/resource_quotable/base.rb +24 -0
  20. data/app/services/resource_quotable/create.rb +29 -0
  21. data/app/services/resource_quotable/destroy.rb +14 -0
  22. data/app/services/resource_quotable/quotum_tracker_services/reset.rb +17 -0
  23. data/app/services/resource_quotable/reset/all.rb +16 -0
  24. data/app/services/resource_quotable/reset/any.rb +16 -0
  25. data/app/services/resource_quotable/reset/base.rb +22 -0
  26. data/app/services/resource_quotable/reset/daily.rb +16 -0
  27. data/app/services/resource_quotable/reset/monthly.rb +16 -0
  28. data/app/services/resource_quotable/reset/weekly.rb +16 -0
  29. data/app/services/resource_quotable/reset/yearly.rb +16 -0
  30. data/app/services/resource_quotable/update.rb +23 -0
  31. data/app/views/layouts/resource_quotable/application.html.erb +15 -0
  32. data/app/views/resource_quotable/quota/_edit.html.erb +11 -0
  33. data/app/views/resource_quotable/quota/_index.html.erb +43 -0
  34. data/app/views/resource_quotable/quota/_new.html.erb +34 -0
  35. data/app/views/resource_quotable/quota/_show.html.erb +41 -0
  36. data/app/views/resource_quotable/quota/create.js.erb +3 -0
  37. data/app/views/resource_quotable/quota/destroy.js.erb +3 -0
  38. data/app/views/resource_quotable/quota/edit.html.erb +1 -0
  39. data/app/views/resource_quotable/quota/edit.js.erb +1 -0
  40. data/app/views/resource_quotable/quota/index/_row.html.erb +3 -0
  41. data/app/views/resource_quotable/quota/index/_row_content.html.erb +43 -0
  42. data/app/views/resource_quotable/quota/index.html.erb +1 -0
  43. data/app/views/resource_quotable/quota/index.js.erb +1 -0
  44. data/app/views/resource_quotable/quota/new.html.erb +1 -0
  45. data/app/views/resource_quotable/quota/new.js.erb +1 -0
  46. data/app/views/resource_quotable/quota/show/_row.html.erb +3 -0
  47. data/app/views/resource_quotable/quota/show/_row_content.html.erb +7 -0
  48. data/app/views/resource_quotable/quota/show.html.erb +1 -0
  49. data/app/views/resource_quotable/quota/show.js.erb +1 -0
  50. data/app/views/resource_quotable/quota/update.js.erb +3 -0
  51. data/app/views/resource_quotable/quotum_trackers/index/_row_content.html.erb +8 -0
  52. data/app/views/resource_quotable/quotum_trackers/reset.js.erb +3 -0
  53. data/config/routes.rb +11 -0
  54. data/db/migrate/20220805102601_create_resource_quotable_quota.rb +17 -0
  55. data/db/migrate/20220811072023_create_resource_quotable_quotum_trackers.rb +18 -0
  56. data/lib/concerns/controllers/allowed_to_manage_quota_check.rb +73 -0
  57. data/lib/concerns/models/act_as_quota_trackable.rb +23 -0
  58. data/lib/concerns/models/act_as_quotable.rb +19 -0
  59. data/lib/resource_quotable/engine.rb +13 -0
  60. data/lib/resource_quotable/exeptions.rb +9 -0
  61. data/lib/resource_quotable/generators/views_generator.rb +18 -0
  62. data/lib/resource_quotable/helper.rb +27 -0
  63. data/lib/resource_quotable/version.rb +5 -0
  64. data/lib/resource_quotable.rb +68 -0
  65. data/lib/tasks/resource_quotable_tasks.rake +5 -0
  66. metadata +322 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8ebb826f39ace180d8f32e12d12ae50ab90a8b2deefe5f19e156810a5ea99636
4
+ data.tar.gz: cd2009f815c64a62f51a03a3977a0bfc5d53acbacfe91da5d839b2007e74ee27
5
+ SHA512:
6
+ metadata.gz: ba541c1da670b1d167bc313399e32c63cfb3858a37072d3ea169a368f1b5e11a813d2c0f5f6e13054afbc6bae72727d5c067fa570c53bafc8108f734fddbbf25
7
+ data.tar.gz: 6896c4c58ed19679d083243c3cead8419684d73703c50eb52ab634fb78f0a21047e4668a804e3c2be0e0c3a9005169abdda8a7ab3dd945beead747e9a67d042c
data/Changelog.md ADDED
@@ -0,0 +1,17 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/).
6
+
7
+ ## [0.2.0] (unreleased)
8
+ ### Changed
9
+ - Change Quota system to allow user group configuration.
10
+
11
+ ## [0.1.0] (1/9/22)
12
+ ### Changed
13
+ - Quota system by user. (alpha version available in branch `by_user`)
14
+
15
+ ## [0.0.0] (4/8/22)
16
+ ### Changed
17
+ - Initial repo creation.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022
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.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
6
+ load 'rails/tasks/engine.rake'
7
+
8
+ load 'rails/tasks/statistics.rake'
9
+
10
+ require 'bundler/gem_tasks'
11
+
12
+ require 'rspec/core'
13
+ require 'rspec/core/rake_task'
14
+
15
+ desc 'Run all specs in spec directory (excluding plugin specs)'
16
+ RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
17
+
18
+ task default: :spec
data/Readme.md ADDED
@@ -0,0 +1,206 @@
1
+ # ResourceQuotable
2
+ A Rails quota limit gem for resources. UNDER DEVELOPMENT
3
+
4
+ ## Installation
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'resource_quotable'
9
+ ```
10
+
11
+ And then execute:
12
+ ```bash
13
+ $ bundle install
14
+ ```
15
+
16
+ Install migrations:
17
+ ```bash
18
+ $ rails resource_quotable:install:migrations
19
+ $ rails db:migrate
20
+ ```
21
+
22
+ Mount engine:
23
+ ```ruby
24
+ # config/routes.rb
25
+ Rails.application.routes.draw do
26
+ # ...
27
+ mount ResourceQuotable::Engine => '/resource_quotable'
28
+ # ...
29
+ end
30
+
31
+ ```
32
+
33
+ Configure:
34
+ ```ruby
35
+ # config/initializers/resource_quotable.rb
36
+
37
+ ResourceQuotable.setup do |config|
38
+
39
+ ##
40
+ # Mandatory settings
41
+ #
42
+ # Resources to track quota.
43
+ # format: Array of strings. Could be anything.
44
+ #
45
+ config.resources = %w[ResourceA ResourceB NotModel]
46
+
47
+ ##
48
+ # Optional settings
49
+
50
+ # Method to access group form user instance.
51
+ # default: 'group'
52
+ config.group_method = 'user_group'
53
+
54
+ # Method to access users form group instance.
55
+ # default: 'users'
56
+ config.users_method = 'admin_users'
57
+
58
+ # main_content ID for rendering.
59
+ # default: 'resource_quotable_content'
60
+ config.main_content = 'resource_quotable_content'
61
+
62
+ # Base controller.
63
+ # default: '::ApplicationController'
64
+ config.base_controller = '::ApplicationController'
65
+
66
+ # Actions
67
+ # Default [:create,:update, :destroy]
68
+ config.actions = {
69
+ create: 0,
70
+ update: 1,
71
+ destroy: 2,
72
+ send: 3
73
+ }.freeze
74
+
75
+ end
76
+ ```
77
+
78
+ Attach Quotable to model.
79
+
80
+ ```ruby
81
+ class User < ApplicationRecord
82
+ acts_as_quota_trackable
83
+ # ....
84
+ belongs_to :group
85
+ # ....
86
+ end
87
+
88
+ class Group < ApplicationRecord
89
+ acts_as_quotable
90
+ # ....
91
+ has_many :users, dependent: :destroy
92
+ # ....
93
+ end
94
+ ```
95
+
96
+ ## Usage
97
+
98
+ ```erb
99
+ <% if allowed_to? :create, 'Post' %>
100
+ <%= link_to "New", new_post_path %>
101
+ <% end %>
102
+ ```
103
+
104
+ ```ruby
105
+ class PostController < ApplicationController
106
+ # ...
107
+
108
+ def new
109
+ quota_authorize! :create, 'Post'
110
+ # ...
111
+ end
112
+
113
+ def create
114
+ quota_increment! :create, 'Post'
115
+ # ...
116
+ end
117
+
118
+ # ...
119
+ end
120
+ ```
121
+
122
+ ## Customizations
123
+
124
+ Customize views
125
+
126
+ `rails g resource_quotable:views`
127
+
128
+ Customize Controllers
129
+
130
+ ```ruby
131
+ class ApplicationController < ActionController::Base
132
+ # ...
133
+
134
+ # Customize how to get the current user model to track
135
+ # default: current_user
136
+ def load_quotable_tracker_user
137
+ # ...
138
+ end
139
+
140
+ # Customize how to retrieve the group model
141
+ # default: quotum_params[:group_type].constantize.find(quotum_params[:group_id])
142
+ def load_quotable_group
143
+ # ...
144
+ end
145
+
146
+ # Customize if the current_user can access to the quota management interface
147
+ # default: true
148
+ def allowed_to_manage_quota?
149
+ # ...
150
+ end
151
+
152
+ # Customize How Quotum model are retrieve/filter. Useful for scopes
153
+ # default: Quotum
154
+ def quota_scoped
155
+ # ...
156
+ end
157
+
158
+ # hook before every action
159
+ # default: nil
160
+ def resource_quotable_before
161
+ # ...
162
+ end
163
+
164
+ # hook after every action
165
+ # default: nil
166
+ def resource_quotable_after
167
+ # ...
168
+ end
169
+
170
+ # ...
171
+ end
172
+ ```
173
+
174
+ ## API
175
+
176
+ Still Working on this doc....
177
+
178
+ API is exposed as a services layer.
179
+
180
+ ```ruby
181
+
182
+ # Check quota for 20 actions on resource for this user
183
+ ResourceQuotable::ActionServices::CheckMultiple.call(user: user, resource: 'ResourceX', action: :create, amount: 20)
184
+ # Increment 20 quota for actions on resource for this user
185
+ ResourceQuotable::ActionServices::IncrementMultiple.call(user: user, resource: 'ResourceX', action: :create, amount: 20)
186
+
187
+ # Reset. Probably a good idea to have a cron job that call this.
188
+ ResourceQuotable::Reset::Any.call
189
+ ResourceQuotable::Reset::Yearly.call
190
+ ResourceQuotable::Reset::Monthly.call
191
+ ResourceQuotable::Reset::Weekly.call
192
+ ResourceQuotable::Reset::Daily.call
193
+ ```
194
+
195
+ ## Contributing
196
+
197
+ ```bash
198
+ $ docker-sync start
199
+ $ docker-compose build
200
+ $ docker-compose run web bundle install
201
+ $ docker-compose run web bundle rails db:setup
202
+ $ docker-compose run web bundle rspec
203
+ ```
204
+
205
+ ## License
206
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/resource_quotable .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ class ApplicationController < ResourceQuotable.base_controller # :nodoc:
5
+ protected
6
+
7
+ def default_load_quotable_group
8
+ quotum_params[:group_type].constantize.find(quotum_params[:group_id])
9
+ end
10
+
11
+ def check_authorization
12
+ raise ResourceQuotable::AuthorizationError unless allowed_to_manage_quota?
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ class QuotaController < ResourceQuotable::ApplicationController # :nodoc:
5
+ layout ResourceQuotable.layout
6
+
7
+ before_action :check_authorization
8
+ before_action :load_quotum, only: %i[show edit update destroy]
9
+
10
+ def index
11
+ resource_quotable_before
12
+ @page = params[:page] || 1
13
+ @per_page = params[:per_page] || 5
14
+
15
+ @quota = quota_scoped.page(@page).per(@per_page)
16
+ resource_quotable_after
17
+ end
18
+
19
+ def show
20
+ resource_quotable_before
21
+ @quotum_trackers = @quotum.quotum_trackers.page(@page).per(@per_page)
22
+ resource_quotable_after
23
+ end
24
+
25
+ def new
26
+ resource_quotable_before
27
+ @quotum = Quotum.new
28
+ resource_quotable_after
29
+ end
30
+
31
+ def create
32
+ resource_quotable_before
33
+ @quotum = ResourceQuotable::Create.call(
34
+ group: load_quotable_group || default_load_quotable_group,
35
+ resource: quotum_params[:resource_class],
36
+ action: quotum_params[:action].to_sym,
37
+ period: quotum_params[:period].to_sym,
38
+ limit: quotum_params[:limit].to_i
39
+ )
40
+ resource_quotable_after
41
+ respond_to do |format|
42
+ format.html do
43
+ flash[:notice] = 'Quotum created'
44
+ redirect_to action: :index
45
+ end
46
+ format.js
47
+ end
48
+ end
49
+
50
+ def edit
51
+ resource_quotable_before
52
+ resource_quotable_after
53
+ end
54
+
55
+ def update
56
+ resource_quotable_before
57
+ @quotum = ResourceQuotable::Update.call(
58
+ quotum: @quotum,
59
+ limit: quotum_edit_params[:limit].to_i
60
+ )
61
+ resource_quotable_after
62
+ respond_to do |format|
63
+ format.html do
64
+ flash[:notice] = 'Quotum updated'
65
+ redirect_to action: :show, id: @quotum.id
66
+ end
67
+ format.js
68
+ end
69
+ end
70
+
71
+ def destroy
72
+ resource_quotable_before
73
+ @id = @quotum.id
74
+ ResourceQuotable::Destroy.call(quotum: @quotum)
75
+ resource_quotable_after
76
+ respond_to do |format|
77
+ format.html do
78
+ flash[:notice] = 'Quotum deleted'
79
+ redirect_to action: :index
80
+ end
81
+ format.js
82
+ end
83
+ end
84
+
85
+ protected
86
+
87
+ def quotum_params
88
+ params.require(:quotum).permit(
89
+ :period,
90
+ :limit,
91
+ :resource_class,
92
+ :action,
93
+ :group_id,
94
+ :group_type
95
+ )
96
+ end
97
+
98
+ def quotum_edit_params
99
+ params.require(:quotum).permit(:limit)
100
+ end
101
+
102
+ def load_quotum
103
+ @quotum = quota_scoped.find(params[:id])
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ class QuotumTrackersController < ResourceQuotable::ApplicationController # :nodoc:
5
+ layout ResourceQuotable.layout
6
+
7
+ before_action :check_authorization
8
+
9
+ def reset
10
+ resource_quotable_before
11
+
12
+ @quotum_tracker = ResourceQuotable::QuotumTrackerServices::Reset.call(quotum_tracker: load_quotum_tracker)
13
+
14
+ resource_quotable_after
15
+ end
16
+
17
+ protected
18
+
19
+ def load_quotum_tracker
20
+ QuotumTracker.find(params[:id])
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ class ApplicationRecord < ActiveRecord::Base # :nodoc:
5
+ self.abstract_class = true
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: resource_quotable_quota
4
+ #
5
+ # id :integer not null, primary key
6
+ # action :integer default("create"), not null
7
+ # group_type :string not null
8
+ # limit :integer default(1), not null
9
+ # period :integer default("any"), not null
10
+ # resource_class :string not null
11
+ # created_at :datetime
12
+ # updated_at :datetime
13
+ # group_id :integer not null
14
+ #
15
+ # Indexes
16
+ #
17
+ # index_resource_quotable_quota_on_group_id (group_id)
18
+ # resource_quotable_quota_unique_index (group_id,resource_class,action,period) UNIQUE
19
+ #
20
+
21
+ # frozen_string_literal: true
22
+
23
+ module ResourceQuotable
24
+ class Quotum < ApplicationRecord # :nodoc:
25
+ belongs_to :group, polymorphic: true, inverse_of: :quota
26
+ has_many :quotum_trackers, dependent: :destroy
27
+
28
+ scope :for_resource_action, ->(resource, action) { where(action: action, resource_class: resource) }
29
+
30
+ validates :resource_class, :action, :period, :limit, presence: true
31
+
32
+ enum action: ResourceQuotable.actions, _suffix: true
33
+
34
+ enum period: {
35
+ any: 0,
36
+ daily: 1,
37
+ weekly: 2,
38
+ monthly: 3,
39
+ yearly: 4
40
+ }, _suffix: true
41
+
42
+ def to_s
43
+ "#{period.to_s.capitalize} #{action} #{resource_class}."
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,60 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: resource_quotable_quotum_trackers
4
+ #
5
+ # id :integer not null, primary key
6
+ # counter :integer default(0), not null
7
+ # flag :boolean default(FALSE), not null
8
+ # user_type :string not null
9
+ # quotum_id :integer not null
10
+ # user_id :integer not null
11
+ #
12
+ # Indexes
13
+ #
14
+ # index_resource_quotable_quotum_trackers_on_quotum_id (quotum_id)
15
+ # index_resource_quotable_quotum_trackers_on_user_id (user_id)
16
+ # resource_quotable_quotum_trackers_unique_index (user_id,quotum_id) UNIQUE
17
+ #
18
+
19
+ # frozen_string_literal: true
20
+
21
+ module ResourceQuotable
22
+ # Flag is true when the quota has been reached.
23
+ class QuotumTracker < ApplicationRecord
24
+ belongs_to :quotum
25
+ belongs_to :user, polymorphic: true, inverse_of: :quotum_trackers
26
+
27
+ validates :counter, presence: true
28
+
29
+ scope :with_active_counter, -> { where('counter > 0') }
30
+ scope :for_user, ->(user) { where(user: user) }
31
+ scope :under_limit, ->(limit_to_check_against) { where('counter < ?', limit_to_check_against) }
32
+ scope :over_limit, ->(limit_to_check_against) { where('counter >= ?', limit_to_check_against) }
33
+ scope :flagged, -> { where(flag: true) }
34
+ scope :not_flagged, -> { where(flag: false) }
35
+
36
+ delegate :action, :resource_class, :limit, :period, to: :quotum
37
+
38
+ def increment!
39
+ raise ResourceQuotable::QuotaLimitError if flag
40
+
41
+ new_counter = counter + 1
42
+ update(counter: new_counter, flag: (new_counter >= limit))
43
+ end
44
+
45
+ def increment_by!(amount)
46
+ new_counter = counter + amount
47
+ raise ResourceQuotable::QuotaMultiLimitError if new_counter > limit
48
+
49
+ update(counter: new_counter, flag: (new_counter >= limit))
50
+ end
51
+
52
+ def reset!
53
+ return if counter.zero?
54
+
55
+ self.counter = 0
56
+ self.flag = (counter >= limit)
57
+ save
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ module ActionServices
5
+ # Check Resource#action Quota for a user.
6
+ # return false if it is ok.
7
+ # return true if it is blocked
8
+ class Base < ResourceQuotable::Base
9
+ attr_accessor :user, :action, :resource
10
+
11
+ validates :user, :resource, presence: true
12
+ validates_inclusion_of :action, in: ResourceQuotable.actions.keys
13
+
14
+ protected
15
+
16
+ def find_or_create_quotum_tracker(quotum)
17
+ quotum_tracker = quotum.quotum_trackers.find_by(user: user)
18
+ quotum_tracker ||= user.quotum_trackers.create!(quotum: quotum, counter: 0, flag: !quotum.limit.positive?)
19
+ quotum_tracker
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ module ActionServices
5
+ # Check Resource#action Quota for a user.
6
+ # return false if it is ok.
7
+ # return true if it is blocked
8
+ class Check < Base
9
+ def call
10
+ user.quota_for_resource_action(resource, action).each do |quotum|
11
+ quotum_tracker = find_or_create_quotum_tracker(quotum)
12
+
13
+ return true if quotum_tracker.flag?
14
+ end
15
+ false
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ module ActionServices
5
+ # Check Resource#action Quota for a user.
6
+ # return false if it is ok.
7
+ # return true if it is blocked
8
+ class CheckMultiple < Base
9
+ attr_accessor :amount
10
+
11
+ validates :amount, presence: true
12
+
13
+ def call
14
+ user.quota_for_resource_action(resource, action).each do |quotum|
15
+ quotum_tracker = find_or_create_quotum_tracker(quotum)
16
+
17
+ return true if quotum_tracker.counter + amount > quotum.limit
18
+ end
19
+ false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ module ActionServices
5
+ # Increment Resource#action Quota counter for a user.
6
+ class Increment < Base
7
+ def call
8
+ ResourceQuotable::Quotum.transaction do
9
+ user.quota_for_resource_action(resource, action).each do |quotum|
10
+ quotum_tracker = find_or_create_quotum_tracker(quotum)
11
+
12
+ quotum_tracker.increment!
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ module ActionServices
5
+ # Increment Resource#action Quota counter for a user.
6
+ class IncrementMultiple < Base
7
+ attr_accessor :amount
8
+
9
+ validates :amount, presence: true
10
+
11
+ def call
12
+ ResourceQuotable::Quotum.transaction do
13
+ user.quota_for_resource_action(resource, action).each do |quotum|
14
+ quotum_tracker = find_or_create_quotum_tracker(quotum)
15
+
16
+ quotum_tracker.increment_by!(amount)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourceQuotable
4
+ class Base # :nodoc:
5
+ include ActiveModel::Validations
6
+
7
+ def initialize(args = {})
8
+ args.each do |k, v|
9
+ instance_variable_set("@#{k}", v) unless v.nil?
10
+ end
11
+ end
12
+
13
+ def self.call(args = {})
14
+ service = new(args)
15
+ raise ArgumentError, service.errors.full_messages.join(', ') if service.invalid?
16
+
17
+ service.call
18
+ end
19
+
20
+ def call
21
+ raise ResourceQuotable::AbstractClassError
22
+ end
23
+ end
24
+ end