nexo 0.1.1 → 0.1.2
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 +4 -4
- data/app/jobs/nexo/base_job.rb +1 -1
- data/app/jobs/nexo/folder_destroy_job.rb +10 -0
- data/app/jobs/nexo/folder_sync_job.rb +12 -4
- data/app/jobs/nexo/synchronizable_changed_job.rb +6 -4
- data/app/lib/nexo/api_client/google_auth_service.rb +0 -3
- data/app/lib/nexo/api_client/google_calendar_service.rb +0 -2
- data/app/lib/nexo/event_receiver.rb +9 -12
- data/app/lib/nexo/folder_service.rb +0 -5
- data/app/models/concerns/nexo/calendar_event.rb +9 -1
- data/app/models/concerns/nexo/synchronizable.rb +4 -4
- data/app/models/nexo/client.rb +1 -1
- data/app/models/nexo/element.rb +2 -2
- data/app/models/nexo/element_version.rb +2 -2
- data/app/models/nexo/folder.rb +18 -3
- data/app/models/nexo/integration.rb +3 -3
- data/app/models/nexo/token.rb +2 -2
- data/db/migrate/20250512025423_create_nexo_folders.rb +1 -0
- data/lib/nexo/engine.rb +11 -0
- data/lib/nexo/version.rb +1 -1
- metadata +3 -3
- data/db/migrate/20250519210346_create_good_jobs.rb +0 -104
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 762b84bd5b5d458091d881a7227c7680048e1ae206e4eef1e6d94246e7be238b
|
4
|
+
data.tar.gz: e5358a64b012b93ffbc7a2f67c21e5179df2d7a7a5581771c1ee97c2466b20e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecf2eb80621fdce1e6d137dc6d5122fe66db21d893349a86e75d1e4251f73dd120eb6cc3e7f2d899b461a118a20dee7e4fa60ed919819a15204a4787fcde7ca2
|
7
|
+
data.tar.gz: 2389d6ea2996feeeae34a3256ca89037f5d2b0acf658d6e02345d349b5e44712870fd32ed3e7e3421dcd37a1068be3aa83ecba5e74cf221ad312f4797659ca88
|
data/app/jobs/nexo/base_job.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Nexo
|
2
|
+
class FolderDestroyJob < BaseJob
|
3
|
+
def perform(folder)
|
4
|
+
if folder.external_identifier.present?
|
5
|
+
protocol_service = ServiceBuilder.instance.build_protocol_service(folder)
|
6
|
+
response = protocol_service.remove_calendar(folder)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,15 +1,23 @@
|
|
1
1
|
module Nexo
|
2
2
|
class FolderSyncJob < BaseJob
|
3
3
|
def perform(folder)
|
4
|
+
if folder.external_identifier.blank?
|
5
|
+
protocol_service = ServiceBuilder.instance.build_protocol_service(folder)
|
6
|
+
response = protocol_service.insert_calendar(folder)
|
7
|
+
folder.update(external_identifier: response.id)
|
8
|
+
end
|
9
|
+
|
4
10
|
policies = PolicyService.instance.policies_for(folder)
|
5
11
|
# flat_map should be equivalent to:
|
6
12
|
# policies.map(&:synchronizable_queries).flatten(1)
|
7
13
|
queries = policies.flat_map(&:synchronizable_queries)
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
15
|
+
GoodJob::Bulk.enqueue do
|
16
|
+
queries.each do |query|
|
17
|
+
# TODO: avoid calling more than once per synchronizable
|
18
|
+
query.find_each do |synchronizable|
|
19
|
+
folder_service.find_element_and_sync(folder, synchronizable)
|
20
|
+
end
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
@@ -9,10 +9,12 @@ module Nexo
|
|
9
9
|
|
10
10
|
def perform(synchronizable)
|
11
11
|
# Maybe restrict this query to a more specific scope
|
12
|
-
scope = Folder.
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
scope = Folder.kept
|
13
|
+
# TODO: test
|
14
|
+
GoodJob::Bulk.enqueue do
|
15
|
+
scope.each do |folder|
|
16
|
+
folder_service.find_element_and_sync(folder, synchronizable)
|
17
|
+
end
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
@@ -3,10 +3,6 @@ module Nexo
|
|
3
3
|
# be called when the system is notified of an external element change
|
4
4
|
class EventReceiver
|
5
5
|
def synchronizable_created(synchronizable)
|
6
|
-
validate_synchronizable_state!(synchronizable)
|
7
|
-
|
8
|
-
synchronizable.initialize_values!
|
9
|
-
|
10
6
|
SynchronizableChangedJob.perform_later(synchronizable)
|
11
7
|
end
|
12
8
|
|
@@ -24,8 +20,15 @@ module Nexo
|
|
24
20
|
folder_service.destroy_elements(synchronizable, :synchronizable_destroyed)
|
25
21
|
end
|
26
22
|
|
27
|
-
def
|
28
|
-
|
23
|
+
def folder_changed(folder)
|
24
|
+
if folder.discarded?
|
25
|
+
raise "folder discarded"
|
26
|
+
end
|
27
|
+
FolderSyncJob.perform_later(folder)
|
28
|
+
end
|
29
|
+
|
30
|
+
def folder_discarded(folder)
|
31
|
+
FolderDestroyJob.perform_later(folder)
|
29
32
|
end
|
30
33
|
|
31
34
|
private
|
@@ -35,11 +38,5 @@ module Nexo
|
|
35
38
|
@folder_service ||= FolderService.new
|
36
39
|
end
|
37
40
|
# :nocov:
|
38
|
-
|
39
|
-
def validate_synchronizable_state!(synchronizable)
|
40
|
-
unless synchronizable.sequence.nil?
|
41
|
-
raise Errors::InvalidSynchronizableState, "sequence is present: #{synchronizable.sequence}"
|
42
|
-
end
|
43
|
-
end
|
44
41
|
end
|
45
42
|
end
|
@@ -14,7 +14,15 @@ module Nexo
|
|
14
14
|
])
|
15
15
|
|
16
16
|
def change_is_significative_to_sequence?
|
17
|
-
previous_changes.keys.map(&:to_sym).intersection(
|
17
|
+
previous_changes.keys.map(&:to_sym).intersection(significative_columns).any?
|
18
|
+
end
|
19
|
+
|
20
|
+
# Model columns relevant to the sequence
|
21
|
+
#
|
22
|
+
# By default is equal to protocol_methods, but each concrete model class
|
23
|
+
# could have its own specific column names
|
24
|
+
def significative_columns
|
25
|
+
protocol_methods
|
18
26
|
end
|
19
27
|
|
20
28
|
def datetime_from
|
@@ -70,11 +70,11 @@ module Nexo
|
|
70
70
|
end
|
71
71
|
# :nocov:
|
72
72
|
|
73
|
-
def initialize_values!
|
74
|
-
update!(sequence: 0)
|
75
|
-
end
|
76
|
-
|
77
73
|
def increment_sequence!
|
74
|
+
if sequence.nil?
|
75
|
+
Rails.logger.warn("Synchronizable sequence is nil on increment_sequence!: #{self.to_gid}")
|
76
|
+
end
|
77
|
+
|
78
78
|
# This operation is performed directly in the database without the need
|
79
79
|
# to read the current value first. So, it is atomic at a database level,
|
80
80
|
# though the in-memory object consitency is subject to race conditions.
|
data/app/models/nexo/client.rb
CHANGED
data/app/models/nexo/element.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
#
|
3
3
|
# Table name: nexo_elements
|
4
4
|
#
|
5
|
-
# id :
|
6
|
-
# folder_id :
|
5
|
+
# id :bigint not null, primary key
|
6
|
+
# folder_id :bigint not null
|
7
7
|
# synchronizable_id :integer not null
|
8
8
|
# synchronizable_type :string not null
|
9
9
|
# uuid :string
|
data/app/models/nexo/folder.rb
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
#
|
3
3
|
# Table name: nexo_folders
|
4
4
|
#
|
5
|
-
# id :
|
6
|
-
# integration_id :
|
5
|
+
# id :bigint not null, primary key
|
6
|
+
# integration_id :bigint not null
|
7
7
|
# protocol :integer not null
|
8
8
|
# external_identifier :string
|
9
9
|
# name :string
|
10
10
|
# description :string
|
11
|
+
# discarded_at :datetime
|
11
12
|
# created_at :datetime not null
|
12
13
|
# updated_at :datetime not null
|
13
14
|
#
|
@@ -16,7 +17,13 @@ module Nexo
|
|
16
17
|
belongs_to :integration, class_name: "Nexo::Integration"
|
17
18
|
has_many :elements, class_name: "Nexo::Element"
|
18
19
|
|
19
|
-
|
20
|
+
if respond_to?(:enumerize)
|
21
|
+
enumerize :protocol, in: { calendar: 0, dummy_calendar: 1 }
|
22
|
+
else
|
23
|
+
enum :protocol, calendar: 0, dummy_calendar: 1
|
24
|
+
end
|
25
|
+
|
26
|
+
scope :kept, -> { where(discarded_at: nil) }
|
20
27
|
|
21
28
|
validates :protocol, :name, presence: true
|
22
29
|
|
@@ -39,5 +46,13 @@ module Nexo
|
|
39
46
|
def time_zone
|
40
47
|
Rails.application.config.time_zone
|
41
48
|
end
|
49
|
+
|
50
|
+
def discarded?
|
51
|
+
discarded_at.present?
|
52
|
+
end
|
53
|
+
|
54
|
+
def discard!
|
55
|
+
update!(discarded_at: Time.current)
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
#
|
3
3
|
# Table name: nexo_integrations
|
4
4
|
#
|
5
|
-
# id :
|
6
|
-
# user_id :
|
7
|
-
# client_id :
|
5
|
+
# id :bigint not null, primary key
|
6
|
+
# user_id :bigint not null
|
7
|
+
# client_id :bigint not null
|
8
8
|
# name :string
|
9
9
|
# scope :string
|
10
10
|
# expires_at :datetime
|
data/app/models/nexo/token.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
#
|
3
3
|
# Table name: nexo_tokens
|
4
4
|
#
|
5
|
-
# id :
|
6
|
-
# integration_id :
|
5
|
+
# id :bigint not null, primary key
|
6
|
+
# integration_id :bigint not null
|
7
7
|
# secret :string
|
8
8
|
# tpt_status :integer not null
|
9
9
|
# environment :string not null
|
data/lib/nexo/engine.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require "googleauth"
|
2
|
+
require "google-apis-oauth2_v2"
|
3
|
+
require "google-apis-calendar_v3"
|
4
|
+
|
1
5
|
module Nexo
|
2
6
|
def self.folder_policies
|
3
7
|
::Nexo::PolicyService.instance
|
@@ -14,6 +18,13 @@ module Nexo
|
|
14
18
|
Rails.autoloaders.main.collapse(dir)
|
15
19
|
end
|
16
20
|
|
21
|
+
initializer "nexo.setup_google_logger" do
|
22
|
+
Google::Apis.logger = ActiveSupport::Logger.new(Rails.root.join("log/google_apis.log"))
|
23
|
+
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
|
24
|
+
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
|
25
|
+
# .tap { |logger| logger.push_tags("FOO") }
|
26
|
+
end
|
27
|
+
|
17
28
|
initializer "configurar_generators" do
|
18
29
|
config.generators do |g|
|
19
30
|
g.test_framework :rspec
|
data/lib/nexo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martín Rosso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- app/jobs/nexo/api_clients.rb
|
81
81
|
- app/jobs/nexo/base_job.rb
|
82
82
|
- app/jobs/nexo/delete_remote_resource_job.rb
|
83
|
+
- app/jobs/nexo/folder_destroy_job.rb
|
83
84
|
- app/jobs/nexo/folder_sync_job.rb
|
84
85
|
- app/jobs/nexo/sync_element_job.rb
|
85
86
|
- app/jobs/nexo/synchronizable_changed_job.rb
|
@@ -112,7 +113,6 @@ files:
|
|
112
113
|
- db/migrate/20250512025423_create_nexo_folders.rb
|
113
114
|
- db/migrate/20250512025950_create_nexo_elements.rb
|
114
115
|
- db/migrate/20250512030530_create_nexo_element_versions.rb
|
115
|
-
- db/migrate/20250519210346_create_good_jobs.rb
|
116
116
|
- db/seeds.rb
|
117
117
|
- lib/nexo.rb
|
118
118
|
- lib/nexo/engine.rb
|
@@ -1,104 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class CreateGoodJobs < ActiveRecord::Migration[7.2]
|
4
|
-
def change
|
5
|
-
# Uncomment for Postgres v12 or earlier to enable gen_random_uuid() support
|
6
|
-
enable_extension 'pgcrypto'
|
7
|
-
|
8
|
-
create_table :good_jobs, id: :uuid do |t|
|
9
|
-
t.text :queue_name
|
10
|
-
t.integer :priority
|
11
|
-
t.jsonb :serialized_params
|
12
|
-
t.datetime :scheduled_at
|
13
|
-
t.datetime :performed_at
|
14
|
-
t.datetime :finished_at
|
15
|
-
t.text :error
|
16
|
-
|
17
|
-
t.timestamps
|
18
|
-
|
19
|
-
t.uuid :active_job_id
|
20
|
-
t.text :concurrency_key
|
21
|
-
t.text :cron_key
|
22
|
-
t.uuid :retried_good_job_id
|
23
|
-
t.datetime :cron_at
|
24
|
-
|
25
|
-
t.uuid :batch_id
|
26
|
-
t.uuid :batch_callback_id
|
27
|
-
|
28
|
-
t.boolean :is_discrete
|
29
|
-
t.integer :executions_count
|
30
|
-
t.text :job_class
|
31
|
-
t.integer :error_event, limit: 2
|
32
|
-
t.text :labels, array: true
|
33
|
-
t.uuid :locked_by_id
|
34
|
-
t.datetime :locked_at
|
35
|
-
end
|
36
|
-
|
37
|
-
create_table :good_job_batches, id: :uuid do |t|
|
38
|
-
t.timestamps
|
39
|
-
t.text :description
|
40
|
-
t.jsonb :serialized_properties
|
41
|
-
t.text :on_finish
|
42
|
-
t.text :on_success
|
43
|
-
t.text :on_discard
|
44
|
-
t.text :callback_queue_name
|
45
|
-
t.integer :callback_priority
|
46
|
-
t.datetime :enqueued_at
|
47
|
-
t.datetime :discarded_at
|
48
|
-
t.datetime :finished_at
|
49
|
-
t.datetime :jobs_finished_at
|
50
|
-
end
|
51
|
-
|
52
|
-
create_table :good_job_executions, id: :uuid do |t|
|
53
|
-
t.timestamps
|
54
|
-
|
55
|
-
t.uuid :active_job_id, null: false
|
56
|
-
t.text :job_class
|
57
|
-
t.text :queue_name
|
58
|
-
t.jsonb :serialized_params
|
59
|
-
t.datetime :scheduled_at
|
60
|
-
t.datetime :finished_at
|
61
|
-
t.text :error
|
62
|
-
t.integer :error_event, limit: 2
|
63
|
-
t.text :error_backtrace, array: true
|
64
|
-
t.uuid :process_id
|
65
|
-
t.interval :duration
|
66
|
-
end
|
67
|
-
|
68
|
-
create_table :good_job_processes, id: :uuid do |t|
|
69
|
-
t.timestamps
|
70
|
-
t.jsonb :state
|
71
|
-
t.integer :lock_type, limit: 2
|
72
|
-
end
|
73
|
-
|
74
|
-
create_table :good_job_settings, id: :uuid do |t|
|
75
|
-
t.timestamps
|
76
|
-
t.text :key
|
77
|
-
t.jsonb :value
|
78
|
-
t.index :key, unique: true
|
79
|
-
end
|
80
|
-
|
81
|
-
add_index :good_jobs, :scheduled_at, where: "(finished_at IS NULL)", name: :index_good_jobs_on_scheduled_at
|
82
|
-
add_index :good_jobs, [:queue_name, :scheduled_at], where: "(finished_at IS NULL)", name: :index_good_jobs_on_queue_name_and_scheduled_at
|
83
|
-
add_index :good_jobs, [:active_job_id, :created_at], name: :index_good_jobs_on_active_job_id_and_created_at
|
84
|
-
add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished
|
85
|
-
add_index :good_jobs, [:concurrency_key, :created_at], name: :index_good_jobs_on_concurrency_key_and_created_at
|
86
|
-
add_index :good_jobs, [:cron_key, :created_at], where: "(cron_key IS NOT NULL)", name: :index_good_jobs_on_cron_key_and_created_at_cond
|
87
|
-
add_index :good_jobs, [:cron_key, :cron_at], where: "(cron_key IS NOT NULL)", unique: true, name: :index_good_jobs_on_cron_key_and_cron_at_cond
|
88
|
-
add_index :good_jobs, [:finished_at], where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at
|
89
|
-
add_index :good_jobs, [:priority, :created_at], order: { priority: "DESC NULLS LAST", created_at: :asc },
|
90
|
-
where: "finished_at IS NULL", name: :index_good_jobs_jobs_on_priority_created_at_when_unfinished
|
91
|
-
add_index :good_jobs, [:priority, :created_at], order: { priority: "ASC NULLS LAST", created_at: :asc },
|
92
|
-
where: "finished_at IS NULL", name: :index_good_job_jobs_for_candidate_lookup
|
93
|
-
add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL"
|
94
|
-
add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL"
|
95
|
-
add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)", name: :index_good_jobs_on_labels
|
96
|
-
|
97
|
-
add_index :good_job_executions, [:active_job_id, :created_at], name: :index_good_job_executions_on_active_job_id_and_created_at
|
98
|
-
add_index :good_jobs, [:priority, :scheduled_at], order: { priority: "ASC NULLS LAST", scheduled_at: :asc },
|
99
|
-
where: "finished_at IS NULL AND locked_by_id IS NULL", name: :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked
|
100
|
-
add_index :good_jobs, :locked_by_id,
|
101
|
-
where: "locked_by_id IS NOT NULL", name: "index_good_jobs_on_locked_by_id"
|
102
|
-
add_index :good_job_executions, [:process_id, :created_at], name: :index_good_job_executions_on_process_id_and_created_at
|
103
|
-
end
|
104
|
-
end
|