···11+// Copyright 2024 The Forgejo Authors. All rights reserved.
22+// SPDX-License-Identifier: MIT
33+44+package user
55+66+import (
77+ "code.gitea.io/gitea/modules/validation"
88+)
99+1010+type FederatedUser struct {
1111+ ID int64 `xorm:"pk autoincr"`
1212+ UserID int64 `xorm:"NOT NULL"`
1313+ ExternalID string `xorm:"UNIQUE(federation_user_mapping) NOT NULL"`
1414+ FederationHostID int64 `xorm:"UNIQUE(federation_user_mapping) NOT NULL"`
1515+}
1616+1717+func NewFederatedUser(userID int64, externalID string, federationHostID int64) (FederatedUser, error) {
1818+ result := FederatedUser{
1919+ UserID: userID,
2020+ ExternalID: externalID,
2121+ FederationHostID: federationHostID,
2222+ }
2323+ if valid, err := validation.IsValid(result); !valid {
2424+ return FederatedUser{}, err
2525+ }
2626+ return result, nil
2727+}
2828+2929+func (user FederatedUser) Validate() []string {
3030+ var result []string
3131+ result = append(result, validation.ValidateNotEmpty(user.UserID, "UserID")...)
3232+ result = append(result, validation.ValidateNotEmpty(user.ExternalID, "ExternalID")...)
3333+ result = append(result, validation.ValidateNotEmpty(user.FederationHostID, "FederationHostID")...)
3434+ return result
3535+}
+29
models/user/federated_user_test.go
···11+// Copyright 2024 The Forgejo Authors. All rights reserved.
22+// SPDX-License-Identifier: MIT
33+44+package user
55+66+import (
77+ "testing"
88+99+ "code.gitea.io/gitea/modules/validation"
1010+)
1111+1212+func Test_FederatedUserValidation(t *testing.T) {
1313+ sut := FederatedUser{
1414+ UserID: 12,
1515+ ExternalID: "12",
1616+ FederationHostID: 1,
1717+ }
1818+ if res, err := validation.IsValid(sut); !res {
1919+ t.Errorf("sut should be valid but was %q", err)
2020+ }
2121+2222+ sut = FederatedUser{
2323+ ExternalID: "12",
2424+ FederationHostID: 1,
2525+ }
2626+ if res, _ := validation.IsValid(sut); res {
2727+ t.Errorf("sut should be invalid")
2828+ }
2929+}
+20
models/user/user.go
···11// Copyright 2014 The Gogs Authors. All rights reserved.
22// Copyright 2019 The Gitea Authors. All rights reserved.
33+// Copyright 2024 The Forgejo Authors. All rights reserved.
34// SPDX-License-Identifier: MIT
4556package user
···130131 Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
131132 AvatarEmail string `xorm:"NOT NULL"`
132133 UseCustomAvatar bool
134134+135135+ // For federation
136136+ NormalizedFederatedURI string
133137134138 // Counters
135139 NumFollowers int
···301305// HTMLURL returns the user or organization's full link.
302306func (u *User) HTMLURL() string {
303307 return setting.AppURL + url.PathEscape(u.Name)
308308+}
309309+310310+// APAPIURL returns the IRI to the api endpoint of the user
311311+func (u *User) APAPIURL() string {
312312+ return fmt.Sprintf("%vapi/v1/activitypub/user-id/%v", setting.AppURL, url.PathEscape(fmt.Sprintf("%v", u.ID)))
304313}
305314306315// OrganisationLink returns the organization sub page link.
···832841 }
833842834843 return nil
844844+}
845845+846846+func (u User) Validate() []string {
847847+ var result []string
848848+ if err := ValidateUser(&u); err != nil {
849849+ result = append(result, err.Error())
850850+ }
851851+ if err := ValidateEmail(u.Email); err != nil {
852852+ result = append(result, err.Error())
853853+ }
854854+ return result
835855}
836856837857// UpdateUserCols update user according special columns