feat(projects): 등록한 프로젝트 수정 기능 추가

- 상세(모달/단독) 소유자 영역에 '수정' 버튼 → 등록 모달을 현재 값으로 채워 재사용
- POST /projects/:id/edit 라우트 + db.updateProject(소유자 조건으로 타인 수정 차단)
- 등록/수정 공용 모달을 _project_form_modal.ejs 로 추출(dashboard·project 에서 include)
- pencil 아이콘 추가, modals.js 에 openEdit/openShare 초기화 로직

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 16:55:09 +09:00
parent 459f37608e
commit 7fe3a8fead
8 changed files with 168 additions and 62 deletions

View File

@@ -179,6 +179,36 @@ app.post("/projects", requireAuth, async (req, res) => {
res.redirect("/?toast=" + encodeURIComponent(msg));
});
// --- 프로젝트 수정 (본인) --- 등록과 동일한 필드 파싱. 소유자 조건은 db.updateProject 에서 강제.
app.post("/projects/:id/edit", requireAuth, async (req, res) => {
const { title, description, repo_url, app_url, tags } = req.body;
const back = safeBack(req.body.return_to, "/");
const sep = back.includes("?") ? "&" : "?";
if (!title || !title.trim()) {
return res.redirect(back + sep + "toast=" + encodeURIComponent("제목을 입력해주세요"));
}
const tagArr = String(tags || "")
.split(",")
.map((t) => t.trim().replace(/^#/, ""))
.filter(Boolean)
.slice(0, 5);
const repoUrl = (repo_url || "").trim();
const lang = (req.body.lang || "").trim() || (await fetchMainLang(repoUrl)) || langFromTags(tagArr);
const n = await db.updateProject({
id: req.params.id,
sabun: req.session.user.sabun,
title: title.trim(),
description: (description || "").trim(),
repoUrl,
appUrl: (app_url || "").trim(),
tags: tagArr.join(", "),
isPublic: req.body.is_public !== "0",
lang,
});
const msg = n ? "수정되었습니다" : "수정 권한이 없습니다";
res.redirect(back + sep + "toast=" + encodeURIComponent(msg));
});
// --- 단독 상세 페이지 (모달의 비-JS 폴백 / 공유 링크) ---
app.get("/projects/:id", requireAuth, async (req, res) => {
const me = req.session.user.sabun;