turash/bugulma/backend/internal/handler/site_handler.go
Damir Mukimov 000eab4740
Major repository reorganization and missing backend endpoints implementation
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools

Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
  * GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
  * GET /api/v1/users/me/organizations - User organizations
  * POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue

API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules

Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
2025-11-25 06:01:16 +01:00

171 lines
4.7 KiB
Go

package handler
import (
"net/http"
"bugulma/backend/internal/domain"
"bugulma/backend/internal/service"
"github.com/gin-gonic/gin"
)
type SiteHandler struct {
siteService *service.SiteService
}
func NewSiteHandler(siteService *service.SiteService) *SiteHandler {
return &SiteHandler{siteService: siteService}
}
type CreateSiteRequest struct {
Name string `json:"name" binding:"required"`
Latitude float64 `json:"latitude" binding:"required"`
Longitude float64 `json:"longitude" binding:"required"`
SiteType domain.SiteType `json:"site_type"`
FloorAreaM2 float64 `json:"floor_area_m2"`
Ownership domain.Ownership `json:"ownership"`
OwnerOrganizationID string `json:"owner_organization_id" binding:"required"`
AvailableUtilities []string `json:"available_utilities"`
ParkingSpaces int `json:"parking_spaces"`
LoadingDocks int `json:"loading_docks"`
CraneCapacityTonnes float64 `json:"crane_capacity_tonnes"`
EnergyRating string `json:"energy_rating"`
}
func (h *SiteHandler) Create(c *gin.Context) {
var req CreateSiteRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
siteReq := service.CreateSiteRequest{
Name: req.Name,
Latitude: req.Latitude,
Longitude: req.Longitude,
SiteType: req.SiteType,
FloorAreaM2: req.FloorAreaM2,
Ownership: req.Ownership,
OwnerOrganizationID: req.OwnerOrganizationID,
AvailableUtilities: req.AvailableUtilities,
ParkingSpaces: req.ParkingSpaces,
LoadingDocks: req.LoadingDocks,
CraneCapacityTonnes: req.CraneCapacityTonnes,
EnergyRating: req.EnergyRating,
}
created, err := h.siteService.Create(c.Request.Context(), siteReq)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, created)
}
func (h *SiteHandler) GetByID(c *gin.Context) {
id := c.Param("id")
site, err := h.siteService.GetByID(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Site not found"})
return
}
c.JSON(http.StatusOK, site)
}
func (h *SiteHandler) GetByOrganization(c *gin.Context) {
organizationID := c.Param("organizationId")
sites, err := h.siteService.GetByOrganizationID(c.Request.Context(), organizationID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, sites)
}
func (h *SiteHandler) GetNearby(c *gin.Context) {
var query struct {
Latitude float64 `form:"lat" binding:"required"`
Longitude float64 `form:"lng" binding:"required"`
RadiusKm float64 `form:"radius" binding:"required"`
}
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
sites, err := h.siteService.GetNearby(c.Request.Context(), query.Latitude, query.Longitude, query.RadiusKm)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, sites)
}
func (h *SiteHandler) GetAll(c *gin.Context) {
sites, err := h.siteService.GetAll(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, sites)
}
func (h *SiteHandler) GetHeritageSites(c *gin.Context) {
locale := extractLocale(c)
sites, err := h.siteService.GetHeritageSites(c.Request.Context(), locale)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, sites)
}
func (h *SiteHandler) Update(c *gin.Context) {
id := c.Param("id")
var req CreateSiteRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
site, err := h.siteService.GetByID(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Site not found"})
return
}
// Update fields
site.Name = req.Name
site.Latitude = req.Latitude
site.Longitude = req.Longitude
site.FloorAreaM2 = req.FloorAreaM2
if err := h.siteService.Update(c.Request.Context(), site); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, site)
}
func (h *SiteHandler) Delete(c *gin.Context) {
id := c.Param("id")
if err := h.siteService.Delete(c.Request.Context(), id); err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Site not found"})
return
}
c.JSON(http.StatusNoContent, nil)
}