postfix_admin 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +21 -11
- data/Thorfile +30 -0
- data/bin/postfix_admin +5 -97
- data/lib/postfix_admin/base.rb +188 -0
- data/lib/postfix_admin/cli.rb +244 -79
- data/lib/postfix_admin/error.rb +4 -0
- data/lib/postfix_admin/models.rb +127 -17
- data/lib/postfix_admin/runner.rb +105 -0
- data/lib/postfix_admin/version.rb +2 -2
- data/lib/postfix_admin.rb +1 -157
- data/postfix_admin.gemspec +2 -1
- data/spec/base_spec.rb +218 -0
- data/spec/cli_spec.rb +165 -0
- data/spec/models_spec.rb +136 -0
- data/spec/postfix_admin.conf +5 -0
- data/spec/postfix_test.sql +250 -0
- data/spec/runner_spec.rb +144 -0
- data/spec/spec_helper.rb +160 -0
- metadata +38 -5
- data/Rakefile +0 -2
data/lib/postfix_admin/models.rb
CHANGED
@@ -1,35 +1,125 @@
|
|
1
1
|
require 'data_mapper'
|
2
2
|
|
3
|
-
|
3
|
+
#
|
4
|
+
# This extension is to avoid 'ArgumentError: invalid date' when datetime value of
|
5
|
+
# MySQL is '0000-00-00 00:00:00'.
|
6
|
+
#
|
7
|
+
class DateTime
|
8
|
+
class << self
|
9
|
+
|
10
|
+
alias org_new new
|
11
|
+
def new(year = -4712, mon = 1, mday = 1, hour = 0, min = 0, sec = 0, offset = 0, start = Date::ITALY)
|
12
|
+
if year == 0
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
org_new(year, mon, mday, hour, min, sec, offset, start)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module PostfixAdmin
|
4
22
|
class Admin
|
5
23
|
include ::DataMapper::Resource
|
6
24
|
property :username, String, :key => true
|
7
25
|
property :password, String
|
8
|
-
property :created, DateTime
|
9
|
-
property :modified, DateTime
|
26
|
+
property :created, DateTime, :default => DateTime.now
|
27
|
+
property :modified, DateTime, :default => DateTime.now
|
10
28
|
|
29
|
+
has n, :domain_admins, :child_key => :username
|
30
|
+
has n, :domains, :model => 'Domain', :through => :domain_admins, :via => :domain
|
11
31
|
storage_names[:default] = 'admin'
|
32
|
+
|
33
|
+
def has_domain?(domain_name)
|
34
|
+
if super_admin?
|
35
|
+
Domain.exist?(domain_name)
|
36
|
+
else
|
37
|
+
exist_domain?(domain_name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def super_admin=(value)
|
42
|
+
if value
|
43
|
+
domains << Domain.find('ALL')
|
44
|
+
save or raise "Could not save ALL domain for Admin"
|
45
|
+
else
|
46
|
+
domain_admins(:domain_name => 'ALL').destroy or raise "Could not destroy DoaminAdmin for Admin"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def super_admin?
|
51
|
+
exist_domain?('ALL')
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find(username)
|
55
|
+
Admin.first(:username => username)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.exist?(username)
|
59
|
+
!!Admin.find(username)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.unnecessary
|
63
|
+
all.delete_if do |admin|
|
64
|
+
admin.domains.size > 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def exist_domain?(domain_name)
|
71
|
+
!!domains.first(:domain_name => domain_name)
|
72
|
+
end
|
12
73
|
end
|
13
74
|
|
14
75
|
class Domain
|
15
76
|
include ::DataMapper::Resource
|
16
|
-
property :
|
17
|
-
property :
|
18
|
-
property :
|
77
|
+
property :domain_name, String, :field => 'domain', :key => true
|
78
|
+
property :maxaliases, Integer, :field => 'aliases'
|
79
|
+
property :maxmailboxes, Integer, :field => 'mailboxes'
|
19
80
|
property :maxquota, Integer
|
20
|
-
property :transport, String
|
21
|
-
property :backupmx, Integer
|
81
|
+
property :transport, String, :default => 'virtual'
|
82
|
+
property :backupmx, Integer, :default => 0
|
22
83
|
property :description, String
|
84
|
+
property :created, DateTime, :default => DateTime.now
|
85
|
+
property :modified, DateTime, :default => DateTime.now
|
23
86
|
|
87
|
+
has n, :domain_admins, :child_key => :domain_name
|
88
|
+
has n, :admins, :model => 'Admin', :through => :domain_admins
|
89
|
+
|
90
|
+
has n, :mailboxes, :model => 'Mailbox', :child_key => :domain_name
|
91
|
+
has n, :aliases, :model => 'Alias', :child_key => :domain_name
|
24
92
|
storage_names[:default] = 'domain'
|
93
|
+
|
94
|
+
def self.all_without_special_domain
|
95
|
+
Domain.all(:domain_name.not => 'ALL')
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.find(domain)
|
99
|
+
Domain.first(:domain_name => domain)
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.exist?(domain)
|
103
|
+
!!Domain.find(domain)
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.num_total_aliases
|
107
|
+
Alias.count - Mailbox.count
|
108
|
+
end
|
109
|
+
|
110
|
+
def num_total_aliases
|
111
|
+
aliases.count - mailboxes.count
|
112
|
+
end
|
25
113
|
end
|
26
114
|
|
27
115
|
class DomainAdmin
|
28
116
|
include ::DataMapper::Resource
|
117
|
+
property :created, DateTime, :default => DateTime.now
|
118
|
+
property :domain_name, String, :field => 'domain', :key => true
|
29
119
|
property :username, String, :key => true
|
30
|
-
property :domain, String, :key => true
|
31
|
-
property :created, DateTime
|
32
120
|
|
121
|
+
belongs_to :domain, :model => 'Domain', :child_key => :domain_name
|
122
|
+
belongs_to :admin, :model => 'Admin', :child_key => :username
|
33
123
|
storage_names[:default] = 'domain_admins'
|
34
124
|
end
|
35
125
|
|
@@ -37,25 +127,45 @@ class PostfixAdmin
|
|
37
127
|
include ::DataMapper::Resource
|
38
128
|
property :username, String, :key => true
|
39
129
|
property :name, String
|
130
|
+
property :domain_name, String, :field => 'domain'
|
40
131
|
property :password, String
|
41
|
-
property :domain, String
|
42
132
|
property :maildir, String
|
43
133
|
property :quota, Integer
|
44
134
|
# property :local_part, String
|
45
|
-
property :created, DateTime
|
46
|
-
property :modified, DateTime
|
135
|
+
property :created, DateTime, :default => DateTime.now
|
136
|
+
property :modified, DateTime, :default => DateTime.now
|
137
|
+
|
138
|
+
belongs_to :domain, :model => 'Domain', :child_key => :domain_name
|
47
139
|
|
48
140
|
storage_names[:default] = 'mailbox'
|
141
|
+
|
142
|
+
def self.find(username)
|
143
|
+
Mailbox.first(:username => username)
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.exist?(username)
|
147
|
+
!!Mailbox.find(username)
|
148
|
+
end
|
49
149
|
end
|
50
150
|
|
51
151
|
class Alias
|
52
152
|
include ::DataMapper::Resource
|
53
153
|
property :address, String, :key => true
|
54
|
-
property :goto, Text
|
55
|
-
property :
|
56
|
-
property :created, DateTime
|
57
|
-
property :modified, DateTime
|
154
|
+
property :goto, Text
|
155
|
+
property :domain_name, String, :field => 'domain'
|
156
|
+
property :created, DateTime, :default => DateTime.now
|
157
|
+
property :modified, DateTime, :default => DateTime.now
|
158
|
+
|
159
|
+
belongs_to :domain, :model => 'Domain', :child_key => :domain_name
|
58
160
|
|
59
161
|
storage_names[:default] = 'alias'
|
162
|
+
|
163
|
+
def self.find(address)
|
164
|
+
Alias.first(:address => address)
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.exist?(address)
|
168
|
+
!!Alias.find(address)
|
169
|
+
end
|
60
170
|
end
|
61
171
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'postfix_admin'
|
3
|
+
require 'postfix_admin/cli'
|
4
|
+
|
5
|
+
module PostfixAdmin
|
6
|
+
class Runner < Thor
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@cli = CLI.new
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "summary [example.com]", "Summarize the usage of PostfixAdmin"
|
13
|
+
def summary(domain_name=nil)
|
14
|
+
runner{ @cli.show_summary(domain_name) }
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "show [example.com]", "List of domains"
|
18
|
+
def show(domain_name=nil)
|
19
|
+
runner{ @cli.show(domain_name) }
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "setup example.com password", "Setup a domain"
|
23
|
+
def setup(domain_name, password)
|
24
|
+
runner{ @cli.setup_domain(domain_name, password) }
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "super_admin admin@example.com", "Enable super admin flag of an admin"
|
28
|
+
method_option :disable, :type => :boolean, :aliases => "-d", :desc => "Disable super admin flag"
|
29
|
+
def super_admin(user_name)
|
30
|
+
runner{ @cli.super_admin(user_name, options[:disable]) }
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "admin_passwd admin@example.com new_password", "Change password of admin"
|
34
|
+
def admin_passwd(user_name, password)
|
35
|
+
runner{ @cli.change_admin_password(user_name, password) }
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "account_passwd user@example.com new_password", "Change password of account"
|
39
|
+
def account_passwd(user_name, password)
|
40
|
+
runner{ @cli.change_account_password(user_name, password) }
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "add_domain example.com", "Add a domain"
|
44
|
+
def add_domain(domain_name)
|
45
|
+
runner{ @cli.add_domain(domain_name) }
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "delete_domain example.com", "Delete a domain"
|
49
|
+
def delete_domain(domain_name)
|
50
|
+
runner{ @cli.delete_domain(domain_name) }
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "delete_admin admin@example.com", "Delete an admin"
|
54
|
+
def delete_admin(user_name)
|
55
|
+
runner{ @cli.delete_admin(user_name) }
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "delete_account user@example.com", "Delete an account"
|
59
|
+
def delete_account(address)
|
60
|
+
runner{ @cli.delete_account(address) }
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "add_account user@example.com password", "Add an account"
|
64
|
+
def add_account(address, password)
|
65
|
+
runner{ @cli.add_account(address, password) }
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "add_admin admin@example.com password", "Add an admin user"
|
69
|
+
method_option :super, :type => :boolean, :aliases => "-s", :desc => "register as a super admin"
|
70
|
+
def add_admin(user_name, password)
|
71
|
+
runner{ @cli.add_admin(user_name, password, options[:super]) }
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "add_admin_domain admin@example.com example.com", "Add admin_domain"
|
75
|
+
def add_admin_domain(user_name, domain_name)
|
76
|
+
runner{ @cli.add_admin_domain(user_name, domain_name) }
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "add_alias alias@example.com goto@example.net", "Add an alias"
|
80
|
+
def add_alias(address, goto)
|
81
|
+
runner{ @cli.add_alias(address, goto) }
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "delete_alias alias@example.com", "Delete an alias"
|
85
|
+
def delete_alias(address)
|
86
|
+
runner{ @cli.delete_alias(address) }
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "version", "Show postfix_admin version"
|
90
|
+
def version
|
91
|
+
require 'postfix_admin/version'
|
92
|
+
say "postfix_admin #{VERSION}"
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def runner
|
98
|
+
begin
|
99
|
+
yield
|
100
|
+
rescue => e
|
101
|
+
warn e.message
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0
|
1
|
+
module PostfixAdmin
|
2
|
+
VERSION = "0.1.0"
|
3
3
|
end
|
data/lib/postfix_admin.rb
CHANGED
@@ -1,158 +1,2 @@
|
|
1
1
|
require "postfix_admin/version"
|
2
|
-
require
|
3
|
-
|
4
|
-
require 'date'
|
5
|
-
require 'data_mapper'
|
6
|
-
|
7
|
-
class PostfixAdmin
|
8
|
-
def initialize(config)
|
9
|
-
DataMapper.setup(:default, config['database'])
|
10
|
-
DataMapper.finalize
|
11
|
-
@config = {}
|
12
|
-
@config[:aliases] = config['aliases'] || 30
|
13
|
-
@config[:mailboxes] = config['mailboxes'] || 30
|
14
|
-
@config[:maxquota] = config['maxquota'] || 100
|
15
|
-
@config[:mailbox_quota] = @config[:maxquota] * 1024 * 1000
|
16
|
-
end
|
17
|
-
def add_admin_domain(username, domain)
|
18
|
-
unless admin_exist?(username)
|
19
|
-
raise "Error: #{username} is not resistered as admin."
|
20
|
-
end
|
21
|
-
unless domain_exist?(domain)
|
22
|
-
raise "Error: Invalid domain #{domain}!"
|
23
|
-
end
|
24
|
-
if admin_domain_exist?(username, domain)
|
25
|
-
raise "Error: #{username} is already resistered as admin of #{domain}."
|
26
|
-
end
|
27
|
-
|
28
|
-
domain_admin = DomainAdmin.new
|
29
|
-
domain_admin.attributes = {
|
30
|
-
:username => username,
|
31
|
-
:domain => domain,
|
32
|
-
:created => DateTime.now
|
33
|
-
}
|
34
|
-
domain_admin.save
|
35
|
-
end
|
36
|
-
def add_admin(username, password)
|
37
|
-
if admin_exist?(username)
|
38
|
-
raise "Error: #{username} is already resistered as admin."
|
39
|
-
end
|
40
|
-
admin = Admin.new
|
41
|
-
admin.attributes = {
|
42
|
-
:username => username,
|
43
|
-
:password => password,
|
44
|
-
:created => DateTime.now,
|
45
|
-
:modified => DateTime.now
|
46
|
-
}
|
47
|
-
admin.save
|
48
|
-
end
|
49
|
-
def add_account(address, password)
|
50
|
-
if address !~ /.+\@.+\..+/
|
51
|
-
raise "Error: Invalid mail address! #{address}"
|
52
|
-
end
|
53
|
-
user, domain = address.split(/@/)
|
54
|
-
path = "#{domain}/#{address}/"
|
55
|
-
|
56
|
-
unless domain_exist?(domain)
|
57
|
-
raise "Error: Invalid domain! #{address}"
|
58
|
-
end
|
59
|
-
|
60
|
-
if alias_exist?(address)
|
61
|
-
raise "Error: #{address} is already resistered."
|
62
|
-
end
|
63
|
-
mail_alias = Alias.new
|
64
|
-
mail_alias.attributes = {
|
65
|
-
:address => address,
|
66
|
-
:goto => address,
|
67
|
-
:domain => domain,
|
68
|
-
:created => DateTime.now,
|
69
|
-
:modified => DateTime.now
|
70
|
-
}
|
71
|
-
mail_alias.save
|
72
|
-
|
73
|
-
mailbox = Mailbox.new
|
74
|
-
mailbox.attributes = {
|
75
|
-
:username => address,
|
76
|
-
:password => password,
|
77
|
-
:name => '',
|
78
|
-
:maildir => path,
|
79
|
-
:quota => @config[:mailbox_quota],
|
80
|
-
:domain => domain,
|
81
|
-
# :local_part => user,
|
82
|
-
:created => DateTime.now,
|
83
|
-
:modified => DateTime.now
|
84
|
-
}
|
85
|
-
mailbox.save
|
86
|
-
end
|
87
|
-
def add_alias(address, goto)
|
88
|
-
if alias_exist?(address)
|
89
|
-
goto_text = "#{address},#{goto}"
|
90
|
-
mail_alias = Alias.first(:address => address)
|
91
|
-
mail_alias.update(:goto => goto_text, :modified => DateTime.now)
|
92
|
-
else
|
93
|
-
raise "Error: Invalid mail address! #{address}"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
def add_domain(domain_name)
|
97
|
-
if domain_name !~ /.+\..+/
|
98
|
-
raise "Error: Ivalid domain! #{domain_name}"
|
99
|
-
end
|
100
|
-
if domain_exist?(domain_name)
|
101
|
-
raise "Error: #{domain_name} is already registered!"
|
102
|
-
end
|
103
|
-
domain = Domain.new
|
104
|
-
domain.attributes = {
|
105
|
-
:domain => domain_name,
|
106
|
-
:description => domain_name,
|
107
|
-
:aliases => @config[:aliases],
|
108
|
-
:mailboxes => @config[:mailboxes],
|
109
|
-
:maxquota => @config[:maxquota],
|
110
|
-
:transport => "virtual",
|
111
|
-
:backupmx => 0
|
112
|
-
}
|
113
|
-
domain.save
|
114
|
-
end
|
115
|
-
def delete_domain(domain)
|
116
|
-
unless domain_exist?(domain)
|
117
|
-
raise "Error: #{domain} is not found!"
|
118
|
-
end
|
119
|
-
username = "admin@#{domain}"
|
120
|
-
Admin.all(:username => username).destroy
|
121
|
-
DomainAdmin.all(:username => username).destroy
|
122
|
-
Mailbox.all(:domain => domain).destroy
|
123
|
-
Alias.all(:domain => domain).destroy
|
124
|
-
Domain.all(:domain => domain).destroy
|
125
|
-
end
|
126
|
-
def admin_domain_exist?(username, domain)
|
127
|
-
DomainAdmin.all(:username => username, :domain => domain).count != 0
|
128
|
-
end
|
129
|
-
def admin_exist?(admin)
|
130
|
-
Admin.all(:username => admin).count != 0
|
131
|
-
end
|
132
|
-
def alias_exist?(address)
|
133
|
-
Alias.all(:address => address).count != 0
|
134
|
-
end
|
135
|
-
def domain_exist?(domain)
|
136
|
-
Domain.all(:domain => domain).count != 0
|
137
|
-
end
|
138
|
-
def domains
|
139
|
-
Domain.all(:domain.not => 'ALL', :order => :domain)
|
140
|
-
end
|
141
|
-
def admins
|
142
|
-
Admin.all(:order => 'username')
|
143
|
-
end
|
144
|
-
def mailboxes(domain=nil)
|
145
|
-
if domain
|
146
|
-
Mailbox.all(:domain => domain, :order => :username)
|
147
|
-
else
|
148
|
-
Mailbox.all(:order => :username)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
def admin_domains(username=nil)
|
152
|
-
if username
|
153
|
-
DomainAdmin.all(:username => username, :order => :domain)
|
154
|
-
else
|
155
|
-
DomainAdmin.all(:order => :domain)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
2
|
+
require "postfix_admin/base"
|