postfix_admin 0.2.0 → 0.3.0

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