fix up git

This commit is contained in:
2026-06-30 15:06:12 +07:00
parent 11e5a76977
commit 38e22b3390
13 changed files with 883 additions and 18 deletions

View File

@@ -231,6 +231,10 @@ func bundleSubmissionZips(rows []submissionRow, destZipPath string) (warnings []
}
func collectSubmissionZipFiles(rows []submissionRow) (files []gitPathFile, warnings []string) {
return collectSubmissionZipFilesWithPrefix(rows, true)
}
func collectSubmissionZipFilesWithPrefix(rows []submissionRow, useStudentFolder bool) (files []gitPathFile, warnings []string) {
byPath := map[string]gitPathFile{}
usedFolders := map[string]int{}
for _, row := range rows {
@@ -238,13 +242,17 @@ func collectSubmissionZipFiles(rows []submissionRow) (files []gitPathFile, warni
warnings = append(warnings, fmt.Sprintf("bài SV %d: không tìm thấy file", row.StudentRkID))
continue
}
folder := studentSubmissionFolder(row.StudentCode, row.FullName)
if n := usedFolders[folder]; n > 0 {
folder = fmt.Sprintf("%s_%d", folder, n+1)
prefix := ""
if useStudentFolder {
folder := studentSubmissionFolder(row.StudentCode, row.FullName)
if n := usedFolders[folder]; n > 0 {
folder = fmt.Sprintf("%s_%d", folder, n+1)
}
usedFolders[folder]++
prefix = folder
}
usedFolders[folder]++
skipped, err := copySubmissionZipEntries(row.FilePath, folder, func(destPath string, open func() (io.ReadCloser, error), size int64) error {
skipped, err := copySubmissionZipEntries(row.FilePath, prefix, func(destPath string, open func() (io.ReadCloser, error), size int64) error {
if size > githubBlobMaxBytes {
warnings = append(warnings, destPath+": file quá lớn (>100MB), bỏ qua")
return nil
@@ -262,11 +270,11 @@ func collectSubmissionZipFiles(rows []submissionRow) (files []gitPathFile, warni
return nil
})
if err != nil {
warnings = append(warnings, folder+": "+err.Error())
warnings = append(warnings, prefix+": "+err.Error())
continue
}
for _, s := range skipped {
warnings = append(warnings, folder+"/"+s)
warnings = append(warnings, prefix+"/"+s)
}
}
files = make([]gitPathFile, 0, len(byPath))
@@ -453,6 +461,8 @@ func PublishExamSubmissionsGitHandler(db *gorm.DB) fiber.Handler {
room.GitPublishURL = viewURL
_ = db.Save(&room).Error
roomIDCopy := roomID
recordStaffGitHubRepo(db, staffID, owner, repo, repoHTML, models.GitPublishModeRoom, room.Name, &roomIDCopy, nil)
msg := fmt.Sprintf("Đã đẩy %d bài lên GitHub — mỗi sinh viên một folder.", len(rows))
if len(allWarn) > 0 {
@@ -471,3 +481,112 @@ func PublishExamSubmissionsGitHandler(db *gorm.DB) fiber.Handler {
})
}
}
// POST /api/exam-rooms/:id/submissions/publish-git-students — mỗi sinh viên một repo GitHub riêng
func PublishExamSubmissionsGitPerStudentHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
staffID := middleware.StaffIDFromCtx(c)
if staffID == 0 {
return c.Status(401).JSON(fiber.Map{"error": "Unauthorized"})
}
token, ghLogin, err := loadStaffGitHubToken(db, staffID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.Status(401).JSON(fiber.Map{
"error": "Chưa kết nối GitHub. Vào Tài khoản của tôi → Kết nối GitHub.",
"needsGitHubOAuth": true,
})
}
return c.Status(500).JSON(fiber.Map{"error": "Không đọc được token GitHub"})
}
roomID, err := parseUintParam(c, "id")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid id"})
}
var room models.ExamRoom
if err := db.First(&room, roomID).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không tìm thấy phòng thi"})
}
rows, err := loadExamSubmissionRows(db, roomID)
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
if len(rows) == 0 {
return c.Status(400).JSON(fiber.Map{"error": "Chưa có bài nộp"})
}
branch := "main"
published := 0
var allWarn []string
var repoURLs []string
type studentRepo struct {
StudentRkID int64 `json:"studentRkId"`
StudentCode string `json:"studentCode"`
FullName string `json:"fullName"`
URL string `json:"url"`
}
studentRepos := make([]studentRepo, 0, len(rows))
for _, row := range rows {
files, unpackWarn := collectSubmissionZipFilesWithPrefix([]submissionRow{row}, false)
allWarn = append(allWarn, unpackWarn...)
if len(files) == 0 {
allWarn = append(allWarn, fmt.Sprintf("%s: không có file để đẩy", studentSubmissionFolder(row.StudentCode, row.FullName)))
continue
}
repoName, repoHTML, err := githubEnsureRepoForStudent(token, ghLogin, &room, &row)
if err != nil {
allWarn = append(allWarn, row.StudentCode+": "+err.Error())
continue
}
label := studentSubmissionFolder(row.StudentCode, row.FullName)
commitMsg := fmt.Sprintf("Simple Care: bài nộp %s — %s", label, room.Name)
viewURL, pushWarn, err := githubPushFiles(token, ghLogin, repoName, branch, files, commitMsg)
allWarn = append(allWarn, pushWarn...)
if err != nil {
allWarn = append(allWarn, label+": "+err.Error())
continue
}
_ = db.Model(&models.ExamSubmission{}).Where("id = ?", row.ID).
Updates(map[string]any{"git_repo_url": repoHTML, "git_publish_url": viewURL}).Error
subID := row.ID
roomIDCopy := roomID
recordStaffGitHubRepo(db, staffID, ghLogin, repoName, repoHTML, models.GitPublishModeStudent, label, &roomIDCopy, &subID)
published++
repoURLs = append(repoURLs, viewURL)
studentRepos = append(studentRepos, studentRepo{
StudentRkID: row.StudentRkID,
StudentCode: row.StudentCode,
FullName: row.FullName,
URL: viewURL,
})
}
if published == 0 {
return c.Status(502).JSON(fiber.Map{
"error": "Không đẩy được repo nào",
"warnings": allWarn,
})
}
msg := fmt.Sprintf("Đã tạo %d repo GitHub — mỗi sinh viên một repo.", published)
if len(allWarn) > 0 {
msg += fmt.Sprintf(" (%d cảnh báo)", len(allWarn))
}
openURL := ""
if len(repoURLs) > 0 {
openURL = repoURLs[0]
}
return c.JSON(fiber.Map{
"ok": true,
"published": published,
"studentRepos": studentRepos,
"openUrl": openURL,
"warnings": allWarn,
"message": msg,
})
}
}