web47core 0.0.9 → 0.0.10

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.
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Objects that can localize time to it, kicking out safe uses of a date format.
5
+ #
6
+ module TimeZoneAble
7
+ extend ActiveSupport::Concern
8
+
9
+ def self.included(base)
10
+ base.class_eval do
11
+ #
12
+ # Fields
13
+ #
14
+ field :time_zone, type: String
15
+ #
16
+ # Validations
17
+ #
18
+ validates :time_zone, inclusion: TZInfo::Timezone.all_identifiers, presence: true
19
+ #
20
+ # Callbacks
21
+ #
22
+ before_validation :default_time_zone
23
+ end
24
+ end
25
+
26
+ #
27
+ # Return the given time in the localized time for this object
28
+ #
29
+ def local_time(time, format = :medium, default = 'N/A')
30
+ tz = TZInfo::Timezone.get(time_zone.presence || SystemConfiguration.default_time_zone)
31
+ time.present? ? I18n.l(time.in_time_zone(tz), format: format) : default
32
+ rescue StandardError
33
+ default
34
+ end
35
+
36
+ #
37
+ # Return the updated_at if found, otherwise return the created_at. If neither are there
38
+ # then return unknown
39
+ #
40
+ def local_updated_time(obj, format = :medium, default = 'N/A')
41
+ obj.updated_at.present? ? local_time(obj.updated_at, format, default) : local_time(created_at, format, default)
42
+ rescue StandardError
43
+ default
44
+ end
45
+
46
+ def default_time_zone
47
+ self.time_zone ||= SystemConfiguration.default_time_zone
48
+ end
49
+ end
@@ -97,9 +97,9 @@ class Notification
97
97
  #
98
98
  # Finish processing the notification successfully
99
99
  #
100
- def finish_processing(message = nil)
101
- if message.present?
102
- set state: STATE_INVALID, error_message: message
100
+ def finish_processing(processing_message = nil)
101
+ if processing_message.present?
102
+ set state: STATE_INVALID, error_message: processing_message
103
103
  else
104
104
  set state: STATE_PROCESSED, error_message: ''
105
105
  end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Easily fetch the redis configuration from redis.yml in the config directory.
5
+ # There are several formats to support
6
+ #
7
+ # URL with single server
8
+ # development:
9
+ # url: 'redis://localhost:6379/0'
10
+ #
11
+ # Host/port combination for single server
12
+ # development:
13
+ # host: localhost
14
+ # port: 6379
15
+ # db: 0
16
+ #
17
+ # Sentinel
18
+ # development:
19
+ # master: production
20
+ # sentinels:
21
+ # - host1:6379
22
+ # - host2:6379
23
+ # - host3:6379
24
+ # role: master
25
+ #
26
+ # Available for all options
27
+ # connect_timeout: 0.2
28
+ # read_timeout: 0.2
29
+ # write_timeout: 0.2
30
+ # timeout: 1
31
+ #
32
+ class RedisConfiguration
33
+ #
34
+ # Methods are static
35
+ #
36
+ class << self
37
+ #
38
+ # Load the configuration using the given DB
39
+ #
40
+ # Trying first the URL, then host, then sentinel, then default method
41
+ #
42
+ def load(database = nil)
43
+ load_url(database) || load_host(database) || load_sentinel(database) || load_default(database)
44
+ end
45
+
46
+ private
47
+
48
+ #
49
+ # Load the base set of parameters from the config file
50
+ #
51
+ def load_base(raw_config)
52
+ base = {}
53
+ %i[connect_timeout namespace read_timeout write_timeout timeout].each do |key|
54
+ base[key] = raw_config[key.to_s] unless raw_config[key.to_s].nil?
55
+ end
56
+ base
57
+ end
58
+
59
+ #
60
+ # Load a default configuration with the given database
61
+ #
62
+ def load_default(database = 0)
63
+ { host: '127.0.0.1', port: 6_379, db: (database || 0) }
64
+ end
65
+
66
+ #
67
+ # Load the url
68
+ #
69
+ def load_url(database = 0)
70
+ raw_config = load_file
71
+ return if raw_config.nil? || raw_config['url'].nil?
72
+
73
+ config = load_base(raw_config)
74
+ config[:url] = raw_config['url']
75
+ config[:db] = (database || 0)
76
+ config
77
+ end
78
+
79
+ #
80
+ # Load the given host
81
+ #
82
+ def load_host(database = nil)
83
+ raw_config = load_file
84
+ return if raw_config.nil? || raw_config['host'].nil?
85
+
86
+ config = load_base(raw_config)
87
+ config[:host] = raw_config['host']
88
+ config[:port] = raw_config['port'] || 6_379
89
+ config[:db] = database || raw_config['db'] || 0
90
+ config
91
+ end
92
+
93
+ #
94
+ # Load the sentinel configuration
95
+ #
96
+ def load_sentinel(database = 0)
97
+ raw_config = load_file
98
+ return if raw_config.nil? || raw_config['master'].nil?
99
+
100
+ config = load_base(raw_config)
101
+ config[:url] = "redis://#{raw_config['master']}"
102
+ config[:sentinels] = raw_config['sentinels'].collect do |sentinel|
103
+ parts = sentinel.split(':')
104
+ host = parts.first
105
+ port = parts.count.eql?(2) ? parts.last : 26_379
106
+ { host: host, port: port }
107
+ end
108
+ config[:db] = database || 0
109
+ config[:role] = raw_config['role'] || 'master'
110
+ config
111
+ end
112
+
113
+ #
114
+ # Return the config file
115
+ #
116
+ def config_file_path
117
+ File.expand_path('config/redis.yml')
118
+ end
119
+
120
+ #
121
+ # Load the config/redis.yml and return the environment name
122
+ #
123
+ def load_file
124
+ config = nil
125
+ file_path = config_file_path
126
+ if File.exist? file_path
127
+ yaml_data = YAML.load_file(file_path)
128
+ config = yaml_data[Rails.env] if yaml_data
129
+ end
130
+
131
+ config
132
+ rescue StandardError => error
133
+ puts "Error loading #{config_file_path} file", error
134
+ nil # return nothing if there is an error
135
+ end
136
+ end
137
+ end
@@ -31,38 +31,24 @@ class SlackNotification < Notification
31
31
  # The slack username to use
32
32
  field :from, type: String
33
33
 
34
- def deliver_message!
35
- return unless SystemConfiguration.slack_configured?
36
-
37
- start_processing
38
- payload = { text: message }
39
- payload[:channel] = if to.present?
40
- to
41
- elsif SystemConfiguration.slack_support_channel.present?
42
- SystemConfiguration.slack_support_channel
43
- else
44
- 'support'
45
- end
46
- # Use the environment as the default, otherwise set it as the from
47
- payload[:username] = from.presence || Rails.env
48
- # Setup the delivery method for this message only.
49
- RestClient.post(SystemConfiguration.slack_api_url, payload.to_json)
50
- finish_processing
34
+ def deliver_message
35
+ if SystemConfiguration.slack_configured?
36
+ start_processing
37
+ payload = { text: message }
38
+ payload[:channel] = to.presence || SystemConfiguration.slack_support_channel
39
+ # Use the environment as the default, otherwise set it as the from
40
+ payload[:username] = from.presence || Rails.env
41
+ # Setup the delivery method for this message only.
42
+ RestClient.post(SystemConfiguration.slack_api_url, payload.to_json)
43
+ finish_processing
44
+ else
45
+ finish_processing 'Slack is not configured'
46
+ end
51
47
  rescue StandardError => error
52
- App47Logger.log_debug '!!! Error sending SLACK notification !!!'
53
- App47Logger.log_debug error.message
54
- App47Logger.log_debug error.backtrace
55
- App47Logger.log_debug '!!! Error sending SLACK notification !!!'
48
+ log_warn '!!! Error sending SLACK notification !!!', error
56
49
  finish_processing error.message
57
50
  end
58
51
 
59
- #
60
- # Limit the number of times the slack notification is retried
61
- #
62
- def max_retries
63
- 1
64
- end
65
-
66
52
  #
67
53
  # Default delivery channel is email, override for sms, SMTP or other channels
68
54
  #
@@ -74,8 +60,6 @@ class SlackNotification < Notification
74
60
  # Convenience method to say something when we see something
75
61
  #
76
62
  def self.say(message, to: nil, from: nil, template: nil)
77
- return unless SystemConfiguration.slack_configured?
78
-
79
63
  notification = SlackNotification.new(to: to, from: from)
80
64
  notification.message = if template.present?
81
65
  notification.message_from_template template, message
@@ -26,9 +26,7 @@ class SmsNotification < Notification
26
26
  #
27
27
  field :sid, type: String
28
28
 
29
- validates_format_of :to, with: %r{\A\+[1-9]{1}[0-9]{3,14}\z}, message: 'Invalid phone number'
30
- validates_presence_of :to
31
- validates_presence_of :account_id
29
+ validates :to, presence: true, format: { with: /\A\+[1-9]{1}[0-9]{3,14}\z/ }
32
30
 
33
31
  def deliver_message!
34
32
  return unless SystemConfiguration.twilio_configured?
@@ -38,13 +36,13 @@ class SmsNotification < Notification
38
36
  auth_token = config.twilio_auth_token
39
37
  client = Twilio::REST::Client.new account_sid, auth_token
40
38
 
41
- message = client.account.messages.create(
42
- body: self.message,
43
- to: self.to,
39
+ twilio_message = client.account.messages.create(
40
+ body: message,
41
+ to: to,
44
42
  from: config.twilio_phone_number
45
43
  )
46
44
  # We are saved in the calling class, no reason to save again
47
- set sid: message.sid
45
+ set sid: twilio_message.sid
48
46
  end
49
47
 
50
48
  #
@@ -28,7 +28,6 @@ class SmtpConfiguration
28
28
  # Callbacks
29
29
  #
30
30
  before_save :update_token
31
- #after_save :send_smtp_verification
32
31
 
33
32
  #
34
33
  # If we can use this SMTP configuration or not, it must be confirmed and
@@ -38,111 +37,37 @@ class SmtpConfiguration
38
37
  confirmed? && active?
39
38
  end
40
39
 
40
+ #
41
+ # Which fields to protect
42
+ #
41
43
  def secure_fields
42
44
  super + %i[password]
43
45
  end
44
46
 
47
+ #
48
+ # Validate the token, returning true of false if valid
49
+ #
45
50
  def validate_token(token)
46
- valid = false
47
- unless confirmation_token.nil?
48
- if confirmation_token.eql? token
49
- valid = true
50
- unset(:confirmation_token)
51
- unset(:verification_message)
52
- end
53
- end
51
+ valid = if confirmation_token.present? && confirmation_token.eql?(token)
52
+ unset(:confirmation_token, :verification_message)
53
+ true
54
+ else
55
+ false
56
+ end
54
57
  set(confirmed: valid)
55
58
  valid
56
59
  end
57
60
 
58
61
  #
59
62
  # Update the token on save if we are active and the token is not already set.
63
+ #
60
64
  def update_token
61
65
  if active?
62
- set(confirmation_token: Devise.friendly_token) if confirmation_token.nil?
66
+ set(confirmation_token: Digest::SHA256.hexdigest("#{id}_#{account.id}")) if confirmation_token.nil?
63
67
  set(confirmed: false)
64
68
  set(verification_message: 'Sending SMTP verification email(s) to SMTP admins.')
65
69
  else
66
70
  set(verification_message: 'SMTP Configuration is not active, no verification email will be sent.')
67
71
  end
68
72
  end
69
-
70
- def send_smtp_verification
71
- if self.active?
72
- sent_to= []
73
- self.account.smtp_admins.each do |admin|
74
- sent_to << admin.email if self.send_confirmation(admin)
75
- end
76
- if sent_to.empty?
77
- set(verification_message: "No confirmations emails sent: (#{verification_message}).")
78
- else
79
- set(verification_message: "Confirmation emails sent to SMTP admins: #{sent_to.join(", ")}")
80
- end
81
- end
82
- end
83
-
84
- def send_confirmation(member)
85
- sent = false
86
- begin
87
- mail = Mail.new
88
- # Set the from line
89
- mail.from = email_address
90
-
91
- # Set the to address
92
- mail.to = member.email
93
-
94
- # Set the subject line
95
- mail.subject = 'Verify SMTP configuration change'
96
-
97
- # set the message body and send
98
- html_message = build_message
99
- mail.html_part do
100
- content_type 'text/html; charset=UTF-8'
101
- body html_message
102
- end
103
-
104
- # Setup the delivery method for this message only.
105
- if Rails.env.test?
106
- mail.delivery_method :test
107
- else
108
- config = { address: self.server_name,
109
- port: self.port,
110
- authentication: self.authentication_method.to_sym,
111
- enable_starttls_auto: self.ssl.eql?(true) }
112
- config[:domain] = self.domain unless self.domain.nil? or self.domain.empty?
113
- config[:user_name] = self.username unless self.username.nil? or self.username.empty?
114
- config[:password] = self.password unless self.password.nil? or self.password.empty?
115
-
116
- mail.delivery_method :smtp, config
117
- end
118
-
119
- # Deliver it
120
- mail.deliver
121
- sent = true
122
-
123
- rescue Exception=>e
124
- App47::Logger.log_error "Unable to send SMTP confirmation email #{e.message}"
125
- App47::Logger.log_error e.backtrace
126
- set(verification_message: "Unable to send verification email to #{member.email}, error: #{e.message}")
127
- end
128
- sent
129
- end
130
-
131
- def build_message
132
- template = File.read(Rails.root.join('app', 'assets', 'templates', 'email', "verify_smtp_configuration.liquid"))
133
- engine = Liquid::Template.parse(template)
134
- engine.render({
135
- 'account_name' => account.name,
136
- 'confirmation_url' => "#{SystemConfiguration.webui_url}/smtp_configuration/confirm_change?token=#{confirmation_token}"
137
- })
138
- end
139
-
140
- def to_yaml_properties(wrap = true)
141
- if wrap
142
- self.class.new.to_yaml_properties(false)
143
- else
144
- super()
145
- end
146
- end
147
-
148
73
  end
@@ -1,8 +1,12 @@
1
1
  require 'app/models/concerns/app47_logger'
2
2
  require 'app/models/concerns/cdn_url'
3
+ require 'app/models/concerns/email_able'
4
+ require 'app/models/concerns/search_able'
5
+ require 'app/models/concerns/time_zone_able'
3
6
  require 'app/models/concerns/standard_model'
4
7
  require 'app/models/concerns/core_system_configuration'
5
8
  require 'app/models/concerns/core_account'
9
+ require 'app/models/redis_configuration'
6
10
  require 'app/models/notification'
7
11
  require 'app/models/template'
8
12
  require 'app/models/notification_template'
@@ -0,0 +1,5 @@
1
+ test:
2
+ host: 127.0.0.1
3
+ port: 6378
4
+ db: 8
5
+ namespace: 'cache'
@@ -0,0 +1,8 @@
1
+ test:
2
+ host: 127.0.0.2
3
+ port: 6372
4
+ db: 7
5
+ connect_timeout: 0.2
6
+ read_timeout: 0.2
7
+ write_timeout: 0.2
8
+ timeout: 1