pax_global_header 0000666 0000000 0000000 00000000064 14574024165 0014522 g ustar 00root root 0000000 0000000 52 comment=0ae57dcc9dc2719a972494ca6f1ab4053b8a4fe0 dnsimple-go-2.0.0/ 0000775 0000000 0000000 00000000000 14574024165 0013737 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/.github/ 0000775 0000000 0000000 00000000000 14574024165 0015277 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/.github/CODEOWNERS 0000664 0000000 0000000 00000000042 14574024165 0016666 0 ustar 00root root 0000000 0000000 * @dnsimple/external-integrations dnsimple-go-2.0.0/.github/dependabot.yml 0000664 0000000 0000000 00000000622 14574024165 0020127 0 ustar 00root root 0000000 0000000 --- version: 2 updates: - package-ecosystem: gomod directory: / schedule: interval: monthly open-pull-requests-limit: 10 labels: - task - dependencies - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" time: '12:00' open-pull-requests-limit: 10 labels: - task - dependencies - automerge dnsimple-go-2.0.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14574024165 0017334 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/.github/workflows/auto-merge.yml 0000664 0000000 0000000 00000001605 14574024165 0022126 0 ustar 00root root 0000000 0000000 name: Auto-merge on: pull_request: types: - labeled - synchronize - opened jobs: auto-merge: name: 'Auto-merge' runs-on: ubuntu-latest permissions: write-all if: github.event.pull_request.user.login == 'dependabot[bot]' && contains(github.event.pull_request.labels.*.name, 'automerge') steps: - name: Wait for tests to succeed uses: lewagon/wait-on-check-action@v1.3.3 timeout-minutes: 15 with: ref: ${{ github.ref }} running-workflow-name: 'Auto-merge' repo-token: ${{ secrets.GITHUB_TOKEN }} wait-interval: 10 allowed-conclusions: success - uses: juliangruber/merge-pull-request-action@v1 with: github-token: "${{ secrets.GITHUB_TOKEN }}" number: ${{ github.event.number }} method: squash repo: dnsimple/dnsimple-go dnsimple-go-2.0.0/.github/workflows/ci.yml 0000664 0000000 0000000 00000002333 14574024165 0020453 0 ustar 00root root 0000000 0000000 name: CI on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: markdownlint-cli: name: Lint markdown runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v4 - name: Run markdownlint-cli uses: nosborn/github-action-markdown-cli@v3.3.0 with: files: . config_file: ".markdownlint.yaml" test: needs: [markdownlint-cli] runs-on: ubuntu-latest name: Go ${{ matrix.go-version }} env: GOPATH: ${{ github.workspace }} defaults: run: working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} # yamllint disable-line rule:line-length strategy: matrix: go-version: - "1.21" - "1.22" steps: - uses: actions/checkout@v4 with: path: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - name: Install dependencies run: go get ./... - name: Test run: go test -v ./... dnsimple-go-2.0.0/.gitignore 0000664 0000000 0000000 00000000055 14574024165 0015727 0 ustar 00root root 0000000 0000000 # ASDF .tool-versions # Build /coverage.txt dnsimple-go-2.0.0/.markdownlint.yaml 0000664 0000000 0000000 00000000045 14574024165 0017411 0 ustar 00root root 0000000 0000000 --- default: true line-length: false dnsimple-go-2.0.0/CHANGELOG.md 0000664 0000000 0000000 00000017646 14574024165 0015566 0 ustar 00root root 0000000 0000000 # CHANGELOG ## main ## 2.0.0 - CHANGED: Bump dependencies - CHANGED: Dropped support for Go < 1.20 - CHANGED: Added support for Go >= 1.22 ## 1.6.0 - NEW: Added `DnsAnalytics` to query and pull data from the DNS Analytics API endpoint(dnsimple/dnsimple-go#164) ## 1.5.1 ENHANCEMENTS: - NEW: Added `Secondary`, `LastTransferredAt`, `Active` to `Zone` (dnsimple/dnsimple-go) ## 1.5.0 FEATURES: - NEW: Added `billing.ListCharges` to list charges for the account [learn more](https://developer.dnsimple.com/v2/billing-charges/). (dnsimple/dnsimple-go#156) ## 1.4.1 ENHANCEMENTS: - NEW: Added events for `domain.transfer_lock_enable` and `domain.transfer_lock_disable` (dnsimple/dnsimple-go#149) ## 1.4.0 FEATURES: - NEW: Added `GetDomainTransferLock`, `EnableDomainTransferLock`, and `DisableDomainTransferLock` APIs to manage domain transfer locks. (dnsimple/dnsimple-go#147) ## 1.3.0 FEATURES: - NEW: Added `ListRegistrantChanges`, `CreateRegistrantChange`, `CheckRegistrantChange`, `GetRegistrantChange`, and `DeleteRegistrantChange` APIs to manage registrant changes. (dnsimple/dnsimple-go#146) ## 1.2.1 FEATURES: - NEW: Added `ActivateZoneDns` to activate DNS services (resolution) for a zone. (dnsimple/dnsimple-go#145) - NEW: Added `DeactivateZoneDns` to deactivate DNS services (resolution) for a zone. (dnsimple/dnsimple-go#145) IMPROVEMENTS: - `EmailForward` `From` is deprecated. Please use `AliasName` instead for creating email forwards, and `AliasEmail` when retrieving email forwards. (dnsimple/dnsimple-go#145) - `EmailForward` `To` is deprecated. Please use `DestinationEmail` instead for creating email forwards. (dnsimple/dnsimple-go#145) ## 1.2.0 - NEW: Support `GetDomainRegistration` and `GetDomainRenewal` APIs (dnsimple/dnsimple-go#132) ## 1.1.0 - NEW: Support `signature_algorithm` in the `LetsencryptCertificateAttributes` struct (dnsimple/dnsimple-go#128) ## 1.0.1 - CHANGED: Bump dependencies ## 1.0.0 - NEW: Expose AttributeErrors in ErrorResponse for getting detailed information about validation errors - CHANGED: Support only last two golang versions: 1.18 and 1.19 according Golang Release Policy. - CHANGED: Use testify/assert instead of stdlib ## 0.80.0 - CHANGED: Deprecate Certificate's `contact_id` (dnsimple/dnsimple-go#111) - CHANGED: Dropped support for Go < 1.13 ## 0.71.1 - FIXED: When purchasing a certificate the certificate id is populated now (CertificatePurchase) ## 0.71.0 - CHANGED: Updated Tld and DelegationSignerRecord types to support DS record key-data interface (dnsimple/dnsimple-go#107) ## 0.70.1 - DEPRECATED: Registrar.GetDomainPremiumPrice() has been deprecated, use Registrar.GetDomainPrices() instead. ## 0.70.0 - NEW: Added Registrar.GetDomainPrices() to retrieve whether a domain is premium and the prices to register, transfer, and renew. (dnsimple/dnsimple-go#103) Incompatible changes: - CHANGED: Domain.ExpiresOn has been replaced by Domain.ExpiresAt. (dnsimple/dnsimple-go#98) - CHANGED: Certificate.ExpiresOn has been replaced by Certificate.ExpiresAt. (dnsimple/dnsimple-go#99) ## Release 0.63.0 - NEW: Added types and parsing for account membership events. (dnsimple/dnsimple-go#97) ## Release 0.62.0 - NEW: Added Registrar.GetDomainTransfer() to retrieve a domain transfer. (dnsimple/dnsimple-go#94) - NEW: Added Registrar.CancelDomainTransfer() to cancel an in progress domain transfer. (dnsimple/dnsimple-go#94) ## Release 0.61.0 - NEW: Added convenient helpers to inizialize a client with common authentication strategies ## Release 0.60.0 - FIXED: A zone record can be updated without the risk of overriding the name by mistake (dnsimple/dnsimple-go#33, dnsimple/dnsimple-go#92) - FIXED: Fixed a conflict where a Go zero-value would prevent sorting to work correctly (dnsimple/dnsimple-go#88, dnsimple/dnsimple-go#93) Incompatible changes: - CHANGED: CreateZoneRecord and UpdateZoneRecord now requires to use ZoneRecordAttributes instead of ZoneRecord. This is required to avoid conflicts caused by blank record names (dnsimple/dnsimple-go#92) - CHANGED: ListOptions now use pointer values (dnsimple/dnsimple-go#93) ## Release 0.50.0 - NEW: Added Client.SetUserAgent() as a convenient helper to set a custom user agent. - NEW: Added support for Registration/Transfer extended attributes (dnsimple/dnsimple-go#86) Incompatible changes: - NEW: Added support for context (dnsimple/dnsimple-go#82, dnsimple/dnsimple-go#90) - CHANGED: Changed all method signatures so that the returned value is exported (dnsimple/dnsimple-go#91) - CHANGED: Renamed the following structs to clarify intent: - DomainRegisterRequest -> RegisterDomainInput - DomainTransferRequest -> TransferDomainInput - DomainRenewRequest -> RenewDomainInput ## Release 0.40.0 Incompatible changes: - CHANGED: Renamed ExchangeAuthorizationError.HttpResponse field to ExchangeAuthorizationError.HTTPResponse - CHANGED: Renamed Response.HttpResponse field to Response.HTTPResponse - REMOVED: Deleted deprecated ResetDomainToken method. ## Release 0.31.0 - CHANGED: User-agent format has been changed to prepend custom token before default token. (dnsimple/dnsimple-go#87) ## Release 0.30.0 - NEW: Added webhook event parser for dnssec.create, dnssec.delete - CHANGE: Redesigned webhook event parsing to avoid event/data conflicts (dnsimple/dnsimple-go#85) IMPORTANT: This release introduce breaking changes compared to the previous one, as the webhook even parsing has been significantly reworked. ## Release 0.23.0 - NEW: Added WHOIS privacy renewal (dnsimple/dnsimple-go#78) ## Release 0.22.0 - CHANGED: Cleaned up webhook tests and added coverage for more events. ## Release 0.21.0 - NEW: Added zone distribution and zone record distribution (dnsimple/dnsimple-go#64) ## Release 0.20.0 - CHANGED: Renamed `Event_Header` to `EventHeader` as it's more go-style. The Event interface has been updated accordingly. - CHANGED: Removed custom code for getting OAuth token. We now use RoundTripper for authentication (and pass an http.Client to create a new Client) (dnsimple/dnsimple-go#15, dnsimple/dnsimple-go#69). ## Release 0.16.0 - NEW: Added Let's Encrypt certificate methods (dnsimple/dnsimple-go#63) - REMOVED: Removed premium_price attribute from registrar order responses (dnsimple/dnsimple-go#67). Please do not rely on that attribute, as it returned an incorrect value. The attribute is going to be removed, and the API now returns a null value. ## Release 0.15.0 - NEW: Added support for the DNSSEC Beta (GH-58) - CHANGED: Changed response types to not be exported (GH-54) - CHANGED: Updated registrar URLs (GH-59) - FIXED: Unable to filter zone records by type (GH-65) ## Release 0.14.0 - NEW: Added support for Collaborators API (GH-48) - NEW: Added support for ZoneRecord regions (GH-47) - NEW: Added support for Domain Pushes API (GH-42) - NEW: Added support for domains premium prices API (GH-53) - CHANGED: Renamed `DomainTransferRequest.AuthInfo` to `AuthCode` (GH-46) - CHANGED: Updated registration, transfer, renewal response payload (dnsimple/dnsimple-developer#111, GH-52). - CHANGED: Normalize unique string identifiers to SID (dnsimple/dnsimple-developer#113) - CHANGED: Update whois privacy setting for domain (dnsimple/dnsimple-developer#120) ## Release 0.13.0 - NEW: Added support for Accounts API (GH-29) - NEW: Added support for Services API (GH-30, GH-35) - NEW: Added support for Certificates API (GH-31) - NEW: Added support for Vanity name servers API (GH-34) - NEW: Added support for delegation API (GH-32) - NEW: Added support for Templates API (GH-36, GH-39) - NEW: Added support for Template Records API (GH-37) - NEW: Added support for Zone files API (GH-38) ## Release 0.12.0 - CHANGED: Setting a custom user-agent no longer overrides the origina user-agent (GH-26) - CHANGED: Renamed Contact#email_address to Contact#email (GH-27) ## Release 0.11.0 - NEW: Added support for parsing ZoneRecord webhooks. - NEW: Added support for listing options (GH-25). - NEW: Added support for Template API (GH-21). ## Release 0.10.0 Initial release. dnsimple-go-2.0.0/CONTRIBUTING.md 0000664 0000000 0000000 00000004121 14574024165 0016166 0 ustar 00root root 0000000 0000000 # Contributing to DNSimple/Go The main `dnsimple` package is defined in the `/dnsimple` subfolder of the `dnsimple/dnsimple-go` repository. Therefore, please note that you will need to move into the subfolder to run any `go` command that assumes the current directory to be the package root. For example, to get the dependencies you will have to run: ```shell git clone git@github.com:dnsimple/dnsimple-go.git cd dnsimple go get ./... ``` Likewise, when you include this library as dependency, you will need to use ```go import "github.com/dnsimple/dnsimple-go/dnsimple" ``` and not ```go import "github.com/dnsimple/dnsimple-go" ``` ## Getting started ### 1. Clone the repository Clone the repository [in your workspace](https://go.dev/doc/code#Organization) and move into it: ```shell git clone git@github.com:dnsimple/dnsimple-go.git cd dnsimple-go ``` ### 2. Build and test [Run the test suite](#testing) to check everything works as expected. ## Releasing The following instructions uses `$VERSION` as a placeholder, where `$VERSION` is a `MAJOR.MINOR.BUGFIX` release such as `1.2.0`. 1. Run the test suite and ensure all the tests pass. 1. Set the version in `dnsimple.go`: ```go Version = "$VERSION" ``` 1. Run the test suite and ensure all the tests pass. 1. Finalize the `## main` section in `CHANGELOG.md` assigning the version. 1. Commit and push the changes ```shell git commit -a -m "Release $VERSION" git push origin main ``` 1. Wait for CI to complete. 1. Create a signed tag. ```shell git tag -a v$VERSION -s -m "Release $VERSION" git push origin --tags ``` ## Testing Submit unit tests for your changes. You can test your changes on your machine by running the test suite (see below). When you submit a PR, tests will also be run on the [continuous integration environment via GitHub Actions](https://github.com/dnsimple/dnsimple-go/actions). ### Test Suite To run the test suite: ```shell go test ./... -v ``` To run the test suite in a live environment (integration): ```shell export DNSIMPLE_TOKEN="some-token" go test ./... -v ``` dnsimple-go-2.0.0/LICENSE.txt 0000664 0000000 0000000 00000002104 14574024165 0015557 0 ustar 00root root 0000000 0000000 The MIT License (MIT) Copyright (c) 2014-2022 DNSimple Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dnsimple-go-2.0.0/README.md 0000664 0000000 0000000 00000011551 14574024165 0015221 0 ustar 00root root 0000000 0000000 # DNSimple Go Client A Go client for the [DNSimple API v2](https://developer.dnsimple.com/v2/). [](https://github.com/dnsimple/dnsimple-go/actions/workflows/ci.yml) [](https://godoc.org/github.com/dnsimple/dnsimple-go/dnsimple) ## Installation ```shell go get github.com/dnsimple/dnsimple-go/dnsimple ``` ## Usage This library is a Go client you can use to interact with the [DNSimple API v2](https://developer.dnsimple.com/v2/). Here are some examples. ```go package main import ( "context" "fmt" "os" "strconv" "github.com/dnsimple/dnsimple-go/dnsimple" ) func main() { tc := dnsimple.StaticTokenHTTPClient(context.Background(), "your-token") // new client client := dnsimple.NewClient(tc) // get the current authenticated account (if you don't know who you are) whoamiResponse, err := client.Identity.Whoami(context.Background()) if err != nil { fmt.Printf("Whoami() returned error: %v\n", err) os.Exit(1) } fmt.Println(whoamiResponse.Data.Account) fmt.Println(whoamiResponse.Data.User) // either assign the account ID or fetch it from the response // if you are authenticated with an account token accountID := strconv.FormatInt(whoamiResponse.Data.Account.ID, 10) // get the list of domains domainsResponse, err := client.Domains.ListDomains(context.Background(), accountID, nil) if err != nil { fmt.Printf("Domains.ListDomains() returned error: %v\n", err) os.Exit(1) } // iterate over all the domains in the // paginated response. for _, domain := range domainsResponse.Data { fmt.Println(domain) } // List methods support a variety of options to paginate, sort and filter records. // Here's a few example: // get the list of domains filtered by name and sorted by expiration client.Domains.ListDomains(context.Background(), accountID, &dnsimple.DomainListOptions{NameLike: dnsimple.String("com"), ListOptions: {Sort: dnsimple.String("expiration:DESC")}}) } ``` For more complete documentation, see [godoc](https://godoc.org/github.com/dnsimple/dnsimple-go/dnsimple). ## Authentication When creating a new client you are required to provide an `http.Client` to use for authenticating the requests. Supported authentication mechanisms are OAuth and HTTP Digest. We provide convenient helpers to generate a preconfigured HTTP client. ### Authenticating with OAuth ```go tc := dnsimple.StaticTokenHTTPClient(context.Background(), "your-token") // new client client := dnsimple.NewClient(tc) ``` ### Authenticating with HTTP Basic Auth ```go hc := dnsimple.BasicAuthHTTPClient(context.Background(), "your-user", "your-password") client := dnsimple.NewClient(hc) ``` For requests made to authorize OAuth access, and to exchange the short lived authorization token for the OAuth token, use an HTTP client with a timeout: ```go client := dnsimple.NewClient(&http.Client{Timeout: time.Second * 10}) ``` For any other custom need you can define your own `http.RoundTripper` implementation and pass a client that authenticated with the custom round tripper. ## Sandbox Environment We highly recommend testing against our [sandbox environment](https://developer.dnsimple.com/sandbox/) before using our production environment. This will allow you to avoid real purchases, live charges on your credit card, and reduce the chance of your running up against rate limits. The client supports both the production and sandbox environment. To switch to sandbox pass the sandbox API host using the `base_url` option when you construct the client: ```go client := dnsimple.NewClient(tc) client.BaseURL = "https://api.sandbox.dnsimple.com" ``` You will need to ensure that you are using an access token created in the sandbox environment. Production tokens will *not* work in the sandbox environment. ## Setting a custom `User-Agent` header You can customize the `User-Agent` header for the calls made to the DNSimple API: ```go client := dnsimple.NewClient(tc) client.SetUserAgent("my-app/1.0") ``` The value you provide will be prepended to the default `User-Agent` the client uses. For example, if you use `my-app/1.0`, the final header value will be `my-app/1.0 dnsimple-go/0.14.0` (note that it will vary depending on the client version). We recommend to customize the user agent. If you are building a library or integration on top of the official client, customizing the client will help us to understand what is this client used for, and allow to contribute back or get in touch. ## Contributing For instructions about contributing and testing, visit the [CONTRIBUTING](CONTRIBUTING.md) file. ## License Copyright (c) 2014-2022 DNSimple Corporation. This is Free Software distributed under the MIT license. dnsimple-go-2.0.0/dnsimple/ 0000775 0000000 0000000 00000000000 14574024165 0015552 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/dnsimple/accounts.go 0000664 0000000 0000000 00000003530 14574024165 0017721 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" ) // AccountsService handles communication with the account related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/accounts/ type AccountsService struct { client *Client } // Account represents a DNSimple account. type Account struct { ID int64 `json:"id,omitempty"` Email string `json:"email,omitempty"` PlanIdentifier string `json:"plan_identifier,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // AccountsResponse represents a response from an API method that returns a collection of Account struct. type AccountsResponse struct { Response Data []Account `json:"data"` } // AccountInvitation represents an invitation to a DNSimple account. type AccountInvitation struct { ID int64 `json:"id,omitempty"` Email string `json:"email,omitempty"` Token string `json:"token,omitempty"` AccountID int64 `json:"account_id,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` InvitationSentAt string `json:"invitation_sent_at,omitempty"` InvitationAcceptedAt string `json:"invitation_accepted_at,omitempty"` } // ListAccounts list the accounts for an user. // // See https://developer.dnsimple.com/v2/accounts/#list func (s *AccountsService) ListAccounts(ctx context.Context, options *ListOptions) (*AccountsResponse, error) { path := versioned("/accounts") accountsResponse := &AccountsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, accountsResponse) if err != nil { return accountsResponse, err } accountsResponse.HTTPResponse = resp return accountsResponse, nil } dnsimple-go-2.0.0/dnsimple/accounts_test.go 0000664 0000000 0000000 00000001453 14574024165 0020762 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestAccountsService_List(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/accounts", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listAccounts/success-user.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountsResponse, err := client.Accounts.ListAccounts(context.Background(), nil) assert.NoError(t, err) accounts := accountsResponse.Data assert.Len(t, accounts, 2) assert.Equal(t, int64(123), accounts[0].ID) assert.Equal(t, "john@example.com", accounts[0].Email) } dnsimple-go-2.0.0/dnsimple/authentication.go 0000664 0000000 0000000 00000004131 14574024165 0021117 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "net/http" "golang.org/x/oauth2" ) // BasicAuthHTTPClient returns a client that authenticates via HTTP Basic Auth with given username and password. func BasicAuthHTTPClient(_ context.Context, username, password string) *http.Client { tp := BasicAuthTransport{Username: username, Password: password} return tp.Client() } // StaticTokenHTTPClient returns a client that authenticates with a static OAuth token. func StaticTokenHTTPClient(ctx context.Context, token string) *http.Client { ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}) return oauth2.NewClient(ctx, ts) } // BasicAuthTransport is an http.RoundTripper that authenticates all requests // using HTTP Basic Authentication with the provided username and password. type BasicAuthTransport struct { Username string Password string // Transport is the transport RoundTripper used to make HTTP requests. // If nil, http.DefaultTransport is used. Transport http.RoundTripper } // RoundTrip implements the RoundTripper interface. We just add the // basic auth and return the RoundTripper for this transport type. func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { req2 := cloneRequest(req) // per RoundTripper contract req2.SetBasicAuth(t.Username, t.Password) return t.transport().RoundTrip(req2) } // Client returns an *http.Client that uses the BasicAuthTransport transport // to authenticate the request via HTTP Basic Auth. func (t *BasicAuthTransport) Client() *http.Client { return &http.Client{Transport: t} } func (t *BasicAuthTransport) transport() http.RoundTripper { if t.Transport != nil { return t.Transport } return http.DefaultTransport } // cloneRequest returns a clone of the provided *http.Request. // The clone is a shallow copy of the struct and its Header map. func cloneRequest(r *http.Request) *http.Request { // shallow copy of the struct r2 := new(http.Request) *r2 = *r // deep copy of the Header r2.Header = make(http.Header, len(r.Header)) for k, s := range r.Header { r2.Header[k] = append([]string(nil), s...) } return r2 } dnsimple-go-2.0.0/dnsimple/authentication_test.go 0000664 0000000 0000000 00000001232 14574024165 0022155 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "testing" "golang.org/x/oauth2" "github.com/stretchr/testify/assert" ) func TestBasicAuthHTTPClient(t *testing.T) { ctx := context.Background() x := "user" y := "pass" h := BasicAuthHTTPClient(ctx, x, y) rt := h.Transport ts, ok := rt.(*BasicAuthTransport) assert.True(t, ok) assert.Equal(t, x, ts.Username) assert.Equal(t, y, ts.Password) } func TestStaticTokenHTTPClient(t *testing.T) { ctx := context.Background() x := "123456" h := StaticTokenHTTPClient(ctx, x) rt := h.Transport ts, ok := rt.(*oauth2.Transport) assert.True(t, ok) tk, _ := ts.Source.Token() assert.Equal(t, x, tk.AccessToken) } dnsimple-go-2.0.0/dnsimple/billing.go 0000664 0000000 0000000 00000003451 14574024165 0017524 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" "github.com/shopspring/decimal" ) type ListChargesOptions struct { // Only include results after the given date. StartDate string `url:"start_date,omitempty"` // Only include results before the given date. EndDate string `url:"end_date,omitempty"` // Sort results. Default sorting is by invoiced ascending. Sort string `url:"sort,omitempty"` } type ListChargesResponse struct { Response Data []Charge `json:"data"` } type Charge struct { InvoicedAt string `json:"invoiced_at,omitempty"` TotalAmount decimal.Decimal `json:"total_amount,omitempty"` BalanceAmount decimal.Decimal `json:"balance_amount,omitempty"` Reference string `json:"reference,omitempty"` State string `json:"state,omitempty"` Items []ChargeItem `json:"items,omitempty"` } type ChargeItem struct { Description string `json:"description,omitempty"` Amount decimal.Decimal `json:"amount,omitempty"` ProductId int64 `json:"product_id,omitempty"` ProductType string `json:"product_type,omitempty"` ProductReference string `json:"product_reference,omitempty"` } type BillingService struct { client *Client } // Lists the billing charges for the account. // // See https://developer.dnsimple.com/v2/billing/#listCharges func (s *BillingService) ListCharges( ctx context.Context, account string, options ListChargesOptions, ) (*ListChargesResponse, error) { res := &ListChargesResponse{} path := fmt.Sprintf("/v2/%v/billing/charges", account) path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } httpRes, err := s.client.get( ctx, path, res, ) if err != nil { return nil, err } res.HTTPResponse = httpRes return res, nil } dnsimple-go-2.0.0/dnsimple/billing_test.go 0000664 0000000 0000000 00000012315 14574024165 0020562 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "encoding/json" "io" "net/http" "net/url" "testing" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" ) func toDecimal(t *testing.T, s string) decimal.Decimal { d, err := decimal.NewFromString(s) if err != nil { assert.Nilf(t, err, "toDecimal() error = %v", err) } return d } func TestBillingService_ListCharges_Success(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/billing/charges", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCharges/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) response, err := client.Billing.ListCharges(context.Background(), "1010", ListChargesOptions{}) assert.NoError(t, err) assert.Equal(t, response.Pagination, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 3}) assert.Equal(t, response.Data, []Charge{ { InvoicedAt: "2023-08-17T05:53:36Z", TotalAmount: toDecimal(t, "14.50"), BalanceAmount: toDecimal(t, "0.00"), Reference: "1-2", State: "collected", Items: []ChargeItem{ { Description: "Register bubble-registered.com", Amount: toDecimal(t, "14.50"), ProductId: 1, ProductType: "domain-registration", ProductReference: "bubble-registered.com", }, }, }, { InvoicedAt: "2023-08-17T05:57:53Z", TotalAmount: toDecimal(t, "14.50"), BalanceAmount: toDecimal(t, "0.00"), Reference: "2-2", State: "refunded", Items: []ChargeItem{ { Description: "Register example.com", Amount: toDecimal(t, "14.50"), ProductId: 2, ProductType: "domain-registration", ProductReference: "example.com", }, }, }, { InvoicedAt: "2023-10-24T07:49:05Z", TotalAmount: toDecimal(t, "1099999.99"), BalanceAmount: toDecimal(t, "0.00"), Reference: "4-2", State: "collected", Items: []ChargeItem{ { Description: "Test Line Item 1", Amount: toDecimal(t, "99999.99"), ProductId: 0, ProductType: "manual", ProductReference: "", }, { Description: "Test Line Item 2", Amount: toDecimal(t, "1000000.00"), ProductId: 0, ProductType: "manual", ProductReference: "", }, }, }, }) } func TestBillingService_ListCharges_Fail400BadFilter(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/billing/charges", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCharges/fail-400-bad-filter.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Billing.ListCharges(context.Background(), "1010", ListChargesOptions{}) assert.Equal(t, err.(*ErrorResponse).Message, "Invalid date format must be ISO8601 (YYYY-MM-DD)") } func TestBillingService_ListCharges_Fail403(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/billing/charges", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCharges/fail-403.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Billing.ListCharges(context.Background(), "1010", ListChargesOptions{}) assert.Equal(t, err.(*ErrorResponse).Message, "Permission Denied. Required Scope: billing:*:read") } func TestUnmarshalCharge(t *testing.T) { tests := []struct { name string jsonStr string want Charge wantErr bool }{ { name: "valid json", jsonStr: `{"total_amount": "123.45", "balance_amount": "67.89"}`, want: Charge{ TotalAmount: decimal.NewFromFloat(123.45), BalanceAmount: decimal.NewFromFloat(67.89), }, wantErr: false, }, { name: "zero values", jsonStr: `{"total_amount": "0.00", "balance_amount": "0.00"}`, want: Charge{ TotalAmount: decimal.NewFromFloat(0.00), BalanceAmount: decimal.NewFromFloat(0.00), }, wantErr: false, }, { name: "invalid amount value", jsonStr: `{"total_amount": "123.45", "balance_amount": "abc"}`, want: Charge{ TotalAmount: decimal.NewFromFloat(123.45), BalanceAmount: decimal.Decimal{}, }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var got Charge err := json.Unmarshal([]byte(tt.jsonStr), &got) if (err != nil) != tt.wantErr { t.Errorf("Unmarshal() error = %v, wantErr %v", err, tt.wantErr) return } assert.Truef(t, got.TotalAmount.Equals(tt.want.TotalAmount), "TotalAmount: got %v, want %v\nTesting: %s\n%s", got.TotalAmount, tt.want.TotalAmount, tt.name, tt.jsonStr) assert.Truef(t, got.BalanceAmount.Equals(tt.want.BalanceAmount), "BalanceAmount: got %v, want %v\nTesting: %s\n%s", got.BalanceAmount, tt.want.BalanceAmount, tt.name, tt.jsonStr) }) } } dnsimple-go-2.0.0/dnsimple/certificates.go 0000664 0000000 0000000 00000024201 14574024165 0020545 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // CertificatesService handles communication with the certificate related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/certificates/ type CertificatesService struct { client *Client } // Certificate represents a Certificate in DNSimple. type Certificate struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` // Deprecated: ContactID is deprecated and its value is ignored and will be removed in the next major version. ContactID int64 `json:"contact_id,omitempty"` CommonName string `json:"common_name,omitempty"` AlternateNames []string `json:"alternate_names,omitempty"` Years int `json:"years,omitempty"` State string `json:"state,omitempty"` AuthorityIdentifier string `json:"authority_identifier,omitempty"` AutoRenew bool `json:"auto_renew"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` ExpiresAt string `json:"expires_at,omitempty"` CertificateRequest string `json:"csr,omitempty"` } // CertificateBundle represents a container for all the PEM-encoded X509 certificate entities, // such as the private key, the server certificate and the intermediate chain. type CertificateBundle struct { // CertificateRequest string `json:"csr,omitempty"` PrivateKey string `json:"private_key,omitempty"` ServerCertificate string `json:"server,omitempty"` RootCertificate string `json:"root,omitempty"` IntermediateCertificates []string `json:"chain,omitempty"` } // CertificatePurchase represents a Certificate Purchase in DNSimple. type CertificatePurchase struct { ID int64 `json:"id,omitempty"` CertificateID int64 `json:"certificate_id,omitempty"` State string `json:"state,omitempty"` AutoRenew bool `json:"auto_renew,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // CertificateRenewal represents a Certificate Renewal in DNSimple. type CertificateRenewal struct { ID int64 `json:"id,omitempty"` OldCertificateID int64 `json:"old_certificate_id,omitempty"` NewCertificateID int64 `json:"new_certificate_id,omitempty"` State string `json:"state,omitempty"` AutoRenew bool `json:"auto_renew,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // LetsencryptCertificateAttributes is a set of attributes to purchase a Let's Encrypt certificate. type LetsencryptCertificateAttributes struct { // Deprecated: ContactID is deprecated and its value is ignored and will be removed in the next major version. ContactID int64 `json:"contact_id,omitempty"` Name string `json:"name,omitempty"` AutoRenew bool `json:"auto_renew,omitempty"` AlternateNames []string `json:"alternate_names,omitempty"` SignatureAlgorithm string `json:"signature_algorithm,omitempty"` } func certificatePath(accountID, domainIdentifier string, certificateID int64) (path string) { path = fmt.Sprintf("%v/certificates", domainPath(accountID, domainIdentifier)) if certificateID != 0 { path += fmt.Sprintf("/%v", certificateID) } return } func letsencryptCertificatePath(accountID, domainIdentifier string, certificateID int64) (path string) { path = fmt.Sprintf("%v/certificates/letsencrypt", domainPath(accountID, domainIdentifier)) if certificateID != 0 { path += fmt.Sprintf("/%v", certificateID) } return } // CertificateResponse represents a response from an API method that returns a Certificate struct. type CertificateResponse struct { Response Data *Certificate `json:"data"` } // CertificateBundleResponse represents a response from an API method that returns a CertificatBundle struct. type CertificateBundleResponse struct { Response Data *CertificateBundle `json:"data"` } // CertificatesResponse represents a response from an API method that returns a collection of Certificate struct. type CertificatesResponse struct { Response Data []Certificate `json:"data"` } // CertificatePurchaseResponse represents a response from an API method that returns a CertificatePurchase struct. type CertificatePurchaseResponse struct { Response Data *CertificatePurchase `json:"data"` } // CertificateRenewalResponse represents a response from an API method that returns a CertificateRenewal struct. type CertificateRenewalResponse struct { Response Data *CertificateRenewal `json:"data"` } // ListCertificates lists the certificates for a domain in the account. // // See https://developer.dnsimple.com/v2/certificates#listCertificates func (s *CertificatesService) ListCertificates(ctx context.Context, accountID, domainIdentifier string, options *ListOptions) (*CertificatesResponse, error) { path := versioned(certificatePath(accountID, domainIdentifier, 0)) certificatesResponse := &CertificatesResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, certificatesResponse) if err != nil { return certificatesResponse, err } certificatesResponse.HTTPResponse = resp return certificatesResponse, nil } // GetCertificate gets the details of a certificate. // // See https://developer.dnsimple.com/v2/certificates#getCertificate func (s *CertificatesService) GetCertificate(ctx context.Context, accountID, domainIdentifier string, certificateID int64) (*CertificateResponse, error) { path := versioned(certificatePath(accountID, domainIdentifier, certificateID)) certificateResponse := &CertificateResponse{} resp, err := s.client.get(ctx, path, certificateResponse) if err != nil { return nil, err } certificateResponse.HTTPResponse = resp return certificateResponse, nil } // DownloadCertificate gets the PEM-encoded certificate, // along with the root certificate and intermediate chain. // // See https://developer.dnsimple.com/v2/certificates#downloadCertificate func (s *CertificatesService) DownloadCertificate(ctx context.Context, accountID, domainIdentifier string, certificateID int64) (*CertificateBundleResponse, error) { path := versioned(certificatePath(accountID, domainIdentifier, certificateID) + "/download") certificateBundleResponse := &CertificateBundleResponse{} resp, err := s.client.get(ctx, path, certificateBundleResponse) if err != nil { return nil, err } certificateBundleResponse.HTTPResponse = resp return certificateBundleResponse, nil } // GetCertificatePrivateKey gets the PEM-encoded certificate private key. // // See https://developer.dnsimple.com/v2/certificates#getCertificatePrivateKey func (s *CertificatesService) GetCertificatePrivateKey(ctx context.Context, accountID, domainIdentifier string, certificateID int64) (*CertificateBundleResponse, error) { path := versioned(certificatePath(accountID, domainIdentifier, certificateID) + "/private_key") certificateBundleResponse := &CertificateBundleResponse{} resp, err := s.client.get(ctx, path, certificateBundleResponse) if err != nil { return nil, err } certificateBundleResponse.HTTPResponse = resp return certificateBundleResponse, nil } // PurchaseLetsencryptCertificate purchases a Let's Encrypt certificate. // // See https://developer.dnsimple.com/v2/certificates/#purchaseLetsencryptCertificate func (s *CertificatesService) PurchaseLetsencryptCertificate(ctx context.Context, accountID, domainIdentifier string, certificateAttributes LetsencryptCertificateAttributes) (*CertificatePurchaseResponse, error) { path := versioned(letsencryptCertificatePath(accountID, domainIdentifier, 0)) certificatePurchaseResponse := &CertificatePurchaseResponse{} resp, err := s.client.post(ctx, path, certificateAttributes, certificatePurchaseResponse) if err != nil { return nil, err } certificatePurchaseResponse.HTTPResponse = resp return certificatePurchaseResponse, nil } // IssueLetsencryptCertificate issues a pending Let's Encrypt certificate purchase order. // // See https://developer.dnsimple.com/v2/certificates/#issueLetsencryptCertificate func (s *CertificatesService) IssueLetsencryptCertificate(ctx context.Context, accountID, domainIdentifier string, certificateID int64) (*CertificateResponse, error) { path := versioned(letsencryptCertificatePath(accountID, domainIdentifier, certificateID) + "/issue") certificateResponse := &CertificateResponse{} resp, err := s.client.post(ctx, path, nil, certificateResponse) if err != nil { return nil, err } certificateResponse.HTTPResponse = resp return certificateResponse, nil } // PurchaseLetsencryptCertificateRenewal purchases a Let's Encrypt certificate renewal. // // See https://developer.dnsimple.com/v2/certificates/#purchaseRenewalLetsencryptCertificate func (s *CertificatesService) PurchaseLetsencryptCertificateRenewal(ctx context.Context, accountID, domainIdentifier string, certificateID int64, certificateAttributes LetsencryptCertificateAttributes) (*CertificateRenewalResponse, error) { path := versioned(letsencryptCertificatePath(accountID, domainIdentifier, certificateID) + "/renewals") certificateRenewalResponse := &CertificateRenewalResponse{} resp, err := s.client.post(ctx, path, certificateAttributes, certificateRenewalResponse) if err != nil { return nil, err } certificateRenewalResponse.HTTPResponse = resp return certificateRenewalResponse, nil } // IssueLetsencryptCertificateRenewal issues a pending Let's Encrypt certificate renewal order. // // See https://developer.dnsimple.com/v2/certificates/#issueRenewalLetsencryptCertificate func (s *CertificatesService) IssueLetsencryptCertificateRenewal(ctx context.Context, accountID, domainIdentifier string, certificateID, certificateRenewalID int64) (*CertificateResponse, error) { path := versioned(letsencryptCertificatePath(accountID, domainIdentifier, certificateID) + fmt.Sprintf("/renewals/%d/issue", certificateRenewalID)) certificateResponse := &CertificateResponse{} resp, err := s.client.post(ctx, path, nil, certificateResponse) if err != nil { return nil, err } certificateResponse.HTTPResponse = resp return certificateResponse, nil } dnsimple-go-2.0.0/dnsimple/certificates_test.go 0000664 0000000 0000000 00000040365 14574024165 0021615 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestCertificatePath(t *testing.T) { assert.Equal(t, "/1010/domains/example.com/certificates", certificatePath("1010", "example.com", 0)) assert.Equal(t, "/1010/domains/example.com/certificates/2", certificatePath("1010", "example.com", 2)) } func TestCertificatesService_ListCertificates(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/dnsimple.us/certificates", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCertificates/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificatesResponse, err := client.Certificates.ListCertificates(context.Background(), "1010", "dnsimple.us", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, certificatesResponse.Pagination) certificates := certificatesResponse.Data assert.Len(t, certificates, 2) assert.Equal(t, int64(101973), certificates[0].ID) assert.Equal(t, "www2.dnsimple.us", certificates[0].CommonName) } func TestCertificatesService_ListCertificates_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/certificates", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCertificates/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Certificates.ListCertificates(context.Background(), "1010", "example.com", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestCertificatesService_GetCertificate(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/bingo.pizza/certificates/101967", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getCertificate/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateResponse, err := client.Certificates.GetCertificate(context.Background(), "1010", "bingo.pizza", 101967) assert.NoError(t, err) certificate := certificateResponse.Data wantSingle := &Certificate{ ID: 101967, DomainID: 289333, ContactID: 2511, CommonName: "www.bingo.pizza", AlternateNames: []string{}, Years: 1, State: "issued", AuthorityIdentifier: "letsencrypt", AutoRenew: false, CreatedAt: "2020-06-18T18:54:17Z", UpdatedAt: "2020-06-18T19:10:14Z", ExpiresAt: "2020-09-16T18:10:13Z", CertificateRequest: "-----BEGIN CERTIFICATE REQUEST-----\nMIICmTCCAYECAQAwGjEYMBYGA1UEAwwPd3d3LmJpbmdvLnBpenphMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw4+KoZ9IDCK2o5qAQpi+Icu5kksmjQzx\n5o5g4B6XhRxhsfHlK/i3iU5hc8CONjyVv8j82835RNsiKrflnxGa9SH68vbQfcn4\nIpbMz9c+Eqv5h0Euqlc3A4DBzp0unEu5QAUhR6Xu1TZIWDPjhrBOGiszRlLQcp4F\nzy6fD6j5/d/ylpzTp5v54j+Ey31Bz86IaBPtSpHI+Qk87Hs8DVoWxZk/6RlAkyur\nXDGWnPu9n3RMfs9ag5anFhggLIhCNtVN4+0vpgPQ59pqwYo8TfdYzK7WSKeL7geu\nCqVE3bHAqU6dLtgHOZfTkLwGycUh4p9aawuc6fsXHHYDpIL8s3vAvwIDAQABoDow\nOAYJKoZIhvcNAQkOMSswKTAnBgNVHREEIDAeggtiaW5nby5waXp6YYIPd3d3LmJp\nbmdvLnBpenphMA0GCSqGSIb3DQEBCwUAA4IBAQBwOLKv+PO5hSJkgqS6wL/wRqLh\nQ1zbcHRHAjRjnpRz06cDvN3X3aPI+lpKSNFCI0A1oKJG7JNtgxX3Est66cuO8ESQ\nPIb6WWN7/xlVlBCe7ZkjAFgN6JurFdclwCp/NI5wBCwj1yb3Ar5QQMFIZOezIgTI\nAWkQSfCmgkB96d6QlDWgidYDDjcsXugQveOQRPlHr0TsElu47GakxZdJCFZU+WPM\nodQQf5SaqiIK2YaH1dWO//4KpTS9QoTy1+mmAa27apHcmz6X6+G5dvpHZ1qH14V0\nJoMWIK+39HRPq6mDo1UMVet/xFUUrG/H7/tFlYIDVbSpVlpVAFITd/eQkaW/\n-----END CERTIFICATE REQUEST-----\n"} assert.Equal(t, wantSingle, certificate) } func TestCertificatesService_DownloadCertificate(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/certificates/2/download", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/downloadCertificate/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateBundleResponse, err := client.Certificates.DownloadCertificate(context.Background(), "1010", "example.com", 2) assert.NoError(t, err) certificateBundle := certificateBundleResponse.Data wantSingle := &CertificateBundle{ RootCertificate: "", ServerCertificate: "-----BEGIN CERTIFICATE-----\nMIIE7TCCA9WgAwIBAgITAPpTe4O3vjuQ9L4gLsogi/ukujANBgkqhkiG9w0BAQsF\nADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0xNjA2MTEx\nNzQ4MDBaFw0xNjA5MDkxNzQ4MDBaMBkxFzAVBgNVBAMTDnd3dy53ZXBwb3MubmV0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtzCcMfWoQRt5AMEY0HUb\n2GaraL1GsWOo6YXdPfe+YDvtnmDw23NcoTX7VSeCgU9M3RKs19AsCJcRNTLJ2dmD\nrAuyCTud9YTAaXQcTOLUhtO8T8+9AFVIva2OmAlKCR5saBW3JaRxW7V2aHEd/d1s\ns1CvNOO7jNppc9NwGSnDHcn3rqNv/U3MaU0gpJJRqsKkvcLU6IHJGgxyQ6AbpwJD\nIqBnzkjHu2IuhGEbRuMjyWLA2qtsjyVlfPotDxUdVouUQpz7dGHUFrLR7ma8QAYu\nOfl1ZMyrc901HGMa7zwbnFWurs3fed7vAosTRZIjnn72/3Wo7L9RiMB+vwr3NX7c\n9QIDAQABo4ICIzCCAh8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF\nBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRh9q/3Zxbk4yA/\nt7j+8xA+rkiZBTAfBgNVHSMEGDAWgBTAzANGuVggzFxycPPhLssgpvVoOjB4Bggr\nBgEFBQcBAQRsMGowMwYIKwYBBQUHMAGGJ2h0dHA6Ly9vY3NwLnN0Zy1pbnQteDEu\nbGV0c2VuY3J5cHQub3JnLzAzBggrBgEFBQcwAoYnaHR0cDovL2NlcnQuc3RnLWlu\ndC14MS5sZXRzZW5jcnlwdC5vcmcvMCUGA1UdEQQeMByCCndlcHBvcy5uZXSCDnd3\ndy53ZXBwb3MubmV0MIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsrBgEEAYLf\nEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcw\ngasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSBy\nZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4gYWNjb3Jk\nYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6\nLy9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEB\nAEqMdWrmdIyQxthWsX3iHmM2h/wXwEesD0VIaA+Pq4mjwmKBkoPSmHGQ/O4v8RaK\nB6gl8v+qmvCwwqC1SkBmm+9C2yt/P6WhAiA/DD+WppYgJWfcz2lEKrgufFlHPukB\nDzE0mJDuXm09QTApWlaTZWYfWKY50T5uOT/rs+OwGFFCO/8o7v5AZRAHos6uzjvq\nAtFZj/FEnXXMjSSlQ7YKTXToVpnAYH4e3/UMsi6/O4orkVz82ZfhKwMWHV8dXlRw\ntQaemFWTjGPgSLXJAtQO30DgNJBHX/fJEaHv6Wy8TF3J0wOGpzGbOwaTX8YAmEzC\nlzzjs+clg5MN5rd1g4POJtU=\n-----END CERTIFICATE-----\n", IntermediateCertificates: []string{ "-----BEGIN CERTIFICATE-----\nMIIEqzCCApOgAwIBAgIRAIvhKg5ZRO08VGQx8JdhT+UwDQYJKoZIhvcNAQELBQAw\nGjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDUyMzIyMDc1OVoXDTM2\nMDUyMzIyMDc1OVowIjEgMB4GA1UEAwwXRmFrZSBMRSBJbnRlcm1lZGlhdGUgWDEw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtWKySDn7rWZc5ggjz3ZB0\n8jO4xti3uzINfD5sQ7Lj7hzetUT+wQob+iXSZkhnvx+IvdbXF5/yt8aWPpUKnPym\noLxsYiI5gQBLxNDzIec0OIaflWqAr29m7J8+NNtApEN8nZFnf3bhehZW7AxmS1m0\nZnSsdHw0Fw+bgixPg2MQ9k9oefFeqa+7Kqdlz5bbrUYV2volxhDFtnI4Mh8BiWCN\nxDH1Hizq+GKCcHsinDZWurCqder/afJBnQs+SBSL6MVApHt+d35zjBD92fO2Je56\ndhMfzCgOKXeJ340WhW3TjD1zqLZXeaCyUNRnfOmWZV8nEhtHOFbUCU7r/KkjMZO9\nAgMBAAGjgeMwgeAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw\nHQYDVR0OBBYEFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHoGCCsGAQUFBwEBBG4wbDA0\nBggrBgEFBQcwAYYoaHR0cDovL29jc3Auc3RnLXJvb3QteDEubGV0c2VuY3J5cHQu\nb3JnLzA0BggrBgEFBQcwAoYoaHR0cDovL2NlcnQuc3RnLXJvb3QteDEubGV0c2Vu\nY3J5cHQub3JnLzAfBgNVHSMEGDAWgBTBJnSkikSg5vogKNhcI5pFiBh54DANBgkq\nhkiG9w0BAQsFAAOCAgEABYSu4Il+fI0MYU42OTmEj+1HqQ5DvyAeyCA6sGuZdwjF\nUGeVOv3NnLyfofuUOjEbY5irFCDtnv+0ckukUZN9lz4Q2YjWGUpW4TTu3ieTsaC9\nAFvCSgNHJyWSVtWvB5XDxsqawl1KzHzzwr132bF2rtGtazSqVqK9E07sGHMCf+zp\nDQVDVVGtqZPHwX3KqUtefE621b8RI6VCl4oD30Olf8pjuzG4JKBFRFclzLRjo/h7\nIkkfjZ8wDa7faOjVXx6n+eUQ29cIMCzr8/rNWHS9pYGGQKJiY2xmVC9h12H99Xyf\nzWE9vb5zKP3MVG6neX1hSdo7PEAb9fqRhHkqVsqUvJlIRmvXvVKTwNCP3eCjRCCI\nPTAvjV+4ni786iXwwFYNz8l3PmPLCyQXWGohnJ8iBm+5nk7O2ynaPVW0U2W+pt2w\nSVuvdDM5zGv2f9ltNWUiYZHJ1mmO97jSY/6YfdOUH66iRtQtDkHBRdkNBsMbD+Em\n2TgBldtHNSJBfB3pm9FblgOcJ0FSWcUDWJ7vO0+NTXlgrRofRT6pVywzxVo6dND0\nWzYlTWeUVsO40xJqhgUQRER9YLOLxJ0O6C8i0xFxAMKOtSdodMB3RIwt7RFQ0uyt\nn5Z5MqkYhlMI3J1tPRTp1nEt9fyGspBOO05gi148Qasp+3N+svqKomoQglNoAxU=\n-----END CERTIFICATE-----", }, } assert.Equal(t, wantSingle, certificateBundle) } func TestCertificatesService_GetCertificatePrivateKey(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/certificates/2/private_key", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getCertificatePrivateKey/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateBundleResponse, err := client.Certificates.GetCertificatePrivateKey(context.Background(), "1010", "example.com", 2) assert.NoError(t, err) certificateBundle := certificateBundleResponse.Data wantSingle := &CertificateBundle{ PrivateKey: "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAtzCcMfWoQRt5AMEY0HUb2GaraL1GsWOo6YXdPfe+YDvtnmDw\n23NcoTX7VSeCgU9M3RKs19AsCJcRNTLJ2dmDrAuyCTud9YTAaXQcTOLUhtO8T8+9\nAFVIva2OmAlKCR5saBW3JaRxW7V2aHEd/d1ss1CvNOO7jNppc9NwGSnDHcn3rqNv\n/U3MaU0gpJJRqsKkvcLU6IHJGgxyQ6AbpwJDIqBnzkjHu2IuhGEbRuMjyWLA2qts\njyVlfPotDxUdVouUQpz7dGHUFrLR7ma8QAYuOfl1ZMyrc901HGMa7zwbnFWurs3f\ned7vAosTRZIjnn72/3Wo7L9RiMB+vwr3NX7c9QIDAQABAoIBAEQx32OlzK34GTKT\nr7Yicmw7xEGofIGa1Q2h3Lut13whsxKLif5X0rrcyqRnoeibacS+qXXrJolIG4rP\nTl8/3wmUDQHs5J+6fJqFM+fXZUCP4AFiFzzhgsPBsVyd0KbWYYrZ0qU7s0ttoRe+\nTGjuHgIe3ip1QKNtx2Xr50YmytDydknmro79J5Gfrub1l2iA8SDm1eBrQ4SFaNQ2\nU709pHeSwX8pTihUX2Zy0ifpr0O1wYQjGLneMoG4rrNQJG/z6iUdhYczwwt1kDRQ\n4WkM2sovFOyxbBfoCQ3Gy/eem7OXfjNKUe47DAVLnPkKbqL/3Lo9FD7kcB8K87Ap\nr/vYrl0CgYEA413RAk7571w5dM+VftrdbFZ+Yi1OPhUshlPSehavro8kMGDEG5Ts\n74wEz2X3cfMxauMpMrBk/XnUCZ20AnWQClK73RB5fzPw5XNv473Tt/AFmt7eLOzl\nOcYrhpEHegtsD/ZaljlGtPqsjQAL9Ijhao03m1cGB1+uxI7FgacdckcCgYEAzkKP\n6xu9+WqOol73cnlYPS3sSZssyUF+eqWSzq2YJGRmfr1fbdtHqAS1ZbyC5fZVNZYV\nml1vfXi2LDcU0qS04JazurVyQr2rJZMTlCWVET1vhik7Y87wgCkLwKpbwamPDmlI\n9GY+fLNEa4yfAOOpvpTJpenUScxyKWH2cdYFOOMCgYBhrJnvffINC/d64Pp+BpP8\nyKN+lav5K6t3AWd4H2rVeJS5W7ijiLTIq8QdPNayUyE1o+S8695WrhGTF/aO3+ZD\nKQufikZHiQ7B43d7xL7BVBF0WK3lateGnEVyh7dIjMOdj92Wj4B6mv2pjQ2VvX/p\nAEWVLCtg24/+zL64VgxmXQKBgGosyXj1Zu2ldJcQ28AJxup3YVLilkNje4AXC2No\n6RCSvlAvm5gpcNGE2vvr9lX6YBKdl7FGt8WXBe/sysNEFfgmm45ZKOBCUn+dHk78\nqaeeQHKHdxMBy7utZWdgSqt+ZS299NgaacA3Z9kVIiSLDS4V2VeW7riujXXP/9TJ\nnxaRAoGBAMWXOfNVzfTyrKff6gvDWH+hqNICLyzvkEn2utNY9Q6WwqGuY9fvP/4Z\nXzc48AOBzUr8OeA4sHKJ79sJirOiWHNfD1swtvyVzsFZb6moiNwD3Ce/FzYCa3lQ\nU8blTH/uqpR2pSC6whzJ/lnSdqHUqhyp00000000000000000000\n-----END RSA PRIVATE KEY-----\n"} assert.Equal(t, wantSingle, certificateBundle) } func TestCertificates_LetsencryptPurchase(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/bingo.pizza/certificates/letsencrypt", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/purchaseLetsencryptCertificate/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateAttributes := LetsencryptCertificateAttributes{} certificateResponse, err := client.Certificates.PurchaseLetsencryptCertificate(context.Background(), "1010", "bingo.pizza", certificateAttributes) assert.NoError(t, err) certificatePurchase := certificateResponse.Data assert.Equal(t, int64(101967), certificatePurchase.ID) assert.Equal(t, int64(101967), certificatePurchase.CertificateID) } func TestCertificates_LetsencryptPurchaseWithAttributes(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/certificates/letsencrypt", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/purchaseLetsencryptCertificate/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"name": "www", "auto_renew": true, "alternate_names": []interface{}{"api.example.com", "status.example.com"}, "signature_algorithm": "RSA"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateAttributes := LetsencryptCertificateAttributes{Name: "www", AutoRenew: true, AlternateNames: []string{"api.example.com", "status.example.com"}, SignatureAlgorithm: "RSA"} _, err := client.Certificates.PurchaseLetsencryptCertificate(context.Background(), "1010", "example.com", certificateAttributes) assert.NoError(t, err) } func TestCertificates_LetsencryptIssue(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/bingo.pizza/certificates/letsencrypt/101967/issue", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/issueLetsencryptCertificate/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateResponse, err := client.Certificates.IssueLetsencryptCertificate(context.Background(), "1010", "bingo.pizza", 101967) assert.NoError(t, err) certificate := certificateResponse.Data assert.Equal(t, int64(101967), certificate.ID) assert.Equal(t, "www.bingo.pizza", certificate.CommonName) } func TestCertificates_LetsencryptPurchaseRenewal(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/bingo.pizza/certificates/letsencrypt/101967/renewals", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/purchaseRenewalLetsencryptCertificate/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateAttributes := LetsencryptCertificateAttributes{} certificateRenewalResponse, err := client.Certificates.PurchaseLetsencryptCertificateRenewal(context.Background(), "1010", "bingo.pizza", 101967, certificateAttributes) assert.NoError(t, err) certificateRenewal := certificateRenewalResponse.Data assert.Equal(t, int64(65082), certificateRenewal.ID) assert.Equal(t, int64(101967), certificateRenewal.OldCertificateID) assert.Equal(t, int64(101972), certificateRenewal.NewCertificateID) assert.Equal(t, "new", certificateRenewal.State) } func TestCertificates_LetsencryptPurchaseRenewalWithAttributes(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/bingo.pizza/certificates/letsencrypt/101967/renewals", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/purchaseRenewalLetsencryptCertificate/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"auto_renew": true, "signature_algorithm": "RSA"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateAttributes := LetsencryptCertificateAttributes{AutoRenew: true, SignatureAlgorithm: "RSA"} certificateRenewalResponse, err := client.Certificates.PurchaseLetsencryptCertificateRenewal(context.Background(), "1010", "bingo.pizza", 101967, certificateAttributes) assert.NoError(t, err) certificateRenewal := certificateRenewalResponse.Data assert.Equal(t, int64(65082), certificateRenewal.ID) assert.Equal(t, int64(101967), certificateRenewal.OldCertificateID) assert.Equal(t, int64(101972), certificateRenewal.NewCertificateID) assert.Equal(t, "new", certificateRenewal.State) } func TestCertificates_LetsencryptIssueRenewal(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/bingo.pizza/certificates/letsencrypt/101967/renewals/65082/issue", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/issueRenewalLetsencryptCertificate/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) certificateResponse, err := client.Certificates.IssueLetsencryptCertificateRenewal(context.Background(), "1010", "bingo.pizza", 101967, 65082) assert.NoError(t, err) certificate := certificateResponse.Data assert.Equal(t, int64(101972), certificate.ID) assert.Equal(t, "www.bingo.pizza", certificate.CommonName) } dnsimple-go-2.0.0/dnsimple/contacts.go 0000664 0000000 0000000 00000010374 14574024165 0017724 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // ContactsService handles communication with the contact related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/contacts/ type ContactsService struct { client *Client } // Contact represents a Contact in DNSimple. type Contact struct { ID int64 `json:"id,omitempty"` AccountID int64 `json:"account_id,omitempty"` Label string `json:"label,omitempty"` FirstName string `json:"first_name,omitempty"` LastName string `json:"last_name,omitempty"` JobTitle string `json:"job_title,omitempty"` Organization string `json:"organization_name,omitempty"` Address1 string `json:"address1,omitempty"` Address2 string `json:"address2,omitempty"` City string `json:"city,omitempty"` StateProvince string `json:"state_province,omitempty"` PostalCode string `json:"postal_code,omitempty"` Country string `json:"country,omitempty"` Phone string `json:"phone,omitempty"` Fax string `json:"fax,omitempty"` Email string `json:"email,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func contactPath(accountID string, contactID int64) (path string) { path = fmt.Sprintf("/%v/contacts", accountID) if contactID != 0 { path += fmt.Sprintf("/%v", contactID) } return } // ContactResponse represents a response from an API method that returns a Contact struct. type ContactResponse struct { Response Data *Contact `json:"data"` } // ContactsResponse represents a response from an API method that returns a collection of Contact struct. type ContactsResponse struct { Response Data []Contact `json:"data"` } // ListContacts list the contacts for an account. // // See https://developer.dnsimple.com/v2/contacts/#list func (s *ContactsService) ListContacts(ctx context.Context, accountID string, options *ListOptions) (*ContactsResponse, error) { path := versioned(contactPath(accountID, 0)) contactsResponse := &ContactsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, contactsResponse) if err != nil { return contactsResponse, err } contactsResponse.HTTPResponse = resp return contactsResponse, nil } // CreateContact creates a new contact. // // See https://developer.dnsimple.com/v2/contacts/#create func (s *ContactsService) CreateContact(ctx context.Context, accountID string, contactAttributes Contact) (*ContactResponse, error) { path := versioned(contactPath(accountID, 0)) contactResponse := &ContactResponse{} resp, err := s.client.post(ctx, path, contactAttributes, contactResponse) if err != nil { return nil, err } contactResponse.HTTPResponse = resp return contactResponse, nil } // GetContact fetches a contact. // // See https://developer.dnsimple.com/v2/contacts/#get func (s *ContactsService) GetContact(ctx context.Context, accountID string, contactID int64) (*ContactResponse, error) { path := versioned(contactPath(accountID, contactID)) contactResponse := &ContactResponse{} resp, err := s.client.get(ctx, path, contactResponse) if err != nil { return nil, err } contactResponse.HTTPResponse = resp return contactResponse, nil } // UpdateContact updates a contact. // // See https://developer.dnsimple.com/v2/contacts/#update func (s *ContactsService) UpdateContact(ctx context.Context, accountID string, contactID int64, contactAttributes Contact) (*ContactResponse, error) { path := versioned(contactPath(accountID, contactID)) contactResponse := &ContactResponse{} resp, err := s.client.patch(ctx, path, contactAttributes, contactResponse) if err != nil { return nil, err } contactResponse.HTTPResponse = resp return contactResponse, nil } // DeleteContact PERMANENTLY deletes a contact from the account. // // See https://developer.dnsimple.com/v2/contacts/#delete func (s *ContactsService) DeleteContact(ctx context.Context, accountID string, contactID int64) (*ContactResponse, error) { path := versioned(contactPath(accountID, contactID)) contactResponse := &ContactResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } contactResponse.HTTPResponse = resp return contactResponse, nil } dnsimple-go-2.0.0/dnsimple/contacts_test.go 0000664 0000000 0000000 00000011604 14574024165 0020760 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestContactPath(t *testing.T) { assert.Equal(t, "/1010/contacts", contactPath("1010", 0)) assert.Equal(t, "/1010/contacts/1", contactPath("1010", 1)) } func TestContactsService_List(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/contacts", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listContacts/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) contactsResponse, err := client.Contacts.ListContacts(context.Background(), "1010", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, contactsResponse.Pagination) contacts := contactsResponse.Data assert.Len(t, contacts, 2) assert.Equal(t, int64(1), contacts[0].ID) assert.Equal(t, "Default", contacts[0].Label) } func TestContactsService_List_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/contacts", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listContacts/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Contacts.ListContacts(context.Background(), "1010", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestContactsService_Create(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/contacts", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createContact/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"label": "Default"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" contactAttributes := Contact{Label: "Default"} contactResponse, err := client.Contacts.CreateContact(context.Background(), accountID, contactAttributes) assert.NoError(t, err) contact := contactResponse.Data assert.Equal(t, int64(1), contact.ID) assert.Equal(t, "Default", contact.Label) } func TestContactsService_Get(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/contacts/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getContact/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" contactID := int64(1) contactResponse, err := client.Contacts.GetContact(context.Background(), accountID, contactID) assert.NoError(t, err) contact := contactResponse.Data wantSingle := &Contact{ ID: 1, AccountID: 1010, Label: "Default", FirstName: "First", LastName: "User", JobTitle: "CEO", Organization: "Awesome Company", Address1: "Italian Street, 10", City: "Roma", StateProvince: "RM", PostalCode: "00100", Country: "IT", Phone: "+18001234567", Fax: "+18011234567", Email: "first@example.com", CreatedAt: "2016-01-19T20:50:26Z", UpdatedAt: "2016-01-19T20:50:26Z"} assert.Equal(t, wantSingle, contact) } func TestContactsService_Update(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/contacts/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateContact/success.http") testMethod(t, r, "PATCH") testHeaders(t, r) want := map[string]interface{}{"label": "Default"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) contactAttributes := Contact{Label: "Default"} accountID := "1010" contactID := int64(1) contactResponse, err := client.Contacts.UpdateContact(context.Background(), accountID, contactID, contactAttributes) assert.NoError(t, err) contact := contactResponse.Data assert.Equal(t, int64(1), contact.ID) assert.Equal(t, "Default", contact.Label) } func TestContactsService_Delete(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/contacts/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteContact/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" contactID := int64(1) _, err := client.Contacts.DeleteContact(context.Background(), accountID, contactID) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/dns_analytics.go 0000664 0000000 0000000 00000005611 14574024165 0020737 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // DnsAnalyticsService handles communication with the DNS Analytics related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/dns-analytics/ type DnsAnalyticsService struct { client *Client } // DnsAnalytics represents DNS Analytics data. type DnsAnalytics struct { Volume int64 ZoneName string Date string } type DnsAnalyticsQueryParameters struct { AccountId interface{} `json:"account_id"` StartDate string `json:"start_date"` EndDate string `json:"end_date"` Sort string `json:"sort"` Page int64 `json:"page"` PerPage int64 `json:"per_page"` Groupings string `json:"groupings"` } // RowAndHeaderData represents the special payload of `data` when it includes lists of `rows` and `headers`. type RowAndHeaderData struct { Rows [][]interface{} `json:"rows"` Headers []string `json:"headers"` } // DnsAnalyticsResponse represents a response from an API method that returns DnsAnalytics data. type DnsAnalyticsResponse struct { Response Data []DnsAnalytics RowAndHeaderData RowAndHeaderData `json:"data"` Query DnsAnalyticsQueryParameters `json:"query"` } func (r *DnsAnalyticsResponse) marshalData() { list := make([]DnsAnalytics, len(r.RowAndHeaderData.Rows)) for i, row := range r.RowAndHeaderData.Rows { var dataEntry DnsAnalytics for j, header := range r.RowAndHeaderData.Headers { switch header { case "volume": dataEntry.Volume = int64(row[j].(float64)) case "zone_name": dataEntry.ZoneName = row[j].(string) case "date": dataEntry.Date = row[j].(string) } } list[i] = dataEntry } r.Data = list } // DnsAnalyticsOptions specifies the optional parameters you can provide // to customize the DnsAnalyticsService.Query method. type DnsAnalyticsOptions struct { // Group results by the provided list of attributes separated by a comma Groupings *string `url:"groupings,omitempty"` // Only include results starting from the provided date in ISO8601 format StartDate *string `url:"start_date,omitempty"` // Only include results up to the provided date in ISO8601 format EndDate *string `url:"end_date,omitempty"` ListOptions } // Query gets DNS Analytics data for an account // // See https://developer.dnsimple.com/v2/dns-analytics/#query func (s *DnsAnalyticsService) Query(ctx context.Context, accountID int64, options *DnsAnalyticsOptions) (*DnsAnalyticsResponse, error) { path := versioned(fmt.Sprintf("/%v/dns_analytics", accountID)) dnsAnalyticsResponse := &DnsAnalyticsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, dnsAnalyticsResponse) if err != nil { return dnsAnalyticsResponse, err } dnsAnalyticsResponse.HTTPResponse = resp dnsAnalyticsResponse.marshalData() return dnsAnalyticsResponse, nil } dnsimple-go-2.0.0/dnsimple/dns_analytics_test.go 0000664 0000000 0000000 00000007447 14574024165 0022007 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestDnsAnalyticsService_Query(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1/dns_analytics", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/dnsAnalytics/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) dnsAnalyticsResponse, err := client.DnsAnalytics.Query(context.Background(), 1, nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 0, PerPage: 100, TotalPages: 1, TotalEntries: 93}, dnsAnalyticsResponse.Pagination) data := dnsAnalyticsResponse.Data assert.Len(t, data, 12) assert.Equal(t, int64(1200), data[0].Volume) assert.Equal(t, "2023-12-08", data[0].Date) assert.Equal(t, "bar.com", data[0].ZoneName) } func TestDnsAnalyticsService_Query_SupportsFiltering(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1/dns_analytics", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/dnsAnalytics/success.http") testMethod(t, r, "GET") testHeaders(t, r) expectedQueryParameters := url.Values{} expectedQueryParameters.Add("start_date", "2023-10-01") expectedQueryParameters.Add("end_date", "2023-11-01") testQuery(t, r, expectedQueryParameters) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, _ = client.DnsAnalytics.Query(context.Background(), 1, &DnsAnalyticsOptions{StartDate: String("2023-10-01"), EndDate: String("2023-11-01")}) } func TestDnsAnalyticsService_Query_SupportsSorting(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1/dns_analytics", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/dnsAnalytics/success.http") testMethod(t, r, "GET") testHeaders(t, r) expectedQueryParameters := url.Values{} expectedQueryParameters.Add("sort", "date:desc,zone_name:asc") testQuery(t, r, expectedQueryParameters) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) options := DnsAnalyticsOptions{} options.Sort = String("date:desc,zone_name:asc") _, _ = client.DnsAnalytics.Query(context.Background(), 1, &options) } func TestDnsAnalyticsService_Query_SupportsPagination(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1/dns_analytics", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/dnsAnalytics/success.http") testMethod(t, r, "GET") testHeaders(t, r) expectedQueryParameters := url.Values{} expectedQueryParameters.Add("page", "33") expectedQueryParameters.Add("per_page", "200") testQuery(t, r, expectedQueryParameters) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) options := DnsAnalyticsOptions{} options.Page = Int(33) options.PerPage = Int(200) _, _ = client.DnsAnalytics.Query(context.Background(), 1, &options) } func TestDnsAnalyticsService_Query_SupportsGrouping(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1/dns_analytics", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/dnsAnalytics/success.http") testMethod(t, r, "GET") testHeaders(t, r) expectedQueryParameters := url.Values{} expectedQueryParameters.Add("groupings", "zone_name,date") testQuery(t, r, expectedQueryParameters) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, _ = client.DnsAnalytics.Query(context.Background(), 1, &DnsAnalyticsOptions{Groupings: String("zone_name,date")}) } dnsimple-go-2.0.0/dnsimple/dnsimple.go 0000664 0000000 0000000 00000027623 14574024165 0017726 0 ustar 00root root 0000000 0000000 // Package dnsimple provides a client for the DNSimple API. // In order to use this package you will need a DNSimple account. package dnsimple import ( "bytes" "context" "encoding/json" "errors" "fmt" "io" "log" "net/http" "net/url" "reflect" "strconv" "strings" "time" "github.com/google/go-querystring/query" ) const ( // Version identifies the current library version. // This is a pro-forma convention given that Go dependencies // tends to be fetched directly from the repo. // It is also used in the user-agent identify the client. Version = "2.0.0" // defaultBaseURL to the DNSimple production API. defaultBaseURL = "https://api.dnsimple.com" // defaultUserAgent represents the base user agent // and is appended to every request. defaultUserAgent = "dnsimple-go/" + Version apiVersion = "v2" ) // Client represents a client to the DNSimple API. type Client struct { // httpClient is the underlying HTTP client // used to communicate with the API. httpClient *http.Client // BaseURL for API requests. // Defaults to the public DNSimple API, but can be set to a different endpoint (e.g. the sandbox). BaseURL string // UserAgent used when communicating with the DNSimple API. UserAgent string // Services used for talking to different parts of the DNSimple API. Identity *IdentityService Accounts *AccountsService Billing *BillingService Certificates *CertificatesService Contacts *ContactsService Domains *DomainsService DnsAnalytics *DnsAnalyticsService Oauth *OauthService Registrar *RegistrarService Services *ServicesService Templates *TemplatesService Tlds *TldsService VanityNameServers *VanityNameServersService Webhooks *WebhooksService Zones *ZonesService // Set to true to output debugging logs during API calls Debug bool } // ListOptions contains the common options you can pass to a List method // in order to control parameters such as pagination and page number. type ListOptions struct { // The page to return Page *int `url:"page,omitempty"` // The number of entries to return per page PerPage *int `url:"per_page,omitempty"` // The order criteria to sort the results. // The value is a comma-separated list of field[:direction], // eg. name | name:desc | name:desc,expiration:desc Sort *string `url:"sort,omitempty"` } // NewClient returns a new DNSimple API client. // // To authenticate you must provide an http.Client that will perform authentication // for you with one of the currently supported mechanisms: OAuth or HTTP Basic. func NewClient(httpClient *http.Client) *Client { c := &Client{httpClient: httpClient, BaseURL: defaultBaseURL} c.Identity = &IdentityService{client: c} c.Accounts = &AccountsService{client: c} c.Billing = &BillingService{client: c} c.Certificates = &CertificatesService{client: c} c.Contacts = &ContactsService{client: c} c.Domains = &DomainsService{client: c} c.DnsAnalytics = &DnsAnalyticsService{client: c} c.Oauth = &OauthService{client: c} c.Registrar = &RegistrarService{client: c} c.Services = &ServicesService{client: c} c.Templates = &TemplatesService{client: c} c.Tlds = &TldsService{client: c} c.VanityNameServers = &VanityNameServersService{client: c} c.Webhooks = &WebhooksService{client: c} c.Zones = &ZonesService{client: c} return c } // SetUserAgent overrides the default UserAgent. // // When a custom user agent is provided, the final user agent is the combination of the custom user agent // prepended by the default user agent. // // customAgentFlag dnsimple-go/1.0 func (c *Client) SetUserAgent(ua string) { c.UserAgent = ua } // formatUserAgent builds the final user agent to use for HTTP requests. // // If no custom user agent is provided, the default user agent is used. // // dnsimple-go/1.0 // // If a custom user agent is provided, the final user agent is the combination of the custom user agent // prepended by the default user agent. // // customAgentFlag dnsimple-go/1.0 func formatUserAgent(customUserAgent string) string { if customUserAgent == "" { return defaultUserAgent } return fmt.Sprintf("%s %s", customUserAgent, defaultUserAgent) } func versioned(path string) string { return fmt.Sprintf("/%s/%s", apiVersion, strings.Trim(path, "/")) } func (c *Client) get(ctx context.Context, path string, obj interface{}) (*http.Response, error) { return c.makeRequest(ctx, http.MethodGet, path, nil, obj, nil) } func (c *Client) post(ctx context.Context, path string, payload, obj interface{}) (*http.Response, error) { return c.makeRequest(ctx, http.MethodPost, path, payload, obj, nil) } func (c *Client) put(ctx context.Context, path string, payload, obj interface{}) (*http.Response, error) { return c.makeRequest(ctx, http.MethodPut, path, payload, obj, nil) } func (c *Client) patch(ctx context.Context, path string, payload, obj interface{}) (*http.Response, error) { return c.makeRequest(ctx, http.MethodPatch, path, payload, obj, nil) } func (c *Client) delete(ctx context.Context, path string, payload, obj interface{}) (*http.Response, error) { return c.makeRequest(ctx, http.MethodDelete, path, payload, obj, nil) } // Request executes an API request with the current client scope, and returns the response. func (c *Client) Request(ctx context.Context, method, path string, payload, obj interface{}, headers http.Header) (*http.Response, error) { return c.makeRequest(ctx, method, path, payload, obj, headers) } // makeRequest executes an API request and returns the HTTP response. // // The content pointed by payload is serialized and used as body of the request. // The HTTP response is JSON decoded and stored in the value pointed by obj. func (c *Client) makeRequest(ctx context.Context, method, path string, payload, obj interface{}, headers http.Header) (*http.Response, error) { req, err := c.newRequestWithHeaders(method, path, payload, headers) if err != nil { return nil, err } if c.Debug { log.Printf("Request (%v): %#v", req.URL, req) } resp, err := c.request(ctx, req, obj) if err != nil { return nil, err } if c.Debug { log.Printf("Response: %#v", resp) } return resp, nil } // newRequest creates an API request. // // The path is expected to be a relative path and will be resolved according to the BaseURL of the Client. // Paths should always be specified without a preceding slash. func (c *Client) newRequest(method, path string, payload interface{}) (*http.Request, error) { return c.newRequestWithHeaders(method, path, payload, nil) } // newRequestWithHeaders creates an API request, with custom headers. func (c *Client) newRequestWithHeaders(method, path string, payload interface{}, headers http.Header) (*http.Request, error) { url := c.BaseURL + path body := new(bytes.Buffer) if payload != nil { err := json.NewEncoder(body).Encode(payload) if err != nil { return nil, err } } req, err := http.NewRequest(method, url, body) if err != nil { return nil, err } combinedHeaders := make(http.Header) copyHeader(combinedHeaders, headers) req.Header = combinedHeaders req.Header.Set("Content-Type", "application/json") req.Header.Add("Accept", "application/json") req.Header.Add("User-Agent", formatUserAgent(c.UserAgent)) return req, err } // copyHeader copies all headers for `source` and sets them on `target`. // based on https://godoc.org/github.com/golang/gddo/httputil/header#Copy func copyHeader(target, source http.Header) { for k, vs := range source { target[k] = vs } } // request sends the HTTP request and returns the HTTP response. // // The HTTP response is JSON decoded and stored in the value pointed by obj, // or returned as an error if an API error has occurred. // If obj implements the io.Writer interface, the raw response body will be written to obj, // without attempting to decode it. func (c *Client) request(ctx context.Context, req *http.Request, obj interface{}) (*http.Response, error) { if ctx == nil { return nil, errors.New("context must be non-nil") } req = req.WithContext(ctx) resp, err := c.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() err = CheckResponse(resp) if err != nil { return resp, err } // If obj implements the io.Writer, // the response body is decoded into v. if obj != nil { if w, ok := obj.(io.Writer); ok { _, err = io.Copy(w, resp.Body) } else { var raw []byte raw, err = io.ReadAll(resp.Body) if err == nil { if len(raw) == 0 { // TODO Ignore empty body as temporary workaround for server sending Content-Type: application/json with an empty body. } else { err = json.Unmarshal(raw, obj) } } } } return resp, err } // A Response represents an API response. type Response struct { // HTTP response HTTPResponse *http.Response // If the response is paginated, the Pagination will store them. Pagination *Pagination `json:"pagination"` } // RateLimit returns the maximum amount of requests this account can send in an hour. func (r *Response) RateLimit() int { value, _ := strconv.Atoi(r.HTTPResponse.Header.Get("X-RateLimit-Limit")) return value } // RateLimitRemaining returns the remaining amount of requests this account can send within this hour window. func (r *Response) RateLimitRemaining() int { value, _ := strconv.Atoi(r.HTTPResponse.Header.Get("X-RateLimit-Remaining")) return value } // RateLimitReset returns when the throttling window will be reset for this account. func (r *Response) RateLimitReset() time.Time { value, _ := strconv.ParseInt(r.HTTPResponse.Header.Get("X-RateLimit-Reset"), 10, 64) return time.Unix(value, 0) } // Pagination represents the pagination information, if the response is paginated. type Pagination struct { CurrentPage int `json:"current_page"` PerPage int `json:"per_page"` TotalPages int `json:"total_pages"` TotalEntries int `json:"total_entries"` } // An ErrorResponse represents an API response that generated an error. type ErrorResponse struct { Response // human-readable message Message string `json:"message"` // detailed validation errors AttributeErrors map[string][]string `json:"errors"` } // Error implements the error interface. func (r *ErrorResponse) Error() string { return fmt.Sprintf("%v %v: %v %v", r.HTTPResponse.Request.Method, r.HTTPResponse.Request.URL, r.HTTPResponse.StatusCode, r.Message) } // CheckResponse checks the API response for errors, and returns them if present. // A response is considered an error if the status code is different than 2xx. Specific requests // may have additional requirements, but this is sufficient in most of the cases. func CheckResponse(resp *http.Response) error { if code := resp.StatusCode; 200 <= code && code <= 299 { return nil } errorResponse := &ErrorResponse{} errorResponse.HTTPResponse = resp err := json.NewDecoder(resp.Body).Decode(errorResponse) if err != nil { return err } return errorResponse } // addOptions adds the parameters in opt as URL query parameters to s. opt // must be a struct whose fields may contain "url" tags. func addURLQueryOptions(path string, options interface{}) (string, error) { opt := reflect.ValueOf(options) // options is a pointer // return if the value of the pointer is nil, if opt.Kind() == reflect.Ptr && opt.IsNil() { return path, nil } // append the options to the URL u, err := url.Parse(path) if err != nil { return path, err } qs, err := query.Values(options) if err != nil { return path, err } uqs := u.Query() for k := range qs { uqs.Set(k, qs.Get(k)) } u.RawQuery = uqs.Encode() return u.String(), nil } // Int is a helper routine that allocates a new int value // to store v and returns a pointer to it. func Int(v int) *int { return &v } // Int64 is a helper routine that allocates a new int64 value // to store v and returns a pointer to it. func Int64(v int64) *int64 { return &v } // String is a helper routine that allocates a new string value // to store v and returns a pointer to it. func String(v string) *string { return &v } dnsimple-go-2.0.0/dnsimple/dnsimple_test.go 0000664 0000000 0000000 00000011676 14574024165 0020766 0 ustar 00root root 0000000 0000000 package dnsimple import ( "bufio" "context" "encoding/json" "errors" "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" "net/url" "strings" "testing" "github.com/stretchr/testify/assert" ) var ( mux *http.ServeMux client *Client server *httptest.Server ) func setupMockServer() { mux = http.NewServeMux() server = httptest.NewServer(mux) client = NewClient(http.DefaultClient) client.BaseURL = server.URL } func teardownMockServer() { server.Close() } func testMethod(t *testing.T, r *http.Request, want string) { assert.Equal(t, want, r.Method) } func testQuery(t *testing.T, r *http.Request, want url.Values) { assert.Equal(t, want, r.URL.Query()) } func testHeaders(t *testing.T, r *http.Request) { assert.Equal(t, "application/json", r.Header.Get("Accept")) assert.Equal(t, defaultUserAgent, r.Header.Get("User-Agent")) } func getRequestJSON(r *http.Request) (map[string]interface{}, error) { var data map[string]interface{} body, _ := ioutil.ReadAll(r.Body) if err := json.Unmarshal(body, &data); err != nil { return nil, err } return data, nil } func testRequestJSON(t *testing.T, r *http.Request, values map[string]interface{}) { data, err := getRequestJSON(r) assert.NoError(t, err) assert.Equal(t, data, values) } func testRequestJSONArray(t *testing.T, r *http.Request, values []interface{}) { var data []interface{} body, _ := ioutil.ReadAll(r.Body) err := json.Unmarshal(body, &data) assert.NoError(t, err) assert.Equal(t, data, values) } func readHTTPFixture(t *testing.T, filename string) string { data, err := ioutil.ReadFile("../fixtures.http" + filename) assert.NoError(t, err) // Terrible hack // Some fixtures have \n and not \r\n // Terrible hack s := string(data[:]) s = strings.Replace(s, "Transfer-Encoding: chunked\n", "", -1) s = strings.Replace(s, "Transfer-Encoding: chunked\r\n", "", -1) return s } func httpResponseFixture(t *testing.T, filename string) *http.Response { resp, err := http.ReadResponse(bufio.NewReader(strings.NewReader(readHTTPFixture(t, filename))), nil) assert.NoError(t, err) // resp.Body.Close() return resp } func TestNewClient(t *testing.T) { c := NewClient(http.DefaultClient) assert.Equal(t, defaultBaseURL, c.BaseURL) } func TestClient_SetUserAgent(t *testing.T) { c := NewClient(http.DefaultClient) customAgent := "custom-agent/0.1" c.SetUserAgent(customAgent) assert.Equal(t, "custom-agent/0.1", c.UserAgent) req, _ := c.newRequest("GET", "/foo", nil) assert.Equal(t, "custom-agent/0.1 "+defaultUserAgent, req.Header.Get("User-Agent")) } func TestClient_NewRequest(t *testing.T) { c := NewClient(http.DefaultClient) c.BaseURL = "https://go.example.com" inURL, outURL := "/foo", "https://go.example.com/foo" req, _ := c.newRequest("GET", inURL, nil) assert.Equal(t, outURL, req.URL.String()) assert.Equal(t, defaultUserAgent, req.Header.Get("User-Agent")) } func TestClient_NewRequest_CustomUserAgent(t *testing.T) { c := NewClient(http.DefaultClient) c.UserAgent = "AwesomeClient" req, _ := c.newRequest("GET", "/", nil) assert.Equal(t, fmt.Sprintf("AwesomeClient %s", defaultUserAgent), req.Header.Get("User-Agent")) } type badObject struct { } func (o *badObject) MarshalJSON() ([]byte, error) { return nil, errors.New("Bad object is bad") } func TestClient_NewRequest_WithBody(t *testing.T) { c := NewClient(http.DefaultClient) c.BaseURL = "https://go.example.com/" inURL, _ := "foo", "https://go.example.com/v2/foo" badObject := badObject{} _, err := c.newRequest("GET", inURL, &badObject) assert.Error(t, err) } func TestClient_NotFound(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/notfound-certificate.http") w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.makeRequest(context.Background(), "POST", "/", nil, nil, nil) var got *ErrorResponse assert.ErrorAs(t, err, &got) assert.Empty(t, got.AttributeErrors) } func TestClient_ValidationError(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/validation-error.http") w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.makeRequest(context.Background(), "POST", "/", nil, nil, nil) var got *ErrorResponse assert.ErrorAs(t, err, &got) want := map[string][]string{ "address1": {"can't be blank"}, "city": {"can't be blank"}, "country": {"can't be blank"}, "email": {"can't be blank", "is an invalid email address"}, "first_name": {"can't be blank"}, "last_name": {"can't be blank"}, "phone": {"can't be blank", "is probably not a phone number"}, "postal_code": {"can't be blank"}, "state_province": {"can't be blank"}, } assert.Equal(t, want, got.AttributeErrors) } dnsimple-go-2.0.0/dnsimple/domains.go 0000664 0000000 0000000 00000007474 14574024165 0017547 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // DomainsService handles communication with the domain related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/domains/ type DomainsService struct { client *Client } // Domain represents a domain in DNSimple. type Domain struct { ID int64 `json:"id,omitempty"` AccountID int64 `json:"account_id,omitempty"` RegistrantID int64 `json:"registrant_id,omitempty"` Name string `json:"name,omitempty"` UnicodeName string `json:"unicode_name,omitempty"` Token string `json:"token,omitempty"` State string `json:"state,omitempty"` AutoRenew bool `json:"auto_renew,omitempty"` PrivateWhois bool `json:"private_whois,omitempty"` ExpiresAt string `json:"expires_at,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func domainPath(accountID string, domainIdentifier string) (path string) { path = fmt.Sprintf("/%v/domains", accountID) if domainIdentifier != "" { path += fmt.Sprintf("/%v", domainIdentifier) } return } // DomainResponse represents a response from an API method that returns a Domain struct. type DomainResponse struct { Response Data *Domain `json:"data"` } // DomainsResponse represents a response from an API method that returns a collection of Domain struct. type DomainsResponse struct { Response Data []Domain `json:"data"` } // DomainListOptions specifies the optional parameters you can provide // to customize the DomainsService.ListDomains method. type DomainListOptions struct { // Select domains where the name contains given string. NameLike *string `url:"name_like,omitempty"` // Select domains where the registrant matches given ID. RegistrantID *int `url:"registrant_id,omitempty"` ListOptions } // ListDomains lists the domains for an account. // // See https://developer.dnsimple.com/v2/domains/#list func (s *DomainsService) ListDomains(ctx context.Context, accountID string, options *DomainListOptions) (*DomainsResponse, error) { path := versioned(domainPath(accountID, "")) domainsResponse := &DomainsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, domainsResponse) if err != nil { return nil, err } domainsResponse.HTTPResponse = resp return domainsResponse, nil } // CreateDomain creates a new domain in the account. // // See https://developer.dnsimple.com/v2/domains/#create func (s *DomainsService) CreateDomain(ctx context.Context, accountID string, domainAttributes Domain) (*DomainResponse, error) { path := versioned(domainPath(accountID, "")) domainResponse := &DomainResponse{} resp, err := s.client.post(ctx, path, domainAttributes, domainResponse) if err != nil { return nil, err } domainResponse.HTTPResponse = resp return domainResponse, nil } // GetDomain fetches a domain. // // See https://developer.dnsimple.com/v2/domains/#get func (s *DomainsService) GetDomain(ctx context.Context, accountID string, domainIdentifier string) (*DomainResponse, error) { path := versioned(domainPath(accountID, domainIdentifier)) domainResponse := &DomainResponse{} resp, err := s.client.get(ctx, path, domainResponse) if err != nil { return nil, err } domainResponse.HTTPResponse = resp return domainResponse, nil } // DeleteDomain PERMANENTLY deletes a domain from the account. // // See https://developer.dnsimple.com/v2/domains/#delete func (s *DomainsService) DeleteDomain(ctx context.Context, accountID string, domainIdentifier string) (*DomainResponse, error) { path := versioned(domainPath(accountID, domainIdentifier)) domainResponse := &DomainResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } domainResponse.HTTPResponse = resp return domainResponse, nil } dnsimple-go-2.0.0/dnsimple/domains_collaborators.go 0000664 0000000 0000000 00000006347 14574024165 0022473 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // Collaborator represents a Collaborator in DNSimple. type Collaborator struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` DomainName string `json:"domain_name,omitempty"` UserID int64 `json:"user_id,omitempty"` UserEmail string `json:"user_email,omitempty"` Invitation bool `json:"invitation,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` AcceptedAt string `json:"accepted_at,omitempty"` } func collaboratorPath(accountID, domainIdentifier string, collaboratorID int64) (path string) { path = fmt.Sprintf("%v/collaborators", domainPath(accountID, domainIdentifier)) if collaboratorID != 0 { path += fmt.Sprintf("/%v", collaboratorID) } return } // CollaboratorAttributes represents Collaborator attributes for AddCollaborator operation. type CollaboratorAttributes struct { Email string `json:"email,omitempty"` } // CollaboratorResponse represents a response from an API method that returns a Collaborator struct. type CollaboratorResponse struct { Response Data *Collaborator `json:"data"` } // CollaboratorsResponse represents a response from an API method that returns a collection of Collaborator struct. type CollaboratorsResponse struct { Response Data []Collaborator `json:"data"` } // ListCollaborators list the collaborators for a domain. // // See https://developer.dnsimple.com/v2/domains/collaborators#list func (s *DomainsService) ListCollaborators(ctx context.Context, accountID, domainIdentifier string, options *ListOptions) (*CollaboratorsResponse, error) { path := versioned(collaboratorPath(accountID, domainIdentifier, 0)) collaboratorsResponse := &CollaboratorsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, collaboratorsResponse) if err != nil { return collaboratorsResponse, err } collaboratorsResponse.HTTPResponse = resp return collaboratorsResponse, nil } // AddCollaborator adds a new collaborator to the domain in the account. // // See https://developer.dnsimple.com/v2/domains/collaborators#add func (s *DomainsService) AddCollaborator(ctx context.Context, accountID string, domainIdentifier string, attributes CollaboratorAttributes) (*CollaboratorResponse, error) { path := versioned(collaboratorPath(accountID, domainIdentifier, 0)) collaboratorResponse := &CollaboratorResponse{} resp, err := s.client.post(ctx, path, attributes, collaboratorResponse) if err != nil { return nil, err } collaboratorResponse.HTTPResponse = resp return collaboratorResponse, nil } // RemoveCollaborator PERMANENTLY deletes a domain from the account. // // See https://developer.dnsimple.com/v2/domains/collaborators#remove func (s *DomainsService) RemoveCollaborator(ctx context.Context, accountID string, domainIdentifier string, collaboratorID int64) (*CollaboratorResponse, error) { path := versioned(collaboratorPath(accountID, domainIdentifier, collaboratorID)) collaboratorResponse := &CollaboratorResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } collaboratorResponse.HTTPResponse = resp return collaboratorResponse, nil } dnsimple-go-2.0.0/dnsimple/domains_collaborators_test.go 0000664 0000000 0000000 00000011257 14574024165 0023526 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestCollaboratorPath(t *testing.T) { assert.Equal(t, "/1010/domains/example.com/collaborators", collaboratorPath("1010", "example.com", 0)) assert.Equal(t, "/1010/domains/example.com/collaborators/2", collaboratorPath("1010", "example.com", 2)) } func TestDomainsService_ListCollaborators(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/collaborators", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCollaborators/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) collaboratorsResponse, err := client.Domains.ListCollaborators(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, collaboratorsResponse.Pagination) collaborators := collaboratorsResponse.Data assert.Len(t, collaborators, 2) assert.Equal(t, int64(100), collaborators[0].ID) assert.Equal(t, "example.com", collaborators[0].DomainName) assert.Equal(t, int64(999), collaborators[0].UserID) assert.False(t, collaborators[0].Invitation) } func TestDomainsService_ListCollaborators_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/collaborators", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listCollaborators/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.ListCollaborators(context.Background(), "1010", "example.com", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestDomainsService_AddCollaborator(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/collaborators", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/addCollaborator/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"email": "existing-user@example.com"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" domainID := "example.com" collaboratorAttributes := CollaboratorAttributes{Email: "existing-user@example.com"} collaboratorResponse, err := client.Domains.AddCollaborator(context.Background(), accountID, domainID, collaboratorAttributes) assert.NoError(t, err) collaborator := collaboratorResponse.Data assert.Equal(t, int64(100), collaborator.ID) assert.Equal(t, "example.com", collaborator.DomainName) assert.False(t, collaborator.Invitation) assert.Equal(t, "2016-10-07T08:53:41Z", collaborator.AcceptedAt) } func TestDomainsService_AddNonExistingCollaborator(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/collaborators", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/addCollaborator/invite-success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"email": "invited-user@example.com"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" domainID := "example.com" collaboratorAttributes := CollaboratorAttributes{Email: "invited-user@example.com"} collaboratorResponse, err := client.Domains.AddCollaborator(context.Background(), accountID, domainID, collaboratorAttributes) assert.NoError(t, err) collaborator := collaboratorResponse.Data assert.Equal(t, int64(101), collaborator.ID) assert.Equal(t, "example.com", collaborator.DomainName) assert.True(t, collaborator.Invitation) assert.Equal(t, "", collaborator.AcceptedAt) } func TestDomainsService_RemoveCollaborator(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/collaborators/100", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/removeCollaborator/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" domainID := "example.com" collaboratorID := int64(100) _, err := client.Domains.RemoveCollaborator(context.Background(), accountID, domainID, collaboratorID) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/domains_delegation_signer_records.go 0000664 0000000 0000000 00000007634 14574024165 0025030 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // DelegationSignerRecord represents a delegation signer record for a domain in DNSimple. type DelegationSignerRecord struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` Algorithm string `json:"algorithm"` Digest string `json:"digest,omitempty"` DigestType string `json:"digest_type,omitempty"` Keytag string `json:"keytag,omitempty"` PublicKey string `json:"public_key,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func delegationSignerRecordPath(accountID string, domainIdentifier string, dsRecordID int64) (path string) { path = fmt.Sprintf("%v/ds_records", domainPath(accountID, domainIdentifier)) if dsRecordID != 0 { path += fmt.Sprintf("/%v", dsRecordID) } return } // DelegationSignerRecordResponse represents a response from an API method that returns a DelegationSignerRecord struct. type DelegationSignerRecordResponse struct { Response Data *DelegationSignerRecord `json:"data"` } // DelegationSignerRecordsResponse represents a response from an API method that returns a DelegationSignerRecord struct. type DelegationSignerRecordsResponse struct { Response Data []DelegationSignerRecord `json:"data"` } // ListDelegationSignerRecords lists the delegation signer records for a domain. // // See https://developer.dnsimple.com/v2/domains/dnssec/#ds-record-list func (s *DomainsService) ListDelegationSignerRecords(ctx context.Context, accountID string, domainIdentifier string, options *ListOptions) (*DelegationSignerRecordsResponse, error) { path := versioned(delegationSignerRecordPath(accountID, domainIdentifier, 0)) dsRecordsResponse := &DelegationSignerRecordsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, dsRecordsResponse) if err != nil { return nil, err } dsRecordsResponse.HTTPResponse = resp return dsRecordsResponse, nil } // CreateDelegationSignerRecord creates a new delegation signer record. // // See https://developer.dnsimple.com/v2/domains/dnssec/#ds-record-create func (s *DomainsService) CreateDelegationSignerRecord(ctx context.Context, accountID string, domainIdentifier string, dsRecordAttributes DelegationSignerRecord) (*DelegationSignerRecordResponse, error) { path := versioned(delegationSignerRecordPath(accountID, domainIdentifier, 0)) dsRecordResponse := &DelegationSignerRecordResponse{} resp, err := s.client.post(ctx, path, dsRecordAttributes, dsRecordResponse) if err != nil { return nil, err } dsRecordResponse.HTTPResponse = resp return dsRecordResponse, nil } // GetDelegationSignerRecord fetches a delegation signer record. // // See https://developer.dnsimple.com/v2/domains/dnssec/#ds-record-get func (s *DomainsService) GetDelegationSignerRecord(ctx context.Context, accountID string, domainIdentifier string, dsRecordID int64) (*DelegationSignerRecordResponse, error) { path := versioned(delegationSignerRecordPath(accountID, domainIdentifier, dsRecordID)) dsRecordResponse := &DelegationSignerRecordResponse{} resp, err := s.client.get(ctx, path, dsRecordResponse) if err != nil { return nil, err } dsRecordResponse.HTTPResponse = resp return dsRecordResponse, nil } // DeleteDelegationSignerRecord PERMANENTLY deletes a delegation signer record // from the domain. // // See https://developer.dnsimple.com/v2/domains/dnssec/#ds-record-delete func (s *DomainsService) DeleteDelegationSignerRecord(ctx context.Context, accountID string, domainIdentifier string, dsRecordID int64) (*DelegationSignerRecordResponse, error) { path := versioned(delegationSignerRecordPath(accountID, domainIdentifier, dsRecordID)) dsRecordResponse := &DelegationSignerRecordResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } dsRecordResponse.HTTPResponse = resp return dsRecordResponse, nil } dnsimple-go-2.0.0/dnsimple/domains_delegation_signer_records_test.go 0000664 0000000 0000000 00000010575 14574024165 0026065 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestDelegationSignerRecordPath(t *testing.T) { assert.Equal(t, "/1010/domains/example.com/ds_records", delegationSignerRecordPath("1010", "example.com", 0)) assert.Equal(t, "/1010/domains/example.com/ds_records/2", delegationSignerRecordPath("1010", "example.com", 2)) } func TestDomainsService_ListDelegationSignerRecords(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/ds_records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listDelegationSignerRecords/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) dsRecordsResponse, err := client.Domains.ListDelegationSignerRecords(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 1}, dsRecordsResponse.Pagination) dsRecords := dsRecordsResponse.Data assert.Len(t, dsRecords, 1) assert.Equal(t, int64(24), dsRecords[0].ID) assert.Equal(t, "8", dsRecords[0].Algorithm) } func TestDomainsService_ListDelegationSignerRecords_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/ds_records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listDelegationSignerRecords/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.ListDelegationSignerRecords(context.Background(), "1010", "example.com", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestDomainsService_CreateDelegationSignerRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/ds_records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createDelegationSignerRecord/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"algorithm": "13", "digest": "ABC123", "digest_type": "2", "keytag": "1234"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) dsRecordAttributes := DelegationSignerRecord{Algorithm: "13", Digest: "ABC123", DigestType: "2", Keytag: "1234"} dsRecordResponse, err := client.Domains.CreateDelegationSignerRecord(context.Background(), "1010", "example.com", dsRecordAttributes) assert.NoError(t, err) dsRecord := dsRecordResponse.Data assert.Equal(t, int64(2), dsRecord.ID) assert.Equal(t, "13", dsRecord.Algorithm) } func TestDomainsService_GetDelegationSignerRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/ds_records/2", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDelegationSignerRecord/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) dsRecordResponse, err := client.Domains.GetDelegationSignerRecord(context.Background(), "1010", "example.com", 2) assert.NoError(t, err) dsRecord := dsRecordResponse.Data wantSingle := &DelegationSignerRecord{ ID: 24, DomainID: 1010, Algorithm: "8", DigestType: "2", Digest: "C1F6E04A5A61FBF65BF9DC8294C363CF11C89E802D926BDAB79C55D27BEFA94F", Keytag: "44620", PublicKey: "", CreatedAt: "2017-03-03T13:49:58Z", UpdatedAt: "2017-03-03T13:49:58Z"} assert.Equal(t, wantSingle, dsRecord) } func TestDomainsService_DeleteDelegationSignerRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/ds_records/2", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteDelegationSignerRecord/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.DeleteDelegationSignerRecord(context.Background(), "1010", "example.com", 2) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/domains_dnssec.go 0000664 0000000 0000000 00000004006 14574024165 0021072 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // Dnssec represents the current DNSSEC settings for a domain in DNSimple. type Dnssec struct { Enabled bool `json:"enabled"` } func dnssecPath(accountID string, domainIdentifier string) (path string) { path = fmt.Sprintf("%v/dnssec", domainPath(accountID, domainIdentifier)) return } // DnssecResponse represents a response from an API method that returns a Dnssec struct. type DnssecResponse struct { Response Data *Dnssec `json:"data"` } // EnableDnssec enables DNSSEC on the domain. // // See https://developer.dnsimple.com/v2/domains/dnssec/#enableDomainDnssec func (s *DomainsService) EnableDnssec(ctx context.Context, accountID string, domainIdentifier string) (*DnssecResponse, error) { path := versioned(dnssecPath(accountID, domainIdentifier)) dnssecResponse := &DnssecResponse{} resp, err := s.client.post(ctx, path, nil, dnssecResponse) if err != nil { return nil, err } dnssecResponse.HTTPResponse = resp return dnssecResponse, nil } // DisableDnssec disables DNSSEC on the domain. // // See https://developer.dnsimple.com/v2/domains/dnssec/#disableDomainDnssec func (s *DomainsService) DisableDnssec(ctx context.Context, accountID string, domainIdentifier string) (*DnssecResponse, error) { path := versioned(dnssecPath(accountID, domainIdentifier)) dnssecResponse := &DnssecResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } dnssecResponse.HTTPResponse = resp return dnssecResponse, nil } // GetDnssec retrieves the current status of DNSSEC on the domain. // // See https://developer.dnsimple.com/v2/domains/dnssec/#getDomainDnssec func (s *DomainsService) GetDnssec(ctx context.Context, accountID string, domainIdentifier string) (*DnssecResponse, error) { path := versioned(dnssecPath(accountID, domainIdentifier)) dnssecResponse := &DnssecResponse{} resp, err := s.client.get(ctx, path, dnssecResponse) if err != nil { return nil, err } dnssecResponse.HTTPResponse = resp return dnssecResponse, nil } dnsimple-go-2.0.0/dnsimple/domains_dnssec_test.go 0000664 0000000 0000000 00000003740 14574024165 0022135 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestDnssecPath(t *testing.T) { assert.Equal(t, "/1010/domains/example.com/dnssec", dnssecPath("1010", "example.com")) } func TestDomainsService_EnableDnssec(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/dnssec", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/enableDnssec/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" res, err := client.Domains.EnableDnssec(context.Background(), accountID, "example.com") assert.NoError(t, err) assert.Equal(t, &Dnssec{Enabled: true}, res.Data) } func TestDomainsService_DisableDnssec(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/dnssec", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/disableDnssec/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" res, err := client.Domains.DisableDnssec(context.Background(), accountID, "example.com") if assert.NoError(t, err) { assert.Nil(t, res.Data) } } func TestDomainsService_GetDnssec(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/dnssec", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDnssec/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) dnssecResponse, err := client.Domains.GetDnssec(context.Background(), "1010", "example.com") assert.NoError(t, err) assert.Equal(t, &Dnssec{Enabled: true}, dnssecResponse.Data) } dnsimple-go-2.0.0/dnsimple/domains_email_forwards.go 0000664 0000000 0000000 00000007536 14574024165 0022624 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // EmailForward represents an email forward in DNSimple. type EmailForward struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` // Deprecated: for requests, please use `AliasName` instead; for responses, please use `AliasEmail` instead. From string `json:"from,omitempty"` // WARNING: This is not set in responses, please use `AliasEmail` instead. AliasName string `json:"alias_name,omitempty"` // WARNING: This is not used by requests, please use `AliasName` instead. AliasEmail string `json:"alias_email,omitempty"` // Deprecated: please use `DestinationEmail` instead. To string `json:"to,omitempty"` DestinationEmail string `json:"destination_email,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func emailForwardPath(accountID string, domainIdentifier string, forwardID int64) (path string) { path = fmt.Sprintf("%v/email_forwards", domainPath(accountID, domainIdentifier)) if forwardID != 0 { path += fmt.Sprintf("/%v", forwardID) } return } // EmailForwardResponse represents a response from an API method that returns an EmailForward struct. type EmailForwardResponse struct { Response Data *EmailForward `json:"data"` } // EmailForwardsResponse represents a response from an API method that returns a collection of EmailForward struct. type EmailForwardsResponse struct { Response Data []EmailForward `json:"data"` } // ListEmailForwards lists the email forwards for a domain. // // See https://developer.dnsimple.com/v2/domains/email-forwards/#list func (s *DomainsService) ListEmailForwards(ctx context.Context, accountID string, domainIdentifier string, options *ListOptions) (*EmailForwardsResponse, error) { path := versioned(emailForwardPath(accountID, domainIdentifier, 0)) forwardsResponse := &EmailForwardsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, forwardsResponse) if err != nil { return nil, err } forwardsResponse.HTTPResponse = resp return forwardsResponse, nil } // CreateEmailForward creates a new email forward. // // See https://developer.dnsimple.com/v2/domains/email-forwards/#create func (s *DomainsService) CreateEmailForward(ctx context.Context, accountID string, domainIdentifier string, forwardAttributes EmailForward) (*EmailForwardResponse, error) { path := versioned(emailForwardPath(accountID, domainIdentifier, 0)) forwardResponse := &EmailForwardResponse{} resp, err := s.client.post(ctx, path, forwardAttributes, forwardResponse) if err != nil { return nil, err } forwardResponse.HTTPResponse = resp return forwardResponse, nil } // GetEmailForward fetches an email forward. // // See https://developer.dnsimple.com/v2/domains/email-forwards/#get func (s *DomainsService) GetEmailForward(ctx context.Context, accountID string, domainIdentifier string, forwardID int64) (*EmailForwardResponse, error) { path := versioned(emailForwardPath(accountID, domainIdentifier, forwardID)) forwardResponse := &EmailForwardResponse{} resp, err := s.client.get(ctx, path, forwardResponse) if err != nil { return nil, err } forwardResponse.HTTPResponse = resp return forwardResponse, nil } // DeleteEmailForward PERMANENTLY deletes an email forward from the domain. // // See https://developer.dnsimple.com/v2/domains/email-forwards/#delete func (s *DomainsService) DeleteEmailForward(ctx context.Context, accountID string, domainIdentifier string, forwardID int64) (*EmailForwardResponse, error) { path := versioned(emailForwardPath(accountID, domainIdentifier, forwardID)) forwardResponse := &EmailForwardResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } forwardResponse.HTTPResponse = resp return forwardResponse, nil } dnsimple-go-2.0.0/dnsimple/domains_email_forwards_test.go 0000664 0000000 0000000 00000010330 14574024165 0023645 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "regexp" "testing" "github.com/stretchr/testify/assert" ) var regexpEmail = regexp.MustCompile(`.+@.+`) func TestEmailForwardPath(t *testing.T) { assert.Equal(t, "/1010/domains/example.com/email_forwards", emailForwardPath("1010", "example.com", 0)) assert.Equal(t, "/1010/domains/example.com/email_forwards/2", emailForwardPath("1010", "example.com", 2)) } func TestDomainsService_EmailForwardsList(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/email_forwards", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listEmailForwards/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) forwardsResponse, err := client.Domains.ListEmailForwards(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, forwardsResponse.Pagination) forwards := forwardsResponse.Data assert.Len(t, forwards, 2) assert.Equal(t, int64(17702), forwards[0].ID) assert.Regexp(t, regexpEmail, forwards[0].From) } func TestDomainsService_EmailForwardsList_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/email_forwards", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listEmailForwards/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.ListEmailForwards(context.Background(), "1010", "example.com", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestDomainsService_CreateEmailForward(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/email_forwards", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createEmailForward/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"from": "me"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) forwardAttributes := EmailForward{From: "me"} forwardResponse, err := client.Domains.CreateEmailForward(context.Background(), "1010", "example.com", forwardAttributes) assert.NoError(t, err) forward := forwardResponse.Data assert.Equal(t, int64(41872), forward.ID) assert.Regexp(t, regexpEmail, forward.From) } func TestDomainsService_GetEmailForward(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/email_forwards/41872", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getEmailForward/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) forwardResponse, err := client.Domains.GetEmailForward(context.Background(), "1010", "example.com", 41872) assert.NoError(t, err) forward := forwardResponse.Data wantSingle := &EmailForward{ ID: 41872, DomainID: 235146, From: "example@dnsimple.xyz", AliasName: "", AliasEmail: "example@dnsimple.xyz", To: "example@example.com", DestinationEmail: "example@example.com", CreatedAt: "2021-01-25T13:54:40Z", UpdatedAt: "2021-01-25T13:54:40Z"} assert.Equal(t, wantSingle, forward) } func TestDomainsService_DeleteEmailForward(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/email_forwards/2", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteEmailForward/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.DeleteEmailForward(context.Background(), "1010", "example.com", 2) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/domains_pushes.go 0000664 0000000 0000000 00000006510 14574024165 0021124 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // DomainPush represents a domain push in DNSimple. type DomainPush struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` ContactID int64 `json:"contact_id,omitempty"` AccountID int64 `json:"account_id,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` AcceptedAt string `json:"accepted_at,omitempty"` } func domainPushPath(accountID string, pushID int64) (path string) { path = fmt.Sprintf("/%v/pushes", accountID) if pushID != 0 { path += fmt.Sprintf("/%v", pushID) } return } // DomainPushResponse represents a response from an API method that returns a DomainPush struct. type DomainPushResponse struct { Response Data *DomainPush `json:"data"` } // DomainPushesResponse represents a response from an API method that returns a collection of DomainPush struct. type DomainPushesResponse struct { Response Data []DomainPush `json:"data"` } // DomainPushAttributes represent a domain push payload (see initiate). type DomainPushAttributes struct { NewAccountEmail string `json:"new_account_email,omitempty"` ContactID int64 `json:"contact_id,omitempty"` } // InitiatePush initiate a new domain push. // // See https://developer.dnsimple.com/v2/domains/pushes/#initiateDomainPush func (s *DomainsService) InitiatePush(ctx context.Context, accountID, domainID string, pushAttributes DomainPushAttributes) (*DomainPushResponse, error) { path := versioned(fmt.Sprintf("/%v/pushes", domainPath(accountID, domainID))) pushResponse := &DomainPushResponse{} resp, err := s.client.post(ctx, path, pushAttributes, pushResponse) if err != nil { return nil, err } pushResponse.HTTPResponse = resp return pushResponse, nil } // ListPushes lists the pushes for an account. // // See https://developer.dnsimple.com/v2/domains/pushes/#listPushes func (s *DomainsService) ListPushes(ctx context.Context, accountID string, options *ListOptions) (*DomainPushesResponse, error) { path := versioned(domainPushPath(accountID, 0)) pushesResponse := &DomainPushesResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, pushesResponse) if err != nil { return nil, err } pushesResponse.HTTPResponse = resp return pushesResponse, nil } // AcceptPush accept a push for a domain. // // See https://developer.dnsimple.com/v2/domains/pushes/#acceptPush func (s *DomainsService) AcceptPush(ctx context.Context, accountID string, pushID int64, pushAttributes DomainPushAttributes) (*DomainPushResponse, error) { path := versioned(domainPushPath(accountID, pushID)) pushResponse := &DomainPushResponse{} resp, err := s.client.post(ctx, path, pushAttributes, nil) if err != nil { return nil, err } pushResponse.HTTPResponse = resp return pushResponse, nil } // RejectPush reject a push for a domain. // // See https://developer.dnsimple.com/v2/domains/pushes/#rejectPush func (s *DomainsService) RejectPush(ctx context.Context, accountID string, pushID int64) (*DomainPushResponse, error) { path := versioned(domainPushPath(accountID, pushID)) pushResponse := &DomainPushResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } pushResponse.HTTPResponse = resp return pushResponse, nil } dnsimple-go-2.0.0/dnsimple/domains_pushes_test.go 0000664 0000000 0000000 00000007070 14574024165 0022165 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestDomainPushPath(t *testing.T) { assert.Equal(t, "/1010/pushes", domainPushPath("1010", 0)) assert.Equal(t, "/1010/pushes/1", domainPushPath("1010", 1)) } func TestDomainsService_InitiatePush(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/pushes", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/initiatePush/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"new_account_email": "admin@target-account.test"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) pushAttributes := DomainPushAttributes{NewAccountEmail: "admin@target-account.test"} pushResponse, err := client.Domains.InitiatePush(context.Background(), "1010", "example.com", pushAttributes) assert.NoError(t, err) push := pushResponse.Data assert.Equal(t, int64(1), push.ID) assert.Equal(t, int64(2020), push.AccountID) } func TestDomainsService_DomainsPushesList(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/2020/pushes", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listPushes/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) pushesResponse, err := client.Domains.ListPushes(context.Background(), "2020", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, pushesResponse.Pagination) pushes := pushesResponse.Data assert.Len(t, pushes, 2) assert.Equal(t, int64(1), pushes[0].ID) assert.Equal(t, int64(2020), pushes[0].AccountID) } func TestDomainsService_DomainsPushesList_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/2020/pushes", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listPushes/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.ListPushes(context.Background(), "2020", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestDomainsService_AcceptPush(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/2020/pushes/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/acceptPush/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"contact_id": float64(2)} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) pushAttributes := DomainPushAttributes{ContactID: 2} _, err := client.Domains.AcceptPush(context.Background(), "2020", 1, pushAttributes) assert.NoError(t, err) } func TestDomainsService_RejectPush(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/2020/pushes/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/rejectPush/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.RejectPush(context.Background(), "2020", 1) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/domains_test.go 0000664 0000000 0000000 00000010400 14574024165 0020565 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestDomainPath(t *testing.T) { assert.Equal(t, "/1010/domains", domainPath("1010", "")) assert.Equal(t, "/1010/domains/example.com", domainPath("1010", "example.com")) } func TestDomainsService_ListDomains(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1385/domains", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listDomains/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) domainsResponse, err := client.Domains.ListDomains(context.Background(), "1385", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, domainsResponse.Pagination) domains := domainsResponse.Data assert.Len(t, domains, 2) assert.Equal(t, int64(181984), domains[0].ID) assert.Equal(t, "example-alpha.com", domains[0].Name) assert.Equal(t, "2021-06-05T02:15:00Z", domains[0].ExpiresAt) } func TestDomainsService_ListDomains_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listDomains/success.http") testQuery(t, r, url.Values{ "page": []string{"2"}, "per_page": []string{"20"}, "sort": []string{"name,expiration:desc"}, "name_like": []string{"example"}, "registrant_id": []string{"10"}, }) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Domains.ListDomains(context.Background(), "1010", &DomainListOptions{NameLike: String("example"), RegistrantID: Int(10), ListOptions: ListOptions{Page: Int(2), PerPage: Int(20), Sort: String("name,expiration:desc")}}) assert.NoError(t, err) } func TestDomainsService_CreateDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1385/domains", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createDomain/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"name": "example-beta.com"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1385" domainAttributes := Domain{Name: "example-beta.com"} domainResponse, err := client.Domains.CreateDomain(context.Background(), accountID, domainAttributes) assert.NoError(t, err) domain := domainResponse.Data assert.Equal(t, int64(181985), domain.ID) } func TestDomainsService_GetDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example-alpha.com", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomain/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" domainResponse, err := client.Domains.GetDomain(context.Background(), accountID, "example-alpha.com") assert.NoError(t, err) domain := domainResponse.Data wantSingle := &Domain{ ID: 181984, AccountID: 1385, RegistrantID: 2715, Name: "example-alpha.com", UnicodeName: "example-alpha.com", Token: "", State: "registered", AutoRenew: false, PrivateWhois: false, ExpiresAt: "2021-06-05T02:15:00Z", CreatedAt: "2020-06-04T19:15:14Z", UpdatedAt: "2020-06-04T19:15:21Z"} assert.Equal(t, wantSingle, domain) } func TestDomainsService_DeleteDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteDomain/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" _, err := client.Domains.DeleteDomain(context.Background(), accountID, "example.com") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/identity.go 0000664 0000000 0000000 00000002450 14574024165 0017733 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" ) // IdentityService handles communication with several authentication identity // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/identity/ type IdentityService struct { client *Client } // WhoamiData represents an authenticated context // that contains information about the current logged User and/or Account. type WhoamiData struct { User *User `json:"user,omitempty"` Account *Account `json:"account,omitempty"` } // WhoamiResponse represents a response from an API method that returns a Whoami struct. type WhoamiResponse struct { Response Data *WhoamiData `json:"data"` } // Whoami gets the current authenticate context. // // See https://developer.dnsimple.com/v2/whoami func (s *IdentityService) Whoami(ctx context.Context) (*WhoamiResponse, error) { path := versioned("/whoami") whoamiResponse := &WhoamiResponse{} resp, err := s.client.get(ctx, path, whoamiResponse) if err != nil { return nil, err } whoamiResponse.HTTPResponse = resp return whoamiResponse, nil } // Whoami is a state-less shortcut to client.Whoami() that returns only the relevant Data. func Whoami(ctx context.Context, c *Client) (data *WhoamiData, err error) { resp, err := c.Identity.Whoami(ctx) if resp != nil { data = resp.Data } return } dnsimple-go-2.0.0/dnsimple/identity_test.go 0000664 0000000 0000000 00000001540 14574024165 0020771 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestAuthService_Whoami(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/whoami", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/whoami/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) whoamiResponse, err := client.Identity.Whoami(context.Background()) assert.NoError(t, err) whoami := whoamiResponse.Data assert.Nil(t, whoami.User) assert.NotNil(t, whoami.Account) account := whoami.Account assert.Equal(t, int64(1), account.ID) assert.Equal(t, "example-account@example.com", account.Email) assert.Equal(t, "dnsimple-professional", account.PlanIdentifier) } dnsimple-go-2.0.0/dnsimple/live_test.go 0000664 0000000 0000000 00000012370 14574024165 0020102 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" "os" "testing" "time" "github.com/stretchr/testify/assert" "golang.org/x/oauth2" ) var ( dnsimpleLiveTest bool dnsimpleToken string dnsimpleBaseURL string dnsimpleClient *Client ) func init() { dnsimpleToken = os.Getenv("DNSIMPLE_TOKEN") dnsimpleBaseURL = os.Getenv("DNSIMPLE_BASE_URL") // Prevent people from wiping out their entire production account by mistake if dnsimpleBaseURL == "" { dnsimpleBaseURL = "https://api.sandbox.dnsimple.com" } if len(dnsimpleToken) > 0 { ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: dnsimpleToken}) tc := oauth2.NewClient(context.Background(), ts) dnsimpleLiveTest = true dnsimpleClient = NewClient(tc) dnsimpleClient.BaseURL = dnsimpleBaseURL dnsimpleClient.UserAgent = fmt.Sprintf("%v +livetest", dnsimpleClient.UserAgent) } } func TestLive_Whoami(t *testing.T) { if !dnsimpleLiveTest { t.Skip("skipping live test") } whoamiResponse, err := dnsimpleClient.Identity.Whoami(context.Background()) assert.NoError(t, err) fmt.Printf("RateLimit: %v/%v until %v\n", whoamiResponse.RateLimitRemaining(), whoamiResponse.RateLimit(), whoamiResponse.RateLimitReset()) whoami := whoamiResponse.Data fmt.Printf("Account: %+v\n", whoami.Account) fmt.Printf("User: %+v\n", whoami.User) } func TestLive_Domains(t *testing.T) { if !dnsimpleLiveTest { t.Skip("skipping live test") } whoami, err := Whoami(context.Background(), dnsimpleClient) if err != nil { t.Fatalf("Live Whoami() returned error: %v", err) } accountID := whoami.Account.ID domainsResponse, err := dnsimpleClient.Domains.ListDomains(context.Background(), fmt.Sprintf("%v", accountID), nil) assert.NoError(t, err) fmt.Printf("RateLimit: %v/%v until %v\n", domainsResponse.RateLimitRemaining(), domainsResponse.RateLimit(), domainsResponse.RateLimitReset()) fmt.Printf("Domains: %+v\n", domainsResponse.Data) } func TestLive_Registration(t *testing.T) { if !dnsimpleLiveTest { t.Skip("skipping live test") } whoami, err := Whoami(context.Background(), dnsimpleClient) assert.NoError(t, err) accountID := whoami.Account.ID // TODO: fetch the registrant randomly registerRequest := &RegisterDomainInput{RegistrantID: 2} registrationResponse, err := dnsimpleClient.Registrar.RegisterDomain(context.Background(), fmt.Sprintf("%v", accountID), fmt.Sprintf("example-%v.com", time.Now().Unix()), registerRequest) assert.NoError(t, err) fmt.Printf("RateLimit: %v/%v until %v\n", registrationResponse.RateLimitRemaining(), registrationResponse.RateLimit(), registrationResponse.RateLimitReset()) fmt.Printf("Domain: %+v\n", registrationResponse.Data) } func TestLive_Webhooks(t *testing.T) { if !dnsimpleLiveTest { t.Skip("skipping live test") } var err error var webhook *Webhook var webhookResponse *WebhookResponse var webhooksResponse *WebhooksResponse whoami, err := Whoami(context.Background(), dnsimpleClient) assert.NoError(t, err) accountID := whoami.Account.ID webhooksResponse, err = dnsimpleClient.Webhooks.ListWebhooks(context.Background(), fmt.Sprintf("%v", accountID), nil) assert.NoError(t, err) fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset()) fmt.Printf("Webhooks: %+v\n", webhooksResponse.Data) webhookAttributes := Webhook{URL: "https://livetest.test"} webhookResponse, err = dnsimpleClient.Webhooks.CreateWebhook(context.Background(), fmt.Sprintf("%v", accountID), webhookAttributes) assert.NoError(t, err) fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset()) fmt.Printf("Webhook: %+v\n", webhookResponse.Data) webhook = webhookResponse.Data webhookResponse, err = dnsimpleClient.Webhooks.DeleteWebhook(context.Background(), fmt.Sprintf("%v", accountID), webhook.ID) assert.NoError(t, err) fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset()) fmt.Printf("Webhook: %+v\n", webhookResponse.Data) } func TestLive_Zones(t *testing.T) { if !dnsimpleLiveTest { t.Skip("skipping live test") } whoami, err := Whoami(context.Background(), dnsimpleClient) assert.NoError(t, err) accountID := fmt.Sprintf("%v", whoami.Account.ID) domainResponse, err := dnsimpleClient.Domains.CreateDomain(context.Background(), accountID, Domain{Name: fmt.Sprintf("example-%v.test", time.Now().Unix())}) assert.NoError(t, err) zoneName := domainResponse.Data.Name recordName := fmt.Sprintf("%v", time.Now().Unix()) recordResponse, err := dnsimpleClient.Zones.CreateRecord(context.Background(), accountID, zoneName, ZoneRecordAttributes{Name: &recordName, Type: "TXT", Content: "Test"}) assert.NoError(t, err) fmt.Printf("ZoneRecord: %+v\n", recordResponse.Data) } func TestLive_Error(t *testing.T) { if !dnsimpleLiveTest { t.Skip("skipping live test") } whoami, err := Whoami(context.Background(), dnsimpleClient) assert.NoError(t, err) _, err = dnsimpleClient.Registrar.RegisterDomain(context.Background(), fmt.Sprintf("%v", whoami.Account.ID), fmt.Sprintf("example-%v.test", time.Now().Unix()), &RegisterDomainInput{}) assert.NoError(t, err) e := err.(*ErrorResponse) fmt.Println(e.Message) } dnsimple-go-2.0.0/dnsimple/oauth.go 0000664 0000000 0000000 00000007043 14574024165 0017225 0 ustar 00root root 0000000 0000000 package dnsimple import ( "encoding/json" "fmt" "net/http" "net/url" "strings" ) // GrantType is a string that identifies a particular grant type in the exchange request. type GrantType string const ( // AuthorizationCodeGrant is the type of access token request // for an Authorization Code Grant flow. // https://tools.ietf.org/html/rfc6749#section-4.1 AuthorizationCodeGrant = GrantType("authorization_code") ) // OauthService handles communication with the authorization related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/oauth/ type OauthService struct { client *Client } // AccessToken represents a DNSimple Oauth access token. type AccessToken struct { Token string `json:"access_token"` Type string `json:"token_type"` AccountID int64 `json:"account_id"` } // ExchangeAuthorizationRequest represents a request to exchange // an authorization code for an access token. // RedirectURI is optional, all the other fields are mandatory. type ExchangeAuthorizationRequest struct { Code string `json:"code"` ClientID string `json:"client_id"` ClientSecret string `json:"client_secret"` RedirectURI string `json:"redirect_uri,omitempty"` State string `json:"state,omitempty"` GrantType GrantType `json:"grant_type,omitempty"` } // ExchangeAuthorizationError represents a failed request to exchange // an authorization code for an access token. type ExchangeAuthorizationError struct { // HTTP response HTTPResponse *http.Response ErrorCode string `json:"error"` ErrorDescription string `json:"error_description"` } // Error implements the error interface. func (r *ExchangeAuthorizationError) Error() string { return fmt.Sprintf("%v %v: %v %v", r.HTTPResponse.Request.Method, r.HTTPResponse.Request.URL, r.ErrorCode, r.ErrorDescription) } // ExchangeAuthorizationForToken exchanges the short-lived authorization code for an access token // you can use to authenticate your API calls. func (s *OauthService) ExchangeAuthorizationForToken(authorization *ExchangeAuthorizationRequest) (*AccessToken, error) { path := versioned("/oauth/access_token") req, err := s.client.newRequest("POST", path, authorization) if err != nil { return nil, err } resp, err := s.client.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { errorResponse := &ExchangeAuthorizationError{} err = json.NewDecoder(resp.Body).Decode(errorResponse) if err != nil { return nil, err } errorResponse.HTTPResponse = resp return nil, errorResponse } accessToken := &AccessToken{} err = json.NewDecoder(resp.Body).Decode(accessToken) return accessToken, err } // AuthorizationOptions represents the option you can use to generate an authorization URL. type AuthorizationOptions struct { RedirectURI string `url:"redirect_uri,omitempty"` // A randomly generated string to verify the validity of the request. // Currently "state" is required by the DNSimple OAuth implementation, so you must specify it. State string `url:"state,omitempty"` } // AuthorizeURL generates the URL to authorize an user for an application via the OAuth2 flow. func (s *OauthService) AuthorizeURL(clientID string, options *AuthorizationOptions) string { uri, _ := url.Parse(strings.Replace(s.client.BaseURL, "api.", "", 1)) uri.Path = "/oauth/authorize" query := uri.Query() query.Add("client_id", clientID) query.Add("response_type", "code") uri.RawQuery = query.Encode() path, _ := addURLQueryOptions(uri.String(), options) return path } dnsimple-go-2.0.0/dnsimple/oauth_test.go 0000664 0000000 0000000 00000004552 14574024165 0020266 0 ustar 00root root 0000000 0000000 package dnsimple import ( "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestOauthService_ExchangeAuthorizationForToken(t *testing.T) { setupMockServer() defer teardownMockServer() code := "1234567890" clientID := "a1b2c3" clientSecret := "thisisasecret" mux.HandleFunc("/v2/oauth/access_token", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/oauthAccessToken/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"code": code, "client_id": clientID, "client_secret": clientSecret, "grant_type": "authorization_code"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) token, err := client.Oauth.ExchangeAuthorizationForToken(&ExchangeAuthorizationRequest{Code: code, ClientID: clientID, ClientSecret: clientSecret, GrantType: AuthorizationCodeGrant}) assert.NoError(t, err) want := &AccessToken{Token: "zKQ7OLqF5N1gylcJweA9WodA000BUNJD", Type: "Bearer", AccountID: int64(1)} assert.Equal(t, want, token) } func TestOauthService_ExchangeAuthorizationForToken_Error(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/oauth/access_token", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/oauthAccessToken/error-invalid-request.http") w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Oauth.ExchangeAuthorizationForToken(&ExchangeAuthorizationRequest{Code: "1234567890", ClientID: "a1b2c3", ClientSecret: "thisisasecret", GrantType: "authorization_code"}) if err == nil { t.Fatalf("Oauth.ExchangeAuthorizationForToken() expected to return an error") } var v *ExchangeAuthorizationError assert.ErrorAs(t, err, &v) assert.Equal(t, `Invalid "state": value doesn't match the "state" in the authorization request`, v.ErrorDescription) } func TestOauthService_AuthorizeURL(t *testing.T) { clientID := "a1b2c3" client.BaseURL = "https://api.host.test" assert.Equal(t, "https://host.test/oauth/authorize?client_id=a1b2c3&response_type=code", client.Oauth.AuthorizeURL(clientID, nil)) assert.Equal(t, "https://host.test/oauth/authorize?client_id=a1b2c3&response_type=code&state=randomstate", client.Oauth.AuthorizeURL(clientID, &AuthorizationOptions{State: "randomstate"})) } dnsimple-go-2.0.0/dnsimple/registrar.go 0000664 0000000 0000000 00000034604 14574024165 0020112 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // RegistrarService handles communication with the registrar related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/registrar/ type RegistrarService struct { client *Client } // DomainCheck represents the result of a domain check. type DomainCheck struct { Domain string `json:"domain"` Available bool `json:"available"` Premium bool `json:"premium"` } // DomainCheckResponse represents a response from a domain check request. type DomainCheckResponse struct { Response Data *DomainCheck `json:"data"` } // CheckDomain checks a domain name. // // See https://developer.dnsimple.com/v2/registrar/#check func (s *RegistrarService) CheckDomain(ctx context.Context, accountID string, domainName string) (*DomainCheckResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/check", accountID, domainName)) checkResponse := &DomainCheckResponse{} resp, err := s.client.get(ctx, path, checkResponse) if err != nil { return nil, err } checkResponse.HTTPResponse = resp return checkResponse, nil } // DomainPremiumPrice represents the premium price for a premium domain. type DomainPremiumPrice struct { // The domain premium price PremiumPrice string `json:"premium_price"` // The registrar action. // Possible values are registration|transfer|renewal Action string `json:"action"` } // DomainPremiumPriceResponse represents a response from a domain premium price request. type DomainPremiumPriceResponse struct { Response Data *DomainPremiumPrice `json:"data"` } // DomainPremiumPriceOptions specifies the optional parameters you can provide // to customize the RegistrarService.GetDomainPremiumPrice method. type DomainPremiumPriceOptions struct { Action string `url:"action,omitempty"` } // GetDomainPremiumPrice gets the premium price for a domain. // // Deprecated: GetDomainPremiumPrice has been deprecated, use GetDomainPrices instead. // // You must specify an action to get the price for. Valid actions are: // - registration // - transfer // - renewal // // See https://developer.dnsimple.com/v2/registrar/#premium-price func (s *RegistrarService) GetDomainPremiumPrice(ctx context.Context, accountID string, domainName string, options *DomainPremiumPriceOptions) (*DomainPremiumPriceResponse, error) { var err error path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/premium_price", accountID, domainName)) priceResponse := &DomainPremiumPriceResponse{} if options != nil { path, err = addURLQueryOptions(path, options) if err != nil { return nil, err } } resp, err := s.client.get(ctx, path, priceResponse) if err != nil { return nil, err } priceResponse.HTTPResponse = resp return priceResponse, nil } // DomainPrice represents the result of a domain prices call. type DomainPrice struct { Domain string `json:"domain"` Premium bool `json:"premium"` RegistrationPrice float64 `json:"registration_price"` RenewalPrice float64 `json:"renewal_price"` TransferPrice float64 `json:"transfer_price"` } // DomainPriceResponse represents a response from an API method that returns a DomainPrice struct. type DomainPriceResponse struct { Response Data *DomainPrice `json:"data"` } // GetDomainPrices get prices for a domain. // // See https://developer.dnsimple.com/v2/registrar/#getDomainPrices func (s *RegistrarService) GetDomainPrices(ctx context.Context, accountID string, domainName string) (*DomainPriceResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/prices", accountID, domainName)) pricesResponse := &DomainPriceResponse{} resp, err := s.client.get(ctx, path, pricesResponse) if err != nil { return nil, err } pricesResponse.HTTPResponse = resp return pricesResponse, nil } // DomainRegistration represents the result of a domain registration call. type DomainRegistration struct { ID int64 `json:"id"` DomainID int64 `json:"domain_id"` RegistrantID int64 `json:"registrant_id"` Period int `json:"period"` State string `json:"state"` AutoRenew bool `json:"auto_renew"` WhoisPrivacy bool `json:"whois_privacy"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // DomainRegistrationResponse represents a response from an API method that results in a domain registration. type DomainRegistrationResponse struct { Response Data *DomainRegistration `json:"data"` } // GetDomainRegistration gets the details of an existing domain registration. // // See https://developer.dnsimple.com/v2/registrar/#getDomainRegistration func (s *RegistrarService) GetDomainRegistration(ctx context.Context, accountID string, domainName string, domainRegistrationID string) (*DomainRegistrationResponse, error) { var err error path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/registrations/%v", accountID, domainName, domainRegistrationID)) res := &DomainRegistrationResponse{} resp, err := s.client.get(ctx, path, res) if err != nil { return nil, err } res.HTTPResponse = resp return res, nil } // RegisterDomainInput represents the attributes you can pass to a register API request. // Some attributes are mandatory. type RegisterDomainInput struct { // The ID of the Contact to use as registrant for the domain RegistrantID int `json:"registrant_id"` // Set to true to enable the whois privacy service. An extra cost may apply. // Default to false. EnableWhoisPrivacy bool `json:"whois_privacy,omitempty"` // Set to true to enable the auto-renewal of the domain. // Default to true. EnableAutoRenewal bool `json:"auto_renew,omitempty"` // Required by some TLDs. Use Tlds.GetTldExtendedAttributes() to get the required entries. ExtendedAttributes map[string]string `json:"extended_attributes,omitempty"` // Required as confirmation of the price, only if the domain is premium. PremiumPrice string `json:"premium_price,omitempty"` } // RegisterDomain registers a domain name. // // See https://developer.dnsimple.com/v2/registrar/#registerDomain func (s *RegistrarService) RegisterDomain(ctx context.Context, accountID string, domainName string, input *RegisterDomainInput) (*DomainRegistrationResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/registrations", accountID, domainName)) registrationResponse := &DomainRegistrationResponse{} // TODO: validate mandatory attributes RegistrantID resp, err := s.client.post(ctx, path, input, registrationResponse) if err != nil { return nil, err } registrationResponse.HTTPResponse = resp return registrationResponse, nil } // DomainTransfer represents the result of a domain transfer call. type DomainTransfer struct { ID int64 `json:"id"` DomainID int64 `json:"domain_id"` RegistrantID int64 `json:"registrant_id"` State string `json:"state"` AutoRenew bool `json:"auto_renew"` WhoisPrivacy bool `json:"whois_privacy"` StatusDescription string `json:"status_description"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // DomainTransferResponse represents a response from an API method that results in a domain transfer. type DomainTransferResponse struct { Response Data *DomainTransfer `json:"data"` } // TransferDomainInput represents the attributes you can pass to a transfer API request. // Some attributes are mandatory. type TransferDomainInput struct { // The ID of the Contact to use as registrant for the domain RegistrantID int `json:"registrant_id"` // The Auth-Code required to transfer the domain. // This is provided by the current registrar of the domain. AuthCode string `json:"auth_code,omitempty"` // Set to true to enable the whois privacy service. An extra cost may apply. // Default to false. EnableWhoisPrivacy bool `json:"whois_privacy,omitempty"` // Set to true to enable the auto-renewal of the domain. // Default to true. EnableAutoRenewal bool `json:"auto_renew,omitempty"` // Required by some TLDs. Use Tlds.GetTldExtendedAttributes() to get the required entries. ExtendedAttributes map[string]string `json:"extended_attributes,omitempty"` // Required as confirmation of the price, only if the domain is premium. PremiumPrice string `json:"premium_price,omitempty"` } // TransferDomain transfers a domain name. // // See https://developer.dnsimple.com/v2/registrar/#transferDomain func (s *RegistrarService) TransferDomain(ctx context.Context, accountID string, domainName string, input *TransferDomainInput) (*DomainTransferResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/transfers", accountID, domainName)) transferResponse := &DomainTransferResponse{} // TODO: validate mandatory attributes RegistrantID resp, err := s.client.post(ctx, path, input, transferResponse) if err != nil { return nil, err } transferResponse.HTTPResponse = resp return transferResponse, nil } // GetDomainTransfer fetches a domain transfer. // // See https://developer.dnsimple.com/v2/registrar/#getDomainTransfer func (s *RegistrarService) GetDomainTransfer(ctx context.Context, accountID string, domainName string, domainTransferID int64) (*DomainTransferResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/transfers/%v", accountID, domainName, domainTransferID)) transferResponse := &DomainTransferResponse{} resp, err := s.client.get(ctx, path, transferResponse) if err != nil { return nil, err } transferResponse.HTTPResponse = resp return transferResponse, nil } // CancelDomainTransfer cancels an in progress domain transfer. // // See https://developer.dnsimple.com/v2/registrar/#cancelDomainTransfer func (s *RegistrarService) CancelDomainTransfer(ctx context.Context, accountID string, domainName string, domainTransferID int64) (*DomainTransferResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/transfers/%v", accountID, domainName, domainTransferID)) transferResponse := &DomainTransferResponse{} resp, err := s.client.delete(ctx, path, nil, transferResponse) if err != nil { return nil, err } transferResponse.HTTPResponse = resp return transferResponse, nil } // DomainTransferOutResponse represents a response from an API method that results in a domain transfer out. type DomainTransferOutResponse struct { Response Data *Domain `json:"data"` } // TransferDomainOut prepares a domain for outbound transfer. // // See https://developer.dnsimple.com/v2/registrar/#authorizeDomainTransferOut func (s *RegistrarService) TransferDomainOut(ctx context.Context, accountID string, domainName string) (*DomainTransferOutResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/authorize_transfer_out", accountID, domainName)) transferResponse := &DomainTransferOutResponse{} resp, err := s.client.post(ctx, path, nil, nil) if err != nil { return nil, err } transferResponse.HTTPResponse = resp return transferResponse, nil } // DomainRenewal represents the result of a domain renewal call. type DomainRenewal struct { ID int64 `json:"id"` DomainID int64 `json:"domain_id"` Period int `json:"period"` State string `json:"state"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // DomainRenewalResponse represents a response from an API method that returns a domain renewal. type DomainRenewalResponse struct { Response Data *DomainRenewal `json:"data"` } // DomainRestore represents the result of a domain restore call. type DomainRestore struct { ID int64 `json:"id"` DomainID int64 `json:"domain_id"` State string `json:"state"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // DomainRestoreResponse represents a response from an API method that returns a domain restore. type DomainRestoreResponse struct { Response Data *DomainRestore `json:"data"` } // GetDomainRenewal gets the details of an existing domain renewal. // // See https://developer.dnsimple.com/v2/registrar/#getDomainRenewal func (s *RegistrarService) GetDomainRenewal(ctx context.Context, accountID string, domainName string, domainRenewalID string) (*DomainRenewalResponse, error) { var err error path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/renewals/%v", accountID, domainName, domainRenewalID)) res := &DomainRenewalResponse{} resp, err := s.client.get(ctx, path, res) if err != nil { return nil, err } res.HTTPResponse = resp return res, nil } // RenewDomainInput represents the attributes you can pass to a renew API request. // Some attributes are mandatory. type RenewDomainInput struct { // The number of years Period int `json:"period"` // Required as confirmation of the price, only if the domain is premium. PremiumPrice string `json:"premium_price,omitempty"` } // RenewDomain renews a domain name. // // See https://developer.dnsimple.com/v2/registrar/#renewDomain func (s *RegistrarService) RenewDomain(ctx context.Context, accountID string, domainName string, input *RenewDomainInput) (*DomainRenewalResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/renewals", accountID, domainName)) renewalResponse := &DomainRenewalResponse{} resp, err := s.client.post(ctx, path, input, renewalResponse) if err != nil { return nil, err } renewalResponse.HTTPResponse = resp return renewalResponse, nil } // RestoreDomain restores a domain name. // // See https://developer.dnsimple.com/v2/registrar/#renewDomain func (s *RegistrarService) RestoreDomain(ctx context.Context, accountID string, domainName string, input *RenewDomainInput) (*DomainRenewalResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/restores", accountID, domainName)) renewalResponse := &DomainRenewalResponse{} resp, err := s.client.post(ctx, path, input, renewalResponse) if err != nil { return nil, err } renewalResponse.HTTPResponse = resp return renewalResponse, nil } // GetDomainRestore gets the details of an existing domain restore. // // See https://developer.dnsimple.com/v2/registrar/#getDomainRestore func (s *RegistrarService) GetDomainRestore(ctx context.Context, accountID string, domainName string, domainRestoreID string) (*DomainRestoreResponse, error) { var err error path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/restores/%v", accountID, domainName, domainRestoreID)) res := &DomainRestoreResponse{} resp, err := s.client.get(ctx, path, res) if err != nil { return nil, err } res.HTTPResponse = resp return res, nil } dnsimple-go-2.0.0/dnsimple/registrar_auto_renewal.go 0000664 0000000 0000000 00000002233 14574024165 0022650 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // EnableDomainAutoRenewal enables auto-renewal for the domain. // // See https://developer.dnsimple.com/v2/registrar/auto-renewal/#enable func (s *RegistrarService) EnableDomainAutoRenewal(ctx context.Context, accountID string, domainName string) (*DomainResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/auto_renewal", accountID, domainName)) domainResponse := &DomainResponse{} resp, err := s.client.put(ctx, path, nil, nil) if err != nil { return nil, err } domainResponse.HTTPResponse = resp return domainResponse, nil } // DisableDomainAutoRenewal disables auto-renewal for the domain. // // See https://developer.dnsimple.com/v2/registrar/auto-renewal/#enable func (s *RegistrarService) DisableDomainAutoRenewal(ctx context.Context, accountID string, domainName string) (*DomainResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/auto_renewal", accountID, domainName)) domainResponse := &DomainResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } domainResponse.HTTPResponse = resp return domainResponse, nil } dnsimple-go-2.0.0/dnsimple/registrar_auto_renewal_test.go 0000664 0000000 0000000 00000002320 14574024165 0023704 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestRegistrarService_EnableDomainAutoRenewal(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/auto_renewal", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/enableDomainAutoRenewal/success.http") testMethod(t, r, "PUT") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) }) accountID := "1010" _, err := client.Registrar.EnableDomainAutoRenewal(context.Background(), accountID, "example.com") assert.NoError(t, err) } func TestRegistrarService_DisableDomainAutoRenewal(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/auto_renewal", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/disableDomainAutoRenewal/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) }) accountID := "1010" _, err := client.Registrar.DisableDomainAutoRenewal(context.Background(), accountID, "example.com") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/registrar_delegation.go 0000664 0000000 0000000 00000006035 14574024165 0022302 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // Delegation represents a list of name servers that correspond to a domain delegation. type Delegation []string // DelegationResponse represents a response from an API method that returns a delegation struct. type DelegationResponse struct { Response Data *Delegation `json:"data"` } // VanityDelegationResponse represents a response for vanity name server enable and disable operations. type VanityDelegationResponse struct { Response Data []VanityNameServer `json:"data"` } // GetDomainDelegation gets the current delegated name servers for the domain. // // See https://developer.dnsimple.com/v2/registrar/delegation/#get func (s *RegistrarService) GetDomainDelegation(ctx context.Context, accountID string, domainName string) (*DelegationResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/delegation", accountID, domainName)) delegationResponse := &DelegationResponse{} resp, err := s.client.get(ctx, path, delegationResponse) if err != nil { return nil, err } delegationResponse.HTTPResponse = resp return delegationResponse, nil } // ChangeDomainDelegation updates the delegated name severs for the domain. // // See https://developer.dnsimple.com/v2/registrar/delegation/#get func (s *RegistrarService) ChangeDomainDelegation(ctx context.Context, accountID string, domainName string, newDelegation *Delegation) (*DelegationResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/delegation", accountID, domainName)) delegationResponse := &DelegationResponse{} resp, err := s.client.put(ctx, path, newDelegation, delegationResponse) if err != nil { return nil, err } delegationResponse.HTTPResponse = resp return delegationResponse, nil } // ChangeDomainDelegationToVanity enables vanity name servers for the given domain. // // See https://developer.dnsimple.com/v2/registrar/delegation/#delegateToVanity func (s *RegistrarService) ChangeDomainDelegationToVanity(ctx context.Context, accountID string, domainName string, newDelegation *Delegation) (*VanityDelegationResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/delegation/vanity", accountID, domainName)) delegationResponse := &VanityDelegationResponse{} resp, err := s.client.put(ctx, path, newDelegation, delegationResponse) if err != nil { return nil, err } delegationResponse.HTTPResponse = resp return delegationResponse, nil } // ChangeDomainDelegationFromVanity disables vanity name servers for the given domain. // // See https://developer.dnsimple.com/v2/registrar/delegation/#dedelegateFromVanity func (s *RegistrarService) ChangeDomainDelegationFromVanity(ctx context.Context, accountID string, domainName string) (*VanityDelegationResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/delegation/vanity", accountID, domainName)) delegationResponse := &VanityDelegationResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } delegationResponse.HTTPResponse = resp return delegationResponse, nil } dnsimple-go-2.0.0/dnsimple/registrar_delegation_test.go 0000664 0000000 0000000 00000006450 14574024165 0023342 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestRegistrarService_GetDomainDelegation(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/delegation", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainDelegation/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) delegationResponse, err := client.Registrar.GetDomainDelegation(context.Background(), "1010", "example.com") assert.NoError(t, err) delegation := delegationResponse.Data wantSingle := &Delegation{"ns1.dnsimple.com", "ns2.dnsimple.com", "ns3.dnsimple.com", "ns4.dnsimple.com"} assert.Equal(t, wantSingle, delegation) } func TestRegistrarService_ChangeDomainDelegation(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/delegation", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/changeDomainDelegation/success.http") testMethod(t, r, "PUT") testHeaders(t, r) want := []interface{}{"ns1.dnsimple.com", "ns2.dnsimple.com"} testRequestJSONArray(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) newDelegation := &Delegation{"ns1.dnsimple.com", "ns2.dnsimple.com"} delegationResponse, err := client.Registrar.ChangeDomainDelegation(context.Background(), "1010", "example.com", newDelegation) assert.NoError(t, err) delegation := delegationResponse.Data wantSingle := &Delegation{"ns1.dnsimple.com", "ns2.dnsimple.com", "ns3.dnsimple.com", "ns4.dnsimple.com"} assert.Equal(t, wantSingle, delegation) } func TestRegistrarService_ChangeDomainDelegationToVanity(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/delegation/vanity", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/changeDomainDelegationToVanity/success.http") testMethod(t, r, "PUT") testHeaders(t, r) want := []interface{}{"ns1.example.com", "ns2.example.com"} testRequestJSONArray(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) newDelegation := &Delegation{"ns1.example.com", "ns2.example.com"} delegationResponse, err := client.Registrar.ChangeDomainDelegationToVanity(context.Background(), "1010", "example.com", newDelegation) assert.NoError(t, err) delegation := delegationResponse.Data[0].Name wantSingle := "ns1.example.com" assert.Equal(t, wantSingle, delegation) } func TestRegistrarService_ChangeDomainDelegationFromVanity(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/delegation/vanity", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/changeDomainDelegationFromVanity/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Registrar.ChangeDomainDelegationFromVanity(context.Background(), "1010", "example.com") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/registrar_domain_transfer_lock.go 0000664 0000000 0000000 00000003647 14574024165 0024360 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) type DomainTransferLock struct { Enabled bool `json:"enabled"` } type DomainTransferLockResponse struct { Response Data *DomainTransferLock `json:"data"` } // GetDomainTransferLock gets the domain transfer lock for a domain. // // See https://developer.dnsimple.com/v2/registrar/#getDomainTransferLock func (s *RegistrarService) GetDomainTransferLock(ctx context.Context, accountID string, domainIdentifier string) (*DomainTransferLockResponse, error) { path := versioned(fmt.Sprintf("%v/registrar/domains/%v/transfer_lock", accountID, domainIdentifier)) res := &DomainTransferLockResponse{} httpRes, err := s.client.get(ctx, path, res) if err != nil { return nil, err } res.HTTPResponse = httpRes return res, nil } // EnableDomainTransferLock gets the domain transfer lock for a domain. // // See https://developer.dnsimple.com/v2/registrar/#enableDomainTransferLock func (s *RegistrarService) EnableDomainTransferLock(ctx context.Context, accountID string, domainIdentifier string) (*DomainTransferLockResponse, error) { path := versioned(fmt.Sprintf("%v/registrar/domains/%v/transfer_lock", accountID, domainIdentifier)) res := &DomainTransferLockResponse{} httpRes, err := s.client.post(ctx, path, nil, res) if err != nil { return nil, err } res.HTTPResponse = httpRes return res, nil } // DisableDomainTransferLock gets the domain transfer lock for a domain. // // See https://developer.dnsimple.com/v2/registrar/#disableDomainTransferLock func (s *RegistrarService) DisableDomainTransferLock(ctx context.Context, accountID string, domainIdentifier string) (*DomainTransferLockResponse, error) { path := versioned(fmt.Sprintf("%v/registrar/domains/%v/transfer_lock", accountID, domainIdentifier)) res := &DomainTransferLockResponse{} httpRes, err := s.client.delete(ctx, path, nil, res) if err != nil { return nil, err } res.HTTPResponse = httpRes return res, nil } dnsimple-go-2.0.0/dnsimple/registrar_domain_transfer_lock_test.go 0000664 0000000 0000000 00000003734 14574024165 0025414 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestRegistrarService_GetDomainTransferLock(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/101/transfer_lock", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainTransferLock/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.GetDomainTransferLock(context.Background(), "1010", "101") assert.NoError(t, err) assert.Equal(t, res.Data, &DomainTransferLock{ Enabled: true, }) } func TestRegistrarService_EnableDomainTransferLock(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/101/transfer_lock", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/enableDomainTransferLock/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.EnableDomainTransferLock(context.Background(), "1010", "101") assert.NoError(t, err) assert.Equal(t, res.Data, &DomainTransferLock{ Enabled: true, }) } func TestRegistrarService_DisableDomainTransferLock(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/101/transfer_lock", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/disableDomainTransferLock/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.DisableDomainTransferLock(context.Background(), "1010", "101") assert.NoError(t, err) assert.Equal(t, res.Data, &DomainTransferLock{ Enabled: false, }) } dnsimple-go-2.0.0/dnsimple/registrar_registrant_changes.go 0000664 0000000 0000000 00000012653 14574024165 0024044 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) type CreateRegistrantChangeInput struct { DomainId string `json:"domain_id"` ContactId string `json:"contact_id"` ExtendedAttributes map[string]string `json:"extended_attributes"` } type RegistrantChange struct { Id int `json:"id"` AccountId int `json:"account_id"` ContactId int `json:"contact_id"` DomainId int `json:"domain_id"` // One of: "new", "pending", "cancelling", "cancelled", "completed". State string `json:"state"` ExtendedAttributes map[string]string `json:"extended_attributes"` RegistryOwnerChange bool `json:"registry_owner_change"` IrtLockLiftedBy string `json:"irt_lock_lifted_by"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } type RegistrantChangeResponse struct { Response Data *RegistrantChange `json:"data"` } type RegistrantChangesListResponse struct { Response Data []RegistrantChange `json:"data"` } type RegistrantChangeListOptions struct { // Only include results with a state field exactly matching the given string State *string `url:"state,omitempty"` // Only include results with a domain_id field exactly matching the given string DomainId *string `url:"domain_id,omitempty"` // Only include results with a contact_id field exactly matching the given string ContactId *string `url:"contact_id,omitempty"` ListOptions } type CheckRegistrantChangeInput struct { DomainId string `json:"domain_id"` ContactId string `json:"contact_id"` } type ExtendedAttribute struct { Name string `json:"name"` Description string `json:"description"` Required bool `json:"required"` Options []ExtendedAttributeOption `json:"options"` } type ExtendedAttributeOption struct { Title string `json:"title"` Value string `json:"value"` Description string `json:"description"` } type RegistrantChangeCheck struct { DomainId int `json:"domain_id"` ContactId int `json:"contact_id"` ExtendedAttributes []ExtendedAttribute `json:"extended_attributes"` RegistryOwnerChange bool `json:"registry_owner_change"` } type RegistrantChangeCheckResponse struct { Response Data *RegistrantChangeCheck `json:"data"` } type RegistrantChangeDeleteResponse struct { Response } // ListRegistrantChange lists registrant changes in the account. // // See https://developer.dnsimple.com/v2/registrar/#listRegistrantChanges func (s *RegistrarService) ListRegistrantChange(ctx context.Context, accountID string, options *RegistrantChangeListOptions) (*RegistrantChangesListResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/registrant_changes", accountID)) changeResponse := &RegistrantChangesListResponse{} resp, err := s.client.get(ctx, path, changeResponse) if err != nil { return nil, err } changeResponse.HTTPResponse = resp return changeResponse, nil } // CreateRegistrantChange starts a registrant change. // // See https://developer.dnsimple.com/v2/registrar/#createRegistrantChange func (s *RegistrarService) CreateRegistrantChange(ctx context.Context, accountID string, input *CreateRegistrantChangeInput) (*RegistrantChangeResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/registrant_changes", accountID)) changeResponse := &RegistrantChangeResponse{} resp, err := s.client.post(ctx, path, input, changeResponse) if err != nil { return nil, err } changeResponse.HTTPResponse = resp return changeResponse, nil } // CheckRegistrantChange retrieves the requirements of a registrant change. // // See https://developer.dnsimple.com/v2/registrar/#checkRegistrantChange func (s *RegistrarService) CheckRegistrantChange(ctx context.Context, accountID string, input *CheckRegistrantChangeInput) (*RegistrantChangeCheckResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/registrant_changes/check", accountID)) checkResponse := &RegistrantChangeCheckResponse{} resp, err := s.client.post(ctx, path, input, checkResponse) if err != nil { return nil, err } checkResponse.HTTPResponse = resp return checkResponse, nil } // GetRegistrantChange retrieves the details of an existing registrant change. // // See https://developer.dnsimple.com/v2/registrar/#getRegistrantChange func (s *RegistrarService) GetRegistrantChange(ctx context.Context, accountID string, registrantChange int) (*RegistrantChangeResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/registrant_changes/%v", accountID, registrantChange)) checkResponse := &RegistrantChangeResponse{} resp, err := s.client.get(ctx, path, checkResponse) if err != nil { return nil, err } checkResponse.HTTPResponse = resp return checkResponse, nil } // DeleteRegistrantChange cancels an ongoing registrant change from the account. // // See https://developer.dnsimple.com/v2/registrar/#deleteRegistrantChange func (s *RegistrarService) DeleteRegistrantChange(ctx context.Context, accountID string, registrantChange int) (*RegistrantChangeDeleteResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/registrant_changes/%v", accountID, registrantChange)) deleteResponse := &RegistrantChangeDeleteResponse{} resp, err := s.client.delete(ctx, path, nil, deleteResponse) if err != nil { return nil, err } deleteResponse.HTTPResponse = resp return deleteResponse, nil } dnsimple-go-2.0.0/dnsimple/registrar_registrant_changes_test.go 0000664 0000000 0000000 00000010664 14574024165 0025103 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestRegistrarService_ListRegistrantChanges(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/registrant_changes", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listRegistrantChanges/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.ListRegistrantChange(context.Background(), "1010", &RegistrantChangeListOptions{}) assert.NoError(t, err) changes := res.Data assert.Equal(t, changes[0], RegistrantChange{ Id: 101, AccountId: 101, DomainId: 101, ContactId: 101, State: "new", ExtendedAttributes: map[string]string{}, RegistryOwnerChange: true, IrtLockLiftedBy: "", CreatedAt: "2017-02-03T17:43:22Z", UpdatedAt: "2017-02-03T17:43:22Z", }) } func TestRegistrarService_CreateRegistrantChange(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/registrant_changes", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createRegistrantChange/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.CreateRegistrantChange(context.Background(), "1010", &CreateRegistrantChangeInput{ DomainId: "example.com", ContactId: "101", ExtendedAttributes: map[string]string{}, }) assert.NoError(t, err) change := res.Data assert.Equal(t, change, &RegistrantChange{ Id: 101, AccountId: 101, DomainId: 101, ContactId: 101, State: "new", ExtendedAttributes: map[string]string{}, RegistryOwnerChange: true, IrtLockLiftedBy: "", CreatedAt: "2017-02-03T17:43:22Z", UpdatedAt: "2017-02-03T17:43:22Z", }) } func TestRegistrarService_CheckRegistrantChange(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/registrant_changes/check", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkRegistrantChange/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.CheckRegistrantChange(context.Background(), "1010", &CheckRegistrantChangeInput{ DomainId: "example.com", ContactId: "101", }) assert.NoError(t, err) change := res.Data assert.Equal(t, change, &RegistrantChangeCheck{ DomainId: 101, ContactId: 101, ExtendedAttributes: make([]ExtendedAttribute, 0), RegistryOwnerChange: true, }) } func TestRegistrarService_GetRegistrantChange(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/registrant_changes/101", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getRegistrantChange/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) res, err := client.Registrar.GetRegistrantChange(context.Background(), "1010", 101) assert.NoError(t, err) change := res.Data assert.Equal(t, change, &RegistrantChange{ Id: 101, AccountId: 101, DomainId: 101, ContactId: 101, State: "new", ExtendedAttributes: map[string]string{}, RegistryOwnerChange: true, IrtLockLiftedBy: "", CreatedAt: "2017-02-03T17:43:22Z", UpdatedAt: "2017-02-03T17:43:22Z", }) } func TestRegistrarService_DeleteRegistrantChange(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/registrant_changes/101", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteRegistrantChange/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Registrar.DeleteRegistrantChange(context.Background(), "1010", 101) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/registrar_test.go 0000664 0000000 0000000 00000032313 14574024165 0021144 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestRegistrarService_CheckDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/check", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkDomain/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) checkResponse, err := client.Registrar.CheckDomain(context.Background(), "1010", "example.com") assert.NoError(t, err) check := checkResponse.Data assert.Equal(t, "ruby.codes", check.Domain) } func TestRegistrarService_GetDomainPremiumPrice(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/premium_price", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainPremiumPrice/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) priceResponse, err := client.Registrar.GetDomainPremiumPrice(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) price := priceResponse.Data assert.Equal(t, "109.00", price.PremiumPrice) } func TestRegistrarService_GetDomainPremiumPrice_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/premium_price", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainPremiumPrice/success.http") testQuery(t, r, url.Values{ "action": []string{"registration"}, }) testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Registrar.GetDomainPremiumPrice(context.Background(), "1010", "example.com", &DomainPremiumPriceOptions{Action: "registration"}) assert.NoError(t, err) } func TestRegistrarService_GetDomainPrices(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/bingo.pizza/prices", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainPrices/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) checkResponse, err := client.Registrar.GetDomainPrices(context.Background(), "1010", "bingo.pizza") assert.NoError(t, err) check := checkResponse.Data assert.Equal(t, "bingo.pizza", check.Domain) assert.True(t, check.Premium) assert.Equal(t, float64(20.0), check.RegistrationPrice) assert.Equal(t, float64(20.0), check.RenewalPrice) assert.Equal(t, float64(20.0), check.TransferPrice) } func TestRegistrarService_GetDomainRegistration(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/bingo.pizza/registrations/361", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainRegistration/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) checkResponse, err := client.Registrar.GetDomainRegistration(context.Background(), "1010", "bingo.pizza", "361") assert.NoError(t, err) check := checkResponse.Data assert.Equal(t, check.ID, int64(361)) assert.Equal(t, check.DomainID, int64(104040)) assert.Equal(t, check.RegistrantID, int64(2715)) assert.Equal(t, check.Period, 1) assert.Equal(t, check.State, "registering") assert.Equal(t, check.AutoRenew, false) assert.Equal(t, check.WhoisPrivacy, false) assert.Equal(t, check.CreatedAt, "2023-01-27T17:44:32Z") assert.Equal(t, check.UpdatedAt, "2023-01-27T17:44:40Z") } func TestRegistrarService_GetDomainRenewal(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/bingo.pizza/renewals/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainRenewal/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) checkResponse, err := client.Registrar.GetDomainRenewal(context.Background(), "1010", "bingo.pizza", "1") assert.NoError(t, err) check := checkResponse.Data assert.Equal(t, check.ID, int64(1)) assert.Equal(t, check.DomainID, int64(999)) assert.Equal(t, check.Period, 1) assert.Equal(t, check.State, "renewed") assert.Equal(t, check.CreatedAt, "2016-12-09T19:46:45Z") assert.Equal(t, check.UpdatedAt, "2016-12-12T19:46:45Z") } func TestRegistrarService_RegisterDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/registrations", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/registerDomain/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"registrant_id": float64(2)} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) registerRequest := &RegisterDomainInput{RegistrantID: 2} registrationResponse, err := client.Registrar.RegisterDomain(context.Background(), "1010", "example.com", registerRequest) assert.NoError(t, err) registration := registrationResponse.Data assert.Equal(t, int64(1), registration.ID) assert.Equal(t, int64(999), registration.DomainID) } func TestRegistrarService_RegisterDomain_ExtendedAttributes(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/registrations", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/registerDomain/success.http") data, _ := getRequestJSON(r) if want, got := map[string]interface{}{"att1": "val1", "att2": "val2"}, data["extended_attributes"]; !reflect.DeepEqual(want, got) { t.Errorf("RegisterDomain() incorrect extended attributes payload, expected `%v`, got `%v`", want, got) } w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) registerRequest := &RegisterDomainInput{RegistrantID: 2, ExtendedAttributes: map[string]string{"att1": "val1", "att2": "val2"}} _, err := client.Registrar.RegisterDomain(context.Background(), "1010", "example.com", registerRequest) assert.NoError(t, err) } func TestRegistrarService_TransferDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/transfers", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/transferDomain/success.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"registrant_id": float64(2), "auth_code": "x1y2z3"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) transferRequest := &TransferDomainInput{RegistrantID: 2, AuthCode: "x1y2z3"} transferResponse, err := client.Registrar.TransferDomain(context.Background(), "1010", "example.com", transferRequest) assert.NoError(t, err) transfer := transferResponse.Data assert.Equal(t, int64(1), transfer.ID) assert.Equal(t, int64(999), transfer.DomainID) } func TestRegistrarService_TransferDomain_ExtendedAttributes(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/transfers", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/transferDomain/success.http") data, _ := getRequestJSON(r) if want, got := map[string]interface{}{"att1": "val1", "att2": "val2"}, data["extended_attributes"]; !reflect.DeepEqual(want, got) { t.Errorf("TransferDomain() incorrect extended attributes payload, expected `%v`, got `%v`", want, got) } w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) transferRequest := &TransferDomainInput{RegistrantID: 2, AuthCode: "x1y2z3", ExtendedAttributes: map[string]string{"att1": "val1", "att2": "val2"}} _, err := client.Registrar.TransferDomain(context.Background(), "1010", "example.com", transferRequest) assert.NoError(t, err) } func TestRegistrarService_TransferDomainOut(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/authorize_transfer_out", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/authorizeDomainTransferOut/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Registrar.TransferDomainOut(context.Background(), "1010", "example.com") assert.NoError(t, err) } func TestRegistrarService_GetDomainTransfer(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/transfers/361", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainTransfer/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) io.Copy(w, httpResponse.Body) }) domainTransferResponse, err := client.Registrar.GetDomainTransfer(context.Background(), "1010", "example.com", 361) assert.NoError(t, err) domainTransfer := domainTransferResponse.Data wantSingle := &DomainTransfer{ ID: int64(361), DomainID: int64(182245), RegistrantID: int64(2715), State: "cancelled", AutoRenew: false, WhoisPrivacy: false, StatusDescription: "Canceled by customer", CreatedAt: "2020-06-05T18:08:00Z", UpdatedAt: "2020-06-05T18:10:01Z"} assert.Equal(t, wantSingle, domainTransfer) } func TestRegistrarService_CancelDomainTransfer(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/transfers/361", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/cancelDomainTransfer/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) io.Copy(w, httpResponse.Body) }) domainTransferResponse, err := client.Registrar.CancelDomainTransfer(context.Background(), "1010", "example.com", 361) assert.NoError(t, err) domainTransfer := domainTransferResponse.Data wantSingle := &DomainTransfer{ ID: int64(361), DomainID: int64(182245), RegistrantID: int64(2715), State: "transferring", AutoRenew: false, WhoisPrivacy: false, StatusDescription: "", CreatedAt: "2020-06-05T18:08:00Z", UpdatedAt: "2020-06-05T18:08:04Z"} assert.Equal(t, wantSingle, domainTransfer) } func TestRegistrarService_RenewDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/renewals", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/renewDomain/success.http") testMethod(t, r, "POST") testHeaders(t, r) //want := map[string]interface{}{} //testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) renewalResponse, err := client.Registrar.RenewDomain(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) renewal := renewalResponse.Data assert.Equal(t, int64(1), renewal.ID) assert.Equal(t, int64(999), renewal.DomainID) } func TestRegistrarService_RestoreDomain(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/restores", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/restoreDomain/success.http") testMethod(t, r, "POST") testHeaders(t, r) //want := map[string]interface{}{} //testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) restoreResponse, err := client.Registrar.RestoreDomain(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) restore := restoreResponse.Data assert.Equal(t, int64(43), restore.ID) assert.Equal(t, int64(214), restore.DomainID) } func TestRegistrarService_GetDomainRestore(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/bingo.pizza/restores/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getDomainRestore/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) checkResponse, err := client.Registrar.GetDomainRestore(context.Background(), "1010", "bingo.pizza", "1") assert.NoError(t, err) check := checkResponse.Data assert.Equal(t, check.ID, int64(1)) assert.Equal(t, check.DomainID, int64(999)) assert.Equal(t, check.State, "restored") assert.Equal(t, check.CreatedAt, "2016-12-09T19:46:45Z") assert.Equal(t, check.UpdatedAt, "2016-12-12T19:46:45Z") } dnsimple-go-2.0.0/dnsimple/registrar_whois_privacy.go 0000664 0000000 0000000 00000007176 14574024165 0023064 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // WhoisPrivacy represents a whois privacy in DNSimple. type WhoisPrivacy struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` Enabled bool `json:"enabled,omitempty"` ExpiresOn string `json:"expires_on,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // WhoisPrivacyRenewal represents a whois privacy renewal in DNSimple. type WhoisPrivacyRenewal struct { ID int64 `json:"id,omitempty"` DomainID int64 `json:"domain_id,omitempty"` WhoisPrivacyID int64 `json:"whois_privacy_id,omitempty"` State string `json:"string,omitempty"` Enabled bool `json:"enabled,omitempty"` ExpiresOn string `json:"expires_on,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // WhoisPrivacyResponse represents a response from an API method that returns a WhoisPrivacy struct. type WhoisPrivacyResponse struct { Response Data *WhoisPrivacy `json:"data"` } // WhoisPrivacyRenewalResponse represents a response from an API method that returns a WhoisPrivacyRenewal struct. type WhoisPrivacyRenewalResponse struct { Response Data *WhoisPrivacyRenewal `json:"data"` } // GetWhoisPrivacy gets the whois privacy for the domain. // // See https://developer.dnsimple.com/v2/registrar/whois-privacy/#get func (s *RegistrarService) GetWhoisPrivacy(ctx context.Context, accountID string, domainName string) (*WhoisPrivacyResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/whois_privacy", accountID, domainName)) privacyResponse := &WhoisPrivacyResponse{} resp, err := s.client.get(ctx, path, privacyResponse) if err != nil { return nil, err } privacyResponse.HTTPResponse = resp return privacyResponse, nil } // EnableWhoisPrivacy enables the whois privacy for the domain. // // See https://developer.dnsimple.com/v2/registrar/whois-privacy/#enable func (s *RegistrarService) EnableWhoisPrivacy(ctx context.Context, accountID string, domainName string) (*WhoisPrivacyResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/whois_privacy", accountID, domainName)) privacyResponse := &WhoisPrivacyResponse{} resp, err := s.client.put(ctx, path, nil, privacyResponse) if err != nil { return nil, err } privacyResponse.HTTPResponse = resp return privacyResponse, nil } // DisableWhoisPrivacy disables the whois privacy for the domain. // // See https://developer.dnsimple.com/v2/registrar/whois-privacy/#enable func (s *RegistrarService) DisableWhoisPrivacy(ctx context.Context, accountID string, domainName string) (*WhoisPrivacyResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/whois_privacy", accountID, domainName)) privacyResponse := &WhoisPrivacyResponse{} resp, err := s.client.delete(ctx, path, nil, privacyResponse) if err != nil { return nil, err } privacyResponse.HTTPResponse = resp return privacyResponse, nil } // RenewWhoisPrivacy renews the whois privacy for the domain. // // See https://developer.dnsimple.com/v2/registrar/whois-privacy/#renew func (s *RegistrarService) RenewWhoisPrivacy(ctx context.Context, accountID string, domainName string) (*WhoisPrivacyRenewalResponse, error) { path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/whois_privacy/renewals", accountID, domainName)) privacyRenewalResponse := &WhoisPrivacyRenewalResponse{} resp, err := s.client.post(ctx, path, nil, privacyRenewalResponse) if err != nil { return nil, err } privacyRenewalResponse.HTTPResponse = resp return privacyRenewalResponse, nil } dnsimple-go-2.0.0/dnsimple/registrar_whois_privacy_test.go 0000664 0000000 0000000 00000005755 14574024165 0024124 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestRegistrarService_GetWhoisPrivacy(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/whois_privacy", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getWhoisPrivacy/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) privacyResponse, err := client.Registrar.GetWhoisPrivacy(context.Background(), "1010", "example.com") assert.NoError(t, err) privacy := privacyResponse.Data wantSingle := &WhoisPrivacy{ ID: 1, DomainID: 2, Enabled: true, ExpiresOn: "2017-02-13", CreatedAt: "2016-02-13T14:34:50Z", UpdatedAt: "2016-02-13T14:34:52Z"} assert.Equal(t, wantSingle, privacy) } func TestRegistrarService_EnableWhoisPrivacy(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/whois_privacy", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/enableWhoisPrivacy/success.http") testMethod(t, r, "PUT") testHeaders(t, r) //want := map[string]interface{}{} //testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) privacyResponse, err := client.Registrar.EnableWhoisPrivacy(context.Background(), "1010", "example.com") assert.NoError(t, err) privacy := privacyResponse.Data assert.Equal(t, int64(1), privacy.ID) } func TestRegistrarService_DisableWhoisPrivacy(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/whois_privacy", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/disableWhoisPrivacy/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) //want := map[string]interface{}{} //testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) privacyResponse, err := client.Registrar.DisableWhoisPrivacy(context.Background(), "1010", "example.com") assert.NoError(t, err) privacy := privacyResponse.Data assert.Equal(t, int64(1), privacy.ID) } func TestRegistrarService_RenewWhoisPrivacy(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/registrar/domains/example.com/whois_privacy/renewals", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/renewWhoisPrivacy/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) privacyRenewalResponse, err := client.Registrar.RenewWhoisPrivacy(context.Background(), "1010", "example.com") assert.NoError(t, err) privacyRenewal := privacyRenewalResponse.Data assert.Equal(t, int64(1), privacyRenewal.ID) } dnsimple-go-2.0.0/dnsimple/services.go 0000664 0000000 0000000 00000005550 14574024165 0017731 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // ServicesService handles communication with the service related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/services/ type ServicesService struct { client *Client } // Service represents a Service in DNSimple. type Service struct { ID int64 `json:"id,omitempty"` SID string `json:"sid,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` SetupDescription string `json:"setup_description,omitempty"` RequiresSetup bool `json:"requires_setup,omitempty"` DefaultSubdomain string `json:"default_subdomain,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` Settings []ServiceSetting `json:"settings,omitempty"` } // ServiceSetting represents a single group of settings for a DNSimple Service. type ServiceSetting struct { Name string `json:"name,omitempty"` Label string `json:"label,omitempty"` Append string `json:"append,omitempty"` Description string `json:"description,omitempty"` Example string `json:"example,omitempty"` Password bool `json:"password,omitempty"` } func servicePath(serviceIdentifier string) (path string) { path = "/services" if serviceIdentifier != "" { path += fmt.Sprintf("/%v", serviceIdentifier) } return } // ServiceResponse represents a response from an API method that returns a Service struct. type ServiceResponse struct { Response Data *Service `json:"data"` } // ServicesResponse represents a response from an API method that returns a collection of Service struct. type ServicesResponse struct { Response Data []Service `json:"data"` } // ListServices lists the one-click services available in DNSimple. // // See https://developer.dnsimple.com/v2/services/#list func (s *ServicesService) ListServices(ctx context.Context, options *ListOptions) (*ServicesResponse, error) { path := versioned(servicePath("")) servicesResponse := &ServicesResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, servicesResponse) if err != nil { return servicesResponse, err } servicesResponse.HTTPResponse = resp return servicesResponse, nil } // GetService fetches a one-click service. // // See https://developer.dnsimple.com/v2/services/#get func (s *ServicesService) GetService(ctx context.Context, serviceIdentifier string) (*ServiceResponse, error) { path := versioned(servicePath(serviceIdentifier)) serviceResponse := &ServiceResponse{} resp, err := s.client.get(ctx, path, serviceResponse) if err != nil { return nil, err } serviceResponse.HTTPResponse = resp return serviceResponse, nil } dnsimple-go-2.0.0/dnsimple/services_domains.go 0000664 0000000 0000000 00000004570 14574024165 0021444 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) func domainServicesPath(accountID string, domainIdentifier string, serviceIdentifier string) string { if serviceIdentifier != "" { return fmt.Sprintf("/%v/domains/%v/services/%v", accountID, domainIdentifier, serviceIdentifier) } return fmt.Sprintf("/%v/domains/%v/services", accountID, domainIdentifier) } // DomainServiceSettings represents optional settings when applying a DNSimple one-click service to a domain. type DomainServiceSettings struct { Settings map[string]string `url:"settings,omitempty"` } // AppliedServices lists the applied one-click services for a domain. // // See https://developer.dnsimple.com/v2/services/domains/#applied func (s *ServicesService) AppliedServices(ctx context.Context, accountID string, domainIdentifier string, options *ListOptions) (*ServicesResponse, error) { path := versioned(domainServicesPath(accountID, domainIdentifier, "")) servicesResponse := &ServicesResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, servicesResponse) if err != nil { return servicesResponse, err } servicesResponse.HTTPResponse = resp return servicesResponse, nil } // ApplyService applies a one-click services to a domain. // // See https://developer.dnsimple.com/v2/services/domains/#apply func (s *ServicesService) ApplyService(ctx context.Context, accountID string, serviceIdentifier string, domainIdentifier string, settings DomainServiceSettings) (*ServiceResponse, error) { path := versioned(domainServicesPath(accountID, domainIdentifier, serviceIdentifier)) serviceResponse := &ServiceResponse{} resp, err := s.client.post(ctx, path, settings, nil) if err != nil { return nil, err } serviceResponse.HTTPResponse = resp return serviceResponse, nil } // UnapplyService unapplies a one-click services from a domain. // // See https://developer.dnsimple.com/v2/services/domains/#unapply func (s *ServicesService) UnapplyService(ctx context.Context, accountID string, serviceIdentifier string, domainIdentifier string) (*ServiceResponse, error) { path := versioned(domainServicesPath(accountID, domainIdentifier, serviceIdentifier)) serviceResponse := &ServiceResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } serviceResponse.HTTPResponse = resp return serviceResponse, nil } dnsimple-go-2.0.0/dnsimple/services_domains_test.go 0000664 0000000 0000000 00000004614 14574024165 0022502 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestDomainServices_domainServicesPath(t *testing.T) { assert.Equal(t, "/1010/domains/example.com/services", domainServicesPath("1010", "example.com", "")) assert.Equal(t, "/1010/domains/example.com/services/1", domainServicesPath("1010", "example.com", "1")) } func TestServicesService_AppliedServices(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/services", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/appliedServices/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) servicesResponse, err := client.Services.AppliedServices(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 1}, servicesResponse.Pagination) services := servicesResponse.Data assert.Len(t, services, 1) assert.Equal(t, int64(1), services[0].ID) assert.Equal(t, "wordpress", services[0].SID) } func TestServicesService_ApplyService(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/services/service1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/applyService/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) settings := DomainServiceSettings{Settings: map[string]string{"app": "foo"}} _, err := client.Services.ApplyService(context.Background(), "1010", "service1", "example.com", settings) assert.NoError(t, err) } func TestServicesService_UnapplyService(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/services/service1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/unapplyService/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Services.UnapplyService(context.Background(), "1010", "service1", "example.com") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/services_test.go 0000664 0000000 0000000 00000005414 14574024165 0020767 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestServicePath(t *testing.T) { assert.Equal(t, "/services", servicePath("")) assert.Equal(t, "/services/name", servicePath("name")) } func TestServicesService_List(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/services", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listServices/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) servicesResponse, err := client.Services.ListServices(context.Background(), nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, servicesResponse.Pagination) services := servicesResponse.Data assert.Len(t, services, 2) assert.Equal(t, int64(1), services[0].ID) assert.Equal(t, "Service 1", services[0].Name) } func TestServicesService_List_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/services", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listServices/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Services.ListServices(context.Background(), &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestServicesService_Get(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/services/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getService/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) serviceID := "1" serviceResponse, err := client.Services.GetService(context.Background(), serviceID) assert.NoError(t, err) service := serviceResponse.Data wantSingle := &Service{ ID: 1, SID: "service1", Name: "Service 1", Description: "First service example.", SetupDescription: "", RequiresSetup: true, DefaultSubdomain: "", CreatedAt: "2014-02-14T19:15:19Z", UpdatedAt: "2016-03-04T09:23:27Z", Settings: []ServiceSetting{ { Name: "username", Label: "Service 1 Account Username", Append: ".service1.com", Description: "Your Service 1 username is used to connect services to your account.", Example: "username", Password: false, }, }, } assert.Equal(t, wantSingle, service) } dnsimple-go-2.0.0/dnsimple/templates.go 0000664 0000000 0000000 00000007515 14574024165 0020107 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // TemplatesService handles communication with the template related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/templates/ type TemplatesService struct { client *Client } // Template represents a Template in DNSimple. type Template struct { ID int64 `json:"id,omitempty"` SID string `json:"sid,omitempty"` AccountID int64 `json:"account_id,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func templatePath(accountID string, templateIdentifier string) (path string) { path = fmt.Sprintf("/%v/templates", accountID) if templateIdentifier != "" { path += fmt.Sprintf("/%v", templateIdentifier) } return } // TemplateResponse represents a response from an API method that returns a Template struct. type TemplateResponse struct { Response Data *Template `json:"data"` } // TemplatesResponse represents a response from an API method that returns a collection of Template struct. type TemplatesResponse struct { Response Data []Template `json:"data"` } // ListTemplates list the templates for an account. // // See https://developer.dnsimple.com/v2/templates/#list func (s *TemplatesService) ListTemplates(ctx context.Context, accountID string, options *ListOptions) (*TemplatesResponse, error) { path := versioned(templatePath(accountID, "")) templatesResponse := &TemplatesResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, templatesResponse) if err != nil { return templatesResponse, err } templatesResponse.HTTPResponse = resp return templatesResponse, nil } // CreateTemplate creates a new template. // // See https://developer.dnsimple.com/v2/templates/#create func (s *TemplatesService) CreateTemplate(ctx context.Context, accountID string, templateAttributes Template) (*TemplateResponse, error) { path := versioned(templatePath(accountID, "")) templateResponse := &TemplateResponse{} resp, err := s.client.post(ctx, path, templateAttributes, templateResponse) if err != nil { return nil, err } templateResponse.HTTPResponse = resp return templateResponse, nil } // GetTemplate fetches a template. // // See https://developer.dnsimple.com/v2/templates/#get func (s *TemplatesService) GetTemplate(ctx context.Context, accountID string, templateIdentifier string) (*TemplateResponse, error) { path := versioned(templatePath(accountID, templateIdentifier)) templateResponse := &TemplateResponse{} resp, err := s.client.get(ctx, path, templateResponse) if err != nil { return nil, err } templateResponse.HTTPResponse = resp return templateResponse, nil } // UpdateTemplate updates a template. // // See https://developer.dnsimple.com/v2/templates/#update func (s *TemplatesService) UpdateTemplate(ctx context.Context, accountID string, templateIdentifier string, templateAttributes Template) (*TemplateResponse, error) { path := versioned(templatePath(accountID, templateIdentifier)) templateResponse := &TemplateResponse{} resp, err := s.client.patch(ctx, path, templateAttributes, templateResponse) if err != nil { return nil, err } templateResponse.HTTPResponse = resp return templateResponse, nil } // DeleteTemplate deletes a template. // // See https://developer.dnsimple.com/v2/templates/#delete func (s *TemplatesService) DeleteTemplate(ctx context.Context, accountID string, templateIdentifier string) (*TemplateResponse, error) { path := versioned(templatePath(accountID, templateIdentifier)) templateResponse := &TemplateResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } templateResponse.HTTPResponse = resp return templateResponse, nil } dnsimple-go-2.0.0/dnsimple/templates_domains.go 0000664 0000000 0000000 00000001227 14574024165 0021613 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // ApplyTemplate applies a template to the given domain. // // See https://developer.dnsimple.com/v2/templates/domains/#applyTemplateToDomain func (s *TemplatesService) ApplyTemplate(ctx context.Context, accountID string, templateIdentifier string, domainIdentifier string) (*TemplateResponse, error) { path := versioned(fmt.Sprintf("%v/templates/%v", domainPath(accountID, domainIdentifier), templateIdentifier)) templateResponse := &TemplateResponse{} resp, err := s.client.post(ctx, path, nil, nil) if err != nil { return nil, err } templateResponse.HTTPResponse = resp return templateResponse, nil } dnsimple-go-2.0.0/dnsimple/templates_domains_test.go 0000664 0000000 0000000 00000001211 14574024165 0022643 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestTemplatesService_ApplyTemplate(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/domains/example.com/templates/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/applyTemplate/success.http") testMethod(t, r, "POST") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Templates.ApplyTemplate(context.Background(), "1010", "1", "example.com") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/templates_records.go 0000664 0000000 0000000 00000007404 14574024165 0021625 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // TemplateRecord represents a DNS record for a template in DNSimple. type TemplateRecord struct { ID int64 `json:"id,omitempty"` TemplateID int64 `json:"template_id,omitempty"` Name string `json:"name"` Content string `json:"content,omitempty"` TTL int `json:"ttl,omitempty"` Type string `json:"type,omitempty"` Priority int `json:"priority,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func templateRecordPath(accountID string, templateIdentifier string, templateRecordID int64) string { if templateRecordID != 0 { return fmt.Sprintf("%v/records/%v", templatePath(accountID, templateIdentifier), templateRecordID) } return templatePath(accountID, templateIdentifier) + "/records" } // TemplateRecordResponse represents a response from an API method that returns a TemplateRecord struct. type TemplateRecordResponse struct { Response Data *TemplateRecord `json:"data"` } // TemplateRecordsResponse represents a response from an API method that returns a collection of TemplateRecord struct. type TemplateRecordsResponse struct { Response Data []TemplateRecord `json:"data"` } // ListTemplateRecords list the templates for an account. // // See https://developer.dnsimple.com/v2/templates/records/#list func (s *TemplatesService) ListTemplateRecords(ctx context.Context, accountID string, templateIdentifier string, options *ListOptions) (*TemplateRecordsResponse, error) { path := versioned(templateRecordPath(accountID, templateIdentifier, 0)) templateRecordsResponse := &TemplateRecordsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, templateRecordsResponse) if err != nil { return templateRecordsResponse, err } templateRecordsResponse.HTTPResponse = resp return templateRecordsResponse, nil } // CreateTemplateRecord creates a new template record. // // See https://developer.dnsimple.com/v2/templates/records/#create func (s *TemplatesService) CreateTemplateRecord(ctx context.Context, accountID string, templateIdentifier string, templateRecordAttributes TemplateRecord) (*TemplateRecordResponse, error) { path := versioned(templateRecordPath(accountID, templateIdentifier, 0)) templateRecordResponse := &TemplateRecordResponse{} resp, err := s.client.post(ctx, path, templateRecordAttributes, templateRecordResponse) if err != nil { return nil, err } templateRecordResponse.HTTPResponse = resp return templateRecordResponse, nil } // GetTemplateRecord fetches a template record. // // See https://developer.dnsimple.com/v2/templates/records/#get func (s *TemplatesService) GetTemplateRecord(ctx context.Context, accountID string, templateIdentifier string, templateRecordID int64) (*TemplateRecordResponse, error) { path := versioned(templateRecordPath(accountID, templateIdentifier, templateRecordID)) templateRecordResponse := &TemplateRecordResponse{} resp, err := s.client.get(ctx, path, templateRecordResponse) if err != nil { return nil, err } templateRecordResponse.HTTPResponse = resp return templateRecordResponse, nil } // DeleteTemplateRecord deletes a template record. // // See https://developer.dnsimple.com/v2/templates/records/#delete func (s *TemplatesService) DeleteTemplateRecord(ctx context.Context, accountID string, templateIdentifier string, templateRecordID int64) (*TemplateRecordResponse, error) { path := versioned(templateRecordPath(accountID, templateIdentifier, templateRecordID)) templateRecordResponse := &TemplateRecordResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } templateRecordResponse.HTTPResponse = resp return templateRecordResponse, nil } dnsimple-go-2.0.0/dnsimple/templates_records_test.go 0000664 0000000 0000000 00000010113 14574024165 0022653 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestTemplates_templateRecordPath(t *testing.T) { assert.Equal(t, "/1010/templates/1/records", templateRecordPath("1010", "1", 0)) assert.Equal(t, "/1010/templates/1/records/2", templateRecordPath("1010", "1", 2)) } func TestTemplatesService_ListTemplateRecords(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listTemplateRecords/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) templatesRecordsResponse, err := client.Templates.ListTemplateRecords(context.Background(), "1010", "1", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, templatesRecordsResponse.Pagination) templates := templatesRecordsResponse.Data assert.Len(t, templates, 2) assert.Equal(t, int64(296), templates[0].ID) assert.Equal(t, "192.168.1.1", templates[0].Content) } func TestTemplatesService_ListTemplateRecords_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listTemplateRecords/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Templates.ListTemplateRecords(context.Background(), "1010", "1", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestTemplatesService_CreateTemplateRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createTemplateRecord/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"name": "Beta"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) templateRecordAttributes := TemplateRecord{Name: "Beta"} templateRecordResponse, err := client.Templates.CreateTemplateRecord(context.Background(), "1010", "1", templateRecordAttributes) assert.NoError(t, err) templateRecord := templateRecordResponse.Data assert.Equal(t, int64(300), templateRecord.ID) assert.Equal(t, "mx.example.com", templateRecord.Content) } func TestTemplatesService_GetTemplateRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1/records/2", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getTemplateRecord/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) templateRecordResponse, err := client.Templates.GetTemplateRecord(context.Background(), "1010", "1", 2) assert.NoError(t, err) templateRecord := templateRecordResponse.Data wantSingle := &TemplateRecord{ ID: 301, TemplateID: 268, Name: "", Content: "mx.example.com", TTL: 600, Priority: 10, Type: "MX", CreatedAt: "2016-05-03T08:03:26Z", UpdatedAt: "2016-05-03T08:03:26Z"} assert.Equal(t, wantSingle, templateRecord) } func TestTemplatesService_DeleteTemplateRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1/records/2", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteTemplateRecord/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Templates.DeleteTemplateRecord(context.Background(), "1010", "1", 2) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/templates_test.go 0000664 0000000 0000000 00000011127 14574024165 0021140 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestTemplatePath(t *testing.T) { assert.Equal(t, "/1010/templates", templatePath("1010", "")) assert.Equal(t, "/1010/templates/1", templatePath("1010", "1")) } func TestTemplatesService_List(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listTemplates/success.http") testMethod(t, r, "GET") testHeaders(t, r) testQuery(t, r, url.Values{}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) templatesResponse, err := client.Templates.ListTemplates(context.Background(), "1010", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, templatesResponse.Pagination) templates := templatesResponse.Data assert.Len(t, templates, 2) assert.Equal(t, int64(1), templates[0].ID) assert.Equal(t, "Alpha", templates[0].Name) } func TestTemplatesService_List_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listTemplates/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Templates.ListTemplates(context.Background(), "1010", &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestTemplatesService_Create(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createTemplate/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"name": "Beta"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" templateAttributes := Template{Name: "Beta"} templateResponse, err := client.Templates.CreateTemplate(context.Background(), accountID, templateAttributes) assert.NoError(t, err) template := templateResponse.Data assert.Equal(t, int64(1), template.ID) assert.Equal(t, "Beta", template.Name) } func TestTemplatesService_Get(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getTemplate/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) templateResponse, err := client.Templates.GetTemplate(context.Background(), "1010", "1") assert.NoError(t, err) template := templateResponse.Data wantSingle := &Template{ ID: 1, SID: "alpha", AccountID: 1010, Name: "Alpha", Description: "An alpha template.", CreatedAt: "2016-03-22T11:08:58Z", UpdatedAt: "2016-03-22T11:08:58Z"} assert.Equal(t, wantSingle, template) } func TestTemplatesService_UpdateTemplate(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateTemplate/success.http") testMethod(t, r, "PATCH") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) templateAttributes := Template{Name: "Alpha"} templateResponse, err := client.Templates.UpdateTemplate(context.Background(), "1010", "1", templateAttributes) assert.NoError(t, err) template := templateResponse.Data wantSingle := &Template{ ID: 1, SID: "alpha", AccountID: 1010, Name: "Alpha", Description: "An alpha template.", CreatedAt: "2016-03-22T11:08:58Z", UpdatedAt: "2016-03-22T11:08:58Z"} assert.Equal(t, wantSingle, template) } func TestTemplatesService_DeleteTemplate(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/templates/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteTemplate/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Templates.DeleteTemplate(context.Background(), "1010", "1") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/tlds.go 0000664 0000000 0000000 00000006576 14574024165 0017065 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // TldsService handles communication with the Tld related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/tlds/ type TldsService struct { client *Client } // Tld represents a TLD in DNSimple. type Tld struct { Tld string `json:"tld"` TldType int `json:"tld_type"` WhoisPrivacy bool `json:"whois_privacy"` AutoRenewOnly bool `json:"auto_renew_only"` MinimumRegistration int `json:"minimum_registration"` RegistrationEnabled bool `json:"registration_enabled"` RenewalEnabled bool `json:"renewal_enabled"` TransferEnabled bool `json:"transfer_enabled"` DnssecInterfaceType string `json:"dnssec_interface_type"` } // TldExtendedAttribute represents an extended attributes supported or required // by a specific TLD. // // See https://developer.dnsimple.com/v2/tlds/ type TldExtendedAttribute struct { Name string `json:"name"` Description string `json:"description"` Required bool `json:"required"` Options []TldExtendedAttributeOption `json:"options"` } // TldExtendedAttributeOption represents a single option you can assign to an extended attributes. // // See https://developer.dnsimple.com/v2/tlds/ type TldExtendedAttributeOption struct { Title string `json:"title"` Value string `json:"value"` Description string `json:"description"` } // TldResponse represents a response from an API method that returns a Tld struct. type TldResponse struct { Response Data *Tld `json:"data"` } // TldsResponse represents a response from an API method that returns a collection of Tld struct. type TldsResponse struct { Response Data []Tld `json:"data"` } // TldExtendedAttributesResponse represents a response from an API method that returns // a collection of Tld extended attributes. type TldExtendedAttributesResponse struct { Response Data []TldExtendedAttribute `json:"data"` } // ListTlds lists the supported TLDs. // // See https://developer.dnsimple.com/v2/tlds/#list func (s *TldsService) ListTlds(ctx context.Context, options *ListOptions) (*TldsResponse, error) { path := versioned("/tlds") tldsResponse := &TldsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, tldsResponse) if err != nil { return tldsResponse, err } tldsResponse.HTTPResponse = resp return tldsResponse, nil } // GetTld fetches a TLD. // // See https://developer.dnsimple.com/v2/tlds/#get func (s *TldsService) GetTld(ctx context.Context, tld string) (*TldResponse, error) { path := versioned(fmt.Sprintf("/tlds/%s", tld)) tldResponse := &TldResponse{} resp, err := s.client.get(ctx, path, tldResponse) if err != nil { return nil, err } tldResponse.HTTPResponse = resp return tldResponse, nil } // GetTldExtendedAttributes fetches the extended attributes of a TLD. // // See https://developer.dnsimple.com/v2/tlds/#get func (s *TldsService) GetTldExtendedAttributes(ctx context.Context, tld string) (*TldExtendedAttributesResponse, error) { path := versioned(fmt.Sprintf("/tlds/%s/extended_attributes", tld)) tldResponse := &TldExtendedAttributesResponse{} resp, err := s.client.get(ctx, path, tldResponse) if err != nil { return nil, err } tldResponse.HTTPResponse = resp return tldResponse, nil } dnsimple-go-2.0.0/dnsimple/tlds_test.go 0000664 0000000 0000000 00000005711 14574024165 0020112 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestTldsService_ListTlds(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/tlds", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listTlds/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) tldsResponse, err := client.Tlds.ListTlds(context.Background(), nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 2, TotalPages: 98, TotalEntries: 195}, tldsResponse.Pagination) tlds := tldsResponse.Data assert.Len(t, tlds, 2) assert.Equal(t, "ac", tlds[0].Tld) assert.Equal(t, 1, tlds[0].MinimumRegistration) assert.True(t, tlds[0].RegistrationEnabled) assert.True(t, tlds[0].RenewalEnabled) assert.False(t, tlds[0].TransferEnabled) } func TestTldsService_ListTlds_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/tlds", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listTlds/success.http") testQuery(t, r, url.Values{"page": []string{"2"}, "per_page": []string{"20"}}) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Tlds.ListTlds(context.Background(), &ListOptions{Page: Int(2), PerPage: Int(20)}) assert.NoError(t, err) } func TestTldsService_GetTld(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/tlds/com", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getTld/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) tldResponse, err := client.Tlds.GetTld(context.Background(), "com") assert.NoError(t, err) tld := tldResponse.Data assert.Equal(t, "com", tld.Tld) assert.Equal(t, 1, tld.TldType) assert.True(t, tld.WhoisPrivacy) assert.False(t, tld.AutoRenewOnly) assert.Equal(t, 1, tld.MinimumRegistration) assert.True(t, tld.RegistrationEnabled) assert.True(t, tld.RenewalEnabled) assert.True(t, tld.TransferEnabled) assert.Equal(t, "ds", tld.DnssecInterfaceType) } func TestTldsService_GetTldExtendedAttributes(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/tlds/com/extended_attributes", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getTldExtendedAttributes/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) tldResponse, err := client.Tlds.GetTldExtendedAttributes(context.Background(), "com") assert.NoError(t, err) attributes := tldResponse.Data assert.Len(t, attributes, 4) assert.Equal(t, "uk_legal_type", attributes[0].Name) } dnsimple-go-2.0.0/dnsimple/users.go 0000664 0000000 0000000 00000000226 14574024165 0017242 0 ustar 00root root 0000000 0000000 package dnsimple // User represents a DNSimple user. type User struct { ID int64 `json:"id,omitempty"` Email string `json:"email,omitempty"` } dnsimple-go-2.0.0/dnsimple/vanity_name_server.go 0000664 0000000 0000000 00000004242 14574024165 0022003 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // VanityNameServersService handles communication with Vanity Name Servers // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/vanity/ type VanityNameServersService struct { client *Client } // VanityNameServer represents data for a single vanity name server. type VanityNameServer struct { ID int64 `json:"id,omitempty"` Name string `json:"name,omitempty"` IPv4 string `json:"ipv4,omitempty"` IPv6 string `json:"ipv6,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } func vanityNameServerPath(accountID string, domainIdentifier string) string { return fmt.Sprintf("/%v/vanity/%v", accountID, domainIdentifier) } // VanityNameServerResponse represents a response for vanity name server enable and disable operations. type VanityNameServerResponse struct { Response Data []VanityNameServer `json:"data"` } // EnableVanityNameServers Vanity Name Servers for the given domain // // See https://developer.dnsimple.com/v2/vanity/#enableVanityNameServers func (s *VanityNameServersService) EnableVanityNameServers(ctx context.Context, accountID string, domainIdentifier string) (*VanityNameServerResponse, error) { path := versioned(vanityNameServerPath(accountID, domainIdentifier)) vanityNameServerResponse := &VanityNameServerResponse{} resp, err := s.client.put(ctx, path, nil, vanityNameServerResponse) if err != nil { return nil, err } vanityNameServerResponse.HTTPResponse = resp return vanityNameServerResponse, nil } // DisableVanityNameServers Vanity Name Servers for the given domain // // See https://developer.dnsimple.com/v2/vanity/#disableVanityNameServers func (s *VanityNameServersService) DisableVanityNameServers(ctx context.Context, accountID string, domainIdentifier string) (*VanityNameServerResponse, error) { path := versioned(vanityNameServerPath(accountID, domainIdentifier)) vanityNameServerResponse := &VanityNameServerResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } vanityNameServerResponse.HTTPResponse = resp return vanityNameServerResponse, nil } dnsimple-go-2.0.0/dnsimple/vanity_name_servers_test.go 0000664 0000000 0000000 00000003025 14574024165 0023223 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestVanityNameServers_vanityNameServerPath(t *testing.T) { assert.Equal(t, "/1010/vanity/example.com", vanityNameServerPath("1010", "example.com")) } func TestVanityNameServersService_EnableVanityNameServers(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/vanity/example.com", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/enableVanityNameServers/success.http") testMethod(t, r, "PUT") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) vanityNameServerResponse, err := client.VanityNameServers.EnableVanityNameServers(context.Background(), "1010", "example.com") assert.NoError(t, err) delegation := vanityNameServerResponse.Data[0].Name wantSingle := "ns1.example.com" assert.Equal(t, wantSingle, delegation) } func TestVanityNameServersService_DisableVanityNameServers(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/vanity/example.com", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/disableVanityNameServers/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.VanityNameServers.DisableVanityNameServers(context.Background(), "1010", "example.com") assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/webhook/ 0000775 0000000 0000000 00000000000 14574024165 0017210 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/dnsimple/webhook/events.go 0000664 0000000 0000000 00000015324 14574024165 0021050 0 ustar 00root root 0000000 0000000 package webhook import ( "github.com/dnsimple/dnsimple-go/dnsimple" ) func switchEventData(event *Event) (EventDataContainer, error) { var data EventDataContainer switch event.Name { case // account "account.billing_settings_update", "account.update": data = &AccountEventData{} case // account_invitation "account.user_invitation_accept", "account.user_invitation_revoke", "account.user_invite", "account.user_remove": data = &AccountMembershipEventData{} case // certificate "certificate.issue", "certificate.remove_private_key": data = &CertificateEventData{} case // contact "contact.create", "contact.delete", "contact.update": data = &ContactEventData{} case // dnssec "dnssec.create", "dnssec.delete", "dnssec.rotation_complete", "dnssec.rotation_start": data = &DNSSECEventData{} case // domain "domain.auto_renewal_disable", "domain.auto_renewal_enable", "domain.create", "domain.delegation_change", "domain.delete", "domain.register", "domain.registrant_change", "domain.registrant_change:started", "domain.registrant_change:cancelled", "domain.renew", "domain.resolution_disable", "domain.resolution_enable", "domain.transfer": // TODO data = &DomainEventData{} case // domain transfer lock "domain.transfer_lock_enable", "domain.transfer_lock_disable": data = &DomainTransferLockEventData{} case // email forward "email_forward.create", "email_forward.delete", "email_forward.update": data = &EmailForwardEventData{} case // webhook "webhook.create", "webhook.delete": data = &WebhookEventData{} case // whois privacy "whois_privacy.disable", "whois_privacy.enable", "whois_privacy.purchase", "whois_privacy.renew": data = &WhoisPrivacyEventData{} case // zone "zone.create", "zone.delete": data = &ZoneEventData{} case // zone record "zone_record.create", "zone_record.delete", "zone_record.update": data = &ZoneRecordEventData{} default: data = &GenericEventData{} } err := data.unmarshalEventData(event.payload) return data, err } // // GenericEvent // // GenericEventData represents the data node for a generic event, where the data is a simple map of strings. type GenericEventData map[string]interface{} func (d *GenericEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // AccountEvent // // AccountEventData represents the data node for an Account event. type AccountEventData struct { Account *dnsimple.Account `json:"account"` } func (d *AccountEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // AccountInvitationEvent // // AccountMembershipEventData represents the data node for an Account event. type AccountMembershipEventData struct { Account *dnsimple.Account `json:"account"` AccountInvitation *dnsimple.AccountInvitation `json:"account_invitation"` User *dnsimple.User `json:"user"` } func (d *AccountMembershipEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // CertificateEvent // // CertificateEventData represents the data node for a Certificate event. type CertificateEventData struct { Certificate *dnsimple.Certificate `json:"certificate"` } func (d *CertificateEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // ContactEvent // // ContactEventData represents the data node for a Contact event. type ContactEventData struct { Contact *dnsimple.Contact `json:"contact"` } func (d *ContactEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // DNSSECEvent // // DNSSECEventData represents the data node for a DNSSEC event. type DNSSECEventData struct { DelegationSignerRecord *dnsimple.DelegationSignerRecord `json:"delegation_signer_record"` //DNSSECConfig *dnsimple.DNSSECConfig `json:"dnssec"` } func (d *DNSSECEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // DomainEvent // // DomainEventData represents the data node for a Domain event. type DomainEventData struct { Auto bool `json:"auto"` Domain *dnsimple.Domain `json:"domain"` Registrant *dnsimple.Contact `json:"registrant"` Delegation *dnsimple.Delegation `json:"name_servers"` } func (d *DomainEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // DomainTransferLockEvent // // DomainTransferLockEventData represents the data node for a DomainTransferLockEnable or DomainTransferLockDisable event. type DomainTransferLockEventData struct { Domain *dnsimple.Domain `json:"domain"` } func (d *DomainTransferLockEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // DomainRegistrantChangeEvent // // DomainRegistrantChangegEventData represents the data node for a DomainRegistrantChange event. type DomainRegistrantChangeEventData struct { Domain *dnsimple.Domain `json:"domain"` Registrant *dnsimple.Contact `json:"registrant"` } func (d *DomainRegistrantChangeEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // EmailForwardEvent // // EmailForwardEventData represents the data node for a EmailForward event. type EmailForwardEventData struct { EmailForward *dnsimple.EmailForward `json:"email_forward"` } func (d *EmailForwardEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // WebhookEvent // // WebhookEventData represents the data node for a Webhook event. type WebhookEventData struct { Webhook *dnsimple.Webhook `json:"webhook"` } func (d *WebhookEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // WhoisPrivacyEvent // // WhoisPrivacyEventData represents the data node for a WhoisPrivacy event. type WhoisPrivacyEventData struct { Domain *dnsimple.Domain `json:"domain"` WhoisPrivacy *dnsimple.WhoisPrivacy `json:"whois_privacy"` } func (d *WhoisPrivacyEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // ZoneEvent // // ZoneEventData represents the data node for a Zone event. type ZoneEventData struct { Zone *dnsimple.Zone `json:"zone"` } func (d *ZoneEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } // // ZoneRecordEvent // // ZoneRecordEventData represents the data node for a ZoneRecord event. type ZoneRecordEventData struct { ZoneRecord *dnsimple.ZoneRecord `json:"zone_record"` } func (d *ZoneRecordEventData) unmarshalEventData(payload []byte) error { return unmarshalEventData(payload, d) } dnsimple-go-2.0.0/dnsimple/webhook/events_test.go 0000664 0000000 0000000 00000061142 14574024165 0022106 0 ustar 00root root 0000000 0000000 package webhook import ( "bufio" "io/ioutil" "net/http" "regexp" "strings" "testing" "github.com/dnsimple/dnsimple-go/dnsimple" "github.com/stretchr/testify/assert" ) var regexpUUID = regexp.MustCompile(`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`) func readHTTPRequestFixture(t *testing.T, filename string) string { data, err := ioutil.ReadFile("../../fixtures.http" + filename) assert.NoError(t, err) s := string(data[:]) return s } func getHTTPRequestFromFixture(t *testing.T, filename string) *http.Request { req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(readHTTPRequestFixture(t, filename)))) assert.NoError(t, err) return req } func getHTTPRequestBodyFromFixture(t *testing.T, filename string) []byte { req := getHTTPRequestFromFixture(t, filename) body, err := ioutil.ReadAll(req.Body) assert.NoError(t, err) return body } func TestParseGenericEvent(t *testing.T) { payload := `{"data": {"domain": {"id": 1, "name": "example.com", "state": "hosted", "token": "domain-token", "account_id": 1010, "auto_renew": false, "created_at": "2016-02-07T14:46:29.142Z", "expires_on": null, "updated_at": "2016-02-07T14:46:29.142Z", "unicode_name": "example.com", "private_whois": false, "registrant_id": null}}, "actor": {"id": "1", "entity": "user", "pretty": "example@example.com"}, "account": {"id": 1010, "display": "User", "identifier": "user"}, "name": "generic", "api_version": "v2", "request_identifier": "096bfc29-2bf0-40c6-991b-f03b1f8521f1"}` event, err := ParseEvent([]byte(payload)) assert.NoError(t, err) assert.Equal(t, "generic", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) dataPointer, ok := event.GetData().(*GenericEventData) assert.True(t, ok) data := *dataPointer assert.Equal(t, "example.com", data["domain"].(map[string]interface{})["name"]) } func TestParseAccountEvent_Account_BillingSettingsUpdate(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.billing_settings_update/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.billing_settings_update", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*AccountEventData) assert.True(t, ok) assert.Equal(t, "hello@example.com", data.Account.Email) } func TestParseAccountEvent_Account_Update(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.update/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.update", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*AccountEventData) assert.True(t, ok) assert.Equal(t, "hello@example.com", data.Account.Email) } func TestParseAccountEvent_Account_UserInvitationAccept(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.user_invitation_accept/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.user_invitation_accept", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*AccountMembershipEventData) assert.True(t, ok) expectedAccount := dnsimple.Account{ ID: 1111, Email: "xxxxx@xxxxxx.xxx", CreatedAt: "2012-03-16T16:02:54Z", UpdatedAt: "2020-05-10T18:11:03Z", PlanIdentifier: "professional-v1-monthly", } assert.Equal(t, expectedAccount, *data.Account) expectedAccountInvitation := dnsimple.AccountInvitation{ ID: 3523, Email: "xxxxxx@xxxxxx.xxx", Token: "eb5763dc-0f24-420b-b7f6-c7355c8b8309", AccountID: 1111, CreatedAt: "2020-05-12T18:42:44Z", UpdatedAt: "2020-05-12T18:43:44Z", InvitationSentAt: "2020-05-12T18:42:44Z", InvitationAcceptedAt: "2020-05-12T18:43:44Z", } assert.Equal(t, expectedAccountInvitation, *data.AccountInvitation) assert.Nil(t, data.User) } func TestParseAccountEvent_Account_UserInvitationRevoke(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.user_invitation_revoke/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.user_invitation_revoke", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*AccountMembershipEventData) assert.True(t, ok) expectedAccount := dnsimple.Account{ ID: 1111, Email: "xxxxx@xxxxxx.xxx", CreatedAt: "2012-03-16T16:02:54Z", UpdatedAt: "2020-05-10T18:11:03Z", PlanIdentifier: "professional-v1-monthly", } assert.Equal(t, expectedAccount, *data.Account) expectedAccountInvitation := dnsimple.AccountInvitation{ ID: 3522, Email: "xxxxxx@xxxxxx.xxx", Token: "be87d69b-a58a-43bd-9a21-aaf303829a60", AccountID: 1111, CreatedAt: "2020-05-12T18:42:27Z", UpdatedAt: "2020-05-12T18:42:27Z", InvitationSentAt: "2020-05-12T18:42:27Z", InvitationAcceptedAt: "", } assert.Equal(t, expectedAccountInvitation, *data.AccountInvitation) assert.Nil(t, data.User) } func TestParseAccountEvent_Account_UserInvite(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.user_invite/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.user_invite", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*AccountMembershipEventData) assert.True(t, ok) expectedAccount := dnsimple.Account{ ID: 1111, Email: "xxxxx@xxxxxx.xxx", CreatedAt: "2012-03-16T16:02:54Z", UpdatedAt: "2020-05-10T18:11:03Z", PlanIdentifier: "professional-v1-monthly", } assert.Equal(t, expectedAccount, *data.Account) expectedAccountInvitation := dnsimple.AccountInvitation{ ID: 3523, Email: "xxxxxx@xxxxxx.xxx", Token: "eb5763dc-0f24-420b-b7f6-c7355c8b8309", AccountID: 1111, CreatedAt: "2020-05-12T18:42:44Z", UpdatedAt: "2020-05-12T18:42:44Z", InvitationSentAt: "2020-05-12T18:42:44Z", InvitationAcceptedAt: "", } assert.Equal(t, expectedAccountInvitation, *data.AccountInvitation) assert.Nil(t, data.User) } func TestParseAccountEvent_Account_UserRemove(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.user_remove/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.user_remove", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*AccountMembershipEventData) assert.True(t, ok) expectedAccount := dnsimple.Account{ ID: 1111, Email: "xxxxx@xxxxxx.xxx", CreatedAt: "2012-03-16T16:02:54Z", UpdatedAt: "2020-05-10T18:11:03Z", PlanIdentifier: "professional-v1-monthly", } assert.Equal(t, expectedAccount, *data.Account) assert.Nil(t, data.AccountInvitation) expectedUser := dnsimple.User{ ID: 1120, Email: "xxxxxx@xxxxxx.xxx", } assert.Equal(t, expectedUser, *data.User) } func TestParseCertificateEvent_Certificate_Issue(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/certificate.issue/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "certificate.issue", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*CertificateEventData) assert.True(t, ok) assert.Equal(t, int64(101967), data.Certificate.ID) } func TestParseCertificateEvent_Certificate_RemovePrivateKey(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/certificate.remove_private_key/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "certificate.remove_private_key", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*CertificateEventData) assert.True(t, ok) assert.Equal(t, int64(101972), data.Certificate.ID) } func TestParseContactEvent_Contact_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/contact.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "contact.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ContactEventData) assert.True(t, ok) assert.Equal(t, "Test", data.Contact.Label) } func TestParseContactEvent_Contact_Update(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/contact.update/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "contact.update", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ContactEventData) assert.True(t, ok) assert.Equal(t, "Test", data.Contact.Label) } func TestParseContactEvent_Contact_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/contact.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "contact.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ContactEventData) assert.True(t, ok) assert.Equal(t, "Test", data.Contact.Label) } func TestParseDNSSECEvent_DNSSEC_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/dnssec.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "dnssec.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) _, ok := event.GetData().(*DNSSECEventData) assert.True(t, ok) } func TestParseDNSSECEvent_DNSSEC_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/dnssec.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "dnssec.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) _, ok := event.GetData().(*DNSSECEventData) assert.True(t, ok) } func TestParseDNSSECEvent_DNSSEC_RotationStart(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/dnssec.rotation_start/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "dnssec.rotation_start", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DNSSECEventData) assert.True(t, ok) assert.Equal(t, "BD9D898E92D0F668E6BDBC5E79D52E5C3BAB12823A6EEE8C8B6DC633007DFABC", data.DelegationSignerRecord.Digest) } func TestParseDNSSECEvent_DNSSEC_RotationComplete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/dnssec.rotation_complete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "dnssec.rotation_complete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DNSSECEventData) assert.True(t, ok) assert.Equal(t, "EF1D343203E03F1C98120646971F7B96806B759B66622F0A224551DA1A1EFC9A", data.DelegationSignerRecord.Digest) } func TestParseDomainEvent_Domain_AutoRenewalDisable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.auto_renewal_disable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.auto_renewal_disable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) } func TestParseDomainEvent_Domain_AutoRenewalEnable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.auto_renewal_enable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.auto_renewal_enable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) } func TestParseDomainEvent_Domain_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-beta.com", data.Domain.Name) } func TestParseDomainEvent_Domain_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-delta.com", data.Domain.Name) } func TestParseDomainEvent_Domain_Register(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.register/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.register", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) } func TestParseDomainEvent_Domain_Renew(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.renew/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.renew", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.True(t, data.Auto) assert.Equal(t, "example-alpha.com", data.Domain.Name) } func TestParseDomainEvent_Domain_DelegationChange(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.delegation_change/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.delegation_change", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, &dnsimple.Delegation{"ns1.dnsimple.com", "ns2.dnsimple.com", "ns3.dnsimple.com"}, data.Delegation) } func TestParseDomainEvent_Domain_RegistrantChange(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.registrant_change/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.registrant_change", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, "new_contact", data.Registrant.Label) } func TestParseDomainEvent_Domain_RegistrantChangeStarted(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.registrant_change/status-started.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.registrant_change:started", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, "new_contact", data.Registrant.Label) } func TestParseDomainEvent_Domain_RegistrantChangeCancelled(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.registrant_change/status-cancelled.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.registrant_change:cancelled", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, "new_contact", data.Registrant.Label) } func TestParseDomainEvent_Domain_ResolutionDisable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.resolution_disable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.resolution_disable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) } func TestParseDomainEvent_Domain_ResolutionEnable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.resolution_enable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.resolution_enable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) } func TestParseDomainEvent_Domain_Transfer(t *testing.T) { payload := `{"data": {"domain": {"id": 6637, "name": "example.com", "state": "hosted", "token": "domain-token", "account_id": 24, "auto_renew": false, "created_at": "2016-03-24T21:03:49.392Z", "expires_on": null, "updated_at": "2016-03-24T21:03:49.392Z", "unicode_name": "example.com", "private_whois": false, "registrant_id": 409}}, "name": "domain.transfer", "actor": {"id": "1", "entity": "user", "pretty": "example@example.com"}, "account": {"id": 1010, "display": "User", "identifier": "user"}, "api_version": "v2", "request_identifier": "49901af0-569e-4acd-900f-6edf0ebc123c"}` event, err := ParseEvent([]byte(payload)) assert.NoError(t, err) assert.Equal(t, "domain.transfer", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainEventData) assert.True(t, ok) assert.Equal(t, "example.com", data.Domain.Name) } func TestParseDomainEvent_Domain_TransferLockEnable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.transfer_lock_enable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "domain.transfer_lock_enable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainTransferLockEventData) assert.True(t, ok) assert.Equal(t, "example.com", data.Domain.Name) } func TestParseDomainEvent_Domain_TransferLockDisable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/domain.transfer_lock_disable/example.http") event, err := ParseEvent([]byte(payload)) assert.NoError(t, err) assert.Equal(t, "domain.transfer_lock_disable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*DomainTransferLockEventData) assert.True(t, ok) assert.Equal(t, "example.com", data.Domain.Name) } func TestParseEmailForwardEvent_EmailForward_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/email_forward.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "email_forward.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*EmailForwardEventData) assert.True(t, ok) assert.Equal(t, "example@example.zone", data.EmailForward.From) } func TestParseEmailForwardEvent_EmailForward_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/email_forward.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "email_forward.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*EmailForwardEventData) assert.True(t, ok) assert.Equal(t, ".*@example.zone", data.EmailForward.From) } func TestParseEmailForwardEvent_EmailForward_Update(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/email_forward.update/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "email_forward.update", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*EmailForwardEventData) assert.True(t, ok) assert.Equal(t, ".*@example.zone", data.EmailForward.From) } func TestParseWebhookEvent_Webhook_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/webhook.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "webhook.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*WebhookEventData) assert.True(t, ok) assert.Equal(t, "https://xxxxxx-xxxxxxx-00000.herokuapp.com/xxxxxxxx", data.Webhook.URL) } func TestParseWebhookEvent_Webhook_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/webhook.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "webhook.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*WebhookEventData) assert.True(t, ok) assert.Equal(t, "https://xxxxxx-xxxxxxx-00000.herokuapp.com/xxxxxxxx", data.Webhook.URL) } func TestParseWhoisPrivacyEvent_WhoisPrivacy_Disable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/whois_privacy.disable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "whois_privacy.disable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*WhoisPrivacyEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, int64(902), data.WhoisPrivacy.ID) } func TestParseWhoisPrivacyEvent_WhoisPrivacy_Enable(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/whois_privacy.enable/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "whois_privacy.enable", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*WhoisPrivacyEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, int64(902), data.WhoisPrivacy.ID) } func TestParseWhoisPrivacyEvent_WhoisPrivacy_Purchase(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/whois_privacy.purchase/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "whois_privacy.purchase", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*WhoisPrivacyEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, int64(902), data.WhoisPrivacy.ID) } func TestParseWhoisPrivacyEvent_WhoisPrivacy_Renew(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/whois_privacy.renew/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "whois_privacy.renew", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*WhoisPrivacyEventData) assert.True(t, ok) assert.Equal(t, "example-alpha.com", data.Domain.Name) assert.Equal(t, int64(902), data.WhoisPrivacy.ID) } func TestParseZoneEvent_Zone_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/zone.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "zone.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ZoneEventData) assert.True(t, ok) assert.Equal(t, "example.zone", data.Zone.Name) } func TestParseZoneEvent_Zone_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/zone.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "zone.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ZoneEventData) assert.True(t, ok) assert.Equal(t, "example.zone", data.Zone.Name) } func TestParseZoneRecordEvent_ZoneRecord_Create(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/zone_record.create/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "zone_record.create", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ZoneRecordEventData) assert.True(t, ok) assert.Equal(t, "", data.ZoneRecord.Name) } func TestParseZoneRecordEvent_ZoneRecord_Update(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/zone_record.update/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "zone_record.update", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ZoneRecordEventData) assert.True(t, ok) assert.Equal(t, "www", data.ZoneRecord.Name) } func TestParseZoneRecordEvent_ZoneRecord_Delete(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/zone_record.delete/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "zone_record.delete", event.Name) assert.Regexp(t, regexpUUID, event.RequestID) data, ok := event.GetData().(*ZoneRecordEventData) assert.True(t, ok) assert.Equal(t, "www", data.ZoneRecord.Name) } dnsimple-go-2.0.0/dnsimple/webhook/webhook.go 0000664 0000000 0000000 00000004700 14574024165 0021176 0 ustar 00root root 0000000 0000000 // Package webhook provides the support for reading and parsing the events // sent from DNSimple via webhook. package webhook import ( "encoding/json" "github.com/dnsimple/dnsimple-go/dnsimple" ) // Actor represents the entity that triggered the event. It can be either an user, // a DNSimple support representative or the DNSimple system. type Actor struct { ID string `json:"id"` Entity string `json:"entity"` Pretty string `json:"pretty"` } // Account represents the account that this event is attached to. type Account struct { dnsimple.Account // Display is a string that can be used as a display label // and it is sent in a webhook payload // It generally represent the name of the account. Display string `json:"display,omitempty"` // Identifier is a human-readable string identifier // and it is sent in a webhook payload // It generally represent the StringID or email of the account. Identifier string `json:"identifier,omitempty"` } // Event represents a webhook event. type Event struct { APIVersion string `json:"api_version"` RequestID string `json:"request_identifier"` Name string `json:"name"` Actor *Actor `json:"actor"` Account *Account `json:"account"` data EventDataContainer payload []byte } // EventDataContainer defines the container for the event payload data. type EventDataContainer interface { unmarshalEventData([]byte) error } // GetData returns the data container for the specific event type. func (e *Event) GetData() EventDataContainer { return e.data } // GetPayload returns the data payload. func (e *Event) GetPayload() []byte { return e.payload } // ParseEvent takes an event payload and attempts to deserialize the payload into an Event. // // The event data will be set with a data type that matches the event action in the payload. // If no direct match is found, then a GenericEventData is assigned. // // The event data type is an EventContainerData interface. Therefore, you must perform typecasting // to access any type-specific field. func ParseEvent(payload []byte) (*Event, error) { e := &Event{payload: payload} if err := json.Unmarshal(payload, e); err != nil { return nil, err } data, err := switchEventData(e) if err != nil { return nil, err } e.data = data return e, nil } type eventDataStruct struct { Data interface{} `json:"data"` } func unmarshalEventData(data []byte, v interface{}) error { return json.Unmarshal(data, &eventDataStruct{Data: v}) } dnsimple-go-2.0.0/dnsimple/webhook/webhook_test.go 0000664 0000000 0000000 00000003670 14574024165 0022242 0 ustar 00root root 0000000 0000000 package webhook import ( "testing" "github.com/stretchr/testify/assert" ) func TestParseEvent_Generic(t *testing.T) { payload := `{"data": {"domain": {"id": 1, "name": "example.com", "state": "hosted", "token": "domain-token", "account_id": 1010, "auto_renew": false, "created_at": "2016-02-07T14:46:29.142Z", "expires_on": null, "updated_at": "2016-02-07T14:46:29.142Z", "unicode_name": "example.com", "private_whois": false, "registrant_id": null}}, "actor": {"id": "1", "entity": "user", "pretty": "example@example.com"}, "account": {"id": 1010, "display": "User", "identifier": "user"}, "name": "generic", "api_version": "v2", "request_identifier": "096bfc29-2bf0-40c6-991b-f03b1f8521f1"}` event, err := ParseEvent([]byte(payload)) assert.NoError(t, err) assert.Equal(t, "generic", event.Name) eventAccount := event.Account assert.Equal(t, "User", eventAccount.Display) _, ok := event.GetData().(*GenericEventData) assert.True(t, ok) } func TestParseEvent_Account(t *testing.T) { payload := getHTTPRequestBodyFromFixture(t, "/webhooks/account.update/example.http") event, err := ParseEvent(payload) assert.NoError(t, err) assert.Equal(t, "account.update", event.Name) eventAccount := event.Account assert.Equal(t, "Personal2", eventAccount.Display) _, ok := event.GetData().(*AccountEventData) assert.True(t, ok) } func TestParseEvent_Webhook(t *testing.T) { payload := `{"data": {"webhook": {"id": 25, "url": "https://webhook.test"}}, "name": "webhook.create", "actor": {"id": "1", "entity": "user", "pretty": "example@example.com"}, "account": {"id": 1, "display": "User", "identifier": "user"}, "api_version": "v2", "request_identifier": "d6362e1f-310b-4009-a29d-ce76c849d32c"}` event, err := ParseEvent([]byte(payload)) assert.NoError(t, err) assert.Equal(t, "webhook.create", event.Name) eventAccount := event.Account assert.Equal(t, "User", eventAccount.Display) _, ok := event.GetData().(*WebhookEventData) assert.True(t, ok) } dnsimple-go-2.0.0/dnsimple/webhooks.go 0000664 0000000 0000000 00000005541 14574024165 0017727 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // WebhooksService handles communication with the webhook related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/webhooks type WebhooksService struct { client *Client } // Webhook represents a DNSimple webhook. type Webhook struct { ID int64 `json:"id,omitempty"` URL string `json:"url,omitempty"` } func webhookPath(accountID string, webhookID int64) (path string) { path = fmt.Sprintf("/%v/webhooks", accountID) if webhookID != 0 { path = fmt.Sprintf("%v/%v", path, webhookID) } return } // WebhookResponse represents a response from an API method that returns a Webhook struct. type WebhookResponse struct { Response Data *Webhook `json:"data"` } // WebhooksResponse represents a response from an API method that returns a collection of Webhook struct. type WebhooksResponse struct { Response Data []Webhook `json:"data"` } // ListWebhooks lists the webhooks for an account. // // See https://developer.dnsimple.com/v2/webhooks/#listWebhooks func (s *WebhooksService) ListWebhooks(ctx context.Context, accountID string, _ *ListOptions) (*WebhooksResponse, error) { path := versioned(webhookPath(accountID, 0)) webhooksResponse := &WebhooksResponse{} resp, err := s.client.get(ctx, path, webhooksResponse) if err != nil { return webhooksResponse, err } webhooksResponse.HTTPResponse = resp return webhooksResponse, nil } // CreateWebhook creates a new webhook. // // See https://developer.dnsimple.com/v2/webhooks/#createWebhook func (s *WebhooksService) CreateWebhook(ctx context.Context, accountID string, webhookAttributes Webhook) (*WebhookResponse, error) { path := versioned(webhookPath(accountID, 0)) webhookResponse := &WebhookResponse{} resp, err := s.client.post(ctx, path, webhookAttributes, webhookResponse) if err != nil { return nil, err } webhookResponse.HTTPResponse = resp return webhookResponse, nil } // GetWebhook fetches a webhook. // // See https://developer.dnsimple.com/v2/webhooks/#getWebhook func (s *WebhooksService) GetWebhook(ctx context.Context, accountID string, webhookID int64) (*WebhookResponse, error) { path := versioned(webhookPath(accountID, webhookID)) webhookResponse := &WebhookResponse{} resp, err := s.client.get(ctx, path, webhookResponse) if err != nil { return nil, err } webhookResponse.HTTPResponse = resp return webhookResponse, nil } // DeleteWebhook PERMANENTLY deletes the webhook. // // See https://developer.dnsimple.com/v2/webhooks/#deleteWebhook func (s *WebhooksService) DeleteWebhook(ctx context.Context, accountID string, webhookID int64) (*WebhookResponse, error) { path := versioned(webhookPath(accountID, webhookID)) webhookResponse := &WebhookResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } webhookResponse.HTTPResponse = resp return webhookResponse, nil } dnsimple-go-2.0.0/dnsimple/webhooks_test.go 0000664 0000000 0000000 00000005534 14574024165 0020770 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestWebhooks_webhookPath(t *testing.T) { assert.Equal(t, "/1010/webhooks", webhookPath("1010", 0)) assert.Equal(t, "/1010/webhooks/1", webhookPath("1010", 1)) } func TestWebhooksService_ListWebhooks(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/webhooks", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listWebhooks/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) webhooksResponse, err := client.Webhooks.ListWebhooks(context.Background(), "1010", nil) assert.NoError(t, err) webhooks := webhooksResponse.Data assert.Len(t, webhooks, 2) assert.Equal(t, int64(1), webhooks[0].ID) assert.Equal(t, "https://webhook.test", webhooks[0].URL) } func TestWebhooksService_CreateWebhook(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/webhooks", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createWebhook/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"url": "https://webhook.test"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) webhookAttributes := Webhook{URL: "https://webhook.test"} webhookResponse, err := client.Webhooks.CreateWebhook(context.Background(), "1010", webhookAttributes) assert.NoError(t, err) webhook := webhookResponse.Data assert.Equal(t, int64(1), webhook.ID) assert.Equal(t, "https://webhook.test", webhook.URL) } func TestWebhooksService_GetWebhook(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/webhooks/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getWebhook/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) webhookResponse, err := client.Webhooks.GetWebhook(context.Background(), "1010", 1) assert.NoError(t, err) webhook := webhookResponse.Data wantSingle := &Webhook{ ID: 1, URL: "https://webhook.test"} assert.Equal(t, wantSingle, webhook) } func TestWebhooksService_DeleteWebhook(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/webhooks/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteWebhook/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Webhooks.DeleteWebhook(context.Background(), "1010", 1) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/zone_distributions.go 0000664 0000000 0000000 00000003236 14574024165 0022042 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // ZoneDistribution is the result of the zone distribution check. type ZoneDistribution struct { Distributed bool `json:"distributed"` } // ZoneDistributionResponse represents a response from an API method that returns a ZoneDistribution struct. type ZoneDistributionResponse struct { Response Data *ZoneDistribution `json:"data"` } // CheckZoneDistribution checks if a zone is fully distributed across DNSimple nodes. // // See https://developer.dnsimple.com/v2/zones/#checkZoneDistribution func (s *ZonesService) CheckZoneDistribution(ctx context.Context, accountID string, zoneName string) (*ZoneDistributionResponse, error) { path := versioned(fmt.Sprintf("/%v/zones/%v/distribution", accountID, zoneName)) zoneDistributionResponse := &ZoneDistributionResponse{} resp, err := s.client.get(ctx, path, zoneDistributionResponse) if err != nil { return nil, err } zoneDistributionResponse.HTTPResponse = resp return zoneDistributionResponse, nil } // CheckZoneRecordDistribution checks if a zone is fully distributed across DNSimple nodes. // // See https://developer.dnsimple.com/v2/zones/#checkZoneRecordDistribution func (s *ZonesService) CheckZoneRecordDistribution(ctx context.Context, accountID string, zoneName string, recordID int64) (*ZoneDistributionResponse, error) { path := versioned(fmt.Sprintf("/%v/zones/%v/records/%v/distribution", accountID, zoneName, recordID)) zoneDistributionResponse := &ZoneDistributionResponse{} resp, err := s.client.get(ctx, path, zoneDistributionResponse) if err != nil { return nil, err } zoneDistributionResponse.HTTPResponse = resp return zoneDistributionResponse, nil } dnsimple-go-2.0.0/dnsimple/zones.go 0000664 0000000 0000000 00000010204 14574024165 0017234 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // ZonesService handles communication with the zone related // methods of the DNSimple API. // // See https://developer.dnsimple.com/v2/zones/ type ZonesService struct { client *Client } // Zone represents a Zone in DNSimple. type Zone struct { ID int64 `json:"id,omitempty"` AccountID int64 `json:"account_id,omitempty"` Name string `json:"name,omitempty"` Reverse bool `json:"reverse,omitempty"` Secondary bool `json:"secondary,omitempty"` LastTransferredAt string `json:"last_transferred_at,omitempty"` Active bool `json:"active,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // ZoneFile represents a Zone File in DNSimple. type ZoneFile struct { Zone string `json:"zone,omitempty"` } // ZoneResponse represents a response from an API method that returns a Zone struct. type ZoneResponse struct { Response Data *Zone `json:"data"` } // ZonesResponse represents a response from an API method that returns a collection of Zone struct. type ZonesResponse struct { Response Data []Zone `json:"data"` } // ZoneFileResponse represents a response from an API method that returns a ZoneFile struct. type ZoneFileResponse struct { Response Data *ZoneFile `json:"data"` } // ZoneListOptions specifies the optional parameters you can provide // to customize the ZonesService.ListZones method. type ZoneListOptions struct { // Select domains where the name contains given string. NameLike *string `url:"name_like,omitempty"` ListOptions } // ListZones the zones for an account. // // See https://developer.dnsimple.com/v2/zones/#listZones func (s *ZonesService) ListZones(ctx context.Context, accountID string, options *ZoneListOptions) (*ZonesResponse, error) { path := versioned(fmt.Sprintf("/%v/zones", accountID)) zonesResponse := &ZonesResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, zonesResponse) if err != nil { return zonesResponse, err } zonesResponse.HTTPResponse = resp return zonesResponse, nil } // GetZone fetches a zone. // // See https://developer.dnsimple.com/v2/zones/#getZone func (s *ZonesService) GetZone(ctx context.Context, accountID string, zoneName string) (*ZoneResponse, error) { path := versioned(fmt.Sprintf("/%v/zones/%v", accountID, zoneName)) zoneResponse := &ZoneResponse{} resp, err := s.client.get(ctx, path, zoneResponse) if err != nil { return nil, err } zoneResponse.HTTPResponse = resp return zoneResponse, nil } // GetZoneFile fetches a zone file. // // See https://developer.dnsimple.com/v2/zones/#getZoneFile func (s *ZonesService) GetZoneFile(ctx context.Context, accountID string, zoneName string) (*ZoneFileResponse, error) { path := versioned(fmt.Sprintf("/%v/zones/%v/file", accountID, zoneName)) zoneFileResponse := &ZoneFileResponse{} resp, err := s.client.get(ctx, path, zoneFileResponse) if err != nil { return nil, err } zoneFileResponse.HTTPResponse = resp return zoneFileResponse, nil } // ActivateZoneDns activates DNS services for a zone. // // See https://developer.dnsimple.com/v2/zones/#activateZoneService func (s *ZonesService) ActivateZoneDns(ctx context.Context, accountID string, zoneName string) (*ZoneResponse, error) { path := versioned(fmt.Sprintf("/%v/zones/%v/activation", accountID, zoneName)) zoneResponse := &ZoneResponse{} resp, err := s.client.put(ctx, path, nil, zoneResponse) if err != nil { return nil, err } zoneResponse.HTTPResponse = resp return zoneResponse, nil } // DeactivateZoneDns deactivates DNS services for a zone. // // See https://developer.dnsimple.com/v2/zones/#deactivateZoneService func (s *ZonesService) DeactivateZoneDns(ctx context.Context, accountID string, zoneName string) (*ZoneResponse, error) { path := versioned(fmt.Sprintf("/%v/zones/%v/activation", accountID, zoneName)) zoneResponse := &ZoneResponse{} resp, err := s.client.delete(ctx, path, nil, zoneResponse) if err != nil { return nil, err } zoneResponse.HTTPResponse = resp return zoneResponse, nil } dnsimple-go-2.0.0/dnsimple/zones_distributions_test.go 0000664 0000000 0000000 00000010734 14574024165 0023265 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestZonesService_CheckZoneDistribution(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/distribution", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkZoneDistribution/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneDistributionResponse, err := client.Zones.CheckZoneDistribution(context.Background(), accountID, zoneName) assert.NoError(t, err) zone := zoneDistributionResponse.Data wantSingle := &ZoneDistribution{ Distributed: true, } assert.Equal(t, wantSingle, zone) } func TestZonesService_CheckZoneDistributionFailure(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/distribution", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkZoneDistribution/failure.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneDistributionResponse, err := client.Zones.CheckZoneDistribution(context.Background(), accountID, zoneName) assert.NoError(t, err) zone := zoneDistributionResponse.Data wantSingle := &ZoneDistribution{ Distributed: false, } assert.Equal(t, wantSingle, zone) } func TestZonesService_CheckZoneDistributionError(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/distribution", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkZoneDistribution/error.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneDistributionResponse, err := client.Zones.CheckZoneDistribution(context.Background(), accountID, zoneName) assert.Error(t, err) assert.Nil(t, zoneDistributionResponse) } func TestZonesService_CheckZoneRecordDistribution(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/1/distribution", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkZoneRecordDistribution/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" recordID := int64(1) zoneDistributionResponse, err := client.Zones.CheckZoneRecordDistribution(context.Background(), accountID, zoneName, recordID) assert.NoError(t, err) zone := zoneDistributionResponse.Data assert.Equal(t, &ZoneDistribution{Distributed: true}, zone) } func TestZonesService_CheckZoneRecordDistributionFailure(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/1/distribution", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkZoneRecordDistribution/failure.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" recordID := int64(1) zoneDistributionResponse, err := client.Zones.CheckZoneRecordDistribution(context.Background(), accountID, zoneName, recordID) assert.NoError(t, err) zone := zoneDistributionResponse.Data assert.Equal(t, &ZoneDistribution{Distributed: false}, zone) } func TestZonesService_CheckZoneRecordDistributionError(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/1/distribution", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/checkZoneRecordDistribution/error.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" recordID := int64(1) zoneDistributionResponse, err := client.Zones.CheckZoneRecordDistribution(context.Background(), accountID, zoneName, recordID) assert.Error(t, err) assert.Nil(t, zoneDistributionResponse) } dnsimple-go-2.0.0/dnsimple/zones_records.go 0000664 0000000 0000000 00000012372 14574024165 0020765 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "fmt" ) // ZoneRecord represents a zone record in DNSimple. type ZoneRecord struct { ID int64 `json:"id,omitempty"` ZoneID string `json:"zone_id,omitempty"` ParentID int64 `json:"parent_id,omitempty"` Type string `json:"type,omitempty"` Name string `json:"name"` Content string `json:"content,omitempty"` TTL int `json:"ttl,omitempty"` Priority int `json:"priority,omitempty"` SystemRecord bool `json:"system_record,omitempty"` Regions []string `json:"regions,omitempty"` CreatedAt string `json:"created_at,omitempty"` UpdatedAt string `json:"updated_at,omitempty"` } // ZoneRecordAttributes represents the attributes you can send to create/update a zone record. // // Compared to most other calls in this library, you should not use ZoneRecord as payload for record calls. // This is because it can lead to side effects due to the inability of go to distinguish between a non-present string // and an empty string. Name can be both, therefore a specific struct is required. type ZoneRecordAttributes struct { ZoneID string `json:"zone_id,omitempty"` Type string `json:"type,omitempty"` Name *string `json:"name,omitempty"` Content string `json:"content,omitempty"` TTL int `json:"ttl,omitempty"` Priority int `json:"priority,omitempty"` Regions []string `json:"regions,omitempty"` } func zoneRecordPath(accountID string, zoneName string, recordID int64) (path string) { path = fmt.Sprintf("/%v/zones/%v/records", accountID, zoneName) if recordID != 0 { path += fmt.Sprintf("/%v", recordID) } return } // ZoneRecordResponse represents a response from an API method that returns a ZoneRecord struct. type ZoneRecordResponse struct { Response Data *ZoneRecord `json:"data"` } // ZoneRecordsResponse represents a response from an API method that returns a collection of ZoneRecord struct. type ZoneRecordsResponse struct { Response Data []ZoneRecord `json:"data"` } // ZoneRecordListOptions specifies the optional parameters you can provide // to customize the ZonesService.ListZoneRecords method. type ZoneRecordListOptions struct { // Select records where the name matches given string. Name *string `url:"name,omitempty"` // Select records where the name contains given string. NameLike *string `url:"name_like,omitempty"` // Select records of given type. // Eg. TXT, A, NS. Type *string `url:"type,omitempty"` ListOptions } // ListRecords lists the zone records for a zone. // // See https://developer.dnsimple.com/v2/zones/records/#listZoneRecords func (s *ZonesService) ListRecords(ctx context.Context, accountID string, zoneName string, options *ZoneRecordListOptions) (*ZoneRecordsResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, 0)) recordsResponse := &ZoneRecordsResponse{} path, err := addURLQueryOptions(path, options) if err != nil { return nil, err } resp, err := s.client.get(ctx, path, recordsResponse) if err != nil { return nil, err } recordsResponse.HTTPResponse = resp return recordsResponse, nil } // CreateRecord creates a zone record. // // See https://developer.dnsimple.com/v2/zones/records/#createZoneRecord func (s *ZonesService) CreateRecord(ctx context.Context, accountID string, zoneName string, recordAttributes ZoneRecordAttributes) (*ZoneRecordResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, 0)) recordResponse := &ZoneRecordResponse{} resp, err := s.client.post(ctx, path, recordAttributes, recordResponse) if err != nil { return nil, err } recordResponse.HTTPResponse = resp return recordResponse, nil } // GetRecord fetches a zone record. // // See https://developer.dnsimple.com/v2/zones/records/#getZoneRecord func (s *ZonesService) GetRecord(ctx context.Context, accountID string, zoneName string, recordID int64) (*ZoneRecordResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, recordID)) recordResponse := &ZoneRecordResponse{} resp, err := s.client.get(ctx, path, recordResponse) if err != nil { return nil, err } recordResponse.HTTPResponse = resp return recordResponse, nil } // UpdateRecord updates a zone record. // // See https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord func (s *ZonesService) UpdateRecord(ctx context.Context, accountID string, zoneName string, recordID int64, recordAttributes ZoneRecordAttributes) (*ZoneRecordResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, recordID)) recordResponse := &ZoneRecordResponse{} resp, err := s.client.patch(ctx, path, recordAttributes, recordResponse) if err != nil { return nil, err } recordResponse.HTTPResponse = resp return recordResponse, nil } // DeleteRecord PERMANENTLY deletes a zone record from the zone. // // See https://developer.dnsimple.com/v2/zones/records/#deleteZoneRecord func (s *ZonesService) DeleteRecord(ctx context.Context, accountID string, zoneName string, recordID int64) (*ZoneRecordResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, recordID)) recordResponse := &ZoneRecordResponse{} resp, err := s.client.delete(ctx, path, nil, nil) if err != nil { return nil, err } recordResponse.HTTPResponse = resp return recordResponse, nil } dnsimple-go-2.0.0/dnsimple/zones_records_test.go 0000664 0000000 0000000 00000026504 14574024165 0022026 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestZoneRecordPath(t *testing.T) { assert.Equal(t, "/1010/zones/example.com/records", zoneRecordPath("1010", "example.com", 0)) assert.Equal(t, "/1010/zones/example.com/records/1", zoneRecordPath("1010", "example.com", 1)) } func TestZonesService_ListRecords(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listZoneRecords/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordsResponse, err := client.Zones.ListRecords(context.Background(), "1010", "example.com", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 5}, recordsResponse.Pagination) records := recordsResponse.Data assert.Len(t, records, 5) assert.Equal(t, int64(1), records[0].ID) assert.Equal(t, "", records[0].Name) assert.Equal(t, []string{"global"}, records[0].Regions) } func TestZonesService_ListRecords_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listZoneRecords/success.http") testQuery(t, r, url.Values{ "page": []string{"2"}, "per_page": []string{"20"}, "sort": []string{"name,expiration:desc"}, "name": []string{"example"}, "name_like": []string{"www"}, "type": []string{"A"}, }) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Zones.ListRecords(context.Background(), "1010", "example.com", &ZoneRecordListOptions{String("example"), String("www"), String("A"), ListOptions{Page: Int(2), PerPage: Int(20), Sort: String("name,expiration:desc")}}) assert.NoError(t, err) } func TestZonesService_ListRecords_WithOptionsSomeBlank(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listZoneRecords/success.http") testQuery(t, r, url.Values{ "page": []string{"2"}, "sort": []string{"name,expiration:desc"}, "name": []string{"example"}, "type": []string{"A"}, }) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Zones.ListRecords(context.Background(), "1010", "example.com", &ZoneRecordListOptions{Name: String("example"), Type: String("A"), ListOptions: ListOptions{Page: Int(2), Sort: String("name,expiration:desc")}}) assert.NoError(t, err) } func TestZonesService_CreateRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"name": "foo", "content": "mxa.example.com", "type": "MX"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" recordValues := ZoneRecordAttributes{Name: String("foo"), Content: "mxa.example.com", Type: "MX"} recordResponse, err := client.Zones.CreateRecord(context.Background(), accountID, "example.com", recordValues) assert.NoError(t, err) record := recordResponse.Data assert.Equal(t, int64(1), record.ID) assert.Equal(t, "www", record.Name) assert.Equal(t, "A", record.Type) assert.Equal(t, []string{"global"}, record.Regions) } func TestZonesService_CreateRecord_BlankName(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created-apex.http") testMethod(t, r, "POST") testHeaders(t, r) want := map[string]interface{}{"name": "", "content": "127.0.0.1", "type": "A"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues := ZoneRecordAttributes{Name: String(""), Content: "127.0.0.1", Type: "A"} recordResponse, err := client.Zones.CreateRecord(context.Background(), "1010", "example.com", recordValues) assert.NoError(t, err) record := recordResponse.Data assert.Equal(t, "", record.Name) assert.Equal(t, []string{"global"}, record.Regions) } func TestZonesService_CreateRecord_Regions(t *testing.T) { setupMockServer() defer teardownMockServer() var recordValues ZoneRecordAttributes mux.HandleFunc("/v2/1/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created.http") want := map[string]interface{}{"name": "foo"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues = ZoneRecordAttributes{Name: String("foo"), Regions: []string{}} _, err := client.Zones.CreateRecord(context.Background(), "1", "example.com", recordValues) assert.NoError(t, err) mux.HandleFunc("/v2/2/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created.http") want := map[string]interface{}{"name": "foo", "regions": []interface{}{"global"}} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues = ZoneRecordAttributes{Name: String("foo"), Regions: []string{"global"}} _, err = client.Zones.CreateRecord(context.Background(), "2", "example.com", recordValues) assert.NoError(t, err) mux.HandleFunc("/v2/3/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created.http") want := map[string]interface{}{"name": "foo", "regions": []interface{}{"global"}} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues = ZoneRecordAttributes{Name: String("foo"), Regions: []string{"global"}} _, err = client.Zones.CreateRecord(context.Background(), "2", "example.com", recordValues) assert.NoError(t, err) } func TestZonesService_GetRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/1539", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getZoneRecord/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" recordResponse, err := client.Zones.GetRecord(context.Background(), accountID, "example.com", 1539) assert.NoError(t, err) record := recordResponse.Data wantSingle := &ZoneRecord{ ID: 5, ZoneID: "example.com", ParentID: 0, Type: "MX", Name: "", Content: "mxa.example.com", TTL: 600, Priority: 10, SystemRecord: false, Regions: []string{"SV1", "IAD"}, CreatedAt: "2016-10-05T09:51:35Z", UpdatedAt: "2016-10-05T09:51:35Z"} assert.Equal(t, wantSingle, record) } func TestZonesService_UpdateRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/5", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http") testMethod(t, r, "PATCH") testHeaders(t, r) want := map[string]interface{}{"name": "foo", "content": "127.0.0.1"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" recordValues := ZoneRecordAttributes{Name: String("foo"), Content: "127.0.0.1"} recordResponse, err := client.Zones.UpdateRecord(context.Background(), accountID, "example.com", 5, recordValues) assert.NoError(t, err) record := recordResponse.Data assert.Equal(t, int64(5), record.ID) assert.Equal(t, "mxb.example.com", record.Content) } func TestZonesService_UpdateRecord_NameNotProvided(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/5", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http") want := map[string]interface{}{"content": "127.0.0.1"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues := ZoneRecordAttributes{Content: "127.0.0.1"} _, err := client.Zones.UpdateRecord(context.Background(), "1010", "example.com", 5, recordValues) assert.NoError(t, err) } func TestZonesService_UpdateRecord_Regions(t *testing.T) { setupMockServer() defer teardownMockServer() var recordValues ZoneRecordAttributes mux.HandleFunc("/v2/1/zones/example.com/records/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http") want := map[string]interface{}{"name": "foo"} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues = ZoneRecordAttributes{Name: String("foo"), Regions: []string{}} _, err := client.Zones.UpdateRecord(context.Background(), "1", "example.com", 1, recordValues) assert.NoError(t, err) mux.HandleFunc("/v2/2/zones/example.com/records/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http") want := map[string]interface{}{"name": "foo", "regions": []interface{}{"global"}} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues = ZoneRecordAttributes{Name: String("foo"), Regions: []string{"global"}} _, err = client.Zones.UpdateRecord(context.Background(), "2", "example.com", 1, recordValues) assert.NoError(t, err) mux.HandleFunc("/v2/3/zones/example.com/records/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http") want := map[string]interface{}{"name": "foo", "regions": []interface{}{"global"}} testRequestJSON(t, r, want) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) recordValues = ZoneRecordAttributes{Name: String("foo"), Regions: []string{"global"}} _, err = client.Zones.UpdateRecord(context.Background(), "2", "example.com", 1, recordValues) assert.NoError(t, err) } func TestZonesService_DeleteRecord(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/records/2", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deleteZoneRecord/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" _, err := client.Zones.DeleteRecord(context.Background(), accountID, "example.com", 2) assert.NoError(t, err) } dnsimple-go-2.0.0/dnsimple/zones_test.go 0000664 0000000 0000000 00000012542 14574024165 0020302 0 ustar 00root root 0000000 0000000 package dnsimple import ( "context" "io" "net/http" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestZonesService_ListZones(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listZones/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) zonesResponse, err := client.Zones.ListZones(context.Background(), "1010", nil) assert.NoError(t, err) assert.Equal(t, &Pagination{CurrentPage: 1, PerPage: 30, TotalPages: 1, TotalEntries: 2}, zonesResponse.Pagination) zones := zonesResponse.Data assert.Len(t, zones, 2) assert.Equal(t, int64(1), zones[0].ID) assert.Equal(t, "example-alpha.com", zones[0].Name) } func TestZonesService_ListZones_WithOptions(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/listZones/success.http") testQuery(t, r, url.Values{ "page": []string{"2"}, "per_page": []string{"20"}, "sort": []string{"name,expiration:desc"}, "name_like": []string{"example"}, }) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) _, err := client.Zones.ListZones(context.Background(), "1010", &ZoneListOptions{String("example"), ListOptions{Page: Int(2), PerPage: Int(20), Sort: String("name,expiration:desc")}}) assert.NoError(t, err) } func TestZonesService_GetZone(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getZone/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneResponse, err := client.Zones.GetZone(context.Background(), accountID, zoneName) assert.NoError(t, err) zone := zoneResponse.Data wantSingle := &Zone{ ID: 1, AccountID: 1010, Name: "example-alpha.com", Reverse: false, Secondary: false, LastTransferredAt: "", Active: true, CreatedAt: "2015-04-23T07:40:03Z", UpdatedAt: "2015-04-23T07:40:03Z"} assert.Equal(t, wantSingle, zone) } func TestZonesService_GetZoneFile(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/file", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/getZoneFile/success.http") testMethod(t, r, "GET") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneFileResponse, err := client.Zones.GetZoneFile(context.Background(), accountID, zoneName) assert.NoError(t, err) zoneFile := zoneFileResponse.Data wantSingle := &ZoneFile{ Zone: "$ORIGIN example.com.\n$TTL 1h\nexample.com. 3600 IN SOA ns1.dnsimple.com. admin.dnsimple.com. 1453132552 86400 7200 604800 300\nexample.com. 3600 IN NS ns1.dnsimple.com.\nexample.com. 3600 IN NS ns2.dnsimple.com.\nexample.com. 3600 IN NS ns3.dnsimple.com.\nexample.com. 3600 IN NS ns4.dnsimple.com.\n", } assert.Equal(t, wantSingle, zoneFile) } func TestZonesService_ActivateZoneDns(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/activation", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/activateZoneService/success.http") testMethod(t, r, "PUT") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneResponse, err := client.Zones.ActivateZoneDns(context.Background(), accountID, zoneName) assert.NoError(t, err) zone := zoneResponse.Data wantSingle := &Zone{ ID: 1, AccountID: 1010, Name: "example.com", Reverse: false, Secondary: false, LastTransferredAt: "", Active: true, CreatedAt: "2015-04-23T07:40:03Z", UpdatedAt: "2015-04-23T07:40:03Z", } assert.Equal(t, wantSingle, zone) } func TestZonesService_DeactivateZoneDns(t *testing.T) { setupMockServer() defer teardownMockServer() mux.HandleFunc("/v2/1010/zones/example.com/activation", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/deactivateZoneService/success.http") testMethod(t, r, "DELETE") testHeaders(t, r) w.WriteHeader(httpResponse.StatusCode) _, _ = io.Copy(w, httpResponse.Body) }) accountID := "1010" zoneName := "example.com" zoneResponse, err := client.Zones.DeactivateZoneDns(context.Background(), accountID, zoneName) assert.NoError(t, err) zone := zoneResponse.Data wantSingle := &Zone{ ID: 1, AccountID: 1010, Name: "example.com", Reverse: false, Secondary: false, LastTransferredAt: "", Active: false, CreatedAt: "2015-04-23T07:40:03Z", UpdatedAt: "2015-04-23T07:40:03Z", } assert.Equal(t, wantSingle, zone) } dnsimple-go-2.0.0/fixtures.http/ 0000775 0000000 0000000 00000000000 14574024165 0016566 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/ 0000775 0000000 0000000 00000000000 14574024165 0017337 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/acceptPush/ 0000775 0000000 0000000 00000000000 14574024165 0021436 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/acceptPush/success.http 0000664 0000000 0000000 00000000730 14574024165 0024007 0 ustar 00root root 0000000 0000000 HTTP/1.1 204 No Content Server: nginx Date: Thu, 11 Aug 2016 10:23:46 GMT Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2392 X-RateLimit-Reset: 1470913058 Cache-Control: no-cache X-Request-Id: 5867ab50-6237-4cf8-b220-51f5ef57debd X-Runtime: 0.582482 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 dnsimple-go-2.0.0/fixtures.http/api/accounts/ 0000775 0000000 0000000 00000000000 14574024165 0021156 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/accounts/success-account.http 0000664 0000000 0000000 00000001367 14574024165 0025170 0 ustar 00root root 0000000 0000000 HTTP/1.1 200 OK Server: nginx Date: Tue, 14 Jun 2016 12:02:58 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2391 X-RateLimit-Reset: 1465908577 ETag: W/"9ef3b4bf1f441a9b1cd6d7041bc181aa" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: f705b65b-3589-43ad-97ca-3b2821d49d81 X-Runtime: 0.012661 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 {"data":[{"id":123,"email":"john@example.com","plan_identifier":"dnsimple-personal","created_at":"2011-09-11T17:15:58Z","updated_at":"2016-06-03T15:02:26Z"}]} dnsimple-go-2.0.0/fixtures.http/api/accounts/success-user.http 0000664 0000000 0000000 00000001616 14574024165 0024507 0 ustar 00root root 0000000 0000000 HTTP/1.1 200 OK Server: nginx Date: Tue, 14 Jun 2016 12:05:38 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2390 X-RateLimit-Reset: 1465908577 ETag: W/"b8dc5b6e94652da599d15d4668b723b5" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: 745455ba-3871-440d-b703-1448b9708c14 X-Runtime: 0.014727 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 {"data":[{"id":123,"email":"john@example.com","plan_identifier":"dnsimple-personal","created_at":"2011-09-11T17:15:58Z","updated_at":"2016-06-03T15:02:26Z"},{"id":456,"email":"ops@company.com","plan_identifier":"dnsimple-professional","created_at":"2012-03-16T16:02:54Z","updated_at":"2016-06-14T11:23:16Z"}]} dnsimple-go-2.0.0/fixtures.http/api/activateZoneService/ 0000775 0000000 0000000 00000000000 14574024165 0023314 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/activateZoneService/success.http 0000664 0000000 0000000 00000001274 14574024165 0025671 0 ustar 00root root 0000000 0000000 HTTP/1.1 200 OK Server: nginx Date: Tue, 08 Aug 2023 04:19:23 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2399 X-RateLimit-Reset: 1691471963 X-WORK-WITH-US: Love automation? So do we! https://dnsimple.com/jobs ETag: W/"fe6afd982459be33146933235343d51d" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: 8e8ac535-9f46-4304-8440-8c68c30427c3 X-Runtime: 0.176579 Strict-Transport-Security: max-age=63072000 {"data":{"id":1,"account_id":1010,"name":"example.com","reverse":false,"secondary":false,"last_transferred_at":null,"active":true,"created_at":"2015-04-23T07:40:03Z","updated_at":"2015-04-23T07:40:03Z"}} dnsimple-go-2.0.0/fixtures.http/api/addCollaborator/ 0000775 0000000 0000000 00000000000 14574024165 0022433 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/addCollaborator/invite-success.http 0000664 0000000 0000000 00000001453 14574024165 0026303 0 ustar 00root root 0000000 0000000 HTTP/1.1 201 Created Server: nginx Date: Fri, 07 Oct 2016 08:51:12 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2398 X-RateLimit-Reset: 1475833772 ETag: W/"3e59e2eafbf1d4b626413a5703309b57" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: 9f27e164-2448-4d23-ad67-4ecedaec063e X-Runtime: 0.387144 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 {"data":{"id":101,"domain_id":1,"domain_name":"example.com","user_id":null,"user_email":"invited-user@example.com","invitation":true,"created_at":"2016-10-07T08:51:12Z","updated_at":"2016-10-07T08:51:12Z","accepted_at":null}} dnsimple-go-2.0.0/fixtures.http/api/addCollaborator/success.http 0000664 0000000 0000000 00000001476 14574024165 0025014 0 ustar 00root root 0000000 0000000 HTTP/1.1 201 Created Server: nginx Date: Fri, 07 Oct 2016 08:53:41 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2397 X-RateLimit-Reset: 1475833772 ETag: W/"d35fa3da40b4f6586503174563d71bfc" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: 42de3144-37c7-4329-88c4-fdc103cb150f X-Runtime: 0.156436 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 {"data":{"id":100,"domain_id":1,"domain_name":"example.com","user_id":999,"user_email":"existing-user@example.com","invitation":false,"created_at":"2016-10-07T08:53:41Z","updated_at":"2016-10-07T08:53:41Z","accepted_at":"2016-10-07T08:53:41Z"}} dnsimple-go-2.0.0/fixtures.http/api/appliedServices/ 0000775 0000000 0000000 00000000000 14574024165 0022461 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/appliedServices/success.http 0000664 0000000 0000000 00000002107 14574024165 0025032 0 ustar 00root root 0000000 0000000 HTTP/1.1 200 OK Server: nginx Date: Wed, 15 Jun 2016 11:09:44 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2398 X-RateLimit-Reset: 1465992405 ETag: W/"f3fb525524e0a0eab452025850afb062" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: 03bcc2ff-d1f1-4fc2-bb3f-9218a21c04b7 X-Runtime: 0.065526 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 {"data":[{"id":1,"name":"WordPress","sid":"wordpress","description":"Share with the world, your community, or your closest friends.","setup_description":null,"requires_setup":true,"default_subdomain":"blog","created_at":"2013-11-05T18:06:50Z","updated_at":"2016-03-04T09:23:27Z","settings":[{"name":"site","label":"Site","append":null,"description":"Your Wordpress.com subdomain","example":null,"password":false}]}],"pagination":{"current_page":1,"per_page":30,"total_entries":1,"total_pages":1}} dnsimple-go-2.0.0/fixtures.http/api/applyService/ 0000775 0000000 0000000 00000000000 14574024165 0022005 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/applyService/success.http 0000664 0000000 0000000 00000000730 14574024165 0024356 0 ustar 00root root 0000000 0000000 HTTP/1.1 204 No Content Server: nginx Date: Sat, 09 Jul 2016 11:12:42 GMT Connection: keep-alive X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2398 X-RateLimit-Reset: 1468066326 Cache-Control: no-cache X-Request-Id: 30a3a44b-5792-4114-a355-a866603311ce X-Runtime: 0.087254 X-Content-Type-Options: nosniff X-Download-Options: noopen X-Frame-Options: DENY X-Permitted-Cross-Domain-Policies: none X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 dnsimple-go-2.0.0/fixtures.http/api/applyTemplate/ 0000775 0000000 0000000 00000000000 14574024165 0022160 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/applyTemplate/success.http 0000664 0000000 0000000 00000000543 14574024165 0024533 0 ustar 00root root 0000000 0000000 HTTP/1.1 204 No Content Server: nginx Date: Thu, 24 Mar 2016 11:05:38 GMT Connection: keep-alive Status: 204 No Content X-RateLimit-Limit: 2400 X-RateLimit-Remaining: 2397 X-RateLimit-Reset: 1458821049 Cache-Control: no-cache X-Request-Id: 967713d5-a203-40ee-875c-1df07868b7eb X-Runtime: 0.147576 Strict-Transport-Security: max-age=31536000 dnsimple-go-2.0.0/fixtures.http/api/authorizeDomainTransferOut/ 0000775 0000000 0000000 00000000000 14574024165 0024676 5 ustar 00root root 0000000 0000000 dnsimple-go-2.0.0/fixtures.http/api/authorizeDomainTransferOut/success.http 0000664 0000000 0000000 00000000543 14574024165 0027251 0 ustar 00root root 0000000 0000000 HTTP/1.1 204 No Content Server: nginx Date: Sun, 21 Feb 2016 13:40:35 GMT Connection: keep-alive Status: 204 No Content X-RateLimit-Limit: 4000 X-RateLimit-Remaining: 3990 X-RateLimit-Reset: 1456063540 Cache-Control: no-cache X-Request-Id: 9af6ab78-7ea8-4675-89f0-14d124fc7ca2 X-Runtime: 3.038699 Strict-Transport-Security: max-age=31536000 dnsimple-go-2.0.0/fixtures.http/api/badgateway.http 0000664 0000000 0000000 00000000451 14574024165 0022350 0 ustar 00root root 0000000 0000000 HTTP/1.1 502 Bad Gateway Server: nginx Date: Mon, 22 Dec 2014 14:16:12 GMT Content-Type: text/html Content-Length: 166 Connection: close