web47core 0.0.9 → 0.0.10

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