feat: add tags support

This commit is contained in:
Paul Pan 2023-12-27 21:30:52 +08:00
parent f51f4fd3eb
commit 8efd032ad3
Signed by: Paul
GPG Key ID: D639BDF5BA578AF4
10 changed files with 34 additions and 150 deletions

View File

@ -7,7 +7,8 @@ import (
) )
type searchRequest struct { type searchRequest struct {
Search string `form:"search" json:"search"` Keyword string `form:"keyword" json:"keyword"`
Tag string `form:"tag" json:"tag"`
} }
// Search // Search
@ -27,13 +28,13 @@ func (h *handler) Search(c *gin.Context) {
} }
// TODO: pagination // TODO: pagination
if req.Search == "" { if req.Keyword == "" {
// TODO: query without LIKE // TODO: query without LIKE
problems, status := h.problemService.QueryFuzz(req.Search, true, true) problems, status := h.problemService.QueryFuzz(req.Keyword, req.Tag, true, true)
e.Pong(c, status, problems) e.Pong(c, status, problems)
return return
} else { } else {
problems, status := h.problemService.QueryFuzz(req.Search, true, true) problems, status := h.problemService.QueryFuzz(req.Keyword, req.Tag, true, true)
e.Pong(c, status, problems) e.Pong(c, status, problems)
return return
} }

View File

@ -6,12 +6,14 @@ import (
"git.0x7f.app/WOJ/woj-server/internal/service/problem" "git.0x7f.app/WOJ/woj-server/internal/service/problem"
"git.0x7f.app/WOJ/woj-server/pkg/utils" "git.0x7f.app/WOJ/woj-server/pkg/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jackc/pgtype"
) )
type updateRequest struct { type updateRequest struct {
Pid uint `form:"pid" json:"pid"` Pid uint `form:"pid" json:"pid"`
Title string `form:"title" json:"title"` Title string `form:"title" json:"title"`
Statement string `form:"statement" json:"statement"` Statement string `form:"statement" json:"statement"`
Tags []string `form:"tags" json:"tags"`
IsEnabled bool `form:"is_enabled" json:"is_enabled"` IsEnabled bool `form:"is_enabled" json:"is_enabled"`
} }
@ -24,6 +26,7 @@ type updateRequest struct {
// @Param pid formData int false "problem id, 0 for create" // @Param pid formData int false "problem id, 0 for create"
// @Param title formData string false "title" // @Param title formData string false "title"
// @Param statement formData string false "statement" // @Param statement formData string false "statement"
// @Param tags formData []string false "tags"
// @Param is_enabled formData bool false "is enabled" // @Param is_enabled formData bool false "is enabled"
// @Response 200 {object} e.Response[model.Problem] "problem info without provider information" // @Response 200 {object} e.Response[model.Problem] "problem info without provider information"
// @Security Authentication // @Security Authentication
@ -60,6 +63,7 @@ func (h *handler) Update(c *gin.Context) {
createData := &problem.CreateData{ createData := &problem.CreateData{
Title: req.Title, Title: req.Title,
Statement: req.Statement, Statement: req.Statement,
Tags: req.Tags,
ProviderID: uid, ProviderID: uid,
IsEnabled: false, IsEnabled: false,
} }
@ -83,6 +87,11 @@ func (h *handler) Update(c *gin.Context) {
// update problem // update problem
p.Title = utils.If(req.Title != "", req.Title, p.Title) p.Title = utils.If(req.Title != "", req.Title, p.Title)
p.Statement = utils.If(req.Statement != "", req.Statement, p.Statement) p.Statement = utils.If(req.Statement != "", req.Statement, p.Statement)
if len(req.Tags) != 0 {
tags := pgtype.TextArray{}
_ = tags.Set(req.Tags)
p.Tags = tags
}
p.IsEnabled = req.IsEnabled p.IsEnabled = req.IsEnabled
p, status = h.problemService.Update(p) p, status = h.problemService.Update(p)

View File

@ -9,6 +9,7 @@ type Problem struct {
gorm.Model `json:"meta"` gorm.Model `json:"meta"`
Title string `json:"title" gorm:"not null"` Title string `json:"title" gorm:"not null"`
Statement string `json:"statement" gorm:"not null"` Statement string `json:"statement" gorm:"not null"`
Tags pgtype.TextArray `json:"tags" gorm:"type:text[]"`
ProviderID uint `json:"-" gorm:"not null;index"` ProviderID uint `json:"-" gorm:"not null;index"`
Provider User `json:"provider" gorm:"foreignKey:ProviderID"` Provider User `json:"provider" gorm:"foreignKey:ProviderID"`
IsEnabled bool `json:"is_enabled" gorm:"not null;index"` IsEnabled bool `json:"is_enabled" gorm:"not null;index"`

View File

@ -3,20 +3,25 @@ package problem
import ( import (
"git.0x7f.app/WOJ/woj-server/internal/e" "git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/internal/model" "git.0x7f.app/WOJ/woj-server/internal/model"
"github.com/jackc/pgtype"
"go.uber.org/zap" "go.uber.org/zap"
) )
type CreateData struct { type CreateData struct {
Title string Title string
Statement string Statement string
Tags []string
ProviderID uint ProviderID uint
IsEnabled bool IsEnabled bool
} }
func (s *service) Create(data *CreateData) (*model.Problem, e.Status) { func (s *service) Create(data *CreateData) (*model.Problem, e.Status) {
tags := pgtype.TextArray{}
_ = tags.Set(data.Tags)
problem := &model.Problem{ problem := &model.Problem{
Title: data.Title, Title: data.Title,
Statement: data.Statement, Statement: data.Statement,
Tags: tags,
ProviderID: data.ProviderID, ProviderID: data.ProviderID,
IsEnabled: data.IsEnabled, IsEnabled: data.IsEnabled,
} }

View File

@ -1,29 +0,0 @@
package problem
import (
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/internal/model"
"github.com/jackc/pgtype"
"go.uber.org/zap"
)
type CreateVersionData struct {
ProblemID uint
StorageKey string
}
func (s *service) CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status) {
problemVersion := &model.ProblemVersion{
ProblemID: data.ProblemID,
Context: pgtype.JSON{Status: pgtype.Null},
StorageKey: data.StorageKey,
}
err := s.db.Get().Create(problemVersion).Error
if err != nil {
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problemVersion", problemVersion))
return nil, e.DatabaseError
}
return problemVersion, e.Success
}

View File

@ -1,30 +0,0 @@
package problem
import (
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/internal/model"
"go.uber.org/zap"
"gorm.io/gorm/clause"
)
func (s *service) QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status) {
problems := make([]*model.Problem, 0)
query := s.db.Get()
if associations {
query = query.Preload(clause.Associations)
}
if shouldEnable {
query = query.Where("is_enabled = true")
}
query = query.
Where(s.db.Get().Where("title LIKE ?", "%"+search+"%").
Or("statement LIKE ?", "%"+search+"%"))
err := query.Find(&problems).Error
if err != nil {
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("search", search))
return nil, e.DatabaseError
}
return problems, e.Success
}

View File

@ -1,29 +0,0 @@
package problem
import (
"errors"
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/internal/model"
"go.uber.org/zap"
"gorm.io/gorm"
)
func (s *service) QueryLatestVersion(pid uint) (*model.ProblemVersion, e.Status) {
problemVersion := &model.ProblemVersion{
ProblemID: pid,
IsEnabled: true,
}
err := s.db.Get().
Where(problemVersion).
Last(&problemVersion).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, e.ProblemVersionNotFound
}
if err != nil {
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("problemVersion", problemVersion))
return nil, e.DatabaseError
}
return problemVersion, e.Success
}

View File

@ -1,27 +0,0 @@
package problem
import (
"errors"
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/internal/model"
"go.uber.org/zap"
"gorm.io/gorm"
)
func (s *service) QueryVersion(pvid uint, shouldEnable bool) (*model.ProblemVersion, e.Status) {
problemVersion := new(model.ProblemVersion)
err := s.db.Get().First(&problemVersion, pvid).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, e.ProblemVersionNotFound
}
if err != nil {
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("pvid", pvid))
return nil, e.DatabaseError
}
if shouldEnable && !problemVersion.IsEnabled {
return nil, e.ProblemVersionNotAvailable
}
return problemVersion, e.Success
}

View File

@ -15,7 +15,7 @@ type Service interface {
Create(data *CreateData) (*model.Problem, e.Status) Create(data *CreateData) (*model.Problem, e.Status)
Update(problem *model.Problem) (*model.Problem, e.Status) Update(problem *model.Problem) (*model.Problem, e.Status)
Query(pid uint, associations bool, shouldEnable bool) (*model.Problem, e.Status) Query(pid uint, associations bool, shouldEnable bool) (*model.Problem, e.Status)
QueryFuzz(search string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status) QueryFuzz(keyword string, tag string, associations bool, shouldEnable bool) ([]*model.Problem, e.Status)
CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status) CreateVersion(data *CreateVersionData) (*model.ProblemVersion, e.Status)
UpdateVersion(pvid uint, values interface{}) e.Status UpdateVersion(pvid uint, values interface{}) e.Status

View File

@ -1,17 +0,0 @@
package problem
import (
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/internal/model"
"go.uber.org/zap"
)
func (s *service) UpdateVersion(pvid uint, values interface{}) e.Status {
err := s.db.Get().Model(&model.ProblemVersion{}).Where("id = ?", pvid).Updates(values).Error
if err != nil {
s.log.Warn("DatabaseError", zap.Error(err), zap.Any("pvid", pvid), zap.Any("values", values))
return e.DatabaseError
}
return e.Success
}