You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
6.8 KiB
Go
304 lines
6.8 KiB
Go
// This package contains the database interface and an in memory implementation.
|
|
//
|
|
// For the in-memory implementation see the "NewInMemoryStore()" function.
|
|
package db
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// ErrAlreadyExists is the error thrown from Store functions when an entity already exists.
|
|
var ErrAlreadyExists = errors.New(`object already exists in database`)
|
|
|
|
// ErrDoesntExist is the error thrown from Store functions when an entity doesn't exist.
|
|
var ErrDoesntExist = errors.New(`object doesn't exist in database`)
|
|
|
|
// Entities
|
|
|
|
// type FrontendUser struct {
|
|
// Anonymous bool `json:"anonymous,omitempty"`
|
|
// ID string `json:"id,omitempty"`
|
|
// Permissions []string `json:"permissions,omitempty"`
|
|
// }
|
|
|
|
// User represents a user in the database.
|
|
type User struct {
|
|
ID string `json:"id"`
|
|
Permissions []string `json:"permissions"`
|
|
|
|
// passwordSaltHash string
|
|
}
|
|
|
|
// HasPermission checks if the user has a specific permission.
|
|
func (user User) HasPermission(neededPerm string) bool {
|
|
for _, perm := range user.Permissions {
|
|
if perm == neededPerm {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Room represents a room in the database, a room has an id, a name and a collection of seatIDs of this room.
|
|
type Room struct {
|
|
ID string `json:"id"`
|
|
SeatIDs []string `json:"seatIds"`
|
|
|
|
// gridRows, gridCols int
|
|
}
|
|
|
|
// Seat represents a seat in the database, it belongs to a single room and can be free or occupied by some user (referenced by userID).
|
|
type Seat struct {
|
|
ID string `json:"id"`
|
|
RoomID string `json:"roomId"`
|
|
|
|
// OccupiedBy is an empty list or a singleton of a userID
|
|
OccupiedBy []string `json:"occupiedBy"`
|
|
|
|
// x, y, w, h int
|
|
}
|
|
|
|
// type FrontendSeat struct {
|
|
// ID string `json:"id"`
|
|
// RoomID string `json:"roomId"`
|
|
|
|
// // OccupiedBy is an empty list or a singleton of a userID
|
|
// OccupiedBy *FrontendUser `json:"occupiedBy"`
|
|
|
|
// DiagramRect struct {
|
|
// X int `json:"x"`
|
|
// Y int `json:"y"`
|
|
// Width int `json:"width"`
|
|
// Height int `json:"height"`
|
|
// } `json:"diagramRect"`
|
|
// }
|
|
|
|
//
|
|
// Database Interfaces
|
|
//
|
|
|
|
// Store is the main interface for interacting with database implementations, for now the only implementation is "memDB".
|
|
type Store interface {
|
|
CreateUser(user *User) error
|
|
CreateRoom(room *Room) error
|
|
CreateSeat(seat *Seat) error
|
|
|
|
DeleteUser(user *User) error
|
|
DeleteRoom(room *Room) error
|
|
DeleteSeat(seat *Seat) error
|
|
|
|
GetUser(userID string) (*User, error)
|
|
GetRoom(roomID string) (*Room, error)
|
|
GetSeat(seatID string) (*Seat, error)
|
|
|
|
GetRooms() ([]string, error)
|
|
|
|
GetRoomOccupiedSeats(roomID string) ([]string, error)
|
|
GetRoomFreeSeats(roomID string) ([]string, error)
|
|
|
|
GetUserSeat(userID string) ([]string, error)
|
|
|
|
OccupySeat(seatID, userID string) error
|
|
FreeSeat(seatID string) error
|
|
}
|
|
|
|
// TODO: Create an SQLite implementation
|
|
|
|
// memDB is the first Store implementation used for testing.
|
|
type memDB struct {
|
|
// FIXME: Giusto per la cronaca fare le modifiche in questo modo alle mappe non è per niente thread safe, servirebbe come minimo usare un mutex per quando si scrive su una di queste variabili
|
|
// mutex *sync.Mutex
|
|
|
|
users map[string]*User
|
|
rooms map[string]*Room
|
|
seats map[string]*Seat
|
|
}
|
|
|
|
// NewInMemoryStore creates an instance of memDB hidden behind the Store interface.
|
|
func NewInMemoryStore() Store {
|
|
db := &memDB{
|
|
make(map[string]*User),
|
|
make(map[string]*Room),
|
|
make(map[string]*Seat),
|
|
}
|
|
|
|
db.rooms["aula-stud"] = &Room{
|
|
ID: "aula-stud",
|
|
SeatIDs: []string{},
|
|
}
|
|
|
|
for i := 1; i <= 11; i++ {
|
|
seatID := fmt.Sprintf(`aula-stud/posto-%d`, i)
|
|
|
|
db.rooms["aula-stud"].SeatIDs = append(db.rooms["aula-stud"].SeatIDs, seatID)
|
|
db.seats[seatID] = &Seat{
|
|
ID: seatID,
|
|
RoomID: "aula-stud",
|
|
OccupiedBy: []string{},
|
|
}
|
|
}
|
|
|
|
db.seats["aula-stud/posto-7"].OccupiedBy = []string{"aziis98"}
|
|
db.seats["aula-stud/posto-1"].OccupiedBy = []string{"bachoseven"}
|
|
|
|
db.users["aziis98"] = &User{
|
|
ID: "aziis98",
|
|
Permissions: []string{"admin"},
|
|
}
|
|
|
|
db.users["bachoseven"] = &User{
|
|
ID: "bachoseven",
|
|
Permissions: []string{"admin"},
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
//
|
|
// memDB Implementation
|
|
//
|
|
|
|
func (db *memDB) CreateUser(user *User) error {
|
|
if _, present := db.users[user.ID]; present {
|
|
return ErrAlreadyExists
|
|
}
|
|
db.users[user.ID] = user
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) CreateRoom(room *Room) error {
|
|
if _, present := db.rooms[room.ID]; present {
|
|
return ErrAlreadyExists
|
|
}
|
|
db.rooms[room.ID] = room
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) CreateSeat(seat *Seat) error {
|
|
if _, present := db.seats[seat.ID]; present {
|
|
return ErrAlreadyExists
|
|
}
|
|
db.seats[seat.ID] = seat
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) DeleteUser(user *User) error {
|
|
if _, present := db.users[user.ID]; !present {
|
|
return ErrDoesntExist
|
|
}
|
|
|
|
delete(db.users, user.ID)
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) DeleteRoom(room *Room) error {
|
|
if _, present := db.rooms[room.ID]; !present {
|
|
return ErrDoesntExist
|
|
}
|
|
|
|
delete(db.rooms, room.ID)
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) DeleteSeat(seat *Seat) error {
|
|
if _, present := db.seats[seat.ID]; !present {
|
|
return ErrDoesntExist
|
|
}
|
|
|
|
delete(db.seats, seat.ID)
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) GetUser(userID string) (*User, error) {
|
|
user, present := db.users[userID]
|
|
if !present {
|
|
return nil, fmt.Errorf(`no such user "%s"`, userID)
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func (db *memDB) GetRoom(roomID string) (*Room, error) {
|
|
room, present := db.rooms[roomID]
|
|
if !present {
|
|
return nil, fmt.Errorf(`no such room "%s"`, roomID)
|
|
}
|
|
|
|
return room, nil
|
|
}
|
|
|
|
func (db *memDB) GetSeat(seatID string) (*Seat, error) {
|
|
seat, present := db.seats[seatID]
|
|
if !present {
|
|
return nil, fmt.Errorf(`no such seat "%s"`, seatID)
|
|
}
|
|
|
|
return seat, nil
|
|
}
|
|
|
|
func (db *memDB) GetRooms() ([]string, error) {
|
|
roomIDs := []string{}
|
|
|
|
for roomID := range db.rooms {
|
|
roomIDs = append(roomIDs, roomID)
|
|
}
|
|
|
|
return roomIDs, nil
|
|
}
|
|
|
|
func (db *memDB) GetRoomOccupiedSeats(roomID string) ([]string, error) {
|
|
room, err := db.GetRoom(roomID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
seats := []string{}
|
|
for _, seatID := range room.SeatIDs {
|
|
seat := db.seats[seatID]
|
|
if len(seat.OccupiedBy) == 1 {
|
|
seats = append(seats, seatID)
|
|
}
|
|
}
|
|
|
|
return seats, nil
|
|
}
|
|
|
|
func (db *memDB) GetRoomFreeSeats(roomID string) ([]string, error) {
|
|
room, err := db.GetRoom(roomID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
seats := []string{}
|
|
for _, seatID := range room.SeatIDs {
|
|
seat := db.seats[seatID]
|
|
if len(seat.OccupiedBy) == 0 {
|
|
seats = append(seats, seatID)
|
|
}
|
|
}
|
|
|
|
return seats, nil
|
|
}
|
|
|
|
func (db *memDB) GetUserSeat(userID string) ([]string, error) {
|
|
for _, seat := range db.seats {
|
|
if len(seat.OccupiedBy) > 0 && seat.OccupiedBy[0] == userID {
|
|
return []string{userID}, nil
|
|
}
|
|
}
|
|
|
|
return []string{}, nil
|
|
}
|
|
|
|
func (db *memDB) OccupySeat(seatID, userID string) error {
|
|
db.seats[seatID].OccupiedBy = []string{userID}
|
|
return nil
|
|
}
|
|
|
|
func (db *memDB) FreeSeat(seatID string) error {
|
|
db.seats[seatID].OccupiedBy = []string{}
|
|
return nil
|
|
}
|