marty 2.7.3 → 2.8.0
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/Gemfile.lock +4 -1
- data/README.md +7 -0
- data/app/components/marty/background_job_schedule_view.rb +94 -0
- data/app/components/marty/main_auth_app.rb +46 -23
- data/app/jobs/marty/cron_job.rb +41 -0
- data/app/models/marty/background_job.rb +4 -0
- data/app/models/marty/background_job/schedule.rb +27 -0
- data/app/services/marty/background_job/update_schedule.rb +34 -0
- data/app/services/marty/jobs/schedule.rb +17 -0
- data/db/migrate/505_add_cron_to_delayed_jobs.rb +9 -0
- data/db/migrate/506_create_marty_delayed_job_schedules.rb +13 -0
- data/lib/marty.rb +1 -0
- data/lib/marty/version.rb +1 -1
- data/lib/tasks/marty_jobs.rake +8 -0
- data/make-dummy.mk +4 -2
- data/marty.gemspec +2 -1
- data/spec/dummy/app/jobs/test_job.rb +4 -0
- data/spec/dummy/app/jobs/test_job2.rb +4 -0
- data/spec/dummy/config/application.rb +2 -0
- data/spec/features/background_job_schedule_spec.rb +112 -0
- data/spec/models/background_job/schedule.rb +43 -0
- data/spec/support/chromedriver.rb +11 -1
- metadata +31 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 1e99ecbf41a6cda553cf318fb21bbe9c3150ec13e46b074171eaa1bd1ea12aed
         | 
| 4 | 
            +
              data.tar.gz: c6dcdf2a95d456e27189c1369ff54de3d62ce4cd58b5d7125bf8f83d57ba8d57
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a43ae65fe90a06f4c1c35652aaba4627431ea449fedc6c262aa37a384d5d4e02d879a47c145b9dab56c756025d42e92d2c49e1a9658301ba50598164dc3e514b
         | 
| 7 | 
            +
              data.tar.gz: ef2702ad5285cb59f777faa7b1ecceecd570945e490100e6542cd3fe7e237e597d491e3b9e7f7b9de32149645959b9142481efc3bf8614330a344a234f9c2397
         | 
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -6,8 +6,9 @@ PATH | |
| 6 6 | 
             
                  axlsx (= 3.0.0pre)
         | 
| 7 7 | 
             
                  coderay
         | 
| 8 8 | 
             
                  daemons (~> 1.3.1)
         | 
| 9 | 
            +
                  delayed_cron_job
         | 
| 9 10 | 
             
                  delayed_job_active_record
         | 
| 10 | 
            -
                  delorean_lang (~> 0.6 | 
| 11 | 
            +
                  delorean_lang (~> 0.6)
         | 
| 11 12 | 
             
                  json-schema
         | 
| 12 13 | 
             
                  mcfly (~> 0.0.20)
         | 
| 13 14 | 
             
                  net-ldap (~> 0.16.1)
         | 
| @@ -89,6 +90,8 @@ GEM | |
| 89 90 | 
             
                crass (1.0.4)
         | 
| 90 91 | 
             
                daemons (1.3.1)
         | 
| 91 92 | 
             
                database_cleaner (1.7.0)
         | 
| 93 | 
            +
                delayed_cron_job (0.7.2)
         | 
| 94 | 
            +
                  delayed_job (>= 4.1)
         | 
| 92 95 | 
             
                delayed_job (4.1.5)
         | 
| 93 96 | 
             
                  activesupport (>= 3.0, < 5.3)
         | 
| 94 97 | 
             
                delayed_job_active_record (4.1.3)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -50,6 +50,13 @@ To delete scripts: | |
| 50 50 | 
             
            ```
         | 
| 51 51 | 
             
            $ rake marty:delete_scripts
         | 
| 52 52 | 
             
            ```
         | 
| 53 | 
            +
            # Scheduled Job
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            To use scheduled backgroud jobs, add to `config/application.rb`:
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            ```
         | 
| 58 | 
            +
              config.active_job.queue_adapter = :delayed_job
         | 
| 59 | 
            +
            ```
         | 
| 53 60 |  | 
| 54 61 | 
             
            # Dummy Application & Testing
         | 
| 55 62 |  | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            class Marty::BackgroundJobScheduleView < Marty::Grid
         | 
| 2 | 
            +
              ACCESSIBLE_BY = [:admin]
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              has_marty_permissions(
         | 
| 5 | 
            +
                read: ACCESSIBLE_BY,
         | 
| 6 | 
            +
                create: ACCESSIBLE_BY,
         | 
| 7 | 
            +
                update: ACCESSIBLE_BY,
         | 
| 8 | 
            +
                delete: ACCESSIBLE_BY,
         | 
| 9 | 
            +
                destroy: ACCESSIBLE_BY,
         | 
| 10 | 
            +
                edit_window__edit_form__submit: ACCESSIBLE_BY,
         | 
| 11 | 
            +
                add_window__add_form__submit: ACCESSIBLE_BY
         | 
| 12 | 
            +
              )
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def configure(c)
         | 
| 15 | 
            +
                super
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                c.title ||= I18n.t('delayed_jobs_schedule_view_title', default: 'Background Jobs Schedule')
         | 
| 18 | 
            +
                c.model = 'Marty::BackgroundJob::Schedule'
         | 
| 19 | 
            +
                c.paging = :buffered
         | 
| 20 | 
            +
                c.editing = :in_form
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                c.attributes = [
         | 
| 23 | 
            +
                  :job_class,
         | 
| 24 | 
            +
                  :cron,
         | 
| 25 | 
            +
                  :state
         | 
| 26 | 
            +
                ]
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def default_context_menu
         | 
| 30 | 
            +
                []
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              attribute :job_class do |c|
         | 
| 34 | 
            +
                c.width = 400
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              attribute :cron do |c|
         | 
| 38 | 
            +
                c.width = 400
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              attribute :state do |c|
         | 
| 42 | 
            +
                c.width = 150
         | 
| 43 | 
            +
                editor_config = {
         | 
| 44 | 
            +
                  trigger_action: :all,
         | 
| 45 | 
            +
                  xtype: :combo,
         | 
| 46 | 
            +
                  store: Marty::BackgroundJob::Schedule::ALL_STATES,
         | 
| 47 | 
            +
                  forceSelection: true,
         | 
| 48 | 
            +
                }
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                c.column_config = { editor: editor_config }
         | 
| 51 | 
            +
                c.field_config  = editor_config
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              endpoint :edit_window__edit_form__submit do |params|
         | 
| 55 | 
            +
                result = super(params)
         | 
| 56 | 
            +
                next result if result.empty?
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                obj_hash = result.first
         | 
| 59 | 
            +
                Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                result
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              endpoint :add_window__add_form__submit do |params|
         | 
| 65 | 
            +
                result = super(params)
         | 
| 66 | 
            +
                next result if result.empty?
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                obj_hash = result.first
         | 
| 69 | 
            +
                Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                result
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              endpoint :multiedit_window__multiedit_form__submit do |_params|
         | 
| 75 | 
            +
                client.netzke_notify 'Multiediting is disabled for cron schedules'
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              endpoint :destroy do |params|
         | 
| 79 | 
            +
                res = params.each_with_object({}) do |id, hash|
         | 
| 80 | 
            +
                  job_class = model.find_by(id: id)&.job_class
         | 
| 81 | 
            +
                  result = super([id])
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  # Do nothing If it wasn't destroyed
         | 
| 84 | 
            +
                  next hash.merge(result) unless result[id.to_i] == 'ok'
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  Marty::BackgroundJob::UpdateSchedule.call(id: id, job_class: job_class)
         | 
| 87 | 
            +
                  hash.merge(result)
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                res
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
            end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            BackgroundJobScheduleView = Marty::BackgroundJobScheduleView
         | 
| @@ -1,16 +1,17 @@ | |
| 1 | 
            -
            require 'marty/scripting'
         | 
| 2 | 
            -
            require 'marty/reporting'
         | 
| 3 | 
            -
            require 'marty/posting_window'
         | 
| 4 | 
            -
            require 'marty/new_posting_window'
         | 
| 5 | 
            -
            require 'marty/import_type_view'
         | 
| 6 | 
            -
            require 'marty/user_view'
         | 
| 7 | 
            -
            require 'marty/event_view'
         | 
| 8 | 
            -
            require 'marty/promise_view'
         | 
| 9 1 | 
             
            require 'marty/api_auth_view'
         | 
| 10 2 | 
             
            require 'marty/api_config_view'
         | 
| 11 3 | 
             
            require 'marty/api_log_view'
         | 
| 12 4 | 
             
            require 'marty/config_view'
         | 
| 13 5 | 
             
            require 'marty/data_grid_view'
         | 
| 6 | 
            +
            require 'marty/background_job_schedule_view'
         | 
| 7 | 
            +
            require 'marty/event_view'
         | 
| 8 | 
            +
            require 'marty/import_type_view'
         | 
| 9 | 
            +
            require 'marty/new_posting_window'
         | 
| 10 | 
            +
            require 'marty/posting_window'
         | 
| 11 | 
            +
            require 'marty/promise_view'
         | 
| 12 | 
            +
            require 'marty/reporting'
         | 
| 13 | 
            +
            require 'marty/scripting'
         | 
| 14 | 
            +
            require 'marty/user_view'
         | 
| 14 15 |  | 
| 15 16 | 
             
            class Marty::MainAuthApp < Marty::AuthApp
         | 
| 16 17 | 
             
              extend ::Marty::Permissions
         | 
| @@ -112,6 +113,7 @@ class Marty::MainAuthApp < Marty::AuthApp | |
| 112 113 | 
             
                      :bg_status,
         | 
| 113 114 | 
             
                      :bg_stop,
         | 
| 114 115 | 
             
                      :bg_restart,
         | 
| 116 | 
            +
                      :background_job_schedule_view,
         | 
| 115 117 | 
             
                    ]
         | 
| 116 118 | 
             
                  },
         | 
| 117 119 | 
             
                ]
         | 
| @@ -276,6 +278,14 @@ class Marty::MainAuthApp < Marty::AuthApp | |
| 276 278 | 
             
                a.disabled = !self.class.has_admin_perm?
         | 
| 277 279 | 
             
              end
         | 
| 278 280 |  | 
| 281 | 
            +
              action :background_job_schedule_view do |a|
         | 
| 282 | 
            +
                a.text     = 'Schedule Background Jobs'
         | 
| 283 | 
            +
                a.tooltip  = 'Edit Delayed Jobs Cron schedules'
         | 
| 284 | 
            +
                a.icon_cls = 'fa fa-cog glyph'
         | 
| 285 | 
            +
                a.disabled = !self.class.has_admin_perm?
         | 
| 286 | 
            +
                a.handler = :netzke_load_component_by_action
         | 
| 287 | 
            +
              end
         | 
| 288 | 
            +
             | 
| 279 289 | 
             
              action :log_view do |a|
         | 
| 280 290 | 
             
                a.text     = 'View Log'
         | 
| 281 291 | 
             
                a.tooltip  = 'View Log'
         | 
| @@ -365,31 +375,44 @@ class Marty::MainAuthApp < Marty::AuthApp | |
| 365 375 | 
             
              end
         | 
| 366 376 |  | 
| 367 377 | 
             
              ######################################################################
         | 
| 368 | 
            -
             | 
| 369 | 
            -
              component :scripting do |c|
         | 
| 370 | 
            -
                c.allow_edit = self.class.has_scripting_perm?
         | 
| 371 | 
            -
              end
         | 
| 372 | 
            -
              component :reporting
         | 
| 373 | 
            -
              component :promise_view
         | 
| 374 | 
            -
              component :posting_window
         | 
| 375 | 
            -
              component :new_posting_window do |c|
         | 
| 376 | 
            -
                c.disabled = Marty::Util.warped? || !self.class.has_posting_perm?
         | 
| 377 | 
            -
              end
         | 
| 378 | 
            -
              component :import_type_view
         | 
| 379 | 
            -
              component :user_view
         | 
| 380 | 
            -
              component :event_view
         | 
| 381 | 
            -
              component :config_view
         | 
| 382 | 
            -
              component :data_grid_view
         | 
| 383 378 | 
             
              component :api_auth_view do |c|
         | 
| 384 379 | 
             
                c.disabled = Marty::Util.warped?
         | 
| 385 380 | 
             
              end
         | 
| 381 | 
            +
             | 
| 386 382 | 
             
              component :api_log_view
         | 
| 383 | 
            +
             | 
| 387 384 | 
             
              component :api_config_view
         | 
| 388 385 |  | 
| 386 | 
            +
              component :background_job_schedule_view
         | 
| 387 | 
            +
             | 
| 388 | 
            +
              component :config_view
         | 
| 389 | 
            +
             | 
| 390 | 
            +
              component :data_grid_view
         | 
| 391 | 
            +
             | 
| 392 | 
            +
              component :event_view
         | 
| 393 | 
            +
             | 
| 394 | 
            +
              component :import_type_view
         | 
| 395 | 
            +
             | 
| 389 396 | 
             
              component :log_view do |c|
         | 
| 390 397 | 
             
                c.klass = Marty::LogView
         | 
| 391 398 | 
             
              end
         | 
| 392 399 |  | 
| 400 | 
            +
              component :new_posting_window do |c|
         | 
| 401 | 
            +
                c.disabled = Marty::Util.warped? || !self.class.has_posting_perm?
         | 
| 402 | 
            +
              end
         | 
| 403 | 
            +
             | 
| 404 | 
            +
              component :posting_window
         | 
| 405 | 
            +
             | 
| 406 | 
            +
              component :promise_view
         | 
| 407 | 
            +
             | 
| 408 | 
            +
              component :reporting
         | 
| 409 | 
            +
             | 
| 410 | 
            +
              component :scripting do |c|
         | 
| 411 | 
            +
                c.allow_edit = self.class.has_scripting_perm?
         | 
| 412 | 
            +
              end
         | 
| 413 | 
            +
             | 
| 414 | 
            +
              component :user_view
         | 
| 415 | 
            +
             | 
| 393 416 | 
             
              endpoint :reload_scripts do |_params|
         | 
| 394 417 | 
             
                Marty::Script.load_scripts
         | 
| 395 418 | 
             
                client.netzke_notify 'Scripts have been reloaded'
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            class Marty::CronJob < ActiveJob::Base
         | 
| 2 | 
            +
              class << self
         | 
| 3 | 
            +
                def schedule
         | 
| 4 | 
            +
                  return reschedule if scheduled?
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  cron = cron_expression
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  return if cron.blank?
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  set(cron: cron).perform_later
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def reschedule
         | 
| 14 | 
            +
                  dj = delayed_job
         | 
| 15 | 
            +
                  return dj.update(cron: cron_expression) if dj.locked_by?
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  remove
         | 
| 18 | 
            +
                  schedule
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def remove
         | 
| 22 | 
            +
                  delayed_job.destroy if scheduled?
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                alias remove_schedule remove
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def scheduled?
         | 
| 28 | 
            +
                  delayed_job.present?
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def delayed_job
         | 
| 32 | 
            +
                  Delayed::Job.
         | 
| 33 | 
            +
                    where('handler LIKE ?', "%job_class: #{name}\n%").
         | 
| 34 | 
            +
                    first
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def cron_expression
         | 
| 38 | 
            +
                  ::Marty::BackgroundJob::Schedule.on.find_by(job_class: name)&.cron
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            module Marty
         | 
| 2 | 
            +
              module BackgroundJob
         | 
| 3 | 
            +
                class Schedule < Marty::Base
         | 
| 4 | 
            +
                  self.table_name = 'marty_background_job_schedules'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  # Copied and adjusted:
         | 
| 7 | 
            +
                  # https://github.com/javan/whenever/blob/e4507e2ed2158c603f0c334a8b0a957711db343a/lib/whenever/cron.rb
         | 
| 8 | 
            +
                  REGEX = %r{\A(((\*?[\d/,\-]*)\s){3}(\*?([\d/,\-])*\s)(\*?([\d/,\-])*))\z}i
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  validates :job_class, :cron, :state, presence: true
         | 
| 11 | 
            +
                  validates :job_class, uniqueness: true
         | 
| 12 | 
            +
                  validates :cron, format: { with: REGEX }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  validate :job_class_validation
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  ALL_STATES = %w[on off].freeze
         | 
| 17 | 
            +
                  enum state: ALL_STATES.zip(ALL_STATES).to_h
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def job_class_validation
         | 
| 20 | 
            +
                    job_class.constantize.respond_to?(:schedule)
         | 
| 21 | 
            +
                  rescue NameError
         | 
| 22 | 
            +
                    errors.add(:job_class, "doesn't exist")
         | 
| 23 | 
            +
                    false
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            module Marty
         | 
| 2 | 
            +
              module BackgroundJob
         | 
| 3 | 
            +
                module UpdateSchedule
         | 
| 4 | 
            +
                  def self.call(id:, job_class:)
         | 
| 5 | 
            +
                    model = Marty::BackgroundJob::Schedule.find_by(id: id)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    return remove_schedule(job_class: job_class) unless model.present?
         | 
| 8 | 
            +
                    return remove_schedule(job_class: job_class) if model.off?
         | 
| 9 | 
            +
                    return schedule(job_class: job_class) if model.on?
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def self.remove_schedule(job_class:)
         | 
| 13 | 
            +
                    klass = job_class.constantize
         | 
| 14 | 
            +
                    klass.remove_schedule if klass.respond_to?(:remove_schedule)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    true
         | 
| 17 | 
            +
                  rescue NameError
         | 
| 18 | 
            +
                    false
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def self.schedule(job_class:)
         | 
| 22 | 
            +
                    klass = job_class.constantize
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    return false unless klass.respond_to?(:schedule)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    klass.schedule
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    true
         | 
| 29 | 
            +
                  rescue NameError
         | 
| 30 | 
            +
                    false
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module Marty
         | 
| 2 | 
            +
              module Jobs
         | 
| 3 | 
            +
                module Schedule
         | 
| 4 | 
            +
                  extend Delorean::Functions
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  delorean_fn :call, sig: 0 do
         | 
| 7 | 
            +
                    glob = Rails.root.join('app', 'jobs', '**', '*_job.rb')
         | 
| 8 | 
            +
                    Dir.glob(glob).each { |f| require f }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    Marty::CronJob.subclasses.map do |klass|
         | 
| 11 | 
            +
                      klass.schedule
         | 
| 12 | 
            +
                      [klass.name, klass.cron_expression]
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            class CreateMartyDelayedJobSchedules < ActiveRecord::Migration[5.1]
         | 
| 2 | 
            +
              def change
         | 
| 3 | 
            +
                create_table :marty_background_job_schedules do |t|
         | 
| 4 | 
            +
                  t.string :job_class, null: false
         | 
| 5 | 
            +
                  t.string :cron, null: false
         | 
| 6 | 
            +
                  t.string :state, null: false
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  t.timestamps
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                add_index :marty_background_job_schedules, :job_class, unique: true
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
    
        data/lib/marty.rb
    CHANGED
    
    
    
        data/lib/marty/version.rb
    CHANGED
    
    
    
        data/make-dummy.mk
    CHANGED
    
    | @@ -2,10 +2,12 @@ dummy-app-build: | |
| 2 2 | 
             
            	docker-compose --file=docker-compose.dummy.yml build
         | 
| 3 3 |  | 
| 4 4 | 
             
            dummy-app:
         | 
| 5 | 
            -
            	docker-compose --file=docker-compose.dummy.yml up
         | 
| 5 | 
            +
            	docker-compose --file=docker-compose.dummy.yml up -d app
         | 
| 6 | 
            +
            	docker attach marty_app_1
         | 
| 6 7 |  | 
| 7 8 | 
             
            dummy-app-start:
         | 
| 8 | 
            -
            	docker-compose --file=docker-compose.dummy.yml up app
         | 
| 9 | 
            +
            	docker-compose --file=docker-compose.dummy.yml up -d app
         | 
| 10 | 
            +
            	docker attach marty_app_1
         | 
| 9 11 |  | 
| 10 12 | 
             
            dummy-app-stop:
         | 
| 11 13 | 
             
            	docker-compose --file=docker-compose.dummy.yml stop
         | 
    
        data/marty.gemspec
    CHANGED
    
    | @@ -33,7 +33,7 @@ Gem::Specification.new do |s| | |
| 33 33 |  | 
| 34 34 | 
             
              s.add_dependency 'axlsx', '3.0.0pre'
         | 
| 35 35 |  | 
| 36 | 
            -
              s.add_dependency 'delorean_lang', '~> 0.6 | 
| 36 | 
            +
              s.add_dependency 'delorean_lang', '~> 0.6'
         | 
| 37 37 | 
             
              s.add_dependency 'mcfly', '~> 0.0.20'
         | 
| 38 38 |  | 
| 39 39 | 
             
              s.add_dependency 'coderay'
         | 
| @@ -46,5 +46,6 @@ Gem::Specification.new do |s| | |
| 46 46 | 
             
              s.add_dependency 'aws-sigv4', '~> 1.0', '>= 1.0.2'
         | 
| 47 47 |  | 
| 48 48 | 
             
              s.add_dependency 'daemons', '~> 1.3.1'
         | 
| 49 | 
            +
              s.add_dependency 'delayed_cron_job'
         | 
| 49 50 | 
             
              s.add_dependency 'delayed_job_active_record'
         | 
| 50 51 | 
             
            end
         | 
| @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            feature 'Background jobs schedule view', js: true do
         | 
| 4 | 
            +
              before do
         | 
| 5 | 
            +
                Delayed::Job.delete_all
         | 
| 6 | 
            +
                populate_test_users
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              context 'as dev' do
         | 
| 10 | 
            +
                before do
         | 
| 11 | 
            +
                  log_in_as('dev1')
         | 
| 12 | 
            +
                  wait_for_ajax
         | 
| 13 | 
            +
                  press('System')
         | 
| 14 | 
            +
                  press('Background Jobs')
         | 
| 15 | 
            +
                  press('Schedule Background Jobs')
         | 
| 16 | 
            +
                  wait_for_ajax
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                it 'access denied' do
         | 
| 20 | 
            +
                  expect(page).to_not have_content 'Background Jobs Schedule'
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              context 'as admin' do
         | 
| 25 | 
            +
                let(:schedule_view) { netzke_find('background_job_schedule_view') }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                let!(:schedule) do
         | 
| 28 | 
            +
                  Marty::BackgroundJob::Schedule.create(
         | 
| 29 | 
            +
                    job_class: 'TestJob2',
         | 
| 30 | 
            +
                    cron: '0 0 * * *',
         | 
| 31 | 
            +
                    state: 'on'
         | 
| 32 | 
            +
                  ).tap do |job|
         | 
| 33 | 
            +
                    Marty::BackgroundJob::UpdateSchedule.call(
         | 
| 34 | 
            +
                      id: job.id,
         | 
| 35 | 
            +
                      job_class: job.job_class
         | 
| 36 | 
            +
                    )
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                before do
         | 
| 41 | 
            +
                  expect(TestJob2.scheduled?).to be true
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  log_in_as('admin1')
         | 
| 44 | 
            +
                  wait_for_ajax
         | 
| 45 | 
            +
                  press('System')
         | 
| 46 | 
            +
                  press('Background Jobs')
         | 
| 47 | 
            +
                  press('Schedule Background Jobs')
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  wait_for_ajax
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  expect(page).to have_content 'Background Jobs Schedule'
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                it 'creates new schedule' do
         | 
| 55 | 
            +
                  expect(TestJob.scheduled?).to be false
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  press('Add')
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  fill_in('Job class', with: 'TestJob')
         | 
| 60 | 
            +
                  fill_in('cron', with: '1 1 * * *')
         | 
| 61 | 
            +
                  fill_in('state', with: 'on')
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  press 'OK'
         | 
| 64 | 
            +
                  wait_for_ajax
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  find('.x-tool-refresh').click
         | 
| 67 | 
            +
                  crons = schedule_view.get_col_vals('cron', 2, 0)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  expect(crons).to include('1 1 * * *')
         | 
| 70 | 
            +
                  expect(crons).to include('0 0 * * *')
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  expect(TestJob.scheduled?).to be true
         | 
| 73 | 
            +
                  expect(TestJob.delayed_job.cron).to eq '1 1 * * *'
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  expect(TestJob2.scheduled?).to be true
         | 
| 76 | 
            +
                  expect(TestJob2.delayed_job.cron).to eq '0 0 * * *'
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                it 'deletes schedule' do
         | 
| 80 | 
            +
                  find('.x-grid-item', text: 'TestJob2').click
         | 
| 81 | 
            +
                  press 'Delete'
         | 
| 82 | 
            +
                  press 'Yes'
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  wait_for_ajax
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  expect(TestJob2.scheduled?).to be false
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                it 'turns the schedule off' do
         | 
| 90 | 
            +
                  find('.x-grid-item', text: 'TestJob2').click
         | 
| 91 | 
            +
                  press 'Edit'
         | 
| 92 | 
            +
                  fill_in('state', with: 'off')
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  press 'OK'
         | 
| 95 | 
            +
                  wait_for_ajax
         | 
| 96 | 
            +
                  expect(TestJob2.scheduled?).to be false
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                it 'shows validation errors' do
         | 
| 100 | 
            +
                  press('Add')
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  fill_in('Job class', with: 'TestJob2')
         | 
| 103 | 
            +
                  fill_in('state', with: 'on')
         | 
| 104 | 
            +
                  fill_in('cron', with: '1')
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                  press 'OK'
         | 
| 107 | 
            +
                  wait_for_ajax
         | 
| 108 | 
            +
                  expect(page).to have_content('Job class has already been taken')
         | 
| 109 | 
            +
                  expect(page).to have_content('Cron is invalid')
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'marty/background_job/schedule'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Marty
         | 
| 5 | 
            +
              module BackgroundJob
         | 
| 6 | 
            +
                describe Schedule do
         | 
| 7 | 
            +
                  let(:subject) do
         | 
| 8 | 
            +
                    described_class.new(job_class: 'TestJob', cron: '* * * * *', state: 'on')
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  VALID_CRONS = [
         | 
| 12 | 
            +
                    '* * * * *',
         | 
| 13 | 
            +
                    '45 23 * * 6',
         | 
| 14 | 
            +
                    '0 7,17 * * *',
         | 
| 15 | 
            +
                    '0 17 * * 6',
         | 
| 16 | 
            +
                    '*/10 * * * *',
         | 
| 17 | 
            +
                    '30 10 * * *',
         | 
| 18 | 
            +
                    '0 * * * *',
         | 
| 19 | 
            +
                    '0 * * * *',
         | 
| 20 | 
            +
                  ].freeze
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  INVALID_CRONS = [
         | 
| 23 | 
            +
                    'text 23 * * 6',
         | 
| 24 | 
            +
                    '1',
         | 
| 25 | 
            +
                    '* * *'
         | 
| 26 | 
            +
                  ].freeze
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  it 'valid with valid cron expression' do
         | 
| 29 | 
            +
                    VALID_CRONS.each do |cron|
         | 
| 30 | 
            +
                      subject.cron = cron
         | 
| 31 | 
            +
                      expect(subject).to be_valid
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  it 'invalid with valid cron expression' do
         | 
| 36 | 
            +
                    INVALID_CRONS.each do |cron|
         | 
| 37 | 
            +
                      subject.cron = cron
         | 
| 38 | 
            +
                      expect(subject).to_not be_valid
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -12,10 +12,20 @@ module Marty; module RSpec; module Chromedriver | |
| 12 12 | 
             
                    pageLoadStrategy: 'none',
         | 
| 13 13 | 
             
                  }
         | 
| 14 14 |  | 
| 15 | 
            +
                  options = ::Selenium::WebDriver::Chrome::Options.new
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # Add arguments to the driver using the Options interface
         | 
| 18 | 
            +
                  if opts[:args]
         | 
| 19 | 
            +
                    opts[:args].each do |arg|
         | 
| 20 | 
            +
                      options.add_argument("--#{arg}")
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 15 24 | 
             
                  caps = Selenium::WebDriver::Remote::Capabilities.chrome(copts)
         | 
| 16 25 | 
             
                  driver = Capybara::Selenium::Driver.new(app,
         | 
| 17 26 | 
             
                                                          browser: :chrome,
         | 
| 18 | 
            -
                                                          desired_capabilities: caps | 
| 27 | 
            +
                                                          desired_capabilities: caps,
         | 
| 28 | 
            +
                                                          options: options)
         | 
| 19 29 | 
             
                  yield driver if block_given?
         | 
| 20 30 | 
             
                  driver
         | 
| 21 31 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: marty
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2. | 
| 4 | 
            +
              version: 2.8.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Arman Bostani
         | 
| @@ -14,7 +14,7 @@ authors: | |
| 14 14 | 
             
            autorequire: 
         | 
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 | 
            -
            date: 2019-06- | 
| 17 | 
            +
            date: 2019-06-12 00:00:00.000000000 Z
         | 
| 18 18 | 
             
            dependencies:
         | 
| 19 19 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 20 20 | 
             
              name: pg
         | 
| @@ -64,14 +64,14 @@ dependencies: | |
| 64 64 | 
             
                requirements:
         | 
| 65 65 | 
             
                - - "~>"
         | 
| 66 66 | 
             
                  - !ruby/object:Gem::Version
         | 
| 67 | 
            -
                    version: 0.6 | 
| 67 | 
            +
                    version: '0.6'
         | 
| 68 68 | 
             
              type: :runtime
         | 
| 69 69 | 
             
              prerelease: false
         | 
| 70 70 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 71 71 | 
             
                requirements:
         | 
| 72 72 | 
             
                - - "~>"
         | 
| 73 73 | 
             
                  - !ruby/object:Gem::Version
         | 
| 74 | 
            -
                    version: 0.6 | 
| 74 | 
            +
                    version: '0.6'
         | 
| 75 75 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 76 76 | 
             
              name: mcfly
         | 
| 77 77 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -190,6 +190,20 @@ dependencies: | |
| 190 190 | 
             
                - - "~>"
         | 
| 191 191 | 
             
                  - !ruby/object:Gem::Version
         | 
| 192 192 | 
             
                    version: 1.3.1
         | 
| 193 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 194 | 
            +
              name: delayed_cron_job
         | 
| 195 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 196 | 
            +
                requirements:
         | 
| 197 | 
            +
                - - ">="
         | 
| 198 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 199 | 
            +
                    version: '0'
         | 
| 200 | 
            +
              type: :runtime
         | 
| 201 | 
            +
              prerelease: false
         | 
| 202 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 203 | 
            +
                requirements:
         | 
| 204 | 
            +
                - - ">="
         | 
| 205 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 206 | 
            +
                    version: '0'
         | 
| 193 207 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 194 208 | 
             
              name: delayed_job_active_record
         | 
| 195 209 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -240,6 +254,7 @@ files: | |
| 240 254 | 
             
            - app/components/marty/api_log_view.rb
         | 
| 241 255 | 
             
            - app/components/marty/auth_app.rb
         | 
| 242 256 | 
             
            - app/components/marty/auth_app/client/auth_app.js
         | 
| 257 | 
            +
            - app/components/marty/background_job_schedule_view.rb
         | 
| 243 258 | 
             
            - app/components/marty/base_rule_view.rb
         | 
| 244 259 | 
             
            - app/components/marty/config_view.rb
         | 
| 245 260 | 
             
            - app/components/marty/data_grid_view.rb
         | 
| @@ -302,8 +317,11 @@ files: | |
| 302 317 | 
             
            - app/helpers/marty/application_helper.rb
         | 
| 303 318 | 
             
            - app/helpers/marty/enum_helper.rb
         | 
| 304 319 | 
             
            - app/helpers/marty/script_set.rb
         | 
| 320 | 
            +
            - app/jobs/marty/cron_job.rb
         | 
| 305 321 | 
             
            - app/models/marty/api_auth.rb
         | 
| 306 322 | 
             
            - app/models/marty/api_config.rb
         | 
| 323 | 
            +
            - app/models/marty/background_job.rb
         | 
| 324 | 
            +
            - app/models/marty/background_job/schedule.rb
         | 
| 307 325 | 
             
            - app/models/marty/base.rb
         | 
| 308 326 | 
             
            - app/models/marty/base_rule.rb
         | 
| 309 327 | 
             
            - app/models/marty/config.rb
         | 
| @@ -333,6 +351,8 @@ files: | |
| 333 351 | 
             
            - app/models/marty/user.rb
         | 
| 334 352 | 
             
            - app/models/marty/user_role.rb
         | 
| 335 353 | 
             
            - app/models/marty/vw_promise.rb
         | 
| 354 | 
            +
            - app/services/marty/background_job/update_schedule.rb
         | 
| 355 | 
            +
            - app/services/marty/jobs/schedule.rb
         | 
| 336 356 | 
             
            - app/services/marty/promises/delorean.rb
         | 
| 337 357 | 
             
            - app/services/marty/promises/delorean/create.rb
         | 
| 338 358 | 
             
            - app/services/marty/promises/ruby.rb
         | 
| @@ -385,6 +405,8 @@ files: | |
| 385 405 | 
             
            - db/migrate/502_add_promise_type_enum.rb
         | 
| 386 406 | 
             
            - db/migrate/503_add_promise_type_to_promises.rb
         | 
| 387 407 | 
             
            - db/migrate/504_remove_plv8_extension.rb
         | 
| 408 | 
            +
            - db/migrate/505_add_cron_to_delayed_jobs.rb
         | 
| 409 | 
            +
            - db/migrate/506_create_marty_delayed_job_schedules.rb
         | 
| 388 410 | 
             
            - db/seeds.rb
         | 
| 389 411 | 
             
            - db/sql/lookup_grid_distinct_v1.sql
         | 
| 390 412 | 
             
            - db/sql/query_grid_dir_v1.sql
         | 
| @@ -428,6 +450,7 @@ files: | |
| 428 450 | 
             
            - lib/pyxll/gemini.py
         | 
| 429 451 | 
             
            - lib/pyxll/pyxll.cfg
         | 
| 430 452 | 
             
            - lib/pyxll/sample.xlsx
         | 
| 453 | 
            +
            - lib/tasks/marty_jobs.rake
         | 
| 431 454 | 
             
            - lib/tasks/marty_tasks.rake
         | 
| 432 455 | 
             
            - lib/tasks/scripts_tasks.rake
         | 
| 433 456 | 
             
            - make-dummy.mk
         | 
| @@ -464,6 +487,8 @@ files: | |
| 464 487 | 
             
            - spec/dummy/app/controllers/application_controller.rb
         | 
| 465 488 | 
             
            - spec/dummy/app/controllers/components_controller.rb
         | 
| 466 489 | 
             
            - spec/dummy/app/helpers/application_helper.rb
         | 
| 490 | 
            +
            - spec/dummy/app/jobs/test_job.rb
         | 
| 491 | 
            +
            - spec/dummy/app/jobs/test_job2.rb
         | 
| 467 492 | 
             
            - spec/dummy/app/mailers/.gitkeep
         | 
| 468 493 | 
             
            - spec/dummy/app/models/.gitkeep
         | 
| 469 494 | 
             
            - spec/dummy/app/models/gemini/amortization_type.rb
         | 
| @@ -1557,6 +1582,7 @@ files: | |
| 1557 1582 | 
             
            - spec/dummy/spec/features/javascripts
         | 
| 1558 1583 | 
             
            - spec/dummy/tmp/.gitkeep
         | 
| 1559 1584 | 
             
            - spec/features/auth_app_spec.rb
         | 
| 1585 | 
            +
            - spec/features/background_job_schedule_spec.rb
         | 
| 1560 1586 | 
             
            - spec/features/data_import_spec.rb
         | 
| 1561 1587 | 
             
            - spec/features/endpoint_access.rb
         | 
| 1562 1588 | 
             
            - spec/features/enum_spec.rb
         | 
| @@ -1592,6 +1618,7 @@ files: | |
| 1592 1618 | 
             
            - spec/lib/xl_spec.rb
         | 
| 1593 1619 | 
             
            - spec/lib/xl_styles_spec.rb
         | 
| 1594 1620 | 
             
            - spec/models/api_auth_spec.rb
         | 
| 1621 | 
            +
            - spec/models/background_job/schedule.rb
         | 
| 1595 1622 | 
             
            - spec/models/config_spec.rb
         | 
| 1596 1623 | 
             
            - spec/models/data_grid_spec.rb
         | 
| 1597 1624 | 
             
            - spec/models/event_spec.rb
         |