4.15.0: Добавлена принадлежность желаний к проектам
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m33s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m33s
This commit is contained in:
@@ -378,6 +378,8 @@ type WishlistItem struct {
|
||||
UnlockConditions []UnlockConditionDisplay `json:"unlock_conditions,omitempty"`
|
||||
LinkedTask *LinkedTask `json:"linked_task,omitempty"`
|
||||
TasksCount int `json:"tasks_count,omitempty"` // Количество задач для этого желания
|
||||
ProjectID *int `json:"project_id,omitempty"` // ID проекта, к которому принадлежит желание
|
||||
ProjectName *string `json:"project_name,omitempty"` // Название проекта
|
||||
}
|
||||
|
||||
type UnlockConditionDisplay struct {
|
||||
@@ -404,6 +406,7 @@ type WishlistRequest struct {
|
||||
Name string `json:"name"`
|
||||
Price *float64 `json:"price,omitempty"`
|
||||
Link *string `json:"link,omitempty"`
|
||||
ProjectID *int `json:"project_id,omitempty"` // ID проекта, к которому принадлежит желание
|
||||
UnlockConditions []UnlockConditionRequest `json:"unlock_conditions,omitempty"`
|
||||
}
|
||||
|
||||
@@ -9938,6 +9941,8 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
||||
wi.image_path,
|
||||
wi.link,
|
||||
wi.completed,
|
||||
wi.project_id AS item_project_id,
|
||||
wp.name AS item_project_name,
|
||||
wc.id AS condition_id,
|
||||
wc.display_order,
|
||||
wc.task_condition_id,
|
||||
@@ -9950,6 +9955,7 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
||||
sc.required_points,
|
||||
sc.start_date
|
||||
FROM wishlist_items wi
|
||||
LEFT JOIN projects wp ON wi.project_id = wp.id AND wp.deleted = FALSE
|
||||
LEFT JOIN wishlist_conditions wc ON wi.id = wc.wishlist_item_id
|
||||
LEFT JOIN task_conditions tc ON wc.task_condition_id = tc.id
|
||||
LEFT JOIN tasks t ON tc.task_id = t.id AND t.deleted = FALSE
|
||||
@@ -9976,6 +9982,8 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
||||
var price sql.NullFloat64
|
||||
var imagePath, link sql.NullString
|
||||
var completed bool
|
||||
var itemProjectID sql.NullInt64
|
||||
var itemProjectName sql.NullString
|
||||
|
||||
var conditionID, displayOrder sql.NullInt64
|
||||
var taskConditionID, scoreConditionID sql.NullInt64
|
||||
@@ -9989,6 +9997,7 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
||||
|
||||
err := rows.Scan(
|
||||
&itemID, &name, &price, &imagePath, &link, &completed,
|
||||
&itemProjectID, &itemProjectName,
|
||||
&conditionID, &displayOrder,
|
||||
&taskConditionID, &scoreConditionID, &conditionUserID,
|
||||
&taskID, &taskName,
|
||||
@@ -10019,6 +10028,14 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
||||
l := link.String
|
||||
item.Link = &l
|
||||
}
|
||||
if itemProjectID.Valid {
|
||||
projectIDVal := int(itemProjectID.Int64)
|
||||
item.ProjectID = &projectIDVal
|
||||
}
|
||||
if itemProjectName.Valid {
|
||||
projectNameVal := itemProjectName.String
|
||||
item.ProjectName = &projectNameVal
|
||||
}
|
||||
itemsMap[itemID] = item
|
||||
}
|
||||
|
||||
@@ -10681,10 +10698,10 @@ func (a *App) createWishlistHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var wishlistID int
|
||||
err = tx.QueryRow(`
|
||||
INSERT INTO wishlist_items (user_id, author_id, name, price, link, completed, deleted)
|
||||
VALUES ($1, $1, $2, $3, $4, FALSE, FALSE)
|
||||
INSERT INTO wishlist_items (user_id, author_id, name, price, link, project_id, completed, deleted)
|
||||
VALUES ($1, $1, $2, $3, $4, $5, FALSE, FALSE)
|
||||
RETURNING id
|
||||
`, userID, strings.TrimSpace(req.Name), req.Price, req.Link).Scan(&wishlistID)
|
||||
`, userID, strings.TrimSpace(req.Name), req.Price, req.Link, req.ProjectID).Scan(&wishlistID)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error creating wishlist item: %v", err)
|
||||
@@ -10895,6 +10912,8 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
wi.image_path,
|
||||
wi.link,
|
||||
wi.completed,
|
||||
wi.project_id AS item_project_id,
|
||||
wp.name AS item_project_name,
|
||||
wc.id AS condition_id,
|
||||
wc.display_order,
|
||||
wc.task_condition_id,
|
||||
@@ -10907,6 +10926,7 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sc.required_points,
|
||||
sc.start_date
|
||||
FROM wishlist_items wi
|
||||
LEFT JOIN projects wp ON wi.project_id = wp.id AND wp.deleted = FALSE
|
||||
LEFT JOIN wishlist_conditions wc ON wi.id = wc.wishlist_item_id
|
||||
LEFT JOIN task_conditions tc ON wc.task_condition_id = tc.id
|
||||
LEFT JOIN tasks t ON tc.task_id = t.id AND t.deleted = FALSE
|
||||
@@ -10933,6 +10953,8 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var imagePath sql.NullString
|
||||
var link sql.NullString
|
||||
var completed bool
|
||||
var itemProjectID sql.NullInt64
|
||||
var itemProjectName sql.NullString
|
||||
var conditionID sql.NullInt64
|
||||
var displayOrder sql.NullInt64
|
||||
var taskConditionID sql.NullInt64
|
||||
@@ -10946,7 +10968,7 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var startDate sql.NullTime
|
||||
|
||||
err := rows.Scan(
|
||||
&itemID, &name, &price, &imagePath, &link, &completed,
|
||||
&itemID, &name, &price, &imagePath, &link, &completed, &itemProjectID, &itemProjectName,
|
||||
&conditionID, &displayOrder, &taskConditionID, &scoreConditionID, &conditionUserID,
|
||||
&taskID, &taskName, &projectID, &projectName, &requiredPoints, &startDate,
|
||||
)
|
||||
@@ -10976,6 +10998,14 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if link.Valid {
|
||||
item.Link = &link.String
|
||||
}
|
||||
if itemProjectID.Valid {
|
||||
projectIDVal := int(itemProjectID.Int64)
|
||||
item.ProjectID = &projectIDVal
|
||||
}
|
||||
if itemProjectName.Valid {
|
||||
projectNameVal := itemProjectName.String
|
||||
item.ProjectName = &projectNameVal
|
||||
}
|
||||
itemsMap[itemID] = item
|
||||
}
|
||||
|
||||
@@ -11231,9 +11261,9 @@ func (a *App) updateWishlistHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Обновляем желание (не проверяем user_id в WHERE, так как доступ уже проверен выше)
|
||||
_, err = tx.Exec(`
|
||||
UPDATE wishlist_items
|
||||
SET name = $1, price = $2, link = $3, updated_at = NOW()
|
||||
WHERE id = $4
|
||||
`, strings.TrimSpace(req.Name), req.Price, req.Link, itemID)
|
||||
SET name = $1, price = $2, link = $3, project_id = $4, updated_at = NOW()
|
||||
WHERE id = $5
|
||||
`, strings.TrimSpace(req.Name), req.Price, req.Link, req.ProjectID, itemID)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error updating wishlist item: %v", err)
|
||||
@@ -13014,6 +13044,8 @@ func (a *App) getBoardCompletedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
wi.image_path,
|
||||
wi.link,
|
||||
wi.completed,
|
||||
wi.project_id AS item_project_id,
|
||||
wp.name AS item_project_name,
|
||||
wc.id AS condition_id,
|
||||
wc.display_order,
|
||||
wc.task_condition_id,
|
||||
@@ -13027,6 +13059,7 @@ func (a *App) getBoardCompletedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sc.start_date,
|
||||
COALESCE(u.name, u.email) AS user_name
|
||||
FROM wishlist_items wi
|
||||
LEFT JOIN projects wp ON wi.project_id = wp.id AND wp.deleted = FALSE
|
||||
LEFT JOIN wishlist_conditions wc ON wi.id = wc.wishlist_item_id
|
||||
LEFT JOIN task_conditions tc ON wc.task_condition_id = tc.id
|
||||
LEFT JOIN tasks t ON tc.task_id = t.id AND t.deleted = FALSE
|
||||
@@ -13056,6 +13089,8 @@ func (a *App) getBoardCompletedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var imagePath sql.NullString
|
||||
var link sql.NullString
|
||||
var completed bool
|
||||
var itemProjectID sql.NullInt64
|
||||
var itemProjectName sql.NullString
|
||||
var conditionID sql.NullInt64
|
||||
var displayOrder sql.NullInt64
|
||||
var taskConditionID sql.NullInt64
|
||||
@@ -13070,7 +13105,7 @@ func (a *App) getBoardCompletedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var userName sql.NullString
|
||||
|
||||
err := rows.Scan(
|
||||
&itemID, &name, &price, &imagePath, &link, &completed,
|
||||
&itemID, &name, &price, &imagePath, &link, &completed, &itemProjectID, &itemProjectName,
|
||||
&conditionID, &displayOrder, &taskConditionID, &scoreConditionID, &userIDCond,
|
||||
&taskID, &taskName, &projectID, &projectName, &requiredPoints, &startDate, &userName,
|
||||
)
|
||||
@@ -13100,6 +13135,8 @@ func (a *App) getBoardCompletedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if link.Valid {
|
||||
item.Link = &link.String
|
||||
}
|
||||
// Для завершённых желаний не устанавливаем project_id и project_name
|
||||
// Они отображаются отдельно без группировки по проектам
|
||||
itemsMap[itemID] = item
|
||||
}
|
||||
|
||||
@@ -13305,6 +13342,8 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
|
||||
wi.image_path,
|
||||
wi.link,
|
||||
wi.completed,
|
||||
wi.project_id AS item_project_id,
|
||||
wp.name AS item_project_name,
|
||||
COALESCE(wi.author_id, wi.user_id) AS item_owner_id,
|
||||
wc.id AS condition_id,
|
||||
wc.display_order,
|
||||
@@ -13318,6 +13357,7 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
|
||||
sc.required_points,
|
||||
sc.start_date
|
||||
FROM wishlist_items wi
|
||||
LEFT JOIN projects wp ON wi.project_id = wp.id AND wp.deleted = FALSE
|
||||
LEFT JOIN wishlist_conditions wc ON wi.id = wc.wishlist_item_id
|
||||
LEFT JOIN task_conditions tc ON wc.task_condition_id = tc.id
|
||||
LEFT JOIN tasks t ON tc.task_id = t.id AND t.deleted = FALSE
|
||||
@@ -13344,6 +13384,8 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
|
||||
var imagePath sql.NullString
|
||||
var link sql.NullString
|
||||
var completed bool
|
||||
var itemProjectID sql.NullInt64
|
||||
var itemProjectName sql.NullString
|
||||
var itemOwnerID sql.NullInt64
|
||||
var conditionID sql.NullInt64
|
||||
var displayOrder sql.NullInt64
|
||||
@@ -13358,7 +13400,7 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
|
||||
var startDate sql.NullTime
|
||||
|
||||
err := rows.Scan(
|
||||
&itemID, &name, &price, &imagePath, &link, &completed, &itemOwnerID,
|
||||
&itemID, &name, &price, &imagePath, &link, &completed, &itemProjectID, &itemProjectName, &itemOwnerID,
|
||||
&conditionID, &displayOrder, &taskConditionID, &scoreConditionID, &conditionUserID,
|
||||
&taskID, &taskName, &projectID, &projectName, &requiredPoints, &startDate,
|
||||
)
|
||||
@@ -13388,6 +13430,14 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
|
||||
if link.Valid {
|
||||
item.Link = &link.String
|
||||
}
|
||||
if itemProjectID.Valid {
|
||||
projectIDVal := int(itemProjectID.Int64)
|
||||
item.ProjectID = &projectIDVal
|
||||
}
|
||||
if itemProjectName.Valid {
|
||||
projectNameVal := itemProjectName.String
|
||||
item.ProjectName = &projectNameVal
|
||||
}
|
||||
itemsMap[itemID] = item
|
||||
}
|
||||
|
||||
@@ -13657,10 +13707,10 @@ func (a *App) createBoardItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var itemID int
|
||||
err = tx.QueryRow(`
|
||||
INSERT INTO wishlist_items (user_id, board_id, author_id, name, price, link, completed, deleted)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, FALSE, FALSE)
|
||||
INSERT INTO wishlist_items (user_id, board_id, author_id, name, price, link, project_id, completed, deleted)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, FALSE, FALSE)
|
||||
RETURNING id
|
||||
`, ownerID, boardID, userID, strings.TrimSpace(req.Name), req.Price, req.Link).Scan(&itemID)
|
||||
`, ownerID, boardID, userID, strings.TrimSpace(req.Name), req.Price, req.Link, req.ProjectID).Scan(&itemID)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("createBoardItemHandler: Error creating board item: %v", err)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Migration: Remove project_id field from wishlist_items table
|
||||
-- Date: 2026-02-02
|
||||
--
|
||||
-- This migration reverts the addition of project_id field.
|
||||
|
||||
DROP INDEX IF EXISTS idx_wishlist_items_project_id;
|
||||
|
||||
ALTER TABLE wishlist_items
|
||||
DROP COLUMN IF EXISTS project_id;
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Migration: Add project_id field to wishlist_items table
|
||||
-- Date: 2026-02-02
|
||||
--
|
||||
-- This migration adds project_id field to wishlist_items table to allow
|
||||
-- grouping wishlist items by project. The field is nullable, so existing
|
||||
-- items without a project will remain valid.
|
||||
|
||||
ALTER TABLE wishlist_items
|
||||
ADD COLUMN project_id INTEGER REFERENCES projects(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX idx_wishlist_items_project_id ON wishlist_items(project_id);
|
||||
|
||||
COMMENT ON COLUMN wishlist_items.project_id IS 'Project this wishlist item belongs to (optional)';
|
||||
Reference in New Issue
Block a user