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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec6db270266a93bc862ae7d6e669a788a37ff69d7a66e196f678deda237b850b
4
- data.tar.gz: ba8486a5c62ae126fa3454acb018a3d3f2ff22957ce889a7d28658f3aa47a7f2
3
+ metadata.gz: 762b84bd5b5d458091d881a7227c7680048e1ae206e4eef1e6d94246e7be238b
4
+ data.tar.gz: e5358a64b012b93ffbc7a2f67c21e5179df2d7a7a5581771c1ee97c2466b20e9
5
5
  SHA512:
6
- metadata.gz: 76b5393e91af23e8b1feabd4ec36a5b6b520212705bcd69d0c70278c2b22251682b5deb20b6ec1fc2dd7b18be0898aa46c80b977f395b2a40103086a0342c477
7
- data.tar.gz: 0cd00659819ad2f62d5d4068a61a24dc699ff87a3bf773cddc0009345c7a8e9eab8c931fb797c105b31620286892098c676d82c05f52b5e9ccb6ccbda1453d3c
6
+ metadata.gz: ecf2eb80621fdce1e6d137dc6d5122fe66db21d893349a86e75d1e4251f73dd120eb6cc3e7f2d899b461a118a20dee7e4fa60ed919819a15204a4787fcde7ca2
7
+ data.tar.gz: 2389d6ea2996feeeae34a3256ca89037f5d2b0acf658d6e02345d349b5e44712870fd32ed3e7e3421dcd37a1068be3aa83ecba5e74cf221ad312f4797659ca88
@@ -2,7 +2,7 @@ module Nexo
2
2
  class BaseJob < ActiveJob::Base
3
3
  def self.limits_concurrency(*)
4
4
  # TODO: implementar
5
- puts "ERROR: Implementar limits_concurrency"
5
+ Rails.logger.error "ERROR: Implementar limits_concurrency"
6
6
  end
7
7
  end
8
8
  end
@@ -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
- queries.each do |query|
10
- # TODO: avoid calling more than once per synchronizable
11
- query.find_each do |synchronizable|
12
- folder_service.find_element_and_sync(folder, synchronizable)
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.all
13
-
14
- scope.each do |folder|
15
- folder_service.find_element_and_sync(folder, synchronizable)
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
 
@@ -1,6 +1,3 @@
1
- require "googleauth"
2
- require "google-apis-oauth2_v2"
3
-
4
1
  module Nexo
5
2
  # This is actually an OAuth 2.0 flow, and that logic should be extracted to
6
3
  # a generic OAuth2Service
@@ -1,5 +1,3 @@
1
- require "google-apis-calendar_v3"
2
-
3
1
  module Nexo
4
2
  # Wrapper around +Google::Apis::CalendarV3+
5
3
  #
@@ -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 folder_policy_changed(folder_policy)
28
- FolderSyncJob.perform_later(folder_policy.folder)
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
@@ -40,11 +40,6 @@ module Nexo
40
40
  folder:
41
41
  )
42
42
 
43
- if synchronizable.sequence.nil?
44
- # TODO: whats the use of having this and also in EventReceiver?
45
- synchronizable.initialize_values!
46
- end
47
-
48
43
  SyncElementJob.perform_later(element)
49
44
  end
50
45
  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(protocol_methods).any?
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.
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Table name: nexo_clients
4
4
  #
5
- # id :integer not null, primary key
5
+ # id :bigint not null, primary key
6
6
  # service :integer
7
7
  # secret :string
8
8
  # tcp_status :integer
@@ -2,8 +2,8 @@
2
2
  #
3
3
  # Table name: nexo_elements
4
4
  #
5
- # id :integer not null, primary key
6
- # folder_id :integer not null
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
@@ -2,8 +2,8 @@
2
2
  #
3
3
  # Table name: nexo_element_versions
4
4
  #
5
- # id :integer not null, primary key
6
- # element_id :integer not null
5
+ # id :bigint not null, primary key
6
+ # element_id :bigint not null
7
7
  # payload :string
8
8
  # etag :string
9
9
  # sequence :integer
@@ -2,12 +2,13 @@
2
2
  #
3
3
  # Table name: nexo_folders
4
4
  #
5
- # id :integer not null, primary key
6
- # integration_id :integer not null
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
- enum :protocol, calendar: 0, dummy_calendar: 1
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 :integer not null, primary key
6
- # user_id :integer not null
7
- # client_id :integer not null
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
@@ -2,8 +2,8 @@
2
2
  #
3
3
  # Table name: nexo_tokens
4
4
  #
5
- # id :integer not null, primary key
6
- # integration_id :integer not null
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
@@ -6,6 +6,7 @@ class CreateNexoFolders < ActiveRecord::Migration[7.2]
6
6
  t.string :external_identifier
7
7
  t.string :name
8
8
  t.string :description
9
+ t.datetime :discarded_at, index: true
9
10
 
10
11
  t.timestamps
11
12
  end
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
@@ -1,5 +1,5 @@
1
1
  # :nocov: non-viable
2
2
  module Nexo
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  # :nocov:
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.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-20 00:00:00.000000000 Z
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