postfix_admin 0.2.0 → 0.3.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.
@@ -1,10 +1,12 @@
1
1
  require 'yaml'
2
2
  require 'postfix_admin'
3
3
  require 'postfix_admin/doveadm'
4
+ require 'terminal-table'
4
5
 
5
6
  module PostfixAdmin
6
7
  class CLI
7
- @config_file = '~/.postfix_admin.conf'
8
+ DEFAULT_CONFIG_PATH = '~/.postfix_admin.conf'
9
+ @config_file = DEFAULT_CONFIG_PATH
8
10
  MIN_NUM_PASSWORD_CHARACTER = 5
9
11
 
10
12
  def initialize
@@ -28,55 +30,49 @@ module PostfixAdmin
28
30
  name = name.downcase if name
29
31
 
30
32
  if name =~ /@/
33
+ # address like argument
31
34
  if Admin.exists?(name)
32
- show_admin_details(name)
33
- end
34
-
35
- if Mailbox.exists?(name)
36
- show_account_details(name)
35
+ # admin
36
+ show_admin_details(name, display_password: true)
37
+ puts
38
+ show_admin_domain(name)
39
+ elsif Mailbox.exists?(name)
40
+ # mailbox
41
+ show_account_details(name, display_password: true)
37
42
  elsif Alias.exists?(name)
43
+ # alias
38
44
  show_alias_details(name)
45
+ else
46
+ raise Error, "Could not find admin/mailbox/alias #{name}"
39
47
  end
40
48
 
41
49
  return
42
50
  end
43
51
 
44
52
  show_summary(name)
53
+ puts
45
54
 
46
55
  if name
47
- show_admin(name)
48
- show_address(name)
49
- show_alias(name)
56
+ # domain name
57
+ show_domain_details(name)
50
58
  else
59
+ # no argument: show all domains and admins
51
60
  show_domain
61
+ puts
52
62
  show_admin
53
63
  end
54
64
  end
55
65
 
56
66
  def show_summary(domain_name = nil)
57
- title = "Summary"
58
67
  if domain_name
59
- domain_name = domain_name.downcase
60
- domain_check(domain_name)
61
- title = "Summary of #{domain_name}"
62
- end
63
-
64
- report(title) do
65
- if domain_name
66
- domain = Domain.find(domain_name)
67
- puts "Mailboxes : %4d / %4s" % [domain.rel_mailboxes.count, max_str(domain.mailboxes)]
68
- puts "Aliases : %4d / %4s" % [domain.pure_aliases.count, max_str(domain.aliases)]
69
- puts "Max Quota : %4d MB" % domain.maxquota
70
- puts "Active : %3s" % domain.active_str
71
- else
72
- puts "Domains : %4d" % Domain.without_all.count
73
- puts "Admins : %4d" % Admin.count
74
- puts "Mailboxes : %4d" % Mailbox.count
75
- puts "Aliases : %4d" % Alias.pure.count
76
- end
68
+ show_domain_summary(domain_name)
69
+ else
70
+ show_general_summary
77
71
  end
78
72
  end
79
73
 
74
+ # Set up a domain
75
+ # Add a domain, add an admin, and grant the admin access to the domain
80
76
  def setup_domain(domain_name, password)
81
77
  admin = "admin@#{domain_name}"
82
78
  add_domain(domain_name)
@@ -84,62 +80,75 @@ module PostfixAdmin
84
80
  add_admin_domain(admin, domain_name)
85
81
  end
86
82
 
87
- def show_account_details(user_name)
83
+ def show_account_details(user_name, display_password: false)
88
84
  account_check(user_name)
89
85
  mailbox = Mailbox.find(user_name)
90
86
  mail_alias = Alias.find(user_name)
91
87
 
92
- report("Mailbox") do
93
- puts "Address : %s" % mailbox.username
94
- puts "Name : %s" % mailbox.name
95
- puts "Password : %s" % mailbox.password
96
- puts "Quota : %d MB" % max_str(mailbox.quota / KB_TO_MB)
97
- puts "Go to : %s" % mail_alias.goto
98
- puts "Active : %s" % mailbox.active_str
99
- end
88
+ rows = []
89
+ puts_title("Mailbox")
90
+ rows << ["Address", mailbox.username]
91
+ rows << ["Name", mailbox.name]
92
+ rows << ["Password", mailbox.password] if display_password
93
+ rows << ["Quota (MB)", mailbox.quota_mb_str]
94
+ rows << ["Go to", mail_alias.goto]
95
+ rows << ["Active", mailbox.active_str]
96
+
97
+ puts_table(rows: rows)
100
98
  end
101
99
 
102
- def show_admin_details(name)
100
+ def show_admin_details(name, display_password: false)
103
101
  admin_check(name)
104
102
  admin = Admin.find(name)
105
103
 
106
- report("Admin") do
107
- puts "Name : %s" % admin.username
108
- puts "Password : %s" % admin.password
109
- puts "Domains : %s" % (admin.super_admin? ? "ALL" : admin.rel_domains.count)
110
- puts "Role : %s" % (admin.super_admin? ? "Super admin" : "Admin")
111
- puts "Active : %s" % admin.active_str
112
- end
104
+ rows = []
105
+ puts_title("Admin")
106
+ rows << ["Name", admin.username]
107
+ rows << ["Password", admin.password] if display_password
108
+ rows << ["Domains", admin.super_admin? ? "ALL" : admin.rel_domains.count.to_s]
109
+ rows << ["Role", admin.super_admin? ? "Super Admin" : "Standard Admin"]
110
+ rows << ["Active", admin.active_str]
111
+
112
+ puts_table(rows: rows)
113
113
  end
114
114
 
115
115
  def show_alias_details(name)
116
116
  alias_check(name)
117
117
  mail_alias = Alias.find(name)
118
- report("Alias") do
119
- puts "Address : %s" % mail_alias.address
120
- puts "Go to : %s" % mail_alias.goto
121
- puts "Active : %s" % mail_alias.active_str
122
- end
118
+
119
+ rows = []
120
+ puts_title("Alias")
121
+ rows << ["Address", mail_alias.address]
122
+ rows << ["Go to", mail_alias.goto]
123
+ rows << ["Active", mail_alias.active_str]
124
+
125
+ puts_table(rows: rows)
123
126
  end
124
127
 
125
128
  def show_domain
126
- index = " No. Domain Aliases Mailboxes Quota (MB) Active"
127
- report('Domains', index) do
128
- if Domain.without_all.empty?
129
- puts " No domains"
130
- next
131
- end
129
+ rows = []
130
+ headings = ["No.", "Domain", "Aliases", "Mailboxes","Max Quota (MB)",
131
+ "Active", "Description"]
132
132
 
133
- Domain.without_all.each_with_index do |d, i|
134
- puts "%4d %-30s %3d /%3s %3d /%3s %10d %-3s" %
135
- [i+1, d.domain, d.pure_aliases.count, max_str(d.aliases),
136
- d.rel_mailboxes.count, max_str(d.mailboxes), d.maxquota, d.active_str]
137
- end
133
+ puts_title("Domains")
134
+ if Domain.without_all.empty?
135
+ puts "No domains"
136
+ return
137
+ end
138
+
139
+ Domain.without_all.each_with_index do |d, i|
140
+ no = i + 1
141
+ aliases_str = "%4d / %4s" % [d.pure_aliases.count, d.aliases_str]
142
+ mailboxes_str = "%4d / %4s" % [d.rel_mailboxes.count, d.mailboxes_str]
143
+ rows << [no.to_s, d.domain, aliases_str, mailboxes_str,
144
+ d.maxquota_str, d.active_str, d.description]
138
145
  end
146
+
147
+ puts_table(headings: headings, rows: rows)
139
148
  end
140
149
 
141
- def add_domain(domain_name)
142
- @base.add_domain(domain_name)
150
+ def add_domain(domain_name, description: nil)
151
+ @base.add_domain(domain_name, description: description)
143
152
  puts_registered(domain_name, "a domain")
144
153
  end
145
154
 
@@ -173,6 +182,7 @@ module PostfixAdmin
173
182
  domain.mailboxes = options[:mailboxes] if options[:mailboxes]
174
183
  domain.maxquota = options[:maxquota] if options[:maxquota]
175
184
  domain.active = options[:active] unless options[:active].nil?
185
+ domain.description = options[:description] if options[:description]
176
186
  domain.save!
177
187
 
178
188
  puts "Successfully updated #{domain_name}"
@@ -186,36 +196,44 @@ module PostfixAdmin
186
196
 
187
197
  def show_admin(domain_name = nil)
188
198
  admins = domain_name ? Admin.select { |a| a.rel_domains.exists?(domain_name) } : Admin.all
189
- index = " No. Admin Domains Active"
190
- report("Admins", index) do
191
- if admins.empty?
192
- puts " No admins"
193
- next
194
- end
199
+ headings = %w[No. Admin Domains Active]
195
200
 
196
- admins.each_with_index do |a, i|
197
- domains = a.super_admin? ? 'Super admin' : a.rel_domains.count
198
- puts "%4d %-40s %11s %-3s" % [i+1, a.username, domains, a.active_str]
199
- end
201
+ puts_title("Admins")
202
+ if admins.empty?
203
+ puts "No admins"
204
+ return
200
205
  end
206
+
207
+ rows = []
208
+ admins.each_with_index do |a, i|
209
+ no = i + 1
210
+ domains = a.super_admin? ? 'Super Admin' : a.rel_domains.count
211
+ rows << [no.to_s, a.username, domains.to_s, a.active_str]
212
+ end
213
+
214
+ puts_table(headings: headings, rows: rows)
201
215
  end
202
216
 
203
217
  def show_address(domain_name)
204
218
  domain_check(domain_name)
205
219
 
220
+ rows = []
206
221
  mailboxes = Domain.find(domain_name).rel_mailboxes
207
- index = " No. Email Name Quota (MB) Active Maildir"
208
- report("Addresses", index) do
209
- if mailboxes.empty?
210
- puts " No addresses"
211
- next
212
- end
222
+ headings = ["No.", "Email", "Name", "Quota (MB)", "Active", "Maildir"]
213
223
 
214
- mailboxes.each_with_index do |m, i|
215
- quota = m.quota.to_f/ KB_TO_MB.to_f
216
- puts "%4d %-30s %-20s %10s %-3s %s" % [i+1, m.username, m.name, max_str(quota.to_i), m.active_str, m.maildir]
217
- end
224
+ puts_title("Addresses")
225
+ if mailboxes.empty?
226
+ puts "No addresses"
227
+ return
228
+ end
229
+
230
+ mailboxes.each_with_index do |m, i|
231
+ no = i + 1
232
+ rows << [no.to_s, m.username, m.name, m.quota_mb_str,
233
+ m.active_str, m.maildir]
218
234
  end
235
+
236
+ puts_table(headings: headings, rows: rows)
219
237
  end
220
238
 
221
239
  def show_alias(domain_name)
@@ -228,21 +246,24 @@ module PostfixAdmin
228
246
  end
229
247
 
230
248
  show_alias_base("Forwards", forwards)
249
+ puts
231
250
  show_alias_base("Aliases", aliases)
232
251
  end
233
252
 
234
253
  def show_admin_domain(user_name)
235
254
  admin = Admin.find(user_name)
255
+ puts_title("Admin Domains (#{user_name})")
236
256
  if admin.rel_domains.empty?
237
- puts "\nNo domain in database"
257
+ puts "\nNo domains for #{user_name}"
238
258
  return
239
259
  end
240
260
 
241
- report("Domains (#{user_name})", " No. Domain") do
242
- admin.rel_domains.each_with_index do |d, i|
243
- puts "%4d %-30s" % [i + 1, d.domain]
244
- end
261
+ rows = []
262
+ admin.rel_domains.each_with_index do |d, i|
263
+ no = i + 1
264
+ rows << [no.to_s, d.domain]
245
265
  end
266
+ puts_table(rows: rows, headings: %w[No. Domain])
246
267
  end
247
268
 
248
269
  def add_admin(user_name, password, super_admin = false, scheme = nil)
@@ -270,9 +291,8 @@ module PostfixAdmin
270
291
  def add_account(address, password, scheme = nil, name = nil)
271
292
  validate_password(password)
272
293
 
273
- @base.add_account(address, hashed_password(password, scheme), name)
294
+ @base.add_account(address, hashed_password(password, scheme), name: name)
274
295
  puts_registered(address, "an account")
275
- show_account_details(address)
276
296
  end
277
297
 
278
298
  def add_alias(address, goto)
@@ -324,11 +344,25 @@ module PostfixAdmin
324
344
  puts_deleted(address)
325
345
  end
326
346
 
327
- def log
328
- Log.all.each do |l|
329
- time = l.timestamp.strftime("%Y-%m-%d %X %Z")
330
- puts "#{time} #{l.username} #{l.domain} #{l.action} #{l.data}"
347
+ def log(domain: nil, last: nil)
348
+ headings = %w[Timestamp Admin Domain Action Data]
349
+ rows = []
350
+
351
+ logs = if domain
352
+ Log.where(domain: domain)
353
+ else
354
+ Log.all
355
+ end
356
+
357
+ logs = logs.last(last) if last
358
+
359
+ logs.each do |l|
360
+ # TODO: Consider if zone should be included ('%Z').
361
+ time = l.timestamp.strftime("%Y-%m-%d %X")
362
+ rows << [time, l.username, l.domain, l.action, l.data]
331
363
  end
364
+
365
+ puts_table(headings: headings, rows: rows)
332
366
  end
333
367
 
334
368
  def dump
@@ -365,17 +399,58 @@ module PostfixAdmin
365
399
 
366
400
  private
367
401
 
402
+ def show_general_summary
403
+ rows = []
404
+ title = "Summary"
405
+ rows << ["Domains", Domain.without_all.count]
406
+ rows << ["Admins", Admin.count]
407
+ rows << ["Mailboxes", Mailbox.count]
408
+ rows << ["Aliases", Alias.pure.count]
409
+
410
+ puts_title(title)
411
+ puts_table(rows: rows)
412
+ end
413
+
414
+ def show_domain_summary(domain_name)
415
+ domain_name = domain_name.downcase
416
+ domain_check(domain_name)
417
+
418
+ rows = []
419
+ domain = Domain.find(domain_name)
420
+ rows << ["Mailboxes", "%4d / %4s" % [domain.rel_mailboxes.count, domain.mailboxes_str]]
421
+ rows << ["Aliases", "%4d / %4s" % [domain.pure_aliases.count, domain.aliases_str]]
422
+ rows << ["Max Quota (MB)", domain.maxquota_str]
423
+ rows << ["Active", domain.active_str]
424
+ rows << ["Description", domain.description]
425
+
426
+ puts_title(domain_name)
427
+ puts_table(rows: rows)
428
+ end
429
+
430
+ def show_domain_details(domain_name)
431
+ show_admin(domain_name)
432
+ puts
433
+ show_address(domain_name)
434
+ puts
435
+ show_alias(domain_name)
436
+ end
437
+
368
438
  def show_alias_base(title, addresses)
369
- report(title, " No. Address Active Go to") do
370
- if addresses.empty?
371
- puts " No #{title.downcase}"
372
- next
373
- end
439
+ rows = []
440
+ puts_title(title)
374
441
 
375
- addresses.each_with_index do |a, i|
376
- puts "%4d %-40s %-3s %s" % [i+1, a.address, a.active_str, a.goto]
377
- end
442
+ if addresses.empty?
443
+ puts "No #{title.downcase}"
444
+ return
378
445
  end
446
+
447
+ headings = ["No.", "Address", "Active", "Go to"]
448
+ addresses.each_with_index do |a, i|
449
+ no = i + 1
450
+ rows << [no.to_s, a.address, a.active_str, a.goto]
451
+ end
452
+
453
+ puts_table(headings: headings, rows: rows)
379
454
  end
380
455
 
381
456
  def puts_registered(name, as_str)
@@ -387,7 +462,7 @@ module PostfixAdmin
387
462
  end
388
463
 
389
464
  def config_file
390
- config_file = File.expand_path(CLI.config_file)
465
+ File.expand_path(CLI.config_file)
391
466
  end
392
467
 
393
468
  def load_config
@@ -408,17 +483,12 @@ module PostfixAdmin
408
483
  File.chmod(0600, file)
409
484
  end
410
485
 
411
- def print_line
412
- puts "-"*120
486
+ def puts_table(args)
487
+ puts Terminal::Table.new(args)
413
488
  end
414
489
 
415
- def report(title, index = nil)
416
- puts "\n[#{title}]"
417
- print_line if index
418
- puts index if index
419
- print_line
420
- yield
421
- print_line
490
+ def puts_title(title)
491
+ puts "| #{title} |"
422
492
  end
423
493
 
424
494
  def account_check(user_name)
@@ -468,23 +538,10 @@ module PostfixAdmin
468
538
  end
469
539
  end
470
540
 
471
- def max_str(value)
472
- case value
473
- when 0
474
- '--'
475
- when -1
476
- '0'
477
- else
478
- value.to_s
479
- end
480
- end
481
-
482
- private
483
-
484
541
  def hashed_password(password, in_scheme = nil)
542
+ prefix = @base.config[:passwordhash_prefix]
485
543
  scheme = in_scheme || @base.config[:scheme]
486
- puts "scheme: #{scheme}"
487
- PostfixAdmin::Doveadm.password(password, scheme)
544
+ PostfixAdmin::Doveadm.password(password, scheme, prefix)
488
545
  end
489
546
  end
490
547
  end
@@ -12,7 +12,6 @@ module DovecotCramMD5Password
12
12
  end
13
13
 
14
14
  attr_reader :password_unencrypted
15
- attr_accessor :password_unencrypted_confirmation
16
15
  end
17
16
 
18
17
  def password_unencrypted=(unencrypted_password)
@@ -8,91 +8,82 @@ module PostfixAdmin
8
8
  message: "must be a valid domain name" }
9
9
  validates :transport, presence: true
10
10
 
11
+ # max aliases (Disabled: -1, Unlimited: 0)
11
12
  validates :aliases, presence: true,
12
13
  numericality: { only_integer: true,
13
- greater_than_or_equal_to: 0 }
14
+ greater_than_or_equal_to: -1 }
15
+ # max mailboxes (Disabled: -1, Unlimited: 0)
14
16
  validates :mailboxes, presence: true,
15
17
  numericality: { only_integer: true,
16
- greater_than_or_equal_to: 0 }
18
+ greater_than_or_equal_to: -1 }
19
+
20
+ # max quota (MB) for each mailbox (Unlimited: 0)
21
+ # It's not sure what 'disabled' means for max quota.
22
+ # So it's better not to allow users to set `maxquota` to -1.
17
23
  validates :maxquota, presence: true,
18
24
  numericality: { only_integer: true,
19
25
  greater_than_or_equal_to: 0 }
20
26
 
27
+ # mailboxes that belong to this domain
21
28
  has_many :rel_mailboxes, class_name: "Mailbox", foreign_key: :domain,
22
29
  dependent: :destroy
30
+ # aliases that belong to this domain
23
31
  has_many :rel_aliases, class_name: "Alias", foreign_key: :domain,
24
32
  dependent: :destroy
25
33
 
34
+ # It causes errors to set `dependent: :destroy` as other columns
35
+ # because the domain_admins table doesn't have a single primary key.
36
+ #
37
+ # PostfixAdmin::DomainAdmin Load (0.5ms) SELECT `domain_admins`.* FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
38
+ # PostfixAdmin::DomainAdmin Destroy (1.1ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`` IS NULL
39
+ #
40
+ # ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
41
+ # from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
42
+ # Caused by Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
43
+ # from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
44
+ #
45
+ # It works well with `dependent: :delete_all` instead.
46
+ #
47
+ # PostfixAdmin::DomainAdmin Destroy (0.4ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
26
48
  has_many :domain_admins, foreign_key: :domain, dependent: :delete_all
49
+
27
50
  has_many :admins, through: :domain_admins
28
51
 
29
52
  before_validation do |domain|
30
- domain.domain = domain.domain.downcase unless domain.domain.empty?
53
+ domain.domain = domain.domain&.downcase
31
54
  domain.transport = "virtual"
32
55
  end
33
56
 
34
57
  scope :without_all, -> { where.not(domain: "ALL") }
35
58
 
59
+ # aliases that don't belong to a mailbox
36
60
  def pure_aliases
37
61
  rel_aliases.pure
38
62
  end
39
63
 
40
- def aliases_unlimited?
41
- aliases.zero?
42
- end
43
-
44
- def mailboxes_unlimited?
45
- mailboxes.zero?
46
- end
47
-
48
64
  def aliases_str
49
- num_str(aliases)
65
+ max_num_str(aliases)
50
66
  end
51
67
 
52
68
  def mailboxes_str
53
- num_str(mailboxes)
54
- end
55
-
56
- def aliases_short_str
57
- num_short_str(aliases)
58
- end
59
-
60
- def mailboxes_short_str
61
- num_short_str(mailboxes)
69
+ max_num_str(mailboxes)
62
70
  end
63
71
 
64
72
  def maxquota_str
65
- if maxquota.zero?
66
- "Unlimited"
67
- else
68
- "#{maxquota} MB"
69
- end
70
- end
71
-
72
- def maxquota_short_str
73
- if maxquota.zero?
74
- "--"
75
- else
76
- "#{maxquota} MB"
77
- end
73
+ max_num_str(maxquota)
78
74
  end
79
75
 
80
76
  private
81
77
 
82
- def num_str(num)
83
- if num.zero?
78
+ def max_num_str(num)
79
+ case num
80
+ when -1
81
+ "Disabled"
82
+ when 0
84
83
  "Unlimited"
85
84
  else
86
85
  num.to_s
87
86
  end
88
87
  end
89
-
90
- def num_short_str(num)
91
- if num.zero?
92
- "--"
93
- else
94
- num.to_s
95
- end
96
- end
97
88
  end
98
89
  end
@@ -9,24 +9,25 @@ module PostfixAdmin
9
9
  result.split
10
10
  end
11
11
 
12
- def self.password(in_password, in_scheme)
12
+ def self.password(in_password, in_scheme, prefix)
13
13
  password = Shellwords.escape(in_password)
14
- scheme = Shellwords.escape(in_scheme)
15
- stdin, stdout, stderr = Open3.popen3("#{self.command_name} -s #{scheme} -p #{password}")
14
+ scheme = Shellwords.escape(in_scheme)
15
+ _stdin, stdout, stderr = Open3.popen3("#{self.command_name} -s #{scheme} -p #{password}")
16
+
16
17
  if stderr.readlines.to_s =~ /Fatal:/
17
18
  raise Error, stderr.readlines
18
19
  else
19
- stdout.readlines.first.chomp
20
+ res = stdout.readlines.first.chomp
21
+ if prefix
22
+ res
23
+ else
24
+ res.gsub("{#{scheme}}", "")
25
+ end
20
26
  end
21
27
  end
22
28
 
23
29
  def self.command_name
24
- begin
25
- Open3.capture3("doveadm pw -l")[2].exited?
26
- "doveadm pw"
27
- rescue Errno::ENOENT
28
- "dovecotpw"
29
- end
30
+ "doveadm pw"
30
31
  end
31
32
  end
32
33
  end
@@ -12,9 +12,13 @@ module PostfixAdmin
12
12
  message: "must be a valid email address" }
13
13
  validates :maildir, presence: true, uniqueness: { case_sensitive: false }
14
14
  validates :local_part, presence: true
15
+
16
+ # quota (KB)
15
17
  validates :quota, presence: true,
16
18
  numericality: { only_integer: true,
17
19
  greater_than_or_equal_to: 0 }
20
+
21
+ # quota (MB), which actually doesn't exist in DB
18
22
  validates :quota_mb, presence: true,
19
23
  numericality: { only_integer: true,
20
24
  greater_than_or_equal_to: 0 }
@@ -63,7 +67,7 @@ module PostfixAdmin
63
67
  mailbox.quota = 0
64
68
  end
65
69
  mailbox.username = "#{mailbox.local_part}@#{mailbox.domain}"
66
- mailbox.maildir = "#{mailbox.domain}/#{mailbox.username}/"
70
+ mailbox.maildir ||= "#{mailbox.domain}/#{mailbox.username}/"
67
71
  mailbox.build_alias(local_part: mailbox.local_part, goto: mailbox.username,
68
72
  domain: mailbox.domain)
69
73
  end
@@ -77,12 +81,16 @@ module PostfixAdmin
77
81
  end
78
82
  end
79
83
 
80
- def quota_str
81
- if quota.zero?
82
- "--"
84
+ def quota_mb_str
85
+ case quota
86
+ when -1
87
+ # It's not sure what 'disabled' means for quota.
88
+ "Disabled"
89
+ when 0
90
+ "Unlimited"
83
91
  else
84
- quota_mb = quota / KB_TO_MB
85
- "#{quota_mb} MB"
92
+ mb_size = quota / KB_TO_MB
93
+ mb_size.to_s
86
94
  end
87
95
  end
88
96
  end