158 lines
3.6 KiB
Go
158 lines
3.6 KiB
Go
package shortener
|
|
|
|
import (
|
|
"database/sql"
|
|
"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 *sql.DB
|
|
authService *auth.Service
|
|
repo *repository
|
|
}
|
|
|
|
// New returns a bare service
|
|
func New(storage *sql.DB, auth *auth.Service) *Service {
|
|
log.Printf("[service.shortener] creating")
|
|
|
|
service := &Service{
|
|
storage: storage,
|
|
authService: auth,
|
|
}
|
|
|
|
// init repo
|
|
repo, err := newRepo(db)
|
|
if err != nil {
|
|
log.Printf("[service.shortener] cannot create repo")
|
|
return service
|
|
}
|
|
|
|
log.Printf("[service.shortener] creating")
|
|
return service
|
|
}
|
|
|
|
// 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.SetError(api.ErrorInvalidParam(), "url", err.Error())
|
|
return
|
|
}
|
|
|
|
// 2. check in db if exists
|
|
longURL := svc.storage.Get(storage.DATA, tinyURL)
|
|
if longURL == nil {
|
|
res.SetError(api.ErrorNoMatchFound())
|
|
return
|
|
}
|
|
|
|
// 3. redirect
|
|
res.Status = http.StatusPermanentRedirect
|
|
res.Headers.Set("Location", string(longURL))
|
|
res.SetError(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.SetError(api.ErrorInvalidParam(), "target", err.Error())
|
|
return
|
|
}
|
|
tinyURL, err := req.Param.GetString("url")
|
|
if err != nil {
|
|
res.SetError(api.ErrorInvalidParam(), "url", err.Error())
|
|
return
|
|
}
|
|
|
|
// 2. fail if already used
|
|
if svc.storage.Get(storage.DATA, tinyURL) != nil {
|
|
res.SetError(api.ErrorAlreadyExists(), "url")
|
|
return
|
|
}
|
|
|
|
// 3. store association
|
|
if !svc.storage.Set(storage.DATA, tinyURL, longURL) {
|
|
res.SetError(api.ErrorFailure())
|
|
return
|
|
}
|
|
|
|
res.SetError(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.SetError(api.ErrorInvalidParam(), "target", err.Error())
|
|
return
|
|
}
|
|
tinyURL, err := req.Param.GetString("url")
|
|
if err != nil {
|
|
res.SetError(api.ErrorInvalidParam(), "url", err.Error())
|
|
return
|
|
}
|
|
|
|
// 2. fail if not already existing
|
|
if svc.storage.Get(storage.DATA, tinyURL) == nil {
|
|
res.SetError(api.ErrorNoMatchFound())
|
|
return
|
|
}
|
|
|
|
// 3. update association
|
|
if !svc.storage.Set(storage.DATA, tinyURL, longURL) {
|
|
res.SetError(api.ErrorFailure())
|
|
return
|
|
}
|
|
|
|
res.SetError(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.SetError(api.ErrorInvalidParam(), "url", err.Error())
|
|
return
|
|
}
|
|
|
|
// 2. fail if not already existing
|
|
if svc.storage.Get(storage.DATA, tinyURL) == nil {
|
|
res.SetError(api.ErrorNoMatchFound())
|
|
return
|
|
}
|
|
|
|
// 3. update association
|
|
if !svc.storage.Del(storage.DATA, tinyURL) {
|
|
res.SetError(api.ErrorFailure())
|
|
return
|
|
}
|
|
|
|
res.SetError(api.ErrorSuccess())
|
|
}
|