Skip to content
Snippets Groups Projects
models.go 7.33 KiB
Newer Older
  • Learn to ignore specific revisions
  • Alexis Poyen's avatar
    Alexis Poyen committed
    package models
    
    import (
    	"net/http"
    	"strings"
    
    	"time"
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    
    
    	"forge.grandlyon.com/apoyen/elections/internal/auth"
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	"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
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    const ErrorIDDoesNotExist = "id does not exist"
    
    
    // ErrorIDIsMissing = "id is missing" with 404 http.StatusNotFound
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    const ErrorIDIsMissing = "id is missing"
    
    
    // ErrorCannotAccessRessource = "You can not access this ressource" with 403 http.StatusForbidden
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    const ErrorCannotAccessRessource = "You can not access this ressource"
    
    
    // ErrorRoleOfLoggedUser = "Could not get role of logged user" with 500 http.StatusInternalServerError
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    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
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    const ErrorNotAuthorizeMethodOnRessource = "You're not authorize to execute this method on this ressource."
    
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    // 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 {
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	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
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	Subscribed  uint
    
    	DeskRounds  []DeskRound
    
    // Party represent a political party or tendance
    
    type Party struct {
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	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
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    // 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{})
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	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":
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	case "Election":
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	case "Area":
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	case "Section":
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	case "Desk":
    
    	case "Round":
    		d.handleRound(w, r)
    
    	case "DeskRound":
    		d.handleDeskRound(w, r)
    
    	case "CapturerDeskRound":
    		d.handleCapturerDeskRound(w, r)
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	case "Party":
    		d.handleParty(w, r)
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	}
    
    }
    
    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
    	}
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    
    	return nil
    }