postfix_admin 0.2.1 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +54 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +16 -9
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +26 -20
- data/Rakefile +19 -1
- data/bin/console +6 -2
- data/docker-admin/config.local.php +3 -0
- data/docker-app/Dockerfile +2 -6
- data/docker-app/my.cnf +2 -2
- data/docker-compose.yml +18 -14
- data/lib/postfix_admin/admin.rb +5 -0
- data/lib/postfix_admin/alias.rb +0 -19
- data/lib/postfix_admin/base.rb +118 -98
- data/lib/postfix_admin/cli.rb +180 -125
- data/lib/postfix_admin/concerns/dovecot_cram_md5_password.rb +0 -1
- data/lib/postfix_admin/domain.rb +35 -44
- data/lib/postfix_admin/doveadm.rb +4 -8
- data/lib/postfix_admin/mailbox.rb +14 -6
- data/lib/postfix_admin/runner.rb +35 -22
- data/lib/postfix_admin/version.rb +1 -1
- data/postfix_admin.gemspec +12 -10
- metadata +48 -22
- data/.github/workflows/ruby.yml +0 -37
- data/docker-app/docker-entrypoint.sh +0 -5
- data/docker-app-2.5/Dockerfile +0 -15
data/lib/postfix_admin/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
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
|
@@ -29,55 +30,49 @@ module PostfixAdmin
|
|
29
30
|
name = name.downcase if name
|
30
31
|
|
31
32
|
if name =~ /@/
|
33
|
+
# address like argument
|
32
34
|
if Admin.exists?(name)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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)
|
38
42
|
elsif Alias.exists?(name)
|
43
|
+
# alias
|
39
44
|
show_alias_details(name)
|
45
|
+
else
|
46
|
+
raise Error, "Could not find admin/mailbox/alias #{name}"
|
40
47
|
end
|
41
48
|
|
42
49
|
return
|
43
50
|
end
|
44
51
|
|
45
52
|
show_summary(name)
|
53
|
+
puts
|
46
54
|
|
47
55
|
if name
|
48
|
-
|
49
|
-
|
50
|
-
show_alias(name)
|
56
|
+
# domain name
|
57
|
+
show_domain_details(name)
|
51
58
|
else
|
59
|
+
# no argument: show all domains and admins
|
52
60
|
show_domain
|
61
|
+
puts
|
53
62
|
show_admin
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
57
66
|
def show_summary(domain_name = nil)
|
58
|
-
title = "Summary"
|
59
67
|
if domain_name
|
60
|
-
domain_name
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
report(title) do
|
66
|
-
if domain_name
|
67
|
-
domain = Domain.find(domain_name)
|
68
|
-
puts "Mailboxes : %4d / %4s" % [domain.rel_mailboxes.count, max_str(domain.mailboxes)]
|
69
|
-
puts "Aliases : %4d / %4s" % [domain.pure_aliases.count, max_str(domain.aliases)]
|
70
|
-
puts "Max Quota : %4d MB" % domain.maxquota
|
71
|
-
puts "Active : %3s" % domain.active_str
|
72
|
-
else
|
73
|
-
puts "Domains : %4d" % Domain.without_all.count
|
74
|
-
puts "Admins : %4d" % Admin.count
|
75
|
-
puts "Mailboxes : %4d" % Mailbox.count
|
76
|
-
puts "Aliases : %4d" % Alias.pure.count
|
77
|
-
end
|
68
|
+
show_domain_summary(domain_name)
|
69
|
+
else
|
70
|
+
show_general_summary
|
78
71
|
end
|
79
72
|
end
|
80
73
|
|
74
|
+
# Set up a domain
|
75
|
+
# Add a domain, add an admin, and grant the admin access to the domain
|
81
76
|
def setup_domain(domain_name, password)
|
82
77
|
admin = "admin@#{domain_name}"
|
83
78
|
add_domain(domain_name)
|
@@ -85,62 +80,75 @@ module PostfixAdmin
|
|
85
80
|
add_admin_domain(admin, domain_name)
|
86
81
|
end
|
87
82
|
|
88
|
-
def show_account_details(user_name)
|
83
|
+
def show_account_details(user_name, display_password: false)
|
89
84
|
account_check(user_name)
|
90
85
|
mailbox = Mailbox.find(user_name)
|
91
86
|
mail_alias = Alias.find(user_name)
|
92
87
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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)
|
101
98
|
end
|
102
99
|
|
103
|
-
def show_admin_details(name)
|
100
|
+
def show_admin_details(name, display_password: false)
|
104
101
|
admin_check(name)
|
105
102
|
admin = Admin.find(name)
|
106
103
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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)
|
114
113
|
end
|
115
114
|
|
116
115
|
def show_alias_details(name)
|
117
116
|
alias_check(name)
|
118
117
|
mail_alias = Alias.find(name)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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)
|
124
126
|
end
|
125
127
|
|
126
128
|
def show_domain
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
puts " No domains"
|
131
|
-
next
|
132
|
-
end
|
129
|
+
rows = []
|
130
|
+
headings = ["No.", "Domain", "Aliases", "Mailboxes","Max Quota (MB)",
|
131
|
+
"Active", "Description"]
|
133
132
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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]
|
139
145
|
end
|
146
|
+
|
147
|
+
puts_table(headings: headings, rows: rows)
|
140
148
|
end
|
141
149
|
|
142
|
-
def add_domain(domain_name)
|
143
|
-
@base.add_domain(domain_name)
|
150
|
+
def add_domain(domain_name, description: nil)
|
151
|
+
@base.add_domain(domain_name, description: description)
|
144
152
|
puts_registered(domain_name, "a domain")
|
145
153
|
end
|
146
154
|
|
@@ -174,6 +182,7 @@ module PostfixAdmin
|
|
174
182
|
domain.mailboxes = options[:mailboxes] if options[:mailboxes]
|
175
183
|
domain.maxquota = options[:maxquota] if options[:maxquota]
|
176
184
|
domain.active = options[:active] unless options[:active].nil?
|
185
|
+
domain.description = options[:description] if options[:description]
|
177
186
|
domain.save!
|
178
187
|
|
179
188
|
puts "Successfully updated #{domain_name}"
|
@@ -187,36 +196,44 @@ module PostfixAdmin
|
|
187
196
|
|
188
197
|
def show_admin(domain_name = nil)
|
189
198
|
admins = domain_name ? Admin.select { |a| a.rel_domains.exists?(domain_name) } : Admin.all
|
190
|
-
|
191
|
-
report("Admins", index) do
|
192
|
-
if admins.empty?
|
193
|
-
puts " No admins"
|
194
|
-
next
|
195
|
-
end
|
199
|
+
headings = %w[No. Admin Domains Active]
|
196
200
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
+
puts_title("Admins")
|
202
|
+
if admins.empty?
|
203
|
+
puts "No admins"
|
204
|
+
return
|
201
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)
|
202
215
|
end
|
203
216
|
|
204
217
|
def show_address(domain_name)
|
205
218
|
domain_check(domain_name)
|
206
219
|
|
220
|
+
rows = []
|
207
221
|
mailboxes = Domain.find(domain_name).rel_mailboxes
|
208
|
-
|
209
|
-
report("Addresses", index) do
|
210
|
-
if mailboxes.empty?
|
211
|
-
puts " No addresses"
|
212
|
-
next
|
213
|
-
end
|
222
|
+
headings = ["No.", "Email", "Name", "Quota (MB)", "Active", "Maildir"]
|
214
223
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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]
|
219
234
|
end
|
235
|
+
|
236
|
+
puts_table(headings: headings, rows: rows)
|
220
237
|
end
|
221
238
|
|
222
239
|
def show_alias(domain_name)
|
@@ -229,21 +246,24 @@ module PostfixAdmin
|
|
229
246
|
end
|
230
247
|
|
231
248
|
show_alias_base("Forwards", forwards)
|
249
|
+
puts
|
232
250
|
show_alias_base("Aliases", aliases)
|
233
251
|
end
|
234
252
|
|
235
253
|
def show_admin_domain(user_name)
|
236
254
|
admin = Admin.find(user_name)
|
255
|
+
puts_title("Admin Domains (#{user_name})")
|
237
256
|
if admin.rel_domains.empty?
|
238
|
-
puts "\nNo
|
257
|
+
puts "\nNo domains for #{user_name}"
|
239
258
|
return
|
240
259
|
end
|
241
260
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
261
|
+
rows = []
|
262
|
+
admin.rel_domains.each_with_index do |d, i|
|
263
|
+
no = i + 1
|
264
|
+
rows << [no.to_s, d.domain]
|
246
265
|
end
|
266
|
+
puts_table(rows: rows, headings: %w[No. Domain])
|
247
267
|
end
|
248
268
|
|
249
269
|
def add_admin(user_name, password, super_admin = false, scheme = nil)
|
@@ -271,9 +291,8 @@ module PostfixAdmin
|
|
271
291
|
def add_account(address, password, scheme = nil, name = nil)
|
272
292
|
validate_password(password)
|
273
293
|
|
274
|
-
@base.add_account(address, hashed_password(password, scheme), name)
|
294
|
+
@base.add_account(address, hashed_password(password, scheme), name: name)
|
275
295
|
puts_registered(address, "an account")
|
276
|
-
show_account_details(address)
|
277
296
|
end
|
278
297
|
|
279
298
|
def add_alias(address, goto)
|
@@ -325,11 +344,25 @@ module PostfixAdmin
|
|
325
344
|
puts_deleted(address)
|
326
345
|
end
|
327
346
|
|
328
|
-
def log
|
329
|
-
|
330
|
-
|
331
|
-
|
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]
|
332
363
|
end
|
364
|
+
|
365
|
+
puts_table(headings: headings, rows: rows)
|
333
366
|
end
|
334
367
|
|
335
368
|
def dump
|
@@ -366,17 +399,58 @@ module PostfixAdmin
|
|
366
399
|
|
367
400
|
private
|
368
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
|
+
|
369
438
|
def show_alias_base(title, addresses)
|
370
|
-
|
371
|
-
|
372
|
-
puts " No #{title.downcase}"
|
373
|
-
next
|
374
|
-
end
|
439
|
+
rows = []
|
440
|
+
puts_title(title)
|
375
441
|
|
376
|
-
|
377
|
-
|
378
|
-
|
442
|
+
if addresses.empty?
|
443
|
+
puts "No #{title.downcase}"
|
444
|
+
return
|
379
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)
|
380
454
|
end
|
381
455
|
|
382
456
|
def puts_registered(name, as_str)
|
@@ -388,7 +462,7 @@ module PostfixAdmin
|
|
388
462
|
end
|
389
463
|
|
390
464
|
def config_file
|
391
|
-
|
465
|
+
File.expand_path(CLI.config_file)
|
392
466
|
end
|
393
467
|
|
394
468
|
def load_config
|
@@ -409,17 +483,12 @@ module PostfixAdmin
|
|
409
483
|
File.chmod(0600, file)
|
410
484
|
end
|
411
485
|
|
412
|
-
def
|
413
|
-
puts
|
486
|
+
def puts_table(args)
|
487
|
+
puts Terminal::Table.new(args)
|
414
488
|
end
|
415
489
|
|
416
|
-
def
|
417
|
-
puts "
|
418
|
-
print_line if index
|
419
|
-
puts index if index
|
420
|
-
print_line
|
421
|
-
yield
|
422
|
-
print_line
|
490
|
+
def puts_title(title)
|
491
|
+
puts "| #{title} |"
|
423
492
|
end
|
424
493
|
|
425
494
|
def account_check(user_name)
|
@@ -469,23 +538,9 @@ module PostfixAdmin
|
|
469
538
|
end
|
470
539
|
end
|
471
540
|
|
472
|
-
def max_str(value)
|
473
|
-
case value
|
474
|
-
when 0
|
475
|
-
'--'
|
476
|
-
when -1
|
477
|
-
'0'
|
478
|
-
else
|
479
|
-
value.to_s
|
480
|
-
end
|
481
|
-
end
|
482
|
-
|
483
|
-
private
|
484
|
-
|
485
541
|
def hashed_password(password, in_scheme = nil)
|
486
542
|
prefix = @base.config[:passwordhash_prefix]
|
487
543
|
scheme = in_scheme || @base.config[:scheme]
|
488
|
-
puts "scheme: #{scheme}"
|
489
544
|
PostfixAdmin::Doveadm.password(password, scheme, prefix)
|
490
545
|
end
|
491
546
|
end
|
data/lib/postfix_admin/domain.rb
CHANGED
@@ -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:
|
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:
|
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
|
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
|
-
|
65
|
+
max_num_str(aliases)
|
50
66
|
end
|
51
67
|
|
52
68
|
def mailboxes_str
|
53
|
-
|
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
|
-
|
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
|
83
|
-
|
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
|
@@ -11,8 +11,9 @@ module PostfixAdmin
|
|
11
11
|
|
12
12
|
def self.password(in_password, in_scheme, prefix)
|
13
13
|
password = Shellwords.escape(in_password)
|
14
|
-
scheme
|
15
|
-
|
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
|
@@ -26,12 +27,7 @@ module PostfixAdmin
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def self.command_name
|
29
|
-
|
30
|
-
Open3.capture3("doveadm pw -l")[2].exited?
|
31
|
-
"doveadm pw"
|
32
|
-
rescue Errno::ENOENT
|
33
|
-
"dovecotpw"
|
34
|
-
end
|
30
|
+
"doveadm pw"
|
35
31
|
end
|
36
32
|
end
|
37
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
|
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
|
81
|
-
|
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
|
-
|
85
|
-
|
92
|
+
mb_size = quota / KB_TO_MB
|
93
|
+
mb_size.to_s
|
86
94
|
end
|
87
95
|
end
|
88
96
|
end
|