sakura-cli 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: efd5e983753789e52601e9ac4a964b12126a4332
4
- data.tar.gz: 738d21ce3ec8ead5bbc4a299cc2facb31d01c780
2
+ SHA256:
3
+ metadata.gz: 63e925b0d5771393ece520ba74ef24695fadf188e82980ae0cc59864a6b3abee
4
+ data.tar.gz: 2c65e42f350a073663eeb9f912b72b07eb9eb2236e839d29a0d910cd481fb483
5
5
  SHA512:
6
- metadata.gz: 1e0ff298884e5271b0b22a4b30d9500c603fa0597b6db756546a225b77ce0f64d17efd72c58f19d0c59bc95a23b22cc30e021f9b67bb422dbc1dd1cb649a3f4a
7
- data.tar.gz: 7ea1e26078515dc5bffd37667870683d1a9c2380c0a6fa0f6da8b452fbf9a022d3903f6c0fdcf91d65b2e97335675f258c4517101530c49e2986487672bddfad
6
+ metadata.gz: d3b7c3668f914eefd3735d32370b2cd4031f45aef33a9e009a490a2b2a6569e59580ab66234426cd8e633163d31aec53945dd16d87068ce50b71b7ad6516d1f4
7
+ data.tar.gz: 259300757340ef237b273025a8438d841f16b65365004fbb60aaa07f6783de2a52daa0af884cf95cfcc33d6983f8695f01007c4877032603a2428e0d9411c35f
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ /.idea/
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Shintaro Kojima
3
+ Copyright (c) 2021 Shintaro Kojima
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -12,13 +12,13 @@ Sakura CLI をインストールします.
12
12
  gem install sakura-cli
13
13
  ```
14
14
 
15
- Sakura CLI は[PhantomJS](http://phantomjs.org/download.html) に依存しています.
15
+ Sakura CLI は[ChromeDriver](https://chromedriver.chromium.org/downloads) に依存しています.
16
16
  お使いのOS に合った方法でインストールしてください.
17
17
 
18
18
  Mac の場合は
19
19
 
20
20
  ```zsh
21
- brew install phantomjs
21
+ brew install chromedriver
22
22
  ```
23
23
 
24
24
  でもインストールできます.
@@ -65,6 +65,7 @@ Commands:
65
65
  sakura mail password LOCAL_PART [PASSWORD] # Update password of a mail address
66
66
  sakura mail quota LOCAL_PART [VALUE] # Update or show quota of a mail address
67
67
  sakura mail scan LOCAL_PART [enable|disable] # Switch virus scan
68
+ sakura mail show LOCAL_PART # Display information about a mail address
68
69
  ```
69
70
 
70
71
  ### メールアドレス一覧
@@ -74,12 +75,25 @@ Commands:
74
75
  ```zsh
75
76
  $ sakura mail list
76
77
  # domain: example.com
77
- address virus_scan usage / quota
78
+ address usage / quota ( %)
78
79
  ---------------------------------------------------------
79
- dummy true 379.13KB / 200MB
80
- dummy001 true 1.79MB / 2GB
81
- dummy002 true 6.28KB / 2GB
82
- postmaster true 0B / 2GB
80
+ dummy 893KB / 200MB ( 0%)
81
+ dummy001 19.5MB / 200MB ( 9%)
82
+ dummy002 11.4MB / 200MB ( 5%)
83
+ postmaster 9.75MB / 200MB ( 4%)
84
+ ```
85
+
86
+ ### メールアドレス詳細
87
+
88
+ ```sakura mail show``` コマンドで, あるメールアドレスの詳細を表示できます.
89
+
90
+ ```zsh
91
+ $ sakura mail show dummy
92
+ usage / quota: 893KB / 200MB ( 0%)
93
+ forward_to: foo@example.com
94
+ keep mail: true
95
+ virus scan: false
96
+ spam filter: disable
83
97
  ```
84
98
 
85
99
  ### メールアドレス作成
@@ -167,4 +181,4 @@ dotenv -f ~/.sakura.env sakura
167
181
 
168
182
  ## Copyright and License
169
183
 
170
- Copyright (c) 2015 Shintaro Kojima. Code released under the [MIT license](LICENSE).
184
+ Copyright (c) 2021 Shintaro Kojima. Code released under the [MIT license](LICENSE).
data/lib/sakura.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'uri'
2
2
 
3
3
  module Sakura
4
- BASE_URL = URI('https://secure.sakura.ad.jp/rscontrol/')
4
+ BASE_URL = URI('https://secure.sakura.ad.jp/rs/cp/')
5
5
  end
@@ -7,41 +7,51 @@ module Sakura
7
7
  module Cli
8
8
  class Mail < Thor
9
9
  desc 'list', 'List all mail addresses of the domain'
10
+
10
11
  def list
12
+ preprocess
13
+
11
14
  addrs = MailAddress.all
12
15
 
13
16
  puts "# domain: #{Client.current_session.domain}"
14
17
  puts MailAddress.header
15
- addrs.each {|addr| puts addr.to_s }
18
+ addrs.each { |addr| puts addr.to_s }
16
19
  end
17
20
 
18
21
  desc 'create LOCAL_PART [PASSWORD]', 'Create a mail address'
19
- def create(local_part, password=nil)
22
+
23
+ def create(local_part, password = nil)
24
+ preprocess
25
+
20
26
  password ||= ask_password
21
27
 
22
28
  begin
23
29
  MailAddress.create local_part, password
24
30
  rescue
31
+ raise if options[:verbose]
25
32
  abort $!
26
33
  end
27
34
  end
28
35
 
29
36
  desc 'delete LOCAL_PART', 'Delete a mail address'
37
+
30
38
  def delete(local_part)
31
- mail = MailAddress.find(local_part)
32
- abort %(No mail address: "#{local_part}") unless mail
39
+ preprocess
33
40
 
34
41
  begin
35
- mail.delete
42
+ find(local_part).delete
36
43
  rescue
44
+ raise if options[:verbose]
37
45
  abort $!
38
46
  end
39
47
  end
40
48
 
41
49
  desc 'quota LOCAL_PART [VALUE]', 'Update or show quota of a mail address'
42
- def quota(local_part, value=nil)
43
- mail = MailAddress.find(local_part)
44
- abort %(No mail address: "#{local_part}") unless mail
50
+
51
+ def quota(local_part, value = nil)
52
+ preprocess
53
+
54
+ mail = find(local_part)
45
55
 
46
56
  begin
47
57
  if value
@@ -50,29 +60,35 @@ module Sakura
50
60
  puts mail.quota
51
61
  end
52
62
  rescue
63
+ raise if options[:verbose]
53
64
  abort $!
54
65
  end
55
66
  end
56
67
 
57
68
  desc 'password LOCAL_PART [PASSWORD]', 'Update password of a mail address'
58
- def password(local_part, password=nil)
69
+
70
+ def password(local_part, password = nil)
71
+ preprocess
72
+
59
73
  password ||= ask_password
60
- mail = MailAddress.find(local_part)
61
- abort %(No mail address: "#{local_part}") unless mail
74
+ mail = find(local_part)
62
75
 
63
76
  begin
64
77
  mail.password = password
65
78
  rescue
79
+ raise if options[:verbose]
66
80
  abort $!
67
81
  end
68
82
  end
69
83
 
70
- desc 'scan LOCAL_PART [enable|disable]', 'Switch virus scan'
71
- def scan(local_part, value=nil)
84
+ desc 'scan LOCAL_PART [enable|disable]', 'Switch virus scan configuration of a mail address'
85
+
86
+ def scan(local_part, value = nil)
87
+ preprocess
88
+
72
89
  self.class.handle_argument_error if value && value !~ /enable|disable/
73
90
 
74
- mail = MailAddress.find(local_part)
75
- abort %(No mail address: "#{local_part}") unless mail
91
+ mail = find(local_part)
76
92
 
77
93
  begin
78
94
  case value
@@ -84,18 +100,21 @@ module Sakura
84
100
  puts mail.virus_scan
85
101
  end
86
102
  rescue
103
+ raise if options[:verbose]
87
104
  abort $!
88
105
  end
89
106
  end
90
107
 
91
108
  desc 'forward LOCAL_PART [{add|remove} EMAIL]', 'Add, remove or show mail address(es) to forward'
92
- def forward(local_part, operation=nil, mail_to_forward=nil)
109
+
110
+ def forward(local_part, operation = nil, mail_to_forward = nil)
111
+ preprocess
112
+
93
113
  if (operation && operation !~ /add|remove/) || (!mail_to_forward && operation)
94
114
  self.class.handle_argument_error
95
115
  end
96
116
 
97
- mail = MailAddress.find(local_part)
98
- abort %(No mail address: "#{local_part}") unless mail
117
+ mail = find(local_part)
99
118
 
100
119
  begin
101
120
  case operation
@@ -104,19 +123,22 @@ module Sakura
104
123
  when 'remove'
105
124
  mail.delete_forward_to mail_to_forward
106
125
  when nil
107
- mail.forward_list.each {|m| puts m }
126
+ mail.forward_list.each { |m| puts m }
108
127
  end
109
128
  rescue
129
+ raise if options[:verbose]
110
130
  abort $!
111
131
  end
112
132
  end
113
133
 
114
- desc 'keep LOCAL_PART [enable|disable]', 'Switch keep or flush mails'
115
- def keep(local_part, value=nil)
134
+ desc 'keep LOCAL_PART [enable|disable]', 'Switch keep or flush configuration of a mail address'
135
+
136
+ def keep(local_part, value = nil)
137
+ preprocess
138
+
116
139
  self.class.handle_argument_error if value && value !~ /enable|disable/
117
140
 
118
- mail = MailAddress.find(local_part)
119
- abort %(No mail address: "#{local_part}") unless mail
141
+ mail = find(local_part)
120
142
 
121
143
  begin
122
144
  case value
@@ -128,17 +150,62 @@ module Sakura
128
150
  puts mail.keep
129
151
  end
130
152
  rescue
153
+ raise if options[:verbose]
131
154
  abort $!
132
155
  end
133
156
  end
134
157
 
158
+ desc 'filter LOCAL_PART [mark|disable|discard|quarantine]', 'Configure spam filter of a mail address'
159
+
160
+ def filter(local_part, value = nil)
161
+ preprocess
162
+
163
+ self.class.handle_argument_error if value && value !~ /mark|disable|discard|quarantine/
164
+
165
+ mail = find(local_part)
166
+
167
+ begin
168
+ case value
169
+ when nil
170
+ puts mail.spam_filter
171
+ else
172
+ mail.spam_filter = value.to_sym
173
+ end
174
+ rescue
175
+ raise if options[:verbose]
176
+ abort $!
177
+ end
178
+ end
179
+
180
+ desc 'show LOCAL_PART', 'Display information about a mail address'
181
+
182
+ def show(local_part)
183
+ preprocess
184
+
185
+ puts find(local_part).detail
186
+ end
135
187
 
136
188
  private
137
189
 
190
+ def preprocess
191
+ Client.verbose = true if options[:verbose]
192
+ end
193
+
194
+ def find(local_part)
195
+ begin
196
+ mail = MailAddress.find(local_part)
197
+ rescue Capybara::ElementNotFound
198
+ raise if options[:verbose]
199
+ abort %(No mail address: "#{local_part}")
200
+ end
201
+
202
+ mail
203
+ end
204
+
138
205
  def ask_password
139
206
  password = ask('password?', echo: false)
140
207
  puts
141
- confirm = ask('password(confirm)?', echo: false)
208
+ confirm = ask('password(confirm)?', echo: false)
142
209
  puts
143
210
  abort "password doesn't match" unless password == confirm
144
211
 
@@ -4,6 +4,13 @@ require 'sakura/cli/mail'
4
4
  module Sakura
5
5
  module Cli
6
6
  class Root < Thor
7
+ class_option :verbose, type: :boolean
8
+
9
+ # Allow failed exit codes (see https://github.com/erikhuda/thor/issues/244)
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+
7
14
  desc 'mail', 'Manage mail addresses'
8
15
  subcommand 'mail', Mail
9
16
  end
@@ -1,5 +1,5 @@
1
1
  module Sakura
2
2
  module Cli
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
data/lib/sakura/client.rb CHANGED
@@ -1,57 +1,77 @@
1
- require 'capybara/poltergeist'
1
+ require 'capybara/dsl'
2
+ require 'selenium-webdriver'
3
+
2
4
  require 'sakura'
3
5
  require 'sakura/cli/version'
4
6
 
5
- Capybara.default_driver = :poltergeist
6
- Capybara.current_session.driver.headers = {'User-Agent' => "sakura-cli/#{Sakura::Cli::VERSION}"}
7
+ Capybara.default_driver = :selenium_chrome_headless
7
8
 
8
9
  module Sakura
9
10
  class Client
10
11
  include Capybara::DSL
11
12
 
12
13
  attr_reader :domain
14
+ @@verbose = false
13
15
 
14
- def self.current_session
15
- @current_session ||= new
16
- end
16
+ class << self
17
+ def current_session
18
+ @current_session ||= new
19
+ end
17
20
 
21
+ def verbose=(bool)
22
+ @@verbose = !!bool
23
+ end
24
+ end
18
25
 
19
26
  def initialize
20
27
  @domain, @passwd = credentials
21
28
  end
22
29
 
23
30
  def login?
24
- !@last_login.nil?
31
+ @logged_in
25
32
  end
26
33
 
27
34
  def login
35
+ $stderr.puts 'login' if @@verbose
36
+
28
37
  visit BASE_URL
29
- fill_in 'domain', with: @domain
30
- fill_in 'password', with: @passwd
31
- find('form input[type=image]').click
38
+ fill_in 'login-username', with: @domain
39
+ fill_in 'login-password', with: @passwd
40
+ find('form button[type=submit]').click
41
+
42
+ wait_for_loading
32
43
 
33
- @last_login = Time.now if page.text =~ /ログインドメイン: #{@domain}/
44
+ if page.text =~ /サーバコントロールパネル ホーム/
45
+ @logged_in = true
46
+ end
34
47
 
35
48
  raise_when_error
36
49
  login?
37
50
  end
38
51
 
39
- def get(url)
52
+ def get(url, expected)
40
53
  login unless login?
54
+
55
+ $stderr.puts "visit #{url}" if @@verbose
41
56
  visit url
57
+ wait_for_loading
58
+ unless page.text =~ expected
59
+ raise Timeout::Error.new('Timed out')
60
+ end
61
+
42
62
  page
43
63
  end
44
64
 
45
- def process(url, &block)
65
+ def process(url, expected, &block)
46
66
  login unless login?
47
- visit url
48
- instance_eval &block
67
+
68
+ get url, expected
69
+ yield page
49
70
 
50
71
  raise_when_error
51
72
  page
52
73
  end
53
74
 
54
-
55
75
  private
56
76
 
57
77
  def credentials
@@ -66,8 +86,20 @@ module Sakura
66
86
  end
67
87
 
68
88
  def raise_when_error
69
- error = page.all('.error-message')
70
- raise error.first.text unless error.empty?
89
+ %w[.error .input-error].each do |cls|
90
+ error = page.all(cls)
91
+ raise error.first.text unless error.empty?
92
+ end
93
+ end
94
+
95
+ def wait_for_loading
96
+ 5.times do
97
+ if find_all('読み込み中').empty?
98
+ break
99
+ else
100
+ $stderr.puts 'still loading ...' if @@verbose
101
+ end
102
+ end
71
103
  end
72
104
  end
73
105
  end
@@ -2,92 +2,133 @@ require 'sakura/client'
2
2
 
3
3
  module Sakura
4
4
  class MailAddress
5
- MAIL_URL = BASE_URL + 'rs/mail'
5
+ MAIL_URL = BASE_URL + 'users/list/'
6
6
 
7
- attr_reader :address, :virus_scan, :usage, :quota, :link, :link_to_delete
7
+ attr_reader :address, :usage, :quota, :link
8
8
 
9
9
  class << self
10
10
  def create(local_part, password)
11
- Client.current_session.process(MAIL_URL) do
12
- fill_in 'NewUsername', with: local_part
13
- fill_in 'Password1', with: password
14
- fill_in 'Password2', with: password
15
- find('input[name="Submit_useradd"]').click
11
+ Client.current_session.process(MAIL_URL, /メールアドレス一覧/) do |page|
12
+ page.first(:xpath, '//a[text() = "新規追加"]').click
13
+
14
+ page.find(:xpath, '//label[contains(text(), "ユーザ名")]/..//input')
15
+ .fill_in with: local_part
16
+ page.find_all(:xpath, '//label[contains(text(), "パスワード")]/..//input').each do |e|
17
+ e.fill_in with: password
18
+ end
19
+ page.find(:xpath, '//button[text() = "作成する"]').click
16
20
  end
17
21
 
18
22
  true
19
23
  end
20
24
 
21
25
  def all
22
- page = Client.current_session.get(MAIL_URL)
26
+ page = Client.current_session.get(MAIL_URL, /メールアドレス一覧/)
27
+ page.first('.input-text').select '300件'
23
28
 
24
- page.all(:xpath, '//a[contains(@href, "mail?Username=")]/../..').map{|element|
25
- arguments = element.all('td').map(&:text)[0..-2] + element.all('a').map{|i| i[:href] }
26
- MailAddress.new(*arguments)
29
+ page.all(:css, '.entity-lists .entity-lists-row').map { |element|
30
+ MailAddress.new_from_element(element)
27
31
  }
28
32
  end
29
33
 
30
34
  def find(local_part)
31
- all.find {|m| m.address == local_part }
35
+ page = Client.current_session.get(MAIL_URL, /メールアドレス一覧/)
36
+ page.first('.input-text').select '300件'
37
+
38
+ element = page.find(:xpath, "//div[contains(@class, \"entity-lists-row\")]//div[@class=\"username\" and contains(text(), \"#{local_part}\")]/../../..")
39
+ MailAddress.new_from_element(element)
40
+ end
41
+
42
+ def new_from_element(element)
43
+ MailAddress.new(
44
+ element.find('.username').text.split('@').first,
45
+ element.find('.capacity').text
46
+ )
32
47
  end
33
48
 
34
49
  def header
35
- str = tabularize('address', 'virus_scan', 'usage', 'quota')
36
- "#{str}\n#{'-' * (str.size+1)}"
50
+ str = tabularize('address', 'usage', 'quota', '%')
51
+ "#{str}\n#{'-' * (str.size + 1)}"
37
52
  end
38
53
 
39
54
  def tabularize(*args)
40
55
  args[0].ljust(20) <<
41
- args[1].to_s.rjust(11) <<
42
- "#{args[2]} /".to_s.rjust(15) <<
43
- args[3].to_s.rjust(10)
56
+ "#{args[1]} /".to_s.rjust(15) <<
57
+ args[2].to_s.rjust(10) <<
58
+ " (#{args[3].to_s.rjust(3)})"
44
59
  end
45
60
  end
46
61
 
47
-
48
- def initialize(address, virus_scan, usage, quota, link, link_to_delete=nil)
49
- @address = address
50
- @virus_scan = virus_scan == '○'
51
- @usage = usage
52
- @quota = quota
53
- @link = link
54
- @link_to_delete = link_to_delete
62
+ def initialize(address, usage)
63
+ @address = address
64
+ @usage, @quota = usage.split(/\s*\/\s*/)
55
65
  end
56
66
 
57
67
  def delete
58
- link = @link_to_delete
59
- Client.current_session.process(MAIL_URL) do
60
- find("a[href=\"#{link}\"]").click
68
+ # FIXME: The URL won't work when mail addresses are more than 300
69
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
70
+ page.accept_confirm do
71
+ page.find('button.dangerous-button').click
72
+ end
61
73
  end
62
74
 
63
75
  true
64
76
  end
65
77
 
66
78
  def quota=(value)
67
- page = Client.current_session.process(MAIL_URL + @link) {
68
- fill_in 'MailQuota', with: value
69
- find('input[name="Submit_quotaedit"]').click
70
- }
79
+ # FIXME: The URL won't work when mail addresses are more than 300
80
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
81
+ case value
82
+ when /(\d+)\s*GB$/
83
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
84
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'GB'
85
+ when /(\d+)\s*MB$/
86
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
87
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'MB'
88
+ when /(\d+)\s*KB$/
89
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
90
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'KB'
91
+ when /(\d+)\s*B$/
92
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
93
+ page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'B'
94
+ else
95
+ raise %(Unsupported quota value "#{value}")
96
+ end
97
+
98
+ page.find(:xpath, '//button[text() = "保存する"]').click
99
+ end
71
100
 
72
- page.text =~ /利用中のディスク領域: \S+ \/ (\S+)/
73
- @quota = $1
101
+ @quota = value
74
102
  end
75
103
 
76
104
  def password=(value)
77
- Client.current_session.process(MAIL_URL + @link) do
78
- fill_in 'Password1', with: value
79
- fill_in 'Password2', with: value
80
- find('input[name="Submit_password"]').click
105
+ # FIXME: The URL won't work when mail addresses are more than 300
106
+ Client.current_session.process(MAIL_URL + "1/password/#{@address}", /#{@address}のパスワード設定/) do |page|
107
+ page.find_all(:xpath, '//label[contains(text(), "パスワード")]/..//input').each do |e|
108
+ e.fill_in with: value
109
+ end
110
+ page.find(:xpath, '//button[text() = "変更する"]').click
111
+ end
112
+ end
113
+
114
+ def virus_scan(page = nil)
115
+ if @virus_scan.nil?
116
+ # FIXME: The URL won't work when mail addresses are more than 300
117
+ page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
118
+ @virus_scan = page.find('[name="usesVirusCheck"]:checked').value == '1'
81
119
  end
120
+
121
+ @virus_scan
82
122
  end
83
123
 
84
124
  def virus_scan=(value)
85
- value = value ? 1 : 0
86
- Client.current_session.process(MAIL_URL + @link) do
87
- find("input[name='VirusScan'][value='#{value}']").click
125
+ # FIXME: The URL won't work when mail addresses are more than 300
126
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
127
+ page.find("[name='usesVirusCheck'][value='#{value ? 1 : 0}']").choose
128
+ page.find(:xpath, '//button[text() = "保存する"]').click
88
129
  end
89
130
 
90
- @virus_scan = value == 1
131
+ @virus_scan = value
91
132
  end
92
133
 
93
134
  def enable_virus_scan
@@ -98,22 +139,24 @@ module Sakura
98
139
  virus_scan = false
99
140
  end
100
141
 
101
- def keep
142
+ def keep(page = nil)
102
143
  if @keep.nil?
103
- page = Client.current_session.get(MAIL_URL + @link)
104
- @keep = page.find('input[name="Save"]:checked').value == '1'
144
+ # FIXME: The URL won't work when mail addresses are more than 300
145
+ page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
146
+ @keep = page.find('[name="receiveType"]:checked').value == '1'
105
147
  end
106
148
 
107
149
  @keep
108
150
  end
109
151
 
110
152
  def keep=(value)
111
- value = value ? 1 : 0
112
- Client.current_session.process(MAIL_URL + @link) do
113
- find("input[name='Save'][value='#{value}']").click
153
+ # FIXME: The URL won't work when mail addresses are more than 300
154
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
155
+ page.find("[name='receiveType'][value='#{value ? 1 : 2}']").choose
156
+ page.find(:xpath, '//button[text() = "保存する"]').click
114
157
  end
115
158
 
116
- @keep = value == 1
159
+ @keep = value
117
160
  end
118
161
 
119
162
  def enable_keep
@@ -124,41 +167,119 @@ module Sakura
124
167
  keep = false
125
168
  end
126
169
 
127
- def forward_list
170
+ def spam_filter(page = nil)
171
+ if @spam_filter.nil?
172
+ # FIXME: The URL won't work when mail addresses are more than 300
173
+ page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
174
+
175
+ case page.find(:xpath, '//label[contains(text(), "迷惑メールフィルタ")]/..//select').value
176
+ when "0"
177
+ @spam_filter = :disable
178
+ when "1"
179
+ @spam_filter = :quarantine
180
+ when "2"
181
+ @spam_filter = :discard
182
+ when "3"
183
+ @spam_filter = :mark
184
+ end
185
+ end
186
+
187
+ @spam_filter
188
+ end
189
+
190
+ def spam_filter=(value)
191
+ # FIXME: The URL won't work when mail addresses are more than 300
192
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
193
+ select = page.find(:xpath, '//label[contains(text(), "迷惑メールフィルタ")]/..//select')
194
+
195
+ value = value.to_sym
196
+ case value
197
+ when :disable
198
+ select.select '利用しない'
199
+ when :quarantine
200
+ select.select '「迷惑メール」フォルダに保存'
201
+ when :discard
202
+ select.select 'メールを破棄'
203
+ when :mark
204
+ select.select 'フィルタの利用'
205
+ end
206
+
207
+ page.find(:xpath, '//button[text() = "保存する"]').click
208
+ end
209
+
210
+ @spam_filter = value
211
+ end
212
+
213
+ def forward_list(page = nil)
128
214
  if @forward_list.nil?
129
- page = Client.current_session.get(MAIL_URL + @link)
130
- @forward_list = page.all('select[name="DeleteAddress[]"] option').map(&:text)
215
+ # FIXME: The URL won't work when mail addresses are more than 300
216
+ page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
217
+ @forward_list = page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea').value.split(/[\n,]+/)
131
218
  end
132
219
 
133
220
  @forward_list
134
221
  end
135
222
 
136
223
  def forward_to(mail)
137
- Client.current_session.process(MAIL_URL + @link) do
138
- execute_script <<-JS
139
- var f = document.Transfer;
140
- f.Address.value = '#{mail}';
141
- f.SubAction.value = 'add';
142
- f.submit();
143
- JS
224
+ # FIXME: The URL won't work when mail addresses are more than 300
225
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
226
+ @forward_list = page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea').value.split(/[\n,]+/)
227
+ page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea')
228
+ .fill_in with: (@forward_list + [mail]).uniq.join("\n")
229
+ page.find(:xpath, '//button[text() = "保存する"]').click
144
230
  end
145
231
 
146
- @forward_list ||= []
147
232
  @forward_list << mail
148
233
  end
149
234
 
150
235
  def delete_forward_to(mail)
151
- Client.current_session.process(MAIL_URL + @link) do
152
- find_field('DeleteAddress[]').select(mail)
153
- find('a[href="javascript:tr_delete();"]').click
236
+ # FIXME: The URL won't work when mail addresses are more than 300
237
+ Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
238
+ @forward_list = page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea').value.split(/[\n,]+/)
239
+ page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea')
240
+ .fill_in with: (@forward_list - [mail]).uniq.join("\n")
241
+ page.find(:xpath, '//button[text() = "保存する"]').click
154
242
  end
155
243
 
156
- @forward_list ||= []
157
244
  @forward_list.delete mail
158
245
  end
159
246
 
160
247
  def to_s
161
- self.class.tabularize(@address, @virus_scan, @usage, @quota)
248
+ self.class.tabularize(@address, @usage, @quota, percentage(@usage, @quota))
249
+ end
250
+
251
+ def detail
252
+ # FIXME: The URL won't work when mail addresses are more than 300
253
+ page = Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
254
+
255
+ <<-EOS
256
+ usage / quota: #{usage} / #{quota} (#{percentage(@usage, @quota)})
257
+ forward_to: #{forward_list(page).join(' ')}
258
+ keep mail: #{keep(page)}
259
+ virus scan: #{virus_scan(page)}
260
+ spam filter: #{spam_filter(page)}
261
+ EOS
262
+ end
263
+
264
+ private
265
+
266
+ def percentage(usage, quota)
267
+ usage, quota = [usage, quota].map { |i|
268
+ case i
269
+ when /([\d.]+)TB$/
270
+ $1.to_f * 1000000000000
271
+ when /([\d.]+)GB$/
272
+ $1.to_f * 1000000000
273
+ when /([\d.]+)MB$/
274
+ $1.to_f * 1000000
275
+ when /([\d.]+)KB$/
276
+ $1.to_f * 1000
277
+ when /([\d.]+)B$/
278
+ $1.to_i
279
+ end
280
+ }
281
+
282
+ "#{(usage * 100 / quota).to_i}%"
162
283
  end
163
284
  end
164
285
  end
data/sakura-cli.gemspec CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_runtime_dependency "poltergeist"
22
+ spec.add_runtime_dependency "capybara"
23
+ spec.add_runtime_dependency "selenium-webdriver"
23
24
  spec.add_runtime_dependency "thor"
24
- spec.add_development_dependency "bundler", "~> 1.9"
25
- spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "bundler"
26
+ spec.add_development_dependency "rake"
26
27
  spec.required_ruby_version = '>= 2.0.0'
27
28
  end
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sakura-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shintaro Kojima
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-12 00:00:00.000000000 Z
11
+ date: 2021-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: poltergeist
14
+ name: capybara
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: selenium-webdriver
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - ">="
@@ -42,30 +56,30 @@ dependencies:
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - "~>"
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
- version: '1.9'
61
+ version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - "~>"
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '1.9'
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - "~>"
73
+ - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: '10.0'
75
+ version: '0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - "~>"
80
+ - - ">="
67
81
  - !ruby/object:Gem::Version
68
- version: '10.0'
82
+ version: '0'
69
83
  description: Command-line tool and client library to control the dashboard of Sakura
70
84
  Rental Server.
71
85
  email:
@@ -92,7 +106,7 @@ homepage: https://github.com/codeout/sakura-cli
92
106
  licenses:
93
107
  - MIT
94
108
  metadata: {}
95
- post_install_message:
109
+ post_install_message:
96
110
  rdoc_options: []
97
111
  require_paths:
98
112
  - lib
@@ -107,10 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
121
  - !ruby/object:Gem::Version
108
122
  version: '0'
109
123
  requirements: []
110
- rubyforge_project:
111
- rubygems_version: 2.4.5
112
- signing_key:
124
+ rubygems_version: 3.2.15
125
+ signing_key:
113
126
  specification_version: 4
114
127
  summary: Command-line tool for Sakura's Rental Server.
115
128
  test_files: []
116
- has_rdoc: