335 lines
6.2 KiB
Go
335 lines
6.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"github.com/labstack/echo/v5"
|
|
"github.com/pocketbase/dbx"
|
|
"github.com/pocketbase/pocketbase"
|
|
"github.com/pocketbase/pocketbase/apis"
|
|
"github.com/pocketbase/pocketbase/core"
|
|
"github.com/pocketbase/pocketbase/models"
|
|
"log"
|
|
"net/http"
|
|
"nurl/base58"
|
|
_import "nurl/import"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
Version string
|
|
Build string
|
|
Webhost = "https://nurl.co/"
|
|
)
|
|
|
|
type Count struct {
|
|
Count int `json:"count" db:"count"`
|
|
}
|
|
|
|
type UrlRequest struct {
|
|
Url string `json:"url"`
|
|
}
|
|
|
|
type Data struct {
|
|
Visits int64 `json:"visits" db:"visits"`
|
|
LongUrl string `json:"long_url" db:"long_url"`
|
|
CreatedAt time.Time `json:"created_at,omitempty" db:"created_at"`
|
|
Id int64 `json:"_id" db:"_id"`
|
|
}
|
|
|
|
type ShortUrl struct {
|
|
ShortUrl string `json:"shortUrl"`
|
|
}
|
|
|
|
func main() {
|
|
log.Printf("GO-PB-NURL v%+v build %+v\n\n", Version, Build)
|
|
|
|
app := pocketbase.New()
|
|
|
|
app.OnRecordBeforeCreateRequest("urls").Add(func(e *core.RecordCreateEvent) error {
|
|
log.Println("OnRecordBeforeCreate")
|
|
|
|
count := Count{}
|
|
err := app.Dao().DB().NewQuery("select count(*) as count from urls").One(&count)
|
|
if err != nil {
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
log.Println("count:", count.Count)
|
|
count.Count++
|
|
|
|
e.Record.Set("_id", count.Count)
|
|
|
|
log.Println("Record", e.Record)
|
|
|
|
return nil
|
|
})
|
|
|
|
app.OnAfterBootstrap().Add(func(e *core.BootstrapEvent) error {
|
|
// log.Println(e.App)
|
|
|
|
return nil
|
|
|
|
collection, err := e.App.Dao().FindCollectionByNameOrId("urls")
|
|
if err != nil {
|
|
log.Println(err)
|
|
return err
|
|
}
|
|
|
|
data := _import.DoImport()
|
|
|
|
// log.Println("Import", data)
|
|
|
|
for _, v := range data {
|
|
|
|
log.Println("v", v)
|
|
record := models.NewRecord(collection)
|
|
|
|
record.Set("long_url", v.LongUrl)
|
|
record.Set("visits", v.Visits)
|
|
record.Set("_id", v.Id)
|
|
record.Set("created_at", v.CreatedAt)
|
|
|
|
log.Println(record)
|
|
|
|
if err := app.Dao().SaveRecord(record); err != nil {
|
|
log.Println("ERROR!! postshort save NewRecord")
|
|
log.Println(err)
|
|
|
|
return err
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
// serves static files from the provided public dir (if exists)
|
|
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
|
e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
|
|
e.Router.GET("/build/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public/build"), false))
|
|
|
|
e.Router.GET("/api/v1/list", func(c echo.Context) error {
|
|
|
|
apis.ActivityLogger(app)
|
|
|
|
getList()
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
e.Router.POST("/api/v1/shorten", func(c echo.Context) error {
|
|
|
|
apis.ActivityLogger(app)
|
|
|
|
postShort(c, app)
|
|
|
|
return nil
|
|
})
|
|
|
|
e.Router.GET("/:encoded", func(c echo.Context) error {
|
|
|
|
apis.ActivityLogger(app)
|
|
|
|
getEncoded(c, app)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
e.Router.GET("/!/hb", func(c echo.Context) error {
|
|
|
|
apis.ActivityLogger(app)
|
|
|
|
return c.NoContent(200)
|
|
|
|
})
|
|
|
|
return nil
|
|
})
|
|
|
|
if err := app.Start(); err != nil {
|
|
log.Fatal(err)
|
|
} else {
|
|
log.Println("Nurl is running...")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func getList() {
|
|
log.Println("Getting list")
|
|
}
|
|
|
|
func getIdByUrl(url string, app *pocketbase.PocketBase) (int64, error) {
|
|
|
|
recordData := &Data{}
|
|
|
|
log.Println("look for:", url)
|
|
|
|
dberr := app.Dao().DB().Select("_id").From("urls").Where(dbx.NewExp("long_url is {:url}", dbx.Params{"url": url})).One(&recordData)
|
|
|
|
log.Println(recordData)
|
|
|
|
if dberr == nil {
|
|
log.Println("Url found", recordData.Id)
|
|
|
|
return recordData.Id, nil
|
|
} else {
|
|
return -1, dberr
|
|
}
|
|
}
|
|
|
|
func saveUrl(url string, app *pocketbase.PocketBase) (string, error) {
|
|
count := Count{}
|
|
err := app.Dao().DB().NewQuery("select count(*) as count from urls").One(&count)
|
|
if err != nil {
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
count.Count += 2000 // Base everything from 2000 now
|
|
count.Count++
|
|
|
|
collection, err := app.Dao().FindCollectionByNameOrId("urls")
|
|
if err != nil {
|
|
log.Println(err)
|
|
return "", err
|
|
}
|
|
|
|
record := models.NewRecord(collection)
|
|
|
|
record.Set("long_url", url)
|
|
record.Set("visits", 0)
|
|
record.Set("_id", count.Count)
|
|
record.Set("created_at", time.Now())
|
|
|
|
if err := app.Dao().SaveRecord(record); err != nil {
|
|
log.Println("ERROR!! postshort save NewRecord")
|
|
log.Println(err)
|
|
|
|
return "", err
|
|
}
|
|
|
|
shortCode := base58.Encode(count.Count)
|
|
log.Println("Return", shortCode)
|
|
return shortCode, nil
|
|
}
|
|
|
|
func postShort(c echo.Context, app *pocketbase.PocketBase) error {
|
|
log.Println("Posting short")
|
|
|
|
j := GetJSONRawBody(c)
|
|
|
|
url := j.Url
|
|
|
|
log.Println("url", url)
|
|
|
|
if url == "" {
|
|
return c.JSON(http.StatusBadRequest, "url is null")
|
|
}
|
|
|
|
id, err := getIdByUrl(url, app)
|
|
|
|
if err != nil {
|
|
log.Println("post getIdByUrl error", err)
|
|
} else {
|
|
log.Println("id:", id)
|
|
|
|
if id != -1 {
|
|
|
|
shortUrl := ShortUrl{}
|
|
|
|
shortUrl.ShortUrl = Webhost + base58.Encode(int(id))
|
|
|
|
return c.JSON(http.StatusOK, shortUrl)
|
|
}
|
|
|
|
}
|
|
|
|
// todo: check that the url doesn't already exist in the db and return it if it does
|
|
// todo: breakout working in other functions. ie: getUrl:done, saveUrl:done
|
|
|
|
shortCode, err := saveUrl(url, app)
|
|
|
|
if err != nil {
|
|
log.Println("post saveUrl error", err)
|
|
} else {
|
|
log.Println("shortCode:", shortCode)
|
|
|
|
if shortCode != "" {
|
|
|
|
shortUrl := ShortUrl{}
|
|
|
|
shortUrl.ShortUrl = Webhost + shortCode
|
|
|
|
return c.JSON(http.StatusOK, shortUrl)
|
|
}
|
|
|
|
}
|
|
|
|
return c.NoContent(200)
|
|
|
|
}
|
|
|
|
func getEncoded(c echo.Context, app *pocketbase.PocketBase) error {
|
|
log.Println("Getting encoded")
|
|
|
|
Encoded := c.PathParam("encoded")
|
|
|
|
log.Println("encoded: ", Encoded)
|
|
|
|
if Encoded == "" || len(Encoded) == 0 || len(Encoded) > 3 {
|
|
return c.NoContent(404)
|
|
}
|
|
|
|
Decoded := base58.Decode(Encoded)
|
|
|
|
log.Println("decoded: ", Decoded)
|
|
|
|
url, err := findById(Decoded, app)
|
|
|
|
if err != nil {
|
|
return c.NoContent(404)
|
|
}
|
|
|
|
return c.Redirect(301, url)
|
|
}
|
|
|
|
func findById(id int, app *pocketbase.PocketBase) (string, error) {
|
|
record, recErr := app.Dao().FindRecordsByExpr("urls", dbx.NewExp("_id = {:id}", dbx.Params{"id": id}))
|
|
|
|
if recErr != nil {
|
|
log.Println(recErr)
|
|
return "", recErr
|
|
}
|
|
|
|
if len(record) != 0 {
|
|
log.Println("-- record", record[0])
|
|
rec := record[0]
|
|
|
|
longUrl := rec.GetString("long_url")
|
|
|
|
return longUrl, nil
|
|
}
|
|
|
|
return "", errors.New("record not found")
|
|
}
|
|
|
|
func GetJSONRawBody(c echo.Context) UrlRequest {
|
|
|
|
urlBody := UrlRequest{}
|
|
err := json.NewDecoder(c.Request().Body).Decode(&urlBody)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("empty json body")
|
|
return urlBody
|
|
}
|
|
|
|
return urlBody
|
|
}
|