perilune 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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