forked from phc/website
working the dispense table and relative api route
This commit is contained in:
+11
-8
@@ -9,8 +9,6 @@ import (
|
||||
type Service interface {
|
||||
GetDispensa(id string) (*model.Dispensa, error)
|
||||
CreateDispensa(template model.Dispensa) (string, error)
|
||||
SetDispensaTags(dispensaId string, tags []string) error
|
||||
// GetDispensaTags(dispensaId string) ([]string, error)
|
||||
}
|
||||
|
||||
type DefaultService struct {
|
||||
@@ -20,12 +18,12 @@ type DefaultService struct {
|
||||
var _ Service = &DefaultService{}
|
||||
|
||||
func (s *DefaultService) GetDispensa(id string) (*model.Dispensa, error) {
|
||||
dispensa, err := s.DB.GetDispensa(id)
|
||||
dispensa, err := s.DB.Dispense.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tags, err := s.DB.GetTags(id)
|
||||
tags, err := s.DB.DispensaTags.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -40,13 +38,18 @@ func (s *DefaultService) GetDispensa(id string) (*model.Dispensa, error) {
|
||||
}
|
||||
|
||||
func (s *DefaultService) CreateDispensa(template model.Dispensa) (string, error) {
|
||||
return s.DB.CreateDispensa(database.Dispensa{
|
||||
dispensaId, err := s.DB.Dispense.Create(database.Dispensa{
|
||||
OwnerId: template.OwnerId,
|
||||
Title: template.Title,
|
||||
Description: template.Description,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (s *DefaultService) SetDispensaTags(dispensaId string, tags []string) error {
|
||||
return s.DB.SetTags(dispensaId, tags)
|
||||
if err := s.DB.DispensaTags.Set(dispensaId, template.Tags); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return dispensaId, nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"git.phc.dm.unipi.it/phc/website/articles"
|
||||
"git.phc.dm.unipi.it/phc/website/auth"
|
||||
"git.phc.dm.unipi.it/phc/website/config"
|
||||
"git.phc.dm.unipi.it/phc/website/database"
|
||||
"git.phc.dm.unipi.it/phc/website/database/sqlite"
|
||||
"git.phc.dm.unipi.it/phc/website/handler"
|
||||
"git.phc.dm.unipi.it/phc/website/lista_utenti"
|
||||
"git.phc.dm.unipi.it/phc/website/server"
|
||||
@@ -22,7 +22,7 @@ func main() {
|
||||
auth := auth.NewDefaultService(config.AuthServiceHost)
|
||||
|
||||
// Create database connection and apply pending migrations
|
||||
db := util.Must(database.NewSqlite3Database("phc-server.local.db"))
|
||||
db := util.Must(sqlite.New("phc-server.local.db"))
|
||||
if err := db.Migrate("./database/migrations"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -40,7 +40,7 @@ func main() {
|
||||
Path: "./_content/storia.yaml",
|
||||
},
|
||||
ListaUtenti: util.Must(lista_utenti.New(auth, config.ListaUtenti)),
|
||||
AppuntiService: &appunti.DefaultService{
|
||||
Appunti: &appunti.DefaultService{
|
||||
DB: db,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ type DBMigrate interface {
|
||||
}
|
||||
|
||||
type DBQueryAppunti interface {
|
||||
AllDispenseFile() ([]DispensaFile, error)
|
||||
AllDispensaFile() ([]DispensaFile, error)
|
||||
}
|
||||
|
||||
type DBDispense interface {
|
||||
@@ -38,12 +38,13 @@ type DBDownloads interface {
|
||||
Create(template Download) error
|
||||
}
|
||||
|
||||
// DB main "interface group" for interacting with the database, with this technique we can test each "table" api of the DB in isolation.
|
||||
type DB struct {
|
||||
DBMigrate
|
||||
DBDispense
|
||||
DBUploads
|
||||
DBFileApprovals
|
||||
DBDispensaTags
|
||||
DBDownloads
|
||||
DBQueryAppunti
|
||||
|
||||
Dispense DBDispense
|
||||
Uploads DBUploads
|
||||
FileApprovals DBFileApprovals
|
||||
DispensaTags DBDispensaTags
|
||||
Downloads DBDownloads
|
||||
}
|
||||
|
||||
+18
-9
@@ -1,5 +1,9 @@
|
||||
package database
|
||||
|
||||
//
|
||||
// Tables
|
||||
//
|
||||
|
||||
type Dispensa struct {
|
||||
Id string `db:"id"`
|
||||
CreatedAt string `db:"created_at"`
|
||||
@@ -8,15 +12,6 @@ type Dispensa struct {
|
||||
Description string `db:"description"`
|
||||
}
|
||||
|
||||
type DispensaFile struct {
|
||||
DispensaId string `db:"dispensa_id"`
|
||||
UploadId string `db:"upload_id"`
|
||||
OwnerId string `db:"owner_id"`
|
||||
Title string `db:"title"`
|
||||
Description string `db:"description"`
|
||||
File string `db:"file"`
|
||||
}
|
||||
|
||||
type Upload struct {
|
||||
Id string `db:"id"`
|
||||
CreatedAt string `db:"created_at"`
|
||||
@@ -42,3 +37,17 @@ type Tag struct {
|
||||
DispensaId string `db:"dispensa_id"`
|
||||
Tag string `db:"tag"`
|
||||
}
|
||||
|
||||
//
|
||||
// Common Joins
|
||||
//
|
||||
|
||||
// DispensaFile is a join of dispensa with the most recent upload for that "dispensa_id"
|
||||
type DispensaFile struct {
|
||||
DispensaId string `db:"dispensa_id"`
|
||||
UploadId string `db:"upload_id"`
|
||||
OwnerId string `db:"owner_id"`
|
||||
Title string `db:"title"`
|
||||
Description string `db:"description"`
|
||||
File string `db:"file"`
|
||||
}
|
||||
|
||||
@@ -22,10 +22,13 @@ func New(filename string) (*database.DB, error) {
|
||||
}
|
||||
|
||||
return &database.DB{
|
||||
DBMigrate: &sqliteDBMigrate{db},
|
||||
DBDispense: &sqliteDBDispense{db},
|
||||
DBUploads: &sqliteDBUploads{db},
|
||||
DBFileApprovals: &sqliteDBFileApprovals{db},
|
||||
DBDownloads: &sqliteDBDownloads{db},
|
||||
DBMigrate: &sqliteDBMigrate{db},
|
||||
// DBQueryAppunti: ...,
|
||||
|
||||
Dispense: &sqliteDBDispense{db},
|
||||
Uploads: &sqliteDBUploads{db},
|
||||
FileApprovals: &sqliteDBFileApprovals{db},
|
||||
Downloads: &sqliteDBDownloads{db},
|
||||
DispensaTags: &sqliteDBTags{db},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ type sqliteDBDispense struct{ *sqlx.DB }
|
||||
var _ database.DBDispense = sqliteDBDispense{}
|
||||
|
||||
func (d sqliteDBDispense) Create(template database.Dispensa) (string, error) {
|
||||
template.Id = "dispensa/" + util.GenerateRandomString(8)
|
||||
template.Id = util.GenerateRandomString(8)
|
||||
template.CreatedAt = time.Now().Format(time.RFC3339)
|
||||
|
||||
if _, err := d.DB.NamedExec(`
|
||||
|
||||
@@ -11,7 +11,7 @@ type sqliteDBUploads struct{ *sqlx.DB }
|
||||
var _ database.DBUploads = sqliteDBUploads{}
|
||||
|
||||
func (u sqliteDBUploads) Create(template database.Upload) (string, error) {
|
||||
template.Id = "upload/" + util.GenerateRandomString(8)
|
||||
template.Id = util.GenerateRandomString(8)
|
||||
|
||||
if _, err := u.DB.NamedExec(`
|
||||
INSERT INTO
|
||||
|
||||
@@ -1,26 +1,64 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.phc.dm.unipi.it/phc/website/database"
|
||||
"git.phc.dm.unipi.it/phc/website/util"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type sqliteDBFileApprovals struct{ *sqlx.DB }
|
||||
|
||||
func (f sqliteDBFileApprovals) Create(template database.FileApproval) (string, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
template.Id = util.GenerateRandomString(8)
|
||||
template.CreatedAt = time.Now().Format(time.RFC3339)
|
||||
|
||||
if _, err := f.DB.NamedExec(`
|
||||
INSERT INTO
|
||||
file_approvals(id, created_at, owner_id, upload_id, status)
|
||||
VALUES
|
||||
(:id, :created_at, :owner_id, :upload_id, :status)
|
||||
`, &template); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return template.Id, nil
|
||||
}
|
||||
|
||||
func (f sqliteDBFileApprovals) Get(id string) (database.FileApproval, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
var fileApproval database.FileApproval
|
||||
if err := f.DB.Get(&fileApproval, `SELECT * FROM file_approvals WHERE id = ?`, id); err != nil {
|
||||
return database.FileApproval{}, err
|
||||
}
|
||||
|
||||
return fileApproval, nil
|
||||
}
|
||||
|
||||
func (f sqliteDBFileApprovals) All() ([]database.FileApproval, error) {
|
||||
panic("not implemented") // TODO: Implement
|
||||
var fileApprovals []database.FileApproval
|
||||
if err := f.DB.Select(&fileApprovals, `SELECT * FROM file_approvals`); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fileApprovals, nil
|
||||
}
|
||||
|
||||
func (f sqliteDBFileApprovals) Update(d database.FileApproval) error {
|
||||
panic("not implemented") // TODO: Implement
|
||||
func (f sqliteDBFileApprovals) Update(fileApproval database.FileApproval) error {
|
||||
if _, err := f.DB.NamedExec(`
|
||||
UPDATE
|
||||
file_approvals
|
||||
SET
|
||||
owner_id = :owner_id,
|
||||
upload_id = :upload_id,
|
||||
status = :status
|
||||
WHERE
|
||||
id = :id
|
||||
`, &fileApproval); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f sqliteDBFileApprovals) Delete(id string) error {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"git.phc.dm.unipi.it/phc/website/database"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type sqliteDBTags struct{ *sqlx.DB }
|
||||
|
||||
var _ database.DBDispensaTags = sqliteDBTags{}
|
||||
|
||||
func (t sqliteDBTags) Set(dispensaId string, tags []string) error {
|
||||
tagsRows := []map[string]any{}
|
||||
for _, t := range tags {
|
||||
tagsRows = append(tagsRows, map[string]any{
|
||||
"dispensa_id": dispensaId,
|
||||
"name": t,
|
||||
})
|
||||
}
|
||||
|
||||
tx, err := t.DB.Beginx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`
|
||||
DELETE FROM tags WHERE dispensa_id = ?
|
||||
`, dispensaId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.NamedExec(`
|
||||
INSERT INTO tags(dispensa_id, name) VALUES (:dispensa_id, :name)
|
||||
`, tagsRows); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t sqliteDBTags) Get(dispensaId string) ([]string, error) {
|
||||
var tags []string
|
||||
if err := t.DB.Select(&tags, `SELECT name FROM tags WHERE dispensa_id = ?`, dispensaId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
+14
-14
@@ -61,7 +61,8 @@ type Service interface {
|
||||
HandleListaUtenti() ([]*model.ListUser, error)
|
||||
|
||||
// Appunti
|
||||
HandleCreateDispensa(template model.Dispensa, ctx Context) (*model.Dispensa, error)
|
||||
HandleCreateDispensa(template model.Dispensa, ctx Context) (string, error)
|
||||
HandleGetDispensa(dispensaId string) (*model.Dispensa, error)
|
||||
}
|
||||
|
||||
//
|
||||
@@ -78,7 +79,7 @@ func (ctx Context) getUser() *model.User {
|
||||
// Handler holds references to abstract services for easy testing provided by every module (TODO: Make every field an interface of -Service)
|
||||
type DefaultHandler struct {
|
||||
AuthService auth.Service
|
||||
AppuntiService appunti.Service
|
||||
Appunti appunti.Service
|
||||
Renderer *templates.TemplateRenderer
|
||||
NewsArticlesRegistry *articles.Registry
|
||||
GuideArticlesRegistry *articles.Registry
|
||||
@@ -138,7 +139,7 @@ func (h *DefaultHandler) HandleAppuntiCondivisiPage(w io.Writer, ctx Context) er
|
||||
}
|
||||
|
||||
func (h *DefaultHandler) HandleDispensaPage(w io.Writer, id string, ctx Context) error {
|
||||
dispensa, err := h.AppuntiService.GetDispensa(id)
|
||||
dispensa, err := h.Appunti.GetDispensa(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -271,23 +272,22 @@ func (h *DefaultHandler) HandleGuideFeedPage(w io.Writer) error {
|
||||
// API
|
||||
//
|
||||
|
||||
func (h *DefaultHandler) HandleCreateDispensa(template model.Dispensa, ctx Context) (*model.Dispensa, error) {
|
||||
func (h *DefaultHandler) HandleCreateDispensa(template model.Dispensa, ctx Context) (string, error) {
|
||||
user := ctx.getUser()
|
||||
if user == nil {
|
||||
return nil, ErrNoUser
|
||||
return "", ErrNoUser
|
||||
}
|
||||
|
||||
template.OwnerId = user.Username
|
||||
id, err := h.AppuntiService.CreateDispensa(template)
|
||||
|
||||
dispensaId, err := h.Appunti.CreateDispensa(template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
template.Id = id
|
||||
|
||||
if len(template.Tags) > 0 {
|
||||
h.AppuntiService.SetDispensaTags(id, template.Tags)
|
||||
}
|
||||
|
||||
return &template, nil
|
||||
return dispensaId, nil
|
||||
}
|
||||
|
||||
func (h *DefaultHandler) HandleGetDispensa(id string) (*model.Dispensa, error) {
|
||||
return h.Appunti.GetDispensa(id)
|
||||
}
|
||||
|
||||
+13
-4
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/etag"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||
"github.com/gofiber/redirect/v2"
|
||||
)
|
||||
|
||||
@@ -46,7 +45,7 @@ func routes(h handler.Service, r fiber.Router) {
|
||||
//
|
||||
|
||||
r.Use(logger.New())
|
||||
r.Use(recover.New())
|
||||
// r.Use(recover.New())
|
||||
|
||||
// Remove trailing slash from URLs
|
||||
r.Use(redirect.New(redirect.Config{
|
||||
@@ -223,13 +222,23 @@ func routesApi(h handler.Service, r fiber.Router) {
|
||||
return c.JSON(user)
|
||||
})
|
||||
|
||||
r.Post("/appunti", func(c *fiber.Ctx) error {
|
||||
r.Post("/appunti/dispense", func(c *fiber.Ctx) error {
|
||||
var dispensaTemplate model.Dispensa
|
||||
if err := c.BodyParser(&dispensaTemplate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dispensa, err := h.HandleCreateDispensa(dispensaTemplate, CreateContext(c))
|
||||
dispensaId, err := h.HandleCreateDispensa(dispensaTemplate, CreateContext(c))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(dispensaId)
|
||||
})
|
||||
r.Get("/appunti/dispense", func(c *fiber.Ctx) error {
|
||||
dispensaId := c.Query("id")
|
||||
|
||||
dispensa, err := h.HandleGetDispensa(dispensaId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user