backend api, swagger, tooling, frontend skeleton
This commit is contained in:
193
backend/internal/handlers/categories.go
Normal file
193
backend/internal/handlers/categories.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/categorie"
|
||||
)
|
||||
|
||||
type categorieRequest struct {
|
||||
Nom *string `json:"nom"`
|
||||
ParentID *string `json:"parent_id"`
|
||||
Slug *string `json:"slug"`
|
||||
Icone *string `json:"icone"`
|
||||
}
|
||||
|
||||
// @Summary Lister les categories
|
||||
// @Tags Categories
|
||||
// @Produce json
|
||||
// @Param page query int false "Page"
|
||||
// @Param limit query int false "Limite"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /categories [get]
|
||||
func (h *Handler) ListCategories(c *gin.Context) {
|
||||
limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
|
||||
query := h.client.Categorie.Query()
|
||||
total, err := query.Count(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les categories"})
|
||||
return
|
||||
}
|
||||
|
||||
items, err := query.
|
||||
Order(ent.Desc(categorie.FieldCreatedAt)).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
All(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les categories"})
|
||||
return
|
||||
}
|
||||
respondPaginated(c, items, total, page, limit)
|
||||
}
|
||||
|
||||
// @Summary Creer une categorie
|
||||
// @Tags Categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body categorieRequest true "Categorie a creer"
|
||||
// @Success 201 {object} ent.Categorie
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /categories [post]
|
||||
func (h *Handler) CreateCategorie(c *gin.Context) {
|
||||
var req categorieRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
if req.Nom == nil || *req.Nom == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "le champ nom est obligatoire"})
|
||||
return
|
||||
}
|
||||
|
||||
create := h.client.Categorie.Create().SetNom(*req.Nom)
|
||||
if req.ParentID != nil && *req.ParentID != "" {
|
||||
if parsed, err := uuid.Parse(*req.ParentID); err == nil {
|
||||
create.SetParentID(parsed)
|
||||
}
|
||||
}
|
||||
if req.Slug != nil {
|
||||
create.SetNillableSlug(req.Slug)
|
||||
}
|
||||
if req.Icone != nil {
|
||||
create.SetNillableIcone(req.Icone)
|
||||
}
|
||||
|
||||
created, err := create.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer la categorie"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, created)
|
||||
}
|
||||
|
||||
// @Summary Recuperer une categorie
|
||||
// @Tags Categories
|
||||
// @Produce json
|
||||
// @Param id path string true "ID categorie"
|
||||
// @Success 200 {object} ent.Categorie
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /categories/{id} [get]
|
||||
func (h *Handler) GetCategorie(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.client.Categorie.Get(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "categorie introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger la categorie"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, item)
|
||||
}
|
||||
|
||||
// @Summary Mettre a jour une categorie
|
||||
// @Tags Categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID categorie"
|
||||
// @Param body body categorieRequest true "Categorie a mettre a jour"
|
||||
// @Success 200 {object} ent.Categorie
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /categories/{id} [put]
|
||||
func (h *Handler) UpdateCategorie(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req categorieRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
|
||||
update := h.client.Categorie.UpdateOneID(id)
|
||||
if req.Nom != nil {
|
||||
update.SetNom(*req.Nom)
|
||||
}
|
||||
if req.ParentID != nil {
|
||||
if *req.ParentID == "" {
|
||||
update.ClearParentID()
|
||||
} else if parsed, err := uuid.Parse(*req.ParentID); err == nil {
|
||||
update.SetParentID(parsed)
|
||||
}
|
||||
}
|
||||
if req.Slug != nil {
|
||||
update.SetNillableSlug(req.Slug)
|
||||
}
|
||||
if req.Icone != nil {
|
||||
update.SetNillableIcone(req.Icone)
|
||||
}
|
||||
|
||||
updated, err := update.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "categorie introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de mettre a jour la categorie"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updated)
|
||||
}
|
||||
|
||||
// @Summary Supprimer une categorie
|
||||
// @Tags Categories
|
||||
// @Param id path string true "ID categorie"
|
||||
// @Success 204 {string} string "No Content"
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /categories/{id} [delete]
|
||||
func (h *Handler) DeleteCategorie(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.client.Categorie.DeleteOneID(id).Exec(c.Request.Context()); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer la categorie"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// helper for compile reference
|
||||
var _ = ent.IsNotFound
|
||||
207
backend/internal/handlers/champs_personnalises.go
Normal file
207
backend/internal/handlers/champs_personnalises.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/champpersonnalise"
|
||||
)
|
||||
|
||||
type champPersonnaliseRequest struct {
|
||||
NomChamp *string `json:"nom_champ"`
|
||||
TypeChamp *string `json:"type_champ"`
|
||||
Valeur *string `json:"valeur"`
|
||||
Unite *string `json:"unite"`
|
||||
}
|
||||
|
||||
// @Summary Lister les champs personnalises
|
||||
// @Tags ChampsPersonnalises
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param page query int false "Page"
|
||||
// @Param limit query int false "Limite"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id}/champs_personnalises [get]
|
||||
func (h *Handler) ListChampsPersonnalises(c *gin.Context) {
|
||||
objetID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
|
||||
query := h.client.ChampPersonnalise.Query().
|
||||
Where(champpersonnalise.ObjetID(objetID))
|
||||
total, err := query.Count(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les champs"})
|
||||
return
|
||||
}
|
||||
|
||||
items, err := query.
|
||||
Order(ent.Desc(champpersonnalise.FieldCreatedAt)).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
All(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les champs"})
|
||||
return
|
||||
}
|
||||
respondPaginated(c, items, total, page, limit)
|
||||
}
|
||||
|
||||
// @Summary Creer un champ personnalise
|
||||
// @Tags ChampsPersonnalises
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param body body champPersonnaliseRequest true "Champ personnalise"
|
||||
// @Success 201 {object} ent.ChampPersonnalise
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id}/champs_personnalises [post]
|
||||
func (h *Handler) CreateChampPersonnalise(c *gin.Context) {
|
||||
objetID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req champPersonnaliseRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
if req.NomChamp == nil || *req.NomChamp == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "le champ nom_champ est obligatoire"})
|
||||
return
|
||||
}
|
||||
|
||||
create := h.client.ChampPersonnalise.Create().
|
||||
SetObjetID(objetID).
|
||||
SetNomChamp(*req.NomChamp)
|
||||
|
||||
if req.TypeChamp != nil && *req.TypeChamp != "" {
|
||||
parsed, ok := parseTypeChamp(*req.TypeChamp)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "type_champ invalide"})
|
||||
return
|
||||
}
|
||||
create.SetTypeChamp(parsed)
|
||||
}
|
||||
if req.Valeur != nil {
|
||||
create.SetNillableValeur(req.Valeur)
|
||||
}
|
||||
if req.Unite != nil {
|
||||
create.SetNillableUnite(req.Unite)
|
||||
}
|
||||
|
||||
created, err := create.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer le champ"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, created)
|
||||
}
|
||||
|
||||
// @Summary Mettre a jour un champ personnalise
|
||||
// @Tags ChampsPersonnalises
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID champ"
|
||||
// @Param body body champPersonnaliseRequest true "Champ personnalise"
|
||||
// @Success 200 {object} ent.ChampPersonnalise
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /champs_personnalises/{id} [put]
|
||||
func (h *Handler) UpdateChampPersonnalise(c *gin.Context) {
|
||||
champID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req champPersonnaliseRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
|
||||
update := h.client.ChampPersonnalise.UpdateOneID(champID)
|
||||
if req.NomChamp != nil {
|
||||
update.SetNomChamp(*req.NomChamp)
|
||||
}
|
||||
if req.TypeChamp != nil {
|
||||
if *req.TypeChamp != "" {
|
||||
parsed, ok := parseTypeChamp(*req.TypeChamp)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "type_champ invalide"})
|
||||
return
|
||||
}
|
||||
update.SetTypeChamp(parsed)
|
||||
}
|
||||
}
|
||||
if req.Valeur != nil {
|
||||
update.SetNillableValeur(req.Valeur)
|
||||
}
|
||||
if req.Unite != nil {
|
||||
update.SetNillableUnite(req.Unite)
|
||||
}
|
||||
|
||||
updated, err := update.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "champ introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de mettre a jour le champ"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updated)
|
||||
}
|
||||
|
||||
// @Summary Supprimer un champ personnalise
|
||||
// @Tags ChampsPersonnalises
|
||||
// @Param id path string true "ID champ"
|
||||
// @Success 204 {string} string "No Content"
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /champs_personnalises/{id} [delete]
|
||||
func (h *Handler) DeleteChampPersonnalise(c *gin.Context) {
|
||||
champID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.client.ChampPersonnalise.DeleteOneID(champID).Exec(c.Request.Context()); err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "champ introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer le champ"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func parseTypeChamp(value string) (champpersonnalise.TypeChamp, bool) {
|
||||
switch value {
|
||||
case "string":
|
||||
return champpersonnalise.TypeChampString, true
|
||||
case "int":
|
||||
return champpersonnalise.TypeChampInt, true
|
||||
case "bool":
|
||||
return champpersonnalise.TypeChampBool, true
|
||||
case "date":
|
||||
return champpersonnalise.TypeChampDate, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
214
backend/internal/handlers/emplacements.go
Normal file
214
backend/internal/handlers/emplacements.go
Normal file
@@ -0,0 +1,214 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/emplacement"
|
||||
)
|
||||
|
||||
type emplacementRequest struct {
|
||||
Nom *string `json:"nom"`
|
||||
ParentID *string `json:"parent_id"`
|
||||
Slug *string `json:"slug"`
|
||||
Piece *string `json:"piece"`
|
||||
Meuble *string `json:"meuble"`
|
||||
NumeroBoite *string `json:"numero_boite"`
|
||||
Icone *string `json:"icone"`
|
||||
}
|
||||
|
||||
// @Summary Lister les emplacements
|
||||
// @Tags Emplacements
|
||||
// @Produce json
|
||||
// @Param page query int false "Page"
|
||||
// @Param limit query int false "Limite"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /emplacements [get]
|
||||
func (h *Handler) ListEmplacements(c *gin.Context) {
|
||||
limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
|
||||
query := h.client.Emplacement.Query()
|
||||
total, err := query.Count(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les emplacements"})
|
||||
return
|
||||
}
|
||||
|
||||
items, err := query.
|
||||
Order(ent.Desc(emplacement.FieldCreatedAt)).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
All(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les emplacements"})
|
||||
return
|
||||
}
|
||||
respondPaginated(c, items, total, page, limit)
|
||||
}
|
||||
|
||||
// @Summary Creer un emplacement
|
||||
// @Tags Emplacements
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body emplacementRequest true "Emplacement a creer"
|
||||
// @Success 201 {object} ent.Emplacement
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /emplacements [post]
|
||||
func (h *Handler) CreateEmplacement(c *gin.Context) {
|
||||
var req emplacementRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
if req.Nom == nil || *req.Nom == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "le champ nom est obligatoire"})
|
||||
return
|
||||
}
|
||||
|
||||
create := h.client.Emplacement.Create().SetNom(*req.Nom)
|
||||
if req.ParentID != nil && *req.ParentID != "" {
|
||||
if parsed, err := uuid.Parse(*req.ParentID); err == nil {
|
||||
create.SetParentID(parsed)
|
||||
}
|
||||
}
|
||||
if req.Slug != nil {
|
||||
create.SetNillableSlug(req.Slug)
|
||||
}
|
||||
if req.Piece != nil {
|
||||
create.SetNillablePiece(req.Piece)
|
||||
}
|
||||
if req.Meuble != nil {
|
||||
create.SetNillableMeuble(req.Meuble)
|
||||
}
|
||||
if req.NumeroBoite != nil {
|
||||
create.SetNillableNumeroBoite(req.NumeroBoite)
|
||||
}
|
||||
if req.Icone != nil {
|
||||
create.SetNillableIcone(req.Icone)
|
||||
}
|
||||
|
||||
created, err := create.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer l'emplacement"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, created)
|
||||
}
|
||||
|
||||
// @Summary Recuperer un emplacement
|
||||
// @Tags Emplacements
|
||||
// @Produce json
|
||||
// @Param id path string true "ID emplacement"
|
||||
// @Success 200 {object} ent.Emplacement
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /emplacements/{id} [get]
|
||||
func (h *Handler) GetEmplacement(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.client.Emplacement.Get(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "emplacement introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger l'emplacement"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, item)
|
||||
}
|
||||
|
||||
// @Summary Mettre a jour un emplacement
|
||||
// @Tags Emplacements
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID emplacement"
|
||||
// @Param body body emplacementRequest true "Emplacement a mettre a jour"
|
||||
// @Success 200 {object} ent.Emplacement
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /emplacements/{id} [put]
|
||||
func (h *Handler) UpdateEmplacement(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req emplacementRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
|
||||
update := h.client.Emplacement.UpdateOneID(id)
|
||||
if req.Nom != nil {
|
||||
update.SetNom(*req.Nom)
|
||||
}
|
||||
if req.ParentID != nil {
|
||||
if *req.ParentID == "" {
|
||||
update.ClearParentID()
|
||||
} else if parsed, err := uuid.Parse(*req.ParentID); err == nil {
|
||||
update.SetParentID(parsed)
|
||||
}
|
||||
}
|
||||
if req.Slug != nil {
|
||||
update.SetNillableSlug(req.Slug)
|
||||
}
|
||||
if req.Piece != nil {
|
||||
update.SetNillablePiece(req.Piece)
|
||||
}
|
||||
if req.Meuble != nil {
|
||||
update.SetNillableMeuble(req.Meuble)
|
||||
}
|
||||
if req.NumeroBoite != nil {
|
||||
update.SetNillableNumeroBoite(req.NumeroBoite)
|
||||
}
|
||||
if req.Icone != nil {
|
||||
update.SetNillableIcone(req.Icone)
|
||||
}
|
||||
|
||||
updated, err := update.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "emplacement introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de mettre a jour l'emplacement"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updated)
|
||||
}
|
||||
|
||||
// @Summary Supprimer un emplacement
|
||||
// @Tags Emplacements
|
||||
// @Param id path string true "ID emplacement"
|
||||
// @Success 204 {string} string "No Content"
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /emplacements/{id} [delete]
|
||||
func (h *Handler) DeleteEmplacement(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.client.Emplacement.DeleteOneID(id).Exec(c.Request.Context()); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer l'emplacement"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// helper for compile reference
|
||||
var _ = ent.IsNotFound
|
||||
8
backend/internal/handlers/handler.go
Normal file
8
backend/internal/handlers/handler.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package handlers
|
||||
|
||||
import "gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
|
||||
// Handler regroupe les dependances pour les handlers.
|
||||
type Handler struct {
|
||||
client *ent.Client
|
||||
}
|
||||
108
backend/internal/handlers/helpers.go
Normal file
108
backend/internal/handlers/helpers.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/objet"
|
||||
)
|
||||
|
||||
// parseDateTime parse une date ISO-8601.
|
||||
func parseDateTime(value string) (time.Time, error) {
|
||||
return time.Parse(time.RFC3339, value)
|
||||
}
|
||||
|
||||
// resolveCategorie determine la categorie d'une piece jointe.
|
||||
func resolveCategorie(ext string, mime string) string {
|
||||
ext = strings.ToLower(ext)
|
||||
mime = strings.ToLower(mime)
|
||||
if ext == ".md" || mime == "text/markdown" {
|
||||
return "markdown_tuto"
|
||||
}
|
||||
if mime == "application/pdf" || ext == ".pdf" {
|
||||
return "pdf_notice"
|
||||
}
|
||||
if strings.HasPrefix(mime, "image/") {
|
||||
return "image"
|
||||
}
|
||||
return "image"
|
||||
}
|
||||
|
||||
// maxUploadBytes retourne la taille max d'un fichier en octets.
|
||||
func maxUploadBytes() int64 {
|
||||
const defaultMB = 50
|
||||
value := os.Getenv("MAX_UPLOAD_MB")
|
||||
if value == "" {
|
||||
return defaultMB * 1024 * 1024
|
||||
}
|
||||
parsed, err := strconv.Atoi(value)
|
||||
if err != nil || parsed <= 0 {
|
||||
return defaultMB * 1024 * 1024
|
||||
}
|
||||
return int64(parsed) * 1024 * 1024
|
||||
}
|
||||
|
||||
// parsePagination calcule la limite et l'offset a partir des params page/limit.
|
||||
func parsePagination(pageValue string, limitValue string) (int, int, int) {
|
||||
const (
|
||||
defaultLimit = 50
|
||||
maxLimit = 200
|
||||
)
|
||||
|
||||
page := 1
|
||||
if pageValue != "" {
|
||||
if parsed, err := strconv.Atoi(pageValue); err == nil && parsed > 0 {
|
||||
page = parsed
|
||||
}
|
||||
}
|
||||
|
||||
limit := defaultLimit
|
||||
if limitValue != "" {
|
||||
if parsed, err := strconv.Atoi(limitValue); err == nil && parsed > 0 {
|
||||
limit = parsed
|
||||
}
|
||||
}
|
||||
if limit > maxLimit {
|
||||
limit = maxLimit
|
||||
}
|
||||
|
||||
offset := (page - 1) * limit
|
||||
return limit, offset, page
|
||||
}
|
||||
|
||||
// isAllowedUpload valide le type de fichier (images, PDF, Markdown).
|
||||
func isAllowedUpload(mime string, ext string) bool {
|
||||
mime = strings.ToLower(mime)
|
||||
ext = strings.ToLower(ext)
|
||||
if strings.HasPrefix(mime, "image/") {
|
||||
return true
|
||||
}
|
||||
if mime == "application/pdf" || ext == ".pdf" {
|
||||
return true
|
||||
}
|
||||
if mime == "text/markdown" || ext == ".md" || ext == ".markdown" {
|
||||
return true
|
||||
}
|
||||
if mime == "text/plain" && (ext == ".md" || ext == ".markdown") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseStatut convertit un statut texte vers l'enum Ent.
|
||||
func parseStatut(value string) (objet.Statut, bool) {
|
||||
switch value {
|
||||
case "en_stock":
|
||||
return objet.StatutEnStock, true
|
||||
case "pret":
|
||||
return objet.StatutPret, true
|
||||
case "hors_service":
|
||||
return objet.StatutHorsService, true
|
||||
case "archive":
|
||||
return objet.StatutArchive, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
74
backend/internal/handlers/helpers_test.go
Normal file
74
backend/internal/handlers/helpers_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package handlers
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIsAllowedUpload(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
mime string
|
||||
ext string
|
||||
want bool
|
||||
}{
|
||||
{"image", "image/png", ".png", true},
|
||||
{"pdf", "application/pdf", ".pdf", true},
|
||||
{"md", "text/markdown", ".md", true},
|
||||
{"md_plain", "text/plain", ".md", true},
|
||||
{"other", "application/zip", ".zip", false},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
if got := isAllowedUpload(c.mime, c.ext); got != c.want {
|
||||
t.Fatalf("attendu %v, obtenu %v", c.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxUploadBytes(t *testing.T) {
|
||||
t.Setenv("MAX_UPLOAD_MB", "1")
|
||||
if got := maxUploadBytes(); got != 1*1024*1024 {
|
||||
t.Fatalf("taille inattendue: %d", got)
|
||||
}
|
||||
|
||||
t.Setenv("MAX_UPLOAD_MB", "0")
|
||||
if got := maxUploadBytes(); got != 50*1024*1024 {
|
||||
t.Fatalf("taille par defaut inattendue: %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTypeChamp(t *testing.T) {
|
||||
valid := []string{"string", "int", "bool", "date"}
|
||||
for _, v := range valid {
|
||||
if _, ok := parseTypeChamp(v); !ok {
|
||||
t.Fatalf("type_champ invalide: %s", v)
|
||||
}
|
||||
}
|
||||
if _, ok := parseTypeChamp("x"); ok {
|
||||
t.Fatal("type_champ devrait etre invalide")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseLienType(t *testing.T) {
|
||||
valid := []string{"stocke", "utilise_dans"}
|
||||
for _, v := range valid {
|
||||
if _, ok := parseLienType(v); !ok {
|
||||
t.Fatalf("type lien invalide: %s", v)
|
||||
}
|
||||
}
|
||||
if _, ok := parseLienType("x"); ok {
|
||||
t.Fatal("type lien devrait etre invalide")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStatut(t *testing.T) {
|
||||
valid := []string{"en_stock", "pret", "hors_service", "archive"}
|
||||
for _, v := range valid {
|
||||
if _, ok := parseStatut(v); !ok {
|
||||
t.Fatalf("statut invalide: %s", v)
|
||||
}
|
||||
}
|
||||
if _, ok := parseStatut("x"); ok {
|
||||
t.Fatal("statut devrait etre invalide")
|
||||
}
|
||||
}
|
||||
269
backend/internal/handlers/liens_objet_emplacement.go
Normal file
269
backend/internal/handlers/liens_objet_emplacement.go
Normal file
@@ -0,0 +1,269 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/lienobjetemplacement"
|
||||
)
|
||||
|
||||
type lienObjetEmplacementRequest struct {
|
||||
EmplacementID *string `json:"emplacement_id"`
|
||||
Type *string `json:"type"`
|
||||
}
|
||||
|
||||
type lienObjetEmplacementUpdateRequest struct {
|
||||
EmplacementID *string `json:"emplacement_id"`
|
||||
Type *string `json:"type"`
|
||||
}
|
||||
|
||||
// @Summary Lister les liens objet/emplacement
|
||||
// @Tags LiensEmplacements
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param page query int false "Page"
|
||||
// @Param limit query int false "Limite"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id}/liens_emplacements [get]
|
||||
func (h *Handler) ListLiensEmplacements(c *gin.Context) {
|
||||
objetID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
|
||||
query := h.client.LienObjetEmplacement.Query().
|
||||
Where(lienobjetemplacement.ObjetID(objetID))
|
||||
total, err := query.Count(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les liens"})
|
||||
return
|
||||
}
|
||||
|
||||
items, err := query.
|
||||
Order(ent.Desc(lienobjetemplacement.FieldCreatedAt)).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
All(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les liens"})
|
||||
return
|
||||
}
|
||||
respondPaginated(c, items, total, page, limit)
|
||||
}
|
||||
|
||||
// @Summary Creer un lien objet/emplacement
|
||||
// @Tags LiensEmplacements
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param body body lienObjetEmplacementRequest true "Lien"
|
||||
// @Success 201 {object} ent.LienObjetEmplacement
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 409 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id}/liens_emplacements [post]
|
||||
func (h *Handler) CreateLienEmplacement(c *gin.Context) {
|
||||
objetID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req lienObjetEmplacementRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
if req.EmplacementID == nil || *req.EmplacementID == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "emplacement_id obligatoire"})
|
||||
return
|
||||
}
|
||||
|
||||
emplacementID, err := uuid.Parse(*req.EmplacementID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "emplacement_id invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := h.client.Emplacement.Get(c.Request.Context(), emplacementID); err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "emplacement introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger l'emplacement"})
|
||||
return
|
||||
}
|
||||
|
||||
create := h.client.LienObjetEmplacement.Create().
|
||||
SetObjetID(objetID).
|
||||
SetEmplacementID(emplacementID)
|
||||
|
||||
typeValeur := lienobjetemplacement.TypeStocke
|
||||
if req.Type != nil && *req.Type != "" {
|
||||
parsed, ok := parseLienType(*req.Type)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "type invalide"})
|
||||
return
|
||||
}
|
||||
typeValeur = parsed
|
||||
}
|
||||
create.SetType(typeValeur)
|
||||
|
||||
exists, err := h.client.LienObjetEmplacement.Query().
|
||||
Where(
|
||||
lienobjetemplacement.ObjetID(objetID),
|
||||
lienobjetemplacement.EmplacementID(emplacementID),
|
||||
lienobjetemplacement.TypeEQ(typeValeur),
|
||||
).
|
||||
Exist(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de verifier le lien"})
|
||||
return
|
||||
}
|
||||
if exists {
|
||||
c.JSON(http.StatusConflict, gin.H{"erreur": "lien deja existant"})
|
||||
return
|
||||
}
|
||||
|
||||
created, err := create.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer le lien"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, created)
|
||||
}
|
||||
|
||||
// @Summary Supprimer un lien objet/emplacement
|
||||
// @Tags LiensEmplacements
|
||||
// @Param id path string true "ID lien"
|
||||
// @Success 204 {string} string "No Content"
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /liens_emplacements/{id} [delete]
|
||||
func (h *Handler) DeleteLienEmplacement(c *gin.Context) {
|
||||
lienID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.client.LienObjetEmplacement.DeleteOneID(lienID).Exec(c.Request.Context()); err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "lien introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer le lien"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// @Summary Mettre a jour un lien objet/emplacement
|
||||
// @Tags LiensEmplacements
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID lien"
|
||||
// @Param body body lienObjetEmplacementUpdateRequest true "Mise a jour"
|
||||
// @Success 200 {object} ent.LienObjetEmplacement
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 409 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /liens_emplacements/{id} [put]
|
||||
func (h *Handler) UpdateLienEmplacement(c *gin.Context) {
|
||||
lienID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req lienObjetEmplacementUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
|
||||
existant, err := h.client.LienObjetEmplacement.Get(c.Request.Context(), lienID)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "lien introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger le lien"})
|
||||
return
|
||||
}
|
||||
|
||||
nouveauEmplacementID := existant.EmplacementID
|
||||
if req.EmplacementID != nil && *req.EmplacementID != "" {
|
||||
parsed, err := uuid.Parse(*req.EmplacementID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "emplacement_id invalide"})
|
||||
return
|
||||
}
|
||||
if _, err := h.client.Emplacement.Get(c.Request.Context(), parsed); err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "emplacement introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger l'emplacement"})
|
||||
return
|
||||
}
|
||||
nouveauEmplacementID = parsed
|
||||
}
|
||||
|
||||
nouveauType := existant.Type
|
||||
if req.Type != nil && *req.Type != "" {
|
||||
parsed, ok := parseLienType(*req.Type)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "type invalide"})
|
||||
return
|
||||
}
|
||||
nouveauType = parsed
|
||||
}
|
||||
|
||||
dupe, err := h.client.LienObjetEmplacement.Query().
|
||||
Where(
|
||||
lienobjetemplacement.ObjetID(existant.ObjetID),
|
||||
lienobjetemplacement.EmplacementID(nouveauEmplacementID),
|
||||
lienobjetemplacement.TypeEQ(nouveauType),
|
||||
lienobjetemplacement.IDNEQ(lienID),
|
||||
).
|
||||
Exist(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de verifier le lien"})
|
||||
return
|
||||
}
|
||||
if dupe {
|
||||
c.JSON(http.StatusConflict, gin.H{"erreur": "lien deja existant"})
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := h.client.LienObjetEmplacement.UpdateOneID(lienID).
|
||||
SetEmplacementID(nouveauEmplacementID).
|
||||
SetType(nouveauType).
|
||||
Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de mettre a jour le lien"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updated)
|
||||
}
|
||||
|
||||
func parseLienType(value string) (lienobjetemplacement.Type, bool) {
|
||||
switch value {
|
||||
case "stocke":
|
||||
return lienobjetemplacement.TypeStocke, true
|
||||
case "utilise_dans":
|
||||
return lienobjetemplacement.TypeUtiliseDans, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
267
backend/internal/handlers/objets.go
Normal file
267
backend/internal/handlers/objets.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/objet"
|
||||
)
|
||||
|
||||
type objetRequest struct {
|
||||
Nom *string `json:"nom"`
|
||||
Description *string `json:"description"`
|
||||
Quantite *int `json:"quantite"`
|
||||
PrixAchat *float64 `json:"prix_achat"`
|
||||
DateAchat *string `json:"date_achat"`
|
||||
Boutique *string `json:"boutique"`
|
||||
NumeroSerie *string `json:"numero_serie"`
|
||||
NumeroModele *string `json:"numero_modele"`
|
||||
Fabricant *string `json:"fabricant"`
|
||||
Statut *string `json:"statut"`
|
||||
Caracteristiques map[string]any `json:"caracteristiques"`
|
||||
}
|
||||
|
||||
// @Summary Lister les objets
|
||||
// @Tags Objets
|
||||
// @Produce json
|
||||
// @Param page query int false "Page"
|
||||
// @Param limit query int false "Limite"
|
||||
// @Param statut query string false "Statut"
|
||||
// @Param nom query string false "Recherche nom"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets [get]
|
||||
func (h *Handler) ListObjets(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
|
||||
query := h.client.Objet.Query()
|
||||
|
||||
if statutValue := c.Query("statut"); statutValue != "" {
|
||||
statut, ok := parseStatut(statutValue)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "statut invalide"})
|
||||
return
|
||||
}
|
||||
query = query.Where(objet.StatutEQ(statut))
|
||||
}
|
||||
if nomValue := c.Query("nom"); nomValue != "" {
|
||||
query = query.Where(objet.NomContainsFold(nomValue))
|
||||
}
|
||||
total, err := query.Count(ctx)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les objets"})
|
||||
return
|
||||
}
|
||||
|
||||
objets, err := query.
|
||||
Order(ent.Desc(objet.FieldCreatedAt)).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
All(ctx)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les objets"})
|
||||
return
|
||||
}
|
||||
respondPaginated(c, objets, total, page, limit)
|
||||
}
|
||||
|
||||
// @Summary Creer un objet
|
||||
// @Tags Objets
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body objetRequest true "Objet a creer"
|
||||
// @Success 201 {object} ent.Objet
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets [post]
|
||||
func (h *Handler) CreateObjet(c *gin.Context) {
|
||||
var req objetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
if req.Nom == nil || *req.Nom == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "le champ nom est obligatoire"})
|
||||
return
|
||||
}
|
||||
|
||||
create := h.client.Objet.Create().SetNom(*req.Nom)
|
||||
|
||||
if req.Description != nil {
|
||||
create.SetNillableDescription(req.Description)
|
||||
}
|
||||
if req.Quantite != nil {
|
||||
create.SetQuantite(*req.Quantite)
|
||||
}
|
||||
if req.PrixAchat != nil {
|
||||
create.SetNillablePrixAchat(req.PrixAchat)
|
||||
}
|
||||
if req.DateAchat != nil {
|
||||
if parsed, err := parseDateTime(*req.DateAchat); err == nil {
|
||||
create.SetNillableDateAchat(&parsed)
|
||||
}
|
||||
}
|
||||
if req.Boutique != nil {
|
||||
create.SetNillableBoutique(req.Boutique)
|
||||
}
|
||||
if req.NumeroSerie != nil {
|
||||
create.SetNillableNumeroSerie(req.NumeroSerie)
|
||||
}
|
||||
if req.NumeroModele != nil {
|
||||
create.SetNillableNumeroModele(req.NumeroModele)
|
||||
}
|
||||
if req.Fabricant != nil {
|
||||
create.SetNillableFabricant(req.Fabricant)
|
||||
}
|
||||
if req.Statut != nil {
|
||||
parsed, ok := parseStatut(*req.Statut)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "statut invalide"})
|
||||
return
|
||||
}
|
||||
create.SetStatut(parsed)
|
||||
}
|
||||
if req.Caracteristiques != nil {
|
||||
create.SetCaracteristiques(req.Caracteristiques)
|
||||
}
|
||||
|
||||
created, err := create.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer l'objet"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, created)
|
||||
}
|
||||
|
||||
// @Summary Recuperer un objet
|
||||
// @Tags Objets
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Success 200 {object} ent.Objet
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id} [get]
|
||||
func (h *Handler) GetObjet(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.client.Objet.Get(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "objet introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger l'objet"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, item)
|
||||
}
|
||||
|
||||
// @Summary Mettre a jour un objet
|
||||
// @Tags Objets
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param body body objetRequest true "Objet a mettre a jour"
|
||||
// @Success 200 {object} ent.Objet
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id} [put]
|
||||
func (h *Handler) UpdateObjet(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
var req objetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
|
||||
return
|
||||
}
|
||||
|
||||
update := h.client.Objet.UpdateOneID(id)
|
||||
|
||||
if req.Nom != nil {
|
||||
update.SetNom(*req.Nom)
|
||||
}
|
||||
if req.Description != nil {
|
||||
update.SetNillableDescription(req.Description)
|
||||
}
|
||||
if req.Quantite != nil {
|
||||
update.SetQuantite(*req.Quantite)
|
||||
}
|
||||
if req.PrixAchat != nil {
|
||||
update.SetNillablePrixAchat(req.PrixAchat)
|
||||
}
|
||||
if req.DateAchat != nil {
|
||||
if parsed, err := parseDateTime(*req.DateAchat); err == nil {
|
||||
update.SetNillableDateAchat(&parsed)
|
||||
}
|
||||
}
|
||||
if req.Boutique != nil {
|
||||
update.SetNillableBoutique(req.Boutique)
|
||||
}
|
||||
if req.NumeroSerie != nil {
|
||||
update.SetNillableNumeroSerie(req.NumeroSerie)
|
||||
}
|
||||
if req.NumeroModele != nil {
|
||||
update.SetNillableNumeroModele(req.NumeroModele)
|
||||
}
|
||||
if req.Fabricant != nil {
|
||||
update.SetNillableFabricant(req.Fabricant)
|
||||
}
|
||||
if req.Statut != nil {
|
||||
parsed, ok := parseStatut(*req.Statut)
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "statut invalide"})
|
||||
return
|
||||
}
|
||||
update.SetStatut(parsed)
|
||||
}
|
||||
if req.Caracteristiques != nil {
|
||||
update.SetCaracteristiques(req.Caracteristiques)
|
||||
}
|
||||
|
||||
updated, err := update.Save(c.Request.Context())
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "objet introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de mettre a jour l'objet"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updated)
|
||||
}
|
||||
|
||||
// @Summary Supprimer un objet
|
||||
// @Tags Objets
|
||||
// @Param id path string true "ID objet"
|
||||
// @Success 204 {string} string "No Content"
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id} [delete]
|
||||
func (h *Handler) DeleteObjet(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.client.Objet.DeleteOneID(id).Exec(c.Request.Context()); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer l'objet"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// helper for compile reference
|
||||
var _ = ent.IsNotFound
|
||||
25
backend/internal/handlers/pagination.go
Normal file
25
backend/internal/handlers/pagination.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type paginatedResponse struct {
|
||||
Items any `json:"items"`
|
||||
Meta struct {
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
} `json:"meta"`
|
||||
}
|
||||
|
||||
func respondPaginated(c *gin.Context, items any, total int, page int, limit int) {
|
||||
var resp paginatedResponse
|
||||
resp.Items = items
|
||||
resp.Meta.Total = total
|
||||
resp.Meta.Page = page
|
||||
resp.Meta.Limit = limit
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
275
backend/internal/handlers/pieces_jointes.go
Normal file
275
backend/internal/handlers/pieces_jointes.go
Normal file
@@ -0,0 +1,275 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/piecejointe"
|
||||
)
|
||||
|
||||
// UploadPiecesJointes gere l'upload multiple des fichiers d'un objet.
|
||||
// @Summary Uploader des pieces jointes
|
||||
// @Tags PiecesJointes
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param fichiers formData file true "Fichiers (multi)"
|
||||
// @Success 201 {object} map[string]any
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 413 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id}/pieces_jointes [post]
|
||||
func (h *Handler) UploadPiecesJointes(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := h.client.Objet.Get(c.Request.Context(), id); err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "objet introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger l'objet"})
|
||||
return
|
||||
}
|
||||
|
||||
form, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "formulaire invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
files := form.File["fichiers"]
|
||||
if len(files) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "aucun fichier fourni"})
|
||||
return
|
||||
}
|
||||
|
||||
maxBytes := maxUploadBytes()
|
||||
|
||||
hasPrincipale, err := h.client.PieceJointe.Query().
|
||||
Where(
|
||||
piecejointe.ObjetID(id),
|
||||
piecejointe.EstPrincipale(true),
|
||||
).
|
||||
Exist(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de verifier la piece jointe principale"})
|
||||
return
|
||||
}
|
||||
|
||||
baseDir := os.Getenv("ATTACHMENTS_DIR")
|
||||
if baseDir == "" {
|
||||
baseDir = "./data/pieces_jointes"
|
||||
}
|
||||
if err := os.MkdirAll(baseDir, 0o755); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer le dossier de stockage"})
|
||||
return
|
||||
}
|
||||
|
||||
var saved []map[string]any
|
||||
for idx, file := range files {
|
||||
ext := strings.ToLower(filepath.Ext(file.Filename))
|
||||
if file.Size > maxBytes {
|
||||
c.JSON(http.StatusRequestEntityTooLarge, gin.H{"erreur": "fichier trop volumineux"})
|
||||
return
|
||||
}
|
||||
|
||||
mime := file.Header.Get("Content-Type")
|
||||
if !isAllowedUpload(mime, ext) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "type de fichier non supporte"})
|
||||
return
|
||||
}
|
||||
|
||||
uuidName := uuid.New().String() + ext
|
||||
path := filepath.Join(baseDir, uuidName)
|
||||
|
||||
if err := c.SaveUploadedFile(file, path); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "echec enregistrement fichier"})
|
||||
return
|
||||
}
|
||||
|
||||
categorie := resolveCategorie(ext, mime)
|
||||
estPrincipale := idx == 0 && !hasPrincipale
|
||||
|
||||
pj, err := h.client.PieceJointe.Create().
|
||||
SetObjetID(id).
|
||||
SetNomFichier(file.Filename).
|
||||
SetChemin(path).
|
||||
SetTypeMime(mime).
|
||||
SetCategorie(piecejointe.Categorie(categorie)).
|
||||
SetEstPrincipale(estPrincipale).
|
||||
Save(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible d'enregistrer la piece jointe"})
|
||||
return
|
||||
}
|
||||
|
||||
saved = append(saved, map[string]any{
|
||||
"id": pj.ID,
|
||||
"nom_fichier": pj.NomFichier,
|
||||
"chemin": pj.Chemin,
|
||||
"type_mime": pj.TypeMime,
|
||||
"categorie": pj.Categorie,
|
||||
"est_principale": pj.EstPrincipale,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"pieces_jointes": saved})
|
||||
}
|
||||
|
||||
// ListPiecesJointes retourne la liste des pieces jointes d'un objet.
|
||||
// @Summary Lister les pieces jointes
|
||||
// @Tags PiecesJointes
|
||||
// @Produce json
|
||||
// @Param id path string true "ID objet"
|
||||
// @Param page query int false "Page"
|
||||
// @Param limit query int false "Limite"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /objets/{id}/pieces_jointes [get]
|
||||
func (h *Handler) ListPiecesJointes(c *gin.Context) {
|
||||
objetID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
|
||||
query := h.client.PieceJointe.Query().
|
||||
Where(piecejointe.ObjetID(objetID))
|
||||
total, err := query.Count(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les pieces jointes"})
|
||||
return
|
||||
}
|
||||
|
||||
items, err := query.
|
||||
Order(ent.Desc(piecejointe.FieldCreatedAt)).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
All(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les pieces jointes"})
|
||||
return
|
||||
}
|
||||
respondPaginated(c, items, total, page, limit)
|
||||
}
|
||||
|
||||
// DeletePieceJointe supprime une piece jointe et son fichier.
|
||||
// @Summary Supprimer une piece jointe
|
||||
// @Tags PiecesJointes
|
||||
// @Param id path string true "ID piece jointe"
|
||||
// @Success 204 {string} string "No Content"
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /pieces_jointes/{id} [delete]
|
||||
func (h *Handler) DeletePieceJointe(c *gin.Context) {
|
||||
pieceID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.client.PieceJointe.Get(c.Request.Context(), pieceID)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "piece jointe introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger la piece jointe"})
|
||||
return
|
||||
}
|
||||
|
||||
if item.Chemin != "" {
|
||||
if err := os.Remove(item.Chemin); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer le fichier"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.client.PieceJointe.DeleteOneID(pieceID).Exec(c.Request.Context()); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer la piece jointe"})
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// SetPieceJointePrincipale marque une piece jointe comme principale.
|
||||
// @Summary Definir la piece jointe principale
|
||||
// @Tags PiecesJointes
|
||||
// @Produce json
|
||||
// @Param id path string true "ID piece jointe"
|
||||
// @Success 200 {object} ent.PieceJointe
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /pieces_jointes/{id}/principale [put]
|
||||
func (h *Handler) SetPieceJointePrincipale(c *gin.Context) {
|
||||
pieceID, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.client.PieceJointe.Get(c.Request.Context(), pieceID)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"erreur": "piece jointe introuvable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger la piece jointe"})
|
||||
return
|
||||
}
|
||||
|
||||
tx, err := h.client.Tx(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible d'ouvrir la transaction"})
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err = tx.PieceJointe.Update().
|
||||
Where(piecejointe.ObjetID(item.ObjetID)).
|
||||
SetEstPrincipale(false).
|
||||
Save(c.Request.Context()); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de reinitialiser la principale"})
|
||||
_ = tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = tx.PieceJointe.UpdateOneID(pieceID).
|
||||
SetEstPrincipale(true).
|
||||
Save(c.Request.Context()); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de definir la principale"})
|
||||
_ = tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
if err = tx.Commit(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de finaliser la transaction"})
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := h.client.PieceJointe.Get(c.Request.Context(), pieceID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de charger la piece jointe"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, updated)
|
||||
}
|
||||
44
backend/internal/handlers/router.go
Normal file
44
backend/internal/handlers/router.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
|
||||
)
|
||||
|
||||
// RegisterRoutes enregistre les routes v1.
|
||||
func RegisterRoutes(r *gin.Engine, client *ent.Client) {
|
||||
h := &Handler{client: client}
|
||||
|
||||
v1 := r.Group("/v1")
|
||||
{
|
||||
v1.GET("/objets", h.ListObjets)
|
||||
v1.POST("/objets", h.CreateObjet)
|
||||
v1.GET("/objets/:id", h.GetObjet)
|
||||
v1.PUT("/objets/:id", h.UpdateObjet)
|
||||
v1.DELETE("/objets/:id", h.DeleteObjet)
|
||||
v1.POST("/objets/:id/pieces_jointes", h.UploadPiecesJointes)
|
||||
v1.GET("/objets/:id/pieces_jointes", h.ListPiecesJointes)
|
||||
v1.DELETE("/pieces_jointes/:id", h.DeletePieceJointe)
|
||||
v1.PUT("/pieces_jointes/:id/principale", h.SetPieceJointePrincipale)
|
||||
v1.GET("/objets/:id/champs_personnalises", h.ListChampsPersonnalises)
|
||||
v1.POST("/objets/:id/champs_personnalises", h.CreateChampPersonnalise)
|
||||
v1.PUT("/champs_personnalises/:id", h.UpdateChampPersonnalise)
|
||||
v1.DELETE("/champs_personnalises/:id", h.DeleteChampPersonnalise)
|
||||
v1.GET("/objets/:id/liens_emplacements", h.ListLiensEmplacements)
|
||||
v1.POST("/objets/:id/liens_emplacements", h.CreateLienEmplacement)
|
||||
v1.PUT("/liens_emplacements/:id", h.UpdateLienEmplacement)
|
||||
v1.DELETE("/liens_emplacements/:id", h.DeleteLienEmplacement)
|
||||
|
||||
v1.GET("/categories", h.ListCategories)
|
||||
v1.POST("/categories", h.CreateCategorie)
|
||||
v1.GET("/categories/:id", h.GetCategorie)
|
||||
v1.PUT("/categories/:id", h.UpdateCategorie)
|
||||
v1.DELETE("/categories/:id", h.DeleteCategorie)
|
||||
|
||||
v1.GET("/emplacements", h.ListEmplacements)
|
||||
v1.POST("/emplacements", h.CreateEmplacement)
|
||||
v1.GET("/emplacements/:id", h.GetEmplacement)
|
||||
v1.PUT("/emplacements/:id", h.UpdateEmplacement)
|
||||
v1.DELETE("/emplacements/:id", h.DeleteEmplacement)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user