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() }