diff --git a/internal/models/models.go b/internal/models/models.go index 2788b429c8d1be7fd07cb7ec603bc6cb53b86fc0..6f0f1150a0d93cf1099c13f2ee0725e5ee893885 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -87,13 +87,13 @@ type Desk struct { // Party represent a political party or tendance type Party struct { - ID uint `gorm:"primary_key"` - CreatedAt time.Time `json:"-"` - UpdatedAt time.Time `json:"-"` - DeletedAt *time.Time `json:"-"` - Name string - Color string - CandidateList []CandidateList + ID uint `gorm:"primary_key"` + CreatedAt time.Time `json:"-"` + UpdatedAt time.Time `json:"-"` + DeletedAt *time.Time `json:"-"` + Name string + Color string + CandidateLists []CandidateList } // Capturer is a user who can capture the results on the desks he is affected @@ -234,6 +234,8 @@ func (d *DataHandler) ProcessAPI(w http.ResponseWriter, r *http.Request) { d.handleDeskRound(w, r) case "CapturerDeskRound": d.handleCapturerDeskRound(w, r) + case "Party": + d.handleParty(w, r) } } diff --git a/internal/models/party.go b/internal/models/party.go new file mode 100644 index 0000000000000000000000000000000000000000..9036b57797c69eb6b68963c41105d26af9cad665 --- /dev/null +++ b/internal/models/party.go @@ -0,0 +1,115 @@ +package models + +import ( + "encoding/json" + "net/http" + "strconv" + "strings" + + "forge.grandlyon.com/apoyen/elections/internal/auth" +) + +func (d *DataHandler) handleParty(w http.ResponseWriter, r *http.Request) { + id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/Party/")) + switch method := r.Method; method { + case "GET": + switch auth.GetLoggedUserTechnical(w, r).Role { + case "ADMIN", "CAPTURER", "VISUALIZER": + d.getParty(w, r, id) + default: + http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError) + } + case "POST": + switch auth.GetLoggedUserTechnical(w, r).Role { + case "ADMIN": + d.postParty(w, r) + case "CAPTURER", "VISUALIZER": + http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed) + default: + http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError) + } + + case "PUT": + switch auth.GetLoggedUserTechnical(w, r).Role { + case "ADMIN": + d.putParty(w, r, id) + case "CAPTURER", "VISUALIZER": + http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed) + default: + http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError) + } + case "DELETE": + switch auth.GetLoggedUserTechnical(w, r).Role { + case "ADMIN": + d.deleteParty(w, r, id) + case "CAPTURER", "VISUALIZER": + http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed) + default: + http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError) + } + default: + http.Error(w, "method not allowed", 400) + } +} + +func (d *DataHandler) getParty(w http.ResponseWriter, r *http.Request, id int) { + if id != 0 { + var o Party + if err := d.db.Preload("CandidateLists").First(&o, id).Error; err != nil { + http.Error(w, ErrorIDIsMissing, http.StatusNotFound) + return + } + json.NewEncoder(w).Encode(o) + } else { + var o []Party + d.db.Preload("CandidateLists").Find(&o) + json.NewEncoder(w).Encode(o) + } +} + +func (d *DataHandler) postParty(w http.ResponseWriter, r *http.Request) { + var o Party + err := json.NewDecoder(r.Body).Decode(&o) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + d.db.Create(&o) + d.db.Last(&o) + json.NewEncoder(w).Encode(o) + +} + +func (d *DataHandler) putParty(w http.ResponseWriter, r *http.Request, id int) { + var o Party + if err := d.db.Preload("CandidateLists").First(&o, id).Error; err != nil { + http.Error(w, ErrorIDIsMissing, http.StatusNotFound) + return + } + var party Party + err := json.NewDecoder(r.Body).Decode(&party) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + o.Name = party.Name + o.Color = party.Color + d.db.Save(&o) + json.NewEncoder(w).Encode(o) + +} + +func (d *DataHandler) deleteParty(w http.ResponseWriter, r *http.Request, id int) { + if id != 0 { + var o Party + if err := d.db.Preload("CandidateLists").First(&o, id).Error; err != nil { + http.Error(w, ErrorIDIsMissing, http.StatusNotFound) + return + } + + d.db.Delete(&o) + } else { + http.Error(w, ErrorIDIsMissing, http.StatusNotFound) + } +} diff --git a/internal/rootmux/admin_test.go b/internal/rootmux/admin_test.go index 64b1c739a43020dc9d79e2eec04265c46ab9da91..68e96e5abc3fedb8fc397153beebe1bbfd3194d8 100644 --- a/internal/rootmux/admin_test.go +++ b/internal/rootmux/admin_test.go @@ -92,9 +92,19 @@ func AdminTests(t *testing.T) { // Remove DeskRound to capturer do("DELETE", "/api/CapturerDeskRound/1", xsrfHeader, `{"CapturerID":1,"DeskRoundID":1}`, 200, ``) - // Update a DeskRound should be done after desk completion by capturing votes - // do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":true,"Votes":[]}`) + // Create a Party + do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":null}`) + // Get a Party + do("GET", "/api/Party/1", xsrfHeader, ``, 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}`) + // Get Parties + do("GET", "/api/Party/", xsrfHeader, ``, 200, `[{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}]`) + // Update a Party + do("PUT", "/api/Party/1", xsrfHeader, `{"ID":1,"Name":"MyBigParty","Color":"#000000"}`, 200, `{"ID":1,"Name":"MyBigParty","Color":"#000000","CandidateLists":[]}`) + // TODO Update a DeskRound to Validated=true can only be done when votes are captured + + // Delete a Party + do("DELETE", "/api/Party/1", xsrfHeader, ``, 200, ``) // Delete a Round do("DELETE", "/api/Round/1", xsrfHeader, ``, 200, ``) // Delete a desk diff --git a/internal/rootmux/capturer_test.go b/internal/rootmux/capturer_test.go index 2de600a1517f14a07cb3a7cf8bc6a07ae7fe1a89..11b4a515dad570b1389bee26ece16723890da354 100644 --- a/internal/rootmux/capturer_test.go +++ b/internal/rootmux/capturer_test.go @@ -91,14 +91,27 @@ func CapturerTests(t *testing.T) { do("DELETE", "/api/Round/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`) // Create a DeskRound should fail with 400 - do("POST", "/api/DeskRound", xsrfHeader, `{"Test":1,"Date":"2020-06-28","Round":1}`, 400, `method not allowed`) + do("POST", "/api/DeskRound", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 400, `method not allowed`) // Get a DeskRound do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}`) // Get DeskRounds do("GET", "/api/DeskRound/", xsrfHeader, ``, 200, `[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}]`) + // Update a desk should fail with 405 + do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 405, `You're not authorize to execute this method on this ressource.`) // Delete a DeskRound should fail with 400 do("DELETE", "/api/DeskRound/1", xsrfHeader, ``, 400, `method not allowed`) + // Create a Party should fail with 405 + do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 405, `You're not authorize to execute this method on this ressource.`) + // Get a party + do("GET", "/api/Party/1", xsrfHeader, "", 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}`) + // Get all the parties + do("GET", "/api/Party/", xsrfHeader, "", 200, `[{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}]`) + // Update a party should fail with 405 + do("PUT", "/api/Party/1", xsrfHeader, `{"ID":1,"Name":"MyBigParty","Color":"#000000"}`, 405, `You're not authorize to execute this method on this ressource.`) + // Delete a party should fail with 405 + do("DELETE", "/api/Party/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`) + // Add deskround to capturer should fail with 405 do("POST", "/api/CapturerDeskRound", xsrfHeader, `{"CapturerID":1,"DeskRoundID":1}`, 405, `You're not authorize to execute this method on this ressource.`) // Remove DeskRound to capturer diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go index c8dfb25d5fde42419d09056d66d9c4af2e8561f7..11becea427954e407b88a8685ce2243cb37dcdb3 100644 --- a/internal/rootmux/rootmux_test.go +++ b/internal/rootmux/rootmux_test.go @@ -101,6 +101,8 @@ func appTests(t *testing.T) { // Verify that a DeskRound can't be validated witout being completed do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 500, `Le bureau doit être complété avant de le valider`) + // TODO After capturing all votes for a DeskRound, it should be mark as completed + // Verify that on Desk deletion deskRounds are deleted do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`) do("DELETE", "/api/Desk/1", xsrfHeader, ``, 200, ``) @@ -216,6 +218,7 @@ func resetDataWithData(t *testing.T) { do("POST", "/api/Section", xsrfHeader, `{"AreaID":1,"Name":"Section 1","MapID":"1"}`, 200, `{"ID":1,"AreaID":1,"Name":"Section 1","MapID":"1","Desks":null}`) do("POST", "/api/Desk", xsrfHeader, `{"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587}`, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":null}`) do("POST", "/api/Round", xsrfHeader, `{"ElectionID":1,"Date":"2020-06-28","Round":1}`, 200, `{"ID":1,"ElectionID":1,"Parameter":{"ID":0,"CountBlankAndNull":false,"ShowOnlyCompleted":false,"ShowMap":false},"Date":"2020-06-28","Round":1,"DeskRounds":null,"CandidateLists":null}`) + do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":null}`) } do("POST", "/Login", noH, `{"login": "admin","password": "password"}`, 200, "") init() diff --git a/internal/rootmux/visualizer_test.go b/internal/rootmux/visualizer_test.go index a36147f1b636ada67e491bb5610c11945e4cb6c0..e798698f5a2fa8a15fea7737dc7dc7a61f7597c3 100644 --- a/internal/rootmux/visualizer_test.go +++ b/internal/rootmux/visualizer_test.go @@ -78,14 +78,27 @@ func VisualizerTests(t *testing.T) { do("DELETE", "/api/Round/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`) // Create a DeskRound should fail with 400 - do("POST", "/api/DeskRound", xsrfHeader, `{"Test":1,"Date":"2020-06-28","Round":1}`, 400, `method not allowed`) + do("POST", "/api/DeskRound", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 400, `method not allowed`) // Get a DeskRound do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}`) // Get DeskRounds do("GET", "/api/DeskRound/", xsrfHeader, ``, 200, `[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}]`) + // Update a desk should fail with 405 + do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 405, `You're not authorize to execute this method on this ressource.`) // Delete a DeskRound should fail with 400 do("DELETE", "/api/DeskRound/1", xsrfHeader, ``, 400, `method not allowed`) + // Create a Party should fail with 405 + do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 405, `You're not authorize to execute this method on this ressource.`) + // Get a party + do("GET", "/api/Party/1", xsrfHeader, "", 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}`) + // Get all the parties + do("GET", "/api/Party/", xsrfHeader, "", 200, `[{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}]`) + // Update a party should fail with 405 + do("PUT", "/api/Party/1", xsrfHeader, `{"ID":1,"Name":"MyBigParty","Color":"#000000"}`, 405, `You're not authorize to execute this method on this ressource.`) + // Delete a party should fail with 405 + do("DELETE", "/api/Party/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`) + // Add deskround to capturer should fail with 405 do("POST", "/api/CapturerDeskRound", xsrfHeader, `{"CapturerID":1,"DeskRoundID":1}`, 405, `You're not authorize to execute this method on this ressource.`) // Remove DeskRound to capturer