From 08f6de0bd7b4ec70942b30419be74333a9506b23 Mon Sep 17 00:00:00 2001 From: mstar Date: Tue, 15 Apr 2025 14:51:07 +0200 Subject: [PATCH] Rename cavage singing func, add import for server --- activitypub/import.go | 391 ++++++++++++-- storage-new/dbgen/access_tokens.gen.go | 25 + storage-new/dbgen/emotes.gen.go | 19 + storage-new/dbgen/feeds.gen.go | 25 + storage-new/dbgen/gen.go | 366 +++++++------ storage-new/dbgen/login_process_tokens.gen.go | 25 + storage-new/dbgen/note_tags.gen.go | 31 ++ storage-new/dbgen/note_to_attachments.gen.go | 31 ++ storage-new/dbgen/note_to_boosts.gen.go | 25 + storage-new/dbgen/note_to_emotes.gen.go | 31 ++ storage-new/dbgen/note_to_feeds.gen.go | 31 ++ storage-new/dbgen/note_to_pings.gen.go | 31 ++ storage-new/dbgen/notes.gen.go | 37 ++ storage-new/dbgen/notifications.gen.go | 25 + storage-new/dbgen/reactions.gen.go | 31 ++ .../dbgen/remote_server_metadata.gen.go | 509 ++++++++++++++++++ storage-new/dbgen/remote_servers.gen.go | 142 ++++- storage-new/dbgen/user_auth_methods.gen.go | 25 + storage-new/dbgen/user_info_fields.gen.go | 25 + storage-new/dbgen/user_remote_links.gen.go | 25 + storage-new/dbgen/user_to_beings.gen.go | 25 + storage-new/dbgen/user_to_pronouns.gen.go | 25 + storage-new/dbgen/user_to_roles.gen.go | 25 + storage-new/dbgen/user_to_tags.gen.go | 25 + .../dbgen/user_to_user_relations.gen.go | 25 + storage-new/dbgen/users.gen.go | 31 ++ storage-new/models/0allTypes.go | 1 + storage-new/models/RemoteServer.go | 17 +- storage-new/models/RemoteServerMetadata.go | 13 + storage-new/models/User.go | 70 +-- storage-new/self.go | 28 +- web/debug/remoteServer.go | 16 + web/debug/server.go | 3 +- web/public/api/activitypub/user.go | 2 + web/public/api/webfinger.go | 116 ++-- web/public/server.go | 5 +- web/shared/Nodeinfo.go | 60 +++ web/shared/clientRfc9421.go | 60 +-- web/shared/signing.go | 2 +- 39 files changed, 2035 insertions(+), 364 deletions(-) create mode 100644 storage-new/dbgen/remote_server_metadata.gen.go create mode 100644 storage-new/models/RemoteServerMetadata.go create mode 100644 web/debug/remoteServer.go create mode 100644 web/shared/Nodeinfo.go diff --git a/activitypub/import.go b/activitypub/import.go index 37d9cdb..004c6c8 100644 --- a/activitypub/import.go +++ b/activitypub/import.go @@ -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 } diff --git a/storage-new/dbgen/access_tokens.gen.go b/storage-new/dbgen/access_tokens.gen.go index da0ae56..45e170b 100644 --- a/storage-new/dbgen/access_tokens.gen.go +++ b/storage-new/dbgen/access_tokens.gen.go @@ -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 diff --git a/storage-new/dbgen/emotes.gen.go b/storage-new/dbgen/emotes.gen.go index d7b6d10..7db20aa 100644 --- a/storage-new/dbgen/emotes.gen.go +++ b/storage-new/dbgen/emotes.gen.go @@ -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 { diff --git a/storage-new/dbgen/feeds.gen.go b/storage-new/dbgen/feeds.gen.go index 16d1c2d..e6a4399 100644 --- a/storage-new/dbgen/feeds.gen.go +++ b/storage-new/dbgen/feeds.gen.go @@ -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 diff --git a/storage-new/dbgen/gen.go b/storage-new/dbgen/gen.go index a01eb2a..bc9ba35 100644 --- a/storage-new/dbgen/gen.go +++ b/storage-new/dbgen/gen.go @@ -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), } } diff --git a/storage-new/dbgen/login_process_tokens.gen.go b/storage-new/dbgen/login_process_tokens.gen.go index 156be88..6fdbe00 100644 --- a/storage-new/dbgen/login_process_tokens.gen.go +++ b/storage-new/dbgen/login_process_tokens.gen.go @@ -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 diff --git a/storage-new/dbgen/note_tags.gen.go b/storage-new/dbgen/note_tags.gen.go index d792e8f..31c1b30 100644 --- a/storage-new/dbgen/note_tags.gen.go +++ b/storage-new/dbgen/note_tags.gen.go @@ -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 diff --git a/storage-new/dbgen/note_to_attachments.gen.go b/storage-new/dbgen/note_to_attachments.gen.go index cfcd57a..9443b86 100644 --- a/storage-new/dbgen/note_to_attachments.gen.go +++ b/storage-new/dbgen/note_to_attachments.gen.go @@ -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 diff --git a/storage-new/dbgen/note_to_boosts.gen.go b/storage-new/dbgen/note_to_boosts.gen.go index a20f7ab..2f7e041 100644 --- a/storage-new/dbgen/note_to_boosts.gen.go +++ b/storage-new/dbgen/note_to_boosts.gen.go @@ -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 diff --git a/storage-new/dbgen/note_to_emotes.gen.go b/storage-new/dbgen/note_to_emotes.gen.go index 3a03a3d..5c4209f 100644 --- a/storage-new/dbgen/note_to_emotes.gen.go +++ b/storage-new/dbgen/note_to_emotes.gen.go @@ -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 diff --git a/storage-new/dbgen/note_to_feeds.gen.go b/storage-new/dbgen/note_to_feeds.gen.go index a3882bd..02a27f0 100644 --- a/storage-new/dbgen/note_to_feeds.gen.go +++ b/storage-new/dbgen/note_to_feeds.gen.go @@ -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 diff --git a/storage-new/dbgen/note_to_pings.gen.go b/storage-new/dbgen/note_to_pings.gen.go index f90a23e..1c711a9 100644 --- a/storage-new/dbgen/note_to_pings.gen.go +++ b/storage-new/dbgen/note_to_pings.gen.go @@ -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 diff --git a/storage-new/dbgen/notes.gen.go b/storage-new/dbgen/notes.gen.go index 798baa7..a8f91c2 100644 --- a/storage-new/dbgen/notes.gen.go +++ b/storage-new/dbgen/notes.gen.go @@ -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 diff --git a/storage-new/dbgen/notifications.gen.go b/storage-new/dbgen/notifications.gen.go index 62e286b..61e8a1a 100644 --- a/storage-new/dbgen/notifications.gen.go +++ b/storage-new/dbgen/notifications.gen.go @@ -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 diff --git a/storage-new/dbgen/reactions.gen.go b/storage-new/dbgen/reactions.gen.go index faef15f..ab6860a 100644 --- a/storage-new/dbgen/reactions.gen.go +++ b/storage-new/dbgen/reactions.gen.go @@ -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 diff --git a/storage-new/dbgen/remote_server_metadata.gen.go b/storage-new/dbgen/remote_server_metadata.gen.go new file mode 100644 index 0000000..23c208e --- /dev/null +++ b/storage-new/dbgen/remote_server_metadata.gen.go @@ -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 +} diff --git a/storage-new/dbgen/remote_servers.gen.go b/storage-new/dbgen/remote_servers.gen.go index 0935601..75d09de 100644 --- a/storage-new/dbgen/remote_servers.gen.go +++ b/storage-new/dbgen/remote_servers.gen.go @@ -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 diff --git a/storage-new/dbgen/user_auth_methods.gen.go b/storage-new/dbgen/user_auth_methods.gen.go index 24898ff..b6acd77 100644 --- a/storage-new/dbgen/user_auth_methods.gen.go +++ b/storage-new/dbgen/user_auth_methods.gen.go @@ -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 diff --git a/storage-new/dbgen/user_info_fields.gen.go b/storage-new/dbgen/user_info_fields.gen.go index fae3c4d..198195a 100644 --- a/storage-new/dbgen/user_info_fields.gen.go +++ b/storage-new/dbgen/user_info_fields.gen.go @@ -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 diff --git a/storage-new/dbgen/user_remote_links.gen.go b/storage-new/dbgen/user_remote_links.gen.go index beb9955..db2c8a6 100644 --- a/storage-new/dbgen/user_remote_links.gen.go +++ b/storage-new/dbgen/user_remote_links.gen.go @@ -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 diff --git a/storage-new/dbgen/user_to_beings.gen.go b/storage-new/dbgen/user_to_beings.gen.go index ee20a00..7e0076f 100644 --- a/storage-new/dbgen/user_to_beings.gen.go +++ b/storage-new/dbgen/user_to_beings.gen.go @@ -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 diff --git a/storage-new/dbgen/user_to_pronouns.gen.go b/storage-new/dbgen/user_to_pronouns.gen.go index fa78aab..9bedbac 100644 --- a/storage-new/dbgen/user_to_pronouns.gen.go +++ b/storage-new/dbgen/user_to_pronouns.gen.go @@ -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 diff --git a/storage-new/dbgen/user_to_roles.gen.go b/storage-new/dbgen/user_to_roles.gen.go index 3524928..90ab600 100644 --- a/storage-new/dbgen/user_to_roles.gen.go +++ b/storage-new/dbgen/user_to_roles.gen.go @@ -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 diff --git a/storage-new/dbgen/user_to_tags.gen.go b/storage-new/dbgen/user_to_tags.gen.go index 42517eb..8a857be 100644 --- a/storage-new/dbgen/user_to_tags.gen.go +++ b/storage-new/dbgen/user_to_tags.gen.go @@ -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 diff --git a/storage-new/dbgen/user_to_user_relations.gen.go b/storage-new/dbgen/user_to_user_relations.gen.go index 117c8cc..451040d 100644 --- a/storage-new/dbgen/user_to_user_relations.gen.go +++ b/storage-new/dbgen/user_to_user_relations.gen.go @@ -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 diff --git a/storage-new/dbgen/users.gen.go b/storage-new/dbgen/users.gen.go index cb7b476..801dc2c 100644 --- a/storage-new/dbgen/users.gen.go +++ b/storage-new/dbgen/users.gen.go @@ -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 diff --git a/storage-new/models/0allTypes.go b/storage-new/models/0allTypes.go index 5c703a5..9d457c2 100644 --- a/storage-new/models/0allTypes.go +++ b/storage-new/models/0allTypes.go @@ -15,6 +15,7 @@ var AllTypes = []any{ &Notification{}, &Reaction{}, &RemoteServer{}, + &RemoteServerMetadata{}, &Role{}, &AccessToken{}, &LoginProcessToken{}, diff --git a/storage-new/models/RemoteServer.go b/storage-new/models/RemoteServer.go index 457d2c7..6f8df6a 100644 --- a/storage-new/models/RemoteServer.go +++ b/storage-new/models/RemoteServer.go @@ -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 } diff --git a/storage-new/models/RemoteServerMetadata.go b/storage-new/models/RemoteServerMetadata.go new file mode 100644 index 0000000..46c654a --- /dev/null +++ b/storage-new/models/RemoteServerMetadata.go @@ -0,0 +1,13 @@ +package models + +import ( + "gorm.io/gorm" +) + +type RemoteServerMetadata struct { + gorm.Model + RemoteServer RemoteServer + RemoteServerId uint + Key string + Value string +} diff --git a/storage-new/models/User.go b/storage-new/models/User.go index 53aaf3f..501174f 100644 --- a/storage-new/models/User.go +++ b/storage-new/models/User.go @@ -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 { diff --git a/storage-new/self.go b/storage-new/self.go index 27f380b..7fcb8e1 100644 --- a/storage-new/self.go +++ b/storage-new/self.go @@ -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 } diff --git a/web/debug/remoteServer.go b/web/debug/remoteServer.go new file mode 100644 index 0000000..bc8f01c --- /dev/null +++ b/web/debug/remoteServer.go @@ -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") + } +} diff --git a/web/debug/server.go b/web/debug/server.go index eb42afc..542e198 100644 --- a/web/debug/server.go +++ b/web/debug/server.go @@ -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( diff --git a/web/public/api/activitypub/user.go b/web/public/api/activitypub/user.go index 0e9212f..556b2cf 100644 --- a/web/public/api/activitypub/user.go +++ b/web/public/api/activitypub/user.go @@ -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, diff --git a/web/public/api/webfinger.go b/web/public/api/webfinger.go index 3e8e1ac..7b49d70 100644 --- a/web/public/api/webfinger.go +++ b/web/public/api/webfinger.go @@ -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[\w-]+)@(?[\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) } diff --git a/web/public/server.go b/web/public/server.go index 61e55cf..6dacc0b 100644 --- a/web/public/server.go +++ b/web/public/server.go @@ -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") diff --git a/web/shared/Nodeinfo.go b/web/shared/Nodeinfo.go new file mode 100644 index 0000000..8c54a81 --- /dev/null +++ b/web/shared/Nodeinfo.go @@ -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 +} diff --git a/web/shared/clientRfc9421.go b/web/shared/clientRfc9421.go index 65ee8b8..6fe9d5d 100644 --- a/web/shared/clientRfc9421.go +++ b/web/shared/clientRfc9421.go @@ -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) } diff --git a/web/shared/signing.go b/web/shared/signing.go index 3eb03c1..b35a65b 100644 --- a/web/shared/signing.go +++ b/web/shared/signing.go @@ -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).