Merge branch 'master' into add-vin
This commit is contained in:
4
server/.gitignore
vendored
4
server/.gitignore
vendored
@@ -12,6 +12,10 @@
|
||||
*.out
|
||||
*.db
|
||||
|
||||
# MS VSCode
|
||||
.vscode
|
||||
__debug_bin
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
assets/*
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
@@ -91,20 +92,20 @@ func userLogin(c *gin.Context) {
|
||||
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
|
||||
return
|
||||
}
|
||||
user, err := db.FindOneUser(&db.User{Email: loginRequest.Email})
|
||||
user, err := db.FindOneUser(&db.User{Email: strings.ToLower(loginRequest.Email)})
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Not Registered email or invalid password")))
|
||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("not Registered email or invalid password")))
|
||||
return
|
||||
}
|
||||
|
||||
if user.CheckPassword(loginRequest.Password) != nil {
|
||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Not Registered email or invalid password")))
|
||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("not Registered email or invalid password")))
|
||||
return
|
||||
}
|
||||
|
||||
if user.IsDisabled {
|
||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Your user has been disabled by the admin. Please contact them to get it re-enabled.")))
|
||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("your user has been disabled by the admin. Please contact them to get it re-enabled")))
|
||||
return
|
||||
}
|
||||
UpdateContextUserModel(c, user.ID)
|
||||
@@ -170,16 +171,16 @@ func changePassword(c *gin.Context) {
|
||||
user, err := service.GetUserById(c.GetString("userId"))
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("Not Registered email or invalid password")))
|
||||
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("not Registered email or invalid password")))
|
||||
return
|
||||
}
|
||||
|
||||
if user.CheckPassword(request.OldPassword) != nil {
|
||||
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("Incorrect old password")))
|
||||
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("incorrect old password")))
|
||||
return
|
||||
}
|
||||
|
||||
user.SetPassword(request.NewPassword)
|
||||
success, err := service.UpdatePassword(user.ID, request.NewPassword)
|
||||
success, _ := service.UpdatePassword(user.ID, request.NewPassword)
|
||||
c.JSON(http.StatusOK, success)
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ func stripBearerPrefixFromTokenString(tok string) (string, error) {
|
||||
// Extract token from Authorization header
|
||||
// Uses PostExtractionFilter to strip "TOKEN " prefix from header
|
||||
var AuthorizationHeaderExtractor = &request.PostExtractionFilter{
|
||||
request.HeaderExtractor{"Authorization"},
|
||||
stripBearerPrefixFromTokenString,
|
||||
Extractor: request.HeaderExtractor{"Authorization"},
|
||||
Filter: stripBearerPrefixFromTokenString,
|
||||
}
|
||||
|
||||
// Extractor for OAuth2 access tokens. Looks in 'Authorization'
|
||||
|
||||
@@ -51,7 +51,7 @@ func migrate(c *gin.Context) {
|
||||
canMigrate, _, _ := db.CanMigrate(request.Url)
|
||||
|
||||
if !canMigrate {
|
||||
c.JSON(http.StatusBadRequest, fmt.Errorf("cannot migrate database. please check connection string."))
|
||||
c.JSON(http.StatusBadRequest, fmt.Errorf("cannot migrate database. please check connection string"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -397,7 +397,7 @@ func deleteVehicle(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
if !canDelete {
|
||||
c.JSON(http.StatusUnprocessableEntity, common.NewError("shareVehicle", errors.New("You are not allowed to delete this vehicle.")))
|
||||
c.JSON(http.StatusUnprocessableEntity, common.NewError("shareVehicle", errors.New("you are not allowed to delete this vehicle")))
|
||||
return
|
||||
}
|
||||
err = service.DeleteVehicle(searchByIdQuery.Id)
|
||||
|
||||
@@ -196,3 +196,50 @@ type VehicleAttachment struct {
|
||||
VehicleID string `gorm:"primaryKey" json:"vehicleId"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type VehicleAlert struct {
|
||||
Base
|
||||
VehicleID string `json:"vehicleId"`
|
||||
Vehicle Vehicle `json:"-"`
|
||||
UserID string `json:"userId"`
|
||||
User User `json:"user"`
|
||||
Title string `json:"title"`
|
||||
Comments string `json:"comments"`
|
||||
StartDate time.Time `json:"date"`
|
||||
StartOdoReading int `json:"startOdoReading"`
|
||||
DistanceUnit DistanceUnit `json:"distanceUnit"`
|
||||
AlertFrequency AlertFrequency `json:"alertFrequency"`
|
||||
OdoFrequency int `json:"odoFrequency"`
|
||||
DayFrequency int `json:"dayFrequency"`
|
||||
AlertAllUsers bool `json:"alertAllUsers"`
|
||||
IsActive bool `json:"isActive"`
|
||||
EndDate *time.Time `json:"endDate"`
|
||||
AlertType AlertType `json:"alertType"`
|
||||
}
|
||||
type AlertOccurance struct {
|
||||
Base
|
||||
VehicleID string `json:"vehicleId"`
|
||||
Vehicle Vehicle `json:"-"`
|
||||
VehicleAlertID string `json:"vehicleAlertId"`
|
||||
VehicleAlert VehicleAlert `json:"-"`
|
||||
UserID string `json:"userId"`
|
||||
User User `json:"-"`
|
||||
OdoReading int `json:"odoReading"`
|
||||
Date *time.Time `json:"date"`
|
||||
ProcessDate *time.Time `json:"processDate"`
|
||||
AlertProcessType AlertType `json:"alertProcessType"`
|
||||
CompleteDate *time.Time `json:"completeDate"`
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
Base
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
UserID string `json:"userId"`
|
||||
VehicleID string `json:"vehicleId"`
|
||||
User User `json:"-"`
|
||||
Date time.Time `json:"date"`
|
||||
ReadDate *time.Time `json:"readDate"`
|
||||
ParentID string `json:"parentId"`
|
||||
ParentType string `json:"parentType"`
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ func UnshareVehicle(vehicleId, userId string) error {
|
||||
return nil
|
||||
}
|
||||
if mapping.IsOwner {
|
||||
return fmt.Errorf("Cannot unshare owner")
|
||||
return fmt.Errorf("cannot unshare owner")
|
||||
}
|
||||
result := DB.Where("id=?", mapping.ID).Delete(&UserVehicle{})
|
||||
return result.Error
|
||||
@@ -160,6 +160,11 @@ func GetFillupsByVehicleId(id string) (*[]Fillup, error) {
|
||||
result := DB.Preload(clause.Associations).Order("date desc").Find(&obj, &Fillup{VehicleID: id})
|
||||
return &obj, result.Error
|
||||
}
|
||||
func GetLatestFillupsByVehicleId(id string) (*Fillup, error) {
|
||||
var obj Fillup
|
||||
result := DB.Preload(clause.Associations).Order("date desc").First(&obj, &Fillup{VehicleID: id})
|
||||
return &obj, result.Error
|
||||
}
|
||||
func GetFillupsByVehicleIdSince(id string, since time.Time) (*[]Fillup, error) {
|
||||
var obj []Fillup
|
||||
result := DB.Where("date >= ? AND vehicle_id = ?", since, id).Preload(clause.Associations).Order("date desc").Find(&obj)
|
||||
@@ -190,6 +195,11 @@ func GetExpensesByVehicleId(id string) (*[]Expense, error) {
|
||||
result := DB.Preload(clause.Associations).Order("date desc").Find(&obj, &Expense{VehicleID: id})
|
||||
return &obj, result.Error
|
||||
}
|
||||
func GetLatestExpenseByVehicleId(id string) (*Expense, error) {
|
||||
var obj Expense
|
||||
result := DB.Preload(clause.Associations).Order("date desc").First(&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)
|
||||
@@ -271,6 +281,29 @@ func GetVehicleAttachments(vehicleId string) (*[]Attachment, error) {
|
||||
}
|
||||
return &attachments, nil
|
||||
}
|
||||
func GeAlertById(id string) (*VehicleAlert, error) {
|
||||
var alert VehicleAlert
|
||||
result := DB.Preload(clause.Associations).First(&alert, "id=?", id)
|
||||
return &alert, result.Error
|
||||
}
|
||||
func GetAlertOccurenceByAlertId(id string) (*[]AlertOccurance, error) {
|
||||
var alertOccurance []AlertOccurance
|
||||
result := DB.Preload(clause.Associations).Order("created_at desc").Find(&alertOccurance, "vehicle_alert_id=?", id)
|
||||
return &alertOccurance, result.Error
|
||||
}
|
||||
|
||||
func GetUnprocessedAlertOccurances() (*[]AlertOccurance, error) {
|
||||
var alertOccurance []AlertOccurance
|
||||
result := DB.Preload(clause.Associations).Order("created_at desc").Find(&alertOccurance, "process_date is NULL")
|
||||
return &alertOccurance, result.Error
|
||||
}
|
||||
func MarkAlertOccuranceAsProcessed(id string, alertProcessType AlertType, date time.Time) error {
|
||||
tx := DB.Debug().Model(&AlertOccurance{}).Where("id= ?", id).
|
||||
Update("alert_process_type", alertProcessType).
|
||||
Update("process_date", date)
|
||||
return tx.Error
|
||||
|
||||
}
|
||||
|
||||
func UpdateSettings(setting *Setting) error {
|
||||
tx := DB.Save(&setting)
|
||||
@@ -332,8 +365,7 @@ func UnlockMissedJobs() {
|
||||
if (job.Date == time.Time{}) {
|
||||
continue
|
||||
}
|
||||
var duration time.Duration
|
||||
duration = time.Duration(job.Duration)
|
||||
var duration = time.Duration(job.Duration)
|
||||
d := job.Date.Add(time.Minute * duration)
|
||||
if d.Before(time.Now()) {
|
||||
fmt.Println(job.Name + " is unlocked")
|
||||
|
||||
@@ -36,6 +36,21 @@ const (
|
||||
USER
|
||||
)
|
||||
|
||||
type AlertFrequency int
|
||||
|
||||
const (
|
||||
ONETIME AlertFrequency = iota
|
||||
RECURRING
|
||||
)
|
||||
|
||||
type AlertType int
|
||||
|
||||
const (
|
||||
DISTANCE AlertType = iota
|
||||
TIME
|
||||
BOTH
|
||||
)
|
||||
|
||||
type EnumDetail struct {
|
||||
Short string `json:"short"`
|
||||
Long string `json:"long"`
|
||||
|
||||
@@ -19,8 +19,13 @@ var migrations = []localMigration{
|
||||
Query: "update users set is_disabled=0",
|
||||
},
|
||||
{
|
||||
Name: "2022_03_08_13_16_AddVIN",
|
||||
Query: "ALTER TABLE vehicles ADD COLUMN vin text",
|
||||
Name: "2021_02_07_00_09_LowerCaseEmails",
|
||||
Query: "update users set email=lower(email)",
|
||||
|
||||
},
|
||||
{
|
||||
Name: "2022_03_08_13_16_AddVIN",
|
||||
Query: "ALTER TABLE vehicles ADD COLUMN vin text",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
21
server/models/alert.go
Normal file
21
server/models/alert.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
)
|
||||
|
||||
type CreateAlertModel struct {
|
||||
Comments string `json:"comments"`
|
||||
Title string `json:"title"`
|
||||
StartDate time.Time `json:"date"`
|
||||
StartOdoReading int `json:"startOdoReading"`
|
||||
DistanceUnit *db.DistanceUnit `json:"distanceUnit"`
|
||||
AlertFrequency *db.AlertFrequency `json:"alertFrequency"`
|
||||
OdoFrequency int `json:"odoFrequency"`
|
||||
DayFrequency int `json:"dayFrequency"`
|
||||
AlertAllUsers bool `json:"alertAllUsers"`
|
||||
IsActive bool `json:"isActive"`
|
||||
AlertType *db.AlertType `json:"alertType"`
|
||||
}
|
||||
172
server/service/alertSevice.go
Normal file
172
server/service/alertSevice.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
)
|
||||
|
||||
func CreateAlert(model models.CreateAlertModel, vehicleId, userId string) (*db.VehicleAlert, error) {
|
||||
alert := db.VehicleAlert{
|
||||
VehicleID: vehicleId,
|
||||
UserID: userId,
|
||||
Title: model.Title,
|
||||
Comments: model.Comments,
|
||||
StartDate: model.StartDate,
|
||||
StartOdoReading: model.StartOdoReading,
|
||||
DistanceUnit: *model.DistanceUnit,
|
||||
AlertFrequency: *model.AlertFrequency,
|
||||
OdoFrequency: model.OdoFrequency,
|
||||
DayFrequency: model.DayFrequency,
|
||||
AlertAllUsers: model.AlertAllUsers,
|
||||
IsActive: model.IsActive,
|
||||
AlertType: *model.AlertType,
|
||||
}
|
||||
tx := db.DB.Create(&alert)
|
||||
if tx.Error != nil {
|
||||
return nil, tx.Error
|
||||
}
|
||||
go CreateAlertInstance(alert.ID)
|
||||
return &alert, nil
|
||||
}
|
||||
|
||||
func CreateAlertInstance(alertId string) error {
|
||||
alert, err := db.GeAlertById(alertId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingOccurence, err := db.GetAlertOccurenceByAlertId(alertId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var lastOccurance db.AlertOccurance
|
||||
useOccurance := false
|
||||
|
||||
if len(*existingOccurence) > 0 {
|
||||
lastOccurance = (*existingOccurence)[0]
|
||||
useOccurance = true
|
||||
if alert.AlertFrequency == db.ONETIME {
|
||||
return errors.New("Only single occurance is possible for this kind of alert")
|
||||
}
|
||||
}
|
||||
users := []string{alert.UserID}
|
||||
if alert.AlertAllUsers {
|
||||
allUsers, err := db.GetVehicleUsers(alert.VehicleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users = make([]string, len(*allUsers))
|
||||
for i, user := range *allUsers {
|
||||
users[i] = user.UserID
|
||||
}
|
||||
}
|
||||
|
||||
for _, userId := range users {
|
||||
model := db.AlertOccurance{
|
||||
VehicleID: alert.VehicleID,
|
||||
UserID: userId,
|
||||
VehicleAlertID: alertId,
|
||||
}
|
||||
|
||||
if alert.AlertType == db.DISTANCE || alert.AlertType == db.BOTH {
|
||||
model.OdoReading = alert.StartOdoReading + alert.OdoFrequency
|
||||
if useOccurance {
|
||||
model.OdoReading = lastOccurance.OdoReading + alert.OdoFrequency
|
||||
}
|
||||
}
|
||||
if alert.AlertType == db.TIME || alert.AlertType == db.BOTH {
|
||||
date := alert.StartDate.Add(time.Duration(alert.DayFrequency) * 24 * time.Hour)
|
||||
if useOccurance {
|
||||
date = lastOccurance.Date.Add(time.Duration(alert.DayFrequency) * 24 * time.Hour)
|
||||
}
|
||||
model.Date = &date
|
||||
}
|
||||
tx := db.DB.Create(&model)
|
||||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func ProcessAlertOccurance(occurance db.AlertOccurance, today time.Time) error {
|
||||
if occurance.ProcessDate != nil {
|
||||
return errors.New("Alert occurence already processed")
|
||||
}
|
||||
alert := occurance.VehicleAlert
|
||||
if !alert.IsActive {
|
||||
return errors.New("Alert is not active")
|
||||
}
|
||||
notification := db.Notification{
|
||||
Title: alert.Title,
|
||||
Content: alert.Comments,
|
||||
UserID: occurance.UserID,
|
||||
VehicleID: occurance.VehicleID,
|
||||
Date: today,
|
||||
ParentID: occurance.ID,
|
||||
ParentType: "AlertOccurance",
|
||||
}
|
||||
var alertProcessType db.AlertType
|
||||
if alert.AlertType == db.DISTANCE || alert.AlertType == db.BOTH {
|
||||
odoReading, err := GetLatestOdoReadingForVehicle(occurance.VehicleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if odoReading >= occurance.OdoReading {
|
||||
alertProcessType = db.DISTANCE
|
||||
}
|
||||
}
|
||||
if alert.AlertType == db.TIME || alert.AlertType == db.BOTH {
|
||||
if occurance.Date.Before(today) {
|
||||
alertProcessType = db.TIME
|
||||
}
|
||||
}
|
||||
|
||||
db.DB.Create(¬ification)
|
||||
return db.MarkAlertOccuranceAsProcessed(occurance.ID, alertProcessType, today)
|
||||
|
||||
}
|
||||
|
||||
func FindAlertOccurancesToProcess(today time.Time) ([]db.AlertOccurance, error) {
|
||||
occurances, err := db.GetUnprocessedAlertOccurances()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(*occurances) == 0 {
|
||||
return make([]db.AlertOccurance, 0), nil
|
||||
}
|
||||
|
||||
var toReturn []db.AlertOccurance
|
||||
|
||||
for _, occurance := range *occurances {
|
||||
alert := occurance.VehicleAlert
|
||||
if !alert.IsActive {
|
||||
continue
|
||||
}
|
||||
if alert.AlertType == db.DISTANCE || alert.AlertType == db.BOTH {
|
||||
odoReading, err := GetLatestOdoReadingForVehicle(occurance.VehicleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if odoReading >= occurance.OdoReading {
|
||||
toReturn = append(toReturn, occurance)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if alert.AlertType == db.TIME || alert.AlertType == db.BOTH {
|
||||
if occurance.Date.Before(today) {
|
||||
toReturn = append(toReturn, occurance)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return toReturn, nil
|
||||
}
|
||||
|
||||
func MarkAlertOccuranceAsCompleted() {
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -126,14 +125,14 @@ func CreateBackup() (string, error) {
|
||||
tarballFilePath := path.Join(folder, backupFileName)
|
||||
file, err := os.Create(tarballFilePath)
|
||||
if err != nil {
|
||||
return "", errors.New(fmt.Sprintf("Could not create tarball file '%s', got error '%s'", tarballFilePath, err.Error()))
|
||||
return "", fmt.Errorf("could not create tarball file '%s', got error '%s'", tarballFilePath, err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
dbPath := path.Join(configPath, "hammond.db")
|
||||
_, err = os.Stat(dbPath)
|
||||
if err != nil {
|
||||
return "", errors.New(fmt.Sprintf("Could not find db file '%s', got error '%s'", dbPath, err.Error()))
|
||||
return "", fmt.Errorf("could not find db file '%s', got error '%s'", dbPath, err.Error())
|
||||
}
|
||||
gzipWriter := gzip.NewWriter(file)
|
||||
defer gzipWriter.Close()
|
||||
@@ -151,13 +150,13 @@ func CreateBackup() (string, error) {
|
||||
func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Could not open file '%s', got error '%s'", filePath, err.Error()))
|
||||
return fmt.Errorf("could not open file '%s', got error '%s'", filePath, err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Could not get stat for file '%s', got error '%s'", filePath, err.Error()))
|
||||
return fmt.Errorf("could not get stat for file '%s', got error '%s'", filePath, err.Error())
|
||||
}
|
||||
|
||||
header := &tar.Header{
|
||||
@@ -169,12 +168,12 @@ func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
|
||||
|
||||
err = tarWriter.WriteHeader(header)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Could not write header for file '%s', got error '%s'", filePath, err.Error()))
|
||||
return fmt.Errorf("could not write header for file '%s', got error '%s'", filePath, err.Error())
|
||||
}
|
||||
|
||||
_, err = io.Copy(tarWriter, file)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Could not copy the file '%s' data to the tarball, got error '%s'", filePath, err.Error()))
|
||||
return fmt.Errorf("could not copy the file '%s' data to the tarball, got error '%s'", filePath, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
@@ -15,6 +16,9 @@ func GetMileageByVehicleId(vehicleId string, since time.Time) (mileage []models.
|
||||
|
||||
fillups := make([]db.Fillup, len(*data))
|
||||
copy(fillups, *data)
|
||||
sort.Slice(fillups, func(i, j int) bool {
|
||||
return fillups[i].OdoReading > fillups[j].OdoReading
|
||||
})
|
||||
|
||||
var mileages []models.MileageModel
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
)
|
||||
@@ -8,7 +10,7 @@ import (
|
||||
func CreateUser(userModel *models.RegisterRequest, role db.Role) error {
|
||||
setting := db.GetOrCreateSetting()
|
||||
toCreate := db.User{
|
||||
Email: userModel.Email,
|
||||
Email: strings.ToLower(userModel.Email),
|
||||
Name: userModel.Name,
|
||||
Role: role,
|
||||
Currency: setting.Currency,
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
@@ -245,6 +246,24 @@ func GetDistinctFuelSubtypesForVehicle(vehicleId string) ([]string, error) {
|
||||
return names, tx.Error
|
||||
}
|
||||
|
||||
func GetLatestOdoReadingForVehicle(vehicleId string) (int, error) {
|
||||
odoReading := 0
|
||||
latestFillup, err := db.GetLatestExpenseByVehicleId(vehicleId)
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return 0, err
|
||||
}
|
||||
odoReading = latestFillup.OdoReading
|
||||
|
||||
latestExpense, err := db.GetLatestExpenseByVehicleId(vehicleId)
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return 0, err
|
||||
}
|
||||
if latestExpense.OdoReading > odoReading {
|
||||
odoReading = latestExpense.OdoReading
|
||||
}
|
||||
return odoReading, nil
|
||||
}
|
||||
|
||||
func GetUserStats(userId string, model models.UserStatsQueryModel) ([]models.VehicleStatsModel, error) {
|
||||
|
||||
vehicles, err := GetUserVehicles(userId)
|
||||
|
||||
Reference in New Issue
Block a user