rails_nexus 2.0.2 → 2.0.6

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.
@@ -4,50 +4,106 @@ module RailsNexus
4
4
  class BackupConfig < BaseRecord
5
5
  self.table_name = "rails_nexus_backup_configs"
6
6
 
7
- ADAPTERS = %w[mysql postgresql sqlite].freeze
7
+ ADAPTERS = %w[mysql postgresql sqlite mongodb redis].freeze
8
+
9
+ # ─── Boolean defaults ──────────────────────────────────────────
10
+ # Rails doesn't apply DB defaults to new in-memory records, so
11
+ # check_box helpers in form_for render unchecked. These declarations
12
+ # ensure the form reflects the intended defaults.
13
+ attribute :enabled, :boolean, default: true
14
+ attribute :compress, :boolean, default: true
15
+ attribute :encrypted, :boolean, default: false
16
+ attribute :rsync_enabled, :boolean, default: false
17
+ attribute :rsync_mirror, :boolean, default: false
18
+ attribute :notify_on_success, :boolean, default: true
19
+ attribute :notify_on_failure, :boolean, default: true
20
+ attribute :s3_enabled, :boolean, default: false
21
+ attribute :gpg_enabled, :boolean, default: false
22
+ attribute :email_notify, :boolean, default: false
23
+ attribute :archive_enabled, :boolean, default: false
24
+ attribute :bzip2_compress, :boolean, default: false
25
+ attribute :split_chunks, :boolean, default: false
8
26
 
9
27
  validates :name, presence: true, uniqueness: true
10
- validates :database_name, presence: true
28
+ validates :database_name, presence: true, if: -> { adapter != "redis" }
11
29
  validates :adapter, presence: true, inclusion: { in: ADAPTERS }
12
30
  validates :storage_path, presence: true
13
31
  validates :keep_count, numericality: { greater_than: 0 }
14
- validates :encrypt_password, presence: true, if: :encrypt?
32
+ validates :encryption_password, presence: true, if: :encrypted?
15
33
  validates :rsync_host, presence: true, if: :rsync_enabled?
16
34
  validates :rsync_user, presence: true, if: :rsync_enabled?
35
+ validates :s3_bucket, presence: true, if: :s3_enabled?
36
+ validates :s3_access_key, presence: true, if: :s3_enabled?
37
+ validates :s3_secret_key, presence: true, if: :s3_enabled?
38
+ validates :gpg_password, presence: true, if: :gpg_enabled?
39
+ validates :email_to, presence: true, if: :email_notify?
17
40
 
18
41
  scope :enabled, -> { where(enabled: true) }
19
42
  scope :disabled, -> { where(enabled: false) }
20
43
 
21
44
  serialize :skip_tables, coder: JSON
45
+ serialize :archive_paths, coder: JSON
46
+ serialize :archive_excludes, coder: JSON
22
47
 
48
+ # ─── Skip Tables ───────────────────────────────────────────────
23
49
  def skip_tables_list
24
50
  return [] if skip_tables.blank?
25
51
  skip_tables.is_a?(Array) ? skip_tables : JSON.parse(skip_tables.to_s) rescue []
26
52
  end
27
53
 
28
- def skip_tables_list=(list)
29
- self.skip_tables = list
54
+ def skip_tables_list=(value)
55
+ return if value.blank?
56
+ self.skip_tables = if value.is_a?(String)
57
+ value.split(",").map(&:strip).reject(&:blank?)
58
+ else
59
+ value
60
+ end
30
61
  end
31
62
 
32
- def mysql?
33
- adapter == "mysql"
63
+ # ─── Archive Paths ─────────────────────────────────────────────
64
+ def archive_paths_list
65
+ return [] if archive_paths.blank?
66
+ archive_paths.is_a?(Array) ? archive_paths : JSON.parse(archive_paths.to_s) rescue []
34
67
  end
35
68
 
36
- def postgresql?
37
- adapter == "postgresql"
69
+ def archive_paths_list=(value)
70
+ return if value.blank?
71
+ self.archive_paths = if value.is_a?(String)
72
+ value.split(",").map(&:strip).reject(&:blank?)
73
+ else
74
+ value
75
+ end
38
76
  end
39
77
 
40
- def sqlite?
41
- adapter == "sqlite"
78
+ def archive_excludes_list
79
+ return [] if archive_excludes.blank?
80
+ archive_excludes.is_a?(Array) ? archive_excludes : JSON.parse(archive_excludes.to_s) rescue []
42
81
  end
43
82
 
83
+ def archive_excludes_list=(value)
84
+ return if value.blank?
85
+ self.archive_excludes = if value.is_a?(String)
86
+ value.split(",").map(&:strip).reject(&:blank?)
87
+ else
88
+ value
89
+ end
90
+ end
91
+
92
+ # ─── Adapter checks ────────────────────────────────────────────
93
+ def mysql?; adapter == "mysql"; end
94
+ def postgresql?; adapter == "postgresql"; end
95
+ def sqlite?; adapter == "sqlite"; end
96
+ def mongodb?; adapter == "mongodb"; end
97
+ def redis?; adapter == "redis"; end
98
+
99
+ # ─── Path helpers ──────────────────────────────────────────────
44
100
  def storage_path_expanded
45
101
  storage_path.gsub("~", Dir.home)
46
102
  end
47
103
 
48
104
  def dump_filename
49
105
  timestamp = Time.current.strftime("%Y%m%d_%H%M%S")
50
- ext = compress? ? "sql.gz" : "sql"
106
+ ext = dump_extension
51
107
  "#{name}_#{timestamp}.#{ext}"
52
108
  end
53
109
 
@@ -55,12 +111,11 @@ module RailsNexus
55
111
  File.join(storage_path_expanded, dump_filename)
56
112
  end
57
113
 
58
- # Get recent backup records for this config
114
+ # ─── Stats ─────────────────────────────────────────────────────
59
115
  def recent_backups(limit: 10)
60
116
  RailsNexus::Backup.where(model_name: name).order(started_at: :desc).limit(limit)
61
117
  end
62
118
 
63
- # Summary stats
64
119
  def stats
65
120
  backups = RailsNexus::Backup.where(model_name: name)
66
121
  recent = backups.where("started_at >= ?", 7.days.ago)
@@ -79,6 +134,14 @@ module RailsNexus
79
134
 
80
135
  private
81
136
 
137
+ def dump_extension
138
+ parts = ["sql"]
139
+ parts << "gz" if compress? && !bzip2_compress?
140
+ parts << "bz2" if bzip2_compress?
141
+ parts << "enc" if encrypted?
142
+ parts.join(".")
143
+ end
144
+
82
145
  def human_size(bytes)
83
146
  return "0 B" if bytes.zero?
84
147
  units = %w[B KB MB GB TB]