add view de

This commit is contained in:
2026-06-30 15:34:59 +07:00
parent 840ddcdce9
commit 595aebd8a5
10 changed files with 1325 additions and 10 deletions

View File

@@ -2,6 +2,7 @@ package handlers
import (
"archive/zip"
"encoding/base64"
"fmt"
"io"
"math/rand"
@@ -992,9 +993,128 @@ func examViewMimeType(fileName string) string {
}
func sendExamFileInline(c *fiber.Ctx, filePath, fileName string) error {
data, err := os.ReadFile(filePath)
if err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không đọc được file"})
}
c.Set("Content-Type", examViewMimeType(fileName))
c.Set("Content-Disposition", fmt.Sprintf("inline; filename=%q", fileName))
return c.SendFile(filePath)
return c.Send(data)
}
func encodeExamFileViewPayload(filePath, fileName, title string) (fiber.Map, error) {
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
if fileName == "" {
fileName = filepath.Base(filePath)
}
return fiber.Map{
"title": title,
"fileName": fileName,
"mime": examViewMimeType(fileName),
"data": base64.StdEncoding.EncodeToString(data),
}, nil
}
// GET /api/exam-rooms/:id/papers/:paperId/view — JSON base64, dùng cho xem trên web (không tải file)
func ViewStaffExamPaperHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
roomID, err := parseUintParam(c, "id")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid id"})
}
paperID, err := parseUintParam(c, "paperId")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid paperId"})
}
var paper models.ExamPaper
if err := db.Where("id = ? AND exam_room_id = ?", paperID, roomID).First(&paper).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không tìm thấy gói đề"})
}
payload, err := encodeExamFileViewPayload(paper.PdfPath, "de-thi.pdf", paper.Title)
if err != nil {
return c.Status(404).JSON(fiber.Map{"error": "File PDF đề không tồn tại trên server"})
}
return c.JSON(payload)
}
}
// GET /api/exam-rooms/:id/papers/:paperId/resources/:resId/view
func ViewStaffExamPaperResourceHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
roomID, err := parseUintParam(c, "id")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid id"})
}
paperID, err := parseUintParam(c, "paperId")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid paperId"})
}
resID, err := parseUintParam(c, "resId")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid resId"})
}
var paper models.ExamPaper
if err := db.Where("id = ? AND exam_room_id = ?", paperID, roomID).First(&paper).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không tìm thấy gói đề"})
}
var res models.ExamPaperResource
if err := db.Where("id = ? AND exam_paper_id = ?", resID, paper.ID).First(&res).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "File tài nguyên không tồn tại"})
}
payload, err := encodeExamFileViewPayload(res.FilePath, res.FileName, res.FileName)
if err != nil {
return c.Status(404).JSON(fiber.Map{"error": "File tài nguyên không tồn tại trên server"})
}
return c.JSON(payload)
}
}
// GET /api/exam-rooms/:id/papers/:paperId/download?kind=pdf|resource&fileId=&view=1
func DownloadStaffExamPaperFileHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
roomID, err := parseUintParam(c, "id")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid id"})
}
paperID, err := parseUintParam(c, "paperId")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid paperId"})
}
var paper models.ExamPaper
if err := db.Where("id = ? AND exam_room_id = ?", paperID, roomID).First(&paper).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không tìm thấy gói đề"})
}
inline := c.Query("view") == "1" || c.Query("inline") == "1"
kind := c.Query("kind", "pdf")
if kind == "pdf" {
if _, statErr := os.Stat(paper.PdfPath); statErr != nil {
return c.Status(404).JSON(fiber.Map{"error": "File PDF đề không tồn tại trên server"})
}
name := filepath.Base(paper.PdfPath)
if name == "" || name == "." {
name = "de-thi.pdf"
}
if inline {
return sendExamFileInline(c, paper.PdfPath, name)
}
return c.Download(paper.PdfPath, name)
}
fileID, _ := strconv.ParseUint(c.Query("fileId", "0"), 10, 64)
var res models.ExamPaperResource
if err := db.Where("id = ? AND exam_paper_id = ?", fileID, paper.ID).First(&res).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "File tài nguyên không tồn tại"})
}
if _, statErr := os.Stat(res.FilePath); statErr != nil {
return c.Status(404).JSON(fiber.Map{"error": "File tài nguyên không tồn tại trên server"})
}
if inline && examFileCanViewInline(res.FileName) {
return sendExamFileInline(c, res.FilePath, res.FileName)
}
return c.Download(res.FilePath, res.FileName)
}
}
// POST /api/student/exam/submit — multipart zip

View File

@@ -179,6 +179,9 @@ func main() {
staff.Post("/exam-rooms/:id/papers", handlers.UploadExamPaperHandler(gormDB))
staff.Post("/exam-rooms/:id/papers/:paperId/resources", handlers.UploadExamPaperResourceHandler(gormDB))
staff.Delete("/exam-rooms/:id/papers/:paperId", handlers.DeleteExamPaperHandler(gormDB))
staff.Get("/exam-rooms/:id/papers/:paperId/view", handlers.ViewStaffExamPaperHandler(gormDB))
staff.Get("/exam-rooms/:id/papers/:paperId/resources/:resId/view", handlers.ViewStaffExamPaperResourceHandler(gormDB))
staff.Get("/exam-rooms/:id/papers/:paperId/download", handlers.DownloadStaffExamPaperFileHandler(gormDB))
staff.Post("/exam-rooms/:id/publish", handlers.PublishExamRoomHandler(gormDB))
staff.Post("/exam-rooms/:id/unpublish", handlers.UnpublishExamRoomHandler(gormDB))
staff.Post("/exam-rooms/:id/cancel", handlers.CancelExamRoomHandler(gormDB))