🎨 Update project structure
This commit is contained in:
80
pkg/internal/models/accounts.go
Normal file
80
pkg/internal/models/accounts.go
Normal file
@ -0,0 +1,80 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
BaseModel
|
||||
|
||||
Name string `json:"name" gorm:"uniqueIndex"`
|
||||
Nick string `json:"nick"`
|
||||
Description string `json:"description"`
|
||||
Avatar *uint `json:"avatar"`
|
||||
Banner *uint `json:"banner"`
|
||||
ConfirmedAt *time.Time `json:"confirmed_at"`
|
||||
PermNodes datatypes.JSONMap `json:"perm_nodes"`
|
||||
|
||||
Profile AccountProfile `json:"profile"`
|
||||
PersonalPage AccountPage `json:"personal_page"`
|
||||
Badges []Badge `json:"badges"`
|
||||
Contacts []AccountContact `json:"contacts"`
|
||||
RealmIdentities []RealmMember `json:"realm_identities"`
|
||||
|
||||
Tickets []AuthTicket `json:"tickets"`
|
||||
Factors []AuthFactor `json:"factors"`
|
||||
|
||||
Events []ActionEvent `json:"events"`
|
||||
MagicTokens []MagicToken `json:"-" gorm:"foreignKey:AssignTo"`
|
||||
|
||||
ThirdClients []ThirdClient `json:"clients"`
|
||||
|
||||
Notifications []Notification `json:"notifications" gorm:"foreignKey:RecipientID"`
|
||||
NotifySubscribers []NotificationSubscriber `json:"notify_subscribers"`
|
||||
|
||||
Friendships []AccountFriendship `json:"friendships" gorm:"foreignKey:AccountID"`
|
||||
RelatedFriendships []AccountFriendship `json:"related_friendships" gorm:"foreignKey:RelatedID"`
|
||||
}
|
||||
|
||||
func (v Account) GetAvatar() *string {
|
||||
if v.Avatar != nil {
|
||||
return lo.ToPtr(fmt.Sprintf("%s/api/attachments/%d", viper.GetString("paperclip.endpoint"), *v.Avatar))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Account) GetBanner() *string {
|
||||
if v.Banner != nil {
|
||||
return lo.ToPtr(fmt.Sprintf("%s/api/attachments/%d", viper.GetString("paperclip.endpoint"), *v.Banner))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Account) GetPrimaryEmail() AccountContact {
|
||||
val, _ := lo.Find(v.Contacts, func(item AccountContact) bool {
|
||||
return item.Type == EmailAccountContact && item.IsPrimary
|
||||
})
|
||||
return val
|
||||
}
|
||||
|
||||
type AccountContactType = int8
|
||||
|
||||
const (
|
||||
EmailAccountContact = AccountContactType(iota)
|
||||
)
|
||||
|
||||
type AccountContact struct {
|
||||
BaseModel
|
||||
|
||||
Type int8 `json:"type"`
|
||||
Content string `json:"content" gorm:"uniqueIndex"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsPrimary bool `json:"is_primary"`
|
||||
VerifiedAt *time.Time `json:"verified_at"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
64
pkg/internal/models/auth.go
Normal file
64
pkg/internal/models/auth.go
Normal file
@ -0,0 +1,64 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
type AuthFactorType = int8
|
||||
|
||||
const (
|
||||
PasswordAuthFactor = AuthFactorType(iota)
|
||||
EmailPasswordFactor
|
||||
)
|
||||
|
||||
type AuthFactor struct {
|
||||
BaseModel
|
||||
|
||||
Type int8 `json:"type"`
|
||||
Secret string `json:"-"`
|
||||
Config JSONMap `json:"config"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
type AuthTicket struct {
|
||||
BaseModel
|
||||
|
||||
Location string `json:"location"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
RequireMFA bool `json:"require_mfa"`
|
||||
RequireAuthenticate bool `json:"require_authenticate"`
|
||||
Claims datatypes.JSONSlice[string] `json:"claims"`
|
||||
Audiences datatypes.JSONSlice[string] `json:"audiences"`
|
||||
GrantToken *string `json:"grant_token"`
|
||||
AccessToken *string `json:"access_token"`
|
||||
RefreshToken *string `json:"refresh_token"`
|
||||
ExpiredAt *time.Time `json:"expired_at"`
|
||||
AvailableAt *time.Time `json:"available_at"`
|
||||
LastGrantAt *time.Time `json:"last_grant_at"`
|
||||
ClientID *uint `json:"client_id"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
func (v AuthTicket) IsAvailable() error {
|
||||
if v.RequireMFA || v.RequireAuthenticate {
|
||||
return fmt.Errorf("ticket isn't authenticated yet")
|
||||
}
|
||||
if v.AvailableAt != nil && time.Now().Unix() < v.AvailableAt.Unix() {
|
||||
return fmt.Errorf("ticket isn't available yet")
|
||||
}
|
||||
if v.ExpiredAt != nil && time.Now().Unix() > v.ExpiredAt.Unix() {
|
||||
return fmt.Errorf("ticket expired")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuthContext struct {
|
||||
Ticket AuthTicket `json:"ticket"`
|
||||
Account Account `json:"account"`
|
||||
LastUsedAt time.Time `json:"last_used_at"`
|
||||
}
|
11
pkg/internal/models/badges.go
Normal file
11
pkg/internal/models/badges.go
Normal file
@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type Badge struct {
|
||||
BaseModel
|
||||
|
||||
Type string `json:"type"`
|
||||
Metadata datatypes.JSONMap `json:"metadata"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
17
pkg/internal/models/base.go
Normal file
17
pkg/internal/models/base.go
Normal file
@ -0,0 +1,17 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type JSONMap = datatypes.JSONType[map[string]any]
|
||||
|
||||
type BaseModel struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
||||
}
|
18
pkg/internal/models/clients.go
Normal file
18
pkg/internal/models/clients.go
Normal file
@ -0,0 +1,18 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type ThirdClient struct {
|
||||
BaseModel
|
||||
|
||||
Alias string `json:"alias" gorm:"uniqueIndex"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Secret string `json:"secret"`
|
||||
Urls datatypes.JSONSlice[string] `json:"urls"`
|
||||
Callbacks datatypes.JSONSlice[string] `json:"callbacks"`
|
||||
Sessions []AuthTicket `json:"tickets" gorm:"foreignKey:ClientID"`
|
||||
Notifications []Notification `json:"notifications" gorm:"foreignKey:SenderID"`
|
||||
IsDraft bool `json:"is_draft"`
|
||||
AccountID *uint `json:"account_id"`
|
||||
}
|
12
pkg/internal/models/events.go
Normal file
12
pkg/internal/models/events.go
Normal file
@ -0,0 +1,12 @@
|
||||
package models
|
||||
|
||||
type ActionEvent struct {
|
||||
BaseModel
|
||||
|
||||
Type string `json:"type"`
|
||||
Target string `json:"target"`
|
||||
Location string `json:"location"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
20
pkg/internal/models/friendships.go
Normal file
20
pkg/internal/models/friendships.go
Normal file
@ -0,0 +1,20 @@
|
||||
package models
|
||||
|
||||
type FriendshipStatus = int8
|
||||
|
||||
const (
|
||||
FriendshipPending = FriendshipStatus(iota)
|
||||
FriendshipActive
|
||||
FriendshipBlocked
|
||||
)
|
||||
|
||||
type AccountFriendship struct {
|
||||
BaseModel
|
||||
|
||||
AccountID uint `json:"account_id"`
|
||||
RelatedID uint `json:"related_id"`
|
||||
BlockedBy *uint `json:"blocked_by"`
|
||||
Account Account `json:"account"`
|
||||
Related Account `json:"related"`
|
||||
Status FriendshipStatus `json:"status"`
|
||||
}
|
40
pkg/internal/models/notifications.go
Normal file
40
pkg/internal/models/notifications.go
Normal file
@ -0,0 +1,40 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
BaseModel
|
||||
|
||||
Type string `json:"type"`
|
||||
Subject string `json:"subject"`
|
||||
Content string `json:"content"`
|
||||
Metadata datatypes.JSONMap `json:"metadata"`
|
||||
Links datatypes.JSONSlice[NotificationLink] `json:"links"`
|
||||
IsRealtime bool `json:"is_realtime" gorm:"-"`
|
||||
IsForcePush bool `json:"is_force_push" gorm:"-"`
|
||||
SenderID *uint `json:"sender_id"`
|
||||
RecipientID uint `json:"recipient_id"`
|
||||
}
|
||||
|
||||
// NotificationLink Used to embed into notify and render actions
|
||||
type NotificationLink struct {
|
||||
Label string `json:"label"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
const (
|
||||
NotifySubscriberFirebase = "firebase"
|
||||
NotifySubscriberAPNs = "apple"
|
||||
)
|
||||
|
||||
type NotificationSubscriber struct {
|
||||
BaseModel
|
||||
|
||||
UserAgent string `json:"user_agent"`
|
||||
Provider string `json:"provider"`
|
||||
DeviceID string `json:"device_id" gorm:"uniqueIndex"`
|
||||
DeviceToken string `json:"device_token"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
31
pkg/internal/models/profiles.go
Normal file
31
pkg/internal/models/profiles.go
Normal file
@ -0,0 +1,31 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/datatypes"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AccountProfile struct {
|
||||
BaseModel
|
||||
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Experience uint64 `json:"experience"`
|
||||
Birthday *time.Time `json:"birthday"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
type AccountPage struct {
|
||||
BaseModel
|
||||
|
||||
Content string `json:"content"`
|
||||
Script string `json:"script"`
|
||||
Style string `json:"style"`
|
||||
Links datatypes.JSONSlice[AccountPageLinks] `json:"links"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
type AccountPageLinks struct {
|
||||
Label string `json:"label"`
|
||||
Url string `json:"url"`
|
||||
}
|
23
pkg/internal/models/realms.go
Normal file
23
pkg/internal/models/realms.go
Normal file
@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
type Realm struct {
|
||||
BaseModel
|
||||
|
||||
Alias string `json:"alias" gorm:"uniqueIndex"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Members []RealmMember `json:"members"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsCommunity bool `json:"is_community"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
type RealmMember struct {
|
||||
BaseModel
|
||||
|
||||
RealmID uint `json:"realm_id"`
|
||||
AccountID uint `json:"account_id"`
|
||||
Realm Realm `json:"realm"`
|
||||
Account Account `json:"account"`
|
||||
PowerLevel int `json:"power_level"`
|
||||
}
|
19
pkg/internal/models/tokens.go
Normal file
19
pkg/internal/models/tokens.go
Normal file
@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type MagicTokenType = int8
|
||||
|
||||
const (
|
||||
ConfirmMagicToken = MagicTokenType(iota)
|
||||
RegistrationMagicToken
|
||||
)
|
||||
|
||||
type MagicToken struct {
|
||||
BaseModel
|
||||
|
||||
Code string `json:"code"`
|
||||
Type int8 `json:"type"`
|
||||
AssignTo *uint `json:"assign_to"`
|
||||
ExpiredAt *time.Time `json:"expired_at"`
|
||||
}
|
21
pkg/internal/models/unified.go
Normal file
21
pkg/internal/models/unified.go
Normal file
@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
import jsoniter "github.com/json-iterator/go"
|
||||
|
||||
type UnifiedCommand struct {
|
||||
Action string `json:"w"`
|
||||
Message string `json:"m"`
|
||||
Payload any `json:"p"`
|
||||
}
|
||||
|
||||
func UnifiedCommandFromError(err error) UnifiedCommand {
|
||||
return UnifiedCommand{
|
||||
Action: "error",
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
func (v UnifiedCommand) Marshal() []byte {
|
||||
data, _ := jsoniter.Marshal(v)
|
||||
return data
|
||||
}
|
Reference in New Issue
Block a user