Исправление дублирования чужих целей в wishlist и защита от редактирования
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m16s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m16s
This commit is contained in:
@@ -9498,6 +9498,14 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
|||||||
DisplayOrder: int(displayOrder.Int64),
|
DisplayOrder: int(displayOrder.Int64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Заполняем UserID для условия
|
||||||
|
if conditionUserID.Valid {
|
||||||
|
conditionOwnerID := int(conditionUserID.Int64)
|
||||||
|
condition.UserID = &conditionOwnerID
|
||||||
|
} else {
|
||||||
|
condition.UserID = &userID
|
||||||
|
}
|
||||||
|
|
||||||
if taskConditionID.Valid {
|
if taskConditionID.Valid {
|
||||||
condition.Type = "task_completion"
|
condition.Type = "task_completion"
|
||||||
if taskName.Valid {
|
if taskName.Valid {
|
||||||
@@ -9824,12 +9832,21 @@ func (a *App) saveWishlistConditions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Определяем user_id для условия:
|
// Определяем user_id для условия:
|
||||||
// - Если условие имеет id и это условие существовало - используем его оригинальный user_id
|
// - Если условие имеет id и это условие существовало - проверяем, принадлежит ли оно текущему пользователю
|
||||||
|
// - Если условие принадлежит другому пользователю - пропускаем (не сохраняем)
|
||||||
|
// - Если условие имеет id, но не существовало (например, было только что добавлено) - игнорируем
|
||||||
// - Иначе - используем userID текущего пользователя
|
// - Иначе - используем userID текущего пользователя
|
||||||
conditionUserID := userID
|
conditionUserID := userID
|
||||||
if condition.ID != nil {
|
if condition.ID != nil {
|
||||||
if originalUserID, exists := existingConditions[*condition.ID]; exists {
|
if originalUserID, exists := existingConditions[*condition.ID]; exists {
|
||||||
|
// Если условие принадлежит другому пользователю - пропускаем (не сохраняем)
|
||||||
|
if originalUserID != userID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
conditionUserID = originalUserID
|
conditionUserID = originalUserID
|
||||||
|
} else {
|
||||||
|
// Условие имеет id, но не существует в базе - пропускаем (не сохраняем)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10258,6 +10275,9 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
conditionOwnerID := itemOwnerID
|
conditionOwnerID := itemOwnerID
|
||||||
if conditionUserID.Valid {
|
if conditionUserID.Valid {
|
||||||
conditionOwnerID = int(conditionUserID.Int64)
|
conditionOwnerID = int(conditionUserID.Int64)
|
||||||
|
condition.UserID = &conditionOwnerID
|
||||||
|
} else {
|
||||||
|
condition.UserID = &itemOwnerID
|
||||||
}
|
}
|
||||||
|
|
||||||
if taskConditionID.Valid {
|
if taskConditionID.Valid {
|
||||||
@@ -10575,6 +10595,9 @@ func (a *App) updateWishlistHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
conditionOwnerID := itemOwnerID
|
conditionOwnerID := itemOwnerID
|
||||||
if conditionUserID.Valid {
|
if conditionUserID.Valid {
|
||||||
conditionOwnerID = int(conditionUserID.Int64)
|
conditionOwnerID = int(conditionUserID.Int64)
|
||||||
|
condition.UserID = &conditionOwnerID
|
||||||
|
} else {
|
||||||
|
condition.UserID = &itemOwnerID
|
||||||
}
|
}
|
||||||
|
|
||||||
if taskConditionID.Valid {
|
if taskConditionID.Valid {
|
||||||
@@ -12387,6 +12410,10 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
|
|||||||
conditionOwnerID := int(itemOwnerID.Int64)
|
conditionOwnerID := int(itemOwnerID.Int64)
|
||||||
if conditionUserID.Valid {
|
if conditionUserID.Valid {
|
||||||
conditionOwnerID = int(conditionUserID.Int64)
|
conditionOwnerID = int(conditionUserID.Int64)
|
||||||
|
condition.UserID = &conditionOwnerID
|
||||||
|
} else {
|
||||||
|
itemOwnerIDVal := int(itemOwnerID.Int64)
|
||||||
|
condition.UserID = &itemOwnerIDVal
|
||||||
}
|
}
|
||||||
|
|
||||||
if taskConditionID.Valid {
|
if taskConditionID.Valid {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "3.14.6",
|
"version": "3.14.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -215,6 +215,16 @@
|
|||||||
color: #3498db;
|
color: #3498db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.condition-item-text.condition-item-other-user {
|
||||||
|
color: #95a5a6;
|
||||||
|
font-style: italic;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condition-item-text.condition-item-other-user:hover {
|
||||||
|
color: #95a5a6;
|
||||||
|
}
|
||||||
|
|
||||||
.remove-condition-button {
|
.remove-condition-button {
|
||||||
background: #e74c3c;
|
background: #e74c3c;
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const PROJECTS_API_URL = '/projects'
|
|||||||
const WISHLIST_FORM_STATE_KEY = 'wishlistFormPendingState'
|
const WISHLIST_FORM_STATE_KEY = 'wishlistFormPendingState'
|
||||||
|
|
||||||
function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, boardId }) {
|
function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, boardId }) {
|
||||||
const { authFetch } = useAuth()
|
const { authFetch, user } = useAuth()
|
||||||
const [name, setName] = useState('')
|
const [name, setName] = useState('')
|
||||||
const [price, setPrice] = useState('')
|
const [price, setPrice] = useState('')
|
||||||
const [link, setLink] = useState('')
|
const [link, setLink] = useState('')
|
||||||
@@ -97,6 +97,7 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
|
|||||||
required_points: cond.required_points || null,
|
required_points: cond.required_points || null,
|
||||||
start_date: cond.start_date || null,
|
start_date: cond.start_date || null,
|
||||||
display_order: idx,
|
display_order: idx,
|
||||||
|
user_id: cond.user_id || null,
|
||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
setUnlockConditions([])
|
setUnlockConditions([])
|
||||||
@@ -251,6 +252,7 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
|
|||||||
required_points: cond.required_points || null,
|
required_points: cond.required_points || null,
|
||||||
start_date: cond.start_date || null,
|
start_date: cond.start_date || null,
|
||||||
display_order: idx,
|
display_order: idx,
|
||||||
|
user_id: cond.user_id || null,
|
||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
setUnlockConditions([])
|
setUnlockConditions([])
|
||||||
@@ -469,6 +471,12 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleEditCondition = (index) => {
|
const handleEditCondition = (index) => {
|
||||||
|
const condition = unlockConditions[index]
|
||||||
|
// Проверяем, что условие принадлежит текущему пользователю
|
||||||
|
if (condition.user_id && condition.user_id !== user?.id) {
|
||||||
|
setToastMessage({ text: 'Нельзя редактировать чужие цели', type: 'error' })
|
||||||
|
return
|
||||||
|
}
|
||||||
setEditingConditionIndex(index)
|
setEditingConditionIndex(index)
|
||||||
setShowConditionForm(true)
|
setShowConditionForm(true)
|
||||||
}
|
}
|
||||||
@@ -493,6 +501,12 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleRemoveCondition = (index) => {
|
const handleRemoveCondition = (index) => {
|
||||||
|
const condition = unlockConditions[index]
|
||||||
|
// Проверяем, что условие принадлежит текущему пользователю
|
||||||
|
if (condition.user_id && condition.user_id !== user?.id) {
|
||||||
|
setToastMessage({ text: 'Нельзя удалять чужие цели', type: 'error' })
|
||||||
|
return
|
||||||
|
}
|
||||||
setUnlockConditions(unlockConditions.filter((_, i) => i !== index))
|
setUnlockConditions(unlockConditions.filter((_, i) => i !== index))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,16 +797,21 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
|
|||||||
<label>Цель</label>
|
<label>Цель</label>
|
||||||
{unlockConditions.length > 0 && (
|
{unlockConditions.length > 0 && (
|
||||||
<div className="conditions-list">
|
<div className="conditions-list">
|
||||||
{unlockConditions.map((cond, idx) => (
|
{unlockConditions.map((cond, idx) => {
|
||||||
|
const isOwnCondition = !cond.user_id || cond.user_id === user?.id
|
||||||
|
return (
|
||||||
<div key={idx} className="condition-item">
|
<div key={idx} className="condition-item">
|
||||||
<span
|
<span
|
||||||
className="condition-item-text"
|
className={`condition-item-text ${!isOwnCondition ? 'condition-item-other-user' : ''}`}
|
||||||
onClick={() => handleEditCondition(idx)}
|
onClick={() => isOwnCondition && handleEditCondition(idx)}
|
||||||
|
style={{ cursor: isOwnCondition ? 'pointer' : 'default' }}
|
||||||
|
title={!isOwnCondition ? 'Чужая цель - нельзя редактировать' : ''}
|
||||||
>
|
>
|
||||||
{cond.type === 'task_completion'
|
{cond.type === 'task_completion'
|
||||||
? `Задача: ${tasks.find(t => t.id === cond.task_id)?.name || 'Не выбрана'}`
|
? `Задача: ${tasks.find(t => t.id === cond.task_id)?.name || 'Не выбрана'}`
|
||||||
: `Баллы: ${cond.required_points} в ${projects.find(p => p.project_id === cond.project_id)?.project_name || cond.project_name || 'Не выбран'}${cond.start_date ? ` с ${new Date(cond.start_date + 'T00:00:00').toLocaleDateString('ru-RU')}` : ' за всё время'}`}
|
: `Баллы: ${cond.required_points} в ${projects.find(p => p.project_id === cond.project_id)?.project_name || cond.project_name || 'Не выбран'}${cond.start_date ? ` с ${new Date(cond.start_date + 'T00:00:00').toLocaleDateString('ru-RU')}` : ' за всё время'}`}
|
||||||
</span>
|
</span>
|
||||||
|
{isOwnCondition && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveCondition(idx)}
|
onClick={() => handleRemoveCondition(idx)}
|
||||||
@@ -800,8 +819,10 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
|
|||||||
>
|
>
|
||||||
✕
|
✕
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user