perilune 0.1.0 → 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: fb116ba6c86f1c24f6981261f9c69335e2b152c1167708c411c41a408dd43893
4
- data.tar.gz: ad39ec022a048edde5c3e18df3e3e62dd5eb75a117ce8a5103dab4c4516876ae
3
+ metadata.gz: 2667aa181ff8f8d006a2bb84243f6d187cf1ce489f610e0a2f95cb2799556c84
4
+ data.tar.gz: f745164223c3bd6a7ce9bab71932f3ca8e0d4b014386f4eedb914bb1ee929df0
5
5
  SHA512:
6
- metadata.gz: 70f2a6f2fcf043f114818939c498fd85a14e183dd78bd3bdb91a2a32608ad94a5fea982c193b912e82530b9f66c95005ca662ca493370265e822d70146d65851
7
- data.tar.gz: c271e506ffd1642a4de1f11e2e81c7abcdbe7566d285e3b67bcee169b52491e67a9c48514b4c1ae8170440c4404faa41bd4af7decd3db48c44727f48c2ebc9a9
6
+ metadata.gz: 6dcf35402e3fafbd90f6a52f2cfc810889de1761e91b485fa3c0cefa5ea4a2416c9bf918f1a4778067d4e55c239b25f3516dd646741a209a27d38a8e7a41a0c9
7
+ data.tar.gz: 47181255a66a80ce2d4f8cdeddb72ee08dd15b5bb4a83a5aad6a7613e858bb791d5427acb9bb2cdff33168e45e9eb2abc8ce85f7e07aaa5fecbfaebf10382aa8
data/README.md CHANGED
@@ -21,6 +21,31 @@ Or install it yourself as:
21
21
  $ gem install perilune
22
22
  ```
23
23
 
24
+ ## Configuration
25
+ You can use diffrent queue name for cron job:
26
+
27
+ ```ruby
28
+ # frozen_string_literal: true
29
+
30
+ Perilune.configure do |config|
31
+ config.queue_name = 'test'
32
+ end
33
+
34
+ ```
35
+
36
+ > Note - Perilune is using *default* as queue name.
37
+
38
+ Perilune using Redis as defualt driver for Trifle Stats. You can configure the driver for Trifle::Stats:
39
+
40
+ ```ruby
41
+ Perilune.configure do |config|
42
+ config.stat_driver = Trifle::Stats::Driver::Postgres.new(
43
+ ActiveRecord::Base.connection.instance_variable_get('@connection')
44
+ )
45
+ end
46
+ ```
47
+ You can find more driver [here](https://trifle.io/docs/stats/drivers/)
48
+
24
49
  ## Contributing
25
50
  Contribution directions go here.
26
51
 
@@ -3,13 +3,14 @@
3
3
  module Perilune
4
4
  module Tasks
5
5
  class ExecutorJob < ApplicationJob
6
- queue_as :default
6
+ queue_as Perilune.default.queue_name
7
7
 
8
8
  class UndefinedTaskKlass < StandardError; end
9
9
 
10
10
  def perform(task_id)
11
11
  @task_id = task_id
12
12
  executor.execute
13
+ track_stats(event: task.task_type, success: executor.success?)
13
14
  executor.success? ? success : failure
14
15
  end
15
16
 
@@ -32,6 +33,16 @@ module Perilune
32
33
 
33
34
  @executor ||= task.task_klass.constantize.new(file: task.file.download, task: task)
34
35
  end
36
+
37
+ def track_stats(event:, success:)
38
+ count_hash = success ? { count: 1, success: 1 } : { count: 1, failure: 1 }
39
+ inner_hash = { event.downcase.intern => count_hash }
40
+ Trifle::Stats.track(
41
+ key: "perilune::#{event.downcase}", at: Time.zone.now,
42
+ config: Perilune.default.stats_driver_config,
43
+ values: count_hash.merge(inner_hash)
44
+ )
45
+ end
35
46
  end
36
47
  end
37
48
  end
@@ -4,10 +4,13 @@ module Perilune
4
4
  class Task < ApplicationRecord
5
5
  self.table_name = 'perilune_tasks'
6
6
  validates :state, inclusion: {
7
- in: %w[draft uploaded processed failed],
7
+ in: %w[draft started processing processed failed],
8
8
  message: '%<value>s is not a valid state'
9
9
  }
10
10
  validates :task_klass, presence: true
11
+
12
+ before_save :update_state_timestamp, if: :state_change_to_be_saved
13
+
11
14
  has_one_attached :file
12
15
 
13
16
  def file_name
@@ -19,5 +22,11 @@ module Perilune
19
22
  rescue StandardError
20
23
  nil
21
24
  end
25
+
26
+ private
27
+
28
+ def update_state_timestamp
29
+ send("#{state}_at=", Time.now) if respond_to?("#{state}_at")
30
+ end
22
31
  end
23
32
  end
@@ -29,6 +29,7 @@ module Perilune
29
29
  @task ||= Perilune::Task.new(
30
30
  state: 'draft',
31
31
  task_klass: params[:task_klass],
32
+ task_type: 'Export',
32
33
  attrs: params[:attrs],
33
34
  tags: params[:tags]
34
35
  )
@@ -2,6 +2,10 @@
2
2
 
3
3
  module Perilune
4
4
  module Tasks
5
- class FindOperation < LedgerSync::Domains::Operation::Find; end
5
+ class FindOperation < LedgerSync::Domains::Operation::Find
6
+ def serializer_for(*)
7
+ Perilune::Tasks::Serializer.new
8
+ end
9
+ end
6
10
  end
7
11
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ module Imports
6
+ class CreateOperation
7
+ include LedgerSync::Domains::Operation::Mixin
8
+
9
+ class Contract < LedgerSync::Ledgers::Contract
10
+ params do
11
+ required(:file).maybe(type?: File)
12
+ required(:file).maybe(type?: Tempfile)
13
+ required(:task_klass).filled(:string)
14
+ optional(:tags).filled(:array)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def operate
21
+ attach!
22
+ if task.save
23
+ Perilune::Tasks::ExecutorJob.perform_later(task.id)
24
+ success(true)
25
+ else
26
+ failure(task.errors.full_messages)
27
+ end
28
+ end
29
+
30
+ def task
31
+ @task ||= Perilune::Task.new(
32
+ state: 'draft',
33
+ task_klass: params[:task_klass],
34
+ task_type: 'Import',
35
+ tags: params[:tags]
36
+ )
37
+ end
38
+
39
+ def attach!
40
+ task.file.attach(
41
+ io: params[:file],
42
+ key: "perilune/#{ActiveStorage::Blob.generate_unique_secure_token}",
43
+ filename: "#{params[:task_klass]}_#{Time.zone.now.to_i}"
44
+ )
45
+ end
46
+
47
+ # override to use common serializer for all domain
48
+ def serializer_for(*)
49
+ Perilune::Tasks::Serializer.new
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ class SearchByTagOperation < Perilune::Tasks::SearchOperation
6
+ class Contract < LedgerSync::Ledgers::Contract
7
+ params do
8
+ required(:tag).value(:string)
9
+ required(:query).value(:hash)
10
+ required(:limit).value(:hash)
11
+ required(:includes).value(:array)
12
+ required(:order).value(:string)
13
+ required(:page).value(:integer)
14
+ required(:per).value(:integer)
15
+ end
16
+ end
17
+
18
+ def resources
19
+ @resources ||= super.where('? = ANY (tags)', params[:tag])
20
+ end
21
+
22
+ def serializer_for(*)
23
+ Perilune::Tasks::Serializer.new
24
+ end
25
+ end
26
+ end
27
+ end
@@ -3,6 +3,9 @@
3
3
  module Perilune
4
4
  module Tasks
5
5
  class SearchOperation < LedgerSync::Domains::Operation::Search
6
+ def serializer_for(*)
7
+ Perilune::Tasks::Serializer.new
8
+ end
6
9
  end
7
10
  end
8
11
  end
@@ -5,6 +5,7 @@ module Perilune
5
5
  class Serializer < LedgerSync::Domains::Serializer
6
6
  attribute :id
7
7
  attribute :task_klass
8
+ attribute :task_type
8
9
  attribute :attrs
9
10
  attribute :state
10
11
  attribute :tags
@@ -13,6 +14,9 @@ module Perilune
13
14
  attribute :updated_at
14
15
  attribute :file_name
15
16
  attribute :file_url
17
+ attribute :file_size do |attr|
18
+ attr[:resource].file.try(:byte_size)
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -21,7 +21,7 @@
21
21
  .rounded-sm.font-mono.text-sm.px-2.w-auto.max-w-max.break-normal.text-purple-500.bg-blue-100= resource.task_klass
22
22
  %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500= task_state(resource)
23
23
  %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500
24
- - resource.tags.each do |tag|
24
+ - resource.tags&.each do |tag|
25
25
  %span.inline-flex.items-center.px-3.py-0.5.rounded-full.text-sm.font-medium.bg-blue-100.text-blue-800= tag
26
26
  %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500= resource.created_at.to_s
27
27
  %td.px-6.py-4.whitespace-nowrap.text-right.text-sm.font-medium
@@ -36,9 +36,9 @@
36
36
  %ul.border.border-gray-200.rounded-md.divide-y.divide-gray-200{:role => "list"}
37
37
  %li.pl-3.pr-4.py-3.flex.items-center.justify-between.text-sm
38
38
  .w-0.flex-1.flex.items-center
39
- / Heroicon name: solid/paper-clip
40
39
  %svg.flex-shrink-0.h-5.w-5.text-gray-400{"aria-hidden" => "true", :fill => "currentColor", :viewbox => "0 0 20 20", :xmlns => "http://www.w3.org/2000/svg"}
41
40
  %path{"clip-rule" => "evenodd", :d => "M8 4a3 3 0 00-3 3v4a5 5 0 0010 0V7a1 1 0 112 0v4a7 7 0 11-14 0V7a5 5 0 0110 0v4a3 3 0 11-6 0V7a1 1 0 012 0v4a1 1 0 102 0V7a3 3 0 00-3-3z", "fill-rule" => "evenodd"}
42
41
  %span.ml-2.flex-1.w-0.truncate #{@resource.file_name}
42
+ %span.text-sm.text-gray-500 #{number_to_human_size(@resource.file_size)}
43
43
  .ml-4.flex-shrink-0
44
44
  = link_to 'Download', @resource.file_url, class: 'font-medium text-indigo-400 hover:text-indigo-900'
@@ -0,0 +1,11 @@
1
+ default: &default
2
+ adapter: postgresql
3
+ encoding: unicode
4
+ username: <%= ENV['POSTGRES_USER'] %>
5
+ password: <%= ENV['POSTGRES_PASSWORD'] %>
6
+ host: <%= ENV['POSTGRES_HOST'] %>
7
+ pool: 5
8
+ database: <%= ENV['POSTGRES_DB'] %>
9
+
10
+ test:
11
+ <<: *default
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/migration'
4
+
5
+ module Perilune
6
+ module Generators
7
+ class InstallGenerator < ::Rails::Generators::Base
8
+ include Rails::Generators::Migration
9
+ source_root File.expand_path('templates', __dir__)
10
+ desc 'add the migrations'
11
+
12
+ def self.next_migration_number(*)
13
+ if @prev_migration_nr
14
+ @prev_migration_nr += 1
15
+ else
16
+ @prev_migration_nr = Time.zone.now.utc.strftime('%Y%m%d%H%M%S').to_i
17
+ end
18
+ @prev_migration_nr.to_s
19
+ end
20
+
21
+ def copy_migrations
22
+ migration_template 'create_periline_tasks.rb', 'db/migrate/create_periline_tasks.rb'
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreatePeriluneTask < ActiveRecord::Migration[7.0]
4
+ def change # rubocop:disable Metrics/MethodLength
5
+ create_table :perilune_tasks do |t|
6
+ t.string :task_klass
7
+ t.jsonb :attrs
8
+ t.string :state
9
+ t.text :tags, array: true, default: []
10
+ t.jsonb :error_data
11
+ t.string :task_type
12
+ t.datetime :processing_at
13
+ t.datetime :processed_at
14
+ t.datetime :failed_at
15
+ t.timestamps
16
+ end
17
+ add_index :perilune_tasks, :tags, using: :gin
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class Configuration
5
+ attr_accessor :queue_name, :stat_driver
6
+
7
+ def initialize
8
+ @queue_name = :default
9
+ @stat_driver = ::Trifle::Stats::Driver::Redis.new
10
+ end
11
+
12
+ def stats_driver_config
13
+ config = ::Trifle::Stats::Configuration.new
14
+ config.driver = @stat_driver
15
+ config.time_zone = 'GMT'
16
+ config.beginning_of_week = :monday
17
+ config.track_ranges = %i[hour day week month quarter year]
18
+ config
19
+ end
20
+ end
21
+ end
@@ -18,6 +18,7 @@ module Perilune
18
18
  end
19
19
 
20
20
  def execute
21
+ task.update(state: 'processing')
21
22
  operate
22
23
  rescue StandardError => e
23
24
  failure(e.message)
@@ -58,6 +59,18 @@ module Perilune
58
59
  key: task.id, reference: task.id, config: tracer_config
59
60
  )
60
61
  end
62
+
63
+ def track_stats(event:, success:)
64
+ Trifle::Stats.track(
65
+ key: "perilune::#{event.downcase}", at: Time.zone.now,
66
+ config: Perilune.default.stats_driver_config,
67
+ values: {
68
+ count: 1,
69
+ success: success ? 1 : 0,
70
+ failure: success ? 0 : 1
71
+ }
72
+ )
73
+ end
61
74
  end
62
75
  end
63
76
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Perilune
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/perilune.rb CHANGED
@@ -2,7 +2,18 @@
2
2
 
3
3
  require 'perilune/engine'
4
4
  require 'perilune/tasks/mixin'
5
+ require 'perilune/configuration'
5
6
 
6
7
  module Perilune
7
- # Your code goes here...
8
+ FACTORY_PATH = File.expand_path('../spec/factories', __dir__)
9
+
10
+ def self.default
11
+ @default ||= Configuration.new
12
+ end
13
+
14
+ def self.configure
15
+ yield(default)
16
+
17
+ default
18
+ end
8
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perilune
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kartavya Pareek
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-03-17 00:00:00.000000000 Z
12
+ date: 2022-07-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ledger_sync-domains
@@ -17,21 +17,21 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 1.1.1
20
+ version: '1.2'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: 1.1.1
27
+ version: '1.2'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rails
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 7.0.0
34
+ version: '7.0'
35
35
  - - ">="
36
36
  - !ruby/object:Gem::Version
37
37
  version: 7.0.0.0
@@ -41,7 +41,7 @@ dependencies:
41
41
  requirements:
42
42
  - - "~>"
43
43
  - !ruby/object:Gem::Version
44
- version: 7.0.0
44
+ version: '7.0'
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 7.0.0.0
@@ -59,6 +59,34 @@ dependencies:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: trifle-stats
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: database_cleaner-active_record
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
62
90
  - !ruby/object:Gem::Dependency
63
91
  name: dotenv-rails
64
92
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +129,20 @@ dependencies:
101
129
  - - ">="
102
130
  - !ruby/object:Gem::Version
103
131
  version: '0'
132
+ - !ruby/object:Gem::Dependency
133
+ name: pry
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.13.1
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.13.1
104
146
  - !ruby/object:Gem::Dependency
105
147
  name: rspec-rails
106
148
  requirement: !ruby/object:Gem::Requirement
@@ -115,7 +157,22 @@ dependencies:
115
157
  - - ">="
116
158
  - !ruby/object:Gem::Version
117
159
  version: '0'
118
- description: Description of Perilune.
160
+ - !ruby/object:Gem::Dependency
161
+ name: timecop
162
+ requirement: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: Perilune is a Rails Engine that allows you to define Task classes for
175
+ procesing files and handles their processing on the background for you.
119
176
  email:
120
177
  - hi@dropbot.sh
121
178
  executables: []
@@ -135,9 +192,10 @@ files:
135
192
  - app/mailers/perilune/application_mailer.rb
136
193
  - app/models/perilune/application_record.rb
137
194
  - app/models/perilune/task.rb
138
- - app/operations/perilune/tasks/create_operation.rb
139
195
  - app/operations/perilune/tasks/exports/create_operation.rb
140
196
  - app/operations/perilune/tasks/find_operation.rb
197
+ - app/operations/perilune/tasks/imports/create_operation.rb
198
+ - app/operations/perilune/tasks/search_by_tag_operation.rb
141
199
  - app/operations/perilune/tasks/search_operation.rb
142
200
  - app/serializers/perilune/tasks/serializer.rb
143
201
  - app/views/kaminari/_first_page.html.haml
@@ -151,17 +209,21 @@ files:
151
209
  - app/views/perilune/home/index.html.haml
152
210
  - app/views/perilune/tasks/index.html.haml
153
211
  - app/views/perilune/tasks/show.html.haml
212
+ - config/github_database.yml
154
213
  - config/routes.rb
214
+ - lib/generators/perilune/install/install_generator.rb
215
+ - lib/generators/perilune/install/templates/create_periline_tasks.rb
155
216
  - lib/perilune.rb
217
+ - lib/perilune/configuration.rb
156
218
  - lib/perilune/engine.rb
157
219
  - lib/perilune/tasks/mixin.rb
158
220
  - lib/perilune/version.rb
159
221
  - lib/tasks/perilune_tasks.rake
160
- homepage: https://engineering.dropbot.sh
222
+ homepage: https://dropbot.sh
161
223
  licenses:
162
224
  - MIT
163
225
  metadata:
164
- homepage_uri: https://engineering.dropbot.sh
226
+ homepage_uri: https://dropbot.sh
165
227
  source_code_uri: https://github.com/sandbite/perilune
166
228
  changelog_uri: https://github.com/sandbite/perilune/blob/main/CHANGELOG.md
167
229
  post_install_message:
@@ -182,5 +244,5 @@ requirements: []
182
244
  rubygems_version: 3.2.9
183
245
  signing_key:
184
246
  specification_version: 4
185
- summary: Summary of Perilune.
247
+ summary: Add Imports and Exports to your app with ease.
186
248
  test_files: []
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Perilune
4
- module Tasks
5
- class CreateOperation
6
- include LedgerSync::Domains::Operation::Mixin
7
-
8
- class Contract < LedgerSync::Ledgers::Contract
9
- params do
10
- required(:file).maybe(type?: File)
11
- required(:file).maybe(type?: Tempfile)
12
- required(:task_klass).filled(:string)
13
- optional(:tags).filled(:array)
14
- end
15
- end
16
-
17
- private
18
-
19
- def operate
20
- attach!
21
- if task.save
22
- Perilune::Tasks::ExecutorJob.perform_later(task.id)
23
- success(true)
24
- else
25
- failure(task.errors.full_messages)
26
- end
27
- end
28
-
29
- def task
30
- @task ||= Perilune::Task.new(
31
- state: 'draft',
32
- task_klass: params[:task_klass],
33
- tags: params[:tags]
34
- )
35
- end
36
-
37
- def attach!
38
- task.file.attach(
39
- io: params[:file],
40
- key: "perilune/#{ActiveStorage::Blob.generate_unique_secure_token}",
41
- filename: "#{params[:task_klass]}_#{Time.zone.now.to_i}"
42
- )
43
- end
44
-
45
- # override to use common serializer for all domain
46
- def serializer_for(*)
47
- Perilune::Tasks::Serializer.new
48
- end
49
- end
50
- end
51
- end