discourse_subscription_client 0.1.0.pre1
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/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +10 -0
- data/app/assets/config/discourse_subscription_client_manifest.js +1 -0
- data/app/assets/stylesheets/discourse_subscription_client/application.css +15 -0
- data/app/controllers/discourse_subscription_client/admin_controller.rb +46 -0
- data/app/controllers/discourse_subscription_client/notices_controller.rb +82 -0
- data/app/controllers/discourse_subscription_client/subscriptions_controller.rb +17 -0
- data/app/controllers/discourse_subscription_client/suppliers_controller.rb +62 -0
- data/app/jobs/regular/discourse_subscription_client/find_resources.rb +9 -0
- data/app/jobs/scheduled/discourse_subscription_client/update_notices.rb +11 -0
- data/app/jobs/scheduled/discourse_subscription_client/update_subscriptions.rb +11 -0
- data/app/models/subscription_client_notice.rb +223 -0
- data/app/models/subscription_client_request.rb +4 -0
- data/app/models/subscription_client_resource.rb +27 -0
- data/app/models/subscription_client_subscription.rb +54 -0
- data/app/models/subscription_client_supplier.rb +54 -0
- data/app/serializers/discourse_subscription_client/notice_serializer.rb +52 -0
- data/app/serializers/discourse_subscription_client/resource_serializer.rb +8 -0
- data/app/serializers/discourse_subscription_client/subscription_serializer.rb +12 -0
- data/app/serializers/discourse_subscription_client/supplier_serializer.rb +16 -0
- data/config/locales/server.en.yml +40 -0
- data/config/routes.rb +19 -0
- data/config/settings.yml +16 -0
- data/db/migrate/20220318160955_create_subscription_client_suppliers.rb +17 -0
- data/db/migrate/20220318181029_create_subscription_client_resources.rb +14 -0
- data/db/migrate/20220318181054_create_subscription_client_notices.rb +22 -0
- data/db/migrate/20220318181140_create_subscription_client_subscriptions.rb +19 -0
- data/db/migrate/20230220130259_create_subscription_client_requests.rb +16 -0
- data/lib/discourse_subscription_client/authorization.rb +100 -0
- data/lib/discourse_subscription_client/engine.rb +97 -0
- data/lib/discourse_subscription_client/notices.rb +154 -0
- data/lib/discourse_subscription_client/request.rb +136 -0
- data/lib/discourse_subscription_client/resources.rb +97 -0
- data/lib/discourse_subscription_client/subscriptions/result.rb +118 -0
- data/lib/discourse_subscription_client/subscriptions.rb +93 -0
- data/lib/discourse_subscription_client/version.rb +5 -0
- data/lib/discourse_subscription_client.rb +8 -0
- metadata +252 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b7303b45879b410ec868c784e77786d7c9c4b864e6cf02b840ac9b62ae7c2a29
|
4
|
+
data.tar.gz: f5c231e658b1023df67810547b9a982d0fe54a57e7a65582fd751067a6def9b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 31fe492137483fbb3ca7ead97f0ad583aa6b3f7a8a2fd57456776b57f767cd5c31ed897c85b2ed8ec35178996b75176a8f01eb584a304d693482f135e06a44ff
|
7
|
+
data.tar.gz: c6474026b3db22c4ab8de05f8e21d286a0140c4b638e504642a2c501bcd9efee0983539baf023c4f40d2902abbf5c11d90e1c608b8d4fcda8dbf9d3d53b1c352
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2023 Angus McLeod
|
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/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# DiscourseSubscriptionClient
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "discourse_subscription_client"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install discourse_subscription_client
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/discourse_subscription_client .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,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiscourseSubscriptionClient
|
4
|
+
class AdminController < ApplicationController
|
5
|
+
requires_login
|
6
|
+
before_action :ensure_can_manage_subscriptions
|
7
|
+
|
8
|
+
def index
|
9
|
+
respond_to do |format|
|
10
|
+
format.html do
|
11
|
+
render :index
|
12
|
+
end
|
13
|
+
format.json do
|
14
|
+
render_json_dump(
|
15
|
+
authorized_supplier_count: SubscriptionClientSupplier.authorized.count,
|
16
|
+
resource_count: SubscriptionClientResource.count
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def ensure_can_manage_subscriptions
|
23
|
+
Guardian.new(current_user).ensure_can_manage_subscriptions!
|
24
|
+
end
|
25
|
+
|
26
|
+
def failed_json
|
27
|
+
{ failed: "FAILED" }
|
28
|
+
end
|
29
|
+
|
30
|
+
def success_json
|
31
|
+
{ success: "OK" }
|
32
|
+
end
|
33
|
+
|
34
|
+
def render_serialized(objects, serializer, opts = {})
|
35
|
+
render_json_dump(serialize_data(objects, serializer, opts))
|
36
|
+
end
|
37
|
+
|
38
|
+
def serialize_data(objects, serializer, opts = {})
|
39
|
+
ActiveModel::ArraySerializer.new(objects.to_a, opts.merge(each_serializer: serializer)).as_json
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_json_dump(json)
|
43
|
+
render json: json, status: 200
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiscourseSubscriptionClient
|
4
|
+
class NoticesController < AdminController
|
5
|
+
before_action :find_notice, only: %i[dismiss hide show]
|
6
|
+
|
7
|
+
def index
|
8
|
+
notice_type = params[:notice_type]
|
9
|
+
notice_subject_type = params[:notice_subject_type]
|
10
|
+
page = params[:page].to_i
|
11
|
+
|
12
|
+
visible = ActiveRecord::Type::Boolean.new.cast(params[:visible])
|
13
|
+
|
14
|
+
include_all = if current_user.admin
|
15
|
+
ActiveRecord::Type::Boolean.new.cast(params[:include_all])
|
16
|
+
else
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
if notice_type
|
21
|
+
notice_type = if notice_type.is_a?(Array)
|
22
|
+
notice_type.map { |t| SubscriptionClientNotice.types[t.to_sym] }
|
23
|
+
else
|
24
|
+
SubscriptionClientNotice.types[notice_type.to_sym]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if notice_subject_type
|
29
|
+
notice_subject_type = if notice_subject_type.is_a?(Array)
|
30
|
+
notice_subject_type.map { |t| SubscriptionClientNotice.notice_subject_types[t.to_sym] }
|
31
|
+
else
|
32
|
+
SubscriptionClientNotice.notice_subject_types[notice_subject_type.to_sym]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
notices = SubscriptionClientNotice.list(
|
37
|
+
include_all: include_all,
|
38
|
+
page: page,
|
39
|
+
notice_type: notice_type,
|
40
|
+
notice_subject_type: notice_subject_type,
|
41
|
+
visible: visible
|
42
|
+
)
|
43
|
+
|
44
|
+
render_json_dump(
|
45
|
+
notices: serialize_data(notices, NoticeSerializer),
|
46
|
+
hidden_notice_count: SubscriptionClientNotice.hidden.count
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def dismiss
|
51
|
+
if @notice.dismissable? && @notice.dismiss!
|
52
|
+
render json: success_json.merge(dismissed_at: @notice.dismissed_at)
|
53
|
+
else
|
54
|
+
render json: failed_json
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def show
|
59
|
+
if @notice.hidden? && @notice.show!
|
60
|
+
render json: success_json
|
61
|
+
else
|
62
|
+
render json: failed_json
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def hide
|
67
|
+
if @notice.can_hide? && @notice.hide!
|
68
|
+
render json: success_json.merge(hidden_at: @notice.hidden_at)
|
69
|
+
else
|
70
|
+
render json: failed_json
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def find_notice
|
77
|
+
params.require(:notice_id)
|
78
|
+
@notice = SubscriptionClientNotice.find(params[:notice_id])
|
79
|
+
raise Discourse::InvalidParameters, :notice_id unless @notice
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiscourseSubscriptionClient
|
4
|
+
class SubscriptionsController < AdminController
|
5
|
+
def index
|
6
|
+
render_serialized(SubscriptionClientSubscription.all, SubscriptionSerializer, root: "subscriptions")
|
7
|
+
end
|
8
|
+
|
9
|
+
def update
|
10
|
+
if DiscourseSubscriptionClient::Subscriptions.update
|
11
|
+
render_serialized(SubscriptionClientSubscription.all, SubscriptionSerializer, root: "subscriptions")
|
12
|
+
else
|
13
|
+
render json: failed_json
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiscourseSubscriptionClient
|
4
|
+
class SuppliersController < AdminController
|
5
|
+
before_action :ensure_can_manage_suppliers
|
6
|
+
skip_before_action :check_xhr, :preload_json, :verify_authenticity_token, only: %i[authorize authorize_callback]
|
7
|
+
before_action :find_supplier, only: %i[authorize destroy]
|
8
|
+
|
9
|
+
def index
|
10
|
+
render_serialized(SubscriptionClientSupplier.all, SupplierSerializer, root: "suppliers")
|
11
|
+
end
|
12
|
+
|
13
|
+
def authorize
|
14
|
+
request_id = DiscourseSubscriptionClient::Authorization.request_id(@supplier.id)
|
15
|
+
cookies[:user_api_request_id] = request_id
|
16
|
+
redirect_to DiscourseSubscriptionClient::Authorization.url(current_user, @supplier, request_id).to_s,
|
17
|
+
allow_other_host: true
|
18
|
+
end
|
19
|
+
|
20
|
+
def authorize_callback
|
21
|
+
payload = params[:payload]
|
22
|
+
request_id = cookies[:user_api_request_id]
|
23
|
+
supplier_id = request_id.split("-").first
|
24
|
+
|
25
|
+
data = DiscourseSubscriptionClient::Authorization.process_response(request_id, payload)
|
26
|
+
raise Discourse::InvalidParameters, :payload unless data
|
27
|
+
|
28
|
+
supplier = SubscriptionClientSupplier.find(supplier_id)
|
29
|
+
raise Discourse::InvalidParameters, :supplier_id unless supplier
|
30
|
+
|
31
|
+
supplier.update(
|
32
|
+
api_key: data[:key],
|
33
|
+
user_id: data[:user_id],
|
34
|
+
authorized_at: DateTime.now.iso8601(3)
|
35
|
+
)
|
36
|
+
|
37
|
+
DiscourseSubscriptionClient::Subscriptions.update
|
38
|
+
|
39
|
+
redirect_to "/admin/plugins/subscription-client/subscriptions"
|
40
|
+
end
|
41
|
+
|
42
|
+
def destroy
|
43
|
+
if @supplier.destroy_authorization
|
44
|
+
render json: success_json.merge(supplier: @supplier.reload)
|
45
|
+
else
|
46
|
+
render json: failed_json
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def find_supplier
|
53
|
+
params.require(:supplier_id)
|
54
|
+
@supplier = SubscriptionClientSupplier.find(params[:supplier_id])
|
55
|
+
raise Discourse::InvalidParameters, :supplier_id unless @supplier
|
56
|
+
end
|
57
|
+
|
58
|
+
def ensure_can_manage_suppliers
|
59
|
+
Guardian.new(current_user).ensure_can_manage_suppliers!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SubscriptionClientNotice < ActiveRecord::Base
|
4
|
+
belongs_to :notice_subject, polymorphic: true
|
5
|
+
delegate :name, to: :subject
|
6
|
+
|
7
|
+
scope :warnings, -> { where(notice_type: SubscriptionClientNotice.types[:warning]) }
|
8
|
+
scope :hidden, -> { where("hidden_at IS NOT NULL AND dismissed_at IS NULL AND expired_at IS NULL") }
|
9
|
+
|
10
|
+
def self.types
|
11
|
+
@types ||= {
|
12
|
+
info: 0,
|
13
|
+
warning: 1,
|
14
|
+
connection_error: 2
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.notice_subject_types
|
19
|
+
@notice_subject_types ||= {
|
20
|
+
resource: "SubscriptionClientResource",
|
21
|
+
supplier: "SubscriptionClientSupplier"
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.error_types
|
26
|
+
@error_types ||= [
|
27
|
+
types[:connection_error],
|
28
|
+
types[:warning]
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def supplier
|
33
|
+
if supplier?
|
34
|
+
notice_subject
|
35
|
+
elsif resource?
|
36
|
+
notice_subject.supplier
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def resource
|
41
|
+
return unless resource?
|
42
|
+
|
43
|
+
notice_subject
|
44
|
+
end
|
45
|
+
|
46
|
+
def supplier?
|
47
|
+
notice_subject_type === self.class.notice_subject_types[:supplier]
|
48
|
+
end
|
49
|
+
|
50
|
+
def resource?
|
51
|
+
notice_subject_type === self.class.notice_subject_types[:resource] && !plugin_status_resource?
|
52
|
+
end
|
53
|
+
|
54
|
+
def plugin_status_resource?
|
55
|
+
DiscourseSubscriptionClient::Notices::PLUGIN_STATUS_RESOURCE_ID === notice_subject_id
|
56
|
+
end
|
57
|
+
|
58
|
+
def dismiss!
|
59
|
+
return unless dismissable?
|
60
|
+
|
61
|
+
self.dismissed_at = DateTime.now.iso8601(3)
|
62
|
+
save_and_publish
|
63
|
+
end
|
64
|
+
|
65
|
+
def hide!
|
66
|
+
if can_hide?
|
67
|
+
self.hidden_at = DateTime.now.iso8601(3)
|
68
|
+
save_and_publish
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def show!
|
75
|
+
if hidden?
|
76
|
+
self.hidden_at = nil
|
77
|
+
save_and_publish
|
78
|
+
else
|
79
|
+
false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def expire!
|
84
|
+
if !expired?
|
85
|
+
self.expired_at = DateTime.now.iso8601(3)
|
86
|
+
save_and_publish
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def save_and_publish
|
93
|
+
if save
|
94
|
+
self.class.publish_notice_count
|
95
|
+
else
|
96
|
+
false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def can_hide?
|
101
|
+
!hidden? && self.class.error_types.include?(notice_type) && (
|
102
|
+
notice_subject_type === self.class.notice_subject_types[:resource]
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def expired?
|
107
|
+
expired_at.present?
|
108
|
+
end
|
109
|
+
|
110
|
+
def dismissed?
|
111
|
+
dismissed_at.present?
|
112
|
+
end
|
113
|
+
|
114
|
+
def dismissable?
|
115
|
+
!expired? && !dismissed? && notice_type === self.class.types[:info]
|
116
|
+
end
|
117
|
+
|
118
|
+
def hidden?
|
119
|
+
hidden_at.present?
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.publish_notice_count
|
123
|
+
payload = {
|
124
|
+
visible_notice_count: list(visible: true).count
|
125
|
+
}
|
126
|
+
group_id_key = SiteSetting.subscription_client_allow_moderator_subscription_management ? :staff : :admins
|
127
|
+
MessageBus.publish("/subscription_client_user", payload, group_ids: [Group::AUTO_GROUPS[group_id_key.to_sym]])
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.list(notice_type: nil, notice_subject_type: nil, notice_subject_id: nil, title: nil, include_all: false, visible: false, page: nil, page_limit: 30)
|
131
|
+
query = SubscriptionClientNotice.all
|
132
|
+
query = query.where("hidden_at IS NULL") if visible && !include_all
|
133
|
+
query = query.where("dismissed_at IS NULL") unless include_all
|
134
|
+
query = query.where("expired_at IS NULL") unless include_all
|
135
|
+
query = query.where("notice_subject_type = ?", notice_subject_type.to_s) if notice_subject_type
|
136
|
+
query = query.where("notice_subject_id = ?", notice_subject_id.to_i) if notice_subject_id
|
137
|
+
if notice_type
|
138
|
+
type_query_str = notice_type.is_a?(Array) ? "notice_type IN (?)" : "notice_type = ?"
|
139
|
+
query = query.where(type_query_str, notice_type)
|
140
|
+
end
|
141
|
+
query = query.where("title = ?", title) if title
|
142
|
+
query = query.limit(page_limit).offset(page.to_i * page_limit) unless page.nil?
|
143
|
+
query.order("expired_at DESC, updated_at DESC, dismissed_at DESC, created_at DESC")
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.notify_connection_error(notice_subject_type_key, notice_subject_id)
|
147
|
+
notice_subject_type = notice_subject_types[notice_subject_type_key.to_sym]
|
148
|
+
return false unless notice_subject_type
|
149
|
+
|
150
|
+
notices = list(
|
151
|
+
notice_type: types[:connection_error],
|
152
|
+
notice_subject_type: notice_subject_type,
|
153
|
+
notice_subject_id: notice_subject_id
|
154
|
+
)
|
155
|
+
if notices.any?
|
156
|
+
notice = notices.first
|
157
|
+
notice.updated_at = DateTime.now.iso8601(3)
|
158
|
+
notice.save
|
159
|
+
else
|
160
|
+
opts = {}
|
161
|
+
if notice_subject_type === notice_subject_types[:supplier]
|
162
|
+
supplier = SubscriptionClientSupplier.find(notice_subject_id)
|
163
|
+
opts[:supplier] = supplier.name
|
164
|
+
end
|
165
|
+
create!(
|
166
|
+
title: I18n.t("subscription_client.notices.#{notice_subject_type_key}.connection_error.title", **opts),
|
167
|
+
message: I18n.t("subscription_client.notices.#{notice_subject_type_key}.connection_error.message", **opts),
|
168
|
+
notice_subject_type: notice_subject_type,
|
169
|
+
notice_subject_id: notice_subject_id,
|
170
|
+
notice_type: types[:connection_error],
|
171
|
+
created_at: DateTime.now.iso8601(3),
|
172
|
+
updated_at: DateTime.now.iso8601(3)
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.expire_connection_error(notice_subject_type_key, notice_subject_id)
|
178
|
+
expired_count = expire_all(types[:connection_error], notice_subject_types[notice_subject_type_key.to_sym],
|
179
|
+
notice_subject_id)
|
180
|
+
publish_notice_count if expired_count.to_i.positive?
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.dismiss_all
|
184
|
+
where("
|
185
|
+
notice_type = #{types[:info]} AND
|
186
|
+
expired_at IS NULL AND
|
187
|
+
dismissed_at IS NULL
|
188
|
+
").update_all("dismissed_at = now()")
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.expire_all(notice_type, notice_subject_type, notice_subject_id)
|
192
|
+
where("
|
193
|
+
notice_type = #{notice_type} AND
|
194
|
+
notice_subject_type = '#{notice_subject_type}' AND
|
195
|
+
notice_subject_id = #{notice_subject_id} AND
|
196
|
+
expired_at IS NULL
|
197
|
+
").update_all("expired_at = now()")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# == Schema Information
|
202
|
+
#
|
203
|
+
# Table name: subscription_client_notices
|
204
|
+
#
|
205
|
+
# id :bigint not null, primary key
|
206
|
+
# title :string not null
|
207
|
+
# message :string
|
208
|
+
# notice_type :integer not null
|
209
|
+
# notice_subject_type :string
|
210
|
+
# notice_subject_id :bigint
|
211
|
+
# changed_at :datetime
|
212
|
+
# retrieved_at :datetime
|
213
|
+
# dismissed_at :datetime
|
214
|
+
# expired_at :datetime
|
215
|
+
# hidden_at :datetime
|
216
|
+
# created_at :datetime not null
|
217
|
+
# updated_at :datetime not null
|
218
|
+
#
|
219
|
+
# Indexes
|
220
|
+
#
|
221
|
+
# index_subscription_client_notices_on_notice_subject (notice_subject_type,notice_subject_id)
|
222
|
+
# sc_unique_notices (notice_type,notice_subject_type,notice_subject_id,changed_at) UNIQUE
|
223
|
+
#
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SubscriptionClientResource < ActiveRecord::Base
|
4
|
+
belongs_to :supplier, class_name: "SubscriptionClientSupplier"
|
5
|
+
has_many :notices, class_name: "SubscriptionClientNotice", as: :notice_subject, dependent: :destroy
|
6
|
+
has_many :subscriptions, foreign_key: "resource_id", class_name: "SubscriptionClientSubscription", dependent: :destroy
|
7
|
+
end
|
8
|
+
|
9
|
+
# == Schema Information
|
10
|
+
#
|
11
|
+
# Table name: subscription_client_resources
|
12
|
+
#
|
13
|
+
# id :bigint not null, primary key
|
14
|
+
# supplier_id :bigint
|
15
|
+
# name :string not null
|
16
|
+
# created_at :datetime not null
|
17
|
+
# updated_at :datetime not null
|
18
|
+
#
|
19
|
+
# Indexes
|
20
|
+
#
|
21
|
+
# index_subscription_client_resources_on_supplier_id (supplier_id)
|
22
|
+
# index_subscription_client_resources_on_supplier_id_and_name (supplier_id,name) UNIQUE
|
23
|
+
#
|
24
|
+
# Foreign Keys
|
25
|
+
#
|
26
|
+
# fk_rails_... (supplier_id => subscription_client_suppliers.id)
|
27
|
+
#
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SubscriptionClientSubscription < ActiveRecord::Base
|
4
|
+
validates :product_id, presence: true, uniqueness: { scope: :price_id }
|
5
|
+
validates :price_id, presence: true
|
6
|
+
|
7
|
+
belongs_to :resource, class_name: "SubscriptionClientResource"
|
8
|
+
|
9
|
+
scope :active, -> { where("subscribed = true AND updated_at > ?", SubscriptionClientSubscription.update_period) }
|
10
|
+
|
11
|
+
def active
|
12
|
+
subscribed && updated_at.to_datetime > self.class.update_period.to_datetime
|
13
|
+
end
|
14
|
+
|
15
|
+
def deactivate!
|
16
|
+
update(subscribed: false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def resource_name
|
20
|
+
resource.name
|
21
|
+
end
|
22
|
+
|
23
|
+
def supplier_name
|
24
|
+
resource.supplier.name
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.update_period
|
28
|
+
Time.zone.now - 2.days
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# == Schema Information
|
33
|
+
#
|
34
|
+
# Table name: subscription_client_subscriptions
|
35
|
+
#
|
36
|
+
# id :bigint not null, primary key
|
37
|
+
# resource_id :bigint
|
38
|
+
# product_id :string not null
|
39
|
+
# product_name :string
|
40
|
+
# price_id :string not null
|
41
|
+
# price_name :string
|
42
|
+
# subscribed :boolean default(FALSE), not null
|
43
|
+
# created_at :datetime not null
|
44
|
+
# updated_at :datetime not null
|
45
|
+
#
|
46
|
+
# Indexes
|
47
|
+
#
|
48
|
+
# index_subscription_client_subscriptions_on_resource_id (resource_id)
|
49
|
+
# sc_unique_subscriptions (resource_id,product_id,price_id) UNIQUE
|
50
|
+
#
|
51
|
+
# Foreign Keys
|
52
|
+
#
|
53
|
+
# fk_rails_... (resource_id => subscription_client_resources.id)
|
54
|
+
#
|