From 0aafb73ab05ba2cc45592b6e9c2deb7286046f7d Mon Sep 17 00:00:00 2001 From: Soohyeonl <1270874562@qq.com> Date: Thu, 18 Aug 2022 17:14:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=8E=A7=E5=88=B6=E5=B1=82?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit b78838d8e9412c54f462fa15e4aee80123c5b25b) --- controllers/account.go | 61 ++++++++ controllers/assignment.go | 116 ++++++++++++++ controllers/audit.go | 150 ++++++++++++++++++ controllers/base.go | 74 +++++++++ controllers/dataset.go | 61 ++++++++ controllers/default.go | 6 + controllers/file.go | 151 +++++++++++++++++++ controllers/project.go | 169 +++++++++++++++++++++ controllers/query.go | 78 ++++++++++ controllers/question.go | 243 ++++++++++++++++++++++++++++++ controllers/step.go | 276 ++++++++++++++++++++++++++++++++++ controllers/submit.go | 224 +++++++++++++++++++++++++++ controllers/testpaper.go | 276 ++++++++++++++++++++++++++++++++++ controllers/token_jwt_key.pem | 29 ++++ controllers/user.go | 8 + controllers/util.go | 53 +++++++ routers/filter.go | 29 ++++ routers/router.go | 113 ++++++++++++++ 18 files changed, 2117 insertions(+) create mode 100644 controllers/account.go create mode 100644 controllers/assignment.go create mode 100644 controllers/audit.go create mode 100644 controllers/base.go create mode 100644 controllers/dataset.go create mode 100644 controllers/default.go create mode 100644 controllers/file.go create mode 100644 controllers/project.go create mode 100644 controllers/query.go create mode 100644 controllers/question.go create mode 100644 controllers/step.go create mode 100644 controllers/submit.go create mode 100644 controllers/testpaper.go create mode 100644 controllers/token_jwt_key.pem create mode 100644 controllers/user.go create mode 100644 controllers/util.go create mode 100644 routers/filter.go create mode 100644 routers/router.go diff --git a/controllers/account.go b/controllers/account.go new file mode 100644 index 0000000..0205a76 --- /dev/null +++ b/controllers/account.go @@ -0,0 +1,61 @@ +package controllers + +import ( + _ "embed" + + "github.com/astaxie/beego" + "github.com/casdoor/casdoor-go-sdk/auth" +) + +//go:embed token_jwt_key.pem +var JwtPublicKey string + +func init() { + InitAuthConfig() +} + +func InitAuthConfig() { + casdoorEndpoint := beego.AppConfig.String("casdoorEndpoint") + clientId := beego.AppConfig.String("clientId") + clientSecret := beego.AppConfig.String("clientSecret") + casdoorOrganization := beego.AppConfig.String("casdoorOrganization") + casdoorApplication := beego.AppConfig.String("casdoorApplication") + + auth.InitConfig(casdoorEndpoint, clientId, clientSecret, JwtPublicKey, casdoorOrganization, casdoorApplication) +} + +func (c *ApiController) Signin() { + code := c.Input().Get("code") + state := c.Input().Get("state") + + token, err := auth.GetOAuthToken(code, state) + if err != nil { + panic(err) + } + + claims, err := auth.ParseJwtToken(token.AccessToken) + if err != nil { + panic(err) + } + + claims.AccessToken = token.AccessToken + c.SetSessionClaims(claims) + + c.ResponseOk(claims) +} + +func (c *ApiController) Signout() { + c.SetSessionClaims(nil) + + c.ResponseOk() +} + +func (c *ApiController) GetAccount() { + if c.RequireSignedIn() { + return + } + + claims := c.GetSessionClaims() + + c.ResponseOk(claims) +} diff --git a/controllers/assignment.go b/controllers/assignment.go new file mode 100644 index 0000000..14aefc4 --- /dev/null +++ b/controllers/assignment.go @@ -0,0 +1,116 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// MakeOneAssignment +// @Title MakeOneAssignment +// @Description create a user assignment for a project (创建一个人员分配记录: 项目-用户-角色) json字段说明: operator-进行角色分配的管理员id(根据token自行填充), project_id-该项分配记录对应的项目id, user_id-要进行分配的用户id, role-要分配的角色(1-项目管理员, 2-专家, 3-学科助理, 4-命题教师, 5-外审人员) +// @Param json body object.MakeOneAssignmentRequest true "assignment information" +// @Success 200 {object} response.Default +// @Failure 400 "invalid token(body)" +// @router /api/review/proj/assign [post] +func (c *ApiController) MakeOneAssignment() { + if c.RequireSignedIn() { + return + } + + var newAssign object.MakeOneAssignmentRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &newAssign) + if err != nil { + c.ResponseError(err.Error()) + return + } + user := c.GetSessionUser() + + newAssign.Operator = user.Id + resp, err := object.MakeOneAssignment(&newAssign) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetProjectAssignments @Title GetProjectAssignment +// @Description 获取一个项目的所有人员分配情况 +// @Param pid path string true "project id owner/name" +// @Success 200 {object} response.Default +// @Failure 400 "invalid project id" +// @router /api/review/proj/assign/:pid [get] +func (c *ApiController) GetProjectAssignments() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid id") + return + } + assigns, err := object.GetProjectAssignment(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(assigns) +} + +// DeleteAssignment @Title DeleteAssignment +// @Description 删除一条角色分配 +// @Param aid path string true "uuid of assignment to delete" +// @Success 200 true +// @Failure 400 "invalid uuid" +// @router /api/review/proj/assign/:aid [delete] +func (c *ApiController) DeleteAssignment() { + if c.RequireSignedIn() { + return + } + + aid := c.GetString(":aid") + if aid == "" { + c.ResponseError("invalid id") + return + } + err := object.RemoveAssignment(aid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(true) +} + +// ChangeAssignment @Title ChangeAssignment +// @Description 更改一个角色分配; 字段说明: operator-进行更改的管理员id(根据token解析), assignment_id-更改的assign id, new_role-新的角色分配, +// @Param json body object.ChangeAssignmentRequest true "new role to change" +// @Success 200 true +// @Failure 400 "invalid bodu" +// @router /api/review/proj/assign [patch] +func (c *ApiController) ChangeAssignment() { + if c.RequireSignedIn() { + return + } + + var update object.ChangeAssignmentRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &update) + if err != nil { + c.ResponseError(err.Error()) + return + } + user := c.GetSessionUser() + update.Operator = user.Id + + err = object.ChangeAssignment(&update) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(true) +} diff --git a/controllers/audit.go b/controllers/audit.go new file mode 100644 index 0000000..1806fbc --- /dev/null +++ b/controllers/audit.go @@ -0,0 +1,150 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// a part of project controller + +// GetOneAudit +// @Title GetOneAudit +// @Description 获取项目管理员/负责人等对一个submit下的content做出的审核 +// @Param auditId path string true "audit id owner/name" +// @Success 200 {object} &object.Audit +// @Failure 400 "invalid audit id" +// @router /api/review/proj/audit/:auditId [get] +func (c *ApiController) GetOneAudit() { + if c.RequireSignedIn() { + return + } + + auditId := c.GetString(":auditId") + if auditId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetOneAudit(auditId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetAuditsInSubmit +// @Title GetAuditsInSubmit +// @Description 获取一个submit下的所有audit +// @Param submitId path string true "submit id" +// @Success 200 {object} &[]object.Audit +// @Failure 400 "invalid submit uuid" +// @router /api/review/proj/audits/:submitId [get] +func (c *ApiController) GetAuditsInSubmit() { + if c.RequireSignedIn() { + return + } + + submitId := c.GetString(":submitId") + if submitId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetSubmitAudits(submitId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// CreateOneAudit +// @Title VreateOneAudit +// @Description 项目负责人创建一个材料审核记录 +// @Param json body object.Audit true "审核信息" +// @Success 200 {object} object.Audit +// @Failure 400 "invalid json" +// @router /api/review/proj/audit [post] +func (c *ApiController) CreateOneAudit() { + if c.RequireSignedIn() { + return + } + + var req object.Audit + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + user := c.GetSessionUser() + req.Owner = user.Id + req.Auditor = user.Id + + resp, err := object.MakeOneAudit(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// CorrectAudit +// @Title CorrectAudit +// @Description 负责人修改审核信息 +// @Param json body object.Audit true "修改后的审核信息" +// @Success 200 {object} object.Audit +// @Failure 400 "invalid json" +// @router /api/review/proj/audit [put] +func (c *ApiController) CorrectAudit() { + if c.RequireSignedIn() { + return + } + + var req object.Audit + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + user := c.GetSessionUser() + req.Owner = user.Id + req.Auditor = user.Id + + resp, err := object.CorrectAudit(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// DeleteAudit +// @Title DeleteAudit +// @Description 删除一条审核记录 +// @Param token header string true "user token get at login" +// @Param auditId path string true "要深处的审核记录Id" +// @Success 200 {object} true +// @Failure 400 "invalid audit id" +// @router /api/review/proj/audit [delete] +func (c *ApiController) DeleteAudit() { + if c.RequireSignedIn() { + return + } + + auditId := c.GetString(":auditId") + if auditId == "" { + c.ResponseError("invalid id") + return + } + err := object.DeleteAudit(auditId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(true) +} diff --git a/controllers/base.go b/controllers/base.go new file mode 100644 index 0000000..af604dd --- /dev/null +++ b/controllers/base.go @@ -0,0 +1,74 @@ +package controllers + +import ( + "encoding/gob" + + "github.com/astaxie/beego" + "github.com/casdoor/casdoor-go-sdk/auth" +) + +type ApiController struct { + beego.Controller +} + +func init() { + gob.Register(auth.Claims{}) +} + +func GetUserName(user *auth.User) string { + if user == nil { + return "" + } + + return user.Name +} + +func (c *ApiController) GetSessionClaims() *auth.Claims { + s := c.GetSession("user") + if s == nil { + return nil + } + + claims := s.(auth.Claims) + return &claims +} + +func (c *ApiController) SetSessionClaims(claims *auth.Claims) { + if claims == nil { + c.DelSession("user") + return + } + + c.SetSession("user", *claims) +} + +func (c *ApiController) GetSessionUser() *auth.User { + claims := c.GetSessionClaims() + if claims == nil { + return nil + } + + return &claims.User +} + +func (c *ApiController) SetSessionUser(user *auth.User) { + if user == nil { + c.DelSession("user") + return + } + + claims := c.GetSessionClaims() + if claims != nil { + claims.User = *user + c.SetSessionClaims(claims) + } +} + +func (c *ApiController) GetSessionUsername() string { + user := c.GetSessionUser() + if user == nil { + return "" + } + + return GetUserName(user) +} diff --git a/controllers/dataset.go b/controllers/dataset.go new file mode 100644 index 0000000..751b205 --- /dev/null +++ b/controllers/dataset.go @@ -0,0 +1,61 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +func (c *ApiController) GetGlobalDatasets() { + c.Data["json"] = object.GetGlobalDatasets() + c.ServeJSON() +} + +func (c *ApiController) GetDatasets() { + owner := c.Input().Get("owner") + + c.Data["json"] = object.GetDatasets(owner) + c.ServeJSON() +} + +func (c *ApiController) GetDataset() { + id := c.Input().Get("id") + + c.Data["json"] = object.GetDataset(id) + c.ServeJSON() +} + +func (c *ApiController) UpdateDataset() { + id := c.Input().Get("id") + + var dataset object.Dataset + err := json.Unmarshal(c.Ctx.Input.RequestBody, &dataset) + if err != nil { + panic(err) + } + + c.Data["json"] = object.UpdateDataset(id, &dataset) + c.ServeJSON() +} + +func (c *ApiController) AddDataset() { + var dataset object.Dataset + err := json.Unmarshal(c.Ctx.Input.RequestBody, &dataset) + if err != nil { + panic(err) + } + + c.Data["json"] = object.AddDataset(&dataset) + c.ServeJSON() +} + +func (c *ApiController) DeleteDataset() { + var dataset object.Dataset + err := json.Unmarshal(c.Ctx.Input.RequestBody, &dataset) + if err != nil { + panic(err) + } + + c.Data["json"] = object.DeleteDataset(&dataset) + c.ServeJSON() +} diff --git a/controllers/default.go b/controllers/default.go new file mode 100644 index 0000000..4a769aa --- /dev/null +++ b/controllers/default.go @@ -0,0 +1,6 @@ +package controllers + +func (c *ApiController) GetPosts() { + c.Data["json"] = "OK" + c.ServeJSON() +} diff --git a/controllers/file.go b/controllers/file.go new file mode 100644 index 0000000..34cea03 --- /dev/null +++ b/controllers/file.go @@ -0,0 +1,151 @@ +package controllers + +import ( + "bytes" + "encoding/json" + "io" + "log" + "mime/multipart" + "net/url" + "path" + "strings" + + "github.com/open-ct/openitem/object" +) + +func getFileBytes(file *multipart.File) []byte { + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, *file); err != nil { + panic(err) + } + + return buf.Bytes() +} + +// UploadFile +// @Title UploadFile +// @Description 文件上传, 使用post form格式上传, 会自动解析token获得对应的上传者id +// @Param file formData file true "文件名" +// @Param description formData string false "文件注释和说明" +// @Param tags formData string false "文件标签(文件类型即为文件的后缀名, 自动解析)" +// @Param source_project formData string true "上传文件对应的项目id, 查询使用" +// @Success 200 {object} object.FileItem +// @Failure 400 "invalid file" +// @router /api/review/file/ [post] +func (c *ApiController) UploadFile() { + if c.RequireSignedIn() { + return + } + + file, fileHeader, err := c.GetFile("file") + if err != nil { + log.Printf("[file] get file from post-request error: %s", err.Error()) + c.ResponseError("get file failed") + return + } + defer file.Close() + + fileName := fileHeader.Filename + fileName = url.QueryEscape(fileName) + fileBytes := getFileBytes(&file) + + fileDescription := c.GetString("description") + fileTags := strings.Split(c.GetString("tags"), ",") + fileSourceProject := c.GetString("source_project") + + user := c.GetSessionUser() + + uploadRequest := object.FileItem{ + Owner: user.Id, + Name: fileName, + Type: path.Ext(fileHeader.Filename), + SourceProject: fileSourceProject, + Description: fileDescription, + Tags: fileTags, + } + fileUrl, objectKey := object.UploadFileToStorage(&uploadRequest, fileBytes) + if fileUrl == "" { + c.ResponseError("upload file error") + return + } + + c.ResponseOk(fileUrl, objectKey) +} + +// GetFileInfo +// @Title GetFileInfo +// @Description 只获取文件信息, 不执行下载 +// @Param fid path string true "file uuid owner/name" +// @Success 200 {object} response.Default +// @Failure 400 "invalid file uuid" +// @router /api/review/file/info/:fid [get] +func (c *ApiController) GetFileInfo() { + if c.RequireSignedIn() { + return + } + + fid := c.GetString(":fid") + if fid == "" { + c.ResponseError("invalid file id") + return + } + fileInfo, err := object.GetFileInfo(fid) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(fileInfo) +} + +// SearchFiles +// @Title SearchFiles +// @Description 条件搜素文件, 搜索结果 (待完善) +// @Param json body object.FileItem true "搜索条件" +// @Success 200 {object} []object.FileItem +// @Failure 400 "invalid conditions (parse body failed)" +// @router /api/review/file/search [post] +func (c *ApiController) SearchFiles() { + if c.RequireSignedIn() { + return + } + + var req object.FileItem + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + log.Printf("[file search] parse search conditions error: %s", err.Error()) + c.ResponseError("parse search conditions error") + return + } + searchResult, err := object.SearchFiles(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(searchResult) +} + +// DeleteFile +// @Title DeleteFile +// @Description 删除文件上传记录(不在磁盘存储中删除文件) login" +// @Param fid path string true "the file's id you want to delete owner/name" +// @Success 200 true +// @Failure 400 "invalid file id" +// @router /api/review/file/:fid [delete] +func (c *ApiController) DeleteFile() { + if c.RequireSignedIn() { + return + } + + fid := c.GetString(":fid") + if fid == "" { + c.ResponseError("invalid file id") + return + } + err := object.DeleteFile(fid) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(true) +} diff --git a/controllers/project.go b/controllers/project.go new file mode 100644 index 0000000..d9e9fb1 --- /dev/null +++ b/controllers/project.go @@ -0,0 +1,169 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// CreateEmptyProject +// @Title CreateEmptyProject +// @Description 创建一个空项目(不创建相关流程和任务) +// @Param json body object.Project true "基本的项目信息, 创建人(creator)一项不需要填写,会根据token自动解析填充" +// @Success 200 projectId owner/name +// @Failure 400 "[request login] please login" +// @router /api/review/proj/ [post] +func (c *ApiController) CreateEmptyProject() { + if c.RequireSignedIn() { + c.ResponseError("[request login] please login") + return + } + + var req object.Project + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + projectUuid, err := object.CreateEmptyProject(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(projectUuid) +} + +// CreatTemplateProject +// @Title CreatTemplateProject +// @Description 创建一个模板项目(创建标准的7个流程和任务) +// @Param json body object.Project true "基本的项目信息, 创建人(creator)一项不需要填写,会根据token自动解析填充" +// @Success 200 projectId owner/name +// @Failure 400 "[request login] please login" +// @router /api/review/proj/template [post] +func (c *ApiController) CreatTemplateProject() { + var req object.Project + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + // get user id from token + if c.RequireSignedIn() { + return + } + user := c.GetSessionUser() + req.Owner = user.Id + + projectUuid, err := object.CreateTemplateProject(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(projectUuid) +} + +// UpdateProjectInfo +// @Title UpdateProjectInfo +// @Description 更新项目相关信息 +// @Param json body object.Project true 要更新的项目信息数据 +// @Success 200 ok +// @Failure 400 "invalid body" +// @router /api/review/proj/ [put] +func (c *ApiController) UpdateProjectInfo() { + if c.RequireSignedIn() { + return + } + var req object.Project + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + err = object.UpdateProjectInfo(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk("ok") +} + +// GetBasicInfo +// @Title GetBasicInfo +// @Description 获取项目的基本信息数据 +// @Param pid path string true "项目的id owner/name" +// @Success 200 {object} object.Project +// @Failure 400 "invalid project id" +// @router /api/review/proj/basic/:pid [get] +func (c *ApiController) GetBasicInfo() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid project id") + return + } + proj, err := object.GetProjectBasicInfo(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(proj) +} + +// GetDetailedInfo +// @Title GetDetailedInfo +// @Description 获取项目的详细信息数据(basic info 基本信息, group-人员情况, steps-项目所有流程信息, materials-项目使用的参考材料) +// @Param pid path string true "项目的id owner/name" +// @Success 200 {object} object.Project +// @Failure 400 "invalid project id" +// @router /api/review/proj/detailed/:pid [get] +func (c *ApiController) GetDetailedInfo() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid project id") + return + } + proj, err := object.GetProjectDetailedInfo(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(proj) +} + +// GetUserAssignments +// @Title GetUserAssignment +// @Description 获取某一个用户的所有项目参与情况(即参与各个项目的角色分配情况) +// @Param uid path string true "user id" +// @Success 200 {object} response.Default +// @Failure 400 "invalid user id" +// @router /api/review/proj/user/:uid [get] +func (c *ApiController) GetUserAssignments() { + if c.RequireSignedIn() { + return + } + + uid := c.GetString(":uid") + if uid == "" { + c.ResponseError("invalid project id") + return + } + assigns, err := object.GetUserAssignments(uid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(assigns) +} diff --git a/controllers/query.go b/controllers/query.go new file mode 100644 index 0000000..b42fa09 --- /dev/null +++ b/controllers/query.go @@ -0,0 +1,78 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/casdoor" + "github.com/open-ct/openitem/object" +) + +type QueryRequest struct { + IdList []string `json:"id_list"` +} + +// GetProjectList +// @Title GetUserList +// @Description 获取项目列表 +// @Param json body QueryRequest true "要获取的id 列表" +// @Success 200 {object} []object.Project +// @Failure 400 "parse id list error" +// @router /api/review/query/proj [post] +func (c *ApiController) GetProjectList() { + if c.RequireSignedIn() { + return + } + + queryRequset := new(QueryRequest) + err := json.Unmarshal(c.Ctx.Input.RequestBody, &queryRequset) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp := object.QueryProjects(queryRequset.IdList) + c.ResponseOk(resp) +} + +// GetTempQuestionList +// @Title GetTempQuestionList +// @Description 根据id列表获取temp-question信息 +// @Param json body models.QueryListRequest true "要获取的id 列表" +// @Success 200 {object} []models.TempQuestion +// @Failure 400 "parse id list error" +// @router /api/qbank/query/t_question [post] +func (c *ApiController) GetTempQuestionList() { + if c.RequireSignedIn() { + return + } + + queryRequset := new(QueryRequest) + err := json.Unmarshal(c.Ctx.Input.RequestBody, queryRequset) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp := object.QueryTempQuestions(queryRequset.IdList) + c.ResponseOk(resp) +} + +// GetUserList +// @Title GetUserList +// @Description 根据id列表获取user信息 +// @Param json body QueryRequest true "要获取的id 列表" +// @Success 200 {object} response.Default +// @Failure 400 "parse id list error" +// @router /api/review/query/user [post] +func (c *ApiController) GetUserList() { + if c.RequireSignedIn() { + return + } + + queryRequset := new(QueryRequest) + err := json.Unmarshal(c.Ctx.Input.RequestBody, &queryRequset) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp := casdoor.QueryUsers(queryRequset.IdList) + c.ResponseOk(resp) +} diff --git a/controllers/question.go b/controllers/question.go new file mode 100644 index 0000000..8eb3d6f --- /dev/null +++ b/controllers/question.go @@ -0,0 +1,243 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// CreateNewQuestion +// @Title CreateNewQuestion +// @Description 创建新的题目(临时题目) +// @Param json body object.TempQuestion true "新题目信息" +// @Success 200 {string} +// @Failure 400 "invalid body" +// @router /api/qbank/question [post] +func (c *ApiController) CreateNewQuestion() { + if c.RequireSignedIn() { + return + } + + var request object.TempQuestion + err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp, err := object.CreateNewTempQuestion(&request) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(resp) +} + +// UpdateQuestion @Title UpdateQuestion +// @Description 更新新题目(创建一个新的分支) +// @Param json body object.TempQuestion true "更新的题目信息" +// @Success 200 {string} +// @Failure 400 "invalid body" +// @router /api/qbank/question [put] +func (c *ApiController) UpdateQuestion() { + if c.RequireSignedIn() { + return + } + + var request object.TempQuestion + err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) + if err != nil { + c.ResponseError(err.Error()) + return + } + + resp, err := object.UpdateQuestion(&request) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(resp) +} + +// AddQuestionComment +// @Title AddQuestionComment +// @Description 添加一条题目的评价内容 +// @Param json body object.AddQuestionCommentRequest true "题目评价" +// @Success 200 {string} +// @Failure 400 "invalid body" +// @router /api/qbank/question/comment [post] +func (c *ApiController) AddQuestionComment() { + if c.RequireSignedIn() { + return + } + + var request object.AddQuestionCommentRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) + if err != nil { + c.ResponseError(err.Error()) + return + } + + err = object.AddQuestionComment(&request) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk("ok") +} + +// TraceQuestionVersion @Title TraceQuestionVersion +// @Description 查询历史版本 +// @Param qid path string true "question id" +// @Success 200 {[]models.TempQuestion} +// @Failure 400 "invalid qid" +// @router /api/qbank/question/trace/:qid [get] +func (c *ApiController) TraceQuestionVersion() { + if c.RequireSignedIn() { + return + } + + qid := c.GetString(":qid") + if qid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.TraceQuestionVersion(qid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// FinishTempQuestion +// @Title FinishTempQuestion +// @Description 最终确定题目 (转移到final数据库下) +// @Param qid path string true "question id" +// @Success 200 {string} +// @Failure 400 "invalid qid" +// @router /api/qbank/question/finish/:qid [get] +func (c *ApiController) FinishTempQuestion() { + if c.RequireSignedIn() { + return + } + + qid := c.GetString(":qid") + if qid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.FinishTempQuestion(qid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetUserTempQuestions +// @Title GetUserTempQuestions +// @Description 获取用户创建的题目(temp数据库下) +// @Param uid path string true "user id" +// @Success 200 {[]object.TempQuestion} +// @Failure 400 "invalid qid" +// @router /api/qbank/question/user_t/:uid [get] +func (c *ApiController) GetUserTempQuestions() { + if c.RequireSignedIn() { + return + } + + uid := c.GetString(":uid") + if uid == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetUserTempQuestions(uid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetUserFinalQuestions +// @Title GetUserFinalQuestions +// @Description 获取用户创建的题目(final数据库下) +// @Param uid path string true "user id" +// @Success 200 {[]object.FinalQuestion} +// @Failure 400 "invalid qid" +// @router /api/qbank/question/user_f/:uid [get] +func (c *ApiController) GetUserFinalQuestions() { + if c.RequireSignedIn() { + return + } + + uid := c.GetString(":uid") + if uid == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetUserFinalQuestions(uid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetProjectTempQuestions +// @Title GetProjectTempQuestions +// @Description 获取项目下的题目(temp数据库下) +// @Param uid path string true "project id" +// @Success 200 {[]object.TempQuestion} +// @Failure 400 "invalid qid" +// @router /api/qbank/question/proj_t/:pid [get] +func (c *ApiController) GetProjectTempQuestions() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetProjectTempQuestions(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetProjectFinalQuestions +// @Title GetProjectFinalQuestions +// @Description 获取项目下的题目(final数据库下) +// @Param uid path string true "project id" +// @Success 200 {[]object.FinalQuestion} +// @Failure 400 "invalid qid" +// @router /api/qbank/question/proj_f/:pid [get] +func (c *ApiController) GetProjectFinalQuestions() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetProjectFinalQuestions(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} diff --git a/controllers/step.go b/controllers/step.go new file mode 100644 index 0000000..ebb8830 --- /dev/null +++ b/controllers/step.go @@ -0,0 +1,276 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// CreateOneStep +// @Title CreateOneStep +// @Description 在指定项目下创建一个流程 +// @Param json body object.Step true "新建步骤的基本信息结构" +// @Success 200 stepId owner/name +// @Failure 400 "invalid step json body" +// @router /api/review/proj/step [post] +func (c *ApiController) CreateOneStep() { + if c.RequireSignedIn() { + return + } + + var req object.Step + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + user := c.GetSessionUser() + req.Creator = user.Id + + resp, err := object.CreateOneStep(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetOneStepInfo +// @Title GetOneStepInfo +// @Description 获取某一个指定id的step信息 +// @Param stepId path string true "对应step的uuid" +// @Success 200 {object} object.Step +// @Failure 400 "invalid stepID" +// @router /api/review/proj/step/:stepId [get] +func (c *ApiController) GetOneStepInfo() { + if c.RequireSignedIn() { + return + } + + stepId := c.GetString(":stepId") + if stepId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetStepInfo(stepId) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(resp) +} + +// GetStepsInProject +// @Title GetStepsInProject +// @Description 获取一个项目下的所有step信息 +// @Param pid path string true "指定的项目uuid" +// @Success 200 {object} []object.Step +// @Failure 400 "invalid project id" +// @router /api/review/proj/steps/:pid [get] +func (c *ApiController) GetStepsInProject() { + if c.RequireSignedIn() { + return + } + + pId := c.GetString(":pid") + if pId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetAllStepsInProject(pId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// UploadStepAttachment +// @Title UploadStepAttachment +// @Description 绑定某个step的附件(这里并不上传文件, 需要调用uploadFile相关接口上传后绑定文件uuid到指定step) +// @Param json body object.AddStepAttachment true "附件信息" +// @Success 200 true +// @Failure 400 "invalid attachment json" +// @router /api/review/proj/step/attachment [post] +func (c *ApiController) UploadStepAttachment() { + if c.RequireSignedIn() { + return + } + + var req object.AddStepAttachment + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + user := c.GetSessionUser() + req.Uploader = user.Id + + err = object.UploadStepAttachments(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(true) +} + +// UpdateStepInfo +// @Title UpdateStepInfo +// @Description 更新某个step的信息 +// @Param json body object.Step true "要更新的信息" +// @Success 200 {object} response.Default +// @Failure 400 "invalid json" +// @router /api/review/proj/step [put] +func (c *ApiController) UpdateStepInfo() { + if c.RequireSignedIn() { + return + } + + var req object.Step + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + err = object.UpdateStepInfo(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(true) +} + +// SetStepStatus +// @Title SetStepStatus +// @Description 更改流程的进度状态 +// @Param json body object.Step true "新的状态信息" +// @Success 200 true +// @Failure 400 "invalid json body" +// @router /api/review/proj/step/status [put] +func (c *ApiController) SetStepStatus() { + if c.RequireSignedIn() { + return + } + + var req object.Step + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + err = object.SetStepStatus(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(true) +} + +// SetStepTimePoint +// @Title SetStepTimePoint +// @Description 为step设置时间点 +// @Param json body object.SetStepTimePoint true "时间点信息" +// @Success 200 {object} []object.ProjectTimePoint +// @Failure 400 "invalid json" +// @router /api/review/proj/step/timepoint [put] +func (c *ApiController) SetStepTimePoint() { + if c.RequireSignedIn() { + return + } + + var req object.SetStepTimePointRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp, err := object.SetStepTimePoint(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(resp) +} + +// DeleteStepTimePoint +// @Title DeleteStepTimePoint +// @Description 删除step下的某个时间点 +// @Param json body object.DeleteStepTimePointRequest true "要删除的时间点信息" +// @Success 200 true +// @Failure 400 "invalid jsob" +// @router /api/review/proj/step/timepoint [delete] +func (c *ApiController) DeleteStepTimePoint() { + if c.RequireSignedIn() { + return + } + + var req object.DeleteStepTimePointRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + err = object.DeleteStepTimePoint(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(true) +} + +// GetStepStatisticData +// @Title GetStepStatisticData +// @Description 获取一个项目step的统计信息 +// @Param stepId path string true "指定的step的uuid" +// @Success 200 {object} object.StepDataStatistic +// @Failure 400 "invalid project id" +// @router /api/review/proj/step/stat/:stepId [get] +func (c *ApiController) GetStepStatisticData() { + if c.RequireSignedIn() { + return + } + + stepId := c.GetString(":stepId") + if stepId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetStepDataStatistic(stepId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// DeleteStep +// @Title DeleteStep +// @Description 删除step +// @Param stepId path string true "要删除的的step的uuid" +// @Success 200 true +// @Failure 400 "invalid step id" +// @router /api/review/proj/step/:stepId [delete] +func (c *ApiController) DeleteStep() { + if c.RequireSignedIn() { + return + } + + stepId := c.GetString(":stepId") + if stepId == "" { + c.ResponseError("invalid id") + return + } + err := object.DeleteStep(stepId) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(true) +} diff --git a/controllers/submit.go b/controllers/submit.go new file mode 100644 index 0000000..28a842c --- /dev/null +++ b/controllers/submit.go @@ -0,0 +1,224 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// GetOneSubmit +// @Title GetOneSubmit +// @Description 获取一个submit的信息 +// @Param submitId path string true "要获取的submit uuid" +// @Success 200 {object} object.Submit +// @Failure 400 "invalid submit id" +// @router /api/review/proj/submit/:submitId [get] +func (c *ApiController) GetOneSubmit() { + if c.RequireSignedIn() { + return + } + + submitId := c.GetString(":submitId") + if submitId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetOneSubmit(submitId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetSubmitsInStep @Title GetSubmitInStep +// @Description 获取一个step下的所有submit +// @Param stepId path string true "step的uuid" +// @Success 200 {object} []object.Submit +// @Failure 400 "invalid step id" +// @router /api/review/proj/submits/:stepId [get] +func (c *ApiController) GetSubmitsInStep() { + if c.RequireSignedIn() { + return + } + + stepId := c.GetString(":stepId") + if stepId == "" { + c.ResponseError("invalid id") + return + } + resp, err := object.GetStepSubmits(stepId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetUserSubmitInStep +// @Title GetUserSubmitInStep +// @Description 获取某个用户在指定step下的submit +// @Param json body object.GetUserSubmitsInStepRequest true "用户&step信息" +// @Success 200 {object} []object.Submit +// @Failure 400 "invalid json" +// @router /api/review/proj/submits/user [post] +func (c *ApiController) GetUserSubmitInStep() { + if c.RequireSignedIn() { + return + } + + var req object.GetUserSubmitsInStepRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp, err := object.GetUserSubmitsInStep(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// MakeOneSubmit +// @Title MakeOneSubmit +// @Description 创建一个新的submit +// @Param token header string true "user token get at login" +// @Param json body object.Submit true "新submit信息" +// @Success 200 {object} response.Default +// @Failure 400 "invalid json" +// @router /api/review/proj/submit [post] +func (c *ApiController) MakeOneSubmit() { + if c.RequireSignedIn() { + return + } + + var req object.Submit + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + user := c.GetSessionUser() + req.Submitter = user.Id + + resp, err := object.MakeOneSubmit(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// AppendContentInStep +// @Title AppendContentInStep +// @Description 在一个step中的content下追加新的材料(即用户在上传材料审核的历史记录) +// @Param json body object.AppendContentInSubmit true "上传的材料信息" +// @Success 200 {object} response.Default +// @Failure 400 "invalid json" +// @router /api/review/proj/submit/content [post] +func (c *ApiController) AppendContentInStep() { + if c.RequireSignedIn() { + return + } + + var req object.AppendContentInSubmit + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp, err := object.AppendContent(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// WithdrawContentInStep +// @Title WithdrawContentInStep +// @Description 用户撤回某次提交的材料审核 +// @Param json body object.WithdrawContentInSubmit true "撤回的信息" +// @Success 200 {object} response.Default +// @Failure 400 "invalid json" +// @router /api/review/proj/submit/content [delete] +func (c *ApiController) WithdrawContentInStep() { + if c.RequireSignedIn() { + return + } + + var req object.WithdrawContentInSubmit + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + resp, err := object.WithdrawContent(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// SetSubmitStatus +// @Title SetSubmitStatus +// @Description 更改提交的状态(即管理员最终审核某次提交是否最终通过) +// @Param json body object.SetSubmitStatusRequest true "设定的状态" +// @Success 200 true +// @Failure 400 "invalid json" +// @router /api/review/proj/submit [put] +func (c *ApiController) SetSubmitStatus() { + if c.RequireSignedIn() { + return + } + + var req object.SetSubmitStatusRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &req) + if err != nil { + c.ResponseError(err.Error()) + return + } + err = object.SetSubmitStatus(&req) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(true) +} + +// DeleteSubmit +// @Title DeleteSubmit +// @Description 删除一次submit +// @Param submitId path string true "要删除的submit的uuid" +// @Success 200 true +// @Failure 400 "invalid submit id" +// @router /api/review/proj/submit/:submitId [delete] +func (c *ApiController) DeleteSubmit() { + if c.RequireSignedIn() { + return + } + + submitId := c.GetString(":submitId") + if submitId == "" { + c.ResponseError("invalid id") + return + } + err := object.DeleteSubmit(submitId) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(true) +} diff --git a/controllers/testpaper.go b/controllers/testpaper.go new file mode 100644 index 0000000..cadb806 --- /dev/null +++ b/controllers/testpaper.go @@ -0,0 +1,276 @@ +package controllers + +import ( + "encoding/json" + + "github.com/open-ct/openitem/object" +) + +// CreateNewTestpaper +// @Title CreateNewTestpaper +// @Description 创建新的题目(临时题目) +// @Param json body object.TempTestpaper true "新试卷信息" +// @Success 200 {string} +// @Failure 400 "invalid body" +// @router /api/qbank/testpaper/ [post] +func (c *ApiController) CreateNewTestpaper() { + if c.RequireSignedIn() { + return + } + + var request object.TempTestpaper + err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) + if err != nil { + c.ResponseError(err.Error()) + return + } + + resp, err := object.CreateNewTestpaper(&request) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(resp) +} + +// UpdateTestpaper +// @Title UpdateTestpaper +// @Description 更新新题目(创建一个新的分支) +// @Param json body models.UpdateTestpaperRequest true "更新的试卷信息or内容" +// @Success 200 {string} +// @Failure 400 "invalid body" +// @router /api/qbank/testpaper/ [put] +func (c *ApiController) UpdateTestpaper() { + if c.RequireSignedIn() { + return + } + + var request object.TempTestpaper + err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) + if err != nil { + c.ResponseError(err.Error()) + return + } + + resp, err := object.UpdateTestpaper(&request) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk(resp) +} + +// AddTestpaperComment +// @Title AddTestpaperComment +// @Description 添加一条题目的评价内容 +// @Param json body object.AddTestpaperCommentRequest true "新建一个试卷评估记录" +// @Success 200 {string} +// @Failure 400 "invalid body" +// @router /api/qbank/testpaper/comment [post] +func (c *ApiController) AddTestpaperComment() { + if c.RequireSignedIn() { + return + } + + var request object.AddTestpaperCommentRequest + err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) + if err != nil { + c.ResponseError(err.Error()) + return + } + + err = object.AddTestpaperComment(&request) + if err != nil { + c.ResponseError(err.Error()) + return + } + c.ResponseOk("ok") +} + +// TraceTestpaperVersion +// @Title TraceTestpaperVersion +// @Description 查询试卷的历史版本(向前查询) +// @Param qid path string true "temp test-paper id" +// @Success 200 {[]object.TempTestpaper} +// @Failure 400 "invalid qid" +// @router /api/qbank/testpaper/trace/:qid [get] +func (c *ApiController) TraceTestpaperVersion() { + if c.RequireSignedIn() { + return + } + + tid := c.GetString(":tid") + if tid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.TraceTestpaperVersion(tid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// FinishTempTestpaper +// @Title FinishTempTestpaper +// @Description 最终确定题目 (试卷完成评审, 转移到final数据库下) +// @Param qid path string true "test-paper id" +// @Success 200 {string} +// @Failure 400 "invalid qid" +// @router /api/qbank/testpaper/finish/:qid [get] +func (c *ApiController) FinishTempTestpaper() { + if c.RequireSignedIn() { + return + } + + tid := c.GetString(":tid") + if tid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.FinishTempTestpaper(tid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetUserTempTestpaper +// @Title GetUserTempTestpaper +// @Description 获取用户创建的试卷(temp数据库下) +// @Param uid path string true "user id" +// @Success 200 {[]object.TempTestpaper} +// @Failure 400 "invalid qid" +// @router /api/qbank/testpaper/user_t/:uid [get] +func (c *ApiController) GetUserTempTestpaper() { + if c.RequireSignedIn() { + return + } + + uid := c.GetString(":uid") + if uid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.GetUserTempTestpaper(uid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetUserFinalTestpaper +// @Title GetUserFinalTestpaper +// @Description 获取用户创建的试卷(final数据库下) +// @Param uid path string true "user id" +// @Success 200 {[]object.FinalTestpaper} +// @Failure 400 "invalid qid" +// @router /api/qbank/testpaper/user_f/:uid [get] +func (c *ApiController) GetUserFinalTestpaper() { + if c.RequireSignedIn() { + return + } + + uid := c.GetString(":uid") + if uid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.GetUserFinalTestpaper(uid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetProjectTempTestpaper +// @Title GetProjectTempTestpaper +// @Description 获取项目下的试卷(temp数据库下) +// @Param uid path string true "project id" +// @Success 200 {[]object.TempTestpaper} +// @Failure 400 "invalid qid" +// @router /api/qbank/testpaper/proj_t/:pid [get] +func (c *ApiController) GetProjectTempTestpaper() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.GetProjectTempTestpaper(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// GetProjectFinalTestpaper +// @Title GetProjectFinalTestpaper +// @Description 获取项目下的试卷(final数据库下) +// @Param uid path string true "project id" +// @Success 200 {[]object.FinalTestpaper} +// @Failure 400 "invalid qid" +// @router /api/qbank/testpaper/proj_f/:pid [get] +func (c *ApiController) GetProjectFinalTestpaper() { + if c.RequireSignedIn() { + return + } + + pid := c.GetString(":pid") + if pid == "" { + c.ResponseError("invalid id") + return + } + + resp, err := object.GetProjecgtFinalTestpaper(pid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk(resp) +} + +// DeleteTempTestpaper +// @Title DeleteTempTestpaper +// @Description 删除temptestpaper +// @Param uid path string true "testpaper id" +// @Success 200 {string} +// @router /api/qbank/testpaper/temp [delete] +func (c *ApiController) DeleteTempTestpaper() { + if c.RequireSignedIn() { + return + } + + tid := c.GetString(":tid") + if tid == "" { + c.ResponseError("invalid id") + return + } + + err := object.DeleteTempTestpaper(tid) + if err != nil { + c.ResponseError(err.Error()) + return + } + + c.ResponseOk("ok") +} diff --git a/controllers/token_jwt_key.pem b/controllers/token_jwt_key.pem new file mode 100644 index 0000000..c2d6d5f --- /dev/null +++ b/controllers/token_jwt_key.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE+TCCAuGgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMDYxHTAbBgNVBAoTFENh +c2Rvb3IgT3JnYW5pemF0aW9uMRUwEwYDVQQDEwxDYXNkb29yIENlcnQwHhcNMjEx +MDE1MDgxMTUyWhcNNDExMDE1MDgxMTUyWjA2MR0wGwYDVQQKExRDYXNkb29yIE9y +Z2FuaXphdGlvbjEVMBMGA1UEAxMMQ2FzZG9vciBDZXJ0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsInpb5E1/ym0f1RfSDSSE8IR7y+lw+RJjI74e5ej +rq4b8zMYk7HeHCyZr/hmNEwEVXnhXu1P0mBeQ5ypp/QGo8vgEmjAETNmzkI1NjOQ +CjCYwUrasO/f/MnI1C0j13vx6mV1kHZjSrKsMhYY1vaxTEP3+VB8Hjg3MHFWrb07 +uvFMCJe5W8+0rKErZCKTR8+9VB3janeBz//zQePFVh79bFZate/hLirPK0Go9P1g +OvwIoC1A3sarHTP4Qm/LQRt0rHqZFybdySpyWAQvhNaDFE7mTstRSBb/wUjNCUBD +PTSLVjC04WllSf6Nkfx0Z7KvmbPstSj+btvcqsvRAGtvdsB9h62Kptjs1Yn7GAuo +I3qt/4zoKbiURYxkQJXIvwCQsEftUuk5ew5zuPSlDRLoLByQTLbx0JqLAFNfW3g/ +pzSDjgd/60d6HTmvbZni4SmjdyFhXCDb1Kn7N+xTojnfaNkwep2REV+RMc0fx4Gu +hRsnLsmkmUDeyIZ9aBL9oj11YEQfM2JZEq+RVtUx+wB4y8K/tD1bcY+IfnG5rBpw +IDpS262boq4SRSvb3Z7bB0w4ZxvOfJ/1VLoRftjPbLIf0bhfr/AeZMHpIKOXvfz4 +yE+hqzi68wdF0VR9xYc/RbSAf7323OsjYnjjEgInUtRohnRgCpjIk/Mt2Kt84Kb0 +wn8CAwEAAaMQMA4wDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn2lf +DKkLX+F1vKRO/5gJ+Plr8P5NKuQkmwH97b8CS2gS1phDyNgIc4/LSdzuf4Awe6ve +C06lVdWSIis8UPUPdjmT2uMPSNjwLxG3QsrimMURNwFlLTfRem/heJe0Zgur9J1M +8haawdSdJjH2RgmFoDeE2r8NVRfhbR8KnCO1ddTJKuS1N0/irHz21W4jt4rxzCvl +2nR42Fybap3O/g2JXMhNNROwZmNjgpsF7XVENCSuFO1jTywLaqjuXCg54IL7XVLG +omKNNNcc8h1FCeKj/nnbGMhodnFWKDTsJcbNmcOPNHo6ixzqMy/Hqc+mWYv7maAG +Jtevs3qgMZ8F9Qzr3HpUc6R3ZYYWDY/xxPisuKftOPZgtH979XC4mdf0WPnOBLqL +2DJ1zaBmjiGJolvb7XNVKcUfDXYw85ZTZQ5b9clI4e+6bmyWqQItlwt+Ati/uFEV +XzCj70B4lALX6xau1kLEpV9O1GERizYRz5P9NJNA7KoO5AVMp9w0DQTkt+LbXnZE +HHnWKy8xHQKZF9sR7YBPGLs/Ac6tviv5Ua15OgJ/8dLRZ/veyFfGo2yZsI+hKVU5 +nCCJHBcAyFnm1hdvdwEdH33jDBjNB6ciotJZrf/3VYaIWSalADosHAgMWfXuWP+h +8XKXmzlxuHbTMQYtZPDgspS5aK+S4Q9wb8RRAYo= +-----END CERTIFICATE----- diff --git a/controllers/user.go b/controllers/user.go new file mode 100644 index 0000000..6068cf6 --- /dev/null +++ b/controllers/user.go @@ -0,0 +1,8 @@ +package controllers + +import "github.com/open-ct/openitem/casdoor" + +func (c *ApiController) GetUsers() { + c.Data["json"] = casdoor.GetUsers() + c.ServeJSON() +} diff --git a/controllers/util.go b/controllers/util.go new file mode 100644 index 0000000..5b651ea --- /dev/null +++ b/controllers/util.go @@ -0,0 +1,53 @@ +package controllers + +type Response struct { + Status string `json:"status"` + Msg string `json:"msg"` + Data interface{} `json:"data"` + Data2 interface{} `json:"data2"` +} + +func (c *ApiController) ResponseOk(data ...interface{}) { + resp := Response{Status: "ok"} + switch len(data) { + case 2: + resp.Data2 = data[1] + fallthrough + case 1: + resp.Data = data[0] + } + c.Data["json"] = resp + c.ServeJSON() +} + +func (c *ApiController) ResponseError(error string, data ...interface{}) { + resp := Response{Status: "error", Msg: error} + switch len(data) { + case 2: + resp.Data2 = data[1] + fallthrough + case 1: + resp.Data = data[0] + } + c.Data["json"] = resp + c.ServeJSON() +} + +func (c *ApiController) RequireSignedIn() bool { + if c.GetSessionUser() == nil { + c.ResponseError("please sign in first") + return true + } + + return false +} + +func (c *ApiController) RequireAdmin() bool { + user := c.GetSessionUser() + if user == nil || !user.IsAdmin { + c.ResponseError("this operation requires admin privilege") + return true + } + + return false +} diff --git a/routers/filter.go b/routers/filter.go new file mode 100644 index 0000000..25492e5 --- /dev/null +++ b/routers/filter.go @@ -0,0 +1,29 @@ +package routers + +import ( + "net/http" + "strings" + + "github.com/astaxie/beego/context" + "github.com/open-ct/openitem/util" +) + +func TransparentStatic(ctx *context.Context) { + urlPath := ctx.Request.URL.Path + if strings.HasPrefix(urlPath, "/api/") { + return + } + + path := "web/build" + if urlPath == "/" { + path += "/index.html" + } else { + path += urlPath + } + + if util.FileExist(path) { + http.ServeFile(ctx.ResponseWriter, ctx.Request, path) + } else { + http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html") + } +} diff --git a/routers/router.go b/routers/router.go new file mode 100644 index 0000000..a9bcc00 --- /dev/null +++ b/routers/router.go @@ -0,0 +1,113 @@ +package routers + +import ( + "github.com/astaxie/beego" + + "github.com/open-ct/openitem/controllers" +) + +func init() { + initAPI() +} + +func initAPI() { + ns := + beego.NewNamespace("/api", + beego.NSInclude( + &controllers.ApiController{}, + ), + ) + beego.AddNamespace(ns) + + beego.Router("/api/signin", &controllers.ApiController{}, "POST:Signin") + beego.Router("/api/signout", &controllers.ApiController{}, "POST:Signout") + beego.Router("/api/get-account", &controllers.ApiController{}, "GET:GetAccount") + + beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers") + + beego.Router("/api/get-global-datasets", &controllers.ApiController{}, "GET:GetGlobalDatasets") + beego.Router("/api/get-datasets", &controllers.ApiController{}, "GET:GetDatasets") + beego.Router("/api/get-dataset", &controllers.ApiController{}, "GET:GetDataset") + beego.Router("/api/update-dataset", &controllers.ApiController{}, "POST:UpdateDataset") + beego.Router("/api/add-dataset", &controllers.ApiController{}, "POST:AddDataset") + beego.Router("/api/delete-dataset", &controllers.ApiController{}, "POST:DeleteDataset") + + // project + beego.Router("/api/review/proj", &controllers.ApiController{}, "POST:CreateEmptyProject") + beego.Router("/api/review/proj/template", &controllers.ApiController{}, "POST:CreatTemplateProject") + beego.Router("/api/review/proj", &controllers.ApiController{}, "PUT:UpdateProjectInfo") + beego.Router("/api/review/proj/basic", &controllers.ApiController{}, "GET:GetBasicInfo") + beego.Router("/api/review/proj/detailed", &controllers.ApiController{}, "GET:GetDetailedInfo") + + // audit + beego.Router("/api/review/proj/audit", &controllers.ApiController{}, "GET:GetOneAudit") + beego.Router("/api/review/proj/audits", &controllers.ApiController{}, "GET:GetAuditsInSubmit") + beego.Router("/api/review/proj/audit", &controllers.ApiController{}, "POST:CreateOneAudit") + beego.Router("/api/review/proj/audit", &controllers.ApiController{}, "PUT:CorrectAudit") + beego.Router("/api/review/proj/audit", &controllers.ApiController{}, "DELETE:DeleteAudit") + + // step + beego.Router("/api/review/proj/step", &controllers.ApiController{}, "POST:CreateOneStep") + beego.Router("/api/review/proj/step", &controllers.ApiController{}, "GET:GetOneStepInfo") + beego.Router("/api/review/proj/steps", &controllers.ApiController{}, "GET:GetStepsInProject") + beego.Router("/api/review/proj/step/attachment", &controllers.ApiController{}, "POST:UploadStepAttachment") + beego.Router("/api/review/proj/step", &controllers.ApiController{}, "PUT:UpdateStepInfo") + beego.Router("/api/review/proj/step/status", &controllers.ApiController{}, "PUT:SetStepStatus") + beego.Router("/api/review/proj/step/timepoint", &controllers.ApiController{}, "PUT:SetStepTimePoint") + beego.Router("/api/review/proj/step/timepoint", &controllers.ApiController{}, "DELETE:DeleteStepTimePoint") + beego.Router("/api/review/proj/step/stat", &controllers.ApiController{}, "GET:GetStepStatisticData") + beego.Router("/api/review/proj/step", &controllers.ApiController{}, "DELETE:DeleteStep") + + // submit + beego.Router("/api/review/proj/submit", &controllers.ApiController{}, "GET:GetOneSubmit") + beego.Router("/api/review/proj/submits", &controllers.ApiController{}, "GET:GetSubmitsInStep") + beego.Router("/api/review/proj/submits/user", &controllers.ApiController{}, "POST:GetUserSubmitInStep") + beego.Router("/api/review/proj/submit", &controllers.ApiController{}, "POST:MakeOneSubmit") + beego.Router("/api/review/proj/submit/content", &controllers.ApiController{}, "POST:AppendContentInStep") + beego.Router("/api/review/proj/submit/content", &controllers.ApiController{}, "DELETE:WithdrawContentInStep") + beego.Router("/api/review/proj/submit", &controllers.ApiController{}, "PUT:SetSubmitStatus") + beego.Router("/api/review/proj/submit", &controllers.ApiController{}, "DELETE:DeleteSubmit") + + // assignment + beego.Router("/api/review/proj/user", &controllers.ApiController{}, "GET:GetUserAssignments") + beego.Router("/api/review/proj/assign", &controllers.ApiController{}, "POST:MakeOneAssignment") + beego.Router("/api/review/proj/assign", &controllers.ApiController{}, "GET:GetProjectAssignments") + beego.Router("/api/review/proj/assign", &controllers.ApiController{}, "DELETE:DeleteAssignment") + beego.Router("/api/review/proj/assign", &controllers.ApiController{}, "PATCH:ChangeAssignment") + + // file + beego.Router("/api/review/file", &controllers.ApiController{}, "POST:UploadFile") + beego.Router("/api/review/file/info", &controllers.ApiController{}, "GET:GetFileInfo") + beego.Router("/api/review/file/search", &controllers.ApiController{}, "POST:SearchFiles") + beego.Router("/api/review/file", &controllers.ApiController{}, "DELETE:DeleteFile") + + // query + beego.Router("/api/review/query/proj", &controllers.ApiController{}, "POST:GetProjectList") + beego.Router("/api/qbank/query/t_question", &controllers.ApiController{}, "POST:GetTempQuestionList") + beego.Router("/api/review/query/user", &controllers.ApiController{}, "POST:GetUserList") + + // qbank + // question + beego.Router("/api/qbank/question", &controllers.ApiController{}, "POST:CreateNewQuestion") + beego.Router("/api/qbank/question", &controllers.ApiController{}, "PUT:UpdateQuestion") + beego.Router("/api/qbank/question/comment", &controllers.ApiController{}, "POST:AddQuestionComment") + beego.Router("/api/qbank/question/trace", &controllers.ApiController{}, "GET:TraceQuestionVersion") + beego.Router("/api/qbank/question/finish", &controllers.ApiController{}, "GET:FinishTempQuestion") + beego.Router("/api/qbank/question/user_t", &controllers.ApiController{}, "GET:GetUserTempQuestions") + beego.Router("/api/qbank/question/user_f", &controllers.ApiController{}, "GET:GetUserFinalQuestions") + beego.Router("/api/qbank/question/proj_t", &controllers.ApiController{}, "GET:GetProjectTempQuestions") + beego.Router("/api/qbank/question/proj_f", &controllers.ApiController{}, "GET:GetProjectFinalQuestions") + + // testpaper + beego.Router("/api/qbank/testpaper", &controllers.ApiController{}, "POST:CreateNewTestpaper") + beego.Router("/api/qbank/testpaper", &controllers.ApiController{}, "PUT:UpdateTestpaper") + beego.Router("/api/qbank/testpaper/temp", &controllers.ApiController{}, "DELETE:DeleteTempTestpaper") + beego.Router("/api/qbank/testpaper/comment", &controllers.ApiController{}, "POST:AddTestpaperComment") + beego.Router("/api/qbank/testpaper/trace", &controllers.ApiController{}, "GET:TraceTestpaperVersion") + beego.Router("/api/qbank/testpaper/finish", &controllers.ApiController{}, "GET:FinishTempTestpaper") + beego.Router("/api/qbank/testpaper/user_t", &controllers.ApiController{}, "GET:GetUserTempTestpaper") + beego.Router("/api/qbank/testpaper/user_t", &controllers.ApiController{}, "GET:GetUserTempTestpaper") + beego.Router("/api/qbank/testpaper/user_f", &controllers.ApiController{}, "GET:GetUserFinalTestpaper") + beego.Router("/api/qbank/testpaper/proj_t", &controllers.ApiController{}, "GET:GetProjectTempTestpaper") + beego.Router("/api/qbank/testpaper/proj_f", &controllers.ApiController{}, "GET:GetProjectFinalTestpaper") +}