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.
- checksums.yaml +7 -0
- data/Changelog.md +17 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +18 -0
- data/Readme.md +206 -0
- data/app/assets/config/resource_quotable_manifest.js +1 -0
- data/app/assets/stylesheets/resource_quotable/application.css +15 -0
- data/app/controllers/resource_quotable/application_controller.rb +15 -0
- data/app/controllers/resource_quotable/quota_controller.rb +106 -0
- data/app/controllers/resource_quotable/quotum_trackers_controller.rb +23 -0
- data/app/models/resource_quotable/application_record.rb +7 -0
- data/app/models/resource_quotable/quotum.rb +46 -0
- data/app/models/resource_quotable/quotum_tracker.rb +60 -0
- data/app/services/resource_quotable/action_services/base.rb +23 -0
- data/app/services/resource_quotable/action_services/check.rb +19 -0
- data/app/services/resource_quotable/action_services/check_multiple.rb +23 -0
- data/app/services/resource_quotable/action_services/increment.rb +18 -0
- data/app/services/resource_quotable/action_services/increment_multiple.rb +22 -0
- data/app/services/resource_quotable/base.rb +24 -0
- data/app/services/resource_quotable/create.rb +29 -0
- data/app/services/resource_quotable/destroy.rb +14 -0
- data/app/services/resource_quotable/quotum_tracker_services/reset.rb +17 -0
- data/app/services/resource_quotable/reset/all.rb +16 -0
- data/app/services/resource_quotable/reset/any.rb +16 -0
- data/app/services/resource_quotable/reset/base.rb +22 -0
- data/app/services/resource_quotable/reset/daily.rb +16 -0
- data/app/services/resource_quotable/reset/monthly.rb +16 -0
- data/app/services/resource_quotable/reset/weekly.rb +16 -0
- data/app/services/resource_quotable/reset/yearly.rb +16 -0
- data/app/services/resource_quotable/update.rb +23 -0
- data/app/views/layouts/resource_quotable/application.html.erb +15 -0
- data/app/views/resource_quotable/quota/_edit.html.erb +11 -0
- data/app/views/resource_quotable/quota/_index.html.erb +43 -0
- data/app/views/resource_quotable/quota/_new.html.erb +34 -0
- data/app/views/resource_quotable/quota/_show.html.erb +41 -0
- data/app/views/resource_quotable/quota/create.js.erb +3 -0
- data/app/views/resource_quotable/quota/destroy.js.erb +3 -0
- data/app/views/resource_quotable/quota/edit.html.erb +1 -0
- data/app/views/resource_quotable/quota/edit.js.erb +1 -0
- data/app/views/resource_quotable/quota/index/_row.html.erb +3 -0
- data/app/views/resource_quotable/quota/index/_row_content.html.erb +43 -0
- data/app/views/resource_quotable/quota/index.html.erb +1 -0
- data/app/views/resource_quotable/quota/index.js.erb +1 -0
- data/app/views/resource_quotable/quota/new.html.erb +1 -0
- data/app/views/resource_quotable/quota/new.js.erb +1 -0
- data/app/views/resource_quotable/quota/show/_row.html.erb +3 -0
- data/app/views/resource_quotable/quota/show/_row_content.html.erb +7 -0
- data/app/views/resource_quotable/quota/show.html.erb +1 -0
- data/app/views/resource_quotable/quota/show.js.erb +1 -0
- data/app/views/resource_quotable/quota/update.js.erb +3 -0
- data/app/views/resource_quotable/quotum_trackers/index/_row_content.html.erb +8 -0
- data/app/views/resource_quotable/quotum_trackers/reset.js.erb +3 -0
- data/config/routes.rb +11 -0
- data/db/migrate/20220805102601_create_resource_quotable_quota.rb +17 -0
- data/db/migrate/20220811072023_create_resource_quotable_quotum_trackers.rb +18 -0
- data/lib/concerns/controllers/allowed_to_manage_quota_check.rb +73 -0
- data/lib/concerns/models/act_as_quota_trackable.rb +23 -0
- data/lib/concerns/models/act_as_quotable.rb +19 -0
- data/lib/resource_quotable/engine.rb +13 -0
- data/lib/resource_quotable/exeptions.rb +9 -0
- data/lib/resource_quotable/generators/views_generator.rb +18 -0
- data/lib/resource_quotable/helper.rb +27 -0
- data/lib/resource_quotable/version.rb +5 -0
- data/lib/resource_quotable.rb +68 -0
- data/lib/tasks/resource_quotable_tasks.rake +5 -0
- 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,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
|