mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
many sidekiq fixes
This commit is contained in:
parent
185b7b7162
commit
9ff0a06029
1
Gemfile
1
Gemfile
@ -99,6 +99,7 @@ gem 'aasm'
|
|||||||
gem 'sidekiq', '>= 6.0.7'
|
gem 'sidekiq', '>= 6.0.7'
|
||||||
# Recurring jobs for Sidekiq
|
# Recurring jobs for Sidekiq
|
||||||
gem 'sidekiq-cron'
|
gem 'sidekiq-cron'
|
||||||
|
gem 'sidekiq-unique-jobs', '~> 6.0.22'
|
||||||
|
|
||||||
gem 'stripe', '5.1.1'
|
gem 'stripe', '5.1.1'
|
||||||
|
|
||||||
|
@ -389,6 +389,10 @@ GEM
|
|||||||
sidekiq-cron (1.1.0)
|
sidekiq-cron (1.1.0)
|
||||||
fugit (~> 1.1)
|
fugit (~> 1.1)
|
||||||
sidekiq (>= 4.2.1)
|
sidekiq (>= 4.2.1)
|
||||||
|
sidekiq-unique-jobs (6.0.22)
|
||||||
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
|
sidekiq (>= 4.0, < 7.0)
|
||||||
|
thor (~> 0)
|
||||||
simplecov (0.16.1)
|
simplecov (0.16.1)
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
json (>= 1.8, < 3)
|
json (>= 1.8, < 3)
|
||||||
@ -412,7 +416,7 @@ GEM
|
|||||||
ffi
|
ffi
|
||||||
term-ansicolor (1.7.1)
|
term-ansicolor (1.7.1)
|
||||||
tins (~> 1.0)
|
tins (~> 1.0)
|
||||||
thor (1.0.1)
|
thor (0.20.3)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.10)
|
tilt (2.0.10)
|
||||||
tins (1.24.1)
|
tins (1.24.1)
|
||||||
@ -517,6 +521,7 @@ DEPENDENCIES
|
|||||||
sha3
|
sha3
|
||||||
sidekiq (>= 6.0.7)
|
sidekiq (>= 6.0.7)
|
||||||
sidekiq-cron
|
sidekiq-cron
|
||||||
|
sidekiq-unique-jobs (~> 6.0.22)
|
||||||
spring
|
spring
|
||||||
spring-watcher-listen (~> 2.0.0)
|
spring-watcher-listen (~> 2.0.0)
|
||||||
stripe (= 5.1.1)
|
stripe (= 5.1.1)
|
||||||
|
@ -24,6 +24,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
|||||||
// number of invoices loaded each time we click on 'load more...'
|
// number of invoices loaded each time we click on 'load more...'
|
||||||
const INVOICES_PER_PAGE = 20;
|
const INVOICES_PER_PAGE = 20;
|
||||||
|
|
||||||
|
// fake stripe secret key
|
||||||
|
const STRIPE_SK_HIDDEN = 'sk_test_hidden-hidden-hidden-hid';
|
||||||
|
|
||||||
/* PUBLIC SCOPE */
|
/* PUBLIC SCOPE */
|
||||||
|
|
||||||
// default active tab
|
// default active tab
|
||||||
@ -173,7 +176,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
|||||||
$scope.allSettings = settings;
|
$scope.allSettings = settings;
|
||||||
|
|
||||||
// is the stripe private set?
|
// is the stripe private set?
|
||||||
$scope.stripeSecretKey = stripeSecretKey.isPresent;
|
$scope.stripeSecretKey = (stripeSecretKey.isPresent ? STRIPE_SK_HIDDEN : '');
|
||||||
|
|
||||||
// Placeholding date for the invoice creation
|
// Placeholding date for the invoice creation
|
||||||
$scope.today = moment();
|
$scope.today = moment();
|
||||||
@ -613,8 +616,8 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
|||||||
Setting.get({ name: 'stripe_public_key' }, function (res) {
|
Setting.get({ name: 'stripe_public_key' }, function (res) {
|
||||||
$scope.allSettings.stripe_public_key = res.setting.value;
|
$scope.allSettings.stripe_public_key = res.setting.value;
|
||||||
})
|
})
|
||||||
Setting.isPresent({ name: 'stripe_private_key' }, function (res) {
|
Setting.isPresent({ name: 'stripe_secret_key' }, function (res) {
|
||||||
$scope.stripeSecretKey = res.isPresent;
|
$scope.stripeSecretKey = (res.isPresent ? STRIPE_SK_HIDDEN : '');
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -841,7 +841,7 @@ angular.module('application.router', ['ui.router'])
|
|||||||
'accounting_Event_code', 'accounting_Event_label', 'accounting_Space_code', 'accounting_Space_label', \
|
'accounting_Event_code', 'accounting_Event_label', 'accounting_Space_code', 'accounting_Space_label', \
|
||||||
'feature_tour_display', 'online_payment_module', 'stripe_public_key']` }).$promise;
|
'feature_tour_display', 'online_payment_module', 'stripe_public_key']` }).$promise;
|
||||||
}],
|
}],
|
||||||
stripeSecretKey: ['Setting', function (Setting) { return Setting.isPresent({ name: 'stripe_private_key' }).$promise; }],
|
stripeSecretKey: ['Setting', function (Setting) { return Setting.isPresent({ name: 'stripe_secret_key' }).$promise; }],
|
||||||
invoices: [ 'Invoice', function (Invoice) {
|
invoices: [ 'Invoice', function (Invoice) {
|
||||||
return Invoice.list({
|
return Invoice.list({
|
||||||
query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 20 }
|
query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 20 }
|
||||||
|
@ -52,43 +52,45 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="alert alert-info" ng-bind-html="'app.admin.invoices.payment.stripe_keys_info_html' | translate"></div>
|
<div class="alert alert-info" ng-bind-html="'app.admin.invoices.payment.stripe_keys_info_html' | translate"></div>
|
||||||
<div class="row m-md">
|
<form name="stripeKeysForm">
|
||||||
<label for="stripe_public_key" class="control-label">{{ 'app.admin.invoices.payment.public_key' | translate }} *</label>
|
<div class="row m-md">
|
||||||
<div class="input-group">
|
<label for="stripe_public_key" class="control-label">{{ 'app.admin.invoices.payment.public_key' | translate }} *</label>
|
||||||
<span class="input-group-addon"><i class="fa fa-info"></i></span>
|
<div class="input-group">
|
||||||
<input type="text"
|
<span class="input-group-addon"><i class="fa fa-info"></i></span>
|
||||||
class="form-control"
|
<input type="text"
|
||||||
id="stripe_public_key"
|
class="form-control"
|
||||||
ng-model="publicKey"
|
id="stripe_public_key"
|
||||||
ng-model-options='{ debounce: 200 }'
|
ng-model="publicKey"
|
||||||
ng-change='testPublicKey()'
|
ng-model-options='{ debounce: 200 }'
|
||||||
required>
|
ng-change='testPublicKey()'
|
||||||
<span class="input-group-addon" ng-class="{'label-success': publicKeyStatus, 'label-danger text-white': !publicKeyStatus}" ng-show="publicKeyStatus !== undefined && publicKey">
|
required>
|
||||||
<i class="fa fa-times" ng-show="!publicKeyStatus"></i>
|
<span class="input-group-addon" ng-class="{'label-success': publicKeyStatus, 'label-danger text-white': !publicKeyStatus}" ng-show="publicKeyStatus !== undefined && publicKey">
|
||||||
<i class="fa fa-check" ng-show="publicKeyStatus"></i>
|
<i class="fa fa-times" ng-show="!publicKeyStatus"></i>
|
||||||
</span>
|
<i class="fa fa-check" ng-show="publicKeyStatus"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row m-md">
|
||||||
<div class="row m-md">
|
<label for="stripe_secret_key" class="control-label">{{ 'app.admin.invoices.payment.secret_key' | translate }} *</label>
|
||||||
<label for="stripe_secret_key" class="control-label">{{ 'app.admin.invoices.payment.secret_key' | translate }} *</label>
|
<div class="input-group">
|
||||||
<div class="input-group">
|
<span class="input-group-addon"><i class="fa fa-key"></i></span>
|
||||||
<span class="input-group-addon"><i class="fa fa-key"></i></span>
|
<input type="text"
|
||||||
<input type="text"
|
class="form-control"
|
||||||
class="form-control"
|
id="stripe_secret_key"
|
||||||
id="stripe_secret_key"
|
ng-model="secretKey"
|
||||||
ng-model="secretKey"
|
ng-model-options='{ debounce: 200 }'
|
||||||
ng-model-options='{ debounce: 200 }'
|
ng-change='testSecretKey()'
|
||||||
ng-change='testSecretKey()'
|
required>
|
||||||
required>
|
<span class="input-group-addon" ng-class="{'label-success': secretKeyStatus, 'label-danger text-white': !secretKeyStatus}" ng-show="secretKeyStatus !== undefined && secretKey">
|
||||||
<span class="input-group-addon" ng-class="{'label-success': secretKeyStatus, 'label-danger text-white': !secretKeyStatus}" ng-show="secretKeyStatus !== undefined && secretKey">
|
<i class="fa fa-times" ng-show="!secretKeyStatus"></i>
|
||||||
<i class="fa fa-times" ng-show="!secretKeyStatus"></i>
|
<i class="fa fa-check" ng-show="secretKeyStatus"></i>
|
||||||
<i class="fa fa-check" ng-show="secretKeyStatus"></i>
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
<button class="btn btn-warning" ng-click="ok()" ng-disabled="stripeKeysForm.$invalid" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ class API::SettingsController < API::ApiController
|
|||||||
render status: :not_modified and return if setting_params[:value] == @setting.value
|
render status: :not_modified and return if setting_params[:value] == @setting.value
|
||||||
|
|
||||||
if @setting.save && @setting.history_values.create(value: setting_params[:value], invoicing_profile: current_user.invoicing_profile)
|
if @setting.save && @setting.history_values.create(value: setting_params[:value], invoicing_profile: current_user.invoicing_profile)
|
||||||
SettingService.new.after_update(@setting)
|
SettingService.after_update(@setting)
|
||||||
render status: :ok
|
render status: :ok
|
||||||
else
|
else
|
||||||
render json: @setting.errors.full_messages, status: :unprocessable_entity
|
render json: @setting.errors.full_messages, status: :unprocessable_entity
|
||||||
@ -30,6 +30,7 @@ class API::SettingsController < API::ApiController
|
|||||||
|
|
||||||
db_setting = Setting.find_or_initialize_by(name: setting[:name])
|
db_setting = Setting.find_or_initialize_by(name: setting[:name])
|
||||||
db_setting.save && db_setting.history_values.create(value: setting[:value], invoicing_profile: current_user.invoicing_profile)
|
db_setting.save && db_setting.history_values.create(value: setting[:value], invoicing_profile: current_user.invoicing_profile)
|
||||||
|
SettingService.after_update(db_setting)
|
||||||
@settings.push db_setting
|
@settings.push db_setting
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Due to the way the controller updates the settings, we cannot safely use ActiveRecord's callbacks (eg. after_update, after_commit...)
|
# Due to the way the controller updates the settings, we cannot safely use ActiveRecord's callbacks (eg. after_update, after_commit...)
|
||||||
# so this service provides a wrapper around these operations.
|
# so this service provides a wrapper around these operations.
|
||||||
class SettingService
|
class SettingService
|
||||||
def after_update(setting)
|
def self.after_update(setting)
|
||||||
# update the stylesheet
|
# update the stylesheet
|
||||||
Stylesheet.theme&.rebuild! if %w[main_color secondary_color].include? setting.name
|
Stylesheet.theme&.rebuild! if %w[main_color secondary_color].include? setting.name
|
||||||
Stylesheet.home_page&.rebuild! if setting.name == 'home_css'
|
Stylesheet.home_page&.rebuild! if setting.name == 'home_css'
|
||||||
@ -13,6 +13,10 @@ class SettingService
|
|||||||
NotifyPrivacyUpdateWorker.perform_async(id) if setting.name == 'privacy_body'
|
NotifyPrivacyUpdateWorker.perform_async(id) if setting.name == 'privacy_body'
|
||||||
|
|
||||||
# sync all users on stripe
|
# sync all users on stripe
|
||||||
StripeWorker.perform_async(:sync_members) if %w[stripe_public_key stripe_secret_key].include? setting.name
|
return unless %w[stripe_public_key stripe_secret_key].include? setting.name
|
||||||
|
|
||||||
|
SyncMembersOnStripeWorker.perform_async(
|
||||||
|
setting.history_values.last&.invoicing_profile&.user&.id
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,6 @@ class AvailabilityIndexerWorker
|
|||||||
include Sidekiq::Worker
|
include Sidekiq::Worker
|
||||||
sidekiq_options queue: 'elasticsearch', retry: true
|
sidekiq_options queue: 'elasticsearch', retry: true
|
||||||
|
|
||||||
Logger = Sidekiq.logger.level == Logger::DEBUG ? Sidekiq.logger : nil
|
|
||||||
Client = Elasticsearch::Model.client
|
Client = Elasticsearch::Model.client
|
||||||
|
|
||||||
def perform(operation, record_id)
|
def perform(operation, record_id)
|
||||||
@ -14,13 +13,13 @@ class AvailabilityIndexerWorker
|
|||||||
record = Availability.find(record_id)
|
record = Availability.find(record_id)
|
||||||
Client.index index: Availability.index_name, type: Availability.document_type, id: record.id, body: record.as_indexed_json
|
Client.index index: Availability.index_name, type: Availability.document_type, id: record.id, body: record.as_indexed_json
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
STDERR.puts "Availability id(#{record_id}) will not be indexed in ElasticSearch as it does not exists anymore in database"
|
logger.warn "Availability id(#{record_id}) will not be indexed in ElasticSearch as it does not exists anymore in database"
|
||||||
end
|
end
|
||||||
when /delete/
|
when /delete/
|
||||||
begin
|
begin
|
||||||
Client.delete index: Availability.index_name, type: Availability.document_type, id: record_id
|
Client.delete index: Availability.index_name, type: Availability.document_type, id: record_id
|
||||||
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
||||||
STDERR.puts "Availability id(#{record_id}) will not be deleted form ElasticSearch as it has not been already indexed"
|
logger.warn "Availability id(#{record_id}) will not be deleted form ElasticSearch as it has not been already indexed"
|
||||||
end
|
end
|
||||||
else raise ArgumentError, "Unknown operation '#{operation}'"
|
else raise ArgumentError, "Unknown operation '#{operation}'"
|
||||||
end
|
end
|
||||||
|
@ -5,8 +5,6 @@ class OpenlabWorker
|
|||||||
include Sidekiq::Worker
|
include Sidekiq::Worker
|
||||||
sidekiq_options queue: 'default', retry: true
|
sidekiq_options queue: 'default', retry: true
|
||||||
|
|
||||||
LOGGER = Sidekiq.logger.level == Logger::DEBUG ? Sidekiq.logger : nil
|
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
client = Openlab::Client.new(app_secret: Setting.get('openlab_app_secret'))
|
client = Openlab::Client.new(app_secret: Setting.get('openlab_app_secret'))
|
||||||
@projets = Openlab::Projects.new(client)
|
@projets = Openlab::Projects.new(client)
|
||||||
@ -14,7 +12,7 @@ class OpenlabWorker
|
|||||||
end
|
end
|
||||||
|
|
||||||
def perform(action, project_id)
|
def perform(action, project_id)
|
||||||
LOGGER&.debug ['Openlab sync', action, "project ID: #{project_id}"]
|
logger.debug ['Openlab sync', action, "project ID: #{project_id}"]
|
||||||
|
|
||||||
case action.to_s
|
case action.to_s
|
||||||
when /create/
|
when /create/
|
||||||
@ -29,6 +27,6 @@ class OpenlabWorker
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
LOGGER&.debug ['Openlab sync', 'RESPONSE ERROR', response.inspect] unless response.success?
|
logger.debug ['Openlab sync', 'RESPONSE ERROR', response.inspect] unless response.success?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,8 +5,6 @@ class StripeWorker
|
|||||||
include Sidekiq::Worker
|
include Sidekiq::Worker
|
||||||
sidekiq_options queue: :stripe
|
sidekiq_options queue: :stripe
|
||||||
|
|
||||||
LOGGER = Sidekiq.logger.level == Logger::DEBUG ? Sidekiq.logger : nil
|
|
||||||
|
|
||||||
def perform(action, *params)
|
def perform(action, *params)
|
||||||
send(action, *params)
|
send(action, *params)
|
||||||
end
|
end
|
||||||
@ -43,24 +41,4 @@ class StripeWorker
|
|||||||
cpn = Stripe::Coupon.retrieve(coupon_code)
|
cpn = Stripe::Coupon.retrieve(coupon_code)
|
||||||
cpn.delete
|
cpn.delete
|
||||||
end
|
end
|
||||||
|
|
||||||
def sync_members
|
|
||||||
LOGGER&.debug ['StripeWorker', 'SyncMembers', 'We create all non-existing customers on stripe. This may take a while...']
|
|
||||||
total = User.online_payers.count
|
|
||||||
User.online_payers.each_with_index do |member, index|
|
|
||||||
LOGGER&.debug ['StripeWorker', 'SyncMembers' "#{index} / #{total}"]
|
|
||||||
begin
|
|
||||||
stp_customer = Stripe::Customer.retrieve member.stp_customer_id
|
|
||||||
create_stripe_customer(member.id) if stp_customer.nil? || stp_customer[:deleted]
|
|
||||||
rescue Stripe::InvalidRequestError
|
|
||||||
create_stripe_customer(member.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
LOGGER&.debug ['StripeWorker', 'SyncMembers', 'Sync is done']
|
|
||||||
notify_user = Setting.find_by(name: 'stripe_secret_key')&.history_values&.last&.invoicing_profile&.user
|
|
||||||
return unless notify_user
|
|
||||||
|
|
||||||
NotificationCenter.call type: :notify_admin_members_stripe_sync,
|
|
||||||
receiver: notify_user
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
27
app/workers/sync_members_on_stripe_worker.rb
Normal file
27
app/workers/sync_members_on_stripe_worker.rb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# This worker perform various requests to the Stripe API (payment service)
|
||||||
|
class SyncMembersOnStripeWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
sidekiq_options lock: :until_executed, on_conflict: :reject, queue: :stripe
|
||||||
|
|
||||||
|
def perform(notify_user_id = nil)
|
||||||
|
logger.debug 'We create all non-existing customers on stripe. This may take a while...'
|
||||||
|
total = User.online_payers.count
|
||||||
|
User.online_payers.each_with_index do |member, index|
|
||||||
|
logger.debug "#{index} / #{total}"
|
||||||
|
begin
|
||||||
|
stp_customer = Stripe::Customer.retrieve member.stp_customer_id
|
||||||
|
StripeWorker.perform_async(:create_stripe_customer, member.id) if stp_customer.nil? || stp_customer[:deleted]
|
||||||
|
rescue Stripe::InvalidRequestError
|
||||||
|
StripeWorker.perform_async(:create_stripe_customer, member.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
logger.debug 'Sync is done'
|
||||||
|
return unless notify_user_id
|
||||||
|
|
||||||
|
logger.debug "Notify user #{notify_user_id}"
|
||||||
|
NotificationCenter.call type: :notify_admin_members_stripe_sync,
|
||||||
|
receiver: User.find(notify_user_id)
|
||||||
|
end
|
||||||
|
end
|
@ -3,6 +3,9 @@
|
|||||||
# Will check the application version to ensure it is up-to-date
|
# Will check the application version to ensure it is up-to-date
|
||||||
class VersionCheckWorker
|
class VersionCheckWorker
|
||||||
include Sidekiq::Worker
|
include Sidekiq::Worker
|
||||||
|
sidekiq_options lock: :until_executed,
|
||||||
|
on_conflict: :reject,
|
||||||
|
queue: :system
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
require 'fab_hub'
|
require 'fab_hub'
|
||||||
@ -10,7 +13,7 @@ class VersionCheckWorker
|
|||||||
res = FabHub.fab_manager_version_check
|
res = FabHub.fab_manager_version_check
|
||||||
rescue Errno::ECONNREFUSED => e
|
rescue Errno::ECONNREFUSED => e
|
||||||
if Rails.env.development?
|
if Rails.env.development?
|
||||||
puts "Unable to check the version, maybe FabHub is not running: #{e}"
|
logger.warn "Unable to check the version, maybe FabHub is not running: #{e}"
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'sidekiq/web'
|
require 'sidekiq_unique_jobs/web'
|
||||||
require 'sidekiq/cron/web'
|
require 'sidekiq/cron/web'
|
||||||
|
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
|
@ -49,7 +49,7 @@ namespace :fablab do
|
|||||||
desc 'sync users to the stripe database'
|
desc 'sync users to the stripe database'
|
||||||
task sync_members: :environment do
|
task sync_members: :environment do
|
||||||
puts 'We create all non-existing customers on stripe. This may take a while, please wait...'
|
puts 'We create all non-existing customers on stripe. This may take a while, please wait...'
|
||||||
StripeWorker.perform(:sync_members)
|
SyncMembersOnStripeWorker.perform
|
||||||
puts 'Done'
|
puts 'Done'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user