OpenProvider API完了

守矢諏訪子 <suwako@076.moe>、2026-11-12 10:56
コミット 5617365df4b875cf6ac2b95f5f1f5b649fa7e6d8 ・親 2493afc ・ファイルを見る

5個のファイル、+857 -1811

@@ -110,6 +110,21 @@
110110 }
111111
112112 /**
113+ * 名前が「$prefix」で始まるキャッシュを全部破壊する(関係するキャッシュをまとめて消す為)
114+ *
115+ * @param string $prefix キャッシュ名の始まり
116+ * @return int 削除した数
117+ */
118+ public function murderPrefix(string $prefix): int {
119+ if (!$this->isSafeName($prefix)) return 0;
120+ $n = 0;
121+ foreach (glob($this->dataDir.'*.json') ?: [] as $f) {
122+ if (str_starts_with(basename($f, '.json'), $prefix) && @unlink($f)) $n++;
123+ }
124+ return $n;
125+ }
126+
127+ /**
113128 * キャッシュ有効期限の確認
114129 *
115130 * @param array $cache

長いので途中までです

@@ -41,6 +41,15 @@
4141 use Std\Lib\Curl;
4242 use Result;
4343
44+/**
45+ * OpenProviderのREST API(v1beta)
46+ *
47+ * 使い方:最初にlogin()を1回実行し、その後で各メソッドを呼ぶ。
48+ * 結果のdataは、特に書いていなければAPIのレスポンス全体(code、data、desc等)。
49+ * 一覧と表示は30分キャッシュし(Cache)、追加・更新・削除をすると関係するキャッシュを消す。
50+ *
51+ * APIの仕様:https://docs.openprovider.com/doc/all
52+ */
4453 class Openprovider {
4554 protected string $cacheDir = 'openprovider';
4655 protected int $tokenDuration = 172800; // 48時間
@@ -83,6 +92,7 @@
8392 $this->lastAuth = (int)($cache['last_auth'] ?? 0);
8493 if (isset($cache['data']['token']) && time() < ($this->lastAuth + $this->tokenDuration)) {
8594 $this->token = $cache['data']['token'];
95+ $this->resellerId = (int)($cache['data']['reseller_id'] ?? 0);
8696 return Result::Success('', $cache);
8797 }
8898
@@ -112,6 +122,8 @@
112122 $res = json_decode($body, true);
113123 if (is_array($res) && isset($res['data']['token'])) {
114124 $this->token = $res['data']['token'];
125+ // 以前はリセラーIDを記録していなかった(getResellerId()が常に0)
126+ $this->resellerId = (int)($res['data']['reseller_id'] ?? 0);
115127 $this->lastAuth = time();
116128 $res['last_auth'] = $this->lastAuth;
117129 $this->cache->set($cacheName, $res);
@@ -122,26 +134,6 @@
122134 return Result::Error('ログインに失敗。');
123135 }
124136
125- /**
126- * SpanExpert向けログインURLの生成
127- * @todo テスト
128- *
129- * @param array $payload フォームデータ
130- * @return Result
131- */
132- public function generateLoginUrlSpamExpert(array $payload = []): Result {
133- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
134-
135- $uri = '/spam-expert-generate-login-url';
136- $curl = $this->setupCurl($uri, 'POST', $payload);
137- $res = $this->curlResult($curl);
138- if (isset($res->data['data'])) {
139- return Result::Success('DNSテンプレートの追加に成功。', $res->data);
140- }
141-
142- return Result::Error('DNSテンプレートの追加に失敗。');
143- }
144-
145137 // ドメイン
146138
147139 //// ドメイン
@@ -149,81 +141,40 @@
149141 /**
150142 * ドメイン一覧。
151143 *
152- * @return Result 結果。
144+ * @param array $query 検索クエリー(limit、offset、order_by.*、status、domain_name_pattern、with_*等)
145+ * @return Result 結果。dataはドメインの配列(results)
153146 */
154147 public function listDomains(array $query = []): Result {
155- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
156- $cacheName = 'listdomains';
157- $cache = $this->cache->get($cacheName);
158- // キャッシュからも同じ形(results)で返す(以前はキャッシュの時だけ応答全体を返した)
159- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache['data']['results'] ?? []);
160-
161- $uri = "/domains?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
162- $curl = $this->setupCurl($uri);
163- $res = $this->curlResult($curl);
164- if (isset($res->data['data']['results'])) {
165- $this->cache->set($cacheName, $res->data + ['query' => $query]);
166- return Result::Success('', $res->data['data']['results']);
167- }
168-
169- return Result::Error('ドメインの確認に失敗。');
148+ $res = $this->get('ドメイン一覧の受け取り', '/domains', $query, 'listdomains');
149+ return $res->isSuccess ? Result::Success('', $res->data['data']['results'] ?? []) : $res;
170150 }
171151
172152 /**
173153 * ドメイン名の登録。
174- * @todo テスト
154+ * ハンドルを省略するとconfig.phpのOPENPROVIDERの「owner_handle」、ネームサーバーを省略するとOpenProviderのネームサーバー
175155 *
176156 * @param string $name 登録したいドメイン名(例:"076studio.jp")
177- * @param array $info カスタマー情報等
157+ * @param array $info owner_handle、admin_handle、tech_handle、billing_handle、reseller_handle、
158+ * name_servers(名前の配列、又は['name' => …, 'ip' => …]の配列)、autorenew、
159+ * 他にAPIの項目(ns_group、additional_data、is_private_whois_enabled等)もそのまま送る
178160 * @param int $period 年間(デフォルト=1年)
179- * @return Result 結果。配列の場合:'activation_date'(リアルタイムで成功したのみ), 'auth_code'(TLDが対応している場合のみ), 'expiration_date', 'id', 'renewal_date', 'status'(ACT又はREQ)
161+ * @return Result 結果。data['data']:'activation_date'(リアルタイムで成功したのみ), 'auth_code'(TLDが対応している場合のみ), 'expiration_date', 'id', 'renewal_date', 'status'(ACT又はREQ)
180162 */
181163 public function createDomain(string $name, array $info, int $period = 1): Result {
182164 if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
183- if (!isset($info['owner_handle']) || $info['owner_handle'] === '') $info['owner_handle'] = OPENPROVIDER['owner_handle'];
184- if (!isset($info['admin_handle']) || $info['admin_handle'] === '') $info['admin_handle'] = OPENPROVIDER['owner_handle'];
185- if (!isset($info['tech_handle']) || $info['tech_handle'] === '') $info['tech_handle'] = OPENPROVIDER['owner_handle'];
186- if (!isset($info['billing_handle']) || $info['billing_handle'] === '') $info['billing_handle'] = OPENPROVIDER['owner_handle'];
187- if (!isset($info['reseller_handle']) || $info['reseller_handle'] === '') $info['reseller_handle'] = OPENPROVIDER['owner_handle'];
188- if (!isset($info['name_servers']) || empty($info['name_servers'])) $info['name_servers'] = ['ns1.openprovider.nl', 'ns2.openprovider.be', 'ns3.openprovider.eu'];
189- if (!isset($info['autorenew']) || $info['autorenew'] === '') $info['autorenew'] = 'default';
165+ $domain = self::splitDomain($name);
166+ if ($domain === null) return Result::Error("不正なドメイン形: {$name}");
190167
191- // 新しい顧客の場合
192-
193- $parts = explode('.', $name, 2);
194- if (count($parts) !== 2 || $parts[0] === '' || $parts[1] === '') return Result::Error("不正なドメイン形: {$name}");
195- $domain = [
196- 'name' => $parts[0],
197- 'extension' => $parts[1],
198- ];
199-
200- $ns = [];
201- foreach ($info['name_servers'] as $n) {
202- $ns[] = ['name' => $n];
168+ foreach (['owner_handle', 'admin_handle', 'tech_handle', 'billing_handle', 'reseller_handle'] as $h) {
169+ if (($info[$h] ?? '') === '') $info[$h] = OPENPROVIDER['owner_handle'];
203170 }
171+ // 以前はns_group等の他の項目を送らなかった
172+ if (empty($info['name_servers']) && empty($info['ns_group'])) $info['name_servers'] = ['ns1.openprovider.nl', 'ns2.openprovider.be', 'ns3.openprovider.eu'];
173+ if (isset($info['name_servers'])) $info['name_servers'] = array_map(fn($n) => is_array($n) ? $n : ['name' => $n], $info['name_servers']);
174+ if (($info['autorenew'] ?? '') === '') $info['autorenew'] = 'default';
204175
205- // 以前は未定義の変数($owner_handle等)を使い、kys('TODO')で止まっていた
206- $payload = [
207- 'domain' => $domain,
208- 'period' => $period,
209- 'owner_handle' => $info['owner_handle'],
210- 'admin_handle' => $info['admin_handle'],
211- 'tech_handle' => $info['tech_handle'],
212- 'billing_handle' => $info['billing_handle'],
213- 'reseller_handle' => $info['reseller_handle'],
214- 'name_servers' => $ns,
215- 'autorenew' => $info['autorenew'],
216- ];
217-
218- $uri = '/domains';
219- $curl = $this->setupCurl($uri, 'POST', $payload);
220- $res = $this->curlResult($curl);
221- if ($res->isSuccess && isset($res->data['data'])) {
222- $this->cache->murder('listdomains');
223- return Result::Success('', $res->data['data']);
224- }
225-
226- return Result::Error('ドメインの確認に失敗。');
176+ $payload = ['domain' => $domain, 'period' => $period] + $info;
177+ return $this->send('ドメインの登録', 'POST', '/domains', $payload, [], ['listdomains', 'domain-']);
227178 }
228179
229180 /**
@@ -231,419 +182,200 @@
231182 *
232183 * @param array $domains ドメイン名リスト。例:['076.moe', '076.co.jp', '076.com']
233184 * @param bool $with_price 値段を表示するかどうか。デフォルトは「false」
234- * @return Result 結果。配列の場合:'domain'と'status'はいつでもあり、'reason', 'premium', 'is_premium'が多分あり、そして'price'が「with_price」が「true」の場合のみ。
185+ * @return Result 結果。dataは配列(results):'domain'と'status'はいつでもあり、'reason', 'premium', 'is_premium'が多分あり、そして'price'が「with_price」が「true」の場合のみ。
235186 */
236187 public function checkDomainAvailable(array $domains, bool $with_price = false): Result {
237188 if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
238189 $domainList = [];
239190 foreach ($domains as $d) {
240191 // 「076.co.jp」の様なTLDもあるので、最初の「.」で分ける
241- $domain = explode('.', (string)$d, 2);
242- if (count($domain) !== 2 || $domain[0] === '' || $domain[1] === '') {
243- return Result::Error("不正なドメイン形: {$d}");
244- }
245-
246- $domainList[] = [
247- 'name' => $domain[0],
248- 'extension' => $domain[1],
249- ];
192+ $domain = self::splitDomain((string)$d);
193+ if ($domain === null) return Result::Error("不正なドメイン形: {$d}");
194+ $domainList[] = $domain;
250195 }
251196
252- $payload = [
253- 'domains' => $domainList,
254- 'with_price' => $with_price,
255- ];
256-
257- $uri = '/domains/check';
258- $curl = $this->setupCurl($uri, 'POST', $payload);
259- $res = $this->curlResult($curl);
260- if (isset($res->data['data']['results'])) return Result::Success('', $res->data['data']['results']);
261-
262- return Result::Error('ドメインの確認に失敗。');
197+ $res = $this->send('ドメインの確認', 'POST', '/domains/check', ['domains' => $domainList, 'with_price' => $with_price]);
198+ return $res->isSuccess ? Result::Success('', $res->data['data']['results'] ?? []) : $res;
263199 }
264200
265201 /**
266202 * ドメイン名を勧められる。
267- * @todo テスト
268203 *
269- * @param array $payload フォームデータ
270- * @return Result 結果。
204+ * @param array $payload name(必須)、tlds、language、limit、sensitive、provider
205+ * @return Result 結果。data['data']['results']:勧められたドメイン
271206 */
272207 public function suggestDomainname(array $payload = []): Result {
273- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
274-
275- $uri = '/domains/suggest-name';
276- $curl = $this->setupCurl($uri, 'POST', $payload);
277- $res = $this->curlResult($curl);
278- if (isset($res->data['data']['results'])) {
279- return Result::Success('ドメインを勧められる事に成功。', $res->data['data']['results']);
280- }
281-
282- return Result::Error('ドメインを勧められる事に失敗。');
208+ return $this->send('ドメイン名の提案', 'POST', '/domains/suggest-name', $payload);
283209 }
284210
285211 /**
286- * ドメイン名を交換する。
287- * @todo テスト
212+ * ドメイン名を交換する(所有者の変更)。
288213 *
289- * @param array $payload フォームデータ
290- * @return Result 結果。
214+ * @param array $payload domain(name、extension)、owner_handle、auth_code等
215+ * @return Result 結果。data['data']:creation_date、expiration_date、renewal_date、status
291216 */
292217 public function tradeDomainname(array $payload = []): Result {
293- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
294-
295- $uri = '/domains/trade';
296- $curl = $this->setupCurl($uri, 'POST', $payload);
297- $res = $this->curlResult($curl);
298- if (isset($res->data['data']['results'])) {
299- $this->cache->murder('listdomains');
300- return Result::Success('ドメインの交換に成功。', $res->data['data']['results']);
301- }
302-
303- return Result::Error('ドメインの交換に失敗。');
218+ return $this->send('ドメインの交換', 'POST', '/domains/trade', $payload, [], ['listdomains', 'domain-']);
304219 }
305220
306221 /**
307222 * ドメイン名を移転する。
308- * @todo テスト
309223 *
310- * @param array $payload フォームデータ
311- * @return Result 結果。
224+ * @param array $payload domain(name、extension)、auth_code、owner_handle等
225+ * @return Result 結果。data['data']:id、status、auth_code、expiration_date等
312226 */
313227 public function transferDomainname(array $payload = []): Result {
314- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
315-
316- $uri = '/domains/transfer';
317- $curl = $this->setupCurl($uri, 'POST', $payload);
318- $res = $this->curlResult($curl);
319- if (isset($res->data['data']['results'])) {
320- $this->cache->murder('listdomains');
321- return Result::Success('ドメインの移転に成功。', $res->data['data']['results']);
322- }
323-
324- return Result::Error('ドメインの移転に失敗。');
228+ return $this->send('ドメインの移転', 'POST', '/domains/transfer', $payload, [], ['listdomains', 'domain-']);
325229 }
326230
327231 /**
328232 * ドメイン名の受け取り
329- * @todo テスト
330233 *
331234 * @param int $id ドメインID
332- * @param array $payload フォームデータ
333- * @return Result 結果。
235+ * @param array $query 検索クエリー(with_history、with_additional_data等)
236+ * @return Result 結果。data['data']:ドメイン
334237 */
335- public function getDomainname(int $id, array $payload = []): Result {
336- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
337- // 以前は未定義の$queryと$dataを使い、GETではなくPOSTで送っていた
338- $cacheName = "getdomain-{$id}";
339- $cache = $this->cache->get($cacheName);
340- if ($this->cache->resurrect($cache, $payload)) return Result::Success('', $cache['data'] ?? []);
341-
342- foreach ($payload as $k => $v) if (is_bool($v)) $payload[$k] = $v ? 'true' : 'false';
343- $uri = "/domains/{$id}".(empty($payload) ? '' : '?'.http_build_query($payload, '', '&', PHP_QUERY_RFC3986));
344- $curl = $this->setupCurl($uri);
345- $res = $this->curlResult($curl);
346- if ($res->isSuccess && isset($res->data['data'])) {
347- $this->cache->set($cacheName, $res->data + ['query' => $payload]);
348- return Result::Success('ドメインの受け取りに成功。', $res->data['data']);
349- }
350-
351- return Result::Error('ドメインの受け取りに失敗。');
238+ public function getDomainname(int $id, array $query = []): Result {
239+ return $this->get('ドメインの受け取り', "/domains/{$id}", $query, "domain-{$id}");
352240 }
353241
354-
355242 /**
356243 * ドメイン名の更新
357- * @todo テスト
358244 *
359245 * @param int $id ドメインID
360- * @param array $payload フォームデータ
361- * @return Result
246+ * @param array $payload 更新する項目(name_servers、autorenew、is_locked等)
247+ * @return Result 結果。data['data']:id、status
362248 */
363249 public function updateDomainname(int $id, array $payload = []): Result {
364- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
365-
366- $uri = "/domains/{$id}";
367- $curl = $this->setupCurl($uri, 'PUT', $payload);
368- $res = $this->curlResult($curl);
369- if (isset($res->data['data'])) {
370- $this->cache->murder('listdomains');
371- $this->cache->murder("listdomain-{$id}");
372- if ($res->data['data']['success']) return Result::Success('ドメイン名の更新に成功。', $res->data);
373- }
374-
375- return Result::Error('ドメイン名の更新に失敗。');
250+ return $this->send('ドメイン名の更新', 'PUT', "/domains/{$id}", $payload, [], ['listdomains', "domain-{$id}"]);
376251 }
377252
378253 /**
379254 * ドメイン名の削除
380- * @todo テスト
381255 *
382256 * @param int $id ドメインID
383- * @param array $payload フォームデータ
384- * @return Result
257+ * @param array $query type(例:「transfer」)、skip_soft_quarantine、force_delete等
258+ * @return Result 結果。data['data']:status
385259 */
386- public function deleteDomainname(int $id, array $payload = []): Result {
387- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
388-
389- $uri = "/domains/{$id}";
390- $curl = $this->setupCurl($uri, 'DELETE', $payload);
391- $res = $this->curlResult($curl);
392- if (isset($res->data['data'])) {
393- $this->cache->murder('listdomains');
394- $this->cache->murder("listdomain-{$id}");
395- if ($res->data['data']['success']) return Result::Success('ドメイン名の削除に成功。', $res->data);
396- }
397-
398- return Result::Error('ドメイン名の削除に失敗。');
260+ public function deleteDomainname(int $id, array $query = []): Result {
261+ // 以前は検索の条件を本文で送っていた(DELETEはクエリー)
262+ return $this->send('ドメイン名の削除', 'DELETE', "/domains/{$id}", null, $query, ['listdomains', "domain-{$id}"]);
399263 }
400264
401265 /**
402266 * ドメイン名の最後行動の再度実行
403- * @todo テスト
404267 *
405268 * @param int $id ドメインID
406- * @param array $payload フォームデータ
407- * @return Result 結果。
269+ * @param array $payload auth_code等
270+ * @return Result 結果
408271 */
409272 public function retryLastDomainnameOperation(int $id, array $payload = []): Result {
410- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
411-
412- $curl = $this->setupCurl("/domains/{$id}/last-operation/restart", 'POST', $payload);
413- $res = $this->curlResult($curl);
414- if (isset($res->data['data']['results'])) {
415- $this->cache->murder('listdomains');
416- $this->cache->murder("listdomain-{$id}");
417- return Result::Success('ドメインの最後行動の再度実行に成功。', $res->data['data']['results']);
418- }
419-
420- return Result::Error('ドメインの最後行動の再度実行に失敗。');
273+ return $this->send('ドメインの最後行動の再度実行', 'POST', "/domains/{$id}/last-operation/restart", ['id' => $id] + $payload, [], ['listdomains', "domain-{$id}"]);
421274 }
422275
423276 /**
424277 * ドメイン名の有効期限の更新
425- * @todo テスト
426278 *
427279 * @param int $id ドメインID
428- * @param array $payload フォームデータ
429- * @return Result 結果。
280+ * @param array $payload period(年)等
281+ * @return Result 結果。data['data']:status
430282 */
431283 public function renewDomainname(int $id, array $payload = []): Result {
432- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
433-
434- $curl = $this->setupCurl("/domains/{$id}/renew", 'POST', $payload);
435- $res = $this->curlResult($curl);
436- if (isset($res->data['data']['results'])) {
437- $this->cache->murder('listdomains');
438- $this->cache->murder("listdomain-{$id}");
439- return Result::Success('ドメインの有効期限の更新に成功。', $res->data['data']['results']);
440- }
441-
442- return Result::Error('ドメインの有効期限の更新に失敗。');
284+ return $this->send('ドメインの有効期限の更新', 'POST', "/domains/{$id}/renew", ['id' => $id] + $payload, [], ['listdomains', "domain-{$id}"]);
443285 }
444286
445287 /**
446288 * 削除済みドメイン名の復活
447- * @todo テスト
448289 *
449290 * @param int $id ドメインID
450291 * @param array $payload フォームデータ
451- * @return Result 結果。
292+ * @return Result 結果。data['data']:status
452293 */
453294 public function restoreDomainname(int $id, array $payload = []): Result {
454- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
455-
456- $curl = $this->setupCurl("/domains/{$id}/restore", 'POST', $payload);
457- $res = $this->curlResult($curl);
458- if (isset($res->data['data']['results'])) {
459- $this->cache->murder('listdomains');
460- $this->cache->murder("listdomain-{$id}");
461- return Result::Success('削除済みドメイン名の復活に成功。', $res->data['data']['results']);
462- }
463-
464- return Result::Error('削除済みドメイン名の復活に失敗。');
295+ return $this->send('削除済みドメイン名の復活', 'POST', "/domains/{$id}/restore", ['id' => $id] + $payload, [], ['listdomains', "domain-{$id}"]);
465296 }
466297
467298 /**
468299 * ドメイン名の移動の承諾
469- * @todo テスト
470300 *
471301 * @param int $id ドメインID
472- * @param array $payload フォームデータ
473- * @return Result 結果。
302+ * @param array $payload approve(1=承諾、0=拒否)、auth_code、registrar_tag等
303+ * @return Result 結果
474304 */
475305 public function approveDomainnameTransfer(int $id, array $payload = []): Result {
476- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
477-
478- $curl = $this->setupCurl("/domains/{$id}/transfer/approve", 'POST', $payload);
479- $res = $this->curlResult($curl);
480- if (isset($res->data['data']['results'])) {
481- $this->cache->murder('listdomains');
482- $this->cache->murder("listdomain-{$id}");
483- return Result::Success('ドメイン名の移動の承諾に成功。', $res->data['data']['results']);
484- }
485-
486- return Result::Error('ドメイン名の移動の承諾に失敗。');
306+ return $this->send('ドメイン名の移動の承諾', 'POST', "/domains/{$id}/transfer/approve", ['id' => $id] + $payload, [], ['listdomains', "domain-{$id}"]);
487307 }
488308
489309 /**
490- * ドメイン名のfoa1の送信
491- * @todo テスト
310+ * ドメイン名のFOA1(移転の確認メール)の送信
492311 *
493312 * @param int $id ドメインID
494313 * @param array $payload フォームデータ
495- * @return Result 結果。
314+ * @return Result 結果
496315 */
497316 public function sendDomainnameFoa1(int $id, array $payload = []): Result {
498- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
499-
500- $curl = $this->setupCurl("/domains/{$id}/transfer/send-foa1", 'POST', $payload);
501- $res = $this->curlResult($curl);
502- if (isset($res->data['data']['results'])) {
503- $this->cache->murder('listdomains');
504- $this->cache->murder("listdomain-{$id}");
505- return Result::Success('ドメイン名のfoa1の送信に成功。', $res->data['data']['results']);
506- }
507-
508- return Result::Error('ドメイン名のfoa1の送信に失敗。');
317+ return $this->send('ドメイン名のFOA1の送信', 'POST', "/domains/{$id}/transfer/send-foa1", ['id' => $id] + $payload);
509318 }
510319
511320 //// 追加データ
512321
513322 /**
514- * 追加データの受け取り
515- * @todo テスト
323+ * 追加データ(TLDで必要な項目)の受け取り
516324 *
517- * @param array $query 検索クエリー
518- * @return Result
325+ * @param array $query domain.name、domain.extension、operation
326+ * @return Result 結果。data['data']:項目の配列
519327 */
520328 public function getDomainAdditionalData(array $query): Result {
521- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
522- $name = '';
523- $ext = '';
524- if (isset($query['domain.name'])) $name = $query['domain.name'];
525- if (isset($query['domain.extension'])) $ext = $query['domain.extension'];
526- $cacheName = $name && $ext ? "domainadditionaldata-{$name}.{$ext}" : 'domainadditionaldata';
527-
528- $cache = $this->cache->get($cacheName);
529- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
530-
531- $uri = "/domains/additional-data?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
532- $curl = $this->setupCurl($uri);
533- $res = $this->curlResult($curl);
534- if (isset($res->data['data'])) {
535- $this->cache->set($cacheName, $res->data + ['query' => $query]);
536- return Result::Success('', $res->data);
537- }
538-
539- return Result::Error('ドメインの追加データの受け取りに失敗。');
329+ return $this->get('ドメインの追加データの受け取り', '/domains/additional-data', $query, 'domainadditionaldata-'.self::cacheKey($query));
540330 }
541331
542332 //// 顧客様の追加データ
543333
544334 /**
545- * 顧客様の追加データの受け取り
546- * @todo テスト
335+ * 顧客様の追加データ(TLDで顧客様に必要な項目)の受け取り
547336 *
548- * @param array $query 検索クエリー
549- * @return Result
337+ * @param array $query domain.name、domain.extension
338+ * @return Result 結果。data['data']:項目の配列
550339 */
551340 public function getDomainCustomerAdditionalData(array $query): Result {
552- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
553- $name = '';
554- $ext = '';
555- if (isset($query['domain.name'])) $name = $query['domain.name'];
556- if (isset($query['domain.extension'])) $ext = $query['domain.extension'];
557- $cacheName = $name && $ext ? "domainadditionaldata-{$name}.{$ext}" : 'domainadditionaldata';
558-
559- $cache = $this->cache->get($cacheName);
560- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
561-
562- $uri = "/domains/additional-data/customers?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
563- $curl = $this->setupCurl($uri);
564- $res = $this->curlResult($curl);
565- if (isset($res->data['data'])) {
566- $this->cache->set($cacheName, $res->data + ['query' => $query]);
567- return Result::Success('', $res->data);
568- }
569-
570- return Result::Error('ドメインの顧客様の追加データの受け取りに失敗。');
341+ // 以前はドメインの追加データと同じキャッシュ名で、違う結果を返す事があった
342+ return $this->get('ドメインの顧客様の追加データの受け取り', '/domains/additional-data/customers', $query, 'domaincustomerdata-'.self::cacheKey($query));
571343 }
572344
573-
574345 //// ドメイン値段
575346
576347 /**
577- * ドメイン値段一覧
348+ * ドメインの値段
578349 *
579- * @param array $query 検索クエリー
580- * @return Result
350+ * @param array $query domain.name、domain.extension、operation(create、transfer、renew等)、period
351+ * @return Result 結果。data['data']:price、is_premium等
581352 */
582353 public function getDomainPrices(array $query): Result {
583- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
584- $name = '';
585- $ext = '';
586- if (isset($query['domain.name'])) $name = $query['domain.name'];
587- if (isset($query['domain.extension'])) $ext = $query['domain.extension'];
588- $cacheName = $name && $ext ? "domainprices-{$name}.{$ext}" : 'domainprices';
589-
590- $cache = $this->cache->get($cacheName);
591- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
592-
593- $uri = "/domains/prices?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
594- $curl = $this->setupCurl($uri);
595- $res = $this->curlResult($curl);
596- if (isset($res->data['data'])) {
597- $this->cache->set($cacheName, $res->data + ['query' => $query]);
598- return Result::Success('', $res->data);
599- }
600-
601- return Result::Error('TLD一覧の受け取りに失敗。');
354+ return $this->get('ドメインの値段の受け取り', '/domains/prices', $query, 'domainprices-'.self::cacheKey($query));
602355 }
603356
604357 //// 認証コード
605358
606359 /**
607- * 認証コードの受け取り
608- * @todo テスト
360+ * 認証コードの受け取り(キャッシュしない)
609361 *
610362 * @param int $id ドメイン名ID
611- * @param array $query 検索クエリー
612- * @return Result
363+ * @param array $query auth_code_type、sending_type等
364+ * @return Result 結果。data['data']:auth_code、type、success
613365 */
614366 public function getAuthCode(int $id, array $query = []): Result {
615- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
616-
617- $uri = "/domains/{$id}/authcode?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
618- $curl = $this->setupCurl($uri);
619- $res = $this->curlResult($curl);
620- if (isset($res->data['data'])) {
621- return Result::Success('', $res->data);
622- }
623-
624- return Result::Error('認証コードの受け取りに失敗。');
367+ return $this->get('認証コードの受け取り', "/domains/{$id}/authcode", $query);
625368 }
626369
627370 /**
628371 * 認証コードの再設定
629- * @todo テスト
630372 *
631373 * @param int $id ドメイン名ID
632- * @param array $payload フォームデータ
633- * @return Result
374+ * @param array $payload auth_code_type、sending_type等
375+ * @return Result 結果。data['data']:auth_code等
634376 */
635377 public function resetAuthCode(int $id, array $payload = []): Result {
636- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
637-
638- $uri = "/domains/{$id}/authcode/reset";
639- $curl = $this->setupCurl($uri, 'POST', $payload);
640- $res = $this->curlResult($curl);
641- // 以前はisset($res)で、失敗しても成功を返していた
642- if ($res->isSuccess) {
643- return Result::Success('', $res->data);
644- }
645-
646- return Result::Error("認証コードの再設定に失敗。");
378+ return $this->send('認証コードの再設定', 'POST', "/domains/{$id}/authcode/reset", ['id' => $id] + $payload, [], ["domain-{$id}"]);
647379 }
648380
649381 //// TLD
@@ -651,54 +383,24 @@
651383 /**
652384 * TLD一覧
653385 *
654- * @param array $query 検索クエリー
655- * @return Result
386+ * @param array $query 検索クエリー(省略すると最初の10件)
387+ * @return Result 結果。data['data']:results、total
656388 */
657389 public function listTlds(array $query = []): Result {
658- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
659- $cacheName = 'listtlds';
660- $cache = $this->cache->get($cacheName);
661- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
662-
663- if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0, 'order' => 'ASC' ];
664- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
665-
666- $uri = '/tlds?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
667- $curl = $this->setupCurl($uri);
668- $res = $this->curlResult($curl);
669- if (isset($res->data['data'])) {
670- $this->cache->set($cacheName, $res->data + ['query' => $query]);
671- return Result::Success('', $res->data);
672- }
673-
674- return Result::Error('TLD一覧の受け取りに失敗。');
390+ if (empty($query)) $query = ['limit' => 10, 'offset' => 0, 'order' => 'ASC'];
391+ return $this->get('TLD一覧の受け取り', '/tlds', $query, 'listtlds');
675392 }
676393
677394 /**
678395 * TLDの表示
679396 *
680397 * @param string $tld TLD
681- * @param array $query 検索クエリー
682- * @return Result
398+ * @param array $query 検索クエリー(with_price、with_description等)
399+ * @return Result 結果。data['data']:TLD
683400 */
684401 public function getTld(string $tld, array $query = []): Result {
685- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
686- $cacheName = "gettld-{$tld}";
687- $cache = $this->cache->get($cacheName);
688- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
689-
690- if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0 ];
691- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
692-
693- $uri = "/tlds/{$tld}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
694- $curl = $this->setupCurl($uri);
695- $res = $this->curlResult($curl);
696- if (isset($res->data['data'])) {
697- $this->cache->set($cacheName, $res->data + ['query' => $query]);
698- return Result::Success('', $res->data);
699- }
700-
701- return Result::Error('TLD一覧の受け取りに失敗。');
402+ if (empty($query)) $query = ['limit' => 10, 'offset' => 0];
403+ return $this->get('TLDの受け取り', '/tlds/'.self::seg($tld), $query, 'gettld-'.self::cacheKey($tld));
702404 }
703405
704406 // 請求
@@ -707,27 +409,12 @@
707409 /**
708410 * 請求書一覧
709411 *
710- * @param array $query 検索クエリー
711- * @return Result
412+ * @param array $query 検索クエリー(省略すると最初の10件)
413+ * @return Result 結果。data['data']:results、total
712414 */
713415 public function listInvoices(array $query = []): Result {
714- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
715- $cacheName = 'listinvoices';
716- $cache = $this->cache->get($cacheName);
717- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
718-
719- if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0 ];
720- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
721-
722- $uri = "/invoices?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
723- $curl = $this->setupCurl($uri);
724- $res = $this->curlResult($curl);
725- if (isset($res->data['data'])) {
726- $this->cache->set($cacheName, $res->data + ['query' => $query]);
727- return Result::Success('', $res->data);
728- }
729-
730- return Result::Error('請求書一覧の受け取りに請求書');
416+ if (empty($query)) $query = ['limit' => 10, 'offset' => 0];
417+ return $this->get('請求書一覧の受け取り', '/invoices', $query, 'listinvoices');
731418 }
732419
733420 //// 支払
@@ -735,27 +422,21 @@
735422 /**
736423 * 支払一覧
737424 *
738- * @param array $query 検索クエリー
739- * @return Result
425+ * @param array $query 検索クエリー(省略すると最初の10件)
426+ * @return Result 結果。data['data']:results、total
740427 */
741428 public function listPayments(array $query = []): Result {
742- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
743- $cacheName = 'listpayments';
744- $cache = $this->cache->get($cacheName);
745- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
429+ if (empty($query)) $query = ['limit' => 10, 'offset' => 0];
430+ return $this->get('支払一覧の受け取り', '/payments', $query, 'listpayments');
431+ }
746432
747- if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0 ];
748- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
749-
750- $uri = "/payments?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
751- $curl = $this->setupCurl($uri);
752- $res = $this->curlResult($curl);
753- if (isset($res->data['data'])) {
754- $this->cache->set($cacheName, $res->data + ['query' => $query]);
755- return Result::Success('', $res->data);
756- }
757-
758- return Result::Error('支払一覧の受け取りに失敗。');
433+ /**
434+ * 推奨のチャージ額(キャッシュしない)
435+ *
436+ * @return Result 結果。data['data']:suggested_top_up_amount
437+ */
438+ public function getSuggestedTopUpAmount(): Result {
439+ return $this->get('推奨のチャージ額の受け取り', '/payments/suggested-top-up-amount');
759440 }
760441
761442 //// トランザクション
@@ -763,391 +444,180 @@
763444 /**
764445 * トランザクション一覧
765446 *
766- * @param array $query 検索クエリー
767- * @return Result
447+ * @param array $query 検索クエリー(省略すると最初の10件)
448+ * @return Result 結果。data['data']:results、total
768449 */
769450 public function listTransactions(array $query = []): Result {
770- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
771- $cacheName = 'listtransactions';
772- $cache = $this->cache->get($cacheName);
773- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
774-
775- if (empty($query)) $query = [ 'limit' => 10, 'offset' => 0 ];
776- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
777-
778- $uri = "/transactions?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
779- $curl = $this->setupCurl($uri);
780- $res = $this->curlResult($curl);
781- if (isset($res->data['data'])) {
782- $this->cache->set($cacheName, $res->data + ['query' => $query]);
783- return Result::Success('', $res->data);
784- }
785-
786- return Result::Error('トランザクション一覧の受け取りに失敗。');
451+ if (empty($query)) $query = ['limit' => 10, 'offset' => 0];
452+ return $this->get('トランザクション一覧の受け取り', '/transactions', $query, 'listtransactions');
787453 }
788454
789455 // DNS
790- //// DomainToken
456+ //// ドメイントークン
791457
792458 /**
793- * ドメイントークンの作成
794- * @todo テスト
459+ * ドメイントークンの作成(他のDNSプロバイダーでドメインの所有を確認する為)
795460 *
796- * @param array $payload フォームデータ
797- * @return Result
461+ * @param array $payload domain、zone_provider
462+ * @return Result 結果。data['data']:token、url
798463 */
799464 public function createDomainToken(array $payload = []): Result {
800- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
801-
802- $uri = '/dns/domain-token';
803- $curl = $this->setupCurl($uri, 'POST', $payload);
804- $res = $this->curlResult($curl);
805- if (isset($res->data['data'])) {
806- return Result::Success('DNSテンプレートの追加に成功。', $res->data);
807- }
808-
809- return Result::Error('DNSテンプレートの追加に失敗。');
465+ // 以前は成功・失敗のメッセージがDNSテンプレートの物だった
466+ return $this->send('ドメイントークンの作成', 'POST', '/dns/domain-token', $payload);
810467 }
811468
812469 //// ネームサーバー
813470
814471 /**
815472 * ネームサーバー一覧
816- * @todo テスト
817473 *
818- * @param array $query
819- * @return Result
474+ * @param array $query 検索クエリー(省略すると名前順の最初の25件)
475+ * @return Result 結果。data['data']:results、total
820476 */
821477 public function listNameservers(array $query = []): Result {
822- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
823- $cacheName = 'listnameservers';
824- $cache = $this->cache->get($cacheName);
825- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
826-
827- if (empty($query)) $query = [ 'limit' => 25, 'offset' => 0, 'order_by.name' => 'asc' ];
828- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
829-
830- $uri = "/dns/nameservers?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
831- $curl = $this->setupCurl($uri);
832- $res = $this->curlResult($curl);
833- if (isset($res->data['data'])) {
834- $this->cache->set($cacheName, $res->data + ['query' => $query]);
835- return Result::Success('', $res->data);
836- }
837-
838- return Result::Error('ネームサーバー一覧の受け取りに失敗。');
478+ // 「order_by.name」はこのAPIに無い(order、order_by)
479+ if (empty($query)) $query = ['limit' => 25, 'offset' => 0, 'order_by' => 'name', 'order' => 'asc'];
480+ return $this->get('ネームサーバー一覧の受け取り', '/dns/nameservers', $query, 'dnsns-list');
839481 }
840482
841483 /**
842484 * ネームサーバーの作成
843- * @todo テスト
844485 *
845- * @param array $payload フォームデータ
846- * @return Result
486+ * @param array $payload name、ip、ip6
487+ * @return Result 結果。data['data']:name、ip、ip6
847488 */
848489 public function createNameserver(array $payload = []): Result {
849- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
850-
851- $uri = '/dns/nameservers';
852- $curl = $this->setupCurl($uri, 'POST', $payload);
853- $res = $this->curlResult($curl);
854- if (isset($res->data['data'])) {
855- $this->cache->murder('listnameservers');
856- return Result::Success('ネームサーバーの追加に成功。', $res->data);
857- }
858-
859- return Result::Error('ネームサーバーの追加に失敗。');
490+ return $this->send('ネームサーバーの追加', 'POST', '/dns/nameservers', $payload, [], ['dnsns-']);
860491 }
861492
862493 /**
863- * ネームサーバー一覧
864- * @todo テスト
494+ * ネームサーバーの表示
865495 *
866- * @param string $domain ドメイン名
867- * @param array $query 検索クエリー
868- * @return Result
496+ * @param string $name ネームサーバー名(例:ns1.example.com)
497+ * @return Result 結果。data['data']:name、ip、ip6
869498 */
870- public function getNameserver(string $domain, array $query = []): Result {
871- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
872- $cacheName = "listnameserver-{$domain}";
873- $cache = $this->cache->get($cacheName);
874- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
875-
876- if (empty($query)) $query = [ 'limit' => 100, 'offset' => 0, 'order_by.name' => 'asc' ];
877- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
878-
879- $uri = "/dns/nameservers/{$domain}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
880- $curl = $this->setupCurl($uri);
881- $res = $this->curlResult($curl);
882- if (isset($res->data['data'])) {
883- $this->cache->set($cacheName, $res->data + ['query' => $query]);
884- return Result::Success('', $res->data);
885- }
886-
887- return Result::Error('ネームサーバー一覧の受け取りに失敗。');
499+ public function getNameserver(string $name): Result {
500+ // 以前は一覧のクエリー(limit等)を付けていた
501+ return $this->get('ネームサーバーの受け取り', '/dns/nameservers/'.self::seg($name), [], 'dnsns-'.self::cacheKey($name));
888502 }
889503
890504 /**
891505 * ネームサーバーの更新
892- * @todo テスト
893506 *
894- * @param string $domain ドメイン名
895- * @param array $payload フォームデータ
896- * @return Result
507+ * @param string $name ネームサーバー名
508+ * @param array $payload ip、ip6
509+ * @return Result 結果
897510 */
898- public function updateNameserver(string $domain, array $payload = []): Result {
899- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
900-
901- $uri = "/dns/nameservers/{$domain}";
902- $curl = $this->setupCurl($uri, 'PUT', $payload);
903- $res = $this->curlResult($curl);
904- if (isset($res->data['data'])) {
905- $this->cache->murder('listnameservers');
906- $this->cache->murder("listnameserver-{$domain}");
907- if ($res->data['data']['success']) return Result::Success('ネームサーバーの更新に成功。', $res->data);
908- }
909-
910- return Result::Error('ネームサーバーの更新に失敗。');
511+ public function updateNameserver(string $name, array $payload = []): Result {
512+ return $this->send('ネームサーバーの更新', 'PUT', '/dns/nameservers/'.self::seg($name), ['name' => $name] + $payload, [], ['dnsns-']);
911513 }
912514
913515 /**
914516 * ネームサーバーの削除
915- * @todo テスト
916517 *
917- * @param string $domain ドメイン名
918- * @return Result
518+ * @param string $name ネームサーバー名
519+ * @return Result 結果
919520 */
920- public function deleteNameserver(string $domain): Result {
921- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
922-
923- $uri = "/dns/nameservers/{$domain}";
924- $curl = $this->setupCurl($uri, 'DELETE');
925- $res = $this->curlResult($curl);
926- if (isset($res->data['data'])) {
927- $this->cache->murder('listnameservers');
928- $this->cache->murder("listnameserver-{$domain}");
929- if ($res->data['data']['success']) return Result::Success('ネームサーバーの削除に成功。', $res->data);
930- }
931-
932- return Result::Error('ネームサーバーの削除に失敗。');
521+ public function deleteNameserver(string $name): Result {
522+ return $this->send('ネームサーバーの削除', 'DELETE', '/dns/nameservers/'.self::seg($name), null, [], ['dnsns-']);
933523 }
934524
935525 //// NSグループ
936526
937527 /**
938528 * NSグループ一覧
939- * @todo テスト
940529 *
941- * @param array $query
942- * @return Result
530+ * @param array $query 検索クエリー(省略すると名前順の最初の25件)
531+ * @return Result 結果。data['data']:results、total
943532 */
944533 public function listNsGroups(array $query = []): Result {
945- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
946- $cacheName = 'listnsgroups';
947- $cache = $this->cache->get($cacheName);
948- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
949-
950- if (empty($query)) $query = [ 'limit' => 25, 'offset' => 0, 'order_by.name' => 'asc' ];
951- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
952-
953- $uri = "/dns/nameservers/groups?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
954- $curl = $this->setupCurl($uri);
955- $res = $this->curlResult($curl);
956- if (isset($res->data['data'])) {
957- $this->cache->set($cacheName, $res->data + ['query' => $query]);
958- return Result::Success('', $res->data);
959- }
960-
961- return Result::Error('NSグループ一覧の受け取りに失敗。');
534+ // 以前は「order_by.name」(このAPIでは「order_by.ns_group」)
535+ if (empty($query)) $query = ['limit' => 25, 'offset' => 0, 'order_by.ns_group' => 'asc'];
536+ return $this->get('NSグループ一覧の受け取り', '/dns/nameservers/groups', $query, 'dnsnsgroup-list');
962537 }
963538
964539 /**
965540 * NSグループの作成
966- * @todo テスト
967541 *
968- * @param array $payload フォームデータ
969- * @return Result
542+ * @param array $payload ns_group、name_servers(['name' => …, 'ip' => …]の配列)
543+ * @return Result 結果
970544 */
971545 public function createNsGroup(array $payload = []): Result {
972- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
973-
974- $uri = '/dns/nameservers/groups';
975- $curl = $this->setupCurl($uri, 'POST', $payload);
976- $res = $this->curlResult($curl);
977- if (isset($res->data['data'])) {
978- $this->cache->murder('listnsgroups');
979- return Result::Success('NSグループの追加に成功。', $res->data);
980- }
981-
982- return Result::Error('NSグループの追加に失敗。');
546+ return $this->send('NSグループの追加', 'POST', '/dns/nameservers/groups', $payload, [], ['dnsnsgroup-']);
983547 }
984548
985549 /**
986- * NSグループ一覧
987- * @todo テスト
550+ * NSグループの表示
988551 *
989- * @param string $nsGroup ネームサーバー名
990- * @param array $query 検索クエリー
991- * @return Result
552+ * @param string $nsGroup NSグループ名
553+ * @param array $query id
554+ * @return Result 結果。data['data']:ns_group、name_servers等
992555 */
993556 public function getNsGroup(string $nsGroup, array $query = []): Result {
994- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
995- $cacheName = "listnsgroup-{$nsGroup}";
996- $cache = $this->cache->get($cacheName);
997- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
998-
999- if (empty($query)) $query = [ 'limit' => 100, 'offset' => 0, 'order_by.name' => 'asc' ];
1000- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
1001-
1002- $uri = "/dns/nameservers/groups/{$nsGroup}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1003- $curl = $this->setupCurl($uri);
1004- $res = $this->curlResult($curl);
1005- if (isset($res->data['data'])) {
1006- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1007- return Result::Success('', $res->data);
1008- }
1009-
1010- return Result::Error('NSグループ一覧の受け取りに失敗。');
557+ return $this->get('NSグループの受け取り', '/dns/nameservers/groups/'.self::seg($nsGroup), $query, 'dnsnsgroup-'.self::cacheKey($nsGroup));
1011558 }
1012559
1013560 /**
1014561 * NSグループの更新
1015- * @todo テスト
1016562 *
1017- * @param string $nsGroup ネームサーバー名
1018- * @param array $payload フォームデータ
1019- * @return Result
563+ * @param string $nsGroup NSグループ名
564+ * @param array $payload name_servers
565+ * @return Result 結果
1020566 */
1021567 public function updateNsGroup(string $nsGroup, array $payload = []): Result {
1022- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1023-
1024- $uri = "/dns/nameservers/groups/{$nsGroup}";
1025- $curl = $this->setupCurl($uri, 'PUT', $payload);
1026- $res = $this->curlResult($curl);
1027- if (isset($res->data['data'])) {
1028- $this->cache->murder('listnsgroups');
1029- $this->cache->murder("listnsgroup-{$nsGroup}");
1030- if ($res->data['data']['success']) return Result::Success('NSグループの更新に成功。', $res->data);
1031- }
1032-
1033- return Result::Error('NSグループの更新に失敗。');
568+ return $this->send('NSグループの更新', 'PUT', '/dns/nameservers/groups/'.self::seg($nsGroup), ['ns_group' => $nsGroup] + $payload, [], ['dnsnsgroup-']);
1034569 }
1035570
1036571 /**
1037572 * NSグループの削除
1038- * @todo テスト
1039573 *
1040- * @param string $nsGroup ネームサーバー名
1041- * @return Result
574+ * @param string $nsGroup NSグループ名
575+ * @return Result 結果
1042576 */
1043577 public function deleteNsGroup(string $nsGroup): Result {
1044- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1045-
1046- $uri = "/dns/nameservers/groups/{$nsGroup}";
1047- $curl = $this->setupCurl($uri, 'DELETE');
1048- $res = $this->curlResult($curl);
1049- if (isset($res->data['data'])) {
1050- $this->cache->murder('listnsgroups');
1051- $this->cache->murder("listnsgroup-{$nsGroup}");
1052- if ($res->data['data']['success']) return Result::Success('NSグループの削除に成功。', $res->data);
1053- }
1054-
1055- return Result::Error('NSグループの削除に失敗。');
578+ return $this->send('NSグループの削除', 'DELETE', '/dns/nameservers/groups/'.self::seg($nsGroup), null, [], ['dnsnsgroup-']);
1056579 }
1057580
1058581 //// テンプレート
1059582
1060583 /**
1061584 * DNSテンプレート一覧
1062- * @todo テスト
1063585 *
1064- * @param array $query 検索クエリー
1065- * @return Result
586+ * @param array $query 検索クエリー(with_records、name_pattern等)
587+ * @return Result 結果。data['data']:results、total
1066588 */
1067589 public function listDnsTemplate(array $query = []): Result {
1068- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1069- $cacheName = 'listdnstemplates';
1070- $cache = $this->cache->get($cacheName);
1071- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1072-
1073- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1074- $uri = '/dns/templates?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1075- $curl = $this->setupCurl($uri);
1076- $res = $this->curlResult($curl);
1077- if (isset($res->data['data'])) {
1078- $res->data['query'] = $query;
1079- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1080- return Result::Success('', $res->data);
1081- }
1082-
1083- return Result::Error('DNSテンプレート一覧の受け取りに失敗。');
590+ return $this->get('DNSテンプレート一覧の受け取り', '/dns/templates', $query, 'dnstemplate-list');
1084591 }
1085592
1086593 /**
1087594 * DNSテンプレートの作成
1088- * @todo テスト
1089595 *
1090- * @param array $payload フォームデータ
1091- * @return Result
596+ * @param array $payload name、records、is_spamexperts_enabled
597+ * @return Result 結果。data['data']:id
1092598 */
1093599 public function createDnsTemplate(array $payload = []): Result {
1094- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1095-
1096- $uri = '/dns/templates';
1097- $curl = $this->setupCurl($uri, 'POST', $payload);
1098- $res = $this->curlResult($curl);
1099- if (isset($res->data['data'])) {
1100- $this->cache->murder('listdnstemplates');
1101- return Result::Success('DNSテンプレートの追加に成功。', $res->data);
1102- }
1103-
1104- return Result::Error('DNSテンプレートの追加に失敗。');
600+ return $this->send('DNSテンプレートの追加', 'POST', '/dns/templates', $payload, [], ['dnstemplate-']);
1105601 }
1106602
1107603 /**
1108604 * DNSテンプレートの表示
1109- * @todo テスト
1110605 *
1111606 * @param int $id DNSテンプレートID
1112- * @return Result
607+ * @return Result 結果。data['data']:id、name、records等
1113608 */
1114609 public function getDnsTemplate(int $id): Result {
1115- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1116- $cacheName = "getdnstemplate-{$id}";
1117- $cache = $this->cache->get($cacheName);
1118- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
1119-
1120- $uri = "/dns/templates/{$id}";
1121- $curl = $this->setupCurl($uri);
1122- $res = $this->curlResult($curl);
1123- if (isset($res->data['data'])) {
1124- $this->cache->set($cacheName, $res->data);
1125- return Result::Success('', $res->data);
1126- }
1127-
1128- return Result::Error('DNSテンプレートの更新に失敗。');
610+ return $this->get('DNSテンプレートの受け取り', "/dns/templates/{$id}", [], "dnstemplate-{$id}");
1129611 }
1130612
1131613 /**
1132614 * DNSテンプレートの削除
1133- * @todo テスト
1134615 *
1135616 * @param int $id DNSテンプレートID
1136- * @return Result
617+ * @return Result 結果
1137618 */
1138619 public function deleteDnsTemplate(int $id): Result {
1139- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1140-
1141- $uri = "/dns/templates/{$id}";
1142- $curl = $this->setupCurl($uri, 'DELETE');
1143- $res = $this->curlResult($curl);
1144- if (isset($res->data['data'])) {
1145- $this->cache->murder('listdnstemplates');
1146- $this->cache->murder("getdnstemplate-{$id}");
1147- if ($res->data['data']['success']) return Result::Success('DNSテンプレートの削除に成功。', $res->data);
1148- }
1149-
1150- return Result::Error('DNSテンプレートの削除に失敗。');
620+ return $this->send('DNSテンプレートの削除', 'DELETE', "/dns/templates/{$id}", null, [], ['dnstemplate-']);
1151621 }
1152622
1153623 //// DNSゾーン
@@ -1155,120 +625,56 @@
1155625 /**
1156626 * DNSゾーン一覧
1157627 *
1158- * @param array $query
1159- * @return Result
628+ * @param array $query 検索クエリー(省略すると名前順の最初の25件)
629+ * @return Result 結果。data['data']:results、total
1160630 */
1161631 public function listDnsZones(array $query = []): Result {
1162- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1163- $cacheName = 'listdnszones';
1164- $cache = $this->cache->get($cacheName);
1165- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1166-
1167- if (empty($query)) $query = [ 'limit' => 25, 'offset' => 0, 'order_by.name' => 'asc' ];
1168- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
1169-
1170- $uri = "/dns/zones?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1171- $curl = $this->setupCurl($uri);
1172- $res = $this->curlResult($curl);
1173- if (isset($res->data['data'])) {
1174- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1175- return Result::Success('', $res->data);
1176- }
1177-
1178- return Result::Error('DNSゾーン一覧の受け取りに失敗。');
632+ if (empty($query)) $query = ['limit' => 25, 'offset' => 0, 'order_by.name' => 'asc'];
633+ return $this->get('DNSゾーン一覧の受け取り', '/dns/zones', $query, 'dnszone-list');
1179634 }
1180635
1181636 /**
1182637 * DNSゾーンの作成
1183- * @todo テスト
1184638 *
1185- * @param array $payload フォームデータ
1186- * @return Result
639+ * @param array $payload domain(name、extension)、type(master又はslave)、records、template_name等
640+ * @return Result 結果
1187641 */
1188642 public function createDnsZone(array $payload = []): Result {
1189- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1190-
1191- $uri = '/dns/zones';
1192- $curl = $this->setupCurl($uri, 'POST', $payload);
1193- $res = $this->curlResult($curl);
1194- if (isset($res->data['data'])) {
1195- $this->cache->murder('listdnszones');
1196- return Result::Success('DNSゾーンの追加に成功。', $res->data);
1197- }
1198-
1199- return Result::Error('DNSゾーンの追加に失敗。');
643+ return $this->send('DNSゾーンの追加', 'POST', '/dns/zones', $payload, [], ['dnszone-']);
1200644 }
1201645
1202646 /**
1203- * DNSゾーン一覧
647+ * DNSゾーンの表示
1204648 *
1205649 * @param string $domain ドメイン名
1206- * @param array $query 検索クエリー
1207- * @return Result
650+ * @param array $query with_records、with_history、with_dnskey、provider
651+ * @return Result 結果。data['data']:ゾーン
1208652 */
1209653 public function getDnsZone(string $domain, array $query = []): Result {
1210- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1211- $cacheName = "getdnszone-{$domain}";
1212- $cache = $this->cache->get($cacheName);
1213- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1214-
1215- if (empty($query)) $query = [ 'limit' => 100, 'offset' => 0, 'order_by.name' => 'asc' ];
1216- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
1217-
1218- $uri = "/dns/zones/{$domain}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1219- $curl = $this->setupCurl($uri);
1220- $res = $this->curlResult($curl);
1221- if (isset($res->data['data'])) {
1222- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1223- return Result::Success('', $res->data);
1224- }
1225-
1226- return Result::Error('DNSゾーン一覧の受け取りに失敗。');
654+ // 以前は一覧のクエリー(limit、order_by.name等)を付けていた
655+ return $this->get('DNSゾーンの受け取り', '/dns/zones/'.self::seg($domain), $query, 'dnszone-'.self::cacheKey($domain));
1227656 }
1228657
1229658 /**
1230659 * DNSゾーンの更新
1231- * @todo テスト
1232660 *
1233661 * @param string $domain ドメイン名
1234- * @param array $payload フォームデータ
1235- * @return Result
662+ * @param array $payload records(add、remove、replace、update)等
663+ * @return Result 結果
1236664 */
1237665 public function updateDnsZone(string $domain, array $payload = []): Result {
1238- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1239-
1240- $uri = "/dns/zones/{$domain}";
1241- $curl = $this->setupCurl($uri, 'PUT', $payload);
1242- $res = $this->curlResult($curl);
1243- if (isset($res->data['data'])) {
1244- $this->cache->murder('listdnszones');
1245- $this->cache->murder("getdnszone-{$domain}");
1246- if ($res->data['data']['success']) return Result::Success('DNSゾーンの更新に成功。', $res->data);
1247- }
1248-
1249- return Result::Error('DNSゾーンの更新に失敗。');
666+ return $this->send('DNSゾーンの更新', 'PUT', '/dns/zones/'.self::seg($domain), ['name' => $domain] + $payload, [], ['dnszone-', 'dnsrecords-'.self::cacheKey($domain)]);
1250667 }
1251668
1252669 /**
1253670 * DNSゾーンの削除
1254- * @todo テスト
1255671 *
1256672 * @param string $domain ドメイン名
1257- * @return Result
673+ * @param array $query id、provider等
674+ * @return Result 結果
1258675 */
1259- public function deleteDnsZone(string $domain): Result {
1260- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1261-
1262- $uri = "/dns/zones/{$domain}";
1263- $curl = $this->setupCurl($uri, 'DELETE');
1264- $res = $this->curlResult($curl);
1265- if (isset($res->data['data'])) {
1266- $this->cache->murder('listdnszones');
1267- $this->cache->murder("getdnszone-{$domain}");
1268- if ($res->data['data']['success']) return Result::Success('DNSゾーンの削除に成功。', $res->data);
1269- }
1270-
1271- return Result::Error('DNSゾーンの削除に失敗。');
676+ public function deleteDnsZone(string $domain, array $query = []): Result {
677+ return $this->send('DNSゾーンの削除', 'DELETE', '/dns/zones/'.self::seg($domain), null, $query, ['dnszone-', 'dnsrecords-'.self::cacheKey($domain)]);
1272678 }
1273679
1274680 //// ゾーンレコード
@@ -1276,500 +682,294 @@
1276682 /**
1277683 * DNSレコード一覧
1278684 *
1279- * @param string $domain
1280- * @return Result
685+ * @param string $domain ドメイン名
686+ * @param array $query 検索クエリー(type、limit、order_by.*等)
687+ * @return Result 結果。data['data']:results、total
1281688 */
1282- public function listZoneRecords(string $domain): Result {
1283- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1284- $cacheName = "getzonerecords-{$domain}";
1285- $cache = $this->cache->get($cacheName);
1286- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
1287-
1288- $curl = $this->setupCurl("/dns/zones/{$domain}/records");
1289- $res = $this->curlResult($curl);
1290- if (isset($res->data['data'])) {
1291- $this->cache->set($cacheName, $res->data);
1292- return Result::Success('', $res->data);
1293- }
1294-
1295- return Result::Error('TLD一覧の受け取りに失敗。');
689+ public function listZoneRecords(string $domain, array $query = []): Result {
690+ return $this->get('DNSレコード一覧の受け取り', '/dns/zones/'.self::seg($domain).'/records', $query, 'dnsrecords-'.self::cacheKey($domain));
1296691 }
1297692
1298- // Easydmarc
693+ // EasyDMARC
1299694
1300695 /**
1301- * Easydmarc一覧
1302- * @todo テスト
696+ * ドメインのEasyDMARCの表示
1303697 *
1304- * @param string $domain ドメイン名
1305- * @return Result
698+ * @param string $domain ドメイン名(例:076.moe)
699+ * @return Result 結果。data['data']:id、status、record_host、record_value等
1306700 */
1307701 public function getEasydmarc(string $domain): Result {
1308- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1309- $cacheName = "listeasydmarc-{$domain}";
1310- $cache = $this->cache->get($cacheName);
1311- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
1312-
1313- $parts = explode('.', $domain, 2);
1314- assert_exists($parts[0]);
1315- assert_exists($parts[1]);
1316- $query = [ 'name' => $parts[0], 'extension' => $parts[1] ];
1317-
1318- $uri = "/dns/easydmarcs?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1319- $curl = $this->setupCurl($uri);
1320- $res = $this->curlResult($curl);
1321- if (isset($res->data['data'])) {
1322- $this->cache->set($cacheName, $res->data);
1323- return Result::Success('', $res->data);
1324- }
1325-
1326- return Result::Error('Easydmarc一覧の受け取りに失敗。');
702+ $d = self::splitDomain($domain);
703+ if ($d === null) return Result::Error("不正なドメイン形: {$domain}");
704+ // 以前は「/dns/easydmarcs」でクエリーも「name」「extension」だった
705+ return $this->get('EasyDMARCの受け取り', '/easydmarcs', ['domain.name' => $d['name'], 'domain.extension' => $d['extension']], 'easydmarc-'.self::cacheKey($domain));
1327706 }
1328707
1329708 /**
1330- * Easydmarcの作成
1331- * @todo テスト
709+ * EasyDMARCの注文
1332710 *
1333711 * @param string $domain ドメイン名
1334- * @return Result
712+ * @param string $ownerHandle 所有者のハンドル(省略するとconfig.phpのOPENPROVIDERの「owner_handle」)
713+ * @return Result 結果。data['data']:注文
1335714 */
1336- public function createEasydmarc(string $domain): Result {
1337- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1338-
1339- $parts = explode('.', $domain, 2);
1340- assert_exists($parts[0]);
1341- assert_exists($parts[1]);
1342- $payload = [ 'name' => $parts[0], 'extension' => $parts[1] ];
1343-
1344- $uri = '/dns/easydmarcs';
1345- $curl = $this->setupCurl($uri, 'POST', $payload);
1346- $res = $this->curlResult($curl);
1347- if (isset($res->data['data'])) {
1348- $this->cache->murder('listeasydmarcs');
1349- return Result::Success('Easydmarcの追加に成功。', $res->data);
1350- }
1351-
1352- return Result::Error('Easydmarcの追加に失敗。');
715+ public function createEasydmarc(string $domain, string $ownerHandle = ''): Result {
716+ $d = self::splitDomain($domain);
717+ if ($d === null) return Result::Error("不正なドメイン形: {$domain}");
718+ $payload = ['domain' => $d, 'owner_handle' => $ownerHandle !== '' ? $ownerHandle : (string)(OPENPROVIDER['owner_handle'] ?? '')];
719+ return $this->send('EasyDMARCの注文', 'POST', '/easydmarcs', $payload, [], ['easydmarc-']);
1353720 }
1354721
1355722 /**
1356- * Easydmarc一覧
1357- * @todo テスト
723+ * EasyDMARC一覧
1358724 *
1359- * @param array $query
1360- * @return Result
725+ * @param array $query 検索クエリー(status、domain.name等)。「domain」(例:076.moe)も使える
726+ * @return Result 結果。data['data']:results、total
1361727 */
1362728 public function listEasydmarcs(array $query = []): Result {
1363- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1364- $cacheName = 'listeasydmarcs';
1365- $cache = $this->cache->get($cacheName);
1366- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1367-
1368- if (!empty($query) && isset($query['domain'])) {
1369- $parts = explode('.', $query['domain'], 2);
1370- assert_exists($parts[0]);
1371- assert_exists($parts[1]);
1372- $query['domain.name'] = $parts[0];
1373- $query['domain.extension'] = $parts[1];
729+ if (isset($query['domain'])) {
730+ $d = self::splitDomain((string)$query['domain']);
731+ if ($d === null) return Result::Error("不正なドメイン形: {$query['domain']}");
732+ unset($query['domain']);
733+ $query += ['domain.name' => $d['name'], 'domain.extension' => $d['extension']];
1374734 }
1375-
1376- if (empty($query)) $query = [ 'limit' => 100, 'offset' => 0, 'order_by.id' => 'asc' ];
1377- foreach ($query as $k => $v) if (is_bool($v)) $query[$k] = $v ? 'true' : 'false';
1378-
1379- $uri = "/dns/easydmarcs/list?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1380- $curl = $this->setupCurl($uri);
1381- $res = $this->curlResult($curl);
1382- if (isset($res->data['data'])) {
1383- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1384- return Result::Success('', $res->data);
1385- }
1386-
1387- return Result::Error('Easydmarc一覧の受け取りに失敗。');
735+ if (empty($query)) $query = ['limit' => 100, 'offset' => 0, 'order_by.id' => 'asc'];
736+ return $this->get('EasyDMARC一覧の受け取り', '/easydmarcs/list', $query, 'easydmarc-list');
1388737 }
1389738
1390739 /**
1391- * Easydmarcの削除
1392- * @todo テスト
740+ * EasyDMARCの削除
1393741 *
1394742 * @param int $orderId 注文ID
1395- * @return Result
743+ * @return Result 結果。data['data']:status
1396744 */
1397745 public function deleteEasydmarc(int $orderId): Result {
1398- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1399-
1400- $uri = "/dns/easydmarcs/{$domain}";
1401- $curl = $this->setupCurl($uri, 'DELETE');
1402- $res = $this->curlResult($curl);
1403- if (isset($res->data['data'])) {
1404- $this->cache->murder('listeasydmarcs');
1405- $this->cache->murder("listeasydmarc-{$domain}");
1406- $this->cache->murder("geteasydmarcssso-{$orderId}");
1407- if ($res->data['data']['success']) return Result::Success('Easydmarcの削除に成功。', $res->data);
1408- }
1409-
1410- return Result::Error('Easydmarcの削除に失敗。');
746+ // 以前は未定義の$domainを使っていた
747+ return $this->send('EasyDMARCの削除', 'DELETE', "/easydmarcs/{$orderId}", null, [], ['easydmarc-']);
1411748 }
1412749
1413750 /**
1414- * Easydmarcを再度注文してみる
1415- * @todo テスト
751+ * 失敗したEasyDMARCの注文の再試行
1416752 *
1417753 * @param int $orderId 注文ID
1418- * @return Result
754+ * @return Result 結果。data['data']:注文
1419755 */
1420756 public function retryEasydmarc(int $orderId): Result {
1421- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1422-
1423- $uri = "/dns/easydmarcs/{$domain}/retry";
1424- $curl = $this->setupCurl($uri, 'POST');
1425- $res = $this->curlResult($curl);
1426- if (isset($res->data['data'])) {
1427- $this->cache->murder('listeasydmarcs');
1428- $this->cache->murder("listeasydmarc-{$domain}");
1429- $this->cache->murder("geteasydmarcssso-{$orderId}");
1430- if ($res->data['data']['success']) return Result::Success('Easydmarcを再度注文してみる事に成功。', $res->data);
1431- }
1432-
1433- return Result::Error('Easydmarcを再度注文してみる事に失敗。');
757+ return $this->send('EasyDMARCの注文の再試行', 'POST', "/easydmarcs/{$orderId}/retry", ['id' => $orderId], [], ['easydmarc-']);
1434758 }
1435759
1436760 /**
1437- * Easydmarcの削除
1438- * @todo テスト
761+ * EasyDMARCの管理画面にログインするURL(使い捨てなのでキャッシュしない)
1439762 *
1440763 * @param int $orderId 注文ID
1441- * @return Result
764+ * @param string $type 画面の種類(省略可)
765+ * @return Result 結果。data['data']:url
1442766 */
1443- public function getEasydmarcSso(int $orderId): Result {
1444- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1445- // SSOのリンクは使い捨てなのでキャッシュしない(以前は未定義の$domainと$dataを使っていた)
1446- $uri = "/dns/easydmarcs/{$orderId}/sso";
1447- $curl = $this->setupCurl($uri);
1448- $res = $this->curlResult($curl);
1449- if ($res->isSuccess && isset($res->data['data'])) return Result::Success('', $res->data);
1450-
1451- return Result::Error('EasydmarcのSSOの受け取りに失敗。');
767+ public function getEasydmarcSso(int $orderId, string $type = ''): Result {
768+ return $this->get('EasyDMARCのSSOの受け取り', "/easydmarcs/{$orderId}/sso", $type !== '' ? ['type' => $type] : []);
1452769 }
1453770
1454-
1455771 // メールテンプレート
1456772
1457773 //// メール
1458774
1459775 /**
1460776 * メールテンプレート一覧
1461- * @todo テスト
1462777 *
1463- * @param array $query 検索クエリー
1464- * @return Result
778+ * @param array $query 検索クエリー(id、name、group、is_system等)
779+ * @return Result 結果。data['data']:results、total
1465780 */
1466781 public function listEmails(array $query = []): Result {
1467- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1468- $cacheName = 'listemails';
1469- $cache = $this->cache->get($cacheName);
1470- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1471-
1472- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1473- $uri = '/emails?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1474- $curl = $this->setupCurl($uri);
1475- $res = $this->curlResult($curl);
1476- if (isset($res->data['data'])) {
1477- $res->data['query'] = $query;
1478- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1479- return Result::Success('', $res->data);
1480- }
1481-
1482- return Result::Error('メールテンプレート一覧の受け取りに失敗。');
782+ return $this->get('メールテンプレート一覧の受け取り', '/emails', $query, 'email-list');
1483783 }
1484784
1485785 /**
1486786 * メールテンプレートの作成
1487- * @todo テスト
1488787 *
1489- * @param array $payload フォームデータ
1490- * @return Result
788+ * @param array $payload name、group、fields、locale、tags、is_active、is_default
789+ * @return Result 結果。data['data']:id
1491790 */
1492791 public function createEmail(array $payload = []): Result {
1493- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1494-
1495- $uri = '/emails';
1496- $curl = $this->setupCurl($uri, 'POST', $payload);
1497- $res = $this->curlResult($curl);
1498- if (isset($res->data['data'])) {
1499- $this->cache->murder('listemails');
1500- return Result::Success('メールテンプレートの追加に成功。', $res->data);
1501- }
1502-
1503- return Result::Error('メールテンプレートの追加に失敗。');
792+ return $this->send('メールテンプレートの追加', 'POST', '/emails', $payload, [], ['email-']);
1504793 }
1505794
1506795 /**
1507796 * メールテンプレートの更新
1508- * @todo テスト
1509797 *
1510798 * @param int $id メールテンプレートID
1511- * @param array $payload フォームデータ
1512- * @return Result
799+ * @param array $payload 更新する項目
800+ * @return Result 結果
1513801 */
1514802 public function updateEmail(int $id, array $payload = []): Result {
1515- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1516-
1517- $uri = "/emails/{$id}";
1518- $curl = $this->setupCurl($uri, 'PUT', $payload);
1519- $res = $this->curlResult($curl);
1520- if (isset($res->data['data'])) {
1521- $this->cache->murder('listemails');
1522- if ($res->data['data']['success']) return Result::Success('メールテンプレートの更新に成功。', $res->data);
1523- }
1524-
1525- return Result::Error('メールテンプレートの更新に失敗。');
803+ return $this->send('メールテンプレートの更新', 'PUT', "/emails/{$id}", ['id' => $id] + $payload, [], ['email-']);
1526804 }
1527805
1528806 /**
1529807 * メールテンプレートの削除
1530- * @todo テスト
1531808 *
1532809 * @param int $id メールテンプレートID
1533- * @return Result
810+ * @return Result 結果
1534811 */
1535812 public function deleteEmail(int $id): Result {
1536- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1537-
1538- $uri = "/emails/{$id}";
1539- $curl = $this->setupCurl($uri, 'DELETE');
1540- $res = $this->curlResult($curl);
1541- if (isset($res->data['data'])) {
1542- $this->cache->murder('listemails');
1543- if ($res->data['data']['success']) return Result::Success('メールテンプレートの削除に成功。', $res->data);
1544- }
1545-
1546- return Result::Error('メールテンプレートの削除に失敗。');
813+ return $this->send('メールテンプレートの削除', 'DELETE', "/emails/{$id}", null, [], ['email-']);
1547814 }
1548815
1549816 // ライセンス
1550817
1551818 /**
1552- * ライセンス一覧
1553- * @todo テスト
819+ * ライセンス一覧(値段付き)
1554820 *
1555- * @param array $query 検索クエリー
1556- * @return Result
821+ * @param array $query 検索クエリー(product、status、key_number等)
822+ * @return Result 結果。data['data']:results、total
1557823 */
1558824 public function listLicenses(array $query = []): Result {
1559- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1560- $cacheName = 'listlicenses';
1561- $cache = $this->cache->get($cacheName);
1562- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1563-
1564- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1565- $uri = '/licenses?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1566- $curl = $this->setupCurl($uri);
1567- $res = $this->curlResult($curl);
1568- if (isset($res->data['data'])) {
1569- $res->data['query'] = $query;
1570- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1571- return Result::Success('ライセンス一覧の受け取りに成功。', $res->data);
1572- }
1573-
1574- return Result::Error('ライセンス一覧の受け取りに失敗。');
825+ return $this->get('ライセンス一覧の受け取り', '/licenses', $query, 'license-list');
1575826 }
1576827
1577828 /**
1578- * HWIDの再設定
1579- * @todo テスト
829+ * ライセンスのハードウェアIDの再設定
1580830 *
1581- * @param string $product 商品種類(Pleskのみ)
1582- * @param int $keyId ライセンスキーID
1583- * @return Result
831+ * @param string $product 商品(例:plesk、virtuozzo)
832+ * @param int $keyId キーID
833+ * @return Result 結果
1584834 */
1585835 public function resetLicenseHwid(string $product, int $keyId): Result {
1586- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1587-
1588- $payload = ['key_id' => $keyId, 'product' => $product];
1589- $uri = "/licenses/hwids/reset/{$product}/{$keyId}";
1590- $curl = $this->setupCurl($uri, 'POST', $payload);
1591- $res = $this->curlResult($curl);
1592- // 以前はisset($res)で、失敗しても成功を返していた
1593- if ($res->isSuccess) {
1594- $this->cache->murder('listlicenses');
1595- return Result::Success('HWIDの再設定に成功。', $res->data);
1596- }
1597-
1598- return Result::Error("HWIDの再設定に失敗。");
836+ return $this->send('ハードウェアIDの再設定', 'POST', '/licenses/hwids/reset/'.self::seg($product)."/{$keyId}", ['key_id' => $keyId, 'product' => $product], [], ['license-']);
1599837 }
1600838
1601839 /**
1602- * 商品一覧
1603- * @todo テスト
840+ * ライセンスの商品一覧
1604841 *
1605- * @param array $query 検索クエリー
1606- * @return Result
842+ * @param array $query 検索クエリー(product等)
843+ * @return Result 結果。data['data']:results、total
1607844 */
1608845 public function listLicenseItems(array $query = []): Result {
1609- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1610- $cacheName = 'listitems';
1611- $cache = $this->cache->get($cacheName);
1612- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1613-
1614- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1615- $uri = '/licenses/items?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1616- $curl = $this->setupCurl($uri);
1617- $res = $this->curlResult($curl);
1618- if (isset($res->data['data'])) {
1619- $res->data['query'] = $query;
1620- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1621- return Result::Success('商品一覧の受け取りに成功。', $res->data);
1622- }
1623-
1624- return Result::Error('商品一覧の受け取りに失敗。');
846+ return $this->get('ライセンスの商品一覧の受け取り', '/licenses/items', $query, 'license-items');
1625847 }
1626848
849+ //// Plesk
850+
1627851 /**
1628- * Pleskライセンス一覧
1629- * @todo テスト
852+ * Pleskのライセンス一覧
1630853 *
1631854 * @param array $query 検索クエリー
1632- * @return Result
855+ * @return Result 結果。data['data']:results、total
1633856 */
1634857 public function listPleskLicenses(array $query = []): Result {
1635- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1636- $cacheName = 'listplesklicenses';
1637- $cache = $this->cache->get($cacheName);
1638- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1639-
1640- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1641- $uri = '/licenses/plesk?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1642- $curl = $this->setupCurl($uri);
1643- $res = $this->curlResult($curl);
1644- if (isset($res->data['data'])) {
1645- $res->data['query'] = $query;
1646- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1647- return Result::Success('Pleskライセンス一覧の受け取りに成功。', $res->data);
1648- }
1649-
1650- return Result::Error('Pleskライセンス一覧の受け取りに失敗。');
858+ return $this->get('Pleskのライセンス一覧の受け取り', '/licenses/plesk', $query, 'license-plesk');
1651859 }
1652860
1653861 /**
1654- * Pleskライセンスの作成
1655- * @todo テスト
862+ * Pleskのライセンスの注文
1656863 *
1657- * @param array $payload フォームデータ
1658- * @return Result
864+ * @param array $payload items、period、title、ip_address_binding等
865+ * @return Result 結果。data['data']:key_id、attached_keys
1659866 */
1660867 public function createPleskLicense(array $payload): Result {
1661- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1662-
1663- $uri = "/licenses/plesk";
1664- $curl = $this->setupCurl($uri, 'POST', $payload);
1665- $res = $this->curlResult($curl);
1666- // 以前はisset($res)で、失敗しても成功を返していた
1667- if ($res->isSuccess) {
1668- $this->cache->murder('listlicenses');
1669- $this->cache->murder('listplesklicenses');
1670- return Result::Success('Pleskライセンスの作成に成功。', $res->data);
1671- }
1672-
1673- return Result::Error("Pleskライセンスの作成に失敗。");
868+ return $this->send('Pleskのライセンスの注文', 'POST', '/licenses/plesk', $payload, [], ['license-']);
1674869 }
1675870
1676871 /**
1677- * Plesk鍵の受け取り
1678- * @todo テスト
872+ * Pleskのライセンスキー(キャッシュしない)
1679873 *
1680- * @param int $keyId 鍵ID
1681- * @return Result
874+ * @param int $keyId キーID
875+ * @return Result 結果。data['data']:key
1682876 */
1683877 public function getPleskKey(int $keyId): Result {
1684- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1685- $cacheName = "getpleskkey-{$keyId}";
1686- $cache = $this->cache->get($cacheName);
1687- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
878+ return $this->get('Pleskのライセンスキーの受け取り', "/licenses/plesk/key/{$keyId}");
879+ }
1688880
1689- $uri = "/licenses/plesk/key/{$keyId}";
1690- $curl = $this->setupCurl($uri);
1691- $res = $this->curlResult($curl);
1692- if (isset($res->data['data'])) {
1693- $res->data['query'] = $query;
1694- $this->cache->set($cacheName, $res->data);
1695- return Result::Success('Plesk鍵の受け取りに成功。', $res->data);
1696- }
881+ /**
882+ * Pleskのライセンスの表示
883+ *
884+ * @param int $keyId キーID
885+ * @return Result 結果。data['data']:ライセンス
886+ */
887+ public function getPleskLicense(int $keyId): Result {
888+ return $this->get('Pleskのライセンスの受け取り', "/licenses/plesk/{$keyId}", [], "license-plesk-{$keyId}");
889+ }
1697890
1698- return Result::Error('Plesk鍵の受け取りに失敗。');
891+ /**
892+ * Pleskのライセンスの更新
893+ *
894+ * @param int $keyId キーID
895+ * @param array $payload 更新する項目(items、title、suspended等)
896+ * @return Result 結果
897+ */
898+ public function updatePleskLicense(int $keyId, array $payload = []): Result {
899+ return $this->send('Pleskのライセンスの更新', 'PUT', "/licenses/plesk/{$keyId}", ['key_id' => $keyId] + $payload, [], ['license-']);
1699900 }
1700901
1701902 /**
1702- * Pleskライセンスの受け取り
1703- * @todo テスト
903+ * Pleskのライセンスの削除
1704904 *
1705- * @param int $keyId 鍵ID
1706- * @return Result
905+ * @param int $keyId キーID
906+ * @return Result 結果
1707907 */
1708- public function getPleskLicense(int $keyId): Result {
1709- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1710- $cacheName = "getplesklicense-{$keyId}";
1711- $cache = $this->cache->get($cacheName);
1712- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
908+ public function deletePleskLicense(int $keyId): Result {
909+ return $this->send('Pleskのライセンスの削除', 'DELETE', "/licenses/plesk/{$keyId}", null, [], ['license-']);
910+ }
1713911
1714- $uri = "/licenses/plesk/{$keyId}";
1715- $curl = $this->setupCurl($uri);
1716- $res = $this->curlResult($curl);
1717- if (isset($res->data['data'])) {
1718- $res->data['query'] = $query;
1719- $this->cache->set($cacheName, $res->data);
1720- return Result::Success('Pleskライセンスの受け取りに成功。', $res->data);
1721- }
912+ //// Virtuozzo
1722913
1723- return Result::Error('Pleskライセンスの受け取りに失敗。');
914+ /**
915+ * Virtuozzoのライセンス一覧
916+ *
917+ * @param array $query 検索クエリー
918+ * @return Result 結果。data['data']:results、total
919+ */
920+ public function listVirtuozzoLicenses(array $query = []): Result {
921+ return $this->get('Virtuozzoのライセンス一覧の受け取り', '/licenses/virtuozzo', $query, 'license-virtuozzo');
1724922 }
1725923
1726924 /**
1727- * 連絡先の更新
1728- * @todo テスト
925+ * Virtuozzoのライセンスの注文
1729926 *
1730- * @param int $keyId 鍵ID
1731- * @param array $payload フォームデータ
1732- * @return Result
927+ * @param array $payload items、period、pcs_capacity、title等
928+ * @return Result 結果。data['data']:key_id、attached_keys
1733929 */
1734- public function updatePleskLicense(int $keyId, array $payload = []): Result {
1735- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
930+ public function createVirtuozzoLicense(array $payload): Result {
931+ return $this->send('Virtuozzoのライセンスの注文', 'POST', '/licenses/virtuozzo', $payload, [], ['license-']);
932+ }
1736933
1737- $uri = "/licenses/plesk/{$keyId}";
1738- $curl = $this->setupCurl($uri, 'PUT', $payload);
1739- $res = $this->curlResult($curl);
1740- if (isset($res->data['data'])) {
1741- $this->cache->murder("getpleskkey-{$keyId}");
1742- $this->cache->murder("getplesklicense-{$keyId}");
1743- $this->cache->murder('listlicenses');
1744- $this->cache->murder('listplesklicenses');
1745- if ($res->data['data']['success']) return Result::Success('連絡先の更新に成功。', $res->data);
1746- }
934+ /**
935+ * Virtuozzoのライセンスの表示
936+ *
937+ * @param int $keyId キーID
938+ * @return Result 結果。data['data']:ライセンス
939+ */
940+ public function getVirtuozzoLicense(int $keyId): Result {
941+ return $this->get('Virtuozzoのライセンスの受け取り', "/licenses/virtuozzo/{$keyId}", [], "license-virtuozzo-{$keyId}");
942+ }
1747943
1748- return Result::Error('連絡先の更新に失敗。');
944+ /**
945+ * Virtuozzoのライセンスの更新
946+ *
947+ * @param int $keyId キーID
948+ * @param array $payload 更新する項目
949+ * @return Result 結果
950+ */
951+ public function updateVirtuozzoLicense(int $keyId, array $payload = []): Result {
952+ return $this->send('Virtuozzoのライセンスの更新', 'PUT', "/licenses/virtuozzo/{$keyId}", ['key_id' => $keyId] + $payload, [], ['license-']);
1749953 }
1750954
1751955 /**
1752- * 連絡先の削除
1753- * @todo テスト
956+ * Virtuozzoのライセンスの削除
1754957 *
1755- * @param int $keyId 鍵ID
1756- * @return Result
958+ * @param int $keyId キーID
959+ * @return Result 結果
1757960 */
1758- public function deletePleskLicense(int $keyId): Result {
1759- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
961+ public function deleteVirtuozzoLicense(int $keyId): Result {
962+ return $this->send('Virtuozzoのライセンスの削除', 'DELETE', "/licenses/virtuozzo/{$keyId}", null, [], ['license-']);
963+ }
1760964
1761- $uri = "/licenses/plesk/{$keyId}";
1762- $curl = $this->setupCurl($uri, 'DELETE');
1763- $res = $this->curlResult($curl);
1764- if (isset($res->data['data'])) {
1765- $this->cache->murder("getpleskkey-{$keyId}");
1766- $this->cache->murder("getplesklicense-{$keyId}");
1767- $this->cache->murder('listlicenses');
1768- $this->cache->murder('listplesklicenses');
1769- if ($res->data['data']['success']) return Result::Success('連絡先の削除に成功。');
1770- }
1771-
1772- return Result::Error('連絡先の削除に失敗。');
965+ /**
966+ * Virtuozzoのライセンスキー(キャッシュしない)
967+ *
968+ * @param int $keyId キーID
969+ * @return Result 結果。data['data']:key
970+ */
971+ public function getVirtuozzoKey(int $keyId): Result {
972+ return $this->get('Virtuozzoのライセンスキーの受け取り', "/licenses/virtuozzo/{$keyId}/key");
1773973 }
1774974
1775975 // リセラー・顧客様
@@ -1778,583 +978,303 @@
1778978
1779979 /**
1780980 * 連絡先の一覧
1781- * @todo テスト
1782981 *
1783982 * @param array $query 検索クエリー
1784- * @return Result
983+ * @return Result 結果。data['data']:results、total
1785984 */
1786985 public function listContacts(array $query = []): Result {
1787- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1788- $cacheName = 'listcontacts';
1789- $cache = $this->cache->get($cacheName);
1790- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1791-
1792- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1793- $uri = '/contacts?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1794- $curl = $this->setupCurl($uri);
1795- $res = $this->curlResult($curl);
1796- if (isset($res->data['data'])) {
1797- $res->data['query'] = $query;
1798- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1799- return Result::Success('', $res->data);
1800- }
1801-
1802- return Result::Error('連絡先一覧の受け取りに失敗。');
986+ return $this->get('連絡先一覧の受け取り', '/contacts', $query, 'contact-list');
1803987 }
1804988
1805989 /**
1806990 * 連絡先の作成
1807- * @todo テスト
1808991 *
1809- * @param array $payload
1810- * @return Result
992+ * @param array $payload name、email、phone、address、role、username、password等
993+ * @return Result 結果。data['data']:id
1811994 */
1812995 public function createContact(array $payload): Result {
1813- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1814-
1815- $uri = '/contacts';
1816- $curl = $this->setupCurl($uri, 'POST', $payload);
1817- $res = $this->curlResult($curl);
1818- // 以前はisset($res)で、失敗しても成功を返していた
1819- if ($res->isSuccess) {
1820- $this->cache->murder('listcontacts');
1821- return Result::Success('', $res->data);
1822- }
1823-
1824- return Result::Error("連絡先の作成に失敗。");
996+ return $this->send('連絡先の追加', 'POST', '/contacts', $payload, [], ['contact-']);
1825997 }
1826998
1827999 /**
18281000 * 連絡先の表示
1829- * @todo テスト
18301001 *
18311002 * @param int $id 連絡先ID
1832- * @param bool $withAdditionalData 詳細データ含むか?
1833- * @return Result
1003+ * @param bool $withAdditionalData 追加データも受け取る
1004+ * @return Result 結果。data['data']:連絡先
18341005 */
18351006 public function getContact(int $id, bool $withAdditionalData = false): Result {
1836- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1837- $cacheName = "getcontact-{$id}";
1838- $cache = $this->cache->get($cacheName);
1839- if ($this->cache->resurrect($cache, $id, 'id')) return Result::Success('', $cache);
1840-
1841- $query = [ 'with_additional_data' => $withAdditionalData ? 'true' : 'false' ];
1842- $uri = "/contacts/{$id}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1843- // kys($uri);
1844- $curl = $this->setupCurl($uri);
1845- $res = $this->curlResult($curl);
1846- if (isset($res->data['data'])) {
1847- $res->data['id'] = $id;
1848- $this->cache->set($cacheName, $res->data);
1849- return Result::Success('', $res->data);
1850- }
1851-
1852- return Result::Error('連絡先の受け取りに失敗。');
1007+ return $this->get('連絡先の受け取り', "/contacts/{$id}", ['with_additional_data' => $withAdditionalData], "contact-{$id}");
18531008 }
18541009
18551010 /**
18561011 * 連絡先の更新
1857- * @todo テスト
18581012 *
18591013 * @param int $id 連絡先ID
1860- * @param array $payload フォームデータ
1861- * @return Result
1014+ * @param array $payload 更新する項目
1015+ * @return Result 結果
18621016 */
18631017 public function updateContact(int $id, array $payload = []): Result {
1864- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1865-
1866- $uri = "/contacts/{$id}";
1867- $curl = $this->setupCurl($uri, 'PUT', $payload);
1868- $res = $this->curlResult($curl);
1869- if (isset($res->data['data'])) {
1870- $this->cache->murder("getcontact-{$id}");
1871- $this->cache->murder('listcontacts');
1872- if ($res->data['data']['success']) return Result::Success('連絡先の更新に成功。', $res->data);
1873- }
1874-
1875- return Result::Error('連絡先の更新に失敗。');
1018+ return $this->send('連絡先の更新', 'PUT', "/contacts/{$id}", ['id' => $id] + $payload, [], ['contact-']);
18761019 }
18771020
18781021 /**
18791022 * 連絡先の削除
1880- * @todo テスト
18811023 *
18821024 * @param int $id 連絡先ID
1883- * @return Result
1025+ * @return Result 結果
18841026 */
18851027 public function deleteContact(int $id): Result {
1886- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1028+ return $this->send('連絡先の削除', 'DELETE', "/contacts/{$id}", null, [], ['contact-']);
1029+ }
18871030
1888- $uri = "/contacts/{$id}";
1889- $curl = $this->setupCurl($uri, 'DELETE');
1890- $res = $this->curlResult($curl);
1891- if (isset($res->data['data'])) {
1892- $this->cache->murder("getcontact-{$id}");
1893- $this->cache->murder('listcontacts');
1894- if ($res->data['data']['success']) return Result::Success('連絡先の削除に成功。');
1895- }
1031+ /**
1032+ * 連絡先の通知の設定(ログイン中の連絡先)
1033+ *
1034+ * @return Result 結果。data['data']:operational_notification、marketing_promotion等
1035+ */
1036+ public function getContactNotificationSetting(): Result {
1037+ return $this->get('通知の設定の受け取り', '/contact/notification-setting', [], 'contact-notification');
1038+ }
18961039
1897- return Result::Error('連絡先の削除に失敗。');
1040+ /**
1041+ * 連絡先の通知の設定の更新
1042+ *
1043+ * @param array $payload educational_content、marketing_promotion、operational_notification、platform_update_news(真偽値)
1044+ * @return Result 結果
1045+ */
1046+ public function updateContactNotificationSetting(array $payload): Result {
1047+ return $this->send('通知の設定の更新', 'POST', '/contact/notification-setting', $payload, [], ['contact-notification']);
18981048 }
18991049
19001050 //// 顧客様
19011051
19021052 /**
1903- * 顧客様の一覧
1053+ * 顧客様一覧
19041054 *
19051055 * @param array $query 検索クエリー
1906- * @return Result
1056+ * @return Result 結果。data['data']:results、total
19071057 */
19081058 public function listCustomers(array $query = []): Result {
1909- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1910- $cacheName = 'listcustomers';
1911- $cache = $this->cache->get($cacheName);
1912- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
1913-
1914- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
1915- $uri = '/customers?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1916- $curl = $this->setupCurl($uri);
1917- $res = $this->curlResult($curl);
1918- if (isset($res->data['data'])) {
1919- $res->data['query'] = $query;
1920- $this->cache->set($cacheName, $res->data + ['query' => $query]);
1921- return Result::Success('', $res->data);
1922- }
1923-
1924- return Result::Error('顧客様一覧の受け取りに失敗。');
1059+ return $this->get('顧客様一覧の受け取り', '/customers', $query, 'customer-list');
19251060 }
19261061
19271062 /**
19281063 * 顧客様の作成
19291064 *
1930- * @param array $payload
1931- * @return Result
1065+ * @param array $payload name、email、phone、address、company_name等
1066+ * @return Result 結果。data['data']:handle
19321067 */
19331068 public function createCustomer(array $payload): Result {
1934- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1935-
1936- $uri = '/customers';
1937- $curl = $this->setupCurl($uri, 'POST', $payload);
1938- $res = $this->curlResult($curl);
1939- // 以前はisset($res)で、失敗しても成功を返していた
1940- if ($res->isSuccess) {
1941- $this->cache->murder('listcustomers');
1942- return Result::Success('', $res->data);
1943- }
1944-
1945- return Result::Error("顧客様の作成に失敗。");
1069+ return $this->send('顧客様の追加', 'POST', '/customers', $payload, [], ['customer-']);
19461070 }
19471071
19481072 /**
19491073 * 顧客様の表示
19501074 *
1951- * @param string $handle ハンドル
1952- * @param bool $withAdditionalData 詳細データ含むか?
1953- * @return Result
1075+ * @param string $handle 顧客様のハンドル
1076+ * @param bool $withAdditionalData 追加データも受け取る
1077+ * @return Result 結果。data['data']:顧客様
19541078 */
19551079 public function getCustomer(string $handle, bool $withAdditionalData = false): Result {
1956- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1957- $cacheName = "getcustomer-{$handle}";
1958- $cache = $this->cache->get($cacheName);
1959- if ($this->cache->resurrect($cache, $handle, 'handle')) return Result::Success('', $cache);
1960-
1961- $query = [ 'with_additional_data' => $withAdditionalData ? 'true' : 'false' ];
1962- $uri = "/customers/{$handle}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
1963- // kys($uri);
1964- $curl = $this->setupCurl($uri);
1965- $res = $this->curlResult($curl);
1966- if (isset($res->data['data'])) {
1967- $res->data['handle'] = $handle;
1968- $this->cache->set($cacheName, $res->data);
1969- return Result::Success('', $res->data);
1970- }
1971-
1972- return Result::Error('顧客様の受け取りに失敗。');
1080+ return $this->get('顧客様の受け取り', '/customers/'.self::seg($handle), ['with_additional_data' => $withAdditionalData], 'customer-'.self::cacheKey($handle));
19731081 }
19741082
19751083 /**
19761084 * 顧客様の更新
1977- * @todo テスト
19781085 *
19791086 * @param string $handle 顧客様のハンドル
1980- * @param array $payload フォームデータ
1981- * @return Result
1087+ * @param array $payload 更新する項目
1088+ * @return Result 結果
19821089 */
19831090 public function updateCustomer(string $handle, array $payload = []): Result {
1984- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
1985-
1986- $uri = "/customers/{$handle}";
1987- $curl = $this->setupCurl($uri, 'PUT', $payload);
1988- $res = $this->curlResult($curl);
1989- if (isset($res->data['data'])) {
1990- $this->cache->murder('listcustomers');
1991- $this->cache->murder("getcustomer-{$handle}");
1992- if ($res->data['data']['success']) return Result::Success('顧客様の更新に成功。', $res->data);
1993- }
1994-
1995- return Result::Error('顧客様の更新に失敗。');
1091+ return $this->send('顧客様の更新', 'PUT', '/customers/'.self::seg($handle), ['handle' => $handle] + $payload, [], ['customer-']);
19961092 }
19971093
19981094 /**
19991095 * 顧客様の削除
20001096 *
20011097 * @param string $handle 顧客様のハンドル
2002- * @return Result
1098+ * @return Result 結果
20031099 */
20041100 public function deleteCustomer(string $handle): Result {
2005- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2006-
2007- $uri = "/customers/{$handle}";
2008- $curl = $this->setupCurl($uri, 'DELETE');
2009- $res = $this->curlResult($curl);
2010- if (isset($res->data['data'])) {
2011- $this->cache->murder('listcustomers');
2012- $this->cache->murder("getcustomer-{$handle}");
2013- if ($res->data['data']['success']) return Result::Success('顧客様の削除に成功。');
2014- }
2015-
2016- return Result::Error('顧客様の削除に失敗。');
1101+ return $this->send('顧客様の削除', 'DELETE', '/customers/'.self::seg($handle), null, [], ['customer-']);
20171102 }
20181103
20191104 //// メール認証
20201105
20211106 /**
2022- * メール認証一覧
2023- * @todo テスト
1107+ * ドメインのメール認証一覧
20241108 *
2025- * @param array $query 検索クエリー
2026- * @return Result
1109+ * @param array $query 検索クエリー(domain、email、handle、status等)
1110+ * @return Result 結果。data['data']:results、total
20271111 */
20281112 public function listEmailVerifications(array $query = []): Result {
2029- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2030- $cacheName = 'listemailverifications';
2031- $cache = $this->cache->get($cacheName);
2032- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2033-
2034- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
2035- $uri = '/customers/verifications/emails/domains?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2036- $curl = $this->setupCurl($uri);
2037- $res = $this->curlResult($curl);
2038- if (isset($res->data['data'])) {
2039- $res->data['query'] = $query;
2040- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2041- return Result::Success('', $res->data);
2042- }
2043-
2044- return Result::Error('メール認証一覧の受け取りに失敗。');
1113+ return $this->get('メール認証一覧の受け取り', '/customers/verifications/emails/domains', $query, 'verification-list');
20451114 }
20461115
20471116 /**
2048- * メール認証の再起動
2049- * @todo テスト
1117+ * メール認証の再送信
20501118 *
20511119 * @param string $email メールアドレス
2052- * @return Result
1120+ * @param string $language 言語(省略可)
1121+ * @param string $tag タグ(省略可)
1122+ * @return Result 結果
20531123 */
20541124 public function restartEmailVerifications(string $email, string $language = '', string $tag = ''): Result {
2055- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2056-
2057- $uri = '/customers/verifications/emails/restart';
2058- $curl = $this->setupCurl($uri, 'POST', ['email' => $email, 'language' => $language, 'tag' => $tag]);
2059- $res = $this->curlResult($curl);
2060- if (isset($res->data['data'])) {
2061- $this->cache->murder('listemailverifications');
2062- return Result::Success('メール認証の再起動に成功。', $res->data);
2063- }
2064-
2065- return Result::Error('メール認証の再起動に失敗。');
1125+ // 以前は空の項目も送っていた
1126+ $payload = array_filter(['email' => $email, 'language' => $language, 'tag' => $tag], fn($v) => $v !== '');
1127+ return $this->send('メール認証の再送信', 'POST', '/customers/verifications/emails/restart', $payload, [], ['verification-']);
20661128 }
20671129
20681130 /**
2069- * メール認証の起動
2070- * @todo テスト
1131+ * メール認証の開始
20711132 *
20721133 * @param string $email メールアドレス
2073- * @param string $handle 顧客様のハンドル
2074- * @param string $language 言語
2075- * @param string $tag タグ
2076- * @return Result
1134+ * @param string $handle 顧客様のハンドル(省略可)
1135+ * @param string $language 言語(省略可)
1136+ * @param string $tag タグ(省略可)
1137+ * @return Result 結果。data['data']:id
20771138 */
20781139 public function startEmailVerifications(string $email, string $handle = '', string $language = '', string $tag = ''): Result {
2079- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2080-
2081- $uri = '/customers/verifications/emails/start';
2082- $curl = $this->setupCurl($uri, 'POST', ['email' => $email, 'handle' => $handle, 'language' => $language, 'tag' => $tag]);
2083- $res = $this->curlResult($curl);
2084- if (isset($res->data['data'])) {
2085- $this->cache->murder('listemailverifications');
2086- return Result::Success('メール認証の起動に成功。', $res->data);
2087- }
2088-
2089- return Result::Error('メール認証の起動に失敗。');
1140+ $payload = array_filter(['email' => $email, 'handle' => $handle, 'language' => $language, 'tag' => $tag], fn($v) => $v !== '');
1141+ return $this->send('メール認証の開始', 'POST', '/customers/verifications/emails/start', $payload, [], ['verification-']);
20901142 }
20911143
20921144 //// リセラー
20931145
20941146 /**
2095- * リセラーの受け取り
1147+ * リセラー(自分)の表示
20961148 *
2097- * @param array $query 検索クエリー
2098- * @return Result
1149+ * @param array $query with_statistics、with_settings、with_contacts、with_additional_data
1150+ * @return Result 結果。data['data']:リセラー(balance等)
20991151 */
21001152 public function getReseller(array $query = []): Result {
2101- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2102- $cacheName = 'getreseller';
2103- $cache = $this->cache->get($cacheName);
2104- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2105-
2106- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
2107- $uri = '/resellers?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2108- $curl = $this->setupCurl($uri);
2109- $res = $this->curlResult($curl);
2110- if (isset($res->data['data'])) {
2111- $res->data['query'] = $query;
2112- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2113- return Result::Success('', $res->data);
2114- }
2115-
2116- return Result::Error('リセラーの受け取りに失敗。');
1153+ return $this->get('リセラーの受け取り', '/resellers', $query, 'reseller');
21171154 }
21181155
21191156 /**
21201157 * リセラーの更新
2121- * @todo テスト
21221158 *
2123- * @param int $id リセラーID
2124- * @param array $payload フォームデータ
2125- * @return Result
1159+ * @param int $id リセラーID(getResellerId())
1160+ * @param array $payload 更新する項目
1161+ * @return Result 結果
21261162 */
21271163 public function updateReseller(int $id, array $payload = []): Result {
2128- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2129-
2130- $uri = "/resellers/{$id}";
2131- $curl = $this->setupCurl($uri, 'PUT', $payload);
2132- $res = $this->curlResult($curl);
2133- if (isset($res->data['data'])) {
2134- $this->cache->murder('getreseller');
2135- if ($res->data['data']['success']) return Result::Success('リセラーの更新に成功。', $res->data);
2136- }
2137-
2138- return Result::Error('リセラーの更新に失敗。');
1164+ return $this->send('リセラーの更新', 'PUT', "/resellers/{$id}", ['id' => $id] + $payload, [], ['reseller']);
21391165 }
21401166
21411167 //// 設定
21421168
21431169 /**
2144- * 設定の受け取り
2145- * @todo テスト
1170+ * リセラーの設定
21461171 *
2147- * @return Result
1172+ * @return Result 結果。data['data']:設定
21481173 */
21491174 public function listSettings(): Result {
2150- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2151- $cacheName = 'listsettings';
2152- $cache = $this->cache->get($cacheName);
2153- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
2154-
2155- $uri = '/resellers/settings';
2156- $curl = $this->setupCurl($uri);
2157- $res = $this->curlResult($curl);
2158- if (isset($res->data['data'])) {
2159- $res->data['query'] = $query;
2160- $this->cache->set($cacheName, $res->data);
2161- return Result::Success('', $res->data);
2162- }
2163-
2164- return Result::Error('設定の受け取りに失敗。');
1175+ return $this->get('設定の受け取り', '/resellers/settings', [], 'reseller-settings');
21651176 }
21661177
21671178 //// 統計
21681179
21691180 /**
2170- * 統計の受け取り
1181+ * リセラーの統計
21711182 *
2172- * @return Result
1183+ * @return Result 結果。data['data']:domain、dns、ssl等の統計
21731184 */
2174- public function listStatistics(array $query = []): Result {
2175- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2176- $cacheName = 'liststatistics';
2177- $cache = $this->cache->get($cacheName);
2178- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2179-
2180- $uri = '/resellers/statistics';
2181- $curl = $this->setupCurl($uri);
2182- $res = $this->curlResult($curl);
2183- if (isset($res->data['data'])) {
2184- $res->data['query'] = $query;
2185- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2186- return Result::Success('', $res->data);
2187- }
2188-
2189- return Result::Error('統計の受け取りに失敗。');
1185+ public function listStatistics(): Result {
1186+ return $this->get('統計の受け取り', '/resellers/statistics', [], 'reseller-statistics');
21901187 }
21911188
21921189 //// タグ
21931190
21941191 /**
21951192 * タグ一覧
2196- * @todo テスト
21971193 *
2198- * @param array $query 検索クエリー
2199- * @return Result
1194+ * @param array $query key、value
1195+ * @return Result 結果。data['data']:results、total
22001196 */
22011197 public function listTags(array $query = []): Result {
2202- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2203- $cacheName = 'listtags';
2204- $cache = $this->cache->get($cacheName);
2205- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2206-
2207- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
2208- $uri = '/tags?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2209- $curl = $this->setupCurl($uri);
2210- $res = $this->curlResult($curl);
2211- if (isset($res->data['data'])) {
2212- $res->data['query'] = $query;
2213- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2214- return Result::Success('', $res->data);
2215- }
2216-
2217- return Result::Error('タグ一覧の受け取りに失敗。');
1198+ return $this->get('タグ一覧の受け取り', '/tags', $query, 'tag-list');
22181199 }
22191200
22201201 /**
22211202 * タグの作成
2222- * @todo テスト
22231203 *
2224- * @param array $payload フォームデータ
2225- * @return Result
1204+ * @param array $payload key、value
1205+ * @return Result 結果
22261206 */
22271207 public function createTag(array $payload = []): Result {
2228- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2229-
2230- $uri = '/tags';
2231- $curl = $this->setupCurl($uri, 'POST', $payload);
2232- $res = $this->curlResult($curl);
2233- if (isset($res->data['data'])) {
2234- $this->cache->murder('listtags');
2235- return Result::Success('タグの追加に成功。', $res->data);
2236- }
2237-
2238- return Result::Error('タグの追加に失敗。');
1208+ return $this->send('タグの追加', 'POST', '/tags', $payload, [], ['tag-']);
22391209 }
22401210
22411211 /**
22421212 * タグの削除
2243- * @todo テスト
22441213 *
2245- * @param array $payload フォームデータ
2246- * @return Result
1214+ * @param array $query key、value(削除するタグ)
1215+ * @return Result 結果
22471216 */
2248- public function deleteTag(array $payload = []): Result {
2249- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2250-
2251- $uri = "/tags/{$id}";
2252- $curl = $this->setupCurl($uri, 'DELETE', $payload);
2253- $res = $this->curlResult($curl);
2254- if (isset($res->data['data'])) {
2255- $this->cache->murder('listtags');
2256- if ($res->data['data']['success']) return Result::Success('タグの削除に成功。', $res->data);
2257- }
2258-
2259- return Result::Error('タグの削除に失敗。');
1217+ public function deleteTag(array $query = []): Result {
1218+ // 以前は未定義の$idで「/tags/{id}」に送っていた(APIは「/tags?key=…&value=…」)
1219+ return $this->send('タグの削除', 'DELETE', '/tags', null, $query, ['tag-']);
22601220 }
22611221
22621222 // SpamExpert
22631223
1224+ /**
1225+ * SpamExpertの管理画面にログインするURL(使い捨てなのでキャッシュしない)
1226+ *
1227+ * @param array $payload domain_or_email、bundle
1228+ * @return Result 結果。data['data']:url
1229+ */
1230+ public function generateLoginUrlSpamExpert(array $payload = []): Result {
1231+ // 以前はURLが「/spam-expert-generate-login-url」で、メッセージがDNSテンプレートの物だった
1232+ return $this->send('SpamExpertのログインURLの作成', 'POST', '/spam-expert/generate-login-url', $payload);
1233+ }
1234+
22641235 //// SEDomain
22651236
22661237 /**
2267- * SEDomainの作成
2268- * @todo テスト
1238+ * SpamExpertにドメインを追加する
22691239 *
2270- * @param array $payload
2271- * @return Result
1240+ * @param array $payload domain_name、destinations、aliases、products、bundle
1241+ * @return Result 結果
22721242 */
22731243 public function createSeDomain(array $payload): Result {
2274- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2275-
2276- $uri = '/spam-expert/domains';
2277- $curl = $this->setupCurl($uri, 'POST', $payload);
2278- $res = $this->curlResult($curl);
2279- // 以前はisset($res)で、失敗しても成功を返していた
2280- if ($res->isSuccess) {
2281- $this->cache->murder('listdomains');
2282- return Result::Success('', $res->data);
2283- }
2284-
2285- return Result::Error("SEDomainの作成に失敗。");
1244+ return $this->send('SpamExpertのドメインの追加', 'POST', '/spam-expert/domains', $payload, [], ['spamexpert-']);
22861245 }
22871246
22881247 /**
2289- * SEDomainの表示
2290- * @todo テスト
1248+ * SpamExpertのドメインの表示
22911249 *
22921250 * @param string $domain ドメイン名
2293- * @param array $query 検索クエリー
2294- * @return Result
1251+ * @param array $query with_records、bundle
1252+ * @return Result 結果。data['data']:ドメイン
22951253 */
22961254 public function getSeDomain(string $domain, array $query = []): Result {
2297- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2298- $cacheName = "getsedomain-{$domain}";
2299- $cache = $this->cache->get($cacheName);
2300- if ($this->cache->resurrect($cache, $domain, 'domain')) return Result::Success('', $cache);
2301-
2302- $uri = "/spam-expert/domains/{$domain}?".http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2303- // kys($uri);
2304- $curl = $this->setupCurl($uri);
2305- $res = $this->curlResult($curl);
2306- if (isset($res->data['data'])) {
2307- $res->data['domain'] = $domain;
2308- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2309- return Result::Success('', $res->data);
2310- }
2311-
2312- return Result::Error('SEDomainの受け取りに失敗。');
1255+ return $this->get('SpamExpertのドメインの受け取り', '/spam-expert/domains/'.self::seg($domain), $query, 'spamexpert-'.self::cacheKey($domain));
23131256 }
23141257
23151258 /**
2316- * SEDomainの更新
2317- * @todo テスト
1259+ * SpamExpertのドメインの更新
23181260 *
23191261 * @param string $domain ドメイン名
2320- * @param array $payload フォームデータ
2321- * @return Result
1262+ * @param array $payload 更新する項目
1263+ * @return Result 結果
23221264 */
23231265 public function updateSeDomain(string $domain, array $payload = []): Result {
2324- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2325-
2326- $uri = "/spam-expert/domains/{$domain}";
2327- $curl = $this->setupCurl($uri, 'PUT', $payload);
2328- $res = $this->curlResult($curl);
2329- if (isset($res->data['data'])) {
2330- $this->cache->murder('listdomains');
2331- $this->cache->murder("getsedomain-{$domain}");
2332- if ($res->data['data']['success']) return Result::Success('SEDomainの更新に成功。', $res->data);
2333- }
2334-
2335- return Result::Error('SEDomainの更新に失敗。');
1266+ return $this->send('SpamExpertのドメインの更新', 'PUT', '/spam-expert/domains/'.self::seg($domain), ['domain_name' => $domain] + $payload, [], ['spamexpert-']);
23361267 }
23371268
23381269 /**
2339- * SEDomainの削除
2340- * @todo テスト
1270+ * SpamExpertのドメインの削除
23411271 *
23421272 * @param string $domain ドメイン名
2343- * @return Result
1273+ * @param array $query bundle
1274+ * @return Result 結果
23441275 */
2345- public function deleteSeDomain(string $domain): Result {
2346- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2347-
2348- $uri = "/spam-expert/domains/{$domain}";
2349- $curl = $this->setupCurl($uri, 'DELETE');
2350- $res = $this->curlResult($curl);
2351- if (isset($res->data['data'])) {
2352- $this->cache->murder('listdomains');
2353- $this->cache->murder("getsedomain-{$domain}");
2354- if ($res->data['data']['success']) return Result::Success('SEDomainの削除に成功。');
2355- }
2356-
2357- return Result::Error('SEDomainの削除に失敗。');
1276+ public function deleteSeDomain(string $domain, array $query = []): Result {
1277+ return $this->send('SpamExpertのドメインの削除', 'DELETE', '/spam-expert/domains/'.self::seg($domain), null, $query, ['spamexpert-']);
23581278 }
23591279
23601280 // SSL証明書
@@ -2362,366 +1282,169 @@
23621282 //// 確認担当者メール
23631283
23641284 /**
2365- * 確認担当者メール一覧
2366- * @todo テスト
1285+ * 確認担当者のメールアドレス一覧(ドメインの所有を確認するメールの宛先)
23671286 *
2368- * @param array $query 検索クエリー
2369- * @return Result
1287+ * @param array $query product_id、domain
1288+ * @return Result 結果。data['data']['results']:メールアドレス
23701289 */
23711290 public function listApproverEmails(array $query = []): Result {
2372- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2373- $cacheName = 'listapproveremails';
2374- $cache = $this->cache->get($cacheName);
2375- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2376-
2377- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
2378- $uri = '/ssl/approver-emails?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2379- $curl = $this->setupCurl($uri);
2380- $res = $this->curlResult($curl);
2381- if (isset($res->data['data'])) {
2382- $res->data['query'] = $query;
2383- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2384- return Result::Success('', $res->data);
2385- }
2386-
2387- return Result::Error('確認担当者メール一覧の受け取りに失敗。');
1291+ return $this->get('確認担当者メール一覧の受け取り', '/ssl/approver-emails', $query, 'ssl-approver-'.self::cacheKey($query));
23881292 }
23891293
23901294 //// CSR
23911295
23921296 /**
2393- * 注文確認担当者メールの再送信
2394- * @todo テスト
1297+ * CSRと秘密鍵の作成
23951298 *
2396- * @param array $payload
2397- * @return Result
1299+ * @param array $payload common_name、country、organization、email、bits、subject_alternative_name等
1300+ * @return Result 結果。data['data']:csr、key等
23981301 */
23991302 public function createCsr(array $payload): Result {
2400- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2401-
2402- $uri = '/ssl/csr';
2403- $curl = $this->setupCurl($uri, 'POST', $payload);
2404- $res = $this->curlResult($curl);
2405- // 以前はisset($res)で、失敗しても成功を返していた
2406- if ($res->isSuccess) {
2407- return Result::Success('', $res->data);
2408- }
2409-
2410- return Result::Error("注文確認担当者メールの再送信に失敗。");
1303+ // 以前はメッセージが確認担当者メールの物だった
1304+ return $this->send('CSRの作成', 'POST', '/ssl/csr', $payload);
24111305 }
24121306
24131307 /**
2414- * 注文確認担当者メールの再送信
2415- * @todo テスト
1308+ * CSRの解析
24161309 *
2417- * @param string $csr
2418- * @return Result
1310+ * @param string $csr CSR(PEM)
1311+ * @return Result 結果。data['data']:subject、subject_alternative_name等
24191312 */
24201313 public function decodeCsr(string $csr): Result {
2421- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2422-
2423- $uri = '/ssl/csr/decode';
2424- $curl = $this->setupCurl($uri, 'POST', ['csr' => $csr]);
2425- $res = $this->curlResult($curl);
2426- // 以前はisset($res)で、失敗しても成功を返していた
2427- if ($res->isSuccess) {
2428- return Result::Success('', $res->data);
2429- }
2430-
2431- return Result::Error("注文確認担当者メールの再送信に失敗。");
1314+ return $this->send('CSRの解析', 'POST', '/ssl/csr/decode', ['csr' => $csr]);
24321315 }
24331316
24341317 //// 注文
24351318
24361319 /**
2437- * 連絡先の一覧
2438- * @todo テスト
1320+ * SSL証明書の注文一覧
24391321 *
2440- * @param array $query 検索クエリー
2441- * @return Result
1322+ * @param array $query 検索クエリー(status、common_name_pattern等)
1323+ * @return Result 結果。data['data']:results、total
24421324 */
24431325 public function listSslOrders(array $query = []): Result {
2444- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2445- $cacheName = 'listsslorders';
2446- $cache = $this->cache->get($cacheName);
2447- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2448-
2449- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
2450- $uri = '/ssl/orders?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2451- $curl = $this->setupCurl($uri);
2452- $res = $this->curlResult($curl);
2453- if (isset($res->data['data'])) {
2454- $res->data['query'] = $query;
2455- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2456- return Result::Success('連絡先一覧の受け取りに成功。', $res->data);
2457- }
2458-
2459- return Result::Error('連絡先一覧の受け取りに失敗。');
1326+ return $this->get('SSL証明書の注文一覧の受け取り', '/ssl/orders', $query, 'ssl-order-list');
24601327 }
24611328
24621329 /**
2463- * SSL注文の作成
2464- * @todo テスト
1330+ * SSL証明書の注文
24651331 *
2466- * @param array $payload
2467- * @return Result
1332+ * @param array $payload product_id、period、csr、host_names、approver_email、organization_handle、technical_handle等
1333+ * @return Result 結果。data['data']:id
24681334 */
24691335 public function createSslOrder(array $payload): Result {
2470- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2471-
2472- $uri = '/ssl/orders';
2473- $curl = $this->setupCurl($uri, 'POST', $payload);
2474- $res = $this->curlResult($curl);
2475- // 以前はisset($res)で、失敗しても成功を返していた
2476- if ($res->isSuccess) {
2477- $this->cache->murder('listsslorders');
2478- return Result::Success('SSL注文の作成に成功。', $res->data);
2479- }
2480-
2481- return Result::Error("SSL注文の作成に失敗。");
1336+ return $this->send('SSL証明書の注文', 'POST', '/ssl/orders', $payload, [], ['ssl-order-']);
24821337 }
24831338
24841339 /**
2485- * SSL注文の表示
2486- * @todo テスト
1340+ * SSL証明書の注文の表示
24871341 *
2488- * @param int $id SSL注文ID
2489- * @return Result
1342+ * @param int $id 注文ID
1343+ * @return Result 結果。data['data']:注文(certificate、status等)
24901344 */
24911345 public function getSslOrder(int $id): Result {
2492- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2493- $cacheName = "getsslorder-{$id}";
2494- $cache = $this->cache->get($cacheName);
2495- if ($this->cache->resurrect($cache)) return Result::Success('', $cache);
2496-
2497- $uri = "/ssl/orders/{$id}";
2498- // kys($uri);
2499- $curl = $this->setupCurl($uri);
2500- $res = $this->curlResult($curl);
2501- if (isset($res->data['data'])) {
2502- $res->data['id'] = $id;
2503- $this->cache->set($cacheName, $res->data);
2504- return Result::Success('SSL注文の受け取りに成功。', $res->data);
2505- }
2506-
2507- return Result::Error('SSL注文の受け取りに失敗。');
1346+ return $this->get('SSL証明書の注文の受け取り', "/ssl/orders/{$id}", [], "ssl-order-{$id}");
25081347 }
25091348
25101349 /**
2511- * SSL注文の更新
2512- * @todo テスト
1350+ * SSL証明書の注文の更新
25131351 *
2514- * @param int $id SSL注文ID
2515- * @param array $payload フォームデータ
2516- * @return Result
1352+ * @param int $id 注文ID
1353+ * @param array $payload 更新する項目
1354+ * @return Result 結果。data['data']:id
25171355 */
25181356 public function updateSslOrder(int $id, array $payload = []): Result {
2519- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2520-
2521- $uri = "/ssl/orders/{$id}";
2522- $curl = $this->setupCurl($uri, 'PUT', $payload);
2523- $res = $this->curlResult($curl);
2524- if (isset($res->data['data'])) {
2525- $this->cache->murder("getsslorder-{$id}");
2526- $this->cache->murder('listsslorders');
2527- if ($res->data['data']['success']) return Result::Success('SSL注文の更新に成功。', $res->data);
2528- }
2529-
2530- return Result::Error('SSL注文の更新に失敗。');
1357+ return $this->send('SSL証明書の注文の更新', 'PUT', "/ssl/orders/{$id}", ['id' => $id] + $payload, [], ['ssl-order-']);
25311358 }
25321359
25331360 /**
2534- * SSL注文のキャンセル
2535- * @todo テスト
1361+ * SSL証明書の注文の取消
25361362 *
2537- * @param int $id SSL注文ID
2538- * @return Result
1363+ * @param int $id 注文ID
1364+ * @return Result 結果。data['data']:id
25391365 */
25401366 public function cancelSslOrder(int $id): Result {
2541- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2542-
2543- $payload = ['id' => $id];
2544- $uri = "/ssl/orders/{$id}/cancel";
2545- $curl = $this->setupCurl($uri, 'POST', $payload);
2546- $res = $this->curlResult($curl);
2547- // 以前はisset($res)で、失敗しても成功を返していた
2548- if ($res->isSuccess) {
2549- $this->cache->murder("getsslorder-{$id}");
2550- $this->cache->murder('listsslorders');
2551- return Result::Success('SSL注文のキャンセルに成功。', $res->data);
2552- }
2553-
2554- return Result::Error("SSL注文のキャンセルに失敗。");
1367+ return $this->send('SSL証明書の注文の取消', 'POST', "/ssl/orders/{$id}/cancel", ['id' => $id], [], ['ssl-order-']);
25551368 }
25561369
25571370 /**
2558- * SSL注文の再発行
2559- * @todo テスト
1371+ * SSL証明書の再発行
25601372 *
2561- * @param int $id SSL注文ID
2562- * @param array $payload フォームデータ
2563- * @return Result
1373+ * @param int $id 注文ID
1374+ * @param array $payload csr、host_names、approver_email等
1375+ * @return Result 結果。data['data']:id
25641376 */
25651377 public function reissueSslOrder(int $id, array $payload = []): Result {
2566- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2567-
2568- $uri = "/ssl/orders/{$id}/reissue";
2569- $curl = $this->setupCurl($uri, 'POST', $payload);
2570- $res = $this->curlResult($curl);
2571- // 以前はisset($res)で、失敗しても成功を返していた
2572- if ($res->isSuccess) {
2573- $this->cache->murder("getsslorder-{$id}");
2574- $this->cache->murder('listsslorders');
2575- return Result::Success('SSL注文の再発行に成功。', $res->data);
2576- }
2577-
2578- return Result::Error("SSL注文の再発行に失敗。");
1378+ return $this->send('SSL証明書の再発行', 'POST', "/ssl/orders/{$id}/reissue", ['id' => $id] + $payload, [], ['ssl-order-']);
25791379 }
25801380
25811381 /**
2582- * SSL注文の更新
2583- * @todo テスト
1382+ * SSL証明書の更新(期間の延長)
25841383 *
2585- * @param int $id SSL注文ID
2586- * @param array $payload フォームデータ
2587- * @return Result
1384+ * @param int $id 注文ID
1385+ * @param array $payload enable_dns_automation
1386+ * @return Result 結果。data['data']:id
25881387 */
25891388 public function renewSslOrder(int $id, array $payload = []): Result {
2590- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2591-
2592- $uri = "/ssl/orders/{$id}/renew";
2593- $curl = $this->setupCurl($uri, 'POST', $payload);
2594- $res = $this->curlResult($curl);
2595- // 以前はisset($res)で、失敗しても成功を返していた
2596- if ($res->isSuccess) {
2597- $this->cache->murder("getsslorder-{$id}");
2598- $this->cache->murder('listsslorders');
2599- return Result::Success('SSL注文の更新に成功。', $res->data);
2600- }
2601-
2602- return Result::Error("SSL注文の更新に失敗。");
1389+ return $this->send('SSL証明書の更新', 'POST', "/ssl/orders/{$id}/renew", ['id' => $id] + $payload, [], ['ssl-order-']);
26031390 }
26041391
26051392 //// 注文確認担当者メール
26061393
26071394 /**
2608- * 注文確認担当者メールの更新
2609- * @todo テスト
1395+ * 注文の確認担当者のメールアドレスの変更
26101396 *
2611- * @param int $id
2612- * @param string $approverEmail
2613- * @return Result
1397+ * @param int $id 注文ID
1398+ * @param string $approverEmail メールアドレス
1399+ * @return Result 結果。data['data']:id
26141400 */
26151401 public function updateSslApproverEmail(int $id, string $approverEmail): Result {
2616- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2617-
2618- $uri = "/ssl/orders/{$id}/approver-email";
2619- $curl = $this->setupCurl($uri, 'PUT', ['id' => $id, 'approver_email' => $approverEmail]);
2620- $res = $this->curlResult($curl);
2621- // 以前はisset($res)で、失敗しても成功を返していた
2622- if ($res->isSuccess) {
2623- $this->cache->murder('listapproveremails');
2624- return Result::Success('', $res->data);
2625- }
2626-
2627- return Result::Error("注文確認担当者メールの更新に失敗。");
1402+ return $this->send('確認担当者メールの変更', 'PUT', "/ssl/orders/{$id}/approver-email", ['id' => $id, 'approver_email' => $approverEmail], [], ["ssl-order-{$id}"]);
26281403 }
26291404
26301405 /**
2631- * 注文確認担当者メールの再送信
2632- * @todo テスト
1406+ * 確認担当者メールの再送信
26331407 *
2634- * @param int $id
2635- * @return Result
1408+ * @param int $id 注文ID
1409+ * @return Result 結果。data['data']:id
26361410 */
26371411 public function resendSslApproverEmail(int $id): Result {
2638- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2639-
2640- $uri = "/ssl/orders/{$id}/approver-email/resend";
2641- $curl = $this->setupCurl($uri, 'POST', ['id' => $id]);
2642- $res = $this->curlResult($curl);
2643- // 以前はisset($res)で、失敗しても成功を返していた
2644- if ($res->isSuccess) {
2645- $this->cache->murder('listapproveremails');
2646- return Result::Success('', $res->data);
2647- }
2648-
2649- return Result::Error("注文確認担当者メールの再送信に失敗。");
1412+ return $this->send('確認担当者メールの再送信', 'POST', "/ssl/orders/{$id}/approver-email/resend", ['id' => $id]);
26501413 }
26511414
26521415 //// OTPトークン
26531416
26541417 /**
2655- * OTPトークンの作成
2656- * @todo テスト
1418+ * SSL証明書の管理画面に入るOTPトークンの作成
26571419 *
2658- * @param int $id
2659- * @return Result
1420+ * @param int $id 注文ID
1421+ * @return Result 結果。data['data']:token、uri、expire_at
26601422 */
26611423 public function createSslOtpToken(int $id): Result {
2662- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2663-
2664- $uri = "/ssl/orders/{$id}/otp-tokens";
2665- $curl = $this->setupCurl($uri, 'POST');
2666- $res = $this->curlResult($curl);
2667- // 以前はisset($res)で、失敗しても成功を返していた
2668- if ($res->isSuccess) {
2669- return Result::Success('', $res->data);
2670- }
2671-
2672- return Result::Error("OTPトークンの作成に失敗。");
1424+ return $this->send('OTPトークンの作成', 'POST', "/ssl/orders/{$id}/otp-tokens", ['id' => $id]);
26731425 }
26741426
26751427 //// 商品
26761428
26771429 /**
2678- * 商品一覧
2679- * @todo テスト
1430+ * SSL証明書の商品一覧
26801431 *
2681- * @param array $query 検索クエリー
2682- * @return Result
1432+ * @param array $query 検索クエリー(with_price、with_description等)
1433+ * @return Result 結果。data['data']:results、total
26831434 */
26841435 public function listSslProducts(array $query = []): Result {
2685- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2686- $cacheName = 'listsslproducts';
2687- $cache = $this->cache->get($cacheName);
2688- if ($this->cache->resurrect($cache, $query)) return Result::Success('', $cache);
2689-
2690- foreach ($query as $k => $v) { if (is_bool($v)) $query[$k] = $v ? 'true' : 'false'; }
2691- $uri = '/ssl/products?'.http_build_query($query, '', '&', PHP_QUERY_RFC3986);
2692- $curl = $this->setupCurl($uri);
2693- $res = $this->curlResult($curl);
2694- if (isset($res->data['data'])) {
2695- $res->data['query'] = $query;
2696- $this->cache->set($cacheName, $res->data + ['query' => $query]);
2697- return Result::Success('', $res->data);
2698- }
2699-
2700- return Result::Error('商品一覧の受け取りに失敗。');
1436+ return $this->get('SSL証明書の商品一覧の受け取り', '/ssl/products', $query, 'ssl-product-list');
27011437 }
27021438
27031439 /**
2704- * 商品の表示
2705- * @todo テスト
1440+ * SSL証明書の商品の表示
27061441 *
27071442 * @param int $id 商品ID
2708- * @return Result
1443+ * @return Result 結果。data['data']:商品
27091444 */
27101445 public function getSslProduct(int $id): Result {
2711- if (!OPENPROVIDER_ENABLED) return Result::Error('エラー:OpenProviderは無効です。');
2712- $cacheName = "getsslproduct-{$id}";
2713- $cache = $this->cache->get($cacheName);
2714- if ($this->cache->resurrect($cache, $id, 'id')) return Result::Success('', $cache);
2715- // kys($uri);
2716- $curl = $this->setupCurl($uri);
2717- $res = $this->curlResult($curl);
2718- if (isset($res->data['data'])) {
2719- $res->data['id'] = $id;
2720- $this->cache->set($cacheName, $res->data);
2721- return Result::Success('', $res->data);
2722- }
2723-
2724- return Result::Error('商品の受け取りに失敗。');
1446+ // 以前は未定義の$uriを使っていた
1447+ return $this->get('SSL証明書の商品の受け取り', "/ssl/products/{$id}", [], "ssl-product-{$id}");
27251448 }
27261449
27271450 ////////
@@ -48,6 +48,9 @@
4848 fflush(STDOUT);
4949
5050 $count = [];
51+// テストが次のレスポンスを決められる(POST /__next)、最後のリクエストを確認出来る(GET /__last)
52+$next = null;
53+$last = null;
5154
5255 /** 生のHTTPレスポンス */
5356 function response(int $code, string $body, array $headers = []): string {
@@ -101,6 +104,20 @@
101104
102105 $bearer = ($headers['authorization'] ?? '') === 'Bearer tok123';
103106
107+ // テスト用の操作(記録しない)
108+ if ($path === '/__next') {
109+ $next = json_decode($body, true);
110+ @fwrite($c, json(200, ['ok' => true]));
111+ fclose($c);
112+ continue;
113+ }
114+ if ($path === '/__last') {
115+ @fwrite($c, json(200, $last ?? []));
116+ fclose($c);
117+ continue;
118+ }
119+ $last = ['method' => $method, 'path' => $path, 'query' => (string)parse_url($target, PHP_URL_QUERY), 'body' => $body];
120+
104121 $out = match (true) {
105122 // Curl用
106123 $path === '/echo' => json(200, $req),
@@ -123,6 +140,12 @@
123140 : json(401, ['code' => 196, 'desc' => 'Authentication/Authorization Failed']);
124141 })(),
125142 $path === '/bad/v1beta/auth/login' => json(401, ['code' => 196, 'desc' => 'Authentication/Authorization Failed']),
143+ // /__nextで決めたレスポンス(1回だけ)
144+ $next !== null && str_starts_with($path, '/v1beta/') && $bearer => (function() use (&$next) {
145+ $out = json((int)($next['status'] ?? 200), (array)($next['body'] ?? []));
146+ $next = null;
147+ return $out;
148+ })(),
126149 $path === '/v1beta/domains/check' && $bearer => (function() use ($body) {
127150 $in = json_decode($body, true);
128151 $results = [];
@@ -99,6 +99,19 @@
9999 $test->assertFalse($cache->murder('domainlist')->isSuccess);
100100 });
101101
102+ $test->it('名前の始まりでまとめて削除出来るはず', function($test) use ($base): void {
103+ $cache = new Cache('prefix', $base);
104+ foreach (['dnszone-list', 'dnszone-076.moe', 'dnsrecords-076.moe', 'login'] as $n) $cache->set($n, ['x' => 1]);
105+ $test->assertEquals(2, $cache->murderPrefix('dnszone-'));
106+ $test->assertEquals([], $cache->get('dnszone-list'));
107+ $test->assertEquals([], $cache->get('dnszone-076.moe'));
108+ $test->assertEquals(1, $cache->get('dnsrecords-076.moe')['x'] ?? null, '他の名前は残る');
109+ $test->assertEquals(1, $cache->get('login')['x'] ?? null);
110+ $test->assertEquals(0, $cache->murderPrefix(''), '空は何も消さない');
111+ $test->assertEquals(0, $cache->murderPrefix('../'));
112+ $test->assertEquals(1, $cache->get('login')['x'] ?? null);
113+ });
114+
102115 $test->it('ディレクトリの外のファイル名を拒否するはず', function($test) use ($base): void {
103116 $cache = new Cache('test', $base);
104117 foreach (['../x', '..', 'a/b', 'a\\b', '', str_repeat('a', 201)] as $bad) {
@@ -52,7 +52,7 @@
5252
5353 // 偽物のAPIサーバーに繋ぐOpenprovider(本物のキャッシュは使わない)
5454 $cacheName = 'lbtest_op_'.bin2hex(random_bytes(4));
55-$make = fn(string $baseUrl) => new class($baseUrl, $cacheName) extends Openprovider {
55+$make = fn(string $baseUrl, ?string $cacheDir = null) => new class($baseUrl, $cacheDir ?? $cacheName) extends Openprovider {
5656 public function __construct(string $baseUrl, string $cacheDir) {
5757 $this->BASEURL = $baseUrl;
5858 $this->cacheDir = $cacheDir;
@@ -175,6 +175,278 @@
175175 });
176176
177177 $srv?->stop();
178+});
179+
180+$test->describe('Openprovider(全部のAPI)', function($test) use ($make, $cacheName): void {
181+ if (!OPENPROVIDER_ENABLED) {
182+ $test->skipAll('OPENPROVIDER_ENABLEDが無効');
183+ }
184+ $srv = OPENPROVIDER_ENABLED ? MockServer::start('http-server.php') : null;
185+ if (OPENPROVIDER_ENABLED && $srv === null) {
186+ $test->skipAll('偽物のサーバーを起動出来ない(proc_openが無効?)');
187+ }
188+ $base = $srv ? $srv->url('/v1beta') : '';
189+ $ctl = function(string $path, ?array $body = null) use ($srv): array {
190+ $c = (new Curl($srv->url($path)))->setBlockPrivateAddresses(false)->setTimeout(5);
191+ if ($body !== null) $c->setMethod('POST')->setPostRaw(json_encode($body));
192+ $c->execute();
193+ return (array)json_decode($c->getResponseBody(), true);
194+ };
195+ // 次のレスポンスを決める
196+ $respond = fn(array $data, int $status = 200, int $code = 0, string $desc = '') => $ctl('/__next', ['status' => $status, 'body' => ['code' => $code, 'desc' => $desc, 'data' => $data]]);
197+ // 配列のキーを並べ替える(JSONの順番に関係なく比べる為)
198+ $sorted = function(mixed $v) use (&$sorted): mixed {
199+ if (!is_array($v)) return $v;
200+ if (!array_is_list($v)) ksort($v);
201+ return array_map($sorted, $v);
202+ };
203+ $quiet = function(callable $fn) {
204+ $old = ini_get('zend.assertions');
205+ if ($old !== '-1') ini_set('zend.assertions', '0');
206+ set_error_handler(fn(int $no, string $msg) => $no === E_USER_WARNING && str_contains($msg, 'assert'));
207+ try {
208+ return $fn();
209+ } finally {
210+ restore_error_handler();
211+ if ($old !== '-1') ini_set('zend.assertions', $old);
212+ }
213+ };
214+ // テスト毎にキャッシュの無いOpenprovider(キャッシュでリクエストが省略されない様に)
215+ $n = 0;
216+ $fresh = function() use ($make, $base, $cacheName, &$n) {
217+ $op = $make($base, $cacheName.'_'.(++$n));
218+ $op->login();
219+ return $op;
220+ };
221+
222+ // [メソッド, 呼び出し, HTTPメソッド, パス, クエリー, 本文(GET・DELETEはnull)]
223+ $owner = (string)(OPENPROVIDER['owner_handle'] ?? '');
224+ $ns = [['name' => 'ns1.076.moe', 'ip' => '192.0.2.1']];
225+ $calls = [
226+ // ドメイン
227+ ['createDomain', fn($op) => $op->createDomain('076studio.jp', ['owner_handle' => 'OW1', 'name_servers' => ['ns1.076.moe'], 'is_private_whois_enabled' => true], 2),
228+ 'POST', '/domains', '', ['domain' => ['name' => '076studio', 'extension' => 'jp'], 'period' => 2, 'owner_handle' => 'OW1',
229+ 'admin_handle' => $owner, 'tech_handle' => $owner, 'billing_handle' => $owner, 'reseller_handle' => $owner,
230+ 'name_servers' => [['name' => 'ns1.076.moe']], 'is_private_whois_enabled' => true, 'autorenew' => 'default']],
231+ ['suggestDomainname', fn($op) => $op->suggestDomainname(['name' => '076', 'tlds' => ['moe']]), 'POST', '/domains/suggest-name', '', ['name' => '076', 'tlds' => ['moe']]],
232+ ['tradeDomainname', fn($op) => $op->tradeDomainname(['domain' => ['name' => '076', 'extension' => 'moe'], 'owner_handle' => 'OW2']),
233+ 'POST', '/domains/trade', '', ['domain' => ['name' => '076', 'extension' => 'moe'], 'owner_handle' => 'OW2']],
234+ ['transferDomainname', fn($op) => $op->transferDomainname(['domain' => ['name' => '076', 'extension' => 'moe'], 'auth_code' => 'abc']),
235+ 'POST', '/domains/transfer', '', ['domain' => ['name' => '076', 'extension' => 'moe'], 'auth_code' => 'abc']],
236+ ['getDomainname', fn($op) => $op->getDomainname(5, ['with_history' => true]), 'GET', '/domains/5', 'with_history=true', null],
237+ ['updateDomainname', fn($op) => $op->updateDomainname(5, ['autorenew' => 'on']), 'PUT', '/domains/5', '', ['autorenew' => 'on']],
238+ ['deleteDomainname', fn($op) => $op->deleteDomainname(5, ['type' => 'transfer']), 'DELETE', '/domains/5', 'type=transfer', null],
239+ ['retryLastDomainnameOperation', fn($op) => $op->retryLastDomainnameOperation(5), 'POST', '/domains/5/last-operation/restart', '', ['id' => 5]],
240+ ['renewDomainname', fn($op) => $op->renewDomainname(5, ['period' => 1]), 'POST', '/domains/5/renew', '', ['id' => 5, 'period' => 1]],
241+ ['restoreDomainname', fn($op) => $op->restoreDomainname(5), 'POST', '/domains/5/restore', '', ['id' => 5]],
242+ ['approveDomainnameTransfer', fn($op) => $op->approveDomainnameTransfer(5, ['approve' => 1]), 'POST', '/domains/5/transfer/approve', '', ['id' => 5, 'approve' => 1]],
243+ ['sendDomainnameFoa1', fn($op) => $op->sendDomainnameFoa1(5), 'POST', '/domains/5/transfer/send-foa1', '', ['id' => 5]],
244+ ['getDomainAdditionalData', fn($op) => $op->getDomainAdditionalData(['domain.name' => '076', 'domain.extension' => 'jp']),
245+ 'GET', '/domains/additional-data', 'domain.name=076&domain.extension=jp', null],
246+ ['getDomainCustomerAdditionalData', fn($op) => $op->getDomainCustomerAdditionalData(['domain.name' => '076', 'domain.extension' => 'jp']),
247+ 'GET', '/domains/additional-data/customers', 'domain.name=076&domain.extension=jp', null],
248+ ['getDomainPrices', fn($op) => $op->getDomainPrices(['domain.name' => '076', 'domain.extension' => 'moe', 'operation' => 'create']),
249+ 'GET', '/domains/prices', 'domain.name=076&domain.extension=moe&operation=create', null],
250+ ['getAuthCode', fn($op) => $op->getAuthCode(5), 'GET', '/domains/5/authcode', '', null],
251+ ['resetAuthCode', fn($op) => $op->resetAuthCode(5), 'POST', '/domains/5/authcode/reset', '', ['id' => 5]],
252+ ['listTlds', fn($op) => $op->listTlds(), 'GET', '/tlds', 'limit=10&offset=0&order=ASC', null],
253+ ['getTld', fn($op) => $op->getTld('moe', ['with_price' => true]), 'GET', '/tlds/moe', 'with_price=true', null],
254+ // 請求
255+ ['listInvoices', fn($op) => $op->listInvoices(), 'GET', '/invoices', 'limit=10&offset=0', null],
256+ ['listPayments', fn($op) => $op->listPayments(), 'GET', '/payments', 'limit=10&offset=0', null],
257+ ['getSuggestedTopUpAmount', fn($op) => $op->getSuggestedTopUpAmount(), 'GET', '/payments/suggested-top-up-amount', '', null],
258+ ['listTransactions', fn($op) => $op->listTransactions(['limit' => 3]), 'GET', '/transactions', 'limit=3', null],
259+ // DNS
260+ ['createDomainToken', fn($op) => $op->createDomainToken(['domain' => '076.moe', 'zone_provider' => 'sectigo']),
261+ 'POST', '/dns/domain-token', '', ['domain' => '076.moe', 'zone_provider' => 'sectigo']],
262+ ['listNameservers', fn($op) => $op->listNameservers(), 'GET', '/dns/nameservers', 'limit=25&offset=0&order_by=name&order=asc', null],
263+ ['createNameserver', fn($op) => $op->createNameserver($ns[0]), 'POST', '/dns/nameservers', '', $ns[0]],
264+ ['getNameserver', fn($op) => $op->getNameserver('ns1.076.moe'), 'GET', '/dns/nameservers/ns1.076.moe', '', null],
265+ ['updateNameserver', fn($op) => $op->updateNameserver('ns1.076.moe', ['ip' => '192.0.2.2']), 'PUT', '/dns/nameservers/ns1.076.moe', '', ['name' => 'ns1.076.moe', 'ip' => '192.0.2.2']],
266+ ['deleteNameserver', fn($op) => $op->deleteNameserver('ns1.076.moe'), 'DELETE', '/dns/nameservers/ns1.076.moe', '', null],
267+ ['listNsGroups', fn($op) => $op->listNsGroups(), 'GET', '/dns/nameservers/groups', 'limit=25&offset=0&order_by.ns_group=asc', null],
268+ ['createNsGroup', fn($op) => $op->createNsGroup(['ns_group' => 'grp', 'name_servers' => $ns]), 'POST', '/dns/nameservers/groups', '', ['ns_group' => 'grp', 'name_servers' => $ns]],
269+ ['getNsGroup', fn($op) => $op->getNsGroup('my group'), 'GET', '/dns/nameservers/groups/my%20group', '', null],
270+ ['updateNsGroup', fn($op) => $op->updateNsGroup('grp', ['name_servers' => $ns]), 'PUT', '/dns/nameservers/groups/grp', '', ['ns_group' => 'grp', 'name_servers' => $ns]],
271+ ['deleteNsGroup', fn($op) => $op->deleteNsGroup('grp'), 'DELETE', '/dns/nameservers/groups/grp', '', null],
272+ ['listDnsTemplate', fn($op) => $op->listDnsTemplate(['with_records' => true]), 'GET', '/dns/templates', 'with_records=true', null],
273+ ['createDnsTemplate', fn($op) => $op->createDnsTemplate(['name' => 'web', 'records' => [['type' => 'A', 'value' => '192.0.2.1']]]),
274+ 'POST', '/dns/templates', '', ['name' => 'web', 'records' => [['type' => 'A', 'value' => '192.0.2.1']]]],
275+ ['getDnsTemplate', fn($op) => $op->getDnsTemplate(3), 'GET', '/dns/templates/3', '', null],
276+ ['deleteDnsTemplate', fn($op) => $op->deleteDnsTemplate(3), 'DELETE', '/dns/templates/3', '', null],
277+ ['listDnsZones', fn($op) => $op->listDnsZones(), 'GET', '/dns/zones', 'limit=25&offset=0&order_by.name=asc', null],
278+ ['createDnsZone', fn($op) => $op->createDnsZone(['domain' => ['name' => '076', 'extension' => 'moe'], 'type' => 'master']),
279+ 'POST', '/dns/zones', '', ['domain' => ['name' => '076', 'extension' => 'moe'], 'type' => 'master']],
280+ ['getDnsZone', fn($op) => $op->getDnsZone('076.moe', ['with_records' => true]), 'GET', '/dns/zones/076.moe', 'with_records=true', null],
281+ ['updateDnsZone', fn($op) => $op->updateDnsZone('076.moe', ['records' => ['add' => [['type' => 'A', 'name' => 'www', 'value' => '192.0.2.1', 'ttl' => 900]]]]),
282+ 'PUT', '/dns/zones/076.moe', '', ['name' => '076.moe', 'records' => ['add' => [['type' => 'A', 'name' => 'www', 'value' => '192.0.2.1', 'ttl' => 900]]]]],
283+ ['deleteDnsZone', fn($op) => $op->deleteDnsZone('076.moe', ['provider' => 'openprovider']), 'DELETE', '/dns/zones/076.moe', 'provider=openprovider', null],
284+ ['listZoneRecords', fn($op) => $op->listZoneRecords('076.moe', ['type' => 'A']), 'GET', '/dns/zones/076.moe/records', 'type=A', null],
285+ // EasyDMARC
286+ ['getEasydmarc', fn($op) => $op->getEasydmarc('076.co.jp'), 'GET', '/easydmarcs', 'domain.name=076&domain.extension=co.jp', null],
287+ ['createEasydmarc', fn($op) => $op->createEasydmarc('076.moe', 'OW1'), 'POST', '/easydmarcs', '', ['domain' => ['name' => '076', 'extension' => 'moe'], 'owner_handle' => 'OW1']],
288+ ['listEasydmarcs', fn($op) => $op->listEasydmarcs(['domain' => '076.moe', 'status' => ['ACT', 'FAI']]),
289+ 'GET', '/easydmarcs/list', 'status=ACT&status=FAI&domain.name=076&domain.extension=moe', null],
290+ ['deleteEasydmarc', fn($op) => $op->deleteEasydmarc(7), 'DELETE', '/easydmarcs/7', '', null],
291+ ['retryEasydmarc', fn($op) => $op->retryEasydmarc(7), 'POST', '/easydmarcs/7/retry', '', ['id' => 7]],
292+ ['getEasydmarcSso', fn($op) => $op->getEasydmarcSso(7, 'dashboard'), 'GET', '/easydmarcs/7/sso', 'type=dashboard', null],
293+ // メールテンプレート
294+ ['listEmails', fn($op) => $op->listEmails(['group' => 'ive']), 'GET', '/emails', 'group=ive', null],
295+ ['createEmail', fn($op) => $op->createEmail(['name' => 'mail', 'group' => 'ive']), 'POST', '/emails', '', ['name' => 'mail', 'group' => 'ive']],
296+ ['updateEmail', fn($op) => $op->updateEmail(9, ['is_active' => false]), 'PUT', '/emails/9', '', ['id' => 9, 'is_active' => false]],
297+ ['deleteEmail', fn($op) => $op->deleteEmail(9), 'DELETE', '/emails/9', '', null],
298+ // ライセンス
299+ ['listLicenses', fn($op) => $op->listLicenses(['product' => 'plesk']), 'GET', '/licenses', 'product=plesk', null],
300+ ['resetLicenseHwid', fn($op) => $op->resetLicenseHwid('plesk', 11), 'POST', '/licenses/hwids/reset/plesk/11', '', ['key_id' => 11, 'product' => 'plesk']],
301+ ['listLicenseItems', fn($op) => $op->listLicenseItems(['product' => 'plesk']), 'GET', '/licenses/items', 'product=plesk', null],
302+ ['listPleskLicenses', fn($op) => $op->listPleskLicenses(), 'GET', '/licenses/plesk', '', null],
303+ ['createPleskLicense', fn($op) => $op->createPleskLicense(['items' => ['PLSK-12-WEB-PRO'], 'period' => 1]),
304+ 'POST', '/licenses/plesk', '', ['items' => ['PLSK-12-WEB-PRO'], 'period' => 1]],
305+ ['getPleskKey', fn($op) => $op->getPleskKey(11), 'GET', '/licenses/plesk/key/11', '', null],
306+ ['getPleskLicense', fn($op) => $op->getPleskLicense(11), 'GET', '/licenses/plesk/11', '', null],
307+ ['updatePleskLicense', fn($op) => $op->updatePleskLicense(11, ['title' => 'web']), 'PUT', '/licenses/plesk/11', '', ['key_id' => 11, 'title' => 'web']],
308+ ['deletePleskLicense', fn($op) => $op->deletePleskLicense(11), 'DELETE', '/licenses/plesk/11', '', null],
309+ ['listVirtuozzoLicenses', fn($op) => $op->listVirtuozzoLicenses(['limit' => 5]), 'GET', '/licenses/virtuozzo', 'limit=5', null],
310+ ['createVirtuozzoLicense', fn($op) => $op->createVirtuozzoLicense(['items' => ['VZ'], 'pcs_capacity' => 2]),
311+ 'POST', '/licenses/virtuozzo', '', ['items' => ['VZ'], 'pcs_capacity' => 2]],
312+ ['getVirtuozzoLicense', fn($op) => $op->getVirtuozzoLicense(12), 'GET', '/licenses/virtuozzo/12', '', null],
313+ ['updateVirtuozzoLicense', fn($op) => $op->updateVirtuozzoLicense(12, ['suspended' => true]), 'PUT', '/licenses/virtuozzo/12', '', ['key_id' => 12, 'suspended' => true]],
314+ ['deleteVirtuozzoLicense', fn($op) => $op->deleteVirtuozzoLicense(12), 'DELETE', '/licenses/virtuozzo/12', '', null],
315+ ['getVirtuozzoKey', fn($op) => $op->getVirtuozzoKey(12), 'GET', '/licenses/virtuozzo/12/key', '', null],
316+ // リセラー・顧客様
317+ ['listContacts', fn($op) => $op->listContacts(['role' => 'tech']), 'GET', '/contacts', 'role=tech', null],
318+ ['createContact', fn($op) => $op->createContact(['username' => 'staff1', 'role' => 'tech']), 'POST', '/contacts', '', ['username' => 'staff1', 'role' => 'tech']],
319+ ['getContact', fn($op) => $op->getContact(4, true), 'GET', '/contacts/4', 'with_additional_data=true', null],
320+ ['updateContact', fn($op) => $op->updateContact(4, ['comments' => 'メモ']), 'PUT', '/contacts/4', '', ['id' => 4, 'comments' => 'メモ']],
321+ ['deleteContact', fn($op) => $op->deleteContact(4), 'DELETE', '/contacts/4', '', null],
322+ ['getContactNotificationSetting', fn($op) => $op->getContactNotificationSetting(), 'GET', '/contact/notification-setting', '', null],
323+ ['updateContactNotificationSetting', fn($op) => $op->updateContactNotificationSetting(['marketing_promotion' => false]),
324+ 'POST', '/contact/notification-setting', '', ['marketing_promotion' => false]],
325+ ['listCustomers', fn($op) => $op->listCustomers(['handle_pattern' => 'AB*']), 'GET', '/customers', 'handle_pattern=AB%2A', null],
326+ ['createCustomer', fn($op) => $op->createCustomer(['email' => 'a@076.moe']), 'POST', '/customers', '', ['email' => 'a@076.moe']],
327+ ['getCustomer', fn($op) => $op->getCustomer('AB123-NL', true), 'GET', '/customers/AB123-NL', 'with_additional_data=true', null],
328+ ['updateCustomer', fn($op) => $op->updateCustomer('AB123-NL', ['email' => 'b@076.moe']), 'PUT', '/customers/AB123-NL', '', ['handle' => 'AB123-NL', 'email' => 'b@076.moe']],
329+ ['deleteCustomer', fn($op) => $op->deleteCustomer('AB123-NL'), 'DELETE', '/customers/AB123-NL', '', null],
330+ ['listEmailVerifications', fn($op) => $op->listEmailVerifications(['email' => 'a@076.moe']), 'GET', '/customers/verifications/emails/domains', 'email=a%40076.moe', null],
331+ ['restartEmailVerifications', fn($op) => $op->restartEmailVerifications('a@076.moe'), 'POST', '/customers/verifications/emails/restart', '', ['email' => 'a@076.moe']],
332+ ['startEmailVerifications', fn($op) => $op->startEmailVerifications('a@076.moe', 'AB123-NL', 'ja'),
333+ 'POST', '/customers/verifications/emails/start', '', ['email' => 'a@076.moe', 'handle' => 'AB123-NL', 'language' => 'ja']],
334+ ['getReseller', fn($op) => $op->getReseller(['with_statistics' => true]), 'GET', '/resellers', 'with_statistics=true', null],
335+ ['updateReseller', fn($op) => $op->updateReseller(42, ['comments' => 'x']), 'PUT', '/resellers/42', '', ['id' => 42, 'comments' => 'x']],
336+ ['listSettings', fn($op) => $op->listSettings(), 'GET', '/resellers/settings', '', null],
337+ ['listStatistics', fn($op) => $op->listStatistics(), 'GET', '/resellers/statistics', '', null],
338+ ['listTags', fn($op) => $op->listTags(['key' => 'k']), 'GET', '/tags', 'key=k', null],
339+ ['createTag', fn($op) => $op->createTag(['key' => 'k', 'value' => 'v']), 'POST', '/tags', '', ['key' => 'k', 'value' => 'v']],
340+ ['deleteTag', fn($op) => $op->deleteTag(['key' => 'k', 'value' => 'v']), 'DELETE', '/tags', 'key=k&value=v', null],
341+ // SpamExpert
342+ ['generateLoginUrlSpamExpert', fn($op) => $op->generateLoginUrlSpamExpert(['domain_or_email' => '076.moe']),
343+ 'POST', '/spam-expert/generate-login-url', '', ['domain_or_email' => '076.moe']],
344+ ['createSeDomain', fn($op) => $op->createSeDomain(['domain_name' => '076.moe']), 'POST', '/spam-expert/domains', '', ['domain_name' => '076.moe']],
345+ ['getSeDomain', fn($op) => $op->getSeDomain('076.moe', ['with_records' => true]), 'GET', '/spam-expert/domains/076.moe', 'with_records=true', null],
346+ ['updateSeDomain', fn($op) => $op->updateSeDomain('076.moe', ['aliases' => ['076.jp']]), 'PUT', '/spam-expert/domains/076.moe', '', ['domain_name' => '076.moe', 'aliases' => ['076.jp']]],
347+ ['deleteSeDomain', fn($op) => $op->deleteSeDomain('076.moe', ['bundle' => true]), 'DELETE', '/spam-expert/domains/076.moe', 'bundle=true', null],
348+ // SSL証明書
349+ ['listApproverEmails', fn($op) => $op->listApproverEmails(['product_id' => 1, 'domain' => '076.moe']), 'GET', '/ssl/approver-emails', 'product_id=1&domain=076.moe', null],
350+ ['createCsr', fn($op) => $op->createCsr(['common_name' => '076.moe', 'bits' => 2048]), 'POST', '/ssl/csr', '', ['common_name' => '076.moe', 'bits' => 2048]],
351+ ['decodeCsr', fn($op) => $op->decodeCsr('-----BEGIN CERTIFICATE REQUEST-----'), 'POST', '/ssl/csr/decode', '', ['csr' => '-----BEGIN CERTIFICATE REQUEST-----']],
352+ ['listSslOrders', fn($op) => $op->listSslOrders(['status' => ['ACT', 'PAI']]), 'GET', '/ssl/orders', 'status=ACT&status=PAI', null],
353+ ['createSslOrder', fn($op) => $op->createSslOrder(['product_id' => 1, 'period' => 1]), 'POST', '/ssl/orders', '', ['product_id' => 1, 'period' => 1]],
354+ ['getSslOrder', fn($op) => $op->getSslOrder(8), 'GET', '/ssl/orders/8', '', null],
355+ ['updateSslOrder', fn($op) => $op->updateSslOrder(8, ['autorenew' => 'on']), 'PUT', '/ssl/orders/8', '', ['id' => 8, 'autorenew' => 'on']],
356+ ['cancelSslOrder', fn($op) => $op->cancelSslOrder(8), 'POST', '/ssl/orders/8/cancel', '', ['id' => 8]],
357+ ['reissueSslOrder', fn($op) => $op->reissueSslOrder(8, ['csr' => 'csr']), 'POST', '/ssl/orders/8/reissue', '', ['id' => 8, 'csr' => 'csr']],
358+ ['renewSslOrder', fn($op) => $op->renewSslOrder(8), 'POST', '/ssl/orders/8/renew', '', ['id' => 8]],
359+ ['updateSslApproverEmail', fn($op) => $op->updateSslApproverEmail(8, 'admin@076.moe'), 'PUT', '/ssl/orders/8/approver-email', '', ['id' => 8, 'approver_email' => 'admin@076.moe']],
360+ ['resendSslApproverEmail', fn($op) => $op->resendSslApproverEmail(8), 'POST', '/ssl/orders/8/approver-email/resend', '', ['id' => 8]],
361+ ['createSslOtpToken', fn($op) => $op->createSslOtpToken(8), 'POST', '/ssl/orders/8/otp-tokens', '', ['id' => 8]],
362+ ['listSslProducts', fn($op) => $op->listSslProducts(['with_price' => true]), 'GET', '/ssl/products', 'with_price=true', null],
363+ ['getSslProduct', fn($op) => $op->getSslProduct(1), 'GET', '/ssl/products/1', '', null],
364+ ];
365+
366+ foreach ($calls as [$name, $call, $method, $path, $query, $body]) {
367+ $test->it("{$name}()は{$method} {$path}を呼ぶはず", function($test) use ($fresh, $respond, $ctl, $sorted, $call, $method, $path, $query, $body): void {
368+ $data = ['id' => 1, 'name' => 'テスト'];
369+ $respond($data);
370+ $res = $call($fresh());
371+ $test->assertTrue($res->isSuccess, (string)$res->message);
372+ $test->assertSame($sorted(['code' => 0, 'desc' => '', 'data' => $data]), $sorted($res->data));
373+ $req = $ctl('/__last');
374+ $test->assertEquals($method, $req['method']);
375+ $test->assertEquals("/v1beta{$path}", $req['path']);
376+ $test->assertEquals($query, $req['query']);
377+ if ($body === null) $test->assertEquals('', $req['body'], 'GET・DELETEに本文は無い');
378+ else $test->assertSame($sorted($body), $sorted(json_decode($req['body'], true)));
379+ });
380+ }
381+
382+ $test->it('一覧と確認はresultsだけを返すはず', function($test) use ($fresh, $respond, $ctl): void {
383+ $respond(['results' => [['id' => 1]], 'total' => 1]);
384+ $res = $fresh()->listDomains(['status' => 'ACT', 'limit' => 5]);
385+ $test->assertEquals([['id' => 1]], $res->data);
386+ $test->assertEquals('status=ACT&limit=5', $ctl('/__last')['query']);
387+
388+ $respond(['results' => [['domain' => '076.moe', 'status' => 'free']]]);
389+ $res = $fresh()->checkDomainAvailable(['076.moe'], true);
390+ $test->assertEquals([['domain' => '076.moe', 'status' => 'free']], $res->data);
391+ $test->assertEquals(['domains' => [['name' => '076', 'extension' => 'moe']], 'with_price' => true], json_decode($ctl('/__last')['body'], true));
392+ });
393+
394+ $test->it('ログインでリセラーIDを記録するはず', function($test) use ($fresh): void {
395+ $test->assertEquals(42, $fresh()->getResellerId());
396+ });
397+
398+ $test->it('APIのエラー(codeが0以外、successがfalse、HTTPのエラー)は失敗のはず', function($test) use ($fresh, $respond, $quiet): void {
399+ $respond([], 200, 316, 'Domain is not available');
400+ $res = $fresh()->getDomainname(5);
401+ $test->assertFalse($res->isSuccess);
402+ $test->assertStringContains('Domain is not available', $res->message);
403+
404+ $respond(['success' => false]);
405+ $test->assertFalse($fresh()->deleteDnsZone('076.moe')->isSuccess);
406+
407+ $respond([], 400, 10001, 'Invalid request');
408+ $res = $quiet(fn() => $fresh()->createDnsZone(['type' => 'master']));
409+ $test->assertFalse($res->isSuccess);
410+ $test->assertStringContains('Invalid request', $res->message);
411+ });
412+
413+ $test->it('不正なドメインはリクエストを送らずに失敗するはず', function($test) use ($fresh, $ctl): void {
414+ $op = $fresh();
415+ $before = $ctl('/__last');
416+ foreach (['getEasydmarc' => fn() => $op->getEasydmarc('076'), 'createEasydmarc' => fn() => $op->createEasydmarc('.moe'),
417+ 'listEasydmarcs' => fn() => $op->listEasydmarcs(['domain' => '076.']), 'createDomain' => fn() => $op->createDomain('076', [])] as $name => $fn) {
418+ $res = $fn();
419+ $test->assertFalse($res->isSuccess, $name);
420+ $test->assertStringContains('不正なドメイン形', $res->message);
421+ }
422+ $test->assertEquals($before, $ctl('/__last'));
423+ });
424+
425+ $test->it('一覧はキャッシュし、変更したらキャッシュを消すはず', function($test) use ($fresh, $respond, $ctl): void {
426+ $op = $fresh();
427+ $respond(['results' => [['name' => '076.moe']], 'total' => 1]);
428+ $test->assertTrue($op->listDnsZones()->isSuccess);
429+ $last = $ctl('/__last');
430+ $cached = $op->listDnsZones();
431+ $test->assertEquals([['name' => '076.moe']], $cached->data['data']['results'], 'キャッシュから同じ形で返す');
432+ $test->assertFalse(isset($cached->data['query']) || isset($cached->data['lifespan']));
433+ $test->assertEquals($last, $ctl('/__last'), 'キャッシュがあればリクエストしない');
434+
435+ $respond(['success' => true]);
436+ $test->assertTrue($op->createDnsZone(['domain' => ['name' => '076', 'extension' => 'jp']])->isSuccess);
437+ $respond(['results' => [], 'total' => 2]);
438+ $test->assertEquals(2, $op->listDnsZones()->data['data']['total'], '追加した後は取り直す');
439+ // 違うクエリーは取り直す
440+ $respond(['results' => [], 'total' => 3]);
441+ $test->assertEquals(3, $op->listDnsZones(['limit' => 1])->data['data']['total']);
442+ });
443+
444+ $srv?->stop();
445+ // テスト毎のキャッシュを削除する
446+ foreach (glob(ROOT.'/data/cache/'.$cacheName.'_*') ?: [] as $dir) {
447+ foreach (glob("{$dir}/*") ?: [] as $f) @unlink($f);
448+ @rmdir($dir);
449+ }
178450 });
179451
180452 // テスト用のキャッシュを削除する