feat: add problem support
This commit is contained in:
parent
8d01144d8b
commit
529b41332c
32
internal/api/problem/handler.go
Normal file
32
internal/api/problem/handler.go
Normal file
@ -0,0 +1,32 @@
|
||||
package problem
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/service/problem"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
Update(c *gin.Context)
|
||||
Search(c *gin.Context)
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
log *zap.Logger
|
||||
problemService problem.Service
|
||||
jwtService global.JwtService
|
||||
}
|
||||
|
||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
||||
app := &handler{
|
||||
log: g.Log,
|
||||
problemService: problem.NewService(g),
|
||||
jwtService: g.Jwt,
|
||||
}
|
||||
|
||||
group.POST("/search", app.Search)
|
||||
group.POST("/update", app.jwtService.Handler(), app.Update)
|
||||
}
|
44
internal/api/problem/search.go
Normal file
44
internal/api/problem/search.go
Normal file
@ -0,0 +1,44 @@
|
||||
package problem
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type searchRequest struct {
|
||||
Pid uint `form:"pid"`
|
||||
Search string `form:"search"`
|
||||
}
|
||||
|
||||
// Search
|
||||
// @Summary get detail of a problem
|
||||
// @Description get detail of a problem
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param pid formData int false "problem id"
|
||||
// @Param search formData string false "search problem"
|
||||
// @Response 200 {object} e.Response "problem info"
|
||||
// @Router /v1/problem/search [post]
|
||||
func (h *handler) Search(c *gin.Context) {
|
||||
req := new(searchRequest)
|
||||
|
||||
if err := c.ShouldBind(req); err != nil {
|
||||
e.Pong(c, e.InvalidParameter, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.Pid == 0 && req.Search == "" {
|
||||
e.Pong(c, e.InvalidParameter, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Pid != 0 {
|
||||
problem, status := h.problemService.Query(req.Pid)
|
||||
e.Pong(c, status, problem)
|
||||
return
|
||||
} else {
|
||||
problem, status := h.problemService.QueryFuzz(req.Search)
|
||||
e.Pong(c, status, problem)
|
||||
return
|
||||
}
|
||||
}
|
81
internal/api/problem/update.go
Normal file
81
internal/api/problem/update.go
Normal file
@ -0,0 +1,81 @@
|
||||
package problem
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type updateRequest struct {
|
||||
Pid uint `form:"pid"`
|
||||
Title string `form:"title" binding:"required"`
|
||||
Content string `form:"content" binding:"required"`
|
||||
TimeLimit uint `form:"time_limit" binding:"required"`
|
||||
MemoryLimit uint `form:"memory_limit" binding:"required"`
|
||||
IsEnabled bool `form:"is_enabled"`
|
||||
}
|
||||
|
||||
// Update
|
||||
// @Summary create or update a problem
|
||||
// @Description create or update a problem
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param pid formData int false "problem id, 0 for create"
|
||||
// @Param title formData string true "title"
|
||||
// @Param content formData string true "content"
|
||||
// @Param time_limit formData int true "time limit in ms"
|
||||
// @Param memory_limit formData int true "memory limit in kb"
|
||||
// @Param is_enabled formData bool false "is enabled"
|
||||
// @Response 200 {object} e.Response "problem info without provider information"
|
||||
// @Security Authentication
|
||||
// @Router /v1/problem/update [post]
|
||||
func (h *handler) Update(c *gin.Context) {
|
||||
claim, exist := c.Get("claim")
|
||||
if !exist {
|
||||
e.Pong(c, e.UserUnauthenticated, nil)
|
||||
return
|
||||
}
|
||||
|
||||
uid := claim.(*global.Claim).UID
|
||||
role := claim.(*global.Claim).Role
|
||||
if role < model.RoleAdmin {
|
||||
e.Pong(c, e.UserUnauthorized, nil)
|
||||
return
|
||||
}
|
||||
|
||||
req := new(updateRequest)
|
||||
if err := c.ShouldBind(req); err != nil {
|
||||
e.Pong(c, e.InvalidParameter, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
problem := &model.Problem{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
TimeLimit: req.TimeLimit,
|
||||
MemoryLimit: req.MemoryLimit,
|
||||
IsEnabled: req.IsEnabled,
|
||||
}
|
||||
|
||||
if req.Pid == 0 {
|
||||
problem, status := h.problemService.Create(uid, problem)
|
||||
e.Pong(c, status, problem)
|
||||
return
|
||||
} else {
|
||||
inDb, status := h.problemService.Query(req.Pid)
|
||||
if status != e.Success && status != e.ProblemNotAvailable {
|
||||
e.Pong(c, status, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if inDb.ProviderID != uid {
|
||||
e.Pong(c, e.UserUnauthorized, nil)
|
||||
return
|
||||
}
|
||||
|
||||
problem, status := h.problemService.Update(req.Pid, problem)
|
||||
e.Pong(c, status, problem)
|
||||
return
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ type handler struct {
|
||||
func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
||||
app := &handler{
|
||||
log: g.Log,
|
||||
userService: user.NewUserService(g),
|
||||
userService: user.NewService(g),
|
||||
jwtService: g.Jwt,
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ type profileRequest struct {
|
||||
// @Description fetch user profile
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Param uid formData string false "user id"
|
||||
// @Param uid formData int false "user id"
|
||||
// @Response 200 {object} e.Response "user info"
|
||||
// @Security Authentication
|
||||
// @Router /v1/user/profile [post]
|
||||
|
@ -26,6 +26,7 @@ const (
|
||||
UserDisabled Status = 305
|
||||
|
||||
ProblemNotFound Status = 500
|
||||
ProblemNotAvailable Status = 501
|
||||
)
|
||||
|
||||
var msgText = map[Status]string{
|
||||
@ -54,4 +55,5 @@ var msgText = map[Status]string{
|
||||
UserDisabled: "User Disabled",
|
||||
|
||||
ProblemNotFound: "Problem Not Found",
|
||||
ProblemNotAvailable: "Problem Not Available",
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ package model
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Problem struct {
|
||||
gorm.Model `json:"-"`
|
||||
gorm.Model `json:"meta"`
|
||||
Title string `json:"title" gorm:"not null"`
|
||||
Content string `json:"content" gorm:"not null"`
|
||||
TimeLimit uint `json:"time_limit" gorm:"not null"`
|
||||
MemoryLimit uint `json:"memory_limit" gorm:"not null"`
|
||||
ProviderID uint `json:"provider_id" gorm:"not null;index"`
|
||||
Provider User `json:"provider" gorm:"foreignKey:ProviderID"`
|
||||
Provider User `json:"-" gorm:"foreignKey:ProviderID"`
|
||||
IsEnabled bool `json:"is_enabled" gorm:"not null;index"`
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package router
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/api/debug"
|
||||
"github.com/WHUPRJ/woj-server/internal/api/problem"
|
||||
"github.com/WHUPRJ/woj-server/internal/api/user"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -23,4 +24,5 @@ func setupApi(g *global.Global, root *gin.RouterGroup) {
|
||||
var endpoints = []global.EndpointInfo{
|
||||
{Version: "", Path: "/debug", Register: debug.RouteRegister},
|
||||
{Version: "/v1", Path: "/user", Register: user.RouteRegister},
|
||||
{Version: "/v1", Path: "/problem", Register: problem.RouteRegister},
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"github.com/WHUPRJ/woj-server/pkg/utils"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
@ -19,5 +20,5 @@ func (s *service) Query(problemId uint) (*model.Problem, e.Status) {
|
||||
return nil, e.DatabaseError
|
||||
}
|
||||
|
||||
return problem, e.Success
|
||||
return problem, utils.If(problem.IsEnabled, e.Success, e.ProblemNotAvailable).(e.Status)
|
||||
}
|
||||
|
@ -5,14 +5,16 @@ import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func (s *service) QueryFuzz(search string) ([]*model.Problem, e.Status) {
|
||||
var problems []*model.Problem
|
||||
|
||||
err := s.db.
|
||||
Where("title LIKE ?", "%"+search+"%").
|
||||
Or("content LIKE ?", "%"+search+"%").
|
||||
err := s.db.Preload(clause.Associations).
|
||||
Where("is_enabled = true").
|
||||
Where(s.db.Where("title LIKE ?", "%"+search+"%").
|
||||
Or("content LIKE ?", "%"+search+"%")).
|
||||
Find(&problems).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, e.ProblemNotFound
|
||||
|
@ -12,6 +12,7 @@ var _ Service = (*service)(nil)
|
||||
|
||||
type Service interface {
|
||||
Create(uint, *model.Problem) (*model.Problem, e.Status)
|
||||
Update(uint, *model.Problem) (*model.Problem, e.Status)
|
||||
Query(uint) (*model.Problem, e.Status)
|
||||
QueryFuzz(string) ([]*model.Problem, e.Status)
|
||||
}
|
||||
@ -21,7 +22,7 @@ type service struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewProblemService(g *global.Global) Service {
|
||||
func NewService(g *global.Global) Service {
|
||||
return &service{
|
||||
log: g.Log,
|
||||
db: g.Db.Get().(*gorm.DB),
|
||||
|
20
internal/service/problem/update.go
Normal file
20
internal/service/problem/update.go
Normal file
@ -0,0 +1,20 @@
|
||||
package problem
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func (s *service) Update(pid uint, problem *model.Problem) (*model.Problem, e.Status) {
|
||||
if err := s.db.Clauses(clause.Returning{}).Model(problem).
|
||||
Where("ID = (?)", pid).
|
||||
Select("Title", "Content", "TimeLimit", "MemoryLimit", "IsEnabled").
|
||||
Updates(problem).Error; err != nil {
|
||||
s.log.Debug("update problem error", zap.Error(err), zap.Any("problem", problem))
|
||||
return nil, e.DatabaseError
|
||||
}
|
||||
|
||||
return problem, e.Success
|
||||
}
|
@ -24,7 +24,7 @@ type service struct {
|
||||
redis *redis.Client
|
||||
}
|
||||
|
||||
func NewUserService(g *global.Global) Service {
|
||||
func NewService(g *global.Global) Service {
|
||||
return &service{
|
||||
log: g.Log,
|
||||
db: g.Db.Get().(*gorm.DB),
|
||||
|
Loading…
Reference in New Issue
Block a user