working the dispense table and relative api route

feat/db
Antonio De Lucreziis 2 years ago
parent c7e33c8e72
commit 807a4c54ac

@ -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
}
if err := s.DB.DispensaTags.Set(dispensaId, template.Tags); err != nil {
return "", err
}
func (s *DefaultService) SetDispensaTags(dispensaId string, tags []string) error {
return s.DB.SetTags(dispensaId, tags)
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
}

@ -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"`
}

@ -23,9 +23,12 @@ 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},
// 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
}

@ -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 dispensaId, nil
}
return &template, nil
func (h *DefaultHandler) HandleGetDispensa(id string) (*model.Dispensa, error) {
return h.Appunti.GetDispensa(id)
}

@ -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
}

Loading…
Cancel
Save