diff --git a/app/delivery/web/api/restricted/productDescription.go b/app/delivery/web/api/restricted/productDescription.go new file mode 100644 index 0000000..ddafe32 --- /dev/null +++ b/app/delivery/web/api/restricted/productDescription.go @@ -0,0 +1,81 @@ +package restricted + +import ( + "strconv" + + "git.ma-al.com/goc_daniel/b2b/app/config" + "git.ma-al.com/goc_daniel/b2b/app/service/productDescriptionService" + "git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors" + + "github.com/gofiber/fiber/v3" +) + +// ProductDescriptionHandler handles endpoints that receive, save and translate product descriptions. +type ProductDescriptionHandler struct { + productDescriptionService *productDescriptionService.ProductDescriptionService + config *config.Config +} + +// NewProductDescriptionHandler creates a new ProductDescriptionHandler instance +func NewProductDescriptionHandler() *ProductDescriptionHandler { + productDescriptionService := productDescriptionService.New() + return &ProductDescriptionHandler{ + productDescriptionService: productDescriptionService, + config: config.Get(), + } +} + +// ProductDescriptionRoutes registers all product description routes +func ProductDescriptionHandlerRoutes(r fiber.Router) fiber.Router { + handler := NewProductDescriptionHandler() + + r.Get("/get-product-description", handler.GetProductDescription) + // r.Get("/get-years", handler.GetYears) + // r.Get("/get-quarters", handler.GetQuarters) + // r.Get("/get-issues", handler.GetIssues) + + return r +} + +// GetProductDescription returns the product description for a given product ID +func (h *ProductDescriptionHandler) GetProductDescription(c fiber.Ctx) error { + userID, ok := c.Locals("userID").(uint) + if !ok { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).JSON(fiber.Map{ + "error": responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody), // possibly could return a dfifferent error + }) + } + + productID_attribute := c.Query("productID") + productID, err := strconv.Atoi(productID_attribute) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{ + "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute), + }) + } + + productShopID_attribute := c.Query("productShopID") + productShopID, err := strconv.Atoi(productShopID_attribute) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{ + "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute), + }) + } + + productLangID_attribute := c.Query("productLangID") + productLangID, err := strconv.Atoi(productLangID_attribute) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).JSON(fiber.Map{ + "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute), + }) + } + + response, err := h.productDescriptionService.GetProductDescription(userID, uint(productID), uint(productShopID), uint(productLangID)) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{ + "error": responseErrors.GetErrorCode(c, err), + }) + } + + return c.JSON(response) +} diff --git a/app/delivery/web/api/restricted/repo.go b/app/delivery/web/api/restricted/repo.go deleted file mode 100644 index 3284fd1..0000000 --- a/app/delivery/web/api/restricted/repo.go +++ /dev/null @@ -1,179 +0,0 @@ -package restricted - -import ( - "strconv" - - "git.ma-al.com/goc_daniel/b2b/app/config" - "git.ma-al.com/goc_daniel/b2b/app/service/repoService" - "git.ma-al.com/goc_daniel/b2b/app/utils/pagination" - "git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors" - - "github.com/gofiber/fiber/v3" -) - -// RepoHandler handles endpoints asking for repository data (to create charts) -type RepoHandler struct { - repoService *repoService.RepoService - config *config.Config -} - -// NewRepoHandler creates a new RepoHandler instance -func NewRepoHandler() *RepoHandler { - repoService := repoService.New() - return &RepoHandler{ - repoService: repoService, - config: config.Get(), - } -} - -// RepoHandlerRoutes registers all repo routes -func RepoHandlerRoutes(r fiber.Router) fiber.Router { - handler := NewRepoHandler() - - r.Get("/get-repos", handler.GetRepoIDs) - r.Get("/get-years", handler.GetYears) - r.Get("/get-quarters", handler.GetQuarters) - r.Get("/get-issues", handler.GetIssues) - - return r -} - -func (h *RepoHandler) GetRepoIDs(c fiber.Ctx) error { - userID, ok := c.Locals("userID").(uint) - if !ok { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody), - }) - } - - response, err := h.repoService.GetRepositoriesForUser(userID) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, err), - }) - } - - return c.JSON(response) -} - -func (h *RepoHandler) GetYears(c fiber.Ctx) error { - userID, ok := c.Locals("userID").(uint) - if !ok { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody), - }) - } - - repoID_attribute := c.Query("repoID") - repoID, err := strconv.Atoi(repoID_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadRepoIDAttribute)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadRepoIDAttribute), - }) - } - - response, err := h.repoService.GetYearsForUser(userID, uint(repoID)) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, err), - }) - } - - return c.JSON(response) -} - -func (h *RepoHandler) GetQuarters(c fiber.Ctx) error { - userID, ok := c.Locals("userID").(uint) - if !ok { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody), - }) - } - - repoID_attribute := c.Query("repoID") - repoID, err := strconv.Atoi(repoID_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadRepoIDAttribute)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadRepoIDAttribute), - }) - } - - year_attribute := c.Query("year") - year, err := strconv.Atoi(year_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadYearAttribute)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadYearAttribute), - }) - } - - response, err := h.repoService.GetQuartersForUser(userID, uint(repoID), uint(year)) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, err), - }) - } - - return c.JSON(response) -} - -func (h *RepoHandler) GetIssues(c fiber.Ctx) error { - userID, ok := c.Locals("userID").(uint) - if !ok { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody), - }) - } - - repoID_attribute := c.Query("repoID") - repoID, err := strconv.Atoi(repoID_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadRepoIDAttribute)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadRepoIDAttribute), - }) - } - - year_attribute := c.Query("year") - year, err := strconv.Atoi(year_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadYearAttribute)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadYearAttribute), - }) - } - - quarter_attribute := c.Query("quarter") - quarter, err := strconv.Atoi(quarter_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadQuarterAttribute)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadQuarterAttribute), - }) - } - - page_number_attribute := c.Query("page_number") - page_number, err := strconv.Atoi(page_number_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadPaging)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadPaging), - }) - } - - elements_per_page_attribute := c.Query("elements_per_page") - elements_per_page, err := strconv.Atoi(elements_per_page_attribute) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadPaging)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, responseErrors.ErrBadPaging), - }) - } - - var paging pagination.Paging - paging.Page = uint(page_number) - paging.Elements = uint(elements_per_page) - - response, err := h.repoService.GetIssuesForUser(userID, uint(repoID), uint(year), uint(quarter), paging) - if err != nil { - return c.Status(responseErrors.GetErrorStatus(err)).JSON(fiber.Map{ - "error": responseErrors.GetErrorCode(c, err), - }) - } - - return c.JSON(response) -} diff --git a/app/delivery/web/init.go b/app/delivery/web/init.go index d334970..2fe263b 100644 --- a/app/delivery/web/init.go +++ b/app/delivery/web/init.go @@ -90,8 +90,8 @@ func (s *Server) Setup() error { public.AuthHandlerRoutes(auth) // Repo routes (restricted) - repo := s.restricted.Group("/repo") - restricted.RepoHandlerRoutes(repo) + productDescription := s.restricted.Group("/product-description") + restricted.ProductDescriptionHandlerRoutes(productDescription) // // Restricted routes example // restricted := s.api.Group("/restricted") diff --git a/app/model/productDescription.go b/app/model/productDescription.go new file mode 100644 index 0000000..9a6287e --- /dev/null +++ b/app/model/productDescription.go @@ -0,0 +1,20 @@ +package model + +// User represents a user in the system +type ProductDescription struct { + ProductID uint `gorm:"column:id_product;primaryKey" json:"product_id"` + ShopID uint `gorm:"column:id_shop;primaryKey" json:"shop_id"` + LangID uint `gorm:"column:id_lang;primaryKey" json:"lang_id"` + Description string `gorm:"column:description;type:text" json:"description"` + DescriptionShort string `gorm:"column:description_short;type:text" json:"description_short"` + LinkRewrite string `gorm:"column:link_rewrite;type:varchar(128)" json:"link_rewrite"` + MetaDescription string `gorm:"column:meta_description;type:varchar(512)" json:"meta_description"` + MetaKeywords string `gorm:"column:meta_keywords;type:varchar(255)" json:"meta_keywords"` + MetaTitle string `gorm:"column:meta_title;type:varchar(128)" json:"meta_title"` + Name string `gorm:"column:name;type:varchar(128)" json:"name"` + AvailableNow string `gorm:"column:available_now;type:varchar(255)" json:"available_now"` + AvailableLater string `gorm:"column:available_later;type:varchar(255)" json:"available_later"` + DeliveryInStock string `gorm:"column:delivery_in_stock;type:varchar(255)" json:"delivery_in_stock"` + DeliveryOutStock string `gorm:"column:delivery_out_stock;type:varchar(255)" json:"delivery_out_stock"` + Usage string `gorm:"column:usage;type:text" json:"usage"` +} diff --git a/app/model/repo.go b/app/model/repo.go deleted file mode 100644 index 8026638..0000000 --- a/app/model/repo.go +++ /dev/null @@ -1,54 +0,0 @@ -package model - -import ( - "time" - - "git.ma-al.com/goc_daniel/b2b/app/utils/pagination" -) - -// LoginRequest represents the login form data -type DataRequest struct { - RepoID uint `json:"repoid" form:"repoid"` - Step uint `json:"step" form:"step"` -} - -type PageMeta struct { - Title string - Description string -} - -type QuarterData struct { - Time float64 `json:"time"` - Quarter string `json:"quarter"` -} - -type DayData struct { - Date string `json:"date"` - Time float64 `json:"time"` -} - -type RepositoryChartData struct { - Years []uint - Quarters []QuarterData - QuartersJSON string - Year uint -} - -type TimeTrackedData struct { - RepoId uint - Year uint - Quarter uint - Step string - TotalTime float64 - DailyData []DayData - DailyDataJSON string - Years []uint - IssueSummaries *pagination.Found[IssueTimeSummary] -} - -type IssueTimeSummary struct { - IssueID uint `gorm:"column:issue_id"` - IssueName string `gorm:"column:issue_name"` - CreatedDate time.Time `gorm:"column:issue_created_at"` - TotalHoursSpent float64 `gorm:"column:total_hours_spent"` -} diff --git a/app/service/productDescriptionService/productDescriptionService.go b/app/service/productDescriptionService/productDescriptionService.go new file mode 100644 index 0000000..698d6b0 --- /dev/null +++ b/app/service/productDescriptionService/productDescriptionService.go @@ -0,0 +1,219 @@ +package productDescriptionService + +import ( + "fmt" + + "git.ma-al.com/goc_daniel/b2b/app/db" + "git.ma-al.com/goc_daniel/b2b/app/model" + "gorm.io/gorm" +) + +type ProductDescriptionService struct { + db *gorm.DB +} + +func New() *ProductDescriptionService { + return &ProductDescriptionService{ + db: db.Get(), + } +} + +// We assume that any user has access to all product descriptions +func (s *ProductDescriptionService) GetProductDescription(userID uint, productID uint, productShopID uint, productLangID uint) (*model.ProductDescription, error) { + var ProductDescription model.ProductDescription + + fmt.Println(userID, productID, productShopID, productLangID) + + err := s.db. + Table("ps_product_lang"). + Where("id_product = ? AND id_shop = ? AND id_lang = ?", productID, productShopID, productLangID). + First(&ProductDescription).Error + if err != nil { + return nil, fmt.Errorf("database error: %w", err) + } + + return &ProductDescription, nil +} + +// func (s *ProductDescriptionService) GetRepositoriesForUser(userID uint) ([]uint, error) { +// var repoIDs []uint + +// err := s.db. +// Table("customer_repo_accesses"). +// Where("user_id = ?", userID). +// Pluck("repo_id", &repoIDs).Error +// if err != nil { +// return nil, fmt.Errorf("database error: %w", err) +// } + +// return repoIDs, nil +// } + +// func (s *RepoService) UserHasAccessToRepo(userID uint, repoID uint) (bool, error) { +// var repositories []uint +// var err error + +// if repositories, err = s.GetRepositoriesForUser(userID); err != nil { +// return false, err +// } + +// if !slices.Contains(repositories, repoID) { +// return false, responseErrors.ErrInvalidRepoID +// } + +// return true, nil +// } + +// // Extract all repositories assigned to user with specific id +// func (s *RepoService) GetYearsForUser(userID uint, repoID uint) ([]uint, error) { +// if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok { +// return nil, err +// } + +// years, err := s.GetYears(repoID) +// if err != nil { +// return nil, fmt.Errorf("database error: %w", err) +// } + +// return years, nil +// } + +// func (s *RepoService) GetYears(repo uint) ([]uint, error) { + +// var years []uint + +// query := ` +// WITH bounds AS ( +// SELECT +// MIN(to_timestamp(tt.created_unix)) AS min_ts, +// MAX(to_timestamp(tt.created_unix)) AS max_ts +// FROM tracked_time tt +// JOIN issue i ON i.id = tt.issue_id +// WHERE i.repo_id = ? +// AND tt.deleted = false +// ) +// SELECT +// EXTRACT(YEAR FROM y.year_start)::int AS year +// FROM bounds +// CROSS JOIN LATERAL generate_series( +// date_trunc('year', min_ts), +// date_trunc('year', max_ts), +// interval '1 year' +// ) AS y(year_start) +// ORDER BY year +// ` + +// err := db.Get().Raw(query, repo).Find(&years).Error +// if err != nil { +// return nil, err +// } +// return years, nil +// } + +// // Extract all repositories assigned to user with specific id +// func (s *RepoService) GetQuartersForUser(userID uint, repoID uint, year uint) ([]model.QuarterData, error) { +// if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok { +// return nil, err +// } + +// response, err := s.GetQuarters(repoID, year) +// if err != nil { +// return nil, fmt.Errorf("database error: %w", err) +// } + +// return response, nil +// } + +// func (s *RepoService) GetQuarters(repo uint, year uint) ([]model.QuarterData, error) { +// var quarters []model.QuarterData + +// query := ` +// WITH quarters AS ( +// SELECT +// make_date(?::int, 1, 1) + (q * interval '3 months') AS quarter_start, +// q + 1 AS quarter +// FROM generate_series(0, 3) AS q +// ), +// data AS ( +// SELECT +// EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) AS quarter, +// SUM(tt.time) / 3600 AS time +// FROM tracked_time tt +// JOIN issue i ON i.id = tt.issue_id +// JOIN repository r ON i.repo_id = r.id +// WHERE +// EXTRACT(YEAR FROM to_timestamp(tt.created_unix)) = ? +// AND r.id = ? +// AND tt.deleted = false +// GROUP BY EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) +// ) +// SELECT +// COALESCE(d.time, 0) AS time, +// CONCAT(EXTRACT(YEAR FROM q.quarter_start)::int, '_Q', q.quarter) AS quarter +// FROM quarters q +// LEFT JOIN data d ON d.quarter = q.quarter +// ORDER BY q.quarter +// ` + +// err := db.Get(). +// Raw(query, year, year, repo). +// Find(&quarters). +// Error +// if err != nil { +// return nil, err +// } + +// return quarters, nil +// } + +// func (s *RepoService) GetIssuesForUser( +// userID uint, +// repoID uint, +// year uint, +// quarter uint, +// p pagination.Paging, +// ) (*pagination.Found[model.IssueTimeSummary], error) { +// if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok { +// return nil, err +// } + +// return s.GetIssues(repoID, year, quarter, p) +// } + +// func (s *RepoService) GetIssues( +// repoId uint, +// year uint, +// quarter uint, +// p pagination.Paging, +// ) (*pagination.Found[model.IssueTimeSummary], error) { + +// query := db.Get(). +// Table("issue i"). +// Select(` +// i.id AS issue_id, +// i.name AS issue_name, +// to_timestamp(i.created_unix) AS issue_created_at, +// ROUND(SUM(tt.time) / 3600.0, 2) AS total_hours_spent +// `). +// Joins(`JOIN tracked_time tt ON tt.issue_id = i.id`). +// Joins(`JOIN "user" u ON u.id = tt.user_id`). +// Where("i.repo_id = ?", repoId). +// Where(` +// EXTRACT(YEAR FROM to_timestamp(tt.created_unix)) = ? +// AND EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) = ? +// `, year, quarter). +// Group(` +// i.id, +// i.name, +// u.id, +// u.full_name +// `). +// Order("i.created_unix") + +// result, err := pagination.Paginate[model.IssueTimeSummary](p, query) +// if err != nil { +// return nil, err +// } + +// return &result, nil +// } diff --git a/app/service/repoService/repo.go b/app/service/repoService/repo.go deleted file mode 100644 index b301141..0000000 --- a/app/service/repoService/repo.go +++ /dev/null @@ -1,206 +0,0 @@ -package repoService - -import ( - "fmt" - "slices" - - "git.ma-al.com/goc_daniel/b2b/app/db" - "git.ma-al.com/goc_daniel/b2b/app/model" - "git.ma-al.com/goc_daniel/b2b/app/utils/pagination" - "git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors" - "gorm.io/gorm" -) - -// type -type RepoService struct { - db *gorm.DB -} - -func New() *RepoService { - return &RepoService{ - db: db.Get(), - } -} - -func (s *RepoService) GetRepositoriesForUser(userID uint) ([]uint, error) { - var repoIDs []uint - - err := s.db. - Table("customer_repo_accesses"). - Where("user_id = ?", userID). - Pluck("repo_id", &repoIDs).Error - if err != nil { - return nil, fmt.Errorf("database error: %w", err) - } - - return repoIDs, nil -} - -func (s *RepoService) UserHasAccessToRepo(userID uint, repoID uint) (bool, error) { - var repositories []uint - var err error - - if repositories, err = s.GetRepositoriesForUser(userID); err != nil { - return false, err - } - - if !slices.Contains(repositories, repoID) { - return false, responseErrors.ErrInvalidRepoID - } - - return true, nil -} - -// Extract all repositories assigned to user with specific id -func (s *RepoService) GetYearsForUser(userID uint, repoID uint) ([]uint, error) { - if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok { - return nil, err - } - - years, err := s.GetYears(repoID) - if err != nil { - return nil, fmt.Errorf("database error: %w", err) - } - - return years, nil -} - -func (s *RepoService) GetYears(repo uint) ([]uint, error) { - - var years []uint - - query := ` - WITH bounds AS ( - SELECT - MIN(to_timestamp(tt.created_unix)) AS min_ts, - MAX(to_timestamp(tt.created_unix)) AS max_ts - FROM tracked_time tt - JOIN issue i ON i.id = tt.issue_id - WHERE i.repo_id = ? - AND tt.deleted = false - ) - SELECT - EXTRACT(YEAR FROM y.year_start)::int AS year - FROM bounds - CROSS JOIN LATERAL generate_series( - date_trunc('year', min_ts), - date_trunc('year', max_ts), - interval '1 year' - ) AS y(year_start) - ORDER BY year - ` - - err := db.Get().Raw(query, repo).Find(&years).Error - if err != nil { - return nil, err - } - return years, nil -} - -// Extract all repositories assigned to user with specific id -func (s *RepoService) GetQuartersForUser(userID uint, repoID uint, year uint) ([]model.QuarterData, error) { - if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok { - return nil, err - } - - response, err := s.GetQuarters(repoID, year) - if err != nil { - return nil, fmt.Errorf("database error: %w", err) - } - - return response, nil -} - -func (s *RepoService) GetQuarters(repo uint, year uint) ([]model.QuarterData, error) { - var quarters []model.QuarterData - - query := ` - WITH quarters AS ( - SELECT - make_date(?::int, 1, 1) + (q * interval '3 months') AS quarter_start, - q + 1 AS quarter - FROM generate_series(0, 3) AS q - ), - data AS ( - SELECT - EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) AS quarter, - SUM(tt.time) / 3600 AS time - FROM tracked_time tt - JOIN issue i ON i.id = tt.issue_id - JOIN repository r ON i.repo_id = r.id - WHERE - EXTRACT(YEAR FROM to_timestamp(tt.created_unix)) = ? - AND r.id = ? - AND tt.deleted = false - GROUP BY EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) - ) - SELECT - COALESCE(d.time, 0) AS time, - CONCAT(EXTRACT(YEAR FROM q.quarter_start)::int, '_Q', q.quarter) AS quarter - FROM quarters q - LEFT JOIN data d ON d.quarter = q.quarter - ORDER BY q.quarter - ` - - err := db.Get(). - Raw(query, year, year, repo). - Find(&quarters). - Error - if err != nil { - return nil, err - } - - return quarters, nil -} - -func (s *RepoService) GetIssuesForUser( - userID uint, - repoID uint, - year uint, - quarter uint, - p pagination.Paging, -) (*pagination.Found[model.IssueTimeSummary], error) { - if ok, err := s.UserHasAccessToRepo(userID, repoID); !ok { - return nil, err - } - - return s.GetIssues(repoID, year, quarter, p) -} - -func (s *RepoService) GetIssues( - repoId uint, - year uint, - quarter uint, - p pagination.Paging, -) (*pagination.Found[model.IssueTimeSummary], error) { - - query := db.Get(). - Table("issue i"). - Select(` - i.id AS issue_id, - i.name AS issue_name, - to_timestamp(i.created_unix) AS issue_created_at, - ROUND(SUM(tt.time) / 3600.0, 2) AS total_hours_spent - `). - Joins(`JOIN tracked_time tt ON tt.issue_id = i.id`). - Joins(`JOIN "user" u ON u.id = tt.user_id`). - Where("i.repo_id = ?", repoId). - Where(` - EXTRACT(YEAR FROM to_timestamp(tt.created_unix)) = ? - AND EXTRACT(QUARTER FROM to_timestamp(tt.created_unix)) = ? - `, year, quarter). - Group(` - i.id, - i.name, - u.id, - u.full_name - `). - Order("i.created_unix") - - result, err := pagination.Paginate[model.IssueTimeSummary](p, query) - if err != nil { - return nil, err - } - - return &result, nil -} diff --git a/app/utils/responseErrors/response_errors.go b/app/utils/responseErrors/response_errors.go index de1737e..85e6091 100644 --- a/app/utils/responseErrors/response_errors.go +++ b/app/utils/responseErrors/response_errors.go @@ -37,12 +37,8 @@ var ( ErrInvalidVerificationToken = errors.New("invalid verification token") ErrVerificationTokenExpired = errors.New("verification token has expired") - // Typed errors for data extraction - ErrBadRepoIDAttribute = errors.New("invalid repo id attribute") - ErrBadYearAttribute = errors.New("invalid year attribute") - ErrBadQuarterAttribute = errors.New("invalid quarter attribute") - ErrBadPaging = errors.New("invalid paging") - ErrInvalidRepoID = errors.New("repo not accessible") + // Typed errors for product description handler + ErrBadAttribute = errors.New("bad attribute") ) // Error represents an error with HTTP status code @@ -112,16 +108,8 @@ func GetErrorCode(c fiber.Ctx, err error) string { case errors.Is(err, ErrVerificationTokenExpired): return i18n.T_(c, "error.err_verification_token_expired") - case errors.Is(err, ErrBadRepoIDAttribute): - return i18n.T_(c, "error.err_bad_repo_id_attribute") - case errors.Is(err, ErrBadYearAttribute): - return i18n.T_(c, "error.err_bad_year_attribute") - case errors.Is(err, ErrBadQuarterAttribute): - return i18n.T_(c, "error.err_bad_quarter_attribute") - case errors.Is(err, ErrBadPaging): - return i18n.T_(c, "error.err_bad_paging") - case errors.Is(err, ErrInvalidRepoID): - return i18n.T_(c, "error.err_invalid_repo_id") + case errors.Is(err, ErrBadAttribute): + return i18n.T_(c, "error.err_bad_attribute") default: return i18n.T_(c, "error.err_internal_server_error") @@ -152,11 +140,7 @@ func GetErrorStatus(err error) int { errors.Is(err, ErrInvalidVerificationToken), errors.Is(err, ErrVerificationTokenExpired), errors.Is(err, ErrInvalidPassword), - errors.Is(err, ErrBadRepoIDAttribute), - errors.Is(err, ErrBadYearAttribute), - errors.Is(err, ErrBadQuarterAttribute), - errors.Is(err, ErrBadPaging), - errors.Is(err, ErrInvalidRepoID): + errors.Is(err, ErrBadAttribute): return fiber.StatusBadRequest case errors.Is(err, ErrEmailExists): return fiber.StatusConflict diff --git a/tmp/build-errors.log b/tmp/build-errors.log index e0de510..cf4bfce 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file diff --git a/tmp/main b/tmp/main index 5bec8d3..5545b4c 100755 Binary files a/tmp/main and b/tmp/main differ