postfix_admin 0.2.1 → 0.3.1

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +52 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +20 -0
  5. data/CHANGELOG.md +26 -12
  6. data/Gemfile +1 -1
  7. data/LICENSE +1 -1
  8. data/README.md +26 -20
  9. data/Rakefile +48 -1
  10. data/bin/console +6 -2
  11. data/db/reset.rb +7 -0
  12. data/db/seeds.rb +26 -0
  13. data/docker-admin/config.local.php +6 -1
  14. data/docker-app/Dockerfile +2 -6
  15. data/docker-app/my.cnf +2 -2
  16. data/docker-compose.yml +20 -20
  17. data/lib/postfix_admin/base.rb +119 -112
  18. data/lib/postfix_admin/cli.rb +267 -158
  19. data/lib/postfix_admin/doveadm.rb +32 -20
  20. data/lib/postfix_admin/{admin.rb → models/admin.rb} +25 -2
  21. data/lib/postfix_admin/{alias.rb → models/alias.rb} +16 -26
  22. data/lib/postfix_admin/{application_record.rb → models/application_record.rb} +1 -1
  23. data/lib/postfix_admin/{concerns → models/concerns}/existing_timestamp.rb +1 -2
  24. data/lib/postfix_admin/models/concerns/has_password.rb +16 -0
  25. data/lib/postfix_admin/models/domain.rb +112 -0
  26. data/lib/postfix_admin/models/domain_admin.rb +19 -0
  27. data/lib/postfix_admin/models/log.rb +20 -0
  28. data/lib/postfix_admin/models/mailbox.rb +126 -0
  29. data/lib/postfix_admin/models/quota2.rb +18 -0
  30. data/lib/postfix_admin/models.rb +8 -9
  31. data/lib/postfix_admin/runner.rb +91 -28
  32. data/lib/postfix_admin/version.rb +1 -1
  33. data/postfix_admin.gemspec +12 -10
  34. metadata +61 -34
  35. data/.github/workflows/ruby.yml +0 -37
  36. data/docker-app/docker-entrypoint.sh +0 -5
  37. data/docker-app-2.5/Dockerfile +0 -15
  38. data/lib/postfix_admin/concerns/dovecot_cram_md5_password.rb +0 -30
  39. data/lib/postfix_admin/domain.rb +0 -98
  40. data/lib/postfix_admin/domain_admin.rb +0 -8
  41. data/lib/postfix_admin/log.rb +0 -5
  42. data/lib/postfix_admin/mail_domain.rb +0 -9
  43. data/lib/postfix_admin/mailbox.rb +0 -89
  44. data/lib/postfix_admin/quota.rb +0 -6
  45. /data/lib/postfix_admin/{concerns → models/concerns}/.keep +0 -0
@@ -1,36 +1,48 @@
1
-
2
1
  require 'open3'
3
2
  require 'shellwords'
4
3
 
5
4
  module PostfixAdmin
6
5
  class Doveadm
6
+ # doveadm-pw: https://doc.dovecot.org/3.0/man/doveadm-pw.1/
7
+ CMD_DOVEADM_PW = "doveadm pw"
8
+
9
+ # List all supported password schemes
7
10
  def self.schemes
8
- result = `#{self.command_name} -l`
11
+ result = `#{CMD_DOVEADM_PW} -l`
9
12
  result.split
10
13
  end
11
14
 
12
- def self.password(in_password, in_scheme, prefix)
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}")
16
- if stderr.readlines.to_s =~ /Fatal:/
17
- raise Error, stderr.readlines
18
- else
19
- res = stdout.readlines.first.chomp
15
+ # Generate a password hash using `doveadm pw` command
16
+ def self.password(password, scheme, rounds: nil, user_name: nil,
17
+ prefix: true)
18
+ escaped_password = Shellwords.escape(password)
19
+ escaped_scheme = Shellwords.escape(scheme)
20
+
21
+ cmd = "#{CMD_DOVEADM_PW} -s #{escaped_scheme} -p #{escaped_password}"
22
+
23
+ # DIGEST-MD5 requires -u option (user name)
24
+ if scheme == "DIGEST-MD5"
25
+ escaped_user_name = Shellwords.escape(user_name)
26
+ cmd << " -u #{escaped_user_name}"
27
+ end
28
+
29
+ if rounds
30
+ escaped_rounds = Shellwords.escape(rounds.to_s)
31
+ cmd << " -r #{rounds}"
32
+ end
33
+
34
+ output, error, status = Open3.capture3(cmd)
35
+
36
+ if status.success?
37
+ res = output.chomp
20
38
  if prefix
21
39
  res
22
40
  else
23
- res.gsub("{#{scheme}}", "")
41
+ # Remove the prefix
42
+ res.gsub("{#{escaped_scheme}}", "")
24
43
  end
25
- end
26
- end
27
-
28
- def self.command_name
29
- begin
30
- Open3.capture3("doveadm pw -l")[2].exited?
31
- "doveadm pw"
32
- rescue Errno::ENOENT
33
- "dovecotpw"
44
+ else
45
+ raise Error, "#{CMD_DOVEADM_PW}: #{error}"
34
46
  end
35
47
  end
36
48
  end
@@ -1,16 +1,34 @@
1
- require 'postfix_admin/concerns/dovecot_cram_md5_password'
1
+ require 'postfix_admin/models/concerns/has_password'
2
2
 
3
3
  module PostfixAdmin
4
4
  class Admin < ApplicationRecord
5
+ # version: 1841
6
+ # > describe admin;
7
+ # +----------------+--------------+------+-----+---------------------+-------+
8
+ # | Field | Type | Null | Key | Default | Extra |
9
+ # +----------------+--------------+------+-----+---------------------+-------+
10
+ # | username | varchar(255) | NO | PRI | NULL | |
11
+ # | password | varchar(255) | NO | | NULL | |
12
+ # | created | datetime | NO | | 2000-01-01 00:00:00 | |
13
+ # | modified | datetime | NO | | 2000-01-01 00:00:00 | |
14
+ # | active | tinyint(1) | NO | | 1 | |
15
+ # | superadmin | tinyint(1) | NO | | 0 | |
16
+ # | phone | varchar(30) | NO | | | |
17
+ # | email_other | varchar(255) | NO | | | |
18
+ # | token | varchar(255) | NO | | | |
19
+ # | token_validity | datetime | NO | | 2000-01-01 00:00:00 | |
20
+ # +----------------+--------------+------+-----+---------------------+-------+
21
+
5
22
  self.table_name = :admin
6
23
  self.primary_key = :username
7
24
 
8
- include DovecotCramMD5Password
25
+ include HasPassword
9
26
 
10
27
  validates :username, presence: true, uniqueness: { case_sensitive: false },
11
28
  format: { with: RE_EMAIL_LIKE_WITH_ANCHORS,
12
29
  message: "must be a valid email address" }
13
30
 
31
+ # Admin <-> DomainAdmin <-> Domain
14
32
  has_many :domain_admins, foreign_key: :username, dependent: :delete_all
15
33
  has_many :rel_domains, through: :domain_admins
16
34
 
@@ -22,6 +40,11 @@ module PostfixAdmin
22
40
  admin.errors.add(:username, 'cannot be changed') if admin.username_changed?
23
41
  end
24
42
 
43
+ def reload
44
+ @super_admin = nil
45
+ super
46
+ end
47
+
25
48
  def super_admin?
26
49
  if @super_admin.nil?
27
50
  @super_admin = if has_superadmin_column?
@@ -1,5 +1,18 @@
1
1
  module PostfixAdmin
2
2
  class Alias < ApplicationRecord
3
+ # version: 1841
4
+ # > describe alias;
5
+ # +----------+--------------+------+-----+---------------------+-------+
6
+ # | Field | Type | Null | Key | Default | Extra |
7
+ # +----------+--------------+------+-----+---------------------+-------+
8
+ # | address | varchar(255) | NO | PRI | NULL | |
9
+ # | goto | text | NO | | NULL | |
10
+ # | domain | varchar(255) | NO | MUL | NULL | |
11
+ # | created | datetime | NO | | 2000-01-01 00:00:00 | |
12
+ # | modified | datetime | NO | | 2000-01-01 00:00:00 | |
13
+ # | active | tinyint(1) | NO | | 1 | |
14
+ # +----------+--------------+------+-----+---------------------+-------+
15
+
3
16
  self.table_name = :alias
4
17
  self.primary_key = :address
5
18
 
@@ -21,34 +34,11 @@ module PostfixAdmin
21
34
  belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
22
35
  belongs_to :mailbox, foreign_key: :address, optional: true
23
36
 
37
+ # aliases which do not belong to any mailbox
24
38
  scope :pure, -> { joins("LEFT OUTER JOIN mailbox ON alias.address = mailbox.username").where("mailbox.username" => nil) }
25
39
 
26
- attribute :local_part, :string
27
- attr_writer :forward_addresses
28
-
29
- def forward_addresses
30
- if @forward_addresses.nil?
31
- if goto.nil?
32
- [nil]
33
- else
34
- goto.split(",") + [nil]
35
- end
36
- else
37
- @forward_addresses
38
- end
39
- end
40
-
41
- before_validation do |a|
42
- unless a.address
43
- a.address = "#{a.local_part}@#{a.domain}" unless a.local_part.empty?
44
- end
45
-
46
- unless a.forward_addresses.empty?
47
- forward_addresses = a.forward_addresses.dup
48
- forward_addresses.delete_if { |f| f.blank? }
49
- a.goto = forward_addresses.join(",")
50
- end
51
- end
40
+ # aliases which belong to a mailbox and have forwardings to other addresses
41
+ scope :forward, -> { joins("LEFT OUTER JOIN mailbox ON alias.address = mailbox.username").where("mailbox.username <> alias.goto") }
52
42
 
53
43
  def mailbox?
54
44
  !!mailbox
@@ -1,5 +1,5 @@
1
1
  require 'active_record'
2
- require 'postfix_admin/concerns/existing_timestamp'
2
+ require 'postfix_admin/models/concerns/existing_timestamp'
3
3
 
4
4
  module PostfixAdmin
5
5
  class ApplicationRecord < ActiveRecord::Base
@@ -14,5 +14,4 @@ module ExistingTimestamp
14
14
  ["modified"]
15
15
  end
16
16
  end
17
-
18
- end
17
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_support/concern'
2
+
3
+ module HasPassword
4
+ extend ActiveSupport::Concern
5
+
6
+ # example: {CRAM-MD5}, {BLF-CRYPT}, {PLAIN}
7
+ # return nil if no scheme prefix
8
+ def scheme_prefix
9
+ res = password&.match(/^\{.*?\}/)
10
+ if res
11
+ res[0]
12
+ else
13
+ nil
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,112 @@
1
+ module PostfixAdmin
2
+ class Domain < ApplicationRecord
3
+ # version: 1841
4
+ # > describe domain;
5
+ # +-------------+--------------+------+-----+---------------------+-------+
6
+ # | Field | Type | Null | Key | Default | Extra |
7
+ # +-------------+--------------+------+-----+---------------------+-------+
8
+ # | domain | varchar(255) | NO | PRI | NULL | |
9
+ # | description | varchar(255) | NO | | NULL | |
10
+ # | aliases | int(10) | NO | | 0 | |
11
+ # | mailboxes | int(10) | NO | | 0 | |
12
+ # | maxquota | bigint(20) | NO | | 0 | |
13
+ # | quota | bigint(20) | NO | | 0 | |
14
+ # | transport | varchar(255) | NO | | NULL | |
15
+ # | backupmx | tinyint(1) | NO | | 0 | |
16
+ # | created | datetime | NO | | 2000-01-01 00:00:00 | |
17
+ # | modified | datetime | NO | | 2000-01-01 00:00:00 | |
18
+ # | active | tinyint(1) | NO | | 1 | |
19
+ # +-------------+--------------+------+-----+---------------------+-------+
20
+
21
+ self.table_name = :domain
22
+ self.primary_key = :domain
23
+
24
+ validates :domain, presence: true, uniqueness: { case_sensitive: false },
25
+ format: { with: RE_DOMAIN_NAME_LIKE_WITH_ANCHORS,
26
+ message: "must be a valid domain name" }
27
+ validates :transport, presence: true
28
+
29
+ # max aliases (Disabled: -1, Unlimited: 0)
30
+ validates :aliases, presence: true,
31
+ numericality: { only_integer: true,
32
+ greater_than_or_equal_to: -1 }
33
+ # max mailboxes (Disabled: -1, Unlimited: 0)
34
+ validates :mailboxes, presence: true,
35
+ numericality: { only_integer: true,
36
+ greater_than_or_equal_to: -1 }
37
+
38
+ # max quota (MB) for each mailbox (Unlimited: 0)
39
+ # It's not sure what 'disabled' means for max quota.
40
+ # So it's better not to allow users to set `maxquota` to -1.
41
+ validates :maxquota, presence: true,
42
+ numericality: { only_integer: true,
43
+ greater_than_or_equal_to: 0 }
44
+
45
+ # mailboxes that belong to this domain
46
+ has_many :rel_mailboxes, class_name: "Mailbox", foreign_key: :domain,
47
+ dependent: :destroy
48
+ # aliases that belong to this domain
49
+ has_many :rel_aliases, class_name: "Alias", foreign_key: :domain,
50
+ dependent: :destroy
51
+
52
+ # logs that belong to this domain
53
+ has_many :logs, class_name: "Log", foreign_key: :domain,
54
+ dependent: :destroy
55
+
56
+ # It causes errors to set `dependent: :destroy` as other columns
57
+ # because the domain_admins table doesn't have a single primary key.
58
+ #
59
+ # PostfixAdmin::DomainAdmin Load (0.5ms) SELECT `domain_admins`.* FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
60
+ # PostfixAdmin::DomainAdmin Destroy (1.1ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`` IS NULL
61
+ #
62
+ # ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
63
+ # from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
64
+ # Caused by Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
65
+ # from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
66
+ #
67
+ # It works well with `dependent: :delete_all` instead.
68
+ #
69
+ # PostfixAdmin::DomainAdmin Destroy (0.4ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
70
+ # Domain <-> DomainAdmin <-> Admin
71
+ has_many :domain_admins, foreign_key: :domain, dependent: :delete_all
72
+
73
+ has_many :admins, through: :domain_admins
74
+
75
+ before_validation do |domain|
76
+ domain.domain = domain.domain&.downcase
77
+ domain.transport = "virtual"
78
+ end
79
+
80
+ scope :without_all, -> { where.not(domain: "ALL") }
81
+
82
+ # aliases that don't belong to a mailbox
83
+ def pure_aliases
84
+ rel_aliases.pure
85
+ end
86
+
87
+ def aliases_str
88
+ max_num_str(aliases)
89
+ end
90
+
91
+ def mailboxes_str
92
+ max_num_str(mailboxes)
93
+ end
94
+
95
+ def maxquota_str
96
+ max_num_str(maxquota)
97
+ end
98
+
99
+ private
100
+
101
+ def max_num_str(num)
102
+ case num
103
+ when -1
104
+ "Disabled"
105
+ when 0
106
+ "Unlimited"
107
+ else
108
+ num.to_s
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,19 @@
1
+ module PostfixAdmin
2
+ class DomainAdmin < ApplicationRecord
3
+ # version: 1841
4
+ # > describe domain_admins;
5
+ # +----------+--------------+------+-----+---------------------+-------+
6
+ # | Field | Type | Null | Key | Default | Extra |
7
+ # +----------+--------------+------+-----+---------------------+-------+
8
+ # | username | varchar(255) | NO | MUL | NULL | |
9
+ # | domain | varchar(255) | NO | | NULL | |
10
+ # | created | datetime | NO | | 2000-01-01 00:00:00 | |
11
+ # | active | tinyint(1) | NO | | 1 | |
12
+ # +----------+--------------+------+-----+---------------------+-------+
13
+
14
+ self.table_name = :domain_admins
15
+
16
+ belongs_to :admin, primary_key: :username, foreign_key: :username
17
+ belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module PostfixAdmin
2
+ class Log < ApplicationRecord
3
+ # version: 1841
4
+ # > describe log;
5
+ # +-----------+--------------+------+-----+---------------------+----------------+
6
+ # | Field | Type | Null | Key | Default | Extra |
7
+ # +-----------+--------------+------+-----+---------------------+----------------+
8
+ # | timestamp | datetime | NO | MUL | 2000-01-01 00:00:00 | |
9
+ # | username | varchar(255) | NO | | NULL | |
10
+ # | domain | varchar(255) | NO | MUL | NULL | |
11
+ # | action | varchar(255) | NO | | NULL | |
12
+ # | data | text | NO | | NULL | |
13
+ # | id | int(11) | NO | PRI | NULL | auto_increment |
14
+ # +-----------+--------------+------+-----+---------------------+----------------+
15
+
16
+ self.table_name = :log
17
+
18
+ belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
19
+ end
20
+ end
@@ -0,0 +1,126 @@
1
+ require 'postfix_admin/models/concerns/has_password'
2
+
3
+ module PostfixAdmin
4
+ class Mailbox < ApplicationRecord
5
+ # version: 1841
6
+ # > describe mailbox;
7
+ # +----------------+--------------+------+-----+---------------------+-------+
8
+ # | Field | Type | Null | Key | Default | Extra |
9
+ # +----------------+--------------+------+-----+---------------------+-------+
10
+ # | username | varchar(255) | NO | PRI | NULL | |
11
+ # | password | varchar(255) | NO | | NULL | |
12
+ # | name | varchar(255) | NO | | NULL | |
13
+ # | maildir | varchar(255) | NO | | NULL | |
14
+ # | quota | bigint(20) | NO | | 0 | |
15
+ # | local_part | varchar(255) | NO | | NULL | |
16
+ # | domain | varchar(255) | NO | MUL | NULL | |
17
+ # | created | datetime | NO | | 2000-01-01 00:00:00 | |
18
+ # | modified | datetime | NO | | 2000-01-01 00:00:00 | |
19
+ # | active | tinyint(1) | NO | | 1 | |
20
+ # | phone | varchar(30) | NO | | | |
21
+ # | email_other | varchar(255) | NO | | | |
22
+ # | token | varchar(255) | NO | | | |
23
+ # | token_validity | datetime | NO | | 2000-01-01 00:00:00 | |
24
+ # +----------------+--------------+------+-----+---------------------+-------+
25
+
26
+ self.table_name = :mailbox
27
+ self.primary_key = :username
28
+
29
+ include HasPassword
30
+
31
+ # attribute :quota_mb, :integer
32
+
33
+ validates :username, presence: true, uniqueness: { case_sensitive: false },
34
+ format: { with: RE_EMAIL_LIKE_WITH_ANCHORS,
35
+ message: "must be a valid email address" }
36
+ validates :maildir, presence: true, uniqueness: { case_sensitive: false }
37
+ validates :local_part, presence: true
38
+
39
+ # quota (KB)
40
+ validates :quota, presence: true,
41
+ numericality: { only_integer: true,
42
+ greater_than_or_equal_to: 0 }
43
+
44
+ belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
45
+ has_one :alias, foreign_key: :address, dependent: :destroy
46
+ has_one :quota_usage, class_name: "Quota2", foreign_key: :username,
47
+ dependent: :destroy
48
+
49
+ validate on: :create do |mailbox|
50
+ domain = mailbox.rel_domain
51
+ if !domain.mailboxes.zero? && domain.rel_mailboxes.count >= domain.mailboxes
52
+ message = "already has the maximum number of mailboxes " \
53
+ "(maximum is #{domain.mailboxes} mailboxes)"
54
+ mailbox.errors.add(:domain, message)
55
+ end
56
+ end
57
+
58
+ # just in case
59
+ validate on: :update do |mailbox|
60
+ mailbox.errors.add(:username, 'cannot be changed') if mailbox.username_changed?
61
+ mailbox.errors.add(:local_part, 'cannot be changed') if mailbox.local_part_changed?
62
+ end
63
+
64
+ validate do |mailbox|
65
+ next if mailbox.quota == -1
66
+
67
+ domain = mailbox.rel_domain
68
+
69
+ unless domain.maxquota.zero?
70
+ if mailbox.quota.zero?
71
+ mailbox.errors.add(:quota, "cannot be 0")
72
+ elsif mailbox.quota_mb > domain.maxquota
73
+ message = "must be less than or equal to #{domain.maxquota} (MB)"
74
+ mailbox.errors.add(:quota, message)
75
+ end
76
+ end
77
+ end
78
+
79
+ before_validation do |mailbox|
80
+ mailbox.name = "" if mailbox.name.nil?
81
+ mailbox.username = "#{mailbox.local_part}@#{mailbox.domain}"
82
+ mailbox.maildir ||= "#{mailbox.domain}/#{mailbox.username}/"
83
+ mailbox.build_alias(address: mailbox.username, goto: mailbox.username,
84
+ domain: mailbox.domain)
85
+ end
86
+
87
+ def quota_mb
88
+ raise Error, "quota is out of range: #{quota}" if quota < 0
89
+
90
+ quota / KB_TO_MB
91
+ end
92
+
93
+ def quota_mb=(value)
94
+ raise Error, "quota is out of range: #{value}" if value < 0
95
+
96
+ self.quota = value * KB_TO_MB
97
+ end
98
+
99
+ def quota_usage_str(format: "%6.1f")
100
+ usage_mb = if quota_usage
101
+ usage_mb = quota_usage.bytes / KB_TO_MB.to_f
102
+ else
103
+ 0.0
104
+ end
105
+
106
+ format % usage_mb
107
+ end
108
+
109
+ def quota_mb_str(format: "%6.1f")
110
+ case quota
111
+ when -1
112
+ # It's not sure what 'disabled' means for quota.
113
+ "Disabled"
114
+ when 0
115
+ "Unlimited"
116
+ else
117
+ quota_mb = quota / KB_TO_MB.to_f
118
+ format % quota_mb
119
+ end
120
+ end
121
+
122
+ def quota_display_str(format: "%6.1f")
123
+ "%s / %s" % [quota_usage_str(format: format), quota_mb_str(format: format)]
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,18 @@
1
+ module PostfixAdmin
2
+ class Quota2 < ApplicationRecord
3
+ # version: 1841
4
+ # > describe quota2;
5
+ # +----------+--------------+------+-----+---------+-------+
6
+ # | Field | Type | Null | Key | Default | Extra |
7
+ # +----------+--------------+------+-----+---------+-------+
8
+ # | username | varchar(100) | NO | PRI | NULL | |
9
+ # | bytes | bigint(20) | NO | | 0 | |
10
+ # | messages | int(11) | NO | | 0 | |
11
+ # +----------+--------------+------+-----+---------+-------+
12
+
13
+ self.table_name = :quota2
14
+ self.primary_key = :username
15
+
16
+ belongs_to :rel_mailbox, class_name: "Mailbox", foreign_key: :username
17
+ end
18
+ end
@@ -1,10 +1,9 @@
1
1
  require 'active_record'
2
- require 'postfix_admin/application_record'
3
- require 'postfix_admin/admin'
4
- require 'postfix_admin/domain'
5
- require 'postfix_admin/mailbox'
6
- require 'postfix_admin/alias'
7
- require 'postfix_admin/domain_admin'
8
- require 'postfix_admin/log'
9
- require 'postfix_admin/mail_domain'
10
- require 'postfix_admin/quota'
2
+ require 'postfix_admin/models/application_record'
3
+ require 'postfix_admin/models/admin'
4
+ require 'postfix_admin/models/domain'
5
+ require 'postfix_admin/models/mailbox'
6
+ require 'postfix_admin/models/alias'
7
+ require 'postfix_admin/models/domain_admin'
8
+ require 'postfix_admin/models/log'
9
+ require 'postfix_admin/models/quota2'