server/admin/api/claim.go

302 lines
9.0 KiB
Go

package api
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"path"
"time"
"srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
)
func init() {
router.GET("/api/teams/:tid/issue.json", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) {
return team.MyIssueFile()
})))
// Tasks
router.GET("/api/claims", apiHandler(getClaims))
router.POST("/api/claims", apiHandler(newClaim))
router.DELETE("/api/claims", apiHandler(clearClaims))
router.GET("/api/teams/:tid/claims", apiHandler(teamHandler(getTeamClaims)))
router.GET("/api/exercices/:eid/claims", apiHandler(exerciceHandler(getExerciceClaims)))
router.GET("/api/themes/:thid/exercices/:eid/claims", apiHandler(exerciceHandler(getExerciceClaims)))
router.GET("/api/claims/:cid", apiHandler(claimHandler(showClaim)))
router.PUT("/api/claims/:cid", apiHandler(claimHandler(updateClaim)))
router.POST("/api/claims/:cid", apiHandler(claimHandler(addClaimDescription)))
router.DELETE("/api/claims/:cid", apiHandler(claimHandler(deleteClaim)))
router.GET("/api/claims/:cid/last_update", apiHandler(claimHandler(getClaimLastUpdate)))
router.PUT("/api/claims/:cid/descriptions", apiHandler(claimHandler(updateClaimDescription)))
// Assignees
router.GET("/api/claims-assignees", apiHandler(getAssignees))
router.POST("/api/claims-assignees", apiHandler(newAssignee))
router.GET("/api/claims-assignees/:aid", apiHandler(claimAssigneeHandler(showClaimAssignee)))
router.PUT("/api/claims-assignees/:aid", apiHandler(claimAssigneeHandler(updateClaimAssignee)))
router.DELETE("/api/claims-assignees/:aid", apiHandler(claimAssigneeHandler(deleteClaimAssignee)))
}
func getClaims(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.GetClaims()
}
func getTeamClaims(team fic.Team, _ []byte) (interface{}, error) {
return team.GetClaims()
}
func getExerciceClaims(exercice fic.Exercice, _ []byte) (interface{}, error) {
return exercice.GetClaims()
}
func getClaimLastUpdate(claim fic.Claim, _ []byte) (interface{}, error) {
return claim.GetLastUpdate()
}
type ClaimExported struct {
Id int64 `json:"id"`
Subject string `json:"subject"`
IdTeam *int64 `json:"id_team"`
Team *fic.Team `json:"team"`
IdExercice *int64 `json:"id_exercice"`
Exercice *fic.Exercice `json:"exercice"`
IdAssignee *int64 `json:"id_assignee"`
Assignee *fic.ClaimAssignee `json:"assignee"`
Creation time.Time `json:"creation"`
LastUpdate time.Time `json:"last_update"`
State string `json:"state"`
Priority string `json:"priority"`
Descriptions []fic.ClaimDescription `json:"descriptions"`
}
func showClaim(claim fic.Claim, _ []byte) (interface{}, error) {
var e ClaimExported
var err error
if e.Team, err = claim.GetTeam(); err != nil {
return nil, fmt.Errorf("Unable to find associated team: %w", err)
}
if e.Exercice, err = claim.GetExercice(); err != nil {
return nil, fmt.Errorf("Unable to find associated exercice: %w", err)
}
if e.Assignee, err = claim.GetAssignee(); err != nil {
return nil, fmt.Errorf("Unable to find associated assignee: %w", err)
}
if e.Descriptions, err = claim.GetDescriptions(); err != nil {
return nil, fmt.Errorf("Unable to find claim's descriptions: %w", err)
}
e.LastUpdate = e.Creation
for _, d := range e.Descriptions {
if d.Date.After(e.LastUpdate) {
e.LastUpdate = d.Date
}
}
e.Id = claim.Id
e.IdAssignee = claim.IdAssignee
e.IdTeam = claim.IdTeam
e.IdExercice = claim.IdExercice
e.Subject = claim.Subject
e.Creation = claim.Creation
e.State = claim.State
e.Priority = claim.Priority
return e, nil
}
type ClaimUploaded struct {
fic.Claim
Whoami *int64 `json:"whoami"`
}
func newClaim(_ httprouter.Params, body []byte) (interface{}, error) {
var uc ClaimUploaded
if err := json.Unmarshal(body, &uc); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err)
}
if uc.Subject == "" {
return nil, errors.New("Claim's subject cannot be empty.")
}
var t *fic.Team
if uc.IdTeam != nil {
if team, err := fic.GetTeam(*uc.IdTeam); err != nil {
return nil, fmt.Errorf("Unable to get associated team: %w", err)
} else {
t = &team
}
} else {
t = nil
}
var e *fic.Exercice
if uc.IdExercice != nil {
if exercice, err := fic.GetExercice(*uc.IdExercice); err != nil {
return nil, fmt.Errorf("Unable to get associated exercice: %w", err)
} else {
e = &exercice
}
} else {
e = nil
}
var a *fic.ClaimAssignee
if uc.IdAssignee != nil {
if assignee, err := fic.GetAssignee(*uc.IdAssignee); err != nil {
return nil, fmt.Errorf("Unable to get associated assignee: %w", err)
} else {
a = &assignee
}
} else {
a = nil
}
if uc.Priority == "" {
uc.Priority = "medium"
}
return fic.NewClaim(uc.Subject, t, e, a, uc.Priority)
}
func clearClaims(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.ClearClaims()
}
func generateTeamIssuesFile(team fic.Team) error {
if my, err := team.MyIssueFile(); err != nil {
return fmt.Errorf("Unable to generate issue FILE (tid=%d): %w", team.Id, err)
} else if j, err := json.Marshal(my); err != nil {
return fmt.Errorf("Unable to encode issues' file JSON: %w", err)
} else if err = ioutil.WriteFile(path.Join(TeamsDir, fmt.Sprintf("%d", team.Id), "issues.json"), j, 0644); err != nil {
return fmt.Errorf("Unable to write issues' file: %w", err)
}
return nil
}
func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
var ud fic.ClaimDescription
if err := json.Unmarshal(body, &ud); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err)
}
if assignee, err := fic.GetAssignee(ud.IdAssignee); err != nil {
return nil, fmt.Errorf("Unable to get associated assignee: %w", err)
} else if description, err := claim.AddDescription(ud.Content, assignee, ud.Publish); err != nil {
return nil, fmt.Errorf("Unable to add description: %w", err)
} else {
if team, _ := claim.GetTeam(); team != nil {
err = generateTeamIssuesFile(*team)
}
return description, err
}
}
func updateClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
var ud fic.ClaimDescription
if err := json.Unmarshal(body, &ud); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err)
}
if _, err := ud.Update(); err != nil {
return nil, fmt.Errorf("Unable to update description: %w", err)
} else {
if team, _ := claim.GetTeam(); team != nil {
err = generateTeamIssuesFile(*team)
}
return ud, err
}
}
func updateClaim(claim fic.Claim, body []byte) (interface{}, error) {
var uc ClaimUploaded
if err := json.Unmarshal(body, &uc); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err)
}
uc.Id = claim.Id
if _, err := uc.Update(); err != nil {
return nil, fmt.Errorf("Unable to update claim: %w", err)
} else {
if claim.State != uc.State {
if uc.Whoami != nil {
if assignee, err := fic.GetAssignee(*uc.Whoami); err == nil {
claim.AddDescription(fmt.Sprintf("%s a changé l'état de la tâche vers %q (était %q).", assignee.Name, uc.State, claim.State), assignee, true)
}
}
}
if claim.IdAssignee != uc.IdAssignee {
if uc.Whoami != nil {
if whoami, err := fic.GetAssignee(*uc.Whoami); err == nil {
if uc.IdAssignee != nil {
if assignee, err := fic.GetAssignee(*uc.IdAssignee); err == nil {
if assignee.Id != whoami.Id {
claim.AddDescription(fmt.Sprintf("%s a assigné la tâche à %s.", whoami.Name, assignee.Name), whoami, false)
} else {
claim.AddDescription(fmt.Sprintf("%s s'est assigné la tâche.", assignee.Name), whoami, false)
}
}
} else {
claim.AddDescription(fmt.Sprintf("%s a retiré l'attribution de la tâche.", whoami.Name), whoami, false)
}
}
}
}
if team, _ := claim.GetTeam(); team != nil {
err = generateTeamIssuesFile(*team)
}
return uc, err
}
}
func deleteClaim(claim fic.Claim, _ []byte) (interface{}, error) {
return claim.Delete()
}
func getAssignees(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.GetAssignees()
}
func showClaimAssignee(assignee fic.ClaimAssignee, _ []byte) (interface{}, error) {
return assignee, nil
}
func newAssignee(_ httprouter.Params, body []byte) (interface{}, error) {
var ua fic.ClaimAssignee
if err := json.Unmarshal(body, &ua); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err)
}
return fic.NewClaimAssignee(ua.Name)
}
func updateClaimAssignee(assignee fic.ClaimAssignee, body []byte) (interface{}, error) {
var ua fic.ClaimAssignee
if err := json.Unmarshal(body, &ua); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err)
}
ua.Id = assignee.Id
if _, err := ua.Update(); err != nil {
return nil, fmt.Errorf("Unable to update claim assignee: %w", err)
} else {
return ua, nil
}
}
func deleteClaimAssignee(assignee fic.ClaimAssignee, _ []byte) (interface{}, error) {
return assignee.Delete()
}