snapshot of https://github.com/traggo/server.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
build / build (push) Failing after 3s
Some checks failed
build / build (push) Failing after 3s
This commit is contained in:
17
model/all.go
Normal file
17
model/all.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
// All returns all schema instances.
|
||||
func All() []interface{} {
|
||||
return []interface{}{
|
||||
new(TagDefinition),
|
||||
new(User),
|
||||
new(Device),
|
||||
new(TimeSpan),
|
||||
new(TimeSpanTag),
|
||||
new(UserSetting),
|
||||
new(Dashboard),
|
||||
new(DashboardEntry),
|
||||
new(DashboardTagFilter),
|
||||
new(DashboardRange),
|
||||
}
|
||||
}
|
||||
17
model/all_test.go
Normal file
17
model/all_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/traggo/server/model"
|
||||
)
|
||||
|
||||
func TestAll_NoDuplicateEntries(t *testing.T) {
|
||||
all := model.All()
|
||||
var checkedItems []interface{}
|
||||
for _, item := range all {
|
||||
assert.NotContains(t, checkedItems, item)
|
||||
checkedItems = append(checkedItems, item)
|
||||
}
|
||||
}
|
||||
106
model/dashboard.go
Normal file
106
model/dashboard.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DashboardRange a named range of a dashboard.
|
||||
type DashboardRange struct {
|
||||
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
|
||||
Name string
|
||||
DashboardID int `gorm:"type:int REFERENCES dashboards(id) ON DELETE CASCADE"`
|
||||
Editable bool
|
||||
From string
|
||||
To string
|
||||
}
|
||||
|
||||
// Dashboard a dashboard
|
||||
type Dashboard struct {
|
||||
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
|
||||
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
|
||||
Name string
|
||||
Entries []DashboardEntry
|
||||
Ranges []DashboardRange
|
||||
}
|
||||
|
||||
// DashboardEntry an entry which represents a diagram in a dashboard.
|
||||
type DashboardEntry struct {
|
||||
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
|
||||
DashboardID int `gorm:"type:int REFERENCES dashboards(id) ON DELETE CASCADE"`
|
||||
Title string
|
||||
Total bool `gorm:"default:false"`
|
||||
Type DashboardType
|
||||
Keys string
|
||||
Interval Interval
|
||||
RangeID int
|
||||
RangeFrom string
|
||||
RangeTo string
|
||||
TagFilters []DashboardTagFilter
|
||||
|
||||
MobilePosition string
|
||||
DesktopPosition string
|
||||
}
|
||||
|
||||
// DashboardTagFilter a tag for filtering timespans
|
||||
type DashboardTagFilter struct {
|
||||
DashboardEntryID int `gorm:"type:int REFERENCES dashboard_entries(id) ON DELETE CASCADE"`
|
||||
Key string
|
||||
StringValue string
|
||||
Include bool
|
||||
}
|
||||
|
||||
// DashboardType the dashboard type
|
||||
type DashboardType string
|
||||
|
||||
// Value for db
|
||||
func (t DashboardType) Value() (driver.Value, error) {
|
||||
return string(t), nil
|
||||
}
|
||||
|
||||
// Scan for db
|
||||
func (t *DashboardType) Scan(value interface{}) error {
|
||||
s, ok := value.([]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected string but was %#v", value)
|
||||
}
|
||||
*t = DashboardType(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Interval the interval in which the diagram data should be grouped.
|
||||
type Interval string
|
||||
|
||||
// Value for db
|
||||
func (t Interval) Value() (driver.Value, error) {
|
||||
return string(t), nil
|
||||
}
|
||||
|
||||
// Scan for db
|
||||
func (t *Interval) Scan(value interface{}) error {
|
||||
s, ok := value.([]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected string but was %#v", value)
|
||||
}
|
||||
*t = Interval(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// No lint errors please.
|
||||
const (
|
||||
TypePieChart DashboardType = "piechart"
|
||||
TypeBarChart DashboardType = "barchart"
|
||||
TypeLineChart DashboardType = "linechart"
|
||||
HorizontalTable DashboardType = "horizontaltable"
|
||||
VerticalTable DashboardType = "verticaltable"
|
||||
TypeStackedBarChart DashboardType = "stackedbarchart"
|
||||
|
||||
IntervalHourly Interval = "hourly"
|
||||
IntervalDaily Interval = "daily"
|
||||
IntervalWeekly Interval = "weekly"
|
||||
IntervalMonthly Interval = "monthly"
|
||||
IntervalYearly Interval = "yearly"
|
||||
IntervalSingle Interval = "single"
|
||||
|
||||
NoRangeIDDefined = -1
|
||||
)
|
||||
68
model/device.go
Normal file
68
model/device.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Device represents something which can connect to traggo
|
||||
type Device struct {
|
||||
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
|
||||
Token string `gorm:"unique"`
|
||||
Name string
|
||||
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
|
||||
CreatedAt time.Time
|
||||
Type DeviceType
|
||||
ActiveAt time.Time
|
||||
}
|
||||
|
||||
// DeviceType the device type
|
||||
type DeviceType string
|
||||
|
||||
// Value for db
|
||||
func (t DeviceType) Value() (driver.Value, error) {
|
||||
return string(t), nil
|
||||
}
|
||||
|
||||
// Scan for db
|
||||
func (t *DeviceType) Scan(value interface{}) error {
|
||||
s, ok := value.([]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected []byte but was %#v", value)
|
||||
}
|
||||
*t = DeviceType(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Seconds returns the amount of seconds after the device expires.
|
||||
func (t DeviceType) Seconds() int {
|
||||
switch t {
|
||||
case TypeLongExpiry:
|
||||
return 60 * 60 * 24 * 30
|
||||
case TypeShortExpiry:
|
||||
return 60 * 60
|
||||
case TypeNoExpiry:
|
||||
return 60 * 60 * 24 * 365
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Valid checks if the device type is valid.
|
||||
func (t DeviceType) Valid() error {
|
||||
switch t {
|
||||
case TypeNoExpiry, TypeShortExpiry, TypeLongExpiry:
|
||||
return nil
|
||||
default:
|
||||
return errors.New("unknown device type")
|
||||
}
|
||||
}
|
||||
|
||||
// Device types
|
||||
const (
|
||||
TypeShortExpiry DeviceType = "ShortExpiry"
|
||||
TypeLongExpiry DeviceType = "LongExpiry"
|
||||
TypeNoExpiry DeviceType = "NoExpiry"
|
||||
)
|
||||
26
model/device_test.go
Normal file
26
model/device_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
dType := DeviceType("abc")
|
||||
require.Error(t, dType.Valid(), "unknown type")
|
||||
|
||||
require.Equal(t, TypeShortExpiry.Seconds(), 3600)
|
||||
require.Equal(t, TypeLongExpiry.Seconds(), 2592000)
|
||||
require.Equal(t, TypeNoExpiry.Seconds(), 31536000)
|
||||
value, err := TypeNoExpiry.Value()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value, "NoExpiry")
|
||||
require.Nil(t, TypeNoExpiry.Valid())
|
||||
|
||||
var scan DeviceType
|
||||
|
||||
err = scan.Scan([]byte("NoExpiry"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, TypeNoExpiry, scan)
|
||||
}
|
||||
49
model/setting.go
Normal file
49
model/setting.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// UserSetting a setting for a user.
|
||||
type UserSetting struct {
|
||||
UserID int `gorm:"primary_key;unique_index"`
|
||||
Theme string
|
||||
DateLocale string
|
||||
FirstDayOfTheWeek string
|
||||
DateTimeInputStyle string
|
||||
}
|
||||
|
||||
// Settings constants
|
||||
const (
|
||||
ThemeGruvboxDark = "GruvboxDark"
|
||||
ThemeGruvboxLight = "GruvboxLight"
|
||||
ThemeMaterialDark = "MaterialDark"
|
||||
ThemeMaterialLight = "MaterialLight"
|
||||
|
||||
DateLocaleGerman = "German"
|
||||
DateLocaleAmerican = "American"
|
||||
DateLocaleAmerican24h = "American24h"
|
||||
DateLocaleBritish = "British"
|
||||
DateLocaleAustralian = "Australian"
|
||||
|
||||
DateTimeInputFancy = "Fancy"
|
||||
DateTimeInputNative = "Native"
|
||||
)
|
||||
|
||||
var daysOfWeek = map[string]time.Weekday{
|
||||
"Sunday": time.Sunday,
|
||||
"Monday": time.Monday,
|
||||
"Tuesday": time.Tuesday,
|
||||
"Wednesday": time.Wednesday,
|
||||
"Thursday": time.Thursday,
|
||||
"Friday": time.Friday,
|
||||
"Saturday": time.Saturday,
|
||||
}
|
||||
|
||||
// FirstDayOfTheWeekTimeWeekday returns the configured first day of the week.
|
||||
func (s UserSetting) FirstDayOfTheWeekTimeWeekday() time.Weekday {
|
||||
return daysOfWeek[s.FirstDayOfTheWeek]
|
||||
}
|
||||
|
||||
// LastDayOfTheWeekTimeWeekday returns the configured last day of the week.
|
||||
func (s UserSetting) LastDayOfTheWeekTimeWeekday() time.Weekday {
|
||||
return daysOfWeek[(daysOfWeek[s.FirstDayOfTheWeek] - 1).String()]
|
||||
}
|
||||
9
model/tagdefinition.go
Normal file
9
model/tagdefinition.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
// TagDefinition describes a tag.
|
||||
type TagDefinition struct {
|
||||
Key string
|
||||
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
|
||||
Color string
|
||||
Usages int `gorm:"-"`
|
||||
}
|
||||
48
model/time.go
Normal file
48
model/time.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time scalar type for graphql
|
||||
type Time time.Time
|
||||
|
||||
// Time returns the wrapped time
|
||||
func (t Time) Time() time.Time {
|
||||
return time.Time(t)
|
||||
}
|
||||
|
||||
// OmitTimeZone omits the time zone and removes a utc date.
|
||||
func (t Time) OmitTimeZone() time.Time {
|
||||
x := t.Time()
|
||||
return time.Date(x.Year(), x.Month(), x.Day(), x.Hour(), x.Minute(), x.Second(), x.Nanosecond(), time.UTC)
|
||||
}
|
||||
|
||||
// UTC changes the timezone to utc.
|
||||
func (t Time) UTC() time.Time {
|
||||
return t.Time().UTC()
|
||||
}
|
||||
|
||||
// MarshalGQL implements the graphql.Marshaler interface
|
||||
func (t Time) MarshalGQL(w io.Writer) {
|
||||
if _, err := w.Write([]byte(fmt.Sprintf(`"%s"`, t.Time().Format(time.RFC3339)))); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalGQL implements the graphql.Unmarshaler interface
|
||||
func (t *Time) UnmarshalGQL(v interface{}) error {
|
||||
raw, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("time must be a string")
|
||||
}
|
||||
|
||||
parse, err := time.Parse(time.RFC3339, raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = Time(parse)
|
||||
return nil
|
||||
}
|
||||
82
model/time_test.go
Normal file
82
model/time_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTime_MarshalGQL(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
expected := `2009-06-30T18:30:00+02:00`
|
||||
parse, err := time.Parse(time.RFC3339, expected)
|
||||
assert.Nil(t, err)
|
||||
toTest := Time(parse)
|
||||
toTest.MarshalGQL(&buffer)
|
||||
actual := buffer.String()
|
||||
assert.Equal(t, `"`+expected+`"`, actual)
|
||||
}
|
||||
|
||||
func TestTime_MarshalGQL_fails(t *testing.T) {
|
||||
toTest := &Time{}
|
||||
assert.Panics(t, func() {
|
||||
toTest.MarshalGQL(&failWriter{})
|
||||
})
|
||||
}
|
||||
|
||||
type failWriter struct {
|
||||
}
|
||||
|
||||
func (*failWriter) Write(p []byte) (n int, err error) {
|
||||
return 0, errors.New("uff")
|
||||
}
|
||||
|
||||
func TestTime_UnmarshalGQL_success(t *testing.T) {
|
||||
date := "2009-06-30T18:30:00+02:00"
|
||||
parse, err := time.Parse(time.RFC3339, date)
|
||||
assert.Nil(t, err)
|
||||
expected := Time(parse)
|
||||
|
||||
actual := &Time{}
|
||||
err = actual.UnmarshalGQL(date)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, expected, *actual)
|
||||
}
|
||||
|
||||
func TestTime_OmitTimeZone(t *testing.T) {
|
||||
date := "2009-06-30T18:30:00+02:00"
|
||||
tzDate, err := time.Parse(time.RFC3339, date)
|
||||
assert.Nil(t, err)
|
||||
utcDate := "2009-06-30T18:30:00Z"
|
||||
withoutTz, err := time.Parse(time.RFC3339, utcDate)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, withoutTz, Time(tzDate).OmitTimeZone())
|
||||
}
|
||||
|
||||
func TestTime_UTC(t *testing.T) {
|
||||
date := "2009-06-30T18:30:00+02:00"
|
||||
parse, err := time.Parse(time.RFC3339, date)
|
||||
assert.Nil(t, err)
|
||||
without := "2009-06-30T16:30:00Z"
|
||||
withoutTz, err := time.Parse(time.RFC3339, without)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, withoutTz, Time(parse).UTC())
|
||||
}
|
||||
|
||||
func TestTime_UnmarshalGQL_failInvalidType(t *testing.T) {
|
||||
actual := &Time{}
|
||||
err := actual.UnmarshalGQL(1)
|
||||
assert.EqualError(t, err, "time must be a string")
|
||||
}
|
||||
|
||||
func TestTime_UnmarshalGQL_invalidFormat(t *testing.T) {
|
||||
actual := &Time{}
|
||||
err := actual.UnmarshalGQL("lol")
|
||||
assert.EqualError(t, err, `parsing time "lol" as "2006-01-02T15:04:05Z07:00": cannot parse "lol" as "2006"`)
|
||||
}
|
||||
23
model/timespan.go
Normal file
23
model/timespan.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// TimeSpan is basically a tagged time range.
|
||||
type TimeSpan struct {
|
||||
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
|
||||
StartUTC time.Time
|
||||
EndUTC *time.Time
|
||||
StartUserTime time.Time
|
||||
EndUserTime *time.Time
|
||||
OffsetUTC int
|
||||
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
|
||||
Tags []TimeSpanTag
|
||||
Note string
|
||||
}
|
||||
|
||||
// TimeSpanTag is a tag for a time range
|
||||
type TimeSpanTag struct {
|
||||
TimeSpanID int `gorm:"type:int REFERENCES time_spans(id) ON DELETE CASCADE"`
|
||||
Key string
|
||||
StringValue string
|
||||
}
|
||||
9
model/user.go
Normal file
9
model/user.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
// User holds information about credentials and authorizations.
|
||||
type User struct {
|
||||
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
|
||||
Name string `gorm:"unique"`
|
||||
Pass []byte
|
||||
Admin bool
|
||||
}
|
||||
8
model/version.go
Normal file
8
model/version.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package model
|
||||
|
||||
// The Version of traggo.
|
||||
type Version struct {
|
||||
Commit string
|
||||
Name string
|
||||
BuildDate string
|
||||
}
|
||||
Reference in New Issue
Block a user