first commit
This commit is contained in:
22
server/db/base.go
Normal file
22
server/db/base.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
//Base is
|
||||
type Base struct {
|
||||
ID string `sql:"type:uuid;primary_key" json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt *time.Time `gorm:"index" json:"deletedAt"`
|
||||
}
|
||||
|
||||
//BeforeCreate
|
||||
func (base *Base) BeforeCreate(tx *gorm.DB) error {
|
||||
tx.Statement.SetColumn("ID", uuid.NewV4().String())
|
||||
return nil
|
||||
}
|
||||
223
server/db/clarkson.go
Normal file
223
server/db/clarkson.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CanMigrate(connectionString string) (bool, interface{}, error) {
|
||||
|
||||
canInitialize, err := CanInitializeSystem()
|
||||
if !canInitialize {
|
||||
return canInitialize, nil, err
|
||||
}
|
||||
|
||||
cdb, err := gorm.Open(mysql.Open(connectionString), &gorm.Config{})
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
var usersCount, vehiclesCount, fuelCount int64
|
||||
tx := cdb.Table("Users").Count(&usersCount)
|
||||
if tx.Error != nil {
|
||||
return false, nil, tx.Error
|
||||
}
|
||||
tx = cdb.Table("Vehicles").Count(&vehiclesCount)
|
||||
if tx.Error != nil {
|
||||
return false, nil, tx.Error
|
||||
}
|
||||
tx = cdb.Table("Fuel").Count(&fuelCount)
|
||||
if tx.Error != nil {
|
||||
return false, nil, tx.Error
|
||||
}
|
||||
data := struct {
|
||||
Users int64 `json:"users"`
|
||||
Vehicles int64 `json:"vehicles"`
|
||||
Fillups int64 `json:"fillups"`
|
||||
}{
|
||||
Vehicles: vehiclesCount,
|
||||
Users: usersCount,
|
||||
Fillups: fuelCount,
|
||||
}
|
||||
|
||||
return true, data, nil
|
||||
}
|
||||
|
||||
func MigrateClarkson(connectionString string) (bool, error) {
|
||||
canInitialize, err := CanInitializeSystem()
|
||||
if !canInitialize {
|
||||
return canInitialize, err
|
||||
}
|
||||
|
||||
//dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
cdb, err := gorm.Open(mysql.Open(connectionString), &gorm.Config{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
/////Models
|
||||
type CUser struct {
|
||||
ID string `gorm:"column:id"`
|
||||
Email string `gorm:"column:email"`
|
||||
Username string `gorm:"column:username"`
|
||||
Password string `gorm:"column:password"`
|
||||
Admin bool `gorm:"column:admin"`
|
||||
FuelUnit int `gorm:"column:fuelUnit"`
|
||||
DistanceUnit int `gorm:"column:distanceUnit"`
|
||||
FuelConsumptionUnit int `gorm:"column:fuelConsumptionUnit"`
|
||||
CurrencyUnit int `gorm:"column:currencyUnit"`
|
||||
}
|
||||
|
||||
type CVehicle struct {
|
||||
ID string `gorm:"column:id"`
|
||||
User string
|
||||
Name string
|
||||
Registration string
|
||||
Make string
|
||||
Model string
|
||||
YearOfManufacture int `gorm:"column:yearOfManufacture"`
|
||||
Vin string
|
||||
EngineSizeCC int `gorm:"column:engineSizeCC"`
|
||||
FuelType int `gorm:"column:fuelType"`
|
||||
}
|
||||
|
||||
type CFuel struct {
|
||||
ID string `gorm:"column:id"`
|
||||
Vehicle string `gorm:"column:vehicle"`
|
||||
Date time.Time `gorm:"column:date"`
|
||||
FuelAmount float32 `gorm:"column:fuelAmount"`
|
||||
TotalCost float32 `gorm:"column:totalCost"`
|
||||
FuelUnitCost float32 `gorm:"column:fuelUnitCost"`
|
||||
OdometerReading int `gorm:"column:odometerReading"`
|
||||
Notes string `gorm:"column:notes"`
|
||||
FullTank bool `gorm:"column:fullTank"`
|
||||
MissedFillup bool `gorm:"column:missedFillUp"`
|
||||
}
|
||||
|
||||
distanceUnitMap := map[int]DistanceUnit{
|
||||
1: MILES,
|
||||
2: KILOMETERS,
|
||||
}
|
||||
|
||||
fuelTypeMap := map[int]FuelType{
|
||||
1: PETROL,
|
||||
2: DIESEL,
|
||||
3: ETHANOL,
|
||||
4: LPG,
|
||||
}
|
||||
|
||||
fuelUnitsMap := map[int]FuelUnit{
|
||||
1: LITRE,
|
||||
2: GALLON,
|
||||
3: US_GALLON,
|
||||
}
|
||||
currencyMap := map[int]string{
|
||||
1: "GBP",
|
||||
2: "USD",
|
||||
3: "EUR",
|
||||
4: "AUD",
|
||||
5: "CAD",
|
||||
}
|
||||
|
||||
newUserIdsMap := make(map[string]User)
|
||||
oldUserIdsMap := make(map[string]CUser)
|
||||
|
||||
var allUsers []CUser
|
||||
cdb.Table("Users").Find(&allUsers)
|
||||
for _, v := range allUsers {
|
||||
role := USER
|
||||
if v.Admin {
|
||||
role = ADMIN
|
||||
}
|
||||
user := User{
|
||||
Email: v.Email,
|
||||
Currency: currencyMap[v.CurrencyUnit],
|
||||
DistanceUnit: distanceUnitMap[v.DistanceUnit],
|
||||
Role: role,
|
||||
Name: v.Username,
|
||||
}
|
||||
user.SetPassword("hammond")
|
||||
err = CreateUser(&user)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
newUserIdsMap[v.ID] = user
|
||||
oldUserIdsMap[v.ID] = v
|
||||
|
||||
if v.Admin {
|
||||
setting := GetOrCreateSetting()
|
||||
setting.Currency = user.Currency
|
||||
setting.DistanceUnit = user.DistanceUnit
|
||||
UpdateSettings(setting)
|
||||
}
|
||||
}
|
||||
|
||||
newVehicleIdsMap := make(map[string]Vehicle)
|
||||
oldVehicleIdsMap := make(map[string]CVehicle)
|
||||
vehicleUserMap := make(map[string]User)
|
||||
var allVehicles []CVehicle
|
||||
cdb.Table("Vehicles").Find(&allVehicles)
|
||||
for _, model := range allVehicles {
|
||||
vehicle := Vehicle{
|
||||
Nickname: model.Name,
|
||||
Registration: model.Registration,
|
||||
Model: model.Model,
|
||||
Make: model.Make,
|
||||
YearOfManufacture: model.YearOfManufacture,
|
||||
EngineSize: float32(model.EngineSizeCC),
|
||||
FuelUnit: fuelUnitsMap[oldUserIdsMap[model.User].FuelUnit],
|
||||
FuelType: fuelTypeMap[model.FuelType],
|
||||
}
|
||||
|
||||
tx := DB.Create(&vehicle)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
association := UserVehicle{
|
||||
UserID: newUserIdsMap[model.User].ID,
|
||||
VehicleID: vehicle.ID,
|
||||
IsOwner: true,
|
||||
}
|
||||
vehicleUserMap[vehicle.ID] = newUserIdsMap[model.User]
|
||||
tx = DB.Create(&association)
|
||||
|
||||
if tx.Error != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
newVehicleIdsMap[model.ID] = vehicle
|
||||
oldVehicleIdsMap[model.ID] = model
|
||||
}
|
||||
|
||||
var allFillups []CFuel
|
||||
cdb.Table("Fuel").Find(&allFillups)
|
||||
for _, model := range allFillups {
|
||||
fillup := Fillup{
|
||||
VehicleID: newVehicleIdsMap[model.Vehicle].ID,
|
||||
FuelUnit: newVehicleIdsMap[model.Vehicle].FuelUnit,
|
||||
FuelQuantity: model.FuelAmount,
|
||||
PerUnitPrice: model.FuelUnitCost,
|
||||
TotalAmount: model.TotalCost,
|
||||
OdoReading: model.OdometerReading,
|
||||
IsTankFull: &model.FullTank,
|
||||
HasMissedFillup: &model.MissedFillup,
|
||||
Comments: model.Notes,
|
||||
UserID: vehicleUserMap[newVehicleIdsMap[model.Vehicle].ID].ID,
|
||||
Date: model.Date,
|
||||
Currency: vehicleUserMap[newVehicleIdsMap[model.Vehicle].ID].Currency,
|
||||
DistanceUnit: vehicleUserMap[newVehicleIdsMap[model.Vehicle].ID].DistanceUnit,
|
||||
}
|
||||
|
||||
tx := DB.Create(&fillup)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
58
server/db/db.go
Normal file
58
server/db/db.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
//DB is
|
||||
var DB *gorm.DB
|
||||
|
||||
//Init is used to Initialize Database
|
||||
func Init() (*gorm.DB, error) {
|
||||
// github.com/mattn/go-sqlite3
|
||||
configPath := os.Getenv("CONFIG")
|
||||
dbPath := path.Join(configPath, "hammond.db")
|
||||
log.Println(dbPath)
|
||||
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||
DisableForeignKeyConstraintWhenMigrating: true,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("db err: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localDB, _ := db.DB()
|
||||
localDB.SetMaxIdleConns(10)
|
||||
//db.LogMode(true)
|
||||
DB = db
|
||||
return DB, nil
|
||||
}
|
||||
|
||||
//Migrate Database
|
||||
func Migrate() {
|
||||
err := DB.AutoMigrate(&Attachment{}, &QuickEntry{}, &User{}, &Vehicle{}, &UserVehicle{}, &VehicleAttachment{}, &Fillup{}, &Expense{}, &Setting{}, &JobLock{}, &Migration{})
|
||||
if err != nil {
|
||||
fmt.Println("1 " + err.Error())
|
||||
}
|
||||
err = DB.SetupJoinTable(&User{}, "Vehicles", &UserVehicle{})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
err = DB.SetupJoinTable(&Vehicle{}, "Attachments", &VehicleAttachment{})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
RunMigrations()
|
||||
}
|
||||
|
||||
// Using this function to get a connection, you can create your connection pool here.
|
||||
func GetDB() *gorm.DB {
|
||||
return DB
|
||||
}
|
||||
192
server/db/dbModels.go
Normal file
192
server/db/dbModels.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Base
|
||||
Email string `gorm:"unique" json:"email"`
|
||||
Password string `json:"-"`
|
||||
Currency string `json:"currency"`
|
||||
DistanceUnit DistanceUnit `json:"distanceUnit"`
|
||||
Role Role `json:"role"`
|
||||
Name string `json:"name"`
|
||||
Vehicles []Vehicle `gorm:"many2many:user_vehicles;" json:"vehicles"`
|
||||
}
|
||||
|
||||
func (b *User) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
User
|
||||
RoleDetail EnumDetail `json:"roleDetail"`
|
||||
DistanceUnitDetail EnumDetail `json:"distanceUnitDetail"`
|
||||
}{
|
||||
User: *b,
|
||||
RoleDetail: b.RoleDetail(),
|
||||
DistanceUnitDetail: b.DistanceUnitDetail(),
|
||||
})
|
||||
}
|
||||
func (v *User) RoleDetail() EnumDetail {
|
||||
return RoleDetails[v.Role]
|
||||
}
|
||||
func (v *User) DistanceUnitDetail() EnumDetail {
|
||||
return DistanceUnitDetails[v.DistanceUnit]
|
||||
}
|
||||
|
||||
func (u *User) SetPassword(password string) error {
|
||||
if len(password) == 0 {
|
||||
return errors.New("password should not be empty")
|
||||
}
|
||||
bytePassword := []byte(password)
|
||||
// Make sure the second param `bcrypt generator cost` between [4, 32)
|
||||
passwordHash, _ := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
|
||||
u.Password = string(passwordHash)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) CheckPassword(password string) error {
|
||||
bytePassword := []byte(password)
|
||||
byteHashedPassword := []byte(u.Password)
|
||||
return bcrypt.CompareHashAndPassword(byteHashedPassword, bytePassword)
|
||||
}
|
||||
|
||||
type Vehicle struct {
|
||||
Base
|
||||
Nickname string `json:"nickname"`
|
||||
Registration string `json:"registration"`
|
||||
Make string `json:"make"`
|
||||
Model string `json:"model"`
|
||||
YearOfManufacture int `json:"yearOfManufacture"`
|
||||
EngineSize float32 `json:"engineSize"`
|
||||
FuelUnit FuelUnit `json:"fuelUnit"`
|
||||
FuelType FuelType `json:"fuelType"`
|
||||
Users []User `gorm:"many2many:user_vehicles;" json:"users"`
|
||||
Fillups []Fillup `json:"fillups"`
|
||||
Expenses []Expense `json:"expenses"`
|
||||
Attachments []Attachment `gorm:"many2many:vehicle_attachments;" json:"attachments"`
|
||||
IsOwner bool `gorm:"->" json:"isOwner"`
|
||||
}
|
||||
|
||||
func (b *Vehicle) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Vehicle
|
||||
FuelTypeDetail EnumDetail `json:"fuelTypeDetail"`
|
||||
FuelUnitDetail EnumDetail `json:"fuelUnitDetail"`
|
||||
}{
|
||||
Vehicle: *b,
|
||||
FuelTypeDetail: b.FuelTypeDetail(),
|
||||
FuelUnitDetail: b.FuelUnitDetail(),
|
||||
})
|
||||
}
|
||||
func (v *Vehicle) FuelTypeDetail() EnumDetail {
|
||||
return FuelTypeDetails[v.FuelType]
|
||||
}
|
||||
|
||||
func (v *Vehicle) FuelUnitDetail() EnumDetail {
|
||||
return FuelUnitDetails[v.FuelUnit]
|
||||
}
|
||||
|
||||
type UserVehicle struct {
|
||||
Base
|
||||
UserID string `gorm:"primaryKey"`
|
||||
User User `json:"user"`
|
||||
VehicleID string `gorm:"primaryKey"`
|
||||
IsOwner bool `json:"isOwner"`
|
||||
}
|
||||
|
||||
type Fillup struct {
|
||||
Base
|
||||
VehicleID string `json:"vehicleId"`
|
||||
Vehicle Vehicle `json:"-"`
|
||||
FuelUnit FuelUnit `json:"fuelUnit"`
|
||||
FuelQuantity float32 `json:"fuelQuantity"`
|
||||
PerUnitPrice float32 `json:"perUnitPrice"`
|
||||
TotalAmount float32 `json:"totalAmount"`
|
||||
OdoReading int `json:"odoReading"`
|
||||
IsTankFull *bool `json:"isTankFull"`
|
||||
HasMissedFillup *bool `json:"hasMissedFillup"`
|
||||
Comments string `json:"comments"`
|
||||
FillingStation string `json:"fillingStation"`
|
||||
UserID string `json:"userId"`
|
||||
User User `json:"user"`
|
||||
Date time.Time `json:"date"`
|
||||
Currency string `json:"currency"`
|
||||
DistanceUnit DistanceUnit `json:"distanceUnit"`
|
||||
}
|
||||
|
||||
func (v *Fillup) FuelUnitDetail() EnumDetail {
|
||||
return FuelUnitDetails[v.FuelUnit]
|
||||
}
|
||||
func (b *Fillup) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Fillup
|
||||
FuelUnitDetail EnumDetail `json:"fuelUnitDetail"`
|
||||
}{
|
||||
Fillup: *b,
|
||||
FuelUnitDetail: b.FuelUnitDetail(),
|
||||
})
|
||||
}
|
||||
|
||||
type Expense struct {
|
||||
Base
|
||||
VehicleID string `json:"vehicleId"`
|
||||
Vehicle Vehicle `json:"-"`
|
||||
Amount float32 `json:"amount"`
|
||||
OdoReading int `json:"odoReading"`
|
||||
Comments string `json:"comments"`
|
||||
ExpenseType string `json:"expenseType"`
|
||||
UserID string `json:"userId"`
|
||||
User User `json:"user"`
|
||||
Date time.Time `json:"date"`
|
||||
Currency string `json:"currency"`
|
||||
DistanceUnit DistanceUnit `json:"distanceUnit"`
|
||||
}
|
||||
|
||||
type Setting struct {
|
||||
Base
|
||||
Currency string `json:"currency" gorm:"default:INR"`
|
||||
DistanceUnit DistanceUnit `json:"distanceUnit" gorm:"default:1"`
|
||||
}
|
||||
type Migration struct {
|
||||
Base
|
||||
Date time.Time
|
||||
Name string
|
||||
}
|
||||
type JobLock struct {
|
||||
Base
|
||||
Date time.Time
|
||||
Name string
|
||||
Duration int
|
||||
}
|
||||
|
||||
type Attachment struct {
|
||||
Base
|
||||
Path string `json:"path"`
|
||||
OriginalName string `json:"originalName"`
|
||||
Size int64 `json:"size"`
|
||||
ContentType string `json:"contentType"`
|
||||
Title string `gorm:"->" json:"title"`
|
||||
UserID string `json:"userId"`
|
||||
User User `json:"user"`
|
||||
}
|
||||
|
||||
type QuickEntry struct {
|
||||
Base
|
||||
AttachmentID string `json:"attachmentId"`
|
||||
Attachment Attachment `json:"attachment"`
|
||||
ProcessDate *time.Time `json:"processDate"`
|
||||
UserID string `json:"userId"`
|
||||
User User `json:"user"`
|
||||
Comments string `json:"comments"`
|
||||
}
|
||||
|
||||
type VehicleAttachment struct {
|
||||
Base
|
||||
AttachmentID string `gorm:"primaryKey" json:"attachmentId"`
|
||||
VehicleID string `gorm:"primaryKey" json:"vehicleId"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
304
server/db/dbfunctions.go
Normal file
304
server/db/dbfunctions.go
Normal file
@@ -0,0 +1,304 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func CanInitializeSystem() (bool, error) {
|
||||
users, _ := GetAllUsers()
|
||||
if len(*users) != 0 {
|
||||
// db.MigrateClarkson("root:password@tcp(192.168.0.117:3306)/clarkson?charset=utf8mb4&parseTime=True&loc=Local")
|
||||
return false,
|
||||
fmt.Errorf("there are already users in the database. Migration can only be done on an empty database")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func CreateUser(user *User) error {
|
||||
tx := DB.Create(&user)
|
||||
return tx.Error
|
||||
}
|
||||
func UpdateUser(user *User) error {
|
||||
tx := DB.Omit(clause.Associations).Save(&user)
|
||||
return tx.Error
|
||||
}
|
||||
func FindOneUser(condition interface{}) (User, error) {
|
||||
|
||||
var model User
|
||||
err := DB.Where(condition).First(&model).Error
|
||||
return model, err
|
||||
}
|
||||
func GetAllUsers() (*[]User, error) {
|
||||
|
||||
sorting := "created_at desc"
|
||||
var users []User
|
||||
result := DB.Order(sorting).Find(&users)
|
||||
return &users, result.Error
|
||||
}
|
||||
|
||||
func GetAllVehicles(sorting string) (*[]Vehicle, error) {
|
||||
if sorting == "" {
|
||||
sorting = "created_at desc"
|
||||
}
|
||||
var vehicles []Vehicle
|
||||
result := DB.Preload("Fillups", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Order("fillups.date DESC")
|
||||
}).Preload("Expenses", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Order("expenses.date DESC")
|
||||
}).Order(sorting).Find(&vehicles)
|
||||
return &vehicles, result.Error
|
||||
}
|
||||
|
||||
func GetVehicleOwner(vehicleId string) (string, error) {
|
||||
var mapping UserVehicle
|
||||
|
||||
tx := DB.Where("vehicle_id = ? AND is_owner = 1", vehicleId).First(&mapping)
|
||||
|
||||
if tx.Error != nil {
|
||||
return "", tx.Error
|
||||
}
|
||||
return mapping.ID, nil
|
||||
}
|
||||
|
||||
func GetVehicleUsers(vehicleId string) (*[]UserVehicle, error) {
|
||||
var mapping []UserVehicle
|
||||
|
||||
tx := DB.Debug().Preload("User").Where("vehicle_id = ?", vehicleId).Find(&mapping)
|
||||
|
||||
if tx.Error != nil {
|
||||
return nil, tx.Error
|
||||
}
|
||||
return &mapping, nil
|
||||
}
|
||||
|
||||
func ShareVehicle(vehicleId, userId string) error {
|
||||
var mapping UserVehicle
|
||||
|
||||
tx := DB.Where("vehicle_id = ? AND user_id = ?", vehicleId, userId).First(&mapping)
|
||||
|
||||
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
|
||||
newMapping := UserVehicle{
|
||||
UserID: userId,
|
||||
VehicleID: vehicleId,
|
||||
IsOwner: false,
|
||||
}
|
||||
tx = DB.Create(&newMapping)
|
||||
return tx.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UnshareVehicle(vehicleId, userId string) error {
|
||||
var mapping UserVehicle
|
||||
|
||||
tx := DB.Where("vehicle_id = ? AND user_id = ?", vehicleId, userId).First(&mapping)
|
||||
|
||||
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
|
||||
return nil
|
||||
}
|
||||
if mapping.IsOwner {
|
||||
return fmt.Errorf("Cannot unshare owner")
|
||||
}
|
||||
result := DB.Where("id=?", mapping.ID).Delete(&UserVehicle{})
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func GetUserVehicles(id string) (*[]Vehicle, error) {
|
||||
var toReturn []Vehicle
|
||||
user, err := GetUserById(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = DB.Preload("Fillups", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Order("fillups.date DESC")
|
||||
}).Preload("Expenses", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Order("expenses.date DESC")
|
||||
}).Model(user).Select("vehicles.*,user_vehicles.is_owner").Association("Vehicles").Find(&toReturn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &toReturn, nil
|
||||
}
|
||||
func GetUserById(id string) (*User, error) {
|
||||
var data User
|
||||
result := DB.Preload(clause.Associations).First(&data, "id=?", id)
|
||||
return &data, result.Error
|
||||
}
|
||||
func GetVehicleById(id string) (*Vehicle, error) {
|
||||
var vehicle Vehicle
|
||||
result := DB.Preload(clause.Associations).First(&vehicle, "id=?", id)
|
||||
return &vehicle, result.Error
|
||||
}
|
||||
func GetFillupById(id string) (*Fillup, error) {
|
||||
var obj Fillup
|
||||
result := DB.Preload(clause.Associations).First(&obj, "id=?", id)
|
||||
return &obj, result.Error
|
||||
}
|
||||
|
||||
func GetFillupsByVehicleId(id string) (*[]Fillup, error) {
|
||||
var obj []Fillup
|
||||
result := DB.Preload(clause.Associations).Order("date desc").Find(&obj, &Fillup{VehicleID: id})
|
||||
return &obj, result.Error
|
||||
}
|
||||
func FindFillups(condition interface{}) (*[]Fillup, error) {
|
||||
|
||||
var model []Fillup
|
||||
err := DB.Where(condition).Find(&model).Error
|
||||
return &model, err
|
||||
}
|
||||
|
||||
func FindFillupsForDateRange(vehicleIds []string, start, end time.Time) (*[]Fillup, error) {
|
||||
|
||||
var model []Fillup
|
||||
err := DB.Where("date <= ? AND date >= ? AND vehicle_id in ?", end, start, vehicleIds).Find(&model).Error
|
||||
return &model, err
|
||||
}
|
||||
func FindExpensesForDateRange(vehicleIds []string, start, end time.Time) (*[]Expense, error) {
|
||||
|
||||
var model []Expense
|
||||
err := DB.Where("date <= ? AND date >= ? AND vehicle_id in ?", end, start, vehicleIds).Find(&model).Error
|
||||
return &model, err
|
||||
}
|
||||
|
||||
func GetExpensesByVehicleId(id string) (*[]Expense, error) {
|
||||
var obj []Expense
|
||||
result := DB.Preload(clause.Associations).Order("date desc").Find(&obj, &Expense{VehicleID: id})
|
||||
return &obj, result.Error
|
||||
}
|
||||
func GetExpenseById(id string) (*Expense, error) {
|
||||
var obj Expense
|
||||
result := DB.Preload(clause.Associations).First(&obj, "id=?", id)
|
||||
return &obj, result.Error
|
||||
}
|
||||
|
||||
func DeleteFillupById(id string) error {
|
||||
|
||||
result := DB.Where("id=?", id).Delete(&Fillup{})
|
||||
return result.Error
|
||||
}
|
||||
func DeleteExpenseById(id string) error {
|
||||
result := DB.Where("id=?", id).Delete(&Expense{})
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func GetAllQuickEntries(sorting string) (*[]QuickEntry, error) {
|
||||
if sorting == "" {
|
||||
sorting = "created_at desc"
|
||||
}
|
||||
var quickEntries []QuickEntry
|
||||
result := DB.Preload(clause.Associations).Order(sorting).Find(&quickEntries)
|
||||
return &quickEntries, result.Error
|
||||
}
|
||||
func GetQuickEntriesForUser(userId, sorting string) (*[]QuickEntry, error) {
|
||||
if sorting == "" {
|
||||
sorting = "created_at desc"
|
||||
}
|
||||
var quickEntries []QuickEntry
|
||||
result := DB.Preload(clause.Associations).Where("user_id = ?", userId).Order(sorting).Find(&quickEntries)
|
||||
return &quickEntries, result.Error
|
||||
}
|
||||
func GetQuickEntryById(id string) (*QuickEntry, error) {
|
||||
var quickEntry QuickEntry
|
||||
result := DB.Preload(clause.Associations).First(&quickEntry, "id=?", id)
|
||||
return &quickEntry, result.Error
|
||||
}
|
||||
func UpdateQuickEntry(entry *QuickEntry) error {
|
||||
return DB.Save(entry).Error
|
||||
}
|
||||
func SetQuickEntryAsProcessed(id string, processDate time.Time) error {
|
||||
result := DB.Model(QuickEntry{}).Where("id=?", id).Update("process_date", processDate)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func GetAttachmentById(id string) (*Attachment, error) {
|
||||
var entry Attachment
|
||||
result := DB.Preload(clause.Associations).First(&entry, "id=?", id)
|
||||
return &entry, result.Error
|
||||
}
|
||||
func GetVehicleAttachments(vehicleId string) (*[]Attachment, error) {
|
||||
var attachments []Attachment
|
||||
vehicle, err := GetVehicleById(vehicleId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = DB.Debug().Model(vehicle).Select("attachments.*,vehicle_attachments.title").Preload("User").Association("Attachments").Find(&attachments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &attachments, nil
|
||||
}
|
||||
|
||||
func UpdateSettings(setting *Setting) error {
|
||||
tx := DB.Save(&setting)
|
||||
return tx.Error
|
||||
}
|
||||
func GetOrCreateSetting() *Setting {
|
||||
var setting Setting
|
||||
result := DB.First(&setting)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
DB.Save(&Setting{})
|
||||
DB.First(&setting)
|
||||
}
|
||||
return &setting
|
||||
}
|
||||
|
||||
func GetLock(name string) *JobLock {
|
||||
var jobLock JobLock
|
||||
result := DB.Where("name = ?", name).First(&jobLock)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return &JobLock{
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
return &jobLock
|
||||
}
|
||||
func Lock(name string, duration int) {
|
||||
jobLock := GetLock(name)
|
||||
if jobLock == nil {
|
||||
jobLock = &JobLock{
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
jobLock.Duration = duration
|
||||
jobLock.Date = time.Now()
|
||||
if jobLock.ID == "" {
|
||||
DB.Create(&jobLock)
|
||||
} else {
|
||||
DB.Save(&jobLock)
|
||||
}
|
||||
}
|
||||
func Unlock(name string) {
|
||||
jobLock := GetLock(name)
|
||||
if jobLock == nil {
|
||||
return
|
||||
}
|
||||
jobLock.Duration = 0
|
||||
jobLock.Date = time.Time{}
|
||||
DB.Save(&jobLock)
|
||||
}
|
||||
|
||||
func UnlockMissedJobs() {
|
||||
var jobLocks []JobLock
|
||||
|
||||
result := DB.Find(&jobLocks)
|
||||
if result.Error != nil {
|
||||
return
|
||||
}
|
||||
for _, job := range jobLocks {
|
||||
if (job.Date == time.Time{}) {
|
||||
continue
|
||||
}
|
||||
var duration time.Duration
|
||||
duration = time.Duration(job.Duration)
|
||||
d := job.Date.Add(time.Minute * duration)
|
||||
if d.Before(time.Now()) {
|
||||
fmt.Println(job.Name + " is unlocked")
|
||||
Unlock(job.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
111
server/db/enums.go
Normal file
111
server/db/enums.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package db
|
||||
|
||||
type FuelUnit int
|
||||
|
||||
const (
|
||||
LITRE FuelUnit = iota
|
||||
GALLON
|
||||
US_GALLON
|
||||
KILOGRAM
|
||||
KILOWATT_HOUR
|
||||
MINUTE
|
||||
)
|
||||
|
||||
type FuelType int
|
||||
|
||||
const (
|
||||
PETROL FuelType = iota
|
||||
DIESEL
|
||||
ETHANOL
|
||||
CNG
|
||||
ELECTRIC
|
||||
LPG
|
||||
)
|
||||
|
||||
type DistanceUnit int
|
||||
|
||||
const (
|
||||
MILES DistanceUnit = iota
|
||||
KILOMETERS
|
||||
)
|
||||
|
||||
type Role int
|
||||
|
||||
const (
|
||||
ADMIN Role = iota
|
||||
USER
|
||||
)
|
||||
|
||||
type EnumDetail struct {
|
||||
Short string `json:"short"`
|
||||
Long string `json:"long"`
|
||||
}
|
||||
|
||||
var FuelUnitDetails map[FuelUnit]EnumDetail = map[FuelUnit]EnumDetail{
|
||||
LITRE: {
|
||||
Short: "Lt",
|
||||
Long: "Litre",
|
||||
},
|
||||
GALLON: {
|
||||
Short: "Gal",
|
||||
Long: "Gallon",
|
||||
}, KILOGRAM: {
|
||||
Short: "Kg",
|
||||
Long: "Kilogram",
|
||||
}, KILOWATT_HOUR: {
|
||||
Short: "KwH",
|
||||
Long: "Kilowatt Hour",
|
||||
}, US_GALLON: {
|
||||
Short: "US Gal",
|
||||
Long: "US Gallon",
|
||||
},
|
||||
MINUTE: {
|
||||
Short: "Mins",
|
||||
Long: "Minutes",
|
||||
},
|
||||
}
|
||||
|
||||
var FuelTypeDetails map[FuelType]EnumDetail = map[FuelType]EnumDetail{
|
||||
PETROL: {
|
||||
Short: "Petrol",
|
||||
Long: "Petrol",
|
||||
},
|
||||
DIESEL: {
|
||||
Short: "Diesel",
|
||||
Long: "Diesel",
|
||||
}, CNG: {
|
||||
Short: "CNG",
|
||||
Long: "CNG",
|
||||
}, LPG: {
|
||||
Short: "LPG",
|
||||
Long: "LPG",
|
||||
}, ELECTRIC: {
|
||||
Short: "Electric",
|
||||
Long: "Electric",
|
||||
}, ETHANOL: {
|
||||
Short: "Ethanol",
|
||||
Long: "Ethanol",
|
||||
},
|
||||
}
|
||||
|
||||
var DistanceUnitDetails map[DistanceUnit]EnumDetail = map[DistanceUnit]EnumDetail{
|
||||
KILOMETERS: {
|
||||
Short: "Km",
|
||||
Long: "Kilometers",
|
||||
},
|
||||
MILES: {
|
||||
Short: "Mi",
|
||||
Long: "Miles",
|
||||
},
|
||||
}
|
||||
|
||||
var RoleDetails map[Role]EnumDetail = map[Role]EnumDetail{
|
||||
ADMIN: {
|
||||
Short: "Admin",
|
||||
Long: "ADMIN",
|
||||
},
|
||||
USER: {
|
||||
Short: "User",
|
||||
Long: "USER",
|
||||
},
|
||||
}
|
||||
43
server/db/migrations.go
Normal file
43
server/db/migrations.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type localMigration struct {
|
||||
Name string
|
||||
Query string
|
||||
}
|
||||
|
||||
var migrations = []localMigration{
|
||||
// {
|
||||
// Name: "2020_11_03_04_42_SetDefaultDownloadStatus",
|
||||
// Query: "update podcast_items set download_status=2 where download_path!='' and download_status=0",
|
||||
// },
|
||||
}
|
||||
|
||||
func RunMigrations() {
|
||||
for _, mig := range migrations {
|
||||
ExecuteAndSaveMigration(mig.Name, mig.Query)
|
||||
}
|
||||
}
|
||||
func ExecuteAndSaveMigration(name string, query string) error {
|
||||
var migration Migration
|
||||
result := DB.Where("name=?", name).First(&migration)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
fmt.Println(query)
|
||||
result = DB.Debug().Exec(query)
|
||||
if result.Error == nil {
|
||||
DB.Save(&Migration{
|
||||
Date: time.Now(),
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user