158 lines
3.5 KiB
Go
158 lines
3.5 KiB
Go
|
package shortener
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"net/http"
|
||
|
|
||
|
"git.xdrm.io/example/aicra/service/auth"
|
||
|
"git.xdrm.io/example/aicra/storage"
|
||
|
"git.xdrm.io/go/aicra"
|
||
|
"git.xdrm.io/go/aicra/api"
|
||
|
)
|
||
|
|
||
|
// Service manages the url shortener
|
||
|
type Service struct {
|
||
|
storage *storage.Client
|
||
|
authService *auth.Service
|
||
|
}
|
||
|
|
||
|
// New returns a bare service
|
||
|
func New(storage *storage.Client, auth *auth.Service) *Service {
|
||
|
log.Printf("[service.shortener] created")
|
||
|
return &Service{
|
||
|
storage: storage,
|
||
|
authService: auth,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wire to the aicra server
|
||
|
func (svc *Service) Wire(server *aicra.Server) {
|
||
|
log.Printf("[service.shortener] wired")
|
||
|
server.HandleFunc("GET", "/", svc.redirect)
|
||
|
server.HandleFunc("POST", "/", svc.authService.CheckToken(svc.register))
|
||
|
server.HandleFunc("PUT", "/", svc.authService.CheckToken(svc.update))
|
||
|
server.HandleFunc("DELETE", "/", svc.authService.CheckToken(svc.delete))
|
||
|
}
|
||
|
|
||
|
// redirect from a tiny url to the long url
|
||
|
func (svc *Service) redirect(req api.Request, res *api.Response) {
|
||
|
|
||
|
// 1. extract input
|
||
|
tinyURL, err := req.Param.GetString("url")
|
||
|
if err != nil {
|
||
|
res.Err = api.ErrorInvalidParam()
|
||
|
res.Err.Put("url")
|
||
|
res.Err.Put(err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 2. check in db if exists
|
||
|
longURL := svc.storage.Get(storage.DATA, tinyURL)
|
||
|
if longURL == nil {
|
||
|
res.Err = api.ErrorNoMatchFound()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 3. redirect
|
||
|
res.Status = http.StatusPermanentRedirect
|
||
|
res.Headers.Set("Location", string(longURL))
|
||
|
res.Err = api.ErrorSuccess()
|
||
|
|
||
|
}
|
||
|
|
||
|
// register registers a new tiny url to a long one
|
||
|
func (svc *Service) register(req api.Request, res *api.Response) {
|
||
|
|
||
|
// 1. extract arguments
|
||
|
longURL, err := req.Param.GetString("target")
|
||
|
if err != nil {
|
||
|
res.Err = api.ErrorInvalidParam()
|
||
|
res.Err.Put("target")
|
||
|
res.Err.Put(err.Error())
|
||
|
return
|
||
|
}
|
||
|
tinyURL, err := req.Param.GetString("url")
|
||
|
if err != nil {
|
||
|
res.Err = api.ErrorInvalidParam()
|
||
|
res.Err.Put("url")
|
||
|
res.Err.Put(err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 2. fail if already used
|
||
|
if svc.storage.Get(storage.DATA, tinyURL) != nil {
|
||
|
res.Err = api.ErrorAlreadyExists()
|
||
|
res.Err.Put("url")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 3. store association
|
||
|
if !svc.storage.Set(storage.DATA, tinyURL, longURL) {
|
||
|
res.Err = api.ErrorFailure()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
res.Err = api.ErrorSuccess()
|
||
|
}
|
||
|
|
||
|
// update updates an existing tiny url to a new long one
|
||
|
func (svc *Service) update(req api.Request, res *api.Response) {
|
||
|
|
||
|
// 1. extract arguments
|
||
|
longURL, err := req.Param.GetString("target")
|
||
|
if err != nil {
|
||
|
res.Err = api.ErrorInvalidParam()
|
||
|
res.Err.Put("target")
|
||
|
res.Err.Put(err.Error())
|
||
|
return
|
||
|
}
|
||
|
tinyURL, err := req.Param.GetString("url")
|
||
|
if err != nil {
|
||
|
res.Err = api.ErrorInvalidParam()
|
||
|
res.Err.Put("url")
|
||
|
res.Err.Put(err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 2. fail if not already existing
|
||
|
if svc.storage.Get(storage.DATA, tinyURL) == nil {
|
||
|
res.Err = api.ErrorNoMatchFound()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 3. update association
|
||
|
if !svc.storage.Set(storage.DATA, tinyURL, longURL) {
|
||
|
res.Err = api.ErrorFailure()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
res.Err = api.ErrorSuccess()
|
||
|
}
|
||
|
|
||
|
// delete removes a new tiny url
|
||
|
func (svc *Service) delete(req api.Request, res *api.Response) {
|
||
|
|
||
|
// 1. extract arguments
|
||
|
tinyURL, err := req.Param.GetString("url")
|
||
|
if err != nil {
|
||
|
res.Err = api.ErrorInvalidParam()
|
||
|
res.Err.Put("url")
|
||
|
res.Err.Put(err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 2. fail if not already existing
|
||
|
if svc.storage.Get(storage.DATA, tinyURL) == nil {
|
||
|
res.Err = api.ErrorNoMatchFound()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// 3. update association
|
||
|
if !svc.storage.Del(storage.DATA, tinyURL) {
|
||
|
res.Err = api.ErrorFailure()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
res.Err = api.ErrorSuccess()
|
||
|
}
|