Rename cavage singing func, add import for server
All checks were successful
/ docker (push) Successful in 4m1s

This commit is contained in:
Melody Becker 2025-04-15 14:51:07 +02:00
parent 5e13817563
commit 08f6de0bd7
Signed by: mstar
SSH key fingerprint: SHA256:9VAo09aaVNTWKzPW7Hq2LW+ox9OdwmTSHRoD4mlz1yI
39 changed files with 2035 additions and 364 deletions

View file

@ -3,20 +3,34 @@ package activitypub
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"time"
"git.mstar.dev/mstar/goutils/other"
"git.mstar.dev/mstar/goutils/sliceutils"
"github.com/rs/zerolog/log"
"gorm.io/gorm"
"git.mstar.dev/mstar/linstrom/config"
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
"git.mstar.dev/mstar/linstrom/storage-new/models"
webshared "git.mstar.dev/mstar/linstrom/web/shared"
)
var interestingMetadata = []string{
"nodeDescription",
"maintainer",
"tosUrl",
"nodeAdmins",
"privacyPolicyUrl",
"inquiryUrl",
"impressumUrl",
"donationUrl",
"staffAccounts",
}
func ImportRemoteAccount(targetName string) (string, error) {
type InboundUserKey struct {
Id string `json:"id"`
@ -62,70 +76,363 @@ func ImportRemoteAccount(targetName string) (string, error) {
// Server actor key for signing
linstromActor, err := dbgen.User.Where(dbgen.User.Username.Eq("linstrom")).First()
if err != nil {
return "", err
return "", other.Error("activitypub", "failed to get server actor", err)
}
var response *http.Response
// if config.GlobalConfig.Experimental.UseEd25519Keys {
// response, err = webshared.RequestSignedCavage(
// "GET",
// *APLink.Href,
// nil,
// config.GlobalConfig.General.GetFullPublicUrl()+"/api/activitypub/user/"+linstromActor.ID+"#main-key",
// linstromActor.PrivateKeyEd,
// true,
// )
// } else {
// response, err = webshared.RequestSignedCavage(
// "GET",
// *APLink.Href,
// nil,
// config.GlobalConfig.General.GetFullPublicUrl()+"/api/activitypub/user/"+linstromActor.ID+"#main-key",
// linstromActor.PrivateKeyRsa,
// false,
// )
// }
response, err = customReq(*APLink.Href, linstromActor)
response, err = webshared.RequestSignedCavage("GET", *APLink.Href, nil, linstromActor)
if err != nil {
return "", err
return "", other.Error("activitypub", "failed to complete cavage signed request", err)
}
defer response.Body.Close()
body, _ := io.ReadAll(response.Body)
log.Debug().
log.Trace().
Int("status", response.StatusCode).
Bytes("body", body).
Any("headers", response.Header).
Msg("Response information")
if response.StatusCode != 200 {
return "", errors.New("bad status")
return "", fmt.Errorf("activitypub: invalid status code: %v", response.StatusCode)
}
var data InboundUser
err = json.Unmarshal(body, &data)
if err != nil {
return "", err
return "", other.Error("activitypub", "failed to unmarshal response", err)
}
log.Info().Any("received-data", data).Msg("Response data")
log.Debug().Any("received-data", data).Msg("Response data")
log.Info().Str("user", targetName).Msg("Import completed")
return "", nil
}
func customReq(target string, linstromActor *models.User) (*http.Response, error) {
req, err := webshared.NewRequest("GET", target, nil)
if err != nil {
return nil, err
}
req.Header.Add("Accept", "application/activity+json")
func ImportRemoteServer(host string) (uint, error) {
// Nodeinfo is not locked behind authentication, so don't do it
var keyBytes []byte
if config.GlobalConfig.Experimental.UseEd25519Keys {
keyBytes = linstromActor.PrivateKeyEd
req, err := webshared.NewRequest("GET", "https://"+host+"/.well-known/nodeinfo", nil)
if err != nil {
return 0, other.Error("activitypub", "failed to create overview request", err)
}
response, err := webshared.RequestClient.Do(req)
if err != nil {
return 0, other.Error("activitypub", "overview request failed", err)
}
var nodeInfoOverview webshared.NodeInfoOverview
decoder := json.NewDecoder(response.Body)
err = decoder.Decode(&nodeInfoOverview)
if err != nil {
return 0, other.Error("activitypub", "overview unmarshal failed", err)
}
relevantInfos := sliceutils.Filter(nodeInfoOverview.Links, func(t webshared.NodeInfoLink) bool {
return strings.HasSuffix(t.Rel, "schema/2.0") || strings.HasSuffix(t.Rel, "schema/2.1")
})
var data webshared.NodeInfo2
v21Slice := sliceutils.Filter(relevantInfos, func(t webshared.NodeInfoLink) bool {
return strings.HasSuffix(t.Rel, "schema/2.1")
})
if len(v21Slice) > 0 {
req, err = webshared.NewRequest("GET", v21Slice[0].Href, nil)
if err != nil {
return 0, other.Error("activitypub", "info 2.1 request creation failed", err)
}
} else {
keyBytes = linstromActor.PrivateKeyRsa
req, err = webshared.NewRequest("GET", relevantInfos[0].Href, nil)
if err != nil {
return 0, other.Error("activitypub", "info 2.0 request creation failed", err)
}
}
res, err := webshared.RequestClient.Do(req)
if err != nil {
return 0, other.Error("activitypub", "info request failed to complete", err)
}
decoder = json.NewDecoder(res.Body)
err = decoder.Decode(&data)
if err != nil {
return 0, other.Error("activitypub", "failed to unmarshal info", err)
}
log.Debug().Any("nodeinfo", data).Msg("Server info received")
rs := dbgen.RemoteServer
// rsm := dbgen.RemoteServerMetadata
serverModelType := webshared.MapNodeServerTypeToModelType(data.Software.Name)
existingEntry, err := rs.Where(rs.Domain.Eq(host)).Preload(rs.Metadata).First()
switch err {
case gorm.ErrRecordNotFound:
existingEntry = &models.RemoteServer{
ServerType: serverModelType,
Version: data.Version,
Domain: host,
SpecificType: data.Software.Name,
}
if err = rs.Create(existingEntry); err != nil {
return 0, other.Error("activitypub", "failed to create new server entry", err)
}
case nil:
default:
return 0, other.Error("activitypub", "db failure", err)
}
existingEntry.SpecificType = data.Software.Name
existingEntry.IsSelf = false
existingEntry.ServerType = serverModelType
existingEntry.Version = data.Version
if name, ok := data.Metadata["nodeName"].(string); ok {
existingEntry.Name = name
} else {
existingEntry.Name = host
}
// Cast without check for existence is ok here
// Default value for `Any` is `nil`, which fails to cast to a valid string
if description, ok := data.Metadata["nodeDescription"].(string); ok {
log.Debug().Msg("Description found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "description"
},
)
if len(targets) > 0 {
targets[0].Value = description
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: description,
Key: "description",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "description").
Str("value", description).
Msg("Failed to append new metadata to server")
}
}
}
if maintainer, ok := data.Metadata["maintainer"].(map[string]any); ok {
log.Debug().Msg("Maintainer found")
name, nameOk := maintainer["name"].(string)
email, emailOk := maintainer["email"].(string)
if nameOk && emailOk {
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "maintainer"
},
)
val := fmt.Sprintf("%s <%s>", name, email)
if len(targets) > 0 {
targets[0].Value = val
} else {
err = rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Key: "maintainer",
Value: val,
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "maintainer").
Str("value", val).
Msg("Failed to append new metadata to server")
}
}
}
}
if tosUrl, ok := data.Metadata["tosUrl"].(string); ok {
log.Debug().Msg("Tos url found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "tosUrl"
},
)
if len(targets) > 0 {
targets[0].Value = tosUrl
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: tosUrl,
Key: "tosUrl",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "tosUrl").
Str("value", tosUrl).
Msg("Failed to append new metadata to server")
}
}
}
if nodeAdmins, ok := data.Metadata["nodeAdmins"].([]map[string]any); ok {
log.Debug().Msg("Node admins url found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "nodeAdmins"
},
)
valueBuilder := strings.Builder{}
for _, v := range nodeAdmins {
name, nameOk := v["name"].(string)
email, emailOk := v["email"].(string)
if nameOk && emailOk {
valueBuilder.WriteString(name)
valueBuilder.WriteString(" <")
valueBuilder.WriteString(email)
valueBuilder.WriteString(">;")
}
}
if len(targets) > 0 {
targets[0].Value = valueBuilder.String()
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: valueBuilder.String(),
Key: "nodeAdmins",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "nodeAdmins").
Str("value", valueBuilder.String()).
Msg("Failed to append new metadata to server")
}
}
}
if privacyPolicyUrl, ok := data.Metadata["privacyPolicyUrl"].(string); ok {
log.Debug().Msg("Privacy policy url found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "privacyPolicyUrl"
},
)
if len(targets) > 0 {
targets[0].Value = privacyPolicyUrl
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: privacyPolicyUrl,
Key: "privacyPolicyUrl",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "privacyPolicyUrl").
Str("value", privacyPolicyUrl).
Msg("Failed to append new metadata to server")
}
}
}
if inquiryUrl, ok := data.Metadata["inquiryUrl"].(string); ok {
log.Debug().Msg("Inquiry found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "inquiryUrl"
},
)
if len(targets) > 0 {
targets[0].Value = inquiryUrl
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: inquiryUrl,
Key: "inquiryUrl",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "inquiryUrl").
Str("value", inquiryUrl).
Msg("Failed to append new metadata to server")
}
}
}
if impressumUrl, ok := data.Metadata["impressumUrl"].(string); ok {
log.Debug().Msg("Impressum url found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "impressumUrl"
},
)
if len(targets) > 0 {
targets[0].Value = impressumUrl
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: impressumUrl,
Key: "impressumUrl",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "impressumUrl").
Str("value", impressumUrl).
Msg("Failed to append new metadata to server")
}
}
}
if donationUrl, ok := data.Metadata["donationUrl"].(string); ok {
log.Debug().Msg("Donation url found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "donationUrl"
},
)
if len(targets) > 0 {
targets[0].Value = donationUrl
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: donationUrl,
Key: "donationUrl",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "donationUrl").
Str("value", donationUrl).
Msg("Failed to append new metadata to server")
}
}
}
if staffAccounts, ok := data.Metadata["nodeAdmins"].([]any); ok {
log.Debug().Msg("Node admins url found")
targets := sliceutils.Filter(
existingEntry.Metadata,
func(t models.RemoteServerMetadata) bool {
return t.Key == "staffAccounts"
},
)
valueBuilder := strings.Builder{}
for _, v := range staffAccounts {
if acc, ok := v.(string); ok {
valueBuilder.WriteString(acc)
valueBuilder.WriteString(";")
}
}
if len(targets) > 0 {
targets[0].Value = valueBuilder.String()
} else {
err := rs.Metadata.Model(existingEntry).Append(&models.RemoteServerMetadata{
Value: valueBuilder.String(),
Key: "staffAccounts",
})
if err != nil {
log.Warn().
Err(err).
Uint("server-id", existingEntry.ID).
Str("key", "staffAccounts").
Str("value", valueBuilder.String()).
Msg("Failed to append new metadata to server")
}
}
}
// Sign and send
err = webshared.SignRequest(req, linstromActor.ID+"#main-key", keyBytes, nil)
// err = webshared.SignRequestWithHttpsig(req, linstromActor.ID+"#main-key", keyBytes, nil)
id := existingEntry.ID
existingEntry.ID = 0
_, err = rs.Where(rs.ID.Eq(id)).UpdateColumns(existingEntry)
if err != nil {
return nil, err
return 0, other.Error("activitypub", "failed to store update in db", err)
}
return webshared.RequestClient.Do(req)
return id, nil
}

View file

@ -40,6 +40,12 @@ func newAccessToken(db *gorm.DB, opts ...gen.DOOption) accessToken {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -47,6 +53,19 @@ func newAccessToken(db *gorm.DB, opts ...gen.DOOption) accessToken {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -263,6 +282,12 @@ type accessTokenBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -48,6 +48,19 @@ func newEmote(db *gorm.DB, opts ...gen.DOOption) emote {
}{
RelationField: field.NewRelation("Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
}
_emote.fillFieldMap()
@ -208,6 +221,12 @@ type emoteBelongsToServer struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
func (a emoteBelongsToServer) Where(conds ...field.Expr) *emoteBelongsToServer {

View file

@ -43,6 +43,12 @@ func newFeed(db *gorm.DB, opts ...gen.DOOption) feed {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Owner.Server", "models.RemoteServer"),
Icon: struct {
@ -50,6 +56,19 @@ func newFeed(db *gorm.DB, opts ...gen.DOOption) feed {
}{
RelationField: field.NewRelation("Owner.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Owner.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Owner.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -278,6 +297,12 @@ type feedBelongsToOwner struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -16,32 +16,33 @@ import (
)
var (
Q = new(Query)
AccessToken *accessToken
Emote *emote
Feed *feed
LoginProcessToken *loginProcessToken
MediaMetadata *mediaMetadata
Note *note
NoteTag *noteTag
NoteToAttachment *noteToAttachment
NoteToBoost *noteToBoost
NoteToEmote *noteToEmote
NoteToFeed *noteToFeed
NoteToPing *noteToPing
Notification *notification
Reaction *reaction
RemoteServer *remoteServer
Role *role
User *user
UserAuthMethod *userAuthMethod
UserInfoField *userInfoField
UserRemoteLinks *userRemoteLinks
UserToBeing *userToBeing
UserToPronoun *userToPronoun
UserToRole *userToRole
UserToTag *userToTag
UserToUserRelation *userToUserRelation
Q = new(Query)
AccessToken *accessToken
Emote *emote
Feed *feed
LoginProcessToken *loginProcessToken
MediaMetadata *mediaMetadata
Note *note
NoteTag *noteTag
NoteToAttachment *noteToAttachment
NoteToBoost *noteToBoost
NoteToEmote *noteToEmote
NoteToFeed *noteToFeed
NoteToPing *noteToPing
Notification *notification
Reaction *reaction
RemoteServer *remoteServer
RemoteServerMetadata *remoteServerMetadata
Role *role
User *user
UserAuthMethod *userAuthMethod
UserInfoField *userInfoField
UserRemoteLinks *userRemoteLinks
UserToBeing *userToBeing
UserToPronoun *userToPronoun
UserToRole *userToRole
UserToTag *userToTag
UserToUserRelation *userToUserRelation
)
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
@ -61,6 +62,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
Notification = &Q.Notification
Reaction = &Q.Reaction
RemoteServer = &Q.RemoteServer
RemoteServerMetadata = &Q.RemoteServerMetadata
Role = &Q.Role
User = &Q.User
UserAuthMethod = &Q.UserAuthMethod
@ -75,95 +77,98 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{
db: db,
AccessToken: newAccessToken(db, opts...),
Emote: newEmote(db, opts...),
Feed: newFeed(db, opts...),
LoginProcessToken: newLoginProcessToken(db, opts...),
MediaMetadata: newMediaMetadata(db, opts...),
Note: newNote(db, opts...),
NoteTag: newNoteTag(db, opts...),
NoteToAttachment: newNoteToAttachment(db, opts...),
NoteToBoost: newNoteToBoost(db, opts...),
NoteToEmote: newNoteToEmote(db, opts...),
NoteToFeed: newNoteToFeed(db, opts...),
NoteToPing: newNoteToPing(db, opts...),
Notification: newNotification(db, opts...),
Reaction: newReaction(db, opts...),
RemoteServer: newRemoteServer(db, opts...),
Role: newRole(db, opts...),
User: newUser(db, opts...),
UserAuthMethod: newUserAuthMethod(db, opts...),
UserInfoField: newUserInfoField(db, opts...),
UserRemoteLinks: newUserRemoteLinks(db, opts...),
UserToBeing: newUserToBeing(db, opts...),
UserToPronoun: newUserToPronoun(db, opts...),
UserToRole: newUserToRole(db, opts...),
UserToTag: newUserToTag(db, opts...),
UserToUserRelation: newUserToUserRelation(db, opts...),
db: db,
AccessToken: newAccessToken(db, opts...),
Emote: newEmote(db, opts...),
Feed: newFeed(db, opts...),
LoginProcessToken: newLoginProcessToken(db, opts...),
MediaMetadata: newMediaMetadata(db, opts...),
Note: newNote(db, opts...),
NoteTag: newNoteTag(db, opts...),
NoteToAttachment: newNoteToAttachment(db, opts...),
NoteToBoost: newNoteToBoost(db, opts...),
NoteToEmote: newNoteToEmote(db, opts...),
NoteToFeed: newNoteToFeed(db, opts...),
NoteToPing: newNoteToPing(db, opts...),
Notification: newNotification(db, opts...),
Reaction: newReaction(db, opts...),
RemoteServer: newRemoteServer(db, opts...),
RemoteServerMetadata: newRemoteServerMetadata(db, opts...),
Role: newRole(db, opts...),
User: newUser(db, opts...),
UserAuthMethod: newUserAuthMethod(db, opts...),
UserInfoField: newUserInfoField(db, opts...),
UserRemoteLinks: newUserRemoteLinks(db, opts...),
UserToBeing: newUserToBeing(db, opts...),
UserToPronoun: newUserToPronoun(db, opts...),
UserToRole: newUserToRole(db, opts...),
UserToTag: newUserToTag(db, opts...),
UserToUserRelation: newUserToUserRelation(db, opts...),
}
}
type Query struct {
db *gorm.DB
AccessToken accessToken
Emote emote
Feed feed
LoginProcessToken loginProcessToken
MediaMetadata mediaMetadata
Note note
NoteTag noteTag
NoteToAttachment noteToAttachment
NoteToBoost noteToBoost
NoteToEmote noteToEmote
NoteToFeed noteToFeed
NoteToPing noteToPing
Notification notification
Reaction reaction
RemoteServer remoteServer
Role role
User user
UserAuthMethod userAuthMethod
UserInfoField userInfoField
UserRemoteLinks userRemoteLinks
UserToBeing userToBeing
UserToPronoun userToPronoun
UserToRole userToRole
UserToTag userToTag
UserToUserRelation userToUserRelation
AccessToken accessToken
Emote emote
Feed feed
LoginProcessToken loginProcessToken
MediaMetadata mediaMetadata
Note note
NoteTag noteTag
NoteToAttachment noteToAttachment
NoteToBoost noteToBoost
NoteToEmote noteToEmote
NoteToFeed noteToFeed
NoteToPing noteToPing
Notification notification
Reaction reaction
RemoteServer remoteServer
RemoteServerMetadata remoteServerMetadata
Role role
User user
UserAuthMethod userAuthMethod
UserInfoField userInfoField
UserRemoteLinks userRemoteLinks
UserToBeing userToBeing
UserToPronoun userToPronoun
UserToRole userToRole
UserToTag userToTag
UserToUserRelation userToUserRelation
}
func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query {
return &Query{
db: db,
AccessToken: q.AccessToken.clone(db),
Emote: q.Emote.clone(db),
Feed: q.Feed.clone(db),
LoginProcessToken: q.LoginProcessToken.clone(db),
MediaMetadata: q.MediaMetadata.clone(db),
Note: q.Note.clone(db),
NoteTag: q.NoteTag.clone(db),
NoteToAttachment: q.NoteToAttachment.clone(db),
NoteToBoost: q.NoteToBoost.clone(db),
NoteToEmote: q.NoteToEmote.clone(db),
NoteToFeed: q.NoteToFeed.clone(db),
NoteToPing: q.NoteToPing.clone(db),
Notification: q.Notification.clone(db),
Reaction: q.Reaction.clone(db),
RemoteServer: q.RemoteServer.clone(db),
Role: q.Role.clone(db),
User: q.User.clone(db),
UserAuthMethod: q.UserAuthMethod.clone(db),
UserInfoField: q.UserInfoField.clone(db),
UserRemoteLinks: q.UserRemoteLinks.clone(db),
UserToBeing: q.UserToBeing.clone(db),
UserToPronoun: q.UserToPronoun.clone(db),
UserToRole: q.UserToRole.clone(db),
UserToTag: q.UserToTag.clone(db),
UserToUserRelation: q.UserToUserRelation.clone(db),
db: db,
AccessToken: q.AccessToken.clone(db),
Emote: q.Emote.clone(db),
Feed: q.Feed.clone(db),
LoginProcessToken: q.LoginProcessToken.clone(db),
MediaMetadata: q.MediaMetadata.clone(db),
Note: q.Note.clone(db),
NoteTag: q.NoteTag.clone(db),
NoteToAttachment: q.NoteToAttachment.clone(db),
NoteToBoost: q.NoteToBoost.clone(db),
NoteToEmote: q.NoteToEmote.clone(db),
NoteToFeed: q.NoteToFeed.clone(db),
NoteToPing: q.NoteToPing.clone(db),
Notification: q.Notification.clone(db),
Reaction: q.Reaction.clone(db),
RemoteServer: q.RemoteServer.clone(db),
RemoteServerMetadata: q.RemoteServerMetadata.clone(db),
Role: q.Role.clone(db),
User: q.User.clone(db),
UserAuthMethod: q.UserAuthMethod.clone(db),
UserInfoField: q.UserInfoField.clone(db),
UserRemoteLinks: q.UserRemoteLinks.clone(db),
UserToBeing: q.UserToBeing.clone(db),
UserToPronoun: q.UserToPronoun.clone(db),
UserToRole: q.UserToRole.clone(db),
UserToTag: q.UserToTag.clone(db),
UserToUserRelation: q.UserToUserRelation.clone(db),
}
}
@ -177,90 +182,93 @@ func (q *Query) WriteDB() *Query {
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{
db: db,
AccessToken: q.AccessToken.replaceDB(db),
Emote: q.Emote.replaceDB(db),
Feed: q.Feed.replaceDB(db),
LoginProcessToken: q.LoginProcessToken.replaceDB(db),
MediaMetadata: q.MediaMetadata.replaceDB(db),
Note: q.Note.replaceDB(db),
NoteTag: q.NoteTag.replaceDB(db),
NoteToAttachment: q.NoteToAttachment.replaceDB(db),
NoteToBoost: q.NoteToBoost.replaceDB(db),
NoteToEmote: q.NoteToEmote.replaceDB(db),
NoteToFeed: q.NoteToFeed.replaceDB(db),
NoteToPing: q.NoteToPing.replaceDB(db),
Notification: q.Notification.replaceDB(db),
Reaction: q.Reaction.replaceDB(db),
RemoteServer: q.RemoteServer.replaceDB(db),
Role: q.Role.replaceDB(db),
User: q.User.replaceDB(db),
UserAuthMethod: q.UserAuthMethod.replaceDB(db),
UserInfoField: q.UserInfoField.replaceDB(db),
UserRemoteLinks: q.UserRemoteLinks.replaceDB(db),
UserToBeing: q.UserToBeing.replaceDB(db),
UserToPronoun: q.UserToPronoun.replaceDB(db),
UserToRole: q.UserToRole.replaceDB(db),
UserToTag: q.UserToTag.replaceDB(db),
UserToUserRelation: q.UserToUserRelation.replaceDB(db),
db: db,
AccessToken: q.AccessToken.replaceDB(db),
Emote: q.Emote.replaceDB(db),
Feed: q.Feed.replaceDB(db),
LoginProcessToken: q.LoginProcessToken.replaceDB(db),
MediaMetadata: q.MediaMetadata.replaceDB(db),
Note: q.Note.replaceDB(db),
NoteTag: q.NoteTag.replaceDB(db),
NoteToAttachment: q.NoteToAttachment.replaceDB(db),
NoteToBoost: q.NoteToBoost.replaceDB(db),
NoteToEmote: q.NoteToEmote.replaceDB(db),
NoteToFeed: q.NoteToFeed.replaceDB(db),
NoteToPing: q.NoteToPing.replaceDB(db),
Notification: q.Notification.replaceDB(db),
Reaction: q.Reaction.replaceDB(db),
RemoteServer: q.RemoteServer.replaceDB(db),
RemoteServerMetadata: q.RemoteServerMetadata.replaceDB(db),
Role: q.Role.replaceDB(db),
User: q.User.replaceDB(db),
UserAuthMethod: q.UserAuthMethod.replaceDB(db),
UserInfoField: q.UserInfoField.replaceDB(db),
UserRemoteLinks: q.UserRemoteLinks.replaceDB(db),
UserToBeing: q.UserToBeing.replaceDB(db),
UserToPronoun: q.UserToPronoun.replaceDB(db),
UserToRole: q.UserToRole.replaceDB(db),
UserToTag: q.UserToTag.replaceDB(db),
UserToUserRelation: q.UserToUserRelation.replaceDB(db),
}
}
type queryCtx struct {
AccessToken IAccessTokenDo
Emote IEmoteDo
Feed IFeedDo
LoginProcessToken ILoginProcessTokenDo
MediaMetadata IMediaMetadataDo
Note INoteDo
NoteTag INoteTagDo
NoteToAttachment INoteToAttachmentDo
NoteToBoost INoteToBoostDo
NoteToEmote INoteToEmoteDo
NoteToFeed INoteToFeedDo
NoteToPing INoteToPingDo
Notification INotificationDo
Reaction IReactionDo
RemoteServer IRemoteServerDo
Role IRoleDo
User IUserDo
UserAuthMethod IUserAuthMethodDo
UserInfoField IUserInfoFieldDo
UserRemoteLinks IUserRemoteLinksDo
UserToBeing IUserToBeingDo
UserToPronoun IUserToPronounDo
UserToRole IUserToRoleDo
UserToTag IUserToTagDo
UserToUserRelation IUserToUserRelationDo
AccessToken IAccessTokenDo
Emote IEmoteDo
Feed IFeedDo
LoginProcessToken ILoginProcessTokenDo
MediaMetadata IMediaMetadataDo
Note INoteDo
NoteTag INoteTagDo
NoteToAttachment INoteToAttachmentDo
NoteToBoost INoteToBoostDo
NoteToEmote INoteToEmoteDo
NoteToFeed INoteToFeedDo
NoteToPing INoteToPingDo
Notification INotificationDo
Reaction IReactionDo
RemoteServer IRemoteServerDo
RemoteServerMetadata IRemoteServerMetadataDo
Role IRoleDo
User IUserDo
UserAuthMethod IUserAuthMethodDo
UserInfoField IUserInfoFieldDo
UserRemoteLinks IUserRemoteLinksDo
UserToBeing IUserToBeingDo
UserToPronoun IUserToPronounDo
UserToRole IUserToRoleDo
UserToTag IUserToTagDo
UserToUserRelation IUserToUserRelationDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{
AccessToken: q.AccessToken.WithContext(ctx),
Emote: q.Emote.WithContext(ctx),
Feed: q.Feed.WithContext(ctx),
LoginProcessToken: q.LoginProcessToken.WithContext(ctx),
MediaMetadata: q.MediaMetadata.WithContext(ctx),
Note: q.Note.WithContext(ctx),
NoteTag: q.NoteTag.WithContext(ctx),
NoteToAttachment: q.NoteToAttachment.WithContext(ctx),
NoteToBoost: q.NoteToBoost.WithContext(ctx),
NoteToEmote: q.NoteToEmote.WithContext(ctx),
NoteToFeed: q.NoteToFeed.WithContext(ctx),
NoteToPing: q.NoteToPing.WithContext(ctx),
Notification: q.Notification.WithContext(ctx),
Reaction: q.Reaction.WithContext(ctx),
RemoteServer: q.RemoteServer.WithContext(ctx),
Role: q.Role.WithContext(ctx),
User: q.User.WithContext(ctx),
UserAuthMethod: q.UserAuthMethod.WithContext(ctx),
UserInfoField: q.UserInfoField.WithContext(ctx),
UserRemoteLinks: q.UserRemoteLinks.WithContext(ctx),
UserToBeing: q.UserToBeing.WithContext(ctx),
UserToPronoun: q.UserToPronoun.WithContext(ctx),
UserToRole: q.UserToRole.WithContext(ctx),
UserToTag: q.UserToTag.WithContext(ctx),
UserToUserRelation: q.UserToUserRelation.WithContext(ctx),
AccessToken: q.AccessToken.WithContext(ctx),
Emote: q.Emote.WithContext(ctx),
Feed: q.Feed.WithContext(ctx),
LoginProcessToken: q.LoginProcessToken.WithContext(ctx),
MediaMetadata: q.MediaMetadata.WithContext(ctx),
Note: q.Note.WithContext(ctx),
NoteTag: q.NoteTag.WithContext(ctx),
NoteToAttachment: q.NoteToAttachment.WithContext(ctx),
NoteToBoost: q.NoteToBoost.WithContext(ctx),
NoteToEmote: q.NoteToEmote.WithContext(ctx),
NoteToFeed: q.NoteToFeed.WithContext(ctx),
NoteToPing: q.NoteToPing.WithContext(ctx),
Notification: q.Notification.WithContext(ctx),
Reaction: q.Reaction.WithContext(ctx),
RemoteServer: q.RemoteServer.WithContext(ctx),
RemoteServerMetadata: q.RemoteServerMetadata.WithContext(ctx),
Role: q.Role.WithContext(ctx),
User: q.User.WithContext(ctx),
UserAuthMethod: q.UserAuthMethod.WithContext(ctx),
UserInfoField: q.UserInfoField.WithContext(ctx),
UserRemoteLinks: q.UserRemoteLinks.WithContext(ctx),
UserToBeing: q.UserToBeing.WithContext(ctx),
UserToPronoun: q.UserToPronoun.WithContext(ctx),
UserToRole: q.UserToRole.WithContext(ctx),
UserToTag: q.UserToTag.WithContext(ctx),
UserToUserRelation: q.UserToUserRelation.WithContext(ctx),
}
}

View file

@ -40,6 +40,12 @@ func newLoginProcessToken(db *gorm.DB, opts ...gen.DOOption) loginProcessToken {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -47,6 +53,19 @@ func newLoginProcessToken(db *gorm.DB, opts ...gen.DOOption) loginProcessToken {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -266,6 +285,12 @@ type loginProcessTokenBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -40,6 +40,12 @@ func newNoteTag(db *gorm.DB, opts ...gen.DOOption) noteTag {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -111,6 +117,12 @@ func newNoteTag(db *gorm.DB, opts ...gen.DOOption) noteTag {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -118,6 +130,19 @@ func newNoteTag(db *gorm.DB, opts ...gen.DOOption) noteTag {
}{
RelationField: field.NewRelation("Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -437,6 +462,12 @@ type noteTagBelongsToNote struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -40,6 +40,12 @@ func newNoteToAttachment(db *gorm.DB, opts ...gen.DOOption) noteToAttachment {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -111,6 +117,12 @@ func newNoteToAttachment(db *gorm.DB, opts ...gen.DOOption) noteToAttachment {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -118,6 +130,19 @@ func newNoteToAttachment(db *gorm.DB, opts ...gen.DOOption) noteToAttachment {
}{
RelationField: field.NewRelation("Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -445,6 +470,12 @@ type noteToAttachmentBelongsToNote struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -39,6 +39,12 @@ func newNoteToBoost(db *gorm.DB, opts ...gen.DOOption) noteToBoost {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -46,6 +52,19 @@ func newNoteToBoost(db *gorm.DB, opts ...gen.DOOption) noteToBoost {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -378,6 +397,12 @@ type noteToBoostBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -40,6 +40,12 @@ func newNoteToEmote(db *gorm.DB, opts ...gen.DOOption) noteToEmote {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -111,6 +117,12 @@ func newNoteToEmote(db *gorm.DB, opts ...gen.DOOption) noteToEmote {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -118,6 +130,19 @@ func newNoteToEmote(db *gorm.DB, opts ...gen.DOOption) noteToEmote {
}{
RelationField: field.NewRelation("Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -445,6 +470,12 @@ type noteToEmoteBelongsToNote struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -40,6 +40,12 @@ func newNoteToFeed(db *gorm.DB, opts ...gen.DOOption) noteToFeed {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -111,6 +117,12 @@ func newNoteToFeed(db *gorm.DB, opts ...gen.DOOption) noteToFeed {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -118,6 +130,19 @@ func newNoteToFeed(db *gorm.DB, opts ...gen.DOOption) noteToFeed {
}{
RelationField: field.NewRelation("Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -437,6 +462,12 @@ type noteToFeedBelongsToNote struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -40,6 +40,12 @@ func newNoteToPing(db *gorm.DB, opts ...gen.DOOption) noteToPing {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -111,6 +117,12 @@ func newNoteToPing(db *gorm.DB, opts ...gen.DOOption) noteToPing {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -118,6 +130,19 @@ func newNoteToPing(db *gorm.DB, opts ...gen.DOOption) noteToPing {
}{
RelationField: field.NewRelation("Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -445,6 +470,12 @@ type noteToPingBelongsToNote struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -52,6 +52,12 @@ func newNote(db *gorm.DB, opts ...gen.DOOption) note {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -162,6 +168,12 @@ func newNote(db *gorm.DB, opts ...gen.DOOption) note {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -233,6 +245,12 @@ func newNote(db *gorm.DB, opts ...gen.DOOption) note {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("AttachmentRelations.Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -240,6 +258,19 @@ func newNote(db *gorm.DB, opts ...gen.DOOption) note {
}{
RelationField: field.NewRelation("AttachmentRelations.Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("AttachmentRelations.Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("AttachmentRelations.Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -618,6 +649,12 @@ type noteHasManyAttachmentRelations struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -45,6 +45,12 @@ func newNotification(db *gorm.DB, opts ...gen.DOOption) notification {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("ForUser.Server", "models.RemoteServer"),
Icon: struct {
@ -52,6 +58,19 @@ func newNotification(db *gorm.DB, opts ...gen.DOOption) notification {
}{
RelationField: field.NewRelation("ForUser.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("ForUser.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("ForUser.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -407,6 +426,12 @@ type notificationBelongsToForUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -44,6 +44,12 @@ func newReaction(db *gorm.DB, opts ...gen.DOOption) reaction {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -115,6 +121,12 @@ func newReaction(db *gorm.DB, opts ...gen.DOOption) reaction {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("Note.Creator.Server", "models.RemoteServer"),
Icon: struct {
@ -122,6 +134,19 @@ func newReaction(db *gorm.DB, opts ...gen.DOOption) reaction {
}{
RelationField: field.NewRelation("Note.Creator.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("Note.Creator.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -469,6 +494,12 @@ type reactionBelongsToNote struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -0,0 +1,509 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dbgen
import (
"context"
"git.mstar.dev/mstar/linstrom/storage-new/models"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
)
func newRemoteServerMetadata(db *gorm.DB, opts ...gen.DOOption) remoteServerMetadata {
_remoteServerMetadata := remoteServerMetadata{}
_remoteServerMetadata.remoteServerMetadataDo.UseDB(db, opts...)
_remoteServerMetadata.remoteServerMetadataDo.UseModel(&models.RemoteServerMetadata{})
tableName := _remoteServerMetadata.remoteServerMetadataDo.TableName()
_remoteServerMetadata.ALL = field.NewAsterisk(tableName)
_remoteServerMetadata.ID = field.NewUint(tableName, "id")
_remoteServerMetadata.CreatedAt = field.NewTime(tableName, "created_at")
_remoteServerMetadata.UpdatedAt = field.NewTime(tableName, "updated_at")
_remoteServerMetadata.DeletedAt = field.NewField(tableName, "deleted_at")
_remoteServerMetadata.RemoteServerId = field.NewUint(tableName, "remote_server_id")
_remoteServerMetadata.Key = field.NewString(tableName, "key")
_remoteServerMetadata.Value = field.NewString(tableName, "value")
_remoteServerMetadata.RemoteServer = remoteServerMetadataBelongsToRemoteServer{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("RemoteServer", "models.RemoteServer"),
Icon: struct {
field.RelationField
}{
RelationField: field.NewRelation("RemoteServer.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("RemoteServer.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("RemoteServer.Metadata.RemoteServer", "models.RemoteServer"),
},
},
}
_remoteServerMetadata.fillFieldMap()
return _remoteServerMetadata
}
type remoteServerMetadata struct {
remoteServerMetadataDo
ALL field.Asterisk
ID field.Uint
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
RemoteServerId field.Uint
Key field.String
Value field.String
RemoteServer remoteServerMetadataBelongsToRemoteServer
fieldMap map[string]field.Expr
}
func (r remoteServerMetadata) Table(newTableName string) *remoteServerMetadata {
r.remoteServerMetadataDo.UseTable(newTableName)
return r.updateTableName(newTableName)
}
func (r remoteServerMetadata) As(alias string) *remoteServerMetadata {
r.remoteServerMetadataDo.DO = *(r.remoteServerMetadataDo.As(alias).(*gen.DO))
return r.updateTableName(alias)
}
func (r *remoteServerMetadata) updateTableName(table string) *remoteServerMetadata {
r.ALL = field.NewAsterisk(table)
r.ID = field.NewUint(table, "id")
r.CreatedAt = field.NewTime(table, "created_at")
r.UpdatedAt = field.NewTime(table, "updated_at")
r.DeletedAt = field.NewField(table, "deleted_at")
r.RemoteServerId = field.NewUint(table, "remote_server_id")
r.Key = field.NewString(table, "key")
r.Value = field.NewString(table, "value")
r.fillFieldMap()
return r
}
func (r *remoteServerMetadata) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := r.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (r *remoteServerMetadata) fillFieldMap() {
r.fieldMap = make(map[string]field.Expr, 8)
r.fieldMap["id"] = r.ID
r.fieldMap["created_at"] = r.CreatedAt
r.fieldMap["updated_at"] = r.UpdatedAt
r.fieldMap["deleted_at"] = r.DeletedAt
r.fieldMap["remote_server_id"] = r.RemoteServerId
r.fieldMap["key"] = r.Key
r.fieldMap["value"] = r.Value
}
func (r remoteServerMetadata) clone(db *gorm.DB) remoteServerMetadata {
r.remoteServerMetadataDo.ReplaceConnPool(db.Statement.ConnPool)
return r
}
func (r remoteServerMetadata) replaceDB(db *gorm.DB) remoteServerMetadata {
r.remoteServerMetadataDo.ReplaceDB(db)
return r
}
type remoteServerMetadataBelongsToRemoteServer struct {
db *gorm.DB
field.RelationField
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
func (a remoteServerMetadataBelongsToRemoteServer) Where(conds ...field.Expr) *remoteServerMetadataBelongsToRemoteServer {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a remoteServerMetadataBelongsToRemoteServer) WithContext(ctx context.Context) *remoteServerMetadataBelongsToRemoteServer {
a.db = a.db.WithContext(ctx)
return &a
}
func (a remoteServerMetadataBelongsToRemoteServer) Session(session *gorm.Session) *remoteServerMetadataBelongsToRemoteServer {
a.db = a.db.Session(session)
return &a
}
func (a remoteServerMetadataBelongsToRemoteServer) Model(m *models.RemoteServerMetadata) *remoteServerMetadataBelongsToRemoteServerTx {
return &remoteServerMetadataBelongsToRemoteServerTx{a.db.Model(m).Association(a.Name())}
}
type remoteServerMetadataBelongsToRemoteServerTx struct{ tx *gorm.Association }
func (a remoteServerMetadataBelongsToRemoteServerTx) Find() (result *models.RemoteServer, err error) {
return result, a.tx.Find(&result)
}
func (a remoteServerMetadataBelongsToRemoteServerTx) Append(values ...*models.RemoteServer) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a remoteServerMetadataBelongsToRemoteServerTx) Replace(values ...*models.RemoteServer) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a remoteServerMetadataBelongsToRemoteServerTx) Delete(values ...*models.RemoteServer) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a remoteServerMetadataBelongsToRemoteServerTx) Clear() error {
return a.tx.Clear()
}
func (a remoteServerMetadataBelongsToRemoteServerTx) Count() int64 {
return a.tx.Count()
}
type remoteServerMetadataDo struct{ gen.DO }
type IRemoteServerMetadataDo interface {
gen.SubQuery
Debug() IRemoteServerMetadataDo
WithContext(ctx context.Context) IRemoteServerMetadataDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IRemoteServerMetadataDo
WriteDB() IRemoteServerMetadataDo
As(alias string) gen.Dao
Session(config *gorm.Session) IRemoteServerMetadataDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IRemoteServerMetadataDo
Not(conds ...gen.Condition) IRemoteServerMetadataDo
Or(conds ...gen.Condition) IRemoteServerMetadataDo
Select(conds ...field.Expr) IRemoteServerMetadataDo
Where(conds ...gen.Condition) IRemoteServerMetadataDo
Order(conds ...field.Expr) IRemoteServerMetadataDo
Distinct(cols ...field.Expr) IRemoteServerMetadataDo
Omit(cols ...field.Expr) IRemoteServerMetadataDo
Join(table schema.Tabler, on ...field.Expr) IRemoteServerMetadataDo
LeftJoin(table schema.Tabler, on ...field.Expr) IRemoteServerMetadataDo
RightJoin(table schema.Tabler, on ...field.Expr) IRemoteServerMetadataDo
Group(cols ...field.Expr) IRemoteServerMetadataDo
Having(conds ...gen.Condition) IRemoteServerMetadataDo
Limit(limit int) IRemoteServerMetadataDo
Offset(offset int) IRemoteServerMetadataDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IRemoteServerMetadataDo
Unscoped() IRemoteServerMetadataDo
Create(values ...*models.RemoteServerMetadata) error
CreateInBatches(values []*models.RemoteServerMetadata, batchSize int) error
Save(values ...*models.RemoteServerMetadata) error
First() (*models.RemoteServerMetadata, error)
Take() (*models.RemoteServerMetadata, error)
Last() (*models.RemoteServerMetadata, error)
Find() ([]*models.RemoteServerMetadata, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.RemoteServerMetadata, err error)
FindInBatches(result *[]*models.RemoteServerMetadata, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*models.RemoteServerMetadata) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IRemoteServerMetadataDo
Assign(attrs ...field.AssignExpr) IRemoteServerMetadataDo
Joins(fields ...field.RelationField) IRemoteServerMetadataDo
Preload(fields ...field.RelationField) IRemoteServerMetadataDo
FirstOrInit() (*models.RemoteServerMetadata, error)
FirstOrCreate() (*models.RemoteServerMetadata, error)
FindByPage(offset int, limit int) (result []*models.RemoteServerMetadata, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IRemoteServerMetadataDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (r remoteServerMetadataDo) Debug() IRemoteServerMetadataDo {
return r.withDO(r.DO.Debug())
}
func (r remoteServerMetadataDo) WithContext(ctx context.Context) IRemoteServerMetadataDo {
return r.withDO(r.DO.WithContext(ctx))
}
func (r remoteServerMetadataDo) ReadDB() IRemoteServerMetadataDo {
return r.Clauses(dbresolver.Read)
}
func (r remoteServerMetadataDo) WriteDB() IRemoteServerMetadataDo {
return r.Clauses(dbresolver.Write)
}
func (r remoteServerMetadataDo) Session(config *gorm.Session) IRemoteServerMetadataDo {
return r.withDO(r.DO.Session(config))
}
func (r remoteServerMetadataDo) Clauses(conds ...clause.Expression) IRemoteServerMetadataDo {
return r.withDO(r.DO.Clauses(conds...))
}
func (r remoteServerMetadataDo) Returning(value interface{}, columns ...string) IRemoteServerMetadataDo {
return r.withDO(r.DO.Returning(value, columns...))
}
func (r remoteServerMetadataDo) Not(conds ...gen.Condition) IRemoteServerMetadataDo {
return r.withDO(r.DO.Not(conds...))
}
func (r remoteServerMetadataDo) Or(conds ...gen.Condition) IRemoteServerMetadataDo {
return r.withDO(r.DO.Or(conds...))
}
func (r remoteServerMetadataDo) Select(conds ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Select(conds...))
}
func (r remoteServerMetadataDo) Where(conds ...gen.Condition) IRemoteServerMetadataDo {
return r.withDO(r.DO.Where(conds...))
}
func (r remoteServerMetadataDo) Order(conds ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Order(conds...))
}
func (r remoteServerMetadataDo) Distinct(cols ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Distinct(cols...))
}
func (r remoteServerMetadataDo) Omit(cols ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Omit(cols...))
}
func (r remoteServerMetadataDo) Join(table schema.Tabler, on ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Join(table, on...))
}
func (r remoteServerMetadataDo) LeftJoin(table schema.Tabler, on ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.LeftJoin(table, on...))
}
func (r remoteServerMetadataDo) RightJoin(table schema.Tabler, on ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.RightJoin(table, on...))
}
func (r remoteServerMetadataDo) Group(cols ...field.Expr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Group(cols...))
}
func (r remoteServerMetadataDo) Having(conds ...gen.Condition) IRemoteServerMetadataDo {
return r.withDO(r.DO.Having(conds...))
}
func (r remoteServerMetadataDo) Limit(limit int) IRemoteServerMetadataDo {
return r.withDO(r.DO.Limit(limit))
}
func (r remoteServerMetadataDo) Offset(offset int) IRemoteServerMetadataDo {
return r.withDO(r.DO.Offset(offset))
}
func (r remoteServerMetadataDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IRemoteServerMetadataDo {
return r.withDO(r.DO.Scopes(funcs...))
}
func (r remoteServerMetadataDo) Unscoped() IRemoteServerMetadataDo {
return r.withDO(r.DO.Unscoped())
}
func (r remoteServerMetadataDo) Create(values ...*models.RemoteServerMetadata) error {
if len(values) == 0 {
return nil
}
return r.DO.Create(values)
}
func (r remoteServerMetadataDo) CreateInBatches(values []*models.RemoteServerMetadata, batchSize int) error {
return r.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (r remoteServerMetadataDo) Save(values ...*models.RemoteServerMetadata) error {
if len(values) == 0 {
return nil
}
return r.DO.Save(values)
}
func (r remoteServerMetadataDo) First() (*models.RemoteServerMetadata, error) {
if result, err := r.DO.First(); err != nil {
return nil, err
} else {
return result.(*models.RemoteServerMetadata), nil
}
}
func (r remoteServerMetadataDo) Take() (*models.RemoteServerMetadata, error) {
if result, err := r.DO.Take(); err != nil {
return nil, err
} else {
return result.(*models.RemoteServerMetadata), nil
}
}
func (r remoteServerMetadataDo) Last() (*models.RemoteServerMetadata, error) {
if result, err := r.DO.Last(); err != nil {
return nil, err
} else {
return result.(*models.RemoteServerMetadata), nil
}
}
func (r remoteServerMetadataDo) Find() ([]*models.RemoteServerMetadata, error) {
result, err := r.DO.Find()
return result.([]*models.RemoteServerMetadata), err
}
func (r remoteServerMetadataDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.RemoteServerMetadata, err error) {
buf := make([]*models.RemoteServerMetadata, 0, batchSize)
err = r.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (r remoteServerMetadataDo) FindInBatches(result *[]*models.RemoteServerMetadata, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return r.DO.FindInBatches(result, batchSize, fc)
}
func (r remoteServerMetadataDo) Attrs(attrs ...field.AssignExpr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Attrs(attrs...))
}
func (r remoteServerMetadataDo) Assign(attrs ...field.AssignExpr) IRemoteServerMetadataDo {
return r.withDO(r.DO.Assign(attrs...))
}
func (r remoteServerMetadataDo) Joins(fields ...field.RelationField) IRemoteServerMetadataDo {
for _, _f := range fields {
r = *r.withDO(r.DO.Joins(_f))
}
return &r
}
func (r remoteServerMetadataDo) Preload(fields ...field.RelationField) IRemoteServerMetadataDo {
for _, _f := range fields {
r = *r.withDO(r.DO.Preload(_f))
}
return &r
}
func (r remoteServerMetadataDo) FirstOrInit() (*models.RemoteServerMetadata, error) {
if result, err := r.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*models.RemoteServerMetadata), nil
}
}
func (r remoteServerMetadataDo) FirstOrCreate() (*models.RemoteServerMetadata, error) {
if result, err := r.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*models.RemoteServerMetadata), nil
}
}
func (r remoteServerMetadataDo) FindByPage(offset int, limit int) (result []*models.RemoteServerMetadata, count int64, err error) {
result, err = r.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = r.Offset(-1).Limit(-1).Count()
return
}
func (r remoteServerMetadataDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = r.Count()
if err != nil {
return
}
err = r.Offset(offset).Limit(limit).Scan(result)
return
}
func (r remoteServerMetadataDo) Scan(result interface{}) (err error) {
return r.DO.Scan(result)
}
func (r remoteServerMetadataDo) Delete(models ...*models.RemoteServerMetadata) (result gen.ResultInfo, err error) {
return r.DO.Delete(models)
}
func (r *remoteServerMetadataDo) withDO(do gen.Dao) *remoteServerMetadataDo {
r.DO = *do.(*gen.DO)
return r
}

View file

@ -31,10 +31,39 @@ func newRemoteServer(db *gorm.DB, opts ...gen.DOOption) remoteServer {
_remoteServer.UpdatedAt = field.NewTime(tableName, "updated_at")
_remoteServer.DeletedAt = field.NewField(tableName, "deleted_at")
_remoteServer.ServerType = field.NewField(tableName, "server_type")
_remoteServer.SpecificType = field.NewString(tableName, "specific_type")
_remoteServer.Version = field.NewString(tableName, "version")
_remoteServer.Domain = field.NewString(tableName, "domain")
_remoteServer.Name = field.NewString(tableName, "name")
_remoteServer.IconId = field.NewField(tableName, "icon_id")
_remoteServer.IsSelf = field.NewBool(tableName, "is_self")
_remoteServer.Metadata = remoteServerHasManyMetadata{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
}
}{
RelationField: field.NewRelation("Metadata.RemoteServer", "models.RemoteServer"),
Icon: struct {
field.RelationField
}{
RelationField: field.NewRelation("Metadata.RemoteServer.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
}{
RelationField: field.NewRelation("Metadata.RemoteServer.Metadata", "models.RemoteServerMetadata"),
},
},
}
_remoteServer.Icon = remoteServerBelongsToIcon{
db: db.Session(&gorm.Session{}),
@ -49,17 +78,21 @@ func newRemoteServer(db *gorm.DB, opts ...gen.DOOption) remoteServer {
type remoteServer struct {
remoteServerDo
ALL field.Asterisk
ID field.Uint
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
ServerType field.Field
Domain field.String
Name field.String
IconId field.Field
IsSelf field.Bool
Icon remoteServerBelongsToIcon
ALL field.Asterisk
ID field.Uint
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
ServerType field.Field
SpecificType field.String
Version field.String
Domain field.String
Name field.String
IconId field.Field
IsSelf field.Bool
Metadata remoteServerHasManyMetadata
Icon remoteServerBelongsToIcon
fieldMap map[string]field.Expr
}
@ -81,6 +114,8 @@ func (r *remoteServer) updateTableName(table string) *remoteServer {
r.UpdatedAt = field.NewTime(table, "updated_at")
r.DeletedAt = field.NewField(table, "deleted_at")
r.ServerType = field.NewField(table, "server_type")
r.SpecificType = field.NewString(table, "specific_type")
r.Version = field.NewString(table, "version")
r.Domain = field.NewString(table, "domain")
r.Name = field.NewString(table, "name")
r.IconId = field.NewField(table, "icon_id")
@ -101,12 +136,14 @@ func (r *remoteServer) GetFieldByName(fieldName string) (field.OrderExpr, bool)
}
func (r *remoteServer) fillFieldMap() {
r.fieldMap = make(map[string]field.Expr, 10)
r.fieldMap = make(map[string]field.Expr, 13)
r.fieldMap["id"] = r.ID
r.fieldMap["created_at"] = r.CreatedAt
r.fieldMap["updated_at"] = r.UpdatedAt
r.fieldMap["deleted_at"] = r.DeletedAt
r.fieldMap["server_type"] = r.ServerType
r.fieldMap["specific_type"] = r.SpecificType
r.fieldMap["version"] = r.Version
r.fieldMap["domain"] = r.Domain
r.fieldMap["name"] = r.Name
r.fieldMap["icon_id"] = r.IconId
@ -124,6 +161,87 @@ func (r remoteServer) replaceDB(db *gorm.DB) remoteServer {
return r
}
type remoteServerHasManyMetadata struct {
db *gorm.DB
field.RelationField
RemoteServer struct {
field.RelationField
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
}
}
}
func (a remoteServerHasManyMetadata) Where(conds ...field.Expr) *remoteServerHasManyMetadata {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a remoteServerHasManyMetadata) WithContext(ctx context.Context) *remoteServerHasManyMetadata {
a.db = a.db.WithContext(ctx)
return &a
}
func (a remoteServerHasManyMetadata) Session(session *gorm.Session) *remoteServerHasManyMetadata {
a.db = a.db.Session(session)
return &a
}
func (a remoteServerHasManyMetadata) Model(m *models.RemoteServer) *remoteServerHasManyMetadataTx {
return &remoteServerHasManyMetadataTx{a.db.Model(m).Association(a.Name())}
}
type remoteServerHasManyMetadataTx struct{ tx *gorm.Association }
func (a remoteServerHasManyMetadataTx) Find() (result []*models.RemoteServerMetadata, err error) {
return result, a.tx.Find(&result)
}
func (a remoteServerHasManyMetadataTx) Append(values ...*models.RemoteServerMetadata) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a remoteServerHasManyMetadataTx) Replace(values ...*models.RemoteServerMetadata) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a remoteServerHasManyMetadataTx) Delete(values ...*models.RemoteServerMetadata) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a remoteServerHasManyMetadataTx) Clear() error {
return a.tx.Clear()
}
func (a remoteServerHasManyMetadataTx) Count() int64 {
return a.tx.Count()
}
type remoteServerBelongsToIcon struct {
db *gorm.DB

View file

@ -43,6 +43,12 @@ func newUserAuthMethod(db *gorm.DB, opts ...gen.DOOption) userAuthMethod {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -50,6 +56,19 @@ func newUserAuthMethod(db *gorm.DB, opts ...gen.DOOption) userAuthMethod {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -278,6 +297,12 @@ type userAuthMethodBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -44,6 +44,12 @@ func newUserInfoField(db *gorm.DB, opts ...gen.DOOption) userInfoField {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -51,6 +57,19 @@ func newUserInfoField(db *gorm.DB, opts ...gen.DOOption) userInfoField {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -282,6 +301,12 @@ type userInfoFieldBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -48,6 +48,12 @@ func newUserRemoteLinks(db *gorm.DB, opts ...gen.DOOption) userRemoteLinks {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -55,6 +61,19 @@ func newUserRemoteLinks(db *gorm.DB, opts ...gen.DOOption) userRemoteLinks {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -298,6 +317,12 @@ type userRemoteLinksBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -38,6 +38,12 @@ func newUserToBeing(db *gorm.DB, opts ...gen.DOOption) userToBeing {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -45,6 +51,19 @@ func newUserToBeing(db *gorm.DB, opts ...gen.DOOption) userToBeing {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -258,6 +277,12 @@ type userToBeingBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -38,6 +38,12 @@ func newUserToPronoun(db *gorm.DB, opts ...gen.DOOption) userToPronoun {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -45,6 +51,19 @@ func newUserToPronoun(db *gorm.DB, opts ...gen.DOOption) userToPronoun {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -258,6 +277,12 @@ type userToPronounBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -38,6 +38,12 @@ func newUserToRole(db *gorm.DB, opts ...gen.DOOption) userToRole {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -45,6 +51,19 @@ func newUserToRole(db *gorm.DB, opts ...gen.DOOption) userToRole {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -266,6 +285,12 @@ type userToRoleBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -38,6 +38,12 @@ func newUserToTag(db *gorm.DB, opts ...gen.DOOption) userToTag {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -45,6 +51,19 @@ func newUserToTag(db *gorm.DB, opts ...gen.DOOption) userToTag {
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -258,6 +277,12 @@ type userToTagBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -39,6 +39,12 @@ func newUserToUserRelation(db *gorm.DB, opts ...gen.DOOption) userToUserRelation
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("User.Server", "models.RemoteServer"),
Icon: struct {
@ -46,6 +52,19 @@ func newUserToUserRelation(db *gorm.DB, opts ...gen.DOOption) userToUserRelation
}{
RelationField: field.NewRelation("User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -270,6 +289,12 @@ type userToUserRelationBelongsToUser struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -61,6 +61,12 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField
@ -129,6 +135,12 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}{
RelationField: field.NewRelation("RemoteInfo.User.Server", "models.RemoteServer"),
Icon: struct {
@ -136,6 +148,19 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user {
}{
RelationField: field.NewRelation("RemoteInfo.User.Server.Icon", "models.MediaMetadata"),
},
Metadata: struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}{
RelationField: field.NewRelation("RemoteInfo.User.Server.Metadata", "models.RemoteServerMetadata"),
RemoteServer: struct {
field.RelationField
}{
RelationField: field.NewRelation("RemoteInfo.User.Server.Metadata.RemoteServer", "models.RemoteServer"),
},
},
},
Icon: struct {
field.RelationField
@ -492,6 +517,12 @@ type userHasOneRemoteInfo struct {
Icon struct {
field.RelationField
}
Metadata struct {
field.RelationField
RemoteServer struct {
field.RelationField
}
}
}
Icon struct {
field.RelationField

View file

@ -15,6 +15,7 @@ var AllTypes = []any{
&Notification{},
&Reaction{},
&RemoteServer{},
&RemoteServerMetadata{},
&Role{},
&AccessToken{},
&LoginProcessToken{},

View file

@ -10,10 +10,15 @@ import (
// This includes self too
type RemoteServer struct {
gorm.Model
ServerType ServerSoftwareType // What software the server is running. Useful for formatting
Domain string // `gorm:"primaryKey"` // Domain the server exists under. Additional primary key
Name string // What the server wants to be known as (usually same as url)
Icon *MediaMetadata // The icon used by the server. May be empty
IconId sql.NullString // ID of a media file
IsSelf bool // Whether this server is yours truly
// What software type the server is running. Useful for formatting.
// Groups various types together (ex. firefish, iceshrimp, sharkey, misskey => misskey)
ServerType ServerSoftwareType
SpecificType string // Specific type
Version string
Domain string // `gorm:"primaryKey"` // Domain the server exists under. Additional primary key
Name string // What the server wants to be known as (usually same as url)
Icon *MediaMetadata // The icon used by the server. May be empty
IconId sql.NullString // ID of a media file
IsSelf bool // Whether this server is yours truly
Metadata []RemoteServerMetadata
}

View file

@ -0,0 +1,13 @@
package models
import (
"gorm.io/gorm"
)
type RemoteServerMetadata struct {
gorm.Model
RemoteServer RemoteServer
RemoteServerId uint
Key string
Value string
}

View file

@ -25,60 +25,60 @@ type User struct {
// identifier for users and other servers, especially when changing the username
// (username != display name) might be a future feature
// Same also applies for other types that use a UUID as primary key
ID string `gorm:"primarykey;default:gen_random_uuid()" json:"id"`
ID string `gorm:"primarykey;default:gen_random_uuid()"`
// Username of the user (eg "max" if the full username is @max@example.com)
// Assume unchangable (once set by a user) to be kind to other implementations
// Would be an easy avenue to fuck with them though
Username string `gorm:"unique" json:"username"`
CreatedAt time.Time ` json:"created_at"` // When this entry was created. Automatically set by gorm
Username string `gorm:"unique"`
CreatedAt time.Time // When this entry was created. Automatically set by gorm
// When this account was last updated. Will also be used for refreshing remote accounts. Automatically set by gorm
UpdatedAt time.Time ` json:"updated_at"`
UpdatedAt time.Time
// When this entry was deleted (for soft deletions)
// Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to
// If not null, this entry is marked as deleted
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
Server RemoteServer ` json:"-"`
ServerId uint ` json:"server_id"` // Id of the server this user is from, needed for including RemoteServer
DisplayName string ` json:"display_name"` // The display name of the user. Can be different from the handle
Description string ` json:"description"` // The description of a user account
IsBot bool ` json:"is_bot"` // Whether to mark this account as a script controlled one
Icon *MediaMetadata ` json:"-"`
IconId sql.NullString ` json:"icon_id"` // ID of a media file used as icon
Background *MediaMetadata ` json:"-"`
BackgroundId sql.NullString ` json:"background_id"` // ID of a media file used as background image
Banner *MediaMetadata ` json:"-"`
BannerId sql.NullString ` json:"banner_id"` // ID of a media file used as banner
Indexable bool ` json:"indexable"` // Whether this account can be found by crawlers
PublicKeyRsa []byte ` json:"public_key_rsa"` // The public RSA key of the account
PublicKeyEd []byte ` json:"public_key_ed"` // The public Ed25519 key of the account
DeletedAt gorm.DeletedAt `gorm:"index"`
Server RemoteServer
ServerId uint // Id of the server this user is from, needed for including RemoteServer
DisplayName string // The display name of the user. Can be different from the handle
Description string // The description of a user account
IsBot bool // Whether to mark this account as a script controlled one
Icon *MediaMetadata
IconId sql.NullString // ID of a media file used as icon
Background *MediaMetadata
BackgroundId sql.NullString // ID of a media file used as background image
Banner *MediaMetadata
BannerId sql.NullString // ID of a media file used as banner
Indexable bool // Whether this account can be found by crawlers
PublicKeyRsa []byte // The public RSA key of the account
PublicKeyEd []byte // The public Ed25519 key of the account
// Whether this account restricts following
// If true, the owner must approve of a follow request first
RestrictedFollow bool ` json:"restricted_follow"`
RestrictedFollow bool
Location sql.NullString `json:"location"`
Birthday sql.NullTime `json:"birthday"`
Location sql.NullString
Birthday sql.NullTime
// Whether the account got verified and is allowed to be active
// For local accounts being active means being allowed to login and perform interactions
// For remote users, if an account is not verified, any interactions it sends are discarded
Verified bool `json:"verified"`
Verified bool
// 64 byte unique id for passkeys, because UUIDs are 128 bytes and passkey spec says 64 bytes max
// In theory, could also slash Id in half, but that would be a lot more calculations than the
// saved space is worth
PasskeyId []byte `json:"-"`
FinishedRegistration bool `json:"-"` // Whether this account has completed registration yet
PrivateKeyRsa []byte `json:"-"`
PrivateKeyEd []byte `json:"-"`
PasskeyId []byte
FinishedRegistration bool // Whether this account has completed registration yet
PrivateKeyRsa []byte
PrivateKeyEd []byte
// ---- "Remote" linked values
InfoFields []UserInfoField `json:"-"`
BeingTypes []UserToBeing `json:"-"`
Tags []UserToTag `json:"-"`
Relations []UserToUserRelation `json:"-"`
Pronouns []UserToPronoun `json:"-"`
Roles []UserToRole `json:"-"`
RemoteInfo *UserRemoteLinks `json:"-"`
AuthMethods []UserAuthMethod `json:"-"`
InfoFields []UserInfoField
BeingTypes []UserToBeing
Tags []UserToTag
Relations []UserToUserRelation
Pronouns []UserToPronoun
Roles []UserToRole
RemoteInfo *UserRemoteLinks
AuthMethods []UserAuthMethod
}
type IUser interface {

View file

@ -70,24 +70,26 @@ func insertDefaultDuck() (*models.MediaMetadata, error) {
}
func insertServer(duck *models.MediaMetadata) (*models.RemoteServer, error) {
dbServer, err := dbgen.RemoteServer.Where(dbgen.RemoteServer.ID.Eq(1)).First()
if err == nil {
return dbServer, nil
} else if err != gorm.ErrRecordNotFound {
return nil, err
}
// dbServer, err := dbgen.RemoteServer.Where(dbgen.RemoteServer.ID.Eq(1)).First()
// if err == nil {
// return dbServer, nil
// } else if err != gorm.ErrRecordNotFound {
// return nil, err
// }
server := models.RemoteServer{
Model: gorm.Model{
ID: 1,
},
ServerType: models.ServerSoftwareLinstrom,
Domain: config.GlobalConfig.General.GetFullDomain(),
Name: config.GlobalConfig.Self.ServerDisplayName,
Icon: duck,
IconId: sql.NullString{String: duck.ID, Valid: true},
IsSelf: true,
ServerType: models.ServerSoftwareLinstrom,
SpecificType: "linstrom",
Version: shared.Version,
Domain: config.GlobalConfig.General.GetFullDomain(),
Name: config.GlobalConfig.Self.ServerDisplayName,
Icon: duck,
IconId: sql.NullString{String: duck.ID, Valid: true},
IsSelf: true,
}
err = dbgen.RemoteServer.Save(&server)
err := dbgen.RemoteServer.Save(&server)
if err != nil {
return nil, err
}

16
web/debug/remoteServer.go Normal file
View file

@ -0,0 +1,16 @@
package webdebug
import (
"net/http"
"github.com/rs/zerolog/hlog"
"git.mstar.dev/mstar/linstrom/activitypub"
)
func importServerInfo(w http.ResponseWriter, r *http.Request) {
target := r.FormValue("target")
if _, err := activitypub.ImportRemoteServer(target); err != nil {
hlog.FromRequest(r).Error().Err(err).Msg("Failed to import")
}
}

View file

@ -27,8 +27,9 @@ func New(addr string) *Server {
handler.HandleFunc("GET /delete", deleteUser)
handler.HandleFunc("POST /post-as", postAs)
handler.HandleFunc("GET /notes-for", notesFrom)
handler.HandleFunc("GET /import", issueUserImport)
handler.HandleFunc("GET /import-user", issueUserImport)
handler.HandleFunc("GET /keys-for", returnKeypair)
handler.HandleFunc("GET /import-server", importServerInfo)
web := http.Server{
Addr: addr,
Handler: webutils.ChainMiddlewares(

View file

@ -38,6 +38,7 @@ func users(w http.ResponseWriter, r *http.Request) {
Type string `json:"type"`
PreferredUsername string `json:"preferredUsername"`
Inbox string `json:"inbox"`
Outboux string `json:"outbox"`
PublicKey OutboundKey `json:"publicKey"`
Published time.Time `json:"published"`
DisplayName string `json:"name"`
@ -82,6 +83,7 @@ func users(w http.ResponseWriter, r *http.Request) {
Type: "Person",
PreferredUsername: user.Username,
Inbox: apUrl + "/inbox",
Outboux: apUrl + "/outbox",
PublicKey: OutboundKey{
Id: apUrl + "#main-key",
Owner: apUrl,

View file

@ -15,6 +15,7 @@ import (
"git.mstar.dev/mstar/linstrom/shared"
"git.mstar.dev/mstar/linstrom/storage-new"
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
webshared "git.mstar.dev/mstar/linstrom/web/shared"
)
var webfingerResourceRegex = regexp.MustCompile(`acct:(?P<username>[\w-]+)@(?<domain>[\w\.-]+)`)
@ -103,7 +104,23 @@ func WellKnownWebfinger(w http.ResponseWriter, r *http.Request) {
webutils.SendJson(w, &data)
}
func Nodeinfo(w http.ResponseWriter, r *http.Request) {
func NodeInfoOverview(w http.ResponseWriter, r *http.Request) {
data := webshared.NodeInfoOverview{
Links: []webshared.NodeInfoLink{
{
Rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
Href: config.GlobalConfig.General.GetFullPublicUrl() + "/nodeinfo/2.1",
},
{
Rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
Href: config.GlobalConfig.General.GetFullPublicUrl() + "/nodeinfo/2.0",
},
},
}
webutils.SendJson(w, data)
}
func NodeInfo21(w http.ResponseWriter, r *http.Request) {
u := dbgen.User
log := hlog.FromRequest(r)
userCount, err := u.Where(u.DeletedAt.IsNull(), u.Verified.Is(true)).Count()
@ -128,42 +145,81 @@ func Nodeinfo(w http.ResponseWriter, r *http.Request) {
return
}
data := map[string]any{
"version": "2.1",
"software": map[string]string{
"name": "linstrom",
"version": shared.Version,
"homepage": "https://git.mstar.dev/mstar/linstrom",
"repository": "https://git.mstar.dev/mstar/linstrom",
data := webshared.NodeInfo2{
Version: "2.1",
Software: webshared.NodeInfo2Software{
Name: "linstrom",
Version: shared.Version,
Homepage: other.IntoPointer("https://git.mstar.dev/mstar/linstrom"),
Repository: other.IntoPointer("https://git.mstar.dev/mstar/linstrom"),
},
"protocols": []string{"activitypub"},
"services": map[string]any{
"inbound": []string{},
"outbound": []string{},
Protocols: []string{"activitypub"},
Services: map[string][]string{
"inbound": {},
"outbound": {},
},
"openRegistrations": config.GlobalConfig.Admin.AllowRegistration,
"usage": map[string]any{
"users": map[string]any{
"total": userCount,
"activeHalfyear": nil,
"activeMonth": nil,
OpenRegistrations: config.GlobalConfig.Admin.AllowRegistration,
Usage: webshared.NodeInfo2Usage{
Users: webshared.NodeInfo2UsageUsers{
Total: uint(userCount),
ActiveHalfYear: nil,
ActiveMonth: nil,
},
"localPosts": noteCount,
"localComments": 0,
},
"metadata": map[string]any{},
LocalPosts: uint(noteCount),
LocalComments: 0},
Metadata: map[string]any{},
}
webutils.SendJson(w, data)
}
func WellKnownNodeinfo(w http.ResponseWriter, r *http.Request) {
data := map[string]any{
"links": []map[string]any{
{
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
"href": config.GlobalConfig.General.GetFullPublicUrl() + "/nodeinfo/2.1",
},
},
func NodeInfo20(w http.ResponseWriter, r *http.Request) {
u := dbgen.User
log := hlog.FromRequest(r)
userCount, err := u.Where(u.DeletedAt.IsNull(), u.Verified.Is(true)).Count()
if err != nil {
webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil)
if storage.HandleReconnectError(err) {
log.Warn().Msg("Connection to db lost. Reconnect attempt started")
} else {
log.Error().Err(err).Msg("Failed to get total user count from db")
}
return
}
n := dbgen.Note
noteCount, err := n.Where(n.DeletedAt.IsNull(), n.OriginId.Eq(1)).Count()
if err != nil {
webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil)
if storage.HandleReconnectError(err) {
log.Warn().Msg("Connection to db lost. Reconnect attempt started")
} else {
log.Error().Err(err).Msg("Failed to get total user count from db")
}
return
}
data := webshared.NodeInfo2{
Version: "2.1",
Software: webshared.NodeInfo2Software{
Name: "linstrom",
Version: shared.Version,
Homepage: nil,
Repository: nil,
},
Protocols: []string{"activitypub"},
Services: map[string][]string{
"inbound": {},
"outbound": {},
},
OpenRegistrations: config.GlobalConfig.Admin.AllowRegistration,
Usage: webshared.NodeInfo2Usage{
Users: webshared.NodeInfo2UsageUsers{
Total: uint(userCount),
ActiveHalfYear: nil,
ActiveMonth: nil,
},
LocalPosts: uint(noteCount),
LocalComments: 0},
Metadata: map[string]any{},
}
webutils.SendJson(w, data)
}

View file

@ -48,8 +48,9 @@ func New(addr string, duckImg *string) *Server {
})
handler.Handle("/api/", http.StripPrefix("/api", api.BuildApiRouter()))
handler.HandleFunc("GET /.well-known/webfinger", api.WellKnownWebfinger)
handler.HandleFunc("GET /.well-known/nodeinfo", api.WellKnownNodeinfo)
handler.HandleFunc("GET /nodeinfo/2.1", api.Nodeinfo)
handler.HandleFunc("GET /.well-known/nodeinfo", api.NodeInfoOverview)
handler.HandleFunc("GET /nodeinfo/2.1", api.NodeInfo21)
handler.HandleFunc("GET /nodeinfo/2.0", api.NodeInfo20)
handler.HandleFunc("GET /errors/{name}", errorTypeHandler)
handler.HandleFunc("GET /default-image", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "image/web")

60
web/shared/Nodeinfo.go Normal file
View file

@ -0,0 +1,60 @@
package webshared
import (
"git.mstar.dev/mstar/goutils/sliceutils"
"git.mstar.dev/mstar/linstrom/storage-new/models"
)
type NodeInfoLink struct {
Rel string
Href string
}
type NodeInfoOverview struct {
Links []NodeInfoLink
}
type NodeInfo2Software struct {
Name string `json:"name"`
Version string `json:"version"`
Homepage *string `json:"homepage,omitempty"`
Repository *string `json:"repository,omitempty"`
}
type NodeInfo2UsageUsers struct {
Total uint `json:"total"`
ActiveHalfYear *uint `json:"active_half_year"`
ActiveMonth *uint `json:"active_month"`
}
type NodeInfo2Usage struct {
Users NodeInfo2UsageUsers `json:"users"`
LocalPosts uint `json:"local_posts"`
LocalComments uint `json:"local_comments"`
}
type NodeInfo2 struct {
Version string `json:"version"`
Software NodeInfo2Software `json:"software"`
Protocols []string `json:"protocols"`
Services map[string][]string `json:"services"`
OpenRegistrations bool `json:"open_registrations"`
Usage NodeInfo2Usage `json:"usage"`
Metadata map[string]any `json:"metadata"`
}
func MapNodeServerTypeToModelType(nodeType string) models.ServerSoftwareType {
if sliceutils.Contains([]string{"mastodon"}, nodeType) {
return models.ServerSoftwareMastodon
} else if sliceutils.Contains([]string{"sharkey", "misskey", "iceshrimp", "firefish"}, nodeType) {
return models.ServerSoftwareMisskey
} else if sliceutils.Contains([]string{"linstrom"}, nodeType) {
return models.ServerSoftwareLinstrom
} else if sliceutils.Contains([]string{"akkoma"}, nodeType) {
return models.ServerSoftwarePlemora
} else if sliceutils.Contains([]string{"wafrn"}, nodeType) {
return models.ServerSoftwareWafrn
}
return models.ServerSoftwareUnknown
}

View file

@ -2,8 +2,6 @@ package webshared
import (
"bytes"
"crypto"
"crypto/ed25519"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
@ -11,12 +9,11 @@ import (
"slices"
"time"
"github.com/go-fed/httpsig"
"github.com/rs/zerolog/log"
"github.com/yaronf/httpsign"
"git.mstar.dev/mstar/linstrom/config"
"git.mstar.dev/mstar/linstrom/shared"
"git.mstar.dev/mstar/linstrom/storage-new/models"
)
/*
@ -78,55 +75,32 @@ func RequestSignedRFC9421(
func RequestSignedCavage(
method, target string,
body []byte,
keyId string,
privateKeyBytes []byte,
useEd bool,
actor *models.User,
) (*http.Response, error) {
req, err := http.NewRequest(method, target, bytes.NewBuffer(slices.Clone(body)))
req, err := NewRequest(method, target, nil)
if err != nil {
return nil, err
}
applyDefaultHeaders(req)
var prefs []httpsig.Algorithm
var key crypto.PrivateKey
if useEd {
log.Debug().Msg("Using ed25519 cavage")
prefs = append(prefs, httpsig.ED25519)
key = ed25519.PrivateKey(privateKeyBytes)
req.Header.Add("Accept", "application/activity+json")
var keyBytes []byte
if config.GlobalConfig.Experimental.UseEd25519Keys {
keyBytes = actor.PrivateKeyEd
} else {
log.Debug().Msg("Using RSA cavage")
// prefs = append(prefs, httpsig.RSA_SHA512, httpsig.RSA_SHA256)
prefs = append(prefs, httpsig.RSA_SHA256)
tempKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes)
if err != nil {
return nil, err
}
key = tempKey
keyBytes = actor.PrivateKeyRsa
}
digestAlgorithm := httpsig.DigestSha256
headersToSign := []string{httpsig.RequestTarget, "date", "host", "user-agent"}
if len(body) > 0 {
headersToSign = append(headersToSign, "digest")
log.Debug().Msg("Non-empty body, adding digest")
} else {
// Just to ensure the signer doesn't fuck up
body = nil
}
signer, chosenAlgorithm, err := httpsig.NewSigner(
prefs,
digestAlgorithm,
headersToSign,
httpsig.Signature,
int64(time.Hour),
// Sign and send
err = SignRequest(
req,
actor.ID+"#main-key",
keyBytes,
body,
)
// err = webshared.SignRequestWithHttpsig(req, linstromActor.ID+"#main-key", keyBytes, nil)
if err != nil {
return nil, err
}
log.Debug().Any("algorithm", chosenAlgorithm).Msg("Signer chose algorithm")
if err = signer.SignRequest(key, keyId, req, body); err != nil {
return nil, err
}
log.Debug().Any("headers", req.Header).Msg("Request post signing")
return RequestClient.Do(req)
}

View file

@ -27,7 +27,7 @@ func CreateSignatureRSA(
return "", nil, err
}
encoded := base64.StdEncoding.EncodeToString(signed)
log.Debug().
log.Trace().
Str("raw-message", message).
Bytes("signed", signed).
Str("encoded", encoded).