bns 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/._.rspec_status +0 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -0
- data/README.md +159 -3
- data/lib/bns/dispatcher/discord/exceptions/invalid_webhook_token.rb +2 -2
- data/lib/bns/dispatcher/discord/implementation.rb +1 -1
- data/lib/bns/dispatcher/slack/exceptions/invalid_webhook_token.rb +16 -0
- data/lib/bns/dispatcher/slack/implementation.rb +51 -0
- data/lib/bns/dispatcher/slack/types/response.rb +21 -0
- data/lib/bns/domain/work_items_limit.rb +39 -0
- data/lib/bns/fetcher/base.rb +13 -0
- data/lib/bns/fetcher/notion/{pto.rb → base.rb} +11 -7
- data/lib/bns/fetcher/notion/types/response.rb +1 -1
- data/lib/bns/fetcher/notion/use_case/birthday_next_week.rb +41 -0
- data/lib/bns/fetcher/notion/use_case/birthday_today.rb +29 -0
- data/lib/bns/fetcher/notion/use_case/pto_next_week.rb +71 -0
- data/lib/bns/fetcher/notion/use_case/pto_today.rb +30 -0
- data/lib/bns/fetcher/notion/use_case/work_items_limit.rb +37 -0
- data/lib/bns/fetcher/postgres/base.rb +46 -0
- data/lib/bns/fetcher/postgres/helper.rb +16 -0
- data/lib/bns/fetcher/postgres/types/response.rb +42 -0
- data/lib/bns/fetcher/postgres/use_case/pto_today.rb +32 -0
- data/lib/bns/formatter/base.rb +11 -8
- data/lib/bns/formatter/birthday.rb +34 -0
- data/lib/bns/formatter/exceptions/invalid_data.rb +15 -0
- data/lib/bns/formatter/pto.rb +76 -0
- data/lib/bns/formatter/work_items_limit.rb +43 -0
- data/lib/bns/mapper/notion/{birthday.rb → birthday_today.rb} +13 -21
- data/lib/bns/mapper/notion/{pto.rb → pto_today.rb} +15 -41
- data/lib/bns/mapper/notion/work_items_limit.rb +65 -0
- data/lib/bns/mapper/postgres/pto_today.rb +47 -0
- data/lib/bns/use_cases/use_cases.rb +227 -49
- data/lib/bns/version.rb +1 -1
- metadata +25 -9
- data/lib/bns/fetcher/notion/birthday.rb +0 -53
- data/lib/bns/formatter/discord/birthday.rb +0 -36
- data/lib/bns/formatter/discord/exceptions/invalid_data.rb +0 -17
- data/lib/bns/formatter/discord/pto.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f27d7368a358fcf6dea96e51922690ff399670b5582387b70f56db0d5b25feb
|
4
|
+
data.tar.gz: a46adf0a088dd65740c85aadc5d3005654f3654e2f12cecf345700be7f44f2b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfa9c1394d5fe161f90fe86e29a44acace8b2a7809ee8bd233ee12d0be082b11a0081e3fb98efefcdfe22c64a50f27335a95ac24f9c8baeec10c5a9f8d381754
|
7
|
+
data.tar.gz: a13978067c0c9ad5a96c8abc8ae2f7781674a0f4b3accc9b2229a11dde525f706a52ee448effad8570c34b2141a5e9c3ad0a3457f29dea2f5d60d42c6ba7bd4e
|
data/._.rspec_status
ADDED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.2.0 (29.02.2024)
|
4
|
+
- [Add a Postgres fetcher component](https://github.com/kommitters/bns/issues/28)
|
5
|
+
- [Use case - PTO's Postgres-Slack implementation](https://github.com/kommitters/bns/issues/30)
|
6
|
+
- [Slack dispatcher](https://github.com/kommitters/bns/issues/32)
|
7
|
+
- [Refactor fetcher components](https://github.com/kommitters/bns/issues/34)
|
8
|
+
- [Add Use Case - Boards WI alerts](https://github.com/kommitters/bns/issues/36)
|
9
|
+
- [Add Use Case - Next Week Birthday](https://github.com/kommitters/bns/issues/38)
|
10
|
+
- [Add Use Case - Next Week PTO's](https://github.com/kommitters/bns/issues/39)
|
11
|
+
|
3
12
|
## 0.1.1 (07.02.2024)
|
4
13
|
- [Add custom templates option](https://github.com/kommitters/bns/issues/25)
|
5
14
|
- [PTO's formatting use cases](https://github.com/kommitters/bns/issues/24)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# BNS - Business Notification System
|
2
2
|
|
3
|
-
|
3
|
+
Many organizations and individuals rely on automatic notifications across various contexts in their daily operations. With BNS, we aim to provide an open-source platform that empowers users to create customized notification systems tailored to their unique requirements. BNS consists of a series of abstract components designed to facilitate the creation of diverse use cases, regardless of context.
|
4
|
+
|
5
|
+
The underlying idea is to develop generic components that can serve a wide range of needs, this approach ensures that all members of the community can leverage the platform's evolving suite of components and use cases to their advantage.
|
4
6
|
|
5
7
|
![Gem Version](https://img.shields.io/gem/v/bns?style=for-the-badge)
|
6
8
|
![Gem Total Downloads](https://img.shields.io/gem/dt/bns?style=for-the-badge)
|
@@ -150,9 +152,163 @@ use_case.perform
|
|
150
152
|
|
151
153
|
```
|
152
154
|
|
153
|
-
|
155
|
+
### Serverless
|
156
|
+
We'll explain how to configure and deploy a use case with serverless, this example will cover the PTO's notifications use case.
|
157
|
+
|
158
|
+
#### Configuring environment variables
|
159
|
+
Create the environment variables configuration file.
|
160
|
+
|
161
|
+
```bash
|
162
|
+
cp env.yml.example env.yml
|
163
|
+
```
|
154
164
|
|
155
|
-
|
165
|
+
And put the following env variables
|
166
|
+
```
|
167
|
+
dev:
|
168
|
+
NOTION_DATABASE_ID: NOTION_DATABASE_ID
|
169
|
+
NOTION_SECRET: NOTION_SECRET
|
170
|
+
DISCORD_WEBHOOK: DISCORD_WEBHOOK
|
171
|
+
DISCORD_BOT_NAME: DISCORD_BOT_NAME
|
172
|
+
prod:
|
173
|
+
NOTION_DATABASE_ID: NOTION_DATABASE_ID
|
174
|
+
NOTION_SECRET: NOTION_SECRET
|
175
|
+
DISCORD_WEBHOOK: DISCORD_WEBHOOK
|
176
|
+
DISCORD_BOT_NAME: DISCORD_BOT_NAME
|
177
|
+
|
178
|
+
```
|
179
|
+
|
180
|
+
The variables should be defined either in the custom settings section within the `serverless.yml` file to ensure accessibility by all lambdas, or in the environment configuration option for each lambda respectively. For example:
|
181
|
+
|
182
|
+
```bash
|
183
|
+
# Accessible by all the lambdas
|
184
|
+
custom:
|
185
|
+
settings:
|
186
|
+
api:
|
187
|
+
NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.NOTION_DATABASE_ID}
|
188
|
+
NOTION_SECRET: ${file(./env.yml):${env:STAGE}.NOTION_SECRET}}
|
189
|
+
|
190
|
+
# Accessible by the lambda
|
191
|
+
functions:
|
192
|
+
lambdaName:
|
193
|
+
environment:
|
194
|
+
NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.NOTION_DATABASE_ID}
|
195
|
+
NOTION_SECRET: ${file(./env.yml):${env:STAGE}.NOTION_SECRET}}
|
196
|
+
```
|
197
|
+
|
198
|
+
#### Schedule
|
199
|
+
the schedule is configured using an environment variable containing the cron configuration. For example:
|
200
|
+
```bash
|
201
|
+
# env.yml file
|
202
|
+
SCHEDULER: cron(0 13 ? * MON-FRI *)
|
203
|
+
|
204
|
+
# serverless.yml
|
205
|
+
functions:
|
206
|
+
lambdaName:
|
207
|
+
events:
|
208
|
+
- schedule:
|
209
|
+
rate: ${file(./env.yml):${env:STAGE}.SCHEDULER}
|
210
|
+
```
|
211
|
+
|
212
|
+
To learn how to modify the cron configuration follow this guide: [Schedule expressions using rate or cron](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html)
|
213
|
+
|
214
|
+
#### Building your lambda
|
215
|
+
On your serverless configuration, create your lambda function, on your serverless `/src` folder.
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# frozen_string_literal: true
|
219
|
+
|
220
|
+
require 'bns'
|
221
|
+
|
222
|
+
# Initialize the environment variables
|
223
|
+
NOTION_BASE_URL = 'https://api.notion.com'
|
224
|
+
NOTION_DATABASE_ID = ENV.fetch('PTO_NOTION_DATABASE_ID')
|
225
|
+
NOTION_SECRET = ENV.fetch('PTO_NOTION_SECRET')
|
226
|
+
DISCORD_WEBHOOK = ENV.fetch('PTO_DISCORD_WEBHOOK')
|
227
|
+
DISCORD_BOT_NAME = ENV.fetch('PTO_DISCORD_BOT_NAME')
|
228
|
+
|
229
|
+
module Notifier
|
230
|
+
# Service description
|
231
|
+
class UseCaseName
|
232
|
+
def self.notify(*)
|
233
|
+
options = { fetch_options:, dispatch_options: }
|
234
|
+
|
235
|
+
begin
|
236
|
+
use_case = UseCases.use_case_build_function(options)
|
237
|
+
|
238
|
+
use_case.perform
|
239
|
+
rescue StandardError => e
|
240
|
+
{ body: { message: e.message } }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def self.fetch_options
|
245
|
+
{
|
246
|
+
base_url: NOTION_BASE_URL,
|
247
|
+
database_id: NOTION_DATABASE_ID,
|
248
|
+
secret: NOTION_SECRET,
|
249
|
+
filter: {
|
250
|
+
filter: { "and": fetch_filter }
|
251
|
+
}
|
252
|
+
}
|
253
|
+
end
|
254
|
+
|
255
|
+
def self.fetch_filter
|
256
|
+
today = Common::TimeZone.set_colombia_time_zone.strftime('%F').to_s
|
257
|
+
|
258
|
+
[
|
259
|
+
{ property: 'Desde?', date: { on_or_before: today } },
|
260
|
+
{ property: 'Hasta?', date: { on_or_after: today } }
|
261
|
+
]
|
262
|
+
end
|
263
|
+
|
264
|
+
def self.dispatch_options
|
265
|
+
{
|
266
|
+
webhook: DISCORD_WEBHOOK,
|
267
|
+
name: DISCORD_BOT_NAME
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
def self.format_options
|
272
|
+
{
|
273
|
+
template: ':beach: individual_name is on PTO'
|
274
|
+
}
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
```
|
279
|
+
|
280
|
+
#### Configure the lambda
|
281
|
+
In the `serverless.yml` file, add a new instance in the `functions` block with this structure:
|
282
|
+
|
283
|
+
```bash
|
284
|
+
functions:
|
285
|
+
ptoNotification:
|
286
|
+
handler: src/lambdas/pto_notification.Notifier::PTO.notify
|
287
|
+
environment:
|
288
|
+
PTO_NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.PTO_NOTION_DATABASE_ID}
|
289
|
+
PTO_NOTION_SECRET: ${file(./env.yml):${env:STAGE}.PTO_NOTION_SECRET}
|
290
|
+
PTO_DISCORD_WEBHOOK: ${file(./env.yml):${env:STAGE}.PTO_DISCORD_WEBHOOK}
|
291
|
+
PTO_DISCORD_BOT_NAME: ${file(./env.yml):${env:STAGE}.DISCORD_BOT_NAME}
|
292
|
+
events:
|
293
|
+
- schedule:
|
294
|
+
name: pto-daily-notification
|
295
|
+
description: "Notify every 24 hours at 8:30 a.m (UTC-5) from monday to friday"
|
296
|
+
rate: cron(${file(./env.yml):${env:STAGE}.PTO_SCHEDULER})
|
297
|
+
enabled: true
|
298
|
+
```
|
299
|
+
|
300
|
+
#### Deploying
|
301
|
+
|
302
|
+
Configure the AWS keys:
|
303
|
+
|
304
|
+
```bash
|
305
|
+
serverless config credentials --provider aws --key YOUR_KEY --secret YOUR_SECRET
|
306
|
+
```
|
307
|
+
|
308
|
+
Deploy the project:
|
309
|
+
```bash
|
310
|
+
STAGE=prod sls deploy --verbose
|
311
|
+
```
|
156
312
|
|
157
313
|
## Development
|
158
314
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dispatcher
|
4
|
+
module Slack
|
5
|
+
module Exceptions
|
6
|
+
##
|
7
|
+
# Domain specific representation when an invalid webhook token is provided to Slack.
|
8
|
+
#
|
9
|
+
class InvalidWebookToken < StandardError
|
10
|
+
def initialize(message = "The provided Webhook token is invalid.")
|
11
|
+
super(message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
require_relative "./exceptions/invalid_webhook_token"
|
5
|
+
require_relative "./types/response"
|
6
|
+
|
7
|
+
module Dispatcher
|
8
|
+
module Slack
|
9
|
+
##
|
10
|
+
# This class is an implementation of the Dispatcher::Base interface, specifically designed
|
11
|
+
# for dispatching messages to Slack.
|
12
|
+
#
|
13
|
+
class Implementation < Base
|
14
|
+
# Implements the dispatching logic for the Slack use case. It sends a POST request to
|
15
|
+
# the Slack webhook with the specified payload.
|
16
|
+
#
|
17
|
+
# <br>
|
18
|
+
# <b>Params:</b>
|
19
|
+
# * <tt>String</tt> payload: Payload to be dispatched to slack.
|
20
|
+
# <br>
|
21
|
+
# <b>raises</b> <tt>Exceptions::Slack::InvalidWebookToken</tt> if the provided webhook token is invalid.
|
22
|
+
#
|
23
|
+
# <br>
|
24
|
+
# <b>returns</b> <tt>Dispatcher::Slack::Types::Response</tt>
|
25
|
+
#
|
26
|
+
def dispatch(payload)
|
27
|
+
body = {
|
28
|
+
username: name,
|
29
|
+
text: payload
|
30
|
+
}.to_json
|
31
|
+
|
32
|
+
response = HTTParty.post(webhook, { body: body, headers: { "Content-Type" => "application/json" } })
|
33
|
+
|
34
|
+
slack_response = Dispatcher::Discord::Types::Response.new(response)
|
35
|
+
|
36
|
+
validate_response(slack_response)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def validate_response(response)
|
42
|
+
case response.http_code
|
43
|
+
when 403
|
44
|
+
raise Dispatcher::Slack::Exceptions::InvalidWebookToken, response.message
|
45
|
+
else
|
46
|
+
response
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dispatcher
|
4
|
+
module Slack
|
5
|
+
module Types
|
6
|
+
##
|
7
|
+
# Represents a response received from Slack. It encapsulates essential information about the response,
|
8
|
+
# providing a structured way to handle and analyze Slack server responses.
|
9
|
+
#
|
10
|
+
class Response
|
11
|
+
attr_reader :body, :http_code, :message
|
12
|
+
|
13
|
+
def initialize(response)
|
14
|
+
@http_code = response.code
|
15
|
+
@message = response.message
|
16
|
+
@body = response.body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Domain
|
4
|
+
##
|
5
|
+
# The Domain::WorkItemsLimit class provides a domain-specific representation of a Work Item object.
|
6
|
+
# It encapsulates information about a work items limit, including the domain, total, and wip_limit.
|
7
|
+
#
|
8
|
+
class WorkItemsLimit
|
9
|
+
attr_reader :domain, :total, :wip_limit
|
10
|
+
|
11
|
+
ATTRIBUTES = %w[domain total wip_limit].freeze
|
12
|
+
|
13
|
+
# Initializes a Domain::WorkItemsLimit instance with the specified domain, total and wip_limit.
|
14
|
+
#
|
15
|
+
# <br>
|
16
|
+
# <b>Params:</b>
|
17
|
+
# * <tt>String</tt> 'domain' responsible domain of the work items.
|
18
|
+
# * <tt>String</tt> 'total' total 'in progress' work items.
|
19
|
+
# * <tt>String</tt> 'wip_limit' maximum 'in progress' work items for the domain
|
20
|
+
#
|
21
|
+
def initialize(domain, total)
|
22
|
+
@domain = domain
|
23
|
+
@total = total
|
24
|
+
@wip_limit = domain_wip_limit(domain)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def domain_wip_limit(domain)
|
30
|
+
case domain
|
31
|
+
when "kommit.ops" then 5
|
32
|
+
when "kommit.sales" then 3
|
33
|
+
when "kommit.marketing" then 4
|
34
|
+
when "kommit.engineering" then 12
|
35
|
+
else 6
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/bns/fetcher/base.rb
CHANGED
@@ -26,5 +26,18 @@ module Fetcher
|
|
26
26
|
def fetch
|
27
27
|
raise Domain::Exceptions::FunctionNotImplemented
|
28
28
|
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
# A method meant to execute the fetch request, retrieven the required data
|
33
|
+
# from an specific filter configuration depending on the use case implementation.
|
34
|
+
# Must be overridden by subclasses, with specific logic based on the use case.
|
35
|
+
#
|
36
|
+
# <br>
|
37
|
+
# <b>raises</b> <tt>Domain::Exceptions::FunctionNotImplemented</tt> when missing implementation.
|
38
|
+
#
|
39
|
+
def execute
|
40
|
+
raise Domain::Exceptions::FunctionNotImplemented
|
41
|
+
end
|
29
42
|
end
|
30
43
|
end
|
@@ -1,21 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "httparty"
|
4
|
-
require "date"
|
5
4
|
|
6
5
|
require_relative "../base"
|
7
6
|
require_relative "./exceptions/invalid_api_key"
|
8
7
|
require_relative "./exceptions/invalid_database_id"
|
9
8
|
require_relative "./types/response"
|
9
|
+
require_relative "./helper"
|
10
10
|
|
11
11
|
module Fetcher
|
12
12
|
module Notion
|
13
13
|
##
|
14
14
|
# This class is an implementation of the Fetcher::Base interface, specifically designed
|
15
|
-
# for fetching
|
15
|
+
# for fetching data from Notion.
|
16
16
|
#
|
17
|
-
class
|
18
|
-
|
17
|
+
class Base < Fetcher::Base
|
18
|
+
NOTION_BASE_URL = "https://api.notion.com"
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
# Implements the data fetching logic for data from Notion. It sends a POST
|
19
23
|
# request to the Notion API to query the specified database and returns a validated response.
|
20
24
|
#
|
21
25
|
# <br>
|
@@ -24,10 +28,10 @@ module Fetcher
|
|
24
28
|
# <b>raises</b> <tt>Exceptions::Notion::InvalidDatabaseId</tt> if the Database id provided is incorrect
|
25
29
|
# or invalid.
|
26
30
|
#
|
27
|
-
def
|
28
|
-
url = "#{
|
31
|
+
def execute(filter)
|
32
|
+
url = "#{NOTION_BASE_URL}/v1/databases/#{config[:database_id]}/query"
|
29
33
|
|
30
|
-
httparty_response = HTTParty.post(url, { body:
|
34
|
+
httparty_response = HTTParty.post(url, { body: filter.to_json, headers: headers })
|
31
35
|
|
32
36
|
notion_response = Fetcher::Notion::Types::Response.new(httparty_response)
|
33
37
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
module Notion
|
7
|
+
##
|
8
|
+
# This class is an implementation of the Fetcher::Notion::Base interface, specifically designed
|
9
|
+
# for fetching next week birthdays data from Notion.
|
10
|
+
#
|
11
|
+
class BirthdayNextWeek < Notion::Base
|
12
|
+
DAYS_BEFORE_NOTIFY = 8
|
13
|
+
|
14
|
+
# Implements the data fetching filter for next week Birthdays data from Notion.
|
15
|
+
#
|
16
|
+
def fetch
|
17
|
+
filter = {
|
18
|
+
filter: {
|
19
|
+
or: [
|
20
|
+
{ property: "BD_this_year", date: { equals: eight_days_from_now } }
|
21
|
+
]
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
execute(filter)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def eight_days_from_now
|
31
|
+
date = Time.now.utc + days_in_second(DAYS_BEFORE_NOTIFY)
|
32
|
+
|
33
|
+
date.utc.strftime("%F").to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def days_in_second(days)
|
37
|
+
days * 24 * 60 * 60
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
module Notion
|
7
|
+
##
|
8
|
+
# This class is an implementation of the Fetcher::Notion::Base interface, specifically designed
|
9
|
+
# for fetching birthday data from Notion.
|
10
|
+
#
|
11
|
+
class BirthdayToday < Notion::Base
|
12
|
+
# Implements the data fetching filter for todays Birthdays data from Notion.
|
13
|
+
#
|
14
|
+
def fetch
|
15
|
+
today = Time.now.utc.strftime("%F").to_s
|
16
|
+
|
17
|
+
filter = {
|
18
|
+
filter: {
|
19
|
+
or: [
|
20
|
+
{ property: "BD_this_year", date: { equals: today } }
|
21
|
+
]
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
execute(filter)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
module Notion
|
7
|
+
##
|
8
|
+
# This class is an implementation of the Fetcher::Notion::Base interface, specifically designed
|
9
|
+
# for fetching next week Paid Time Off (PTO) data from Notion.
|
10
|
+
#
|
11
|
+
class PtoNextWeek < Notion::Base
|
12
|
+
# Implements the data fetching filter for next week PTO's data from Notion.
|
13
|
+
#
|
14
|
+
def fetch
|
15
|
+
filter = build_filter
|
16
|
+
|
17
|
+
execute(filter)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def next_week_dates
|
23
|
+
monday = next_week_monday
|
24
|
+
sunday = monday + 6
|
25
|
+
|
26
|
+
[monday, sunday]
|
27
|
+
end
|
28
|
+
|
29
|
+
def next_week_monday
|
30
|
+
today = Date.today
|
31
|
+
week_day = today.wday
|
32
|
+
|
33
|
+
days = week_day.zero? ? 1 : 8 - week_day
|
34
|
+
|
35
|
+
today + days
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_filter
|
39
|
+
monday, sunday = next_week_dates
|
40
|
+
|
41
|
+
{
|
42
|
+
filter: {
|
43
|
+
or: [
|
44
|
+
belong_next_week("Desde?", monday, sunday),
|
45
|
+
belong_next_week("Hasta?", monday, sunday),
|
46
|
+
cover_next_week(monday, sunday)
|
47
|
+
]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def belong_next_week(property, after_day, before_day)
|
53
|
+
{
|
54
|
+
and: [
|
55
|
+
{ property: property, date: { on_or_after: after_day } },
|
56
|
+
{ property: property, date: { on_or_before: before_day } }
|
57
|
+
]
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def cover_next_week(monday, sunday)
|
62
|
+
{
|
63
|
+
and: [
|
64
|
+
{ property: "Hasta?", date: { on_or_after: sunday } },
|
65
|
+
{ property: "Desde?", date: { on_or_before: monday } }
|
66
|
+
]
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
module Notion
|
7
|
+
##
|
8
|
+
# This class is an implementation of the Fetcher::Notion::Base interface, specifically designed
|
9
|
+
# for fetching Paid Time Off (PTO) data from Notion.
|
10
|
+
#
|
11
|
+
class PtoToday < Notion::Base
|
12
|
+
# Implements the data fetching filter for todays PTO's data from Notion.
|
13
|
+
#
|
14
|
+
def fetch
|
15
|
+
today = Time.now.utc.strftime("%F").to_s
|
16
|
+
|
17
|
+
filter = {
|
18
|
+
filter: {
|
19
|
+
"and": [
|
20
|
+
{ property: "Desde?", date: { on_or_before: today } },
|
21
|
+
{ property: "Hasta?", date: { on_or_after: today } }
|
22
|
+
]
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
execute(filter)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Fetcher
|
6
|
+
module Notion
|
7
|
+
##
|
8
|
+
# This class is an implementation of the Fetcher::Notion::Base interface, specifically designed
|
9
|
+
# for counting "in progress" work items from work item database in Notion.
|
10
|
+
#
|
11
|
+
class WorkItemsLimit < Notion::Base
|
12
|
+
# Implements the data fetching count of "in progress" work items from Notion.
|
13
|
+
#
|
14
|
+
def fetch
|
15
|
+
filter = {
|
16
|
+
filter: {
|
17
|
+
"and": [
|
18
|
+
{ property: "OK", formula: { string: { contains: "✅" } } },
|
19
|
+
{ "or": status_conditions }
|
20
|
+
]
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
execute(filter)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def status_conditions
|
30
|
+
[
|
31
|
+
{ property: "Status", status: { equals: "In Progress" } },
|
32
|
+
{ property: "Status", status: { equals: "On Hold" } }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|