Skip to content

Commit

Permalink
refactor: use service factory in api handler
Browse files Browse the repository at this point in the history
  • Loading branch information
davidramiro committed Feb 11, 2024
1 parent 4c282dc commit b80ea4c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 197 deletions.
74 changes: 28 additions & 46 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package api

import (
"fmt"
"github.com/davidramiro/frigabun/pkg/cloudflare"
"github.com/davidramiro/frigabun/services"
"net/http"
"strings"

"github.com/asaskevich/govalidator"
"github.com/davidramiro/frigabun/internal/logger"
"github.com/davidramiro/frigabun/pkg/gandi"
"github.com/davidramiro/frigabun/pkg/porkbun"
"github.com/labstack/echo/v4"
)

type UpdateApi struct {
}

type StatusResponse struct {
ApiStatus bool `json:"api_status"`
}
Expand All @@ -23,12 +24,10 @@ type ApiError struct {
}

type UpdateRequest struct {
Domain string `query:"domain"`
Subdomains string `query:"subdomain"`
IP string `query:"ip"`
ApiKey string `query:"apikey"`
ApiSecretKey string `query:"apisecretkey"`
Registrar string `query:"registrar"`
Domain string `query:"domain"`
Subdomains string `query:"subdomain"`
IP string `query:"ip"`
Registrar string `query:"registrar"`
}

func HandleUpdateRequest(c echo.Context) error {
Expand All @@ -55,44 +54,27 @@ func HandleUpdateRequest(c echo.Context) error {
return c.String(http.StatusBadRequest, "missing subdomains parameter")
}

factory, err := services.NewDnsUpdateServiceFactory()
if err != nil {
return err
}

for i := range subdomains {
if request.Registrar == "gandi" {
dns := &gandi.GandiDns{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
ApiKey: request.ApiKey,
}
err := dns.SaveRecord()
if err != nil {
return c.String(err.Code, err.Message)
}
} else if request.Registrar == "porkbun" {
dns := &porkbun.PorkbunDns{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
ApiKey: request.ApiKey,
SecretApiKey: request.ApiSecretKey,
}
err := dns.AddRecord()
if err != nil {
return c.String(err.Code, err.Message)
}
} else if request.Registrar == "cloudflare" {
dns := &cloudflare.CloudflareDns{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
ApiKey: request.ApiSecretKey,
ZoneId: request.ApiKey,
}
err := dns.SaveRecord()
if err != nil {
return c.String(err.Code, err.Message)
}
} else {
return c.String(http.StatusBadRequest, "missing or invalid registrar")

service, err := factory.Find(services.Registrar(request.Registrar))
if err != nil {
return err
}

request := &services.DynDnsRequest{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
}

err = service.UpdateRecord(request)
if err != nil {
return c.String(http.StatusBadRequest, err.Error())
}

successfulUpdates++
Expand Down
153 changes: 2 additions & 151 deletions internal/api/api_test.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
package api

import (
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"runtime"
"testing"

"github.com/davidramiro/frigabun/internal/config"
"github.com/go-faker/faker/v4"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
)

func init() {
// make sure we're in project root for tests
_, filename, _, _ := runtime.Caller(0)
dir := path.Join(path.Dir(filename), "../..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}

config.InitConfig()
}

func TestStatusEndpoint(t *testing.T) {

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
Expand All @@ -45,144 +25,15 @@ func TestStatusEndpoint(t *testing.T) {

func TestValidDomainAndIp(t *testing.T) {
err := validateRequest("domain.com", "1.1.1.1")

assert.Nil(t, err, "valid domain and ip should not return error")
}

func TestInvalidIPv4(t *testing.T) {
err := validateRequest("domain.com", "::1")

assert.Equal(t, 400, err.Code, "invalid IPv4 should return error")
}

func TestInvalidDomain(t *testing.T) {
err := validateRequest("domain .com", "1.1.1.1")

assert.Equal(t, 400, err.Code, "invalid domain should return error")
}

func TestGandiUpdateWithValidRequest(t *testing.T) {
q := make(url.Values)
q.Set("ip", faker.IPv4())
q.Set("domain", config.AppConfig.Test.Gandi.Domain)
q.Set("subdomain", config.AppConfig.Test.Gandi.Subdomain+"2")
q.Set("apiKey", config.AppConfig.Test.Gandi.ApiKey)
q.Set("registrar", "gandi")

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

// Assertions
if assert.NoError(t, HandleUpdateRequest(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
b, _ := io.ReadAll(rec.Body)
assert.Contains(t, string(b), "created")
}
}

func TestPorkbunUpdateWithValidRequest(t *testing.T) {
q := make(url.Values)
q.Set("ip", faker.IPv4())
q.Set("domain", config.AppConfig.Test.Porkbun.Domain)
q.Set("subdomain", config.AppConfig.Test.Porkbun.Subdomain+"2")
q.Set("apikey", config.AppConfig.Test.Porkbun.ApiKey)
q.Set("apisecretkey", config.AppConfig.Test.Porkbun.ApiSecretKey)
q.Set("registrar", "porkbun")

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

// Assertions
if assert.NoError(t, HandleUpdateRequest(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
b, _ := io.ReadAll(rec.Body)
assert.Contains(t, string(b), "created")
}
}

func TestGandiUpdateWithInvalidIp(t *testing.T) {
q := make(url.Values)
q.Set("ip", "::1")
q.Set("domain", "domain.com")
q.Set("subdomain", "test1,test2")
q.Set("apiKey", "foo")
q.Set("registrar", "gandi")

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

// Assertions
if assert.NoError(t, HandleUpdateRequest(c)) {
assert.Equal(t, http.StatusBadRequest, rec.Code)
b, _ := io.ReadAll(rec.Body)
assert.Contains(t, string(b), "invalid IP address")
}
}

func TestGandiUpdateWithMissingParam(t *testing.T) {
q := make(url.Values)
q.Set("ip", "1.2.3.4")
q.Set("subdomain", "test1,test2")
q.Set("apiKey", "foo")
q.Set("registrar", "gandi")

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

// Assertions
if assert.NoError(t, HandleUpdateRequest(c)) {
assert.Equal(t, http.StatusBadRequest, rec.Code)
b, _ := io.ReadAll(rec.Body)
assert.Contains(t, string(b), "missing or invalid domain name")
}
}

func TestGandiUpdateWithInvalidMissingSubdomains(t *testing.T) {
q := make(url.Values)
q.Set("ip", "1.2.3.4")
q.Set("domain", "domain.com")
q.Set("apiKey", "foo")
q.Set("registrar", "gandi")

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

// Assertions
if assert.NoError(t, HandleUpdateRequest(c)) {
assert.Equal(t, http.StatusBadRequest, rec.Code)
b, _ := io.ReadAll(rec.Body)
assert.Contains(t, string(b), "missing subdomains parameter")
}
}

func TestGandiUpdateWithInvalidApiKey(t *testing.T) {
// Setup
q := make(url.Values)
q.Set("ip", "1.2.3.4")
q.Set("domain", "domain.com")
q.Set("subdomain", "test1,test2")
q.Set("apiKey", "foo")
q.Set("registrar", "gandi")

e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

// Assertions
if assert.NoError(t, HandleUpdateRequest(c)) {
assert.Equal(t, http.StatusForbidden, rec.Code)
b, _ := io.ReadAll(rec.Body)
assert.Contains(t, string(b), "gandi rejected request")
}
}

0 comments on commit b80ea4c

Please sign in to comment.