Skip to content

Commit 3ed86e2

Browse files
committed
fix: GET params not correctly send
fix: 'billing_handle' missing from domain actions fix: Domain details datetime incorrect format feat: All domain details now fetched
1 parent 52058d0 commit 3ed86e2

File tree

3 files changed

+174
-63
lines changed

3 files changed

+174
-63
lines changed

README.md

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,71 @@
1-
# fossbilling-registrar-openprovider
2-
1+
# OpenProvider Integration for FOSSBilling
2+
3+
This project integrates the OpenProvider domain registrar with FOSSBilling, enabling users to manage domain registration, transfer, and renewal directly from their FOSSBilling platform.
4+
5+
---
6+
7+
## Features
8+
9+
- **Domain Registration**: Register new domains using OpenProvider's API.
10+
- **Domain Transfer**: Transfer existing domains to OpenProvider from FOSSBilling.
11+
- **Domain Management**: Update DNS, WHOIS, and other settings directly.
12+
- **Renewals**: Automate domain renewals through OpenProvider.
13+
14+
---
15+
16+
## Requirements
17+
18+
- **FOSSBilling**: Make sure you have FOSSBilling installed and properly configured.
19+
- **OpenProvider Account**: An active account with OpenProvider is required to use their API.
20+
21+
---
22+
23+
## Installation
24+
25+
1. Clone this repository and copy the files to the root of your FOSSBilling installation:
26+
```bash
27+
git clone https://github.com/Devife/fossbilling-registrar-openprovider.git
28+
```
29+
1. Navigate to the FOSSBilling admin panel.
30+
31+
1. Go to System > Domain registration > New domain registrar and enable the OpenProvider module.
32+
33+
1. Refresh the page, go to the Registrars tab and edit the OpenProvider settings
34+
35+
1. Enter your OpenProvider API credentials:
36+
- API URL: Live https://api.openprovider.eu (Sandbox http://api.sandbox.openprovider.nl:8480)
37+
- Username
38+
- Password
39+
1. Save your configuration.
40+
41+
## Usage
42+
43+
1. Add OpenProvider as your registrar for specific TLDs in FOSSBilling.
44+
45+
1. Clients can register, transfer, or renew domains through your billing system, and the integration will communicate with OpenProvider's API to process requests.
46+
47+
1. Monitor and manage domain actions directly from your FOSSBilling admin panel.
48+
49+
## Troubleshooting
50+
51+
- Connection Issues: Ensure your server can connect to the OpenProvider API endpoint.
52+
- API Errors: Double-check your credentials and ensure your OpenProvider account has sufficient privileges.
53+
- PHP Errors: Verify if your PHP version is supported by FOSSBilling.
54+
55+
## Contributing
56+
57+
Contributions are welcome! Please follow these steps:
58+
59+
1. Fork the repository.
60+
1. Create a new branch (feature/your-feature).
61+
1. Commit your changes.
62+
1. Open a pull request with a detailed description.
63+
64+
## License
65+
66+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
67+
68+
## Acknowledgments
69+
70+
1. OpenProvider for their robust API.
71+
1. FOSSBilling for their open-source billing platform.

library/Registrar/Adapter/OpenProvider.php

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ class Registrar_Adapter_OpenProvider extends Registrar_AdapterAbstract
2323
);
2424

2525
private const MODULE_VERSION = "0.1";
26-
private const PATH_LOG = "./library/Registrar/Adapter";
2726
private const DIR_LOG = "logs";
2827
private const FILE_LOG = "openprovider.log";
2928

@@ -33,21 +32,21 @@ public function __construct($options)
3332
$this->config['Username'] = $options['Username'];
3433
unset($options['Username']);
3534
} else {
36-
throw new Registrar_Exception('OpenProvider Registrar module error.<br>Please update configuration parameter "Reseller Username" at "Configuration -> Domain registration"');
35+
throw new Registrar_Exception('OpenProvider Registrar module error. Please update configuration parameter "Reseller Username" at "Configuration -> Domain registration"', [':domain_registrar' => 'OpenProvider', ':missing' => 'OpenProvider Username'], 3001);
3736
}
3837

3938
if (isset($options['Password']) && !empty($options['Password'])) {
4039
$this->config['Password'] = $options['Password'];
4140
unset($options['Password']);
4241
} else {
43-
throw new Registrar_Exception('OpenProvider Registrar module error.<br>Please update configuration parameter "Reseller Password" at "Configuration -> Domain registration"');
42+
throw new Registrar_Exception('OpenProvider Registrar module error. Please update configuration parameter "Reseller Password" at "Configuration -> Domain registration"', [':domain_registrar' => 'OpenProvider', ':missing' => 'OpenProvider Password'], 3001);
4443
}
4544

4645
if (isset($options['ApiUrl']) && !empty($options['ApiUrl'])) {
4746
$this->config['ApiUrl'] = $options['ApiUrl'];
4847
unset($options['ApiUrl']);
4948
} else {
50-
throw new Registrar_Exception('OpenProvider Registrar module error.<br>Please update configuration parameter "API url" at "Configuration -> Domain registration"');
49+
throw new Registrar_Exception('OpenProvider Registrar module error. Please update configuration parameter "API url" at "Configuration -> Domain registration"', [':domain_registrar' => 'OpenProvider', ':missing' => 'OpenProvider API Url'], 3001);
5150
}
5251
}
5352
/**
@@ -93,7 +92,8 @@ public function getTlds(): array
9392
}
9493

9594
public function registerDomain(Registrar_Domain $domain)
96-
{ // Step 1: Ensure a customer handle exists
95+
{
96+
// Step 1: Ensure a customer handle exists
9797
$customerHandle = $this->_getOrCreateCustomer($domain->getContactAdmin());
9898

9999
// Step 2: Prepare the domain registration data
@@ -106,6 +106,7 @@ public function registerDomain(Registrar_Domain $domain)
106106
'owner_handle' => $customerHandle,
107107
'admin_handle' => $customerHandle,
108108
'tech_handle' => $customerHandle,
109+
'billing_handle' => $customerHandle,
109110
'ns_group' => 'dns-openprovider',
110111
'autorenew' => 'default'
111112
];
@@ -115,7 +116,7 @@ public function registerDomain(Registrar_Domain $domain)
115116
if ($response['code'] === 0) {
116117
return true;
117118
}
118-
throw new Registrar_Exception('Failed to register domain: ' . $response['msg']);
119+
return false;
119120
} catch (Exception $e) {
120121
throw new Registrar_Exception('OpenProvider API Error: ' . $e->getMessage());
121122
}
@@ -174,6 +175,7 @@ public function transferDomain(Registrar_Domain $domain)
174175
'owner_handle' => $customerHandle,
175176
'admin_handle' => $customerHandle,
176177
'tech_handle' => $customerHandle,
178+
'billing_handle' => $customerHandle,
177179
'ns_group' => 'dns-openprovider',
178180
'autorenew' => 'default',
179181
'auth_code' => $domain->getEpp(),
@@ -240,27 +242,35 @@ public function getDomainDetails(Registrar_Domain $domain)
240242
$response = $this->_request('GET', "/domains/{$domainId}");
241243
$opDomain = $response['data'];
242244

243-
$domain->setRegistrationTime((string) $opDomain['creation_date']);
244-
$domain->setExpirationTime((string) $opDomain['expiration_date']);
245+
$domain->setRegistrationTime(strtotime($opDomain['creation_date']));
246+
$domain->setExpirationTime(strtotime($opDomain['expiration_date']));
245247
$domain->setPrivacyEnabled($opDomain['is_private_whois_enabled']);
248+
$domain->setLocked($opDomain['is_locked']);
246249

247-
// create new Domain obj to return
248-
$newDomain = new Registrar_Domain();
249-
250-
// set SLD and TLD
251-
$newDomain->setSld($domain->getSld());
252-
$newDomain->setTld($domain->getTld());
253-
$newDomain->setRegistrationTime((string) $opDomain['creation_date']);
254-
$newDomain->setExpirationTime((string) $opDomain['expiration_date']);
255-
$newDomain->setPrivacyEnabled($opDomain['is_private_whois_enabled']);
250+
$nameservers = $opDomain['name_servers'];
251+
if (isset($nameservers[0])) {
252+
$domain->setNs1($nameservers[0]['name']);
253+
}
254+
if (isset($nameservers[1])) {
255+
$domain->setNs2($nameservers[1]['name']);
256+
}
257+
if (isset($nameservers[2])) {
258+
$domain->setNs3($nameservers[2]['name']);
259+
}
260+
if (isset($nameservers[3])) {
261+
$domain->setNs4($nameservers[3]['name']);
262+
}
256263

257264
$registrarContact = new Registrar_Domain_Contact();
258265
$adminContact = new Registrar_Domain_Contact();
259266
$techContact = new Registrar_Domain_Contact();
267+
$billingContact = new Registrar_Domain_Contact();
268+
269+
// Get customer info from the api
270+
$customer = $this->_getCustomer($opDomain['admin_handle']);
260271

261272
// Set contact data on our Domain obj using info from our API call
262-
foreach (['Registrant', 'Admin', 'Tech'] as $contactType) {
263-
$owner = $opDomain->owner;
273+
foreach (['Registrant', 'Admin', 'Tech', 'Billing'] as $contactType) {
264274
$contact = $registrarContact;
265275

266276
if ($contactType == 'Admin') {
@@ -269,28 +279,29 @@ public function getDomainDetails(Registrar_Domain $domain)
269279
if ($contactType == 'Tech') {
270280
$contact = $techContact;
271281
}
282+
if ($contactType == 'Billing') {
283+
$contact = $billingContact;
284+
}
272285

273-
$split = explode(" ", $owner->full_name);
274-
$lastName = end($split);
275-
$firstName = str_replace($lastName, '', $owner->full_name);
276-
277-
$contact->setFirstName((string) $firstName);
278-
$contact->setLastName((string) $lastName);
279-
// $contact->setEmail((string) $contactApi->EmailAddress);
280-
// $contact->setTel((string) $contactApi->Phone);
281-
// $contact->setAddress1((string) $contactApi->Address1);
282-
// $contact->setAddress2((string) $contactApi->Address2);
283-
// $contact->setCity((string) $contactApi->City);
284-
// $contact->setState((string) $contactApi->StateProvince);
285-
// $contact->setCountry((string) $contactApi->Country);
286-
// $contact->setZip((string) $contactApi->PostalCode);
286+
$contact->setFirstName($customer['name']['first_name']);
287+
$contact->setLastName($customer['name']['last_name']);
288+
$contact->setEmail($customer['email']);
289+
$contact->setTelCc($customer['phone']['country_code']);
290+
$contact->setTel($customer['phone']['subscriber_number']);
291+
$contact->setAddress1($customer['address']['street']);
292+
$contact->setCity($customer['address']['city']);
293+
$contact->setState($customer['address']['state']);
294+
$contact->setCountry($customer['address']['country']);
295+
$contact->setZip($customer['address']['zipcode']);
296+
$contact->setCompany(isset($customer['company_name']) ? $customer['company_name'] : '');
287297
}
288298

289-
$newDomain->setContactRegistrar($registrarContact);
290-
$newDomain->setContactAdmin($adminContact);
291-
$newDomain->setContactTech($techContact);
299+
$domain->setContactRegistrar($registrarContact);
300+
$domain->setContactAdmin($adminContact);
301+
$domain->setContactTech($techContact);
302+
$domain->setContactBilling($billingContact);
292303

293-
return $newDomain;
304+
return $domain;
294305
}
295306

296307
public function modifyNs(Registrar_Domain $domain)
@@ -328,13 +339,14 @@ public function modifyContact(Registrar_Domain $domain)
328339
$domainId = $this->_getDomainId($domain);
329340

330341
// Step 2: Get or create the customer handle
331-
$customerHandle = $this->_getOrCreateCustomer($domain->getContactAdmin());
342+
$customerHandle = $this->_getOrCreateCustomer($domain->getContactAdmin(), true);
332343

333344
// Step 3: Prepare the request data
334345
$data = [
335346
'owner_handle' => $customerHandle,
336347
'admin_handle' => $customerHandle,
337348
'tech_handle' => $customerHandle,
349+
'billing_handle' => $customerHandle,
338350
];
339351

340352
// Step 4: Send the PUT request to update contact
@@ -434,15 +446,8 @@ private function _getDomainId(Registrar_Domain $domain)
434446
}
435447
}
436448

437-
private function _getOrCreateCustomer(Registrar_Domain_Contact $contact)
449+
private function _getOrCreateCustomer(Registrar_Domain_Contact $contact, $updateExisting = false)
438450
{
439-
// Step 1: Check if the customer already exists by email
440-
$existingCustomerHandle = $this->_findCustomerByEmail($contact->getEmail());
441-
if ($existingCustomerHandle) {
442-
return $existingCustomerHandle;
443-
}
444-
445-
// Step 2: Create a new customer if not found
446451
$data = [
447452
'email' => $contact->getEmail(),
448453
'phone' => [
@@ -464,12 +469,25 @@ private function _getOrCreateCustomer(Registrar_Domain_Contact $contact)
464469
]
465470
];
466471

472+
// Step 1: Check if the customer already exists by email
473+
$existingCustomerHandle = $this->_findCustomerByEmail($contact->getEmail());
474+
if ($existingCustomerHandle) {
475+
if ($updateExisting) {
476+
$response = $this->_request('PUT', "/customers/{$existingCustomerHandle}", $data);
477+
if ($response['code'] !== 0) {
478+
throw new Registrar_Exception('Failed to update contact: ' . $response['msg']);
479+
}
480+
}
481+
482+
return $existingCustomerHandle;
483+
}
484+
485+
// Step 2: Create a new customer if not found
467486
try {
468487
$response = $this->_request('POST', '/customers', $data);
469488
if (isset($response['data']['handle'])) {
470489
return $response['data']['handle'];
471490
}
472-
// var_dump(json_encode($data), $response);
473491
throw new Registrar_Exception('Failed to create customer: ' . $response['msg']);
474492
} catch (Exception $e) {
475493
throw new Registrar_Exception('OpenProvider API Error: ' . $e->getMessage());
@@ -493,6 +511,20 @@ private function _findCustomerByEmail($email)
493511
}
494512
}
495513

514+
515+
private function _getCustomer($handle)
516+
{
517+
try {
518+
$response = $this->_request('GET', "/customers/{$handle}");
519+
if ($response['code'] === 0 && !empty($response['data'])) {
520+
return $response['data']; // Return the customer data
521+
}
522+
return null; // No matching customer found
523+
} catch (Exception $e) {
524+
throw new Registrar_Exception('Failed to find customer by email: ' . $e->getMessage());
525+
}
526+
}
527+
496528
/**
497529
* Send OpenProvider request
498530
*/
@@ -518,7 +550,7 @@ private function _request($method, $url, $data = []): array
518550

519551
private function _logResponse($method, $url, $data, $response)
520552
{
521-
file_put_contents(self::PATH_LOG . '/' . self::DIR_LOG . '/' . self::FILE_LOG, json_encode([
553+
file_put_contents(__DIR__ . '/' . self::DIR_LOG . '/' . self::FILE_LOG, json_encode([
522554
'method' => $method,
523555
'url' => $url,
524556
'data' => $data,
@@ -528,7 +560,7 @@ private function _logResponse($method, $url, $data, $response)
528560

529561
private function _logError($method, $url, $data, $error)
530562
{
531-
file_put_contents(self::PATH_LOG . '/' . self::DIR_LOG . '/' . self::FILE_LOG, json_encode([
563+
file_put_contents(__DIR__ . '/' . self::DIR_LOG . '/' . self::FILE_LOG, json_encode([
532564
'method' => $method,
533565
'url' => $url,
534566
'data' => $data,

0 commit comments

Comments
 (0)