feat(project): 댓글 수정 기능 + 달력 드래그 드롭 수정
- 댓글 수정: PUT /api/comments/{id}(본인·관리자), 모달서 인라인 편집(textarea)
- 달력 드래그 드롭이 안 되던 문제 수정: 드롭 대상을 day 셀 대신 주(week)
단위로 받고 마우스 X 로 날짜 칸을 계산. bar 오버레이/pointer-events 간섭
없이 안정적으로 드롭됨. dragover 에서 dropEffect=move 명시.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -521,6 +521,26 @@ class ProjectStore:
|
||||
).fetchone()
|
||||
return self._serialize(row)
|
||||
|
||||
def update_comment(
|
||||
self, *, comment_id: int, requester: str, is_admin: bool, body: str
|
||||
) -> dict[str, Any]:
|
||||
text = store.norm_str(body)
|
||||
if not text:
|
||||
raise ValueError("댓글 내용이 비었습니다.")
|
||||
with self._pool.connection() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT author_email FROM task_comments WHERE id = %s", (comment_id,)
|
||||
).fetchone()
|
||||
if not row:
|
||||
raise KeyError(comment_id)
|
||||
if not is_admin and row["author_email"] != store.norm_str(requester, lower=True):
|
||||
raise PermissionError("본인 댓글만 수정할 수 있습니다.")
|
||||
out = conn.execute(
|
||||
"UPDATE task_comments SET body = %s WHERE id = %s RETURNING *",
|
||||
(text, comment_id),
|
||||
).fetchone()
|
||||
return self._serialize(out)
|
||||
|
||||
def delete_comment(self, *, comment_id: int, requester: str, is_admin: bool) -> None:
|
||||
with self._pool.connection() as conn:
|
||||
row = conn.execute(
|
||||
|
||||
@@ -813,6 +813,28 @@ async def api_add_comment(
|
||||
return JSONResponse({"comment": comment}, status_code=201)
|
||||
|
||||
|
||||
@router.put("/api/comments/{comment_id}")
|
||||
async def api_update_comment(
|
||||
request: Request, comment_id: int, payload: dict[str, Any] = Body(...)
|
||||
) -> JSONResponse:
|
||||
from app.store import is_admin # noqa: WPS433
|
||||
|
||||
user = _require_user(request)
|
||||
st = _db_or_503(request)
|
||||
try:
|
||||
comment = st.update_comment(
|
||||
comment_id=comment_id, requester=user["email"],
|
||||
is_admin=is_admin(user), body=payload.get("body", ""),
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="댓글을 찾을 수 없습니다.")
|
||||
except PermissionError as exc:
|
||||
raise HTTPException(status_code=403, detail=str(exc))
|
||||
return JSONResponse({"comment": comment})
|
||||
|
||||
|
||||
@router.delete("/api/comments/{comment_id}")
|
||||
async def api_delete_comment(request: Request, comment_id: int) -> JSONResponse:
|
||||
from app.store import is_admin # noqa: WPS433
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625f" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625g" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="/static/project.js?v=20260625f" defer></script>
|
||||
<script src="/static/project.js?v=20260625g" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625f" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625g" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -101,5 +101,5 @@
|
||||
<script>
|
||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||
</script>
|
||||
<script src="/static/project.js?v=20260625f" defer></script>
|
||||
<script src="/static/project.js?v=20260625g" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625f" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625g" />
|
||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
<!-- 타임라인 vis-timeline — self-host -->
|
||||
@@ -256,5 +256,5 @@
|
||||
</script>
|
||||
|
||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||
<script src="/static/project.js?v=20260625f" defer></script>
|
||||
<script src="/static/project.js?v=20260625g" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user