Compare commits
17 commits
Author | SHA1 | Date | |
---|---|---|---|
|
66d86fb092 | ||
|
bfc94ffc04 | ||
|
997979f1b8 | ||
|
ef93a5772e | ||
|
2aded968d2 | ||
|
cc5aa6c9ed | ||
|
6afd3822b2 | ||
|
b7148fab83 | ||
|
ea449f0dda | ||
|
cf5fdbb592 | ||
|
3b41066138 | ||
|
6af1099b71 | ||
|
4570ff381b | ||
|
023a8ba939 | ||
|
e57854683b | ||
|
797513210f | ||
|
4cbecbf44d |
10 changed files with 258 additions and 34 deletions
|
@ -1,6 +0,0 @@
|
|||
version: 1
|
||||
|
||||
update_configs:
|
||||
- package_manager: "go:modules"
|
||||
directory: "/"
|
||||
update_schedule: "daily"
|
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
@ -7,7 +7,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: go get
|
||||
|
|
77
README.md
77
README.md
|
@ -11,6 +11,7 @@ are:
|
|||
* `add-record`
|
||||
* `edit-record`
|
||||
* `remove-record`
|
||||
* `find-domains`
|
||||
|
||||
**TO NOTE**: Even though `record` methods are implemented, I'm fairly certain
|
||||
they'll fail (silently or not) in some cases. I deal mostly with `TXT`, `MX`,
|
||||
|
@ -28,6 +29,11 @@ cover all types of DNS records), as long as they're all tested and documented.
|
|||
|
||||
### Usage
|
||||
|
||||
Most of the methods are pretty self-explanatory if you read the documentation
|
||||
and read the function signature. Some of the most "complex" operations, like
|
||||
creating/updating records can be figured out from the tests. But here's some
|
||||
examples:
|
||||
|
||||
```golang
|
||||
package main
|
||||
|
||||
|
@ -41,14 +47,79 @@ func main() {
|
|||
token := "api-token"
|
||||
domain := "your-domain"
|
||||
|
||||
records, err := ListRecords(token, domain)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
// 1. Listing records in a domain
|
||||
records, err1 := gonjalla.ListRecords(token, domain)
|
||||
if err1 != nil {
|
||||
fmt.Println(err1)
|
||||
}
|
||||
|
||||
// It will print an array of gonjalla.Record
|
||||
fmt.Println(records)
|
||||
|
||||
|
||||
// 2. Adding a new record to a domain
|
||||
priority := 10
|
||||
adding := gonjalla.Record{
|
||||
Name: "@",
|
||||
Type: "MX",
|
||||
Content: "testing.com",
|
||||
TTL: 10800,
|
||||
Priority: &priority,
|
||||
}
|
||||
|
||||
confirmation, err2 := gonjalla.AddRecord(token, domain, adding)
|
||||
if err2 != nil {
|
||||
fmt.Println(err2)
|
||||
}
|
||||
|
||||
// confirmation will be a gonjalla.Record with the response from the
|
||||
// server, so it should be pretty similar to your starting
|
||||
// gonjalla.Record but this will contain the ID filled in, which is
|
||||
// needed for updates
|
||||
fmt.Println(confirmation)
|
||||
|
||||
|
||||
// 3. Updating a record of a given domain
|
||||
// Let's assume we got the ID of the record created in step 2
|
||||
// and we want to change either some or all fields
|
||||
id_we_look_for := confirmation.ID
|
||||
|
||||
// The edit method updates all the fields due to limitations of the
|
||||
// API. Get the record from the API if you only want to change some,
|
||||
// but not all, fields
|
||||
for _, record := range records {
|
||||
if record.ID == id_we_look_for {
|
||||
record.Content = "edited-value"
|
||||
record.TTL = 900
|
||||
|
||||
err3 := gonjalla.EditRecord(token, domain, record)
|
||||
if err3 != nil {
|
||||
fmt.Println(err3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If you don't care about overwriting previous values
|
||||
new_priority := 20
|
||||
editing := gonjalla.Record{
|
||||
ID: id_we_look_for,
|
||||
Name: "@",
|
||||
Type: "MX",
|
||||
Content: "edited-thing",
|
||||
TTL: 300,
|
||||
Priority: &new_priority,
|
||||
}
|
||||
|
||||
err4 := gonjalla.EditRecord(token, domain, editing)
|
||||
if err4 != nil {
|
||||
fmt.Println(err4)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Some actual code making use of this library (mainly dealing with records) can
|
||||
also be seen at the [Njalla Terraform provider].
|
||||
|
||||
[Njalla]: https://njal.la
|
||||
[official API]: https://njal.la/api/
|
||||
[Njalla Terraform provider]: https://github.com/Sighery/terraform-provider-njalla
|
33
domains.go
33
domains.go
|
@ -15,6 +15,13 @@ type Domain struct {
|
|||
MaxNameservers *int `json:"max_nameservers,omitempty"`
|
||||
}
|
||||
|
||||
// Domain availability and price data returned by `find-domains`
|
||||
type MarketDomain struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Price int `json:"price"`
|
||||
}
|
||||
|
||||
// ListDomains returns a listing of domains with minimal data
|
||||
func ListDomains(token string) ([]Domain, error) {
|
||||
params := map[string]interface{}{}
|
||||
|
@ -56,3 +63,29 @@ func GetDomain(token string, domain string) (Domain, error) {
|
|||
|
||||
return domainStruct, nil
|
||||
}
|
||||
|
||||
// FindDomains returns availability and price information for a query.
|
||||
// If query was `example`, then it'd show availability and price of
|
||||
// domains `example.com`, `example.net`, etc.
|
||||
func FindDomains(token string, query string) ([]MarketDomain, error) {
|
||||
params := map[string]interface{}{
|
||||
"query": query,
|
||||
}
|
||||
|
||||
data, err := Request(token, "find-domains", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Domains []MarketDomain `json:"domains"`
|
||||
}
|
||||
|
||||
var response Response
|
||||
err = json.Unmarshal(data, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response.Domains, nil
|
||||
}
|
||||
|
|
|
@ -161,3 +161,101 @@ func TestGetDomainError(t *testing.T) {
|
|||
_, err := GetDomain(token, domain)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFindDomainsExpected(t *testing.T) {
|
||||
token := "test-token"
|
||||
query := "testing"
|
||||
Client = &mocks.MockClient{}
|
||||
|
||||
testData := `{
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"domains": [
|
||||
{
|
||||
"name": "testing.com",
|
||||
"status": "taken",
|
||||
"price": 45
|
||||
},
|
||||
{
|
||||
"name": "testing.net",
|
||||
"status": "available",
|
||||
"price": 30
|
||||
},
|
||||
{
|
||||
"name": "testing.rocks",
|
||||
"status": "in progress",
|
||||
"price": 15
|
||||
},
|
||||
{
|
||||
"name": "testing.express",
|
||||
"status": "failed",
|
||||
"price": 75
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
r := ioutil.NopCloser(bytes.NewReader([]byte(testData)))
|
||||
|
||||
mocks.GetDoFunc = func(*http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
domains, err := FindDomains(token, query)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expected := []MarketDomain{
|
||||
{
|
||||
Name: "testing.com",
|
||||
Status: "taken",
|
||||
Price: 45,
|
||||
},
|
||||
{
|
||||
Name: "testing.net",
|
||||
Status: "available",
|
||||
Price: 30,
|
||||
},
|
||||
{
|
||||
Name: "testing.rocks",
|
||||
Status: "in progress",
|
||||
Price: 15,
|
||||
},
|
||||
{
|
||||
Name: "testing.express",
|
||||
Status: "failed",
|
||||
Price: 75,
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, domains, expected)
|
||||
}
|
||||
|
||||
func TestFindDomainsError(t *testing.T) {
|
||||
token := "test-token"
|
||||
query := "testing"
|
||||
Client = &mocks.MockClient{}
|
||||
|
||||
testData := `{
|
||||
"jsonrpc": "2.0",
|
||||
"error": {
|
||||
"code": 0,
|
||||
"message": "Testing error"
|
||||
}
|
||||
}`
|
||||
r := ioutil.NopCloser(bytes.NewReader([]byte(testData)))
|
||||
|
||||
mocks.GetDoFunc = func(*http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
domains, err := FindDomains(token, query)
|
||||
assert.Nil(t, domains)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
|
10
go.mod
10
go.mod
|
@ -1,5 +1,11 @@
|
|||
module github.com/Sighery/gonjalla
|
||||
|
||||
go 1.14
|
||||
go 1.17
|
||||
|
||||
require github.com/stretchr/testify v1.5.1
|
||||
require github.com/stretchr/testify v1.8.1
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
16
go.sum
16
go.sum
|
@ -1,11 +1,17 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -10,7 +10,7 @@ var ValidPriority = []int{0, 1, 5, 10, 20, 30, 40, 50, 60}
|
|||
|
||||
// Record struct contains data returned by `list-records`
|
||||
type Record struct {
|
||||
ID int `json:"id"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
|
@ -75,7 +75,7 @@ func AddRecord(token string, domain string, record Record) (Record, error) {
|
|||
|
||||
// RemoveRecord removes a given record from a given domain.
|
||||
// If there are no errors it will return `nil`.
|
||||
func RemoveRecord(token string, domain string, id int) error {
|
||||
func RemoveRecord(token string, domain string, id string) error {
|
||||
params := map[string]interface{}{
|
||||
"domain": domain,
|
||||
"id": id,
|
||||
|
@ -94,6 +94,10 @@ func RemoveRecord(token string, domain string, id int) error {
|
|||
// its filled fields to send to Njalla.
|
||||
// So, if you want to only change a given field, get the `Record` object from
|
||||
// say ListRecords, change the one field you want, and then pass that here.
|
||||
//
|
||||
// Note that the record type cannot be changed, so if you want to do so, you'll
|
||||
// have to remove and create the record again under a different type. Trying to
|
||||
// change the record type will just return an API error.
|
||||
func EditRecord(token string, domain string, record Record) error {
|
||||
marshal, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
|
|
|
@ -21,28 +21,28 @@ func TestListRecordsExpected(t *testing.T) {
|
|||
"result": {
|
||||
"records": [
|
||||
{
|
||||
"id": 1337,
|
||||
"id": "1337",
|
||||
"name": "_acme-challenge",
|
||||
"type": "TXT",
|
||||
"content": "long-string",
|
||||
"ttl": 10800
|
||||
},
|
||||
{
|
||||
"id": 1338,
|
||||
"id": "1338",
|
||||
"name": "@",
|
||||
"type": "A",
|
||||
"content": "1.2.3.4",
|
||||
"ttl": 3600
|
||||
},
|
||||
{
|
||||
"id": 1339,
|
||||
"id": "1339",
|
||||
"name": "@",
|
||||
"type": "AAAA",
|
||||
"content": "2001:0DB8:0000:0000:0000:8A2E:0370:7334",
|
||||
"ttl": 900
|
||||
},
|
||||
{
|
||||
"id": 1340,
|
||||
"id": "1340",
|
||||
"name": "@",
|
||||
"type": "MX",
|
||||
"content": "mail.protonmail.ch",
|
||||
|
@ -70,28 +70,28 @@ func TestListRecordsExpected(t *testing.T) {
|
|||
|
||||
expected := []Record{
|
||||
{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "_acme-challenge",
|
||||
Type: "TXT",
|
||||
Content: "long-string",
|
||||
TTL: 10800,
|
||||
},
|
||||
{
|
||||
ID: 1338,
|
||||
ID: "1338",
|
||||
Name: "@",
|
||||
Type: "A",
|
||||
Content: "1.2.3.4",
|
||||
TTL: 3600,
|
||||
},
|
||||
{
|
||||
ID: 1339,
|
||||
ID: "1339",
|
||||
Name: "@",
|
||||
Type: "AAAA",
|
||||
Content: "2001:0DB8:0000:0000:0000:8A2E:0370:7334",
|
||||
TTL: 900,
|
||||
},
|
||||
{
|
||||
ID: 1340,
|
||||
ID: "1340",
|
||||
Name: "@",
|
||||
Type: "MX",
|
||||
Content: "mail.protonmail.ch",
|
||||
|
@ -140,7 +140,7 @@ func TestAddRecordExpected(t *testing.T) {
|
|||
testData := `{
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"id": 1337,
|
||||
"id": "1337",
|
||||
"name": "@",
|
||||
"type": "MX",
|
||||
"content": "testing.com",
|
||||
|
@ -173,7 +173,7 @@ func TestAddRecordExpected(t *testing.T) {
|
|||
}
|
||||
|
||||
expected := Record{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "@",
|
||||
Type: "MX",
|
||||
Content: "testing.com",
|
||||
|
@ -221,7 +221,7 @@ func TestAddRecordError(t *testing.T) {
|
|||
func TestRemoveRecordExpected(t *testing.T) {
|
||||
token := "test-token"
|
||||
domain := "testing.com"
|
||||
id := 1337
|
||||
id := "1337"
|
||||
Client = &mocks.MockClient{}
|
||||
|
||||
testData := `{
|
||||
|
@ -244,7 +244,7 @@ func TestRemoveRecordExpected(t *testing.T) {
|
|||
func TestRemoveRecordError(t *testing.T) {
|
||||
token := "test-token"
|
||||
domain := "testing.com"
|
||||
id := 1337
|
||||
id := "1337"
|
||||
Client = &mocks.MockClient{}
|
||||
|
||||
testData := `{
|
||||
|
@ -275,7 +275,7 @@ func TestEditRecordExpected(t *testing.T) {
|
|||
testData := `{
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"id": 1337,
|
||||
"id": "1337",
|
||||
"name": "@",
|
||||
"type": "MX",
|
||||
"content": "testing.com",
|
||||
|
@ -294,7 +294,7 @@ func TestEditRecordExpected(t *testing.T) {
|
|||
|
||||
priority := 10
|
||||
editing := Record{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "@",
|
||||
Type: "MX",
|
||||
Content: "testing.com",
|
||||
|
@ -329,7 +329,7 @@ func TestEditRecordError(t *testing.T) {
|
|||
|
||||
priority := 10
|
||||
editing := Record{
|
||||
ID: 1337,
|
||||
ID: "1337",
|
||||
Name: "@",
|
||||
Type: "MX",
|
||||
Content: "testing.com",
|
||||
|
|
Loading…
Reference in a new issue