Add Swagger
continuous-integration/drone/push Build is running Details

This commit is contained in:
nemunaire 2023-08-05 18:15:52 +02:00
parent 9b6b78d837
commit 216cdee5d5
27 changed files with 900 additions and 244 deletions

View File

@ -58,8 +58,9 @@ steps:
commands:
- apk add --no-cache git
- sed -i '/npm run build/d' ui/assets.go
- go install github.com/swaggo/swag/cmd/swag@latest
- go generate -v ./...
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- ln happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} happydomain
environment:
CGO_ENABLED: 0
@ -73,8 +74,9 @@ steps:
commands:
- apk add --no-cache git
- sed -i '/npm run build/d' ui/assets.go
- go install github.com/swaggo/swag/cmd/swag@latest
- go generate -v ./...
- go build -v -tags netgo -ldflags '-w -X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- ln happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} happydomain
environment:
CGO_ENABLED: 0
@ -129,7 +131,7 @@ steps:
image: golang:1-alpine
commands:
- apk add --no-cache git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
environment:
CGO_ENABLED: 0
GOOS: darwin
@ -143,7 +145,7 @@ steps:
image: golang:1-alpine
commands:
- apk add --no-cache git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
environment:
CGO_ENABLED: 0
GOOS: darwin
@ -227,8 +229,9 @@ steps:
commands:
- apk add --no-cache git
- sed -i '/npm run build/d' ui/assets.go
- go install github.com/swaggo/swag/cmd/swag@latest
- go generate -v ./...
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- ln happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} happydomain
environment:
CGO_ENABLED: 0
@ -242,8 +245,9 @@ steps:
commands:
- apk add --no-cache git
- sed -i '/npm run build/d' ui/assets.go
- go install github.com/swaggo/swag/cmd/swag@latest
- go generate -v ./...
- go build -v -tags netgo -ldflags '-w -X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
- ln happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} happydomain
environment:
CGO_ENABLED: 0
@ -290,7 +294,7 @@ steps:
image: golang:1-alpine
commands:
- apk add --no-cache git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
environment:
CGO_ENABLED: 0
GOOS: darwin
@ -304,7 +308,7 @@ steps:
image: golang:1-alpine
commands:
- apk add --no-cache git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-darwin-${DRONE_STAGE_ARCH}
environment:
CGO_ENABLED: 0
GOOS: darwin
@ -388,8 +392,9 @@ steps:
commands:
- apk --no-cache add build-base git
- sed -i '/npm run build/d' ui/assets.go
- go install github.com/swaggo/swag/cmd/swag@latest
- go generate -v ./...
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}el
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}el
environment:
CGO_ENABLED: 0
GOARM: 5
@ -406,8 +411,9 @@ steps:
commands:
- apk --no-cache add build-base git
- sed -i '/npm run build/d' ui/assets.go
- go install github.com/swaggo/swag/cmd/swag@latest
- go generate -v ./...
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}el
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}el
environment:
CGO_ENABLED: 0
GOARM: 5
@ -454,7 +460,7 @@ steps:
image: golang:1-alpine
commands:
- apk --no-cache add build-base git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}hf
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}hf
environment:
CGO_ENABLED: 0
GOARM: 6
@ -470,7 +476,7 @@ steps:
image: golang:1-alpine
commands:
- apk --no-cache add build-base git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}hf
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}hf
environment:
CGO_ENABLED: 0
GOARM: 6
@ -517,7 +523,7 @@ steps:
image: golang:1-alpine
commands:
- apk --no-cache add build-base git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}v7
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_BRANCH}-${DRONE_COMMIT}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}v7
- ln happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}v7 happydomain
environment:
CGO_ENABLED: 0
@ -531,7 +537,7 @@ steps:
image: golang:1-alpine
commands:
- apk --no-cache add build-base git
- go build -v -tags netgo -ldflags '-w -X main.version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}v7
- go build -v -tags netgo -ldflags '-w -X main.Version="${DRONE_TAG##v}" -X main.build=${DRONE_BUILD_NUMBER}' -o happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}v7
- ln happydomain-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}v7 happydomain
environment:
CGO_ENABLED: 0

View File

@ -30,9 +30,9 @@ COPY storage ./storage
COPY utils ./utils
COPY generate.go go.mod go.sum main.go ./
RUN sed -i '/yarn --offline build/d' ui/assets.go && \
go get -d -v && \
go generate -v && \
RUN sed -i '/npm run build/d' ui/assets.go && \
go install github.com/swaggo/swag/cmd/swag@latest && \
go generate -v ./... && \
go build -v -ldflags '-w'

View File

@ -58,6 +58,19 @@ func declareDomainsRoutes(cfg *config.Options, router *gin.RouterGroup) {
declareZonesRoutes(cfg, apiDomainsRoutes)
}
// GetDomains retrieves all domains belonging to the user.
//
// @Summary Retrieve user's domains
// @Schemes
// @Description Retrieve all domains belonging to the user.
// @Tags domains
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Success 200 {array} happydns.Domain
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Unable to retrieve user's domains"
// @Router /domains [get]
func GetDomains(c *gin.Context) {
user := myUser(c)
if user == nil {
@ -75,6 +88,21 @@ func GetDomains(c *gin.Context) {
}
}
// addDomain appends a new domain to those managed.
//
// @Summary Manage a new domain
// @Schemes
// @Description Append a new domain to those managed.
// @Tags domains
// @Accept json
// @Produce json
// @Param body body happydns.DomainMinimal true "Domain object that you want to manage through happyDomain."
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.Domain
// @Failure 400 {object} happydns.Error "Error in received data"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 500 {object} happydns.Error "Unable to retrieve current user's domains"
// @Router /domains [post]
func addDomain(c *gin.Context) {
var uz happydns.Domain
err := c.ShouldBindJSON(&uz)
@ -140,15 +168,15 @@ func DomainHandler(c *gin.Context) {
return
}
// If source is provided, check that the domain is a parent of the source
var source *happydns.SourceMeta
if src, exists := c.Get("source"); exists {
source = &src.(*happydns.SourceCombined).SourceMeta
} else if src, exists := c.Get("sourcemeta"); exists {
source = src.(*happydns.SourceMeta)
// If provider is provided, check that the domain is a parent of the provider
var provider *happydns.ProviderMeta
if src, exists := c.Get("provider"); exists {
provider = &src.(*happydns.ProviderCombined).ProviderMeta
} else if src, exists := c.Get("providermeta"); exists {
provider = src.(*happydns.ProviderMeta)
}
if source != nil && !source.Id.Equals(domain.IdProvider) {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Domain not found (not child of source)"})
if provider != nil && !provider.Id.Equals(domain.IdProvider) {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Domain not found (not child of provider)"})
return
}
@ -158,14 +186,40 @@ func DomainHandler(c *gin.Context) {
}
type apiDomain struct {
Id happydns.Identifier `json:"id"`
IdUser happydns.Identifier `json:"id_owner"`
IdProvider happydns.Identifier `json:"id_provider"`
DomainName string `json:"domain"`
// Id is the Domain's identifier in the database.
Id happydns.Identifier `json:"id" swaggertype:"string"`
// IdUser is the identifier of the Domain's Owner.
IdUser happydns.Identifier `json:"id_owner" swaggertype:"string"`
// IsProvider is the identifier of the Provider used to access and edit the
// Domain.
IdProvider happydns.Identifier `json:"id_provider" swaggertype:"string"`
// DomainName is the FQDN of the managed Domain.
DomainName string `json:"domain"`
// Group is a hint string aims to group domains.
Group string `json:"group,omitempty"`
// ZoneHistory are the metadata associated to each Zone saved with the
// current Domain.
ZoneHistory []happydns.ZoneMeta `json:"zone_history"`
Group string `json:"group,omitempty"`
}
// GetDomain retrieves information about a given Domain owned by the user.
//
// @Summary Retrieve Domain local information.
// @Schemes
// @Description Retrieve information in the database about a given Domain owned by the user.
// @Tags domains
// @Accept json
// @Produce json
// @Param domainId path string true "Domain identifier"
// @Security securitydefinitions.basic
// @Success 200 {object} apiDomain
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain not found"
// @Router /domains/{domainId} [get]
func GetDomain(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
ret := &apiDomain{
@ -190,6 +244,24 @@ func GetDomain(c *gin.Context) {
c.JSON(http.StatusOK, ret)
}
// UpdateDomain updates the information about a given Domain owned by the user.
//
// @Summary Update Domain local information.
// @Schemes
// @Description Updates the information about a given Domain owned by the user.
// @Tags domains
// @Accept json
// @Produce json
// @Param domainId path string true "Domain identifier"
// @Param body body happydns.Domain true "The new object overriding the current domain"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.Domain
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 400 {object} happydns.Error "Identifier changed"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain not found"
// @Failure 500 {object} happydns.Error "Database writing error"
// @Router /domains/{domainId} [put]
func UpdateDomain(c *gin.Context) {
old := c.MustGet("domain").(*happydns.Domain)
@ -217,6 +289,22 @@ func UpdateDomain(c *gin.Context) {
c.JSON(http.StatusOK, old)
}
// delDomain removes a domain from the database.
//
// @Summary Stop managing a Domain.
// @Schemes
// @Description Delete all the information in the database about the given Domain. This only stops happyDomain from managing the Domain, it doesn't do anything on the Provider.
// @Tags domains
// @Accept json
// @Produce json
// @Param domainId path string true "Domain identifier"
// @Security securitydefinitions.basic
// @Success 204 "Domain deleted"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain not found"
// @Failure 500 {object} happydns.Error "Database writing error"
// @Router /domains/{domainId} [delete]
func delDomain(c *gin.Context) {
if err := storage.MainStore.DeleteDomain(c.MustGet("domain").(*happydns.Domain)); err != nil {
log.Printf("%s was unable to DeleteDomain: %s", c.ClientIP(), err.Error())
@ -224,5 +312,5 @@ func delDomain(c *gin.Context) {
return
}
c.JSON(http.StatusNoContent, true)
c.Status(http.StatusNoContent)
}

View File

@ -40,10 +40,17 @@ import (
)
type FormState struct {
Id *happydns.Identifier `json:"_id,omitempty"`
Name string `json:"_comment"`
State int32 `json:"state"`
Recall string `json:"recall,omitempty"`
// Id for an already existing element.
Id *happydns.Identifier `json:"_id,omitempty" swaggertype:"string"`
// User defined name of the element.
Name string `json:"_comment"`
// State is the desired form to shows next (starting at 0).
State int32 `json:"state"`
// Recall is the identifier for a saved FormState you want to retrieve.
Recall string `json:"recall,omitempty"`
}
func formDoState(cfg *config.Options, c *gin.Context, fs *FormState, data interface{}, defaultForm func(interface{}) *forms.CustomForm) (form *forms.CustomForm, d map[string]interface{}, err error) {

View File

@ -54,15 +54,31 @@ func declareProviderSettingsRoutes(cfg *config.Options, router *gin.RouterGroup)
type ProviderSettingsState struct {
FormState
happydns.Provider
happydns.Provider `json:"Provider" swaggertype:"object"`
}
type ProviderSettingsResponse struct {
Provider *happydns.Provider `json:"Provider,omitempty"`
Provider *happydns.Provider `json:"Provider,omitempty" swaggertype:"object"`
Values map[string]interface{} `json:"values,omitempty"`
Form *forms.CustomForm `json:"form,omitempty"`
}
// getProviderSettingsState creates or updates a Provider with human fillable forms.
// @Summary Assistant to Provider creation.
// @Schemes
// @Description This creates or updates a Provider with human fillable forms.
// @Tags provider_specs
// @Accept json
// @Produce json
// @Param providerType path string true "The provider's type"
// @Param body body ProviderSettingsState true "The current state of the Provider's settings, possibly empty (but not null)"
// @Security securitydefinitions.basic
// @Success 200 {object} ProviderSettingsResponse "The settings need more rafinement"
// @Success 200 {object} happydns.ProviderCombined "The Provider has been created with the given settings"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Provider not found"
// @Router /providers/_specs/{providerType}/settings [post]
func getProviderSettingsState(cfg *config.Options, c *gin.Context) {
user := myUser(c)
if user == nil {

View File

@ -54,6 +54,15 @@ func declareProviderSpecsRoutes(router *gin.RouterGroup) {
apiProviderSpecsRoutes.GET("", getProviderSpec)
}
// listProviders returns the static list of usable providers in this happyDomain release.
// @Summary List all providers with which you can connect.
// @Schemes
// @Description This returns the static list of usable providers in this happyDomain release.
// @Tags provider_specs
// @Accept json
// @Produce json
// @Success 200 {object} map[string]providers.ProviderInfos{} "The list"
// @Router /providers/_specs [get]
func listProviders(c *gin.Context) {
srcs := providers.GetProviders()
@ -65,6 +74,17 @@ func listProviders(c *gin.Context) {
c.JSON(http.StatusOK, ret)
}
// getProviderSpecIcon returns the icon as image/png.
// @Summary Get the PNG icon.
// @Schemes
// @Description Return the icon as a image/png file for the given provider type.
// @Tags provider_specs
// @Accept json
// @Produce png
// @Param providerType path string true "The provider's type"
// @Success 200 {file} png
// @Failure 404 {object} happydns.Error "Provider type does not exist"
// @Router /providers/_specs/{providerType}/icon.png [get]
func getProviderSpecIcon(c *gin.Context) {
psid := string(c.Param("psid"))
@ -91,10 +111,24 @@ func ProviderSpecsHandler(c *gin.Context) {
}
type viewProviderSpec struct {
Fields []*forms.Field `json:"fields,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
// Fields describes the settings needed to configure the provider.
Fields []*forms.Field `json:"fields,omitempty"`
// Capabilities exposes what the provider can do.
Capabilities []string `json:"capabilities,omitempty"`
}
// getProviderSpec returns a description of the expected settings and the provider capabilities.
// @Summary Get the provider capabilities and expected settings.
// @Schemes
// @Description Return a description of the expected settings and the provider capabilities.
// @Tags provider_specs
// @Accept json
// @Produce json
// @Param providerType path string true "The provider's type"
// @Success 200 {object} viewProviderSpec
// @Failure 404 {object} happydns.Error "Provider type does not exist"
// @Router /providers/_specs/{providerType} [get]
func getProviderSpec(c *gin.Context) {
src := c.MustGet("providertype").(happydns.Provider)

View File

@ -65,6 +65,18 @@ func declareProvidersRoutes(cfg *config.Options, router *gin.RouterGroup) {
apiProviderRoutes.GET("/domains", getDomainsHostedByProvider)
}
// getDomains retrieves all providers belonging to the user.
// @Summary Retrieve user's providers
// @Schemes
// @Description Retrieve all DNS providers belonging to the user.
// @Tags providers
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Success 200 {array} happydns.Provider
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Unable to retrieve user's domains"
// @Router /providers [get]
func getProviders(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
@ -171,12 +183,39 @@ func ProviderHandler(c *gin.Context) {
c.Next()
}
// GetProvider retrieves information about a given Provider owned by the user.
// @Summary Retrieve Provider information.
// @Schemes
// @Description Retrieve information in the database about a given Provider owned by the user.
// @Tags providers
// @Accept json
// @Produce json
// @Param providerId path string true "Provider identifier"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.ProviderCombined
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Provider not found"
// @Router /providers/{providerId} [get]
func GetProvider(c *gin.Context) {
provider := c.MustGet("provider").(*happydns.ProviderCombined)
c.JSON(http.StatusOK, provider)
}
// addProvider appends a new provider.
// @Summary Add a new provider
// @Schemes
// @Description Append a new provider for the user.
// @Tags providers
// @Accept json
// @Produce json
// @Param body body happydns.ProviderMinimal true "Provider to add"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.Provider
// @Failure 400 {object} happydns.Error "Error in received data"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 500 {object} happydns.Error "Unable to retrieve current user's providers"
// @Router /providers [post]
func addProvider(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
@ -196,6 +235,23 @@ func addProvider(c *gin.Context) {
c.JSON(http.StatusOK, s)
}
// UpdateProvider updates the information about a given Provider owned by the user.
// @Summary Update Provider information.
// @Schemes
// @Description Updates the information about a given Provider owned by the user.
// @Tags providers
// @Accept json
// @Produce json
// @Param providerId path string true "Provider identifier"
// @Param body body happydns.Provider true "The new object overriding the current provider"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.Provider
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 400 {object} happydns.Error "Identifier changed"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Provider not found"
// @Failure 500 {object} happydns.Error "Database writing error"
// @Router /providers/{providerId} [put]
func UpdateProvider(c *gin.Context) {
provider := c.MustGet("provider").(*happydns.ProviderCombined)
@ -217,6 +273,21 @@ func UpdateProvider(c *gin.Context) {
c.JSON(http.StatusOK, src)
}
// deleteProvider removes a provider from the database.
// @Summary Delete a Provider.
// @Schemes
// @Description Delete a Provider from the database. It is required that no Domain are still managed by this Provider before calling this route.
// @Tags providers
// @Accept json
// @Produce json
// @Param providerId path string true "Provider identifier"
// @Security securitydefinitions.basic
// @Success 204 "Provider deleted"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Provider not found"
// @Failure 500 {object} happydns.Error "Database writing error"
// @Router /providers/{providerId} [delete]
func deleteProvider(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
providermeta := c.MustGet("providermeta").(*happydns.ProviderMeta)
@ -245,6 +316,22 @@ func deleteProvider(c *gin.Context) {
c.JSON(http.StatusNoContent, nil)
}
// getDomainsHostedByProvider lists domains available to management from the given Provider.
// @Summary Lists manageable domains from the Provider.
// @Schemes
// @Description List domains available from the given Provider.
// @Tags providers
// @Accept json
// @Produce json
// @Param providerId path string true "Provider identifier"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.ProviderCombined
// @Failure 400 {object} happydns.Error "Unable to instantiate the provider"
// @Failure 400 {object} happydns.Error "The provider doesn't support domain listing"
// @Failure 400 {object} happydns.Error "Provider error"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Provider not found"
// @Router /providers/{providerId}/domains [get]
func getDomainsHostedByProvider(c *gin.Context) {
provider := c.MustGet("provider").(*happydns.ProviderCombined)

View File

@ -51,11 +51,19 @@ func declareResolverRoutes(router *gin.RouterGroup) {
router.POST("/resolver", runResolver)
}
// resolverRequest holds the resolution parameters
type resolverRequest struct {
Resolver string `json:"resolver"`
Custom string `json:"custom,omitempty"`
// Resolver is the name of the resolver to use (or local or custom).
Resolver string `json:"resolver"`
// Custom is the address to the recursive server to use.
Custom string `json:"custom,omitempty"`
// DomainName is the FQDN to resolve.
DomainName string `json:"domain"`
Type string `json:"type"`
// Type is the type of record to retrieve.
Type string `json:"type"`
}
func resolverANYQuestion(client dns.Client, resolver string, dn string) (r *dns.Msg, err error) {
@ -105,6 +113,49 @@ func resolverQuestion(client dns.Client, resolver string, dn string, rrType uint
return r, err
}
// DNSMsg is the documentation structur corresponding to dns.Msg
type DNSMsg struct {
// Question is the Question section of the DNS response.
Question []DNSQuestion
// Answer is the list of Answer records in the DNS response.
Answer []interface{} `swaggertype:"object"`
// Ns is the list of Authoritative records in the DNS response.
Ns []interface{} `swaggertype:"object"`
// Extra is the list of extra records in the DNS response.
Extra []interface{} `swaggertype:"object"`
}
type DNSQuestion struct {
// Name is the domain name researched.
Name string
// Qtype is the type of record researched.
Qtype uint16
// Qclass is the class of record researched.
Qclass uint16
}
// runResolver performs a NS resolution for a given domain, with options.
// @Summary Perform a DNS resolution.
// @Schemes
// @Description Perform a NS resolution for a given domain, with options.
// @Tags resolver
// @Accept json
// @Produce json
// @Param body body resolverRequest true "Options to the resolution"
// @Success 200 {object} DNSMsg
// @Success 204 {object} happydns.Error "No content"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 403 {object} happydns.Error "The resolver refused to treat our request"
// @Failure 404 {object} happydns.Error "The domain doesn't exist"
// @Failure 406 {object} happydns.Error "The resolver returned an error"
// @Failure 500 {object} happydns.Error
// @Router /resolver [post]
func runResolver(c *gin.Context) {
var urr resolverRequest
if err := c.ShouldBindJSON(&urr); err != nil {

View File

@ -32,11 +32,38 @@
package api
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"git.happydns.org/happydomain/config"
docs "git.happydns.org/happydomain/docs"
)
// @title happyDomain API
// @version 0.1
// @description Finally a simple interface for domain names.
// @contact.name happyDomain team
// @contact.email contact+api@happydomain.org
// @license.name CeCILL Free Software License Agreement
// @license.url https://spdx.org/licenses/CECILL-2.1.html
// @host localhost:8081
// @BasePath /api
// @securityDefinitions.basic BasicAuth
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
// @description Description for what is this security definition being used
func DeclareRoutes(cfg *config.Options, router *gin.Engine) {
apiRoutes := router.Group("/api")
@ -54,4 +81,17 @@ func DeclareRoutes(cfg *config.Options, router *gin.Engine) {
declareProvidersRoutes(cfg, apiAuthRoutes)
declareProviderSettingsRoutes(cfg, apiAuthRoutes)
declareUsersAuthRoutes(cfg, apiAuthRoutes)
// Expose Swagger
if cfg.ExternalURL != "" {
docs.SwaggerInfo.Host = cfg.ExternalURL[strings.Index(cfg.ExternalURL, "://")+3:]
} else {
docs.SwaggerInfo.Host = fmt.Sprintf("localhost%s", cfg.Bind[strings.Index(cfg.Bind, ":"):])
}
docs.SwaggerInfo.BasePath = "/api"
if cfg.BaseURL != "" {
docs.SwaggerInfo.BasePath = cfg.BaseURL + docs.SwaggerInfo.BasePath
}
router.GET("/swagger", func(c *gin.Context) { c.Redirect(http.StatusFound, "./swagger/index.html") })
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
}

View File

@ -53,13 +53,31 @@ func declareServiceSettingsRoutes(cfg *config.Options, router *gin.RouterGroup)
type ServiceSettingsState struct {
FormState
happydns.Service
happydns.Service `json:"Service" swaggertype:"object"`
}
type ServiceSettingsResponse struct {
Services map[string][]*happydns.ServiceCombined `json:"services,omitempty"`
Values map[string]interface{} `json:"values,omitempty"`
Form *forms.CustomForm `json:"form,omitempty"`
}
// getServiceSettingsState creates or updates a Service with human fillable forms.
// @Summary Assistant to Service creation.
// @Schemes
// @Description This creates or updates a Service with human fillable forms.
// @Tags service_specs
// @Accept json
// @Produce json
// @Param serviceType path string true "The service's type"
// @Param body body ServiceSettingsState true "The current state of the Service's parameters, possibly empty (but not null)"
// @Security securitydefinitions.basic
// @Success 200 {object} ServiceSettingsResponse "The settings need more rafinement"
// @Success 200 {object} happydns.ServiceCombined "The Service has been created with the given settings"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Service not found"
// @Router /service/{serviceType} [post]
func getServiceSettingsState(cfg *config.Options, c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
zone := c.MustGet("zone").(*happydns.Zone)
@ -118,7 +136,7 @@ func getServiceSettingsState(cfg *config.Options, c *gin.Context) {
return
}
c.JSON(http.StatusOK, ProviderSettingsResponse{
c.JSON(http.StatusOK, ServiceSettingsResponse{
Form: form,
Values: p,
})

View File

@ -54,6 +54,15 @@ func declareServiceSpecsRoutes(router *gin.RouterGroup) {
apiServiceSpecsRoutes.GET("", getServiceSpec)
}
// getServiceSpecs returns the static list of usable services in this happyDomain release.
// @Summary List all services with which you can connect.
// @Schemes
// @Description This returns the static list of usable services in this happyDomain release.
// @Tags service_specs
// @Accept json
// @Produce json
// @Success 200 {object} map[string]svcs.ServiceInfos{} "The list"
// @Router /service_specs [get]
func getServiceSpecs(c *gin.Context) {
services := svcs.GetServices()
@ -65,6 +74,17 @@ func getServiceSpecs(c *gin.Context) {
c.JSON(http.StatusOK, ret)
}
// getServiceSpecIcon returns the icon as image/png.
// @Summary Get the PNG icon.
// @Schemes
// @Description Return the icon as a image/png file for the given service type.
// @Tags service_specs
// @Accept json
// @Produce png
// @Param serviceType path string true "The service's type"
// @Success 200 {file} png
// @Failure 404 {object} happydns.Error "Service type does not exist"
// @Router /service_specs/{serviceType}/icon.png [get]
func getServiceSpecIcon(c *gin.Context) {
ssid := string(c.Param("ssid"))
@ -144,6 +164,17 @@ func getSpecs(svcType reflect.Type) viewServiceSpec {
return viewServiceSpec{fields}
}
// getServiceSpec returns a description of the expected fields.
// @Summary Get the service expected fields.
// @Schemes
// @Description Return a description of the expected fields.
// @Tags service_specs
// @Accept json
// @Produce json
// @Param serviceType path string true "The service's type"
// @Success 200 {object} viewServiceSpec
// @Failure 404 {object} happydns.Error "Service type does not exist"
// @Router /services/_specs/{serviceType} [get]
func getServiceSpec(c *gin.Context) {
svctype := c.MustGet("servicetype").(reflect.Type)

View File

@ -1,92 +0,0 @@
// Copyright or © or Copr. happyDNS (2020)
//
// contact@happydomain.org
//
// This software is a computer program whose purpose is to provide a modern
// interface to interact with DNS systems.
//
// This software is governed by the CeCILL license under French law and abiding
// by the rules of distribution of free software. You can use, modify and/or
// redistribute the software under the terms of the CeCILL license as
// circulated by CEA, CNRS and INRIA at the following URL
// "http://www.cecill.info".
//
// As a counterpart to the access to the source code and rights to copy, modify
// and redistribute granted by the license, users are provided only with a
// limited warranty and the software's author, the holder of the economic
// rights, and the successive licensors have only limited liability.
//
// In this respect, the user's attention is drawn to the risks associated with
// loading, using, modifying and/or developing or reproducing the software by
// the user in light of its specific status of free software, that may mean
// that it is complicated to manipulate, and that also therefore means that it
// is reserved for developers and experienced professionals having in-depth
// computer knowledge. Users are therefore encouraged to load and test the
// software's suitability as regards their requirements in conditions enabling
// the security of their systems and/or data to be ensured and, more generally,
// to use and operate it in the same conditions as regards security.
//
// The fact that you are presently reading this means that you have had
// knowledge of the CeCILL license and that you accept its terms.
package api
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"git.happydns.org/happydomain/model"
"git.happydns.org/happydomain/services"
"git.happydns.org/happydomain/storage"
)
func declareServiceRoutes(router *gin.RouterGroup) {
router.GET("/services", listServices)
//router.POST("/services", newService)
//router.POST("/domains/:domain/analyze", analyzeDomain)
}
func listServices(c *gin.Context) {
ret := map[string]svcs.ServiceInfos{}
for k, svc := range *svcs.GetServices() {
ret[k] = svc.Infos
}
c.JSON(http.StatusOK, ret)
}
func analyzeDomain(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
user := myUser(c)
if user == nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": "User not defined"})
return
}
provider, err := storage.MainStore.GetProvider(user, domain.IdProvider)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Unable to get the related provider: %s", err.Error())})
return
}
zone, err := provider.ImportZone(domain)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Unable to import zone: %s", err.Error())})
return
}
services, defaultTTL, err := svcs.AnalyzeZone(domain.DomainName, zone)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs during analysis: %s", err.Error())})
return
}
c.JSON(http.StatusOK, gin.H{
"services": services,
"defaultTTL": defaultTTL,
})
}

View File

@ -71,10 +71,17 @@ func declareAuthenticationRoutes(opts *config.Options, router *gin.RouterGroup)
}
type DisplayUser struct {
Id happydns.Identifier `json:"id"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at,omitempty"`
Settings happydns.UserSettings `json:"settings,omitempty"`
// Id is the user identifier
Id happydns.Identifier `json:"id" swaggertype:"string"`
// Email is the user email.
Email string `json:"email"`
// CreatedAt stores the date of the account creation.
CreatedAt time.Time `json:"created_at,omitempty"`
// Settings holds the user configuration.
Settings happydns.UserSettings `json:"settings,omitempty"`
}
func currentUser(u *happydns.User) *DisplayUser {
@ -86,6 +93,18 @@ func currentUser(u *happydns.User) *DisplayUser {
}
}
// displayAuthToken returns the user information.
//
// @Summary User info.
// @Schemes
// @Description Retrieve information about the currently logged user.
// @Tags user_auth
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Success 200 {object} DisplayUser
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Router /auth [get]
func displayAuthToken(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
@ -117,6 +136,17 @@ func displayNotAuthToken(opts *config.Options, c *gin.Context) {
}
}
// logout closes the user session.
//
// @Summary Close session.
// @Schemes
// @Description Erase the HTTP-only cookie. This leads to user logout in its browser.
// @Tags user_auth
// @Accept json
// @Produce json
// @Success 204 {null} null "Loged out"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Router /auth/logout [post]
func logout(opts *config.Options, c *gin.Context) {
c.SetCookie(
COOKIE_NAME,
@ -127,14 +157,30 @@ func logout(opts *config.Options, c *gin.Context) {
opts.DevProxy == "" && !strings.HasPrefix(opts.ExternalURL, "http://"),
true,
)
c.JSON(http.StatusNoContent, true)
c.Status(http.StatusNoContent)
}
type loginForm struct {
Email string
// Email of the user.
Email string
// Password of the user.
Password string
}
// checkAuth validate user authentication and delivers a session token.
//
// @Summary Authenticate user.
// @Schemes
// @Description Validate user authentication and delivers a session token.
// @Tags user_auth
// @Accept json
// @Produce json
// @Param body body loginForm true "Login information"
// @Success 200 {object} DisplayUser "Login success"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 500 {object} happydns.Error
// @Router /auth [post]
func checkAuth(opts *config.Options, c *gin.Context) {
var lf loginForm
if err := c.ShouldBindJSON(&lf); err != nil {

View File

@ -93,16 +93,27 @@ func myUser(c *gin.Context) (user *happydns.User) {
return
}
type UploadedUser struct {
Kind string
type UserRegistration struct {
Email string
Password string
Language string `json:"lang,omitempty"`
Newsletter bool `json:"wantReceiveUpdate,omitempty"`
}
// registerUser checks and appends a user in the database.
// @Summary Register account.
// @Schemes
// @Description Register a new happyDomain account (when using internal authentication system).
// @Tags users
// @Accept json
// @Produce json
// @Param body body UserRegistration true "Account information"
// @Success 200 {object} happydns.User "The created user"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 500 {object} happydns.Error
// @Router /users [post]
func registerUser(opts *config.Options, c *gin.Context) {
var uu UploadedUser
var uu UserRegistration
err := c.ShouldBindJSON(&uu)
if err != nil {
log.Printf("%s sends invalid User JSON: %s", c.ClientIP(), err.Error())
@ -150,8 +161,27 @@ func registerUser(opts *config.Options, c *gin.Context) {
c.JSON(http.StatusOK, user)
}
type UserSpecialAction struct {
// Kind of special action to perform: "recovery" or "validation".
Kind string
// Email on which to perform actions.
Email string
}
// specialUserOperations performs account recovery.
// @Summary Account recovery.
// @Schemes
// @Description This will send an email to the user either to recover its account or with a new email validation link.
// @Tags users
// @Accept json
// @Produce json
// @Param body body UserSpecialAction true "Description of the action to perform and email of the user"
// @Success 200 {object} happydns.Error "Perhaps something happen"
// @Failure 500 {object} happydns.Error
// @Router /users [patch]
func specialUserOperations(opts *config.Options, c *gin.Context) {
var uu UploadedUser
var uu UserSpecialAction
err := c.ShouldBindJSON(&uu)
if err != nil {
log.Printf("%s sends invalid User JSON: %s", c.ClientIP(), err.Error())
@ -229,12 +259,41 @@ func getUser(c *gin.Context) {
c.JSON(http.StatusOK, user)
}
// getUserSettings gets the settings of the given user.
// @Summary Retrieve user's settings.
// @Schemes
// @Description Retrieve the user's settings.
// @Tags users
// @Accept json
// @Produce json
// @Param userId path string true "User identifier"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.UserSettings "User settings"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 403 {object} happydns.Error "Not your account"
// @Router /users/{userId}/settings [get]
func getUserSettings(c *gin.Context) {
user := c.MustGet("user").(*happydns.User)
c.JSON(http.StatusOK, user.Settings)
}
// changeUserSettings updates the settings of the given user.
// @Summary Update user's settings.
// @Schemes
// @Description Update the user's settings.
// @Tags users
// @Accept json
// @Produce json
// @Param userId path string true "User identifier"
// @Param body body happydns.UserSettings true "User settings"
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.UserSettings "User settings"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 403 {object} happydns.Error "Not your account"
// @Failure 500 {object} happydns.Error
// @Router /users/{userId}/settings [post]
func changeUserSettings(c *gin.Context) {
user := c.MustGet("user").(*happydns.User)
@ -262,6 +321,22 @@ type passwordForm struct {
PasswordConfirm string
}
// changePassword changes the password of the given account.
// @Summary Change password
// @Schemes
// @Description Change the password of the given account.
// @Tags users
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param userId path string true "User identifier"
// @Param body body passwordForm true "Password confirmation"
// @Success 204 {null} null
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 403 {object} happydns.Error "Bad current password"
// @Failure 500 {object} happydns.Error
// @Router /users/{userId}/new_password [post]
func changePassword(opts *config.Options, c *gin.Context) {
user := c.MustGet("authuser").(*happydns.UserAuth)
@ -314,6 +389,22 @@ func changePassword(opts *config.Options, c *gin.Context) {
logout(opts, c)
}
// deleteUser delete the account related to the given user.
// @Summary Drop account
// @Schemes
// @Description Delete the account related to the given user.
// @Tags users
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param userId path string true "User identifier"
// @Param body body passwordForm true "Password confirmation"
// @Success 204 {null} null
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 403 {object} happydns.Error "Bad current password"
// @Failure 500 {object} happydns.Error
// @Router /users/{userId}/delete [post]
func deleteUser(opts *config.Options, c *gin.Context) {
user := c.MustGet("authuser").(*happydns.UserAuth)
@ -408,9 +499,23 @@ func userAuthHandler(c *gin.Context) {
}
type UploadedAddressValidation struct {
// Key able to validate the email address.
Key string
}
// validateUserAddress validates a user address after registration.
// @Summary Validate e-mail address.
// @Schemes
// @Description This is the route called by the web interface in order to validate the e-mail address of the user.
// @Tags users
// @Accept json
// @Produce json
// @Param userId path string true "User identifier"
// @Param body body UploadedAddressValidation true "Validation form"
// @Success 204 {null} null "Email validated, you can now login"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 500 {object} happydns.Error
// @Router /users/{userId}/email [post]
func validateUserAddress(c *gin.Context) {
user := c.MustGet("authuser").(*happydns.UserAuth)
@ -434,14 +539,30 @@ func validateUserAddress(c *gin.Context) {
return
}
c.JSON(http.StatusNoContent, true)
c.Status(http.StatusNoContent)
}
type UploadedAccountRecovery struct {
Key string
// Key is the secret sent by email to the user.
Key string
// Password is the new password to use with this account.
Password string
}
// recoverUserAccount performs account recovery by reseting the password of the account.
// @Summary Reset password with link in email.
// @Schemes
// @Description This performs account recovery by reseting the password of the account.
// @Tags users
// @Accept json
// @Produce json
// @Param userId path string true "User identifier"
// @Param body body UploadedAccountRecovery true "Recovery form"
// @Success 204 {null} null "Recovery completed, you can now login with your new credentials"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 500 {object} happydns.Error
// @Router /users/{userId}/recovery [post]
func recoverUserAccount(c *gin.Context) {
user := c.MustGet("authuser").(*happydns.UserAuth)
@ -475,19 +596,41 @@ func recoverUserAccount(c *gin.Context) {
}
log.Printf("%s: User recovered: %s", c.ClientIP(), user.Email)
c.JSON(http.StatusNoContent, true)
c.Status(http.StatusNoContent)
}
// getSession gets the content of the current user's session.
// @Summary Retrieve user's session content
// @Schemes
// @Description Get the content of the current user's session.
// @Tags users
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Success 200 {object} happydns.Session
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Router /sessions [get]
func getSession(c *gin.Context) {
session := c.MustGet("MySession").(*happydns.Session)
c.JSON(http.StatusOK, session)
}
// clearSession removes the content of the current user's session.
// @Summary Remove user's session content
// @Schemes
// @Description Remove the content of the current user's session.
// @Tags users
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Success 204 {null} null
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Router /sessions [delete]
func clearSession(c *gin.Context) {
session := c.MustGet("MySession").(*happydns.Session)
session.ClearSession()
c.JSON(http.StatusOK, true)
c.Status(http.StatusNoContent)
}

View File

@ -37,10 +37,27 @@ import (
"github.com/gin-gonic/gin"
)
var (
HDVersion Version
)
func DeclareVersionRoutes(router *gin.RouterGroup) {
router.GET("/version", showVersion)
}
func showVersion(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"version": 0.1})
type Version struct {
Version string `json:"version"`
}
// showVersion returns the current happyDomain version.
// @Summary Get happyDomain version
// @Schemes
// @Description Retrieve the current happyDomain version.
// @Tags version
// @Accept json
// @Produce json
// @Success 200 {object} Version
// @Router /version [get]
func showVersion(c *gin.Context) {
c.JSON(http.StatusOK, HDVersion)
}

View File

@ -125,13 +125,50 @@ func subdomainHandler(c *gin.Context) {
c.Next()
}
type zoneServices struct {
Services []*happydns.ServiceCombined `json:"services"`
}
// getZoneSubdomain returns the services associated with a given subdomain.
// @Summary List services
// @Schemes
// @Description Returns the services associated with the given subdomain.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param subdomain path string true "Part of the subdomain considered for the service (@ for the root of the zone ; subdomain is relative to the root, do not include it)"
// @Success 200 {object} zoneServices
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId}/{subdomain} [get]
func getZoneSubdomain(c *gin.Context) {
zone := c.MustGet("zone").(*happydns.Zone)
subdomain := c.MustGet("subdomain").(string)
c.JSON(http.StatusOK, gin.H{"services": zone.Services[subdomain]})
c.JSON(http.StatusOK, zoneServices{
Services: zone.Services[subdomain],
})
}
// addZoneService adds a Service to the given subdomain of the Zone.
// @Summary Add a Service.
// @Schemes
// @Description Add a Service to the given subdomain of the Zone.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param subdomain path string true "Part of the subdomain considered for the service (@ for the root of the zone ; subdomain is relative to the root, do not include it)"
// @Success 200 {object} happydns.Zone
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId}/{subdomain}/services [post]
func addZoneService(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
zone := c.MustGet("zone").(*happydns.Zone)
@ -178,6 +215,22 @@ func serviceIdHandler(c *gin.Context) {
c.Next()
}
// getServiceService retrieves the designated Service.
// @Summary Get the Service.
// @Schemes
// @Description Retrieve the designated Service.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param subdomain path string true "Part of the subdomain considered for the service (@ for the root of the zone ; subdomain is relative to the root, do not include it)"
// @Param serviceId path string true "Service identifier"
// @Success 200 {object} happydns.ServiceCombined
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId}/{subdomain}/services/{serviceId} [get]
func getZoneService(c *gin.Context) {
zone := c.MustGet("zone").(*happydns.Zone)
serviceid := c.MustGet("serviceid").([]byte)
@ -186,6 +239,19 @@ func getZoneService(c *gin.Context) {
c.JSON(http.StatusOK, zone.FindSubdomainService(subdomain, serviceid))
}
// retrieveZone retrieves the current zone deployed on the NS Provider.
// @Summary Retrieve the zone on the Provider.
// @Schemes
// @Description Retrieve the current zone deployed on the NS Provider.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Success 200 {object} happydns.ZoneMeta "The new zone metadata"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain not found"
// @Router /domains/{domainId}/retrieve_zone [post]
func retrieveZone(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
domain := c.MustGet("domain").(*happydns.Domain)
@ -285,6 +351,24 @@ func importZone(c *gin.Context) {
c.JSON(http.StatusOK, zone)
}
// diffZones computes the difference between the two zone identifiers given.
// @Summary Compute differences between zones.
// @Schemes
// @Description Compute the difference between the two zone identifiers given.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId1 path string true "Zone identifier to use as the old one. Currently only @ are expected, to use the currently deployed zone."
// @Param zoneId2 path string true "Zone identifier to use as the new one"
// @Success 200 {object} []string "Differences, reported as text, one diff per item"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain not found"
// @Failure 500 {object} happydns.Error
// @Failure 501 {object} happydns.Error "Diff between to zone identifier, currently not supported"
// @Router /domains/{domainId}/diff_zones/{zoneId1}/{zoneId2} [post]
func diffZones(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
domain := c.MustGet("domain").(*happydns.Domain)
@ -331,6 +415,23 @@ func diffZones(c *gin.Context) {
c.JSON(http.StatusOK, rrCorected)
}
// applyZone performs the requested changes with the provider.
// @Summary Performs requested changes to the real zone.
// @Schemes
// @Description Perform the requested changes with the provider.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param body body []string true "Differences (from /diff_zones) to apply"
// @Success 200 {object} happydns.ZoneMeta "The new Zone metadata containing the current zone"
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Failure 500 {object} happydns.Error
// @Router /domains/{domainId}/zone/{zoneId}/apply_changes [post]
func applyZone(c *gin.Context) {
user := c.MustGet("LoggedUser").(*happydns.User)
domain := c.MustGet("domain").(*happydns.Domain)
@ -422,6 +523,20 @@ func applyZone(c *gin.Context) {
c.JSON(http.StatusOK, newZone.ZoneMeta)
}
// viewZone creates a flatten export of the zone.
// @Summary Get flatten zone file.
// @Schemes
// @Description Create a flatten export of the zone that can be read as a BIND-like file.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Success 200 {object} string "The exported zone file (with initial and leading JSON quote)"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId}/view [post]
func viewZone(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
zone := c.MustGet("zone").(*happydns.Zone)
@ -435,6 +550,21 @@ func viewZone(c *gin.Context) {
c.JSON(http.StatusOK, ret)
}
// UpdateZoneService adds or updates a service inside the given Zone.
// @Summary Add or update a Service.
// @Schemes
// @Description Add or update a Service inside the given Zone.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param body body happydns.ServiceCombined true "Service to update"
// @Success 200 {object} happydns.Zone
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId} [patch]
func UpdateZoneService(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
zone := c.MustGet("zone").(*happydns.Zone)
@ -465,6 +595,23 @@ func UpdateZoneService(c *gin.Context) {
c.JSON(http.StatusOK, zone)
}
// deleteZoneService drops the given Service.
// @Summary Drop the given Service.
// @Schemes
// @Description Drop the given Service.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param subdomain path string true "Part of the subdomain considered for the service (@ for the root of the zone ; subdomain is relative to the root, do not include it)"
// @Param serviceId path string true "Service identifier"
// @Success 200 {object} happydns.Zone
// @Failure 400 {object} happydns.Error "Invalid input"
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId}/{subdomain}/services/{serviceId} [delete]
func deleteZoneService(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
zone := c.MustGet("zone").(*happydns.Zone)
@ -494,6 +641,22 @@ type serviceRecord struct {
Fields *dns.RR `json:"fields,omitempty"`
}
// getServiceRecords retrieves the records that will be generated by a Service.
// @Summary Get the records for a Service.
// @Schemes
// @Description Retrieve the records that will be generated by a Service.
// @Tags zones
// @Accept json
// @Produce json
// @Security securitydefinitions.basic
// @Param domainId path string true "Domain identifier"
// @Param zoneId path string true "Zone identifier"
// @Param subdomain path string true "Part of the subdomain considered for the service (@ for the root of the zone ; subdomain is relative to the root, do not include it)"
// @Param serviceId path string true "Service identifier"
// @Success 200 {object} happydns.Zone
// @Failure 401 {object} happydns.Error "Authentication failure"
// @Failure 404 {object} happydns.Error "Domain or Zone not found"
// @Router /domains/{domainId}/zone/{zoneId}/{subdomain}/services/{serviceId}/records [get]
func getServiceRecords(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
zone := c.MustGet("zone").(*happydns.Zone)

View File

@ -33,3 +33,4 @@ package main
//go:generate go run generators/gen_icon.go providers providers
//go:generate go run generators/gen_icon.go services svcs
//go:generate swag init --generalInfo api/routes.go

13
go.mod
View File

@ -27,7 +27,10 @@ require (
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
github.com/G-Core/gcore-dns-sdk-go v0.2.6 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/goquery v1.8.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.18.1 // indirect
@ -57,6 +60,10 @@ require (
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-gandi/go-gandi v0.6.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
@ -76,11 +83,13 @@ require (
github.com/hexonet/go-sdk/v3 v3.5.4 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
@ -103,6 +112,9 @@ require (
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/softlayer/softlayer-go v1.1.2 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/swaggo/files v1.0.1 // indirect
github.com/swaggo/gin-swagger v1.6.0 // indirect
github.com/swaggo/swag v1.16.1 // indirect
github.com/transip/gotransip/v6 v6.20.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
@ -128,6 +140,7 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/ns1/ns1-go.v2 v2.7.4 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
moul.io/http2curl v1.0.0 // indirect
)

34
go.sum
View File

@ -27,8 +27,14 @@ github.com/G-Core/gcore-dns-sdk-go v0.2.3 h1:WODi+qWlZyF7E7SH8rq/DCACa/Zhsuhu1h0
github.com/G-Core/gcore-dns-sdk-go v0.2.3/go.mod h1:TM+VaDvBPObF+x085lS3i0kc2OPAkuW2c4Leg7Pe6jI=
github.com/G-Core/gcore-dns-sdk-go v0.2.6 h1:R82ANd7BnhIe2mV/12Ebdx9QYVl2++E4kfDIu97JEOk=
github.com/G-Core/gcore-dns-sdk-go v0.2.6/go.mod h1:KliUjfPonDvXyAGNiuO+MYVG/7lmWHZ+4Hi0sPxgOjg=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 h1:F1j7z+/DKEsYqZNoxC6wvfmaiDneLsQOFQmuq9NADSY=
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2/go.mod h1:QlXr/TrICfQ/ANa76sLeQyhAJyNR9sEcfNuZBkY9jgY=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
@ -152,6 +158,16 @@ github.com/go-gandi/go-gandi v0.6.0 h1:RgFoevggRRp7hF9XsOmWmtwbUg2axhe2ygEdd6Mts
github.com/go-gandi/go-gandi v0.6.0/go.mod h1:9NoYyfWCjFosClPiWjkbbRK5UViaZ4ctpT8/pKSSFlw=
github.com/go-mail/mail v2.3.1+incompatible h1:UzNOn0k5lpfVtO31cK3hn6I4VEVGhe3lX8AJBAxXExM=
github.com/go-mail/mail v2.3.1+incompatible/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIINUkSmuKOiLIDkWbL6M=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@ -253,6 +269,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@ -264,6 +282,7 @@ github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@ -275,6 +294,10 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -371,6 +394,12 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/transip/gotransip/v6 v6.20.0 h1:AuvwyOZ51f2brzMbTqlRy/wmaM3kF7Vx5Wds8xcDflY=
@ -437,6 +466,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@ -473,6 +503,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -569,6 +600,7 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@ -591,7 +623,9 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=

View File

@ -42,6 +42,7 @@ import (
"github.com/fatih/color"
"git.happydns.org/happydomain/api"
"git.happydns.org/happydomain/config"
"git.happydns.org/happydomain/internal/app"
"git.happydns.org/happydomain/storage"
@ -58,6 +59,10 @@ var (
func main() {
var err error
api.HDVersion = api.Version{
Version: Version,
}
log.Println("This is happyDomain", Version)
rand.Seed(time.Now().UTC().UnixNano())

View File

@ -35,17 +35,27 @@ import (
"github.com/miekg/dns"
)
// DomainMinimal is used for swagger documentation as Domain add.
type DomainMinimal struct {
// IsProvider is the identifier of the Provider used to access and edit the
// Domain.
IdProvider Identifier `json:"id_provider" swaggertype:"string"`
// DomainName is the FQDN of the managed Domain.
DomainName string `json:"domain"`
}
// Domain holds information about a domain name own by a User.
type Domain struct {
// Id is the Domain's identifier in the database.
Id Identifier `json:"id"`
Id Identifier `json:"id" swaggertype:"string"`
// IdUser is the identifier of the Domain's Owner.
IdUser Identifier `json:"id_owner"`
IdUser Identifier `json:"id_owner" swaggertype:"string"`
// IsProvider is the identifier of the Provider used to access and edit the
// Domain.
IdProvider Identifier `json:"id_provider"`
IdProvider Identifier `json:"id_provider" swaggertype:"string"`
// DomainName is the FQDN of the managed Domain.
DomainName string `json:"domain"`
@ -55,7 +65,7 @@ type Domain struct {
// ZoneHistory are the identifiers to the Zone attached to the current
// Domain.
ZoneHistory []Identifier `json:"zone_history"`
ZoneHistory []Identifier `json:"zone_history" swaggertype:"array,string"`
}
// Domains is an array of Domain.

6
model/error.go Normal file
View File

@ -0,0 +1,6 @@
package happydns
type Error struct {
// Err describe the error to display to the user.
Err string `json:"errmsg"`
}

View File

@ -46,16 +46,27 @@ type Provider interface {
DNSControlName() string
}
// ProviderMinimal is used for swagger documentation as Provider add.
type ProviderMinimal struct {
// Type is the string representation of the Provider's type.
Type string `json:"_srctype"`
Provider
// Comment is a string that helps user to distinguish the Provider.
Comment string `json:"_comment,omitempty"`
}
// ProviderMeta holds the metadata associated to a Provider.
type ProviderMeta struct {
// Type is the string representation of the Provider's type.
Type string `json:"_srctype"`
// Id is the Provider's identifier.
Id Identifier `json:"_id"`
Id Identifier `json:"_id" swaggertype:"string"`
// OwnerId is the User's identifier for the current Provider.
OwnerId Identifier `json:"_ownerid"`
OwnerId Identifier `json:"_ownerid" swaggertype:"string"`
// Comment is a string that helps user to distinguish the Provider.
Comment string `json:"_comment,omitempty"`

View File

@ -57,10 +57,10 @@ type ServiceMeta struct {
Type string `json:"_svctype"`
// Id is the Service's identifier.
Id Identifier `json:"_id,omitempty"`
Id Identifier `json:"_id,omitempty" swaggertype:"string"`
// OwnerId is the User's identifier for the current Service.
OwnerId Identifier `json:"_ownerid,omitempty"`
OwnerId Identifier `json:"_ownerid,omitempty" swaggertype:"string"`
// Domain contains the abstract domain where this Service relates.
Domain string `json:"_domain"`

View File

@ -42,10 +42,10 @@ import (
// Session holds informatin about a User's currently connected.
type Session struct {
// Id is the Session's identifier.
Id Identifier `json:"id"`
Id Identifier `json:"id" swaggertype:"string"`
// IdUser is the User's identifier of the Session.
IdUser Identifier `json:"login"`
IdUser Identifier `json:"login" swaggertype:"string"`
// IssuedAt holds the creation date of the Session.
IssuedAt time.Time `json:"time"`

View File

@ -1,79 +0,0 @@
// Copyright or © or Copr. happyDNS (2020)
//
// contact@happydomain.org
//
// This software is a computer program whose purpose is to provide a modern
// interface to interact with DNS systems.
//
// This software is governed by the CeCILL license under French law and abiding
// by the rules of distribution of free software. You can use, modify and/or
// redistribute the software under the terms of the CeCILL license as
// circulated by CEA, CNRS and INRIA at the following URL
// "http://www.cecill.info".
//
// As a counterpart to the access to the source code and rights to copy, modify
// and redistribute granted by the license, users are provided only with a
// limited warranty and the software's author, the holder of the economic
// rights, and the successive licensors have only limited liability.
//
// In this respect, the user's attention is drawn to the risks associated with
// loading, using, modifying and/or developing or reproducing the software by
// the user in light of its specific status of free software, that may mean
// that it is complicated to manipulate, and that also therefore means that it
// is reserved for developers and experienced professionals having in-depth
// computer knowledge. Users are therefore encouraged to load and test the
// software's suitability as regards their requirements in conditions enabling
// the security of their systems and/or data to be ensured and, more generally,
// to use and operate it in the same conditions as regards security.
//
// The fact that you are presently reading this means that you have had
// knowledge of the CeCILL license and that you accept its terms.
package happydns
import (
"github.com/miekg/dns"
)
// Source is where Domains and Zones can be managed.
type Source interface {
// Validate tells if the Source's settings are good.
Validate() error
// DomainExists tells if the given domain exists for the Source.
DomainExists(string) error
// ImportZone retrieves all RRs for the given Domain.
ImportZone(*Domain) ([]dns.RR, error)
// AddRR adds an RR in the zone of the given Domain.
AddRR(*Domain, dns.RR) error
// DeleteRR removes the given RR in the zone of the given Domain.
DeleteRR(*Domain, dns.RR) error
// UpdateSOA tries to update the Zone's SOA record, according to the
// given parameters.
UpdateSOA(*Domain, *dns.SOA, bool) error
}
// SourceMeta holds the metadata associated to a Source.
type SourceMeta struct {
// Type is the string representation of the Source's type.
Type string `json:"_srctype"`
// Id is the Source's identifier.
Id Identifier `json:"_id"`
// OwnerId is the User's identifier for the current Source.
OwnerId Identifier `json:"_ownerid"`
// Comment is a string that helps user to distinguish the Source.
Comment string `json:"_comment,omitempty"`
}
// SourceCombined combined SourceMeta + Source
type SourceCombined struct {
Source
SourceMeta
}

View File

@ -42,10 +42,10 @@ import (
// ZoneMeta holds the metadata associated to a Zone.
type ZoneMeta struct {
// Id is the Zone's identifier.
Id Identifier `json:"id"`
Id Identifier `json:"id" swaggertype:"string"`
// IdAuthor is the User's identifier for the current Zone.
IdAuthor Identifier `json:"id_author"`
IdAuthor Identifier `json:"id_author" swaggertype:"string"`
// DefaultTTL is the TTL to use when no TTL has been defined for a record in this Zone.
DefaultTTL uint32 `json:"default_ttl"`