package models import ( "net/http" "strings" "time" "forge.grandlyon.com/apoyen/elections/internal/auth" "github.com/jinzhu/gorm" // Needed for sqlite _ "github.com/jinzhu/gorm/dialects/sqlite" ) // DataHandler init a gorm DB an presents API handlers type DataHandler struct { db *gorm.DB } // ErrorIDDoesNotExist = "id does not exist" with 404 http.StatusNotFound const ErrorIDDoesNotExist = "id does not exist" // ErrorIDIsMissing = "id is missing" with 404 http.StatusNotFound const ErrorIDIsMissing = "id is missing" // ErrorCannotAccessRessource = "You can not access this ressource" with 403 http.StatusForbidden const ErrorCannotAccessRessource = "You can not access this ressource" // ErrorRoleOfLoggedUser = "Could not get role of logged user" with 500 http.StatusInternalServerError const ErrorRoleOfLoggedUser = "Could not get role of logged user" // ErrorNotAuthorizeMethodOnRessource = "You're not authorize to execute this method on this ressource." with 405 http.StatusMethodNotAllowed const ErrorNotAuthorizeMethodOnRessource = "You're not authorize to execute this method on this ressource." // ErrorParentNotFound = "Could not get the parent associated to the object" with 500 http.StatusInternalServerError const ErrorParentNotFound = "Could not get the parent associated to the object" // Election represent an election divided in areas with 1 or several rounds type Election struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` Name string BallotType string Areas []Area Rounds []Round } // Area represent an area of an election divided in one or several Sections type Area struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` ElectionID uint Name string SeatNumber uint MapID string Sections []Section } // Section represent a section of an area divided in 1 or several Desks type Section struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` AreaID uint Name string MapID string Desks []Desk } // Desk represent a Desk office to vote from a section with the number of subscribed. It can be set to be a witness desk type Desk struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` SectionID uint Name string WitnessDesk bool Subscribed uint DeskRounds []DeskRound } // 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 CandidateLists []CandidateList } // Capturer is a user who can capture the results on the desks he is affected type Capturer struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` UserID int `gorm:"not null;unique"` Name string DeskRounds []DeskRound `gorm:"many2many:capturer_deskrounds;"` } // Parameter save the parameter for a round type Parameter struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` CountBlankAndNull bool ShowOnlyCompleted bool ShowMap bool } // Round represent a round for an election type Round struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` ElectionID uint Parameter Parameter Date string Round uint DeskRounds []DeskRound CandidateLists []CandidateList } // DeskRound is a duplicate instance of a Desk to save the result for a round type DeskRound struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` RoundID uint DeskID uint Capturers []Capturer `gorm:"many2many:capturer_deskrounds;"` Completed bool DateCompletion time.Time Validated bool Votes []Vote } // CandidateList is a list presented in an Area on an election type CandidateList struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` PartyID uint RoundID uint Area Area `gorm:"foreignkey:AreaRefer"` Name string Candidates []Candidate Votes []Vote } // Candidate is a candiate presented on a list type Candidate struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` CandidateListID uint FullName string Rank uint CommunityCounseller bool Birthdate time.Time PotentialIncompatibility bool Refused bool Removed bool } // Vote represent the number of voice between a CanidateList and a Desk (+blank and null) type Vote struct { ID uint `gorm:"primary_key"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` DeskRoundID uint CandidateListID uint VoiceNumber uint Blank bool Null bool } // NewDataHandler init a DataHandler and returns a pointer to it func NewDataHandler() *DataHandler { db, err := gorm.Open("sqlite3", "./data/test.db") if err != nil { panic("failed to connect database") } db.LogMode(true) // Migrate the schema db.AutoMigrate(&Capturer{}) db.AutoMigrate(&Election{}) db.AutoMigrate(&Area{}) db.AutoMigrate(&Section{}) db.AutoMigrate(&Desk{}) db.AutoMigrate(&Round{}) db.AutoMigrate(&DeskRound{}) db.AutoMigrate(&Party{}) db.AutoMigrate(&CandidateList{}) db.AutoMigrate(&Candidate{}) db.AutoMigrate(&Vote{}) db.AutoMigrate(&Parameter{}) return &DataHandler{db: db} } // ProcessAPI redirect API call to DataHandler to each correct API func func (d *DataHandler) ProcessAPI(w http.ResponseWriter, r *http.Request) { api := strings.Split(strings.TrimPrefix(r.URL.Path, "/api/"), "/")[0] switch api { case "Capturer": d.handleCapturer(w, r) case "Election": d.handleElection(w, r) case "Area": d.handleArea(w, r) case "Section": d.handleSection(w, r) case "Desk": d.handleDesk(w, r) case "Round": d.handleRound(w, r) case "DeskRound": d.handleDeskRound(w, r) case "CapturerDeskRound": d.handleCapturerDeskRound(w, r) case "Party": d.handleParty(w, r) } } func (d *DataHandler) getLoggedUser(w http.ResponseWriter, r *http.Request) interface{} { user := auth.GetLoggedUserTechnical(w, r) if user.Role != "" && (user.Role == "CAPTURER") { var o Capturer if err := d.db.Where("user_id = ?", user.ID).First(&o).Error; err != nil { o := Capturer{UserID: user.ID, Name: user.Login} d.db.Create(&o) d.db.First(&o, user.ID) return o } return o } return nil }