2019-05-06 01:40:41 +03:00
package models
2020-05-30 23:19:05 +03:00
import (
"database/sql/driver"
2021-02-07 14:37:51 +03:00
"encoding/json"
2020-05-30 23:19:05 +03:00
"errors"
"fmt"
"strconv"
"strings"
"time"
)
2020-05-30 21:41:27 +03:00
2019-05-06 01:40:41 +03:00
const (
2022-11-05 21:30:40 +03:00
UserKey = "user"
ImprintKey = "imprint"
AuthCookieKey = "wakapi_auth"
PersistentIntervalKey = "wakapi_summary_interval"
2019-05-06 01:40:41 +03:00
)
2020-05-30 21:41:27 +03:00
type KeyStringValue struct {
Key string ` gorm:"primary_key" `
2020-05-30 22:10:44 +03:00
Value string ` gorm:"type:text" `
2020-05-30 21:41:27 +03:00
}
2020-05-30 23:19:05 +03:00
2020-11-07 14:01:35 +03:00
type Interval struct {
Start time . Time
End time . Time
}
2022-04-18 12:39:26 +03:00
type KeyedInterval struct {
Interval
Key * IntervalKey
}
2021-04-25 10:21:21 +03:00
// CustomTime is a wrapper type around time.Time, mainly used for the purpose of transparently unmarshalling Python timestamps in the format <sec>.<nsec> (e.g. 1619335137.3324468)
2020-08-30 02:42:00 +03:00
type CustomTime time . Time
2021-02-07 14:37:51 +03:00
func ( j * CustomTime ) MarshalJSON ( ) ( [ ] byte , error ) {
2021-04-25 10:21:21 +03:00
return json . Marshal ( j . T ( ) )
2021-02-07 14:37:51 +03:00
}
2020-05-30 23:19:05 +03:00
func ( j * CustomTime ) UnmarshalJSON ( b [ ] byte ) error {
2021-04-25 10:21:21 +03:00
s := strings . Trim ( string ( b ) , "\"" )
ts , err := strconv . ParseFloat ( s , 64 )
2020-05-30 23:19:05 +03:00
if err != nil {
return err
}
2021-04-25 10:21:21 +03:00
t := time . Unix ( 0 , int64 ( ts * 1e9 ) ) // ms to ns
2020-05-30 23:19:05 +03:00
* j = CustomTime ( t )
return nil
}
func ( j * CustomTime ) Scan ( value interface { } ) error {
2020-10-16 13:49:36 +03:00
var (
t time . Time
err error
)
2020-05-30 23:19:05 +03:00
switch value . ( type ) {
case string :
2021-04-25 10:21:21 +03:00
// with sqlite, some queries (like GetLastByUser()) return dates as strings,
// however, most of the time they are returned as time.Time
2020-10-16 13:49:36 +03:00
t , err = time . Parse ( "2006-01-02 15:04:05-07:00" , value . ( string ) )
2020-05-30 23:19:05 +03:00
if err != nil {
return errors . New ( fmt . Sprintf ( "unsupported date time format: %s" , value ) )
}
case time . Time :
2020-10-16 13:49:36 +03:00
t = value . ( time . Time )
2020-05-30 23:19:05 +03:00
break
default :
return errors . New ( fmt . Sprintf ( "unsupported type: %T" , value ) )
}
2020-10-16 13:49:36 +03:00
t = time . Unix ( 0 , ( t . UnixNano ( ) / int64 ( time . Millisecond ) ) * int64 ( time . Millisecond ) ) // round to millisecond precision
* j = CustomTime ( t )
2020-05-30 23:19:05 +03:00
return nil
}
func ( j CustomTime ) Value ( ) ( driver . Value , error ) {
2020-10-16 13:49:36 +03:00
t := time . Unix ( 0 , j . T ( ) . UnixNano ( ) / int64 ( time . Millisecond ) * int64 ( time . Millisecond ) ) // round to millisecond precision
return t , nil
2020-05-30 23:19:05 +03:00
}
2021-04-25 10:21:21 +03:00
func ( j * CustomTime ) Hash ( ) ( uint64 , error ) {
return uint64 ( ( j . T ( ) . UnixNano ( ) / 1000 ) / 1000 ) , nil
}
2020-05-30 23:19:05 +03:00
func ( j CustomTime ) String ( ) string {
2021-04-25 10:21:21 +03:00
return j . T ( ) . String ( )
2020-05-30 23:19:05 +03:00
}
2020-10-16 13:49:36 +03:00
func ( j CustomTime ) T ( ) time . Time {
2020-05-30 23:19:05 +03:00
return time . Time ( j )
}
2020-11-07 14:01:35 +03:00
func ( j CustomTime ) Valid ( ) bool {
return j . T ( ) . Unix ( ) >= 0
}