Skip to content

Commit

Permalink
feat: domain contact management
Browse files Browse the repository at this point in the history
  • Loading branch information
DXTimer committed Dec 27, 2023
1 parent e319997 commit aa89451
Show file tree
Hide file tree
Showing 11 changed files with 520 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/dnsimple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub mod oauth;
pub mod registrar;
pub mod registrar_auto_renewal;
pub mod registrar_name_servers;
pub mod registrar_registrant_changes;
pub mod registrar_whois_privacy;
pub mod services;
pub mod templates;
Expand Down Expand Up @@ -442,6 +443,19 @@ impl Client {

let status = resp.status();

// if the response is empty, we return empty data
if resp.status() == 204 {
return Ok(DNSimpleResponse {
rate_limit,
rate_limit_remaining,
rate_limit_reset,
status,
data: None,
pagination: None,
body: None,
});
}

let json = resp
.into_json::<Value>()
.map_err(|e| DNSimpleError::Deserialization(e.to_string()))?;
Expand Down
193 changes: 193 additions & 0 deletions src/dnsimple/registrar_registrant_changes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
use crate::dnsimple::registrar::Registrar;
use crate::dnsimple::tlds::TldExtendedAttribute;
use crate::dnsimple::{DNSimpleResponse, Endpoint, RequestOptions};
use crate::errors::DNSimpleError;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Represents the contact change data
#[derive(Debug, Deserialize)]
pub struct RegistrantChange {
/// The contact change id in DNSimple
pub id: u64,
/// The associated account ID.
pub account_id: u64,
/// The associated contact ID.
pub contact_id: u64,
/// The associated domain ID.
pub domain_id: u64,
/// The registrant change state.
pub state: String,
/// The extended attributes.
pub extended_attributes: Option<HashMap<String, String>>,
/// True if the registrant change is a registry owner change.
pub registry_owner_change: bool,
/// When the Inter-Registrar Transfer lock (60 days) is going to be lifted.
pub irt_lock_lifted_by: Option<String>,
/// When the registrant change was created in DNSimple.
pub created_at: String,
/// When the registrant change was last updated in DNSimple.
pub updated_at: String,
}

/// Represents the contact change check data
#[derive(Debug, Deserialize)]
pub struct RegistrantChangeCheck {
/// The associated contact ID.
pub contact_id: u64,
/// The associated domain ID.
pub domain_id: u64,
/// The extended attributes.
pub extended_attributes: Option<Vec<TldExtendedAttribute>>,
/// True if the registrant change is a registry owner change.
pub registry_owner_change: bool,
}

/// Payload used to check the requirements for a contact change
#[derive(Debug, Deserialize, Serialize)]
pub struct RegistrantChangePayload {
/// The associated domain ID.
pub domain_id: u64,
/// The associated registrant (contact) ID.
pub contact_id: u64,
// The extended attributes.
#[serde(skip_serializing_if = "Option::is_none")]
pub extended_attributes: Option<HashMap<String, String>>,
}

/// Payload used to check the requirements for a contact change
#[derive(Debug, Deserialize, Serialize)]
pub struct RegistrantChangeCheckPayload {
/// The associated domain ID.
pub domain_id: u64,
/// The associated registrant (contact) ID.
pub contact_id: u64,
}

struct RegistrantChangeEndpoint;

impl Endpoint for RegistrantChangeEndpoint {
type Output = RegistrantChange;
}

struct DeleteRegistrantChangeEndpoint;

impl Endpoint for DeleteRegistrantChangeEndpoint {
type Output = Option<RegistrantChange>;
}

struct RegistrantChangesEndpoint;

impl Endpoint for RegistrantChangesEndpoint {
type Output = Vec<RegistrantChange>;
}

struct RegistrantChangeCheckEndpoint;

impl Endpoint for RegistrantChangeCheckEndpoint {
type Output = RegistrantChangeCheck;
}

impl Registrar<'_> {
/// Retrieve the domain contact change
///
/// # Arguments
///
/// `account_id`: The account ID
/// `registrant_change_id`: The contact change ID
pub fn get_registrant_change(
&self,
account_id: u64,
registrant_change_id: u64,
) -> Result<DNSimpleResponse<RegistrantChange>, DNSimpleError> {
let path = format!(
"/{}/registrar/registrant_changes/{}",
account_id, registrant_change_id
);

self.client.get::<RegistrantChangeEndpoint>(&path, None)
}

/// Retrieves the requirements of a registrant change
///
/// # Arguments
///
/// `account_id`: The account ID
/// `payload`: The `RegistrantChangeCheckPayload` with the information needed to check the
/// requirements for a registrant change
pub fn check_registrant_change(
&self,
account_id: u64,
payload: RegistrantChangeCheckPayload,
) -> Result<DNSimpleResponse<RegistrantChangeCheck>, DNSimpleError> {
let path = format!("/{}/registrar/registrant_changes/check", account_id);

match serde_json::to_value(payload) {
Ok(json) => self
.client
.post::<RegistrantChangeCheckEndpoint>(&path, json),
Err(_) => Err(DNSimpleError::Deserialization(String::from(
"Cannot deserialize json payload",
))),
}
}

/// Start registrant change.
///
/// # Arguments
///
/// `account_id`: The account ID
/// `payload`: The `RegistrantChangePayload` with the information needed to start a registrant change
pub fn create_registrant_change(
&self,
account_id: u64,
payload: RegistrantChangePayload,
) -> Result<DNSimpleResponse<RegistrantChange>, DNSimpleError> {
let path = format!("/{}/registrar/registrant_changes", account_id);

match serde_json::to_value(payload) {
Ok(json) => self.client.post::<RegistrantChangeEndpoint>(&path, json),
Err(_) => Err(DNSimpleError::Deserialization(String::from(
"Cannot deserialize json payload",
))),
}
}

/// List registrant changes in the account.
///
/// # Arguments
///
/// `account_id`: The account ID
/// `options`: The `RequestOptions`
/// - Filters: `domain_id`, `state`, `contact_id`
/// - Sorting: `id`
pub fn list_registrant_changes(
&self,
account_id: u64,
options: Option<RequestOptions>,
) -> Result<DNSimpleResponse<Vec<RegistrantChange>>, DNSimpleError> {
let path = format!("/{}/registrar/registrant_changes", account_id);

self.client.get::<RegistrantChangesEndpoint>(&path, options)
}

/// Cancel a registrant change.
///
/// # Arguments
///
/// `account_id`: The account ID
/// `registrant_change_id`: The contact change ID
pub fn delete_registrant_change(
&self,
account_id: u64,
registrant_change_id: u64,
) -> Result<DNSimpleResponse<Option<RegistrantChange>>, DNSimpleError> {
let path = format!(
"/{}/registrar/registrant_changes/{}",
account_id, registrant_change_id
);

self.client
.delete_with_response::<DeleteRegistrantChangeEndpoint>(&path)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
HTTP/1.1 404
server: nginx
date: Tue, 22 Aug 2023 13:59:02 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2398
x-ratelimit-reset: 1692716201
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
cache-control: no-cache
x-request-id: b1dd3f42-ebb9-42fd-a121-d595de96f667
x-runtime: 0.019122
strict-transport-security: max-age=63072000

{"message":"Contact `21` not found"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
HTTP/1.1 404
server: nginx
date: Tue, 22 Aug 2023 11:09:40 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2395
x-ratelimit-reset: 1692705338
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
etag: W/"cef1e7d85d0b9bfd25e81b812891d34f"
cache-control: max-age=0, private, must-revalidate
x-request-id: 5b0d8bfb-7b6a-40b5-a079-b640fd817e34
x-runtime: 3.066249
strict-transport-security: max-age=63072000

{"message":"Domain `dnsimple-rraform.bio` not found"}
15 changes: 15 additions & 0 deletions tests/fixtures/v2/api/checkRegistrantChange/success.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
HTTP/1.1 200
server: nginx
date: Tue, 22 Aug 2023 11:09:40 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2395
x-ratelimit-reset: 1692705338
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
etag: W/"cef1e7d85d0b9bfd25e81b812891d34f"
cache-control: max-age=0, private, must-revalidate
x-request-id: 5b0d8bfb-7b6a-40b5-a079-b640fd817e34
x-runtime: 3.066249
strict-transport-security: max-age=63072000

{"data":{"domain_id":101,"contact_id":101,"extended_attributes":[],"registry_owner_change":true}}
14 changes: 14 additions & 0 deletions tests/fixtures/v2/api/createRegistrantChange/success.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
HTTP/1.1 202
server: nginx
date: Tue, 22 Aug 2023 11:11:00 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2394
x-ratelimit-reset: 1692705339
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
cache-control: no-cache
x-request-id: 26bf7ff9-2075-42b0-9431-1778c825b6b0
x-runtime: 3.408950
strict-transport-security: max-age=63072000

{"data":{"id":101,"account_id":101,"domain_id":101,"contact_id":101,"state":"new","extended_attributes":{},"registry_owner_change":true,"irt_lock_lifted_by":null,"created_at":"2017-02-03T17:43:22Z","updated_at":"2017-02-03T17:43:22Z"}}
12 changes: 12 additions & 0 deletions tests/fixtures/v2/api/deleteRegistrantChange/success.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
HTTP/1.1 204 No Content
server: nginx
date: Tue, 22 Aug 2023 11:14:44 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2391
x-ratelimit-reset: 1692705338
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
cache-control: no-cache
x-request-id: b123e1f0-aa70-4abb-95cf-34f377c83ef4
x-runtime: 0.114839
strict-transport-security: max-age=63072000
14 changes: 14 additions & 0 deletions tests/fixtures/v2/api/deleteRegistrantChange/success_async.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
HTTP/1.1 202
server: nginx
date: Tue, 22 Aug 2023 11:11:00 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2394
x-ratelimit-reset: 1692705339
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
cache-control: no-cache
x-request-id: 26bf7ff9-2075-42b0-9431-1778c825b6b0
x-runtime: 3.408950
strict-transport-security: max-age=63072000

{"data":{"id":101,"account_id":101,"domain_id":101,"contact_id":101,"state":"cancelling","extended_attributes":{},"registry_owner_change":true,"irt_lock_lifted_by":null,"created_at":"2017-02-03T17:43:22Z","updated_at":"2017-02-03T17:43:22Z"}}
15 changes: 15 additions & 0 deletions tests/fixtures/v2/api/getRegistrantChange/success.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
HTTP/1.1 200
server: nginx
date: Tue, 22 Aug 2023 11:13:58 GMT
content-type: application/json; charset=utf-8
X-RateLimit-Limit: 2400
X-RateLimit-Remaining: 2395
X-RateLimit-Reset: 1692705338
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
etag: W/"76c5d4c7579b754b94a42ac7fa37a901"
cache-control: max-age=0, private, must-revalidate
x-request-id: e910cd08-3f9c-4da4-9986-50dbe9c3bc55
x-runtime: 0.022006
strict-transport-security: max-age=63072000

{"data":{"id":101,"account_id":101,"domain_id":101,"contact_id":101,"state":"new","extended_attributes":{},"registry_owner_change":true,"irt_lock_lifted_by":null,"created_at":"2017-02-03T17:43:22Z","updated_at":"2017-02-03T17:43:22Z"}}
15 changes: 15 additions & 0 deletions tests/fixtures/v2/api/listRegistrantChanges/success.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
HTTP/1.1 200
server: nginx
date: Tue, 22 Aug 2023 11:12:49 GMT
content-type: application/json; charset=utf-8
x-ratelimit-limit: 2400
x-ratelimit-remaining: 2393
x-ratelimit-reset: 1692705338
x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
etag: W/"0049703ea058b06346df4c0e169eac29"
cache-control: max-age=0, private, must-revalidate
x-request-id: fd0334ce-414a-4872-8889-e548e0b1410c
x-runtime: 0.030759
strict-transport-security: max-age=63072000

{"data":[{"id":101,"account_id":101,"domain_id":101,"contact_id":101,"state":"new","extended_attributes":{},"registry_owner_change":true,"irt_lock_lifted_by":null,"created_at":"2017-02-03T17:43:22Z","updated_at":"2017-02-03T17:43:22Z"}],"pagination":{"current_page":1,"per_page":30,"total_entries":1,"total_pages":1}}
Loading

0 comments on commit aa89451

Please sign in to comment.