 f6a5b783d2
			
		
	
	
	f6a5b783d2
	
	
	
		
			
			## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [ ] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] I do not want this change to show in the release notes. - [ ] I want the title to show in the release notes with a link to this pull request. - [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title. Co-authored-by: Michael Jerger <michael.jerger@meissa-gmbh.de> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7203 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: zam <mirco.zachmann@meissa.de> Co-committed-by: zam <mirco.zachmann@meissa.de>
		
			
				
	
	
		
			106 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2025 The Forgejo Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package forgejo_migrations //nolint:revive
 | |
| 
 | |
| import (
 | |
| 	"time"
 | |
| 
 | |
| 	"forgejo.org/models/migrations/base"
 | |
| 	"forgejo.org/modules/forgefed"
 | |
| 	"forgejo.org/modules/log"
 | |
| 	"forgejo.org/modules/timeutil"
 | |
| 
 | |
| 	"xorm.io/xorm"
 | |
| )
 | |
| 
 | |
| func MigrateNormalizedFederatedURI(x *xorm.Engine) error {
 | |
| 	// Update schema
 | |
| 	type FederatedUser struct {
 | |
| 		ID                    int64  `xorm:"pk autoincr"`
 | |
| 		UserID                int64  `xorm:"NOT NULL"`
 | |
| 		ExternalID            string `xorm:"UNIQUE(federation_user_mapping) NOT NULL"`
 | |
| 		FederationHostID      int64  `xorm:"UNIQUE(federation_user_mapping) NOT NULL"`
 | |
| 		NormalizedOriginalURL string
 | |
| 	}
 | |
| 	type User struct {
 | |
| 		ID                     int64 `xorm:"pk autoincr"`
 | |
| 		NormalizedFederatedURI string
 | |
| 	}
 | |
| 	type FederationHost struct {
 | |
| 		ID             int64              `xorm:"pk autoincr"`
 | |
| 		HostFqdn       string             `xorm:"host_fqdn UNIQUE INDEX VARCHAR(255) NOT NULL"`
 | |
| 		NodeInfo       NodeInfo           `xorm:"extends NOT NULL"`
 | |
| 		HostPort       uint16             `xorm:"NOT NULL DEFAULT 443"`
 | |
| 		HostSchema     string             `xorm:"NOT NULL DEFAULT 'https'"`
 | |
| 		LatestActivity time.Time          `xorm:"NOT NULL"`
 | |
| 		Created        timeutil.TimeStamp `xorm:"created"`
 | |
| 		Updated        timeutil.TimeStamp `xorm:"updated"`
 | |
| 	}
 | |
| 	if err := x.Sync(new(User), new(FederatedUser), new(FederationHost)); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Migrate
 | |
| 	sessMigration := x.NewSession()
 | |
| 	defer sessMigration.Close()
 | |
| 	if err := sessMigration.Begin(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	federatedUsers := make([]*FederatedUser, 0)
 | |
| 	err := sessMigration.OrderBy("id").Find(&federatedUsers)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	for _, federatedUser := range federatedUsers {
 | |
| 		if federatedUser.NormalizedOriginalURL != "" {
 | |
| 			log.Trace("migration[30]: FederatedUser was already migrated %v", federatedUser)
 | |
| 		} else {
 | |
| 			user := &User{}
 | |
| 			has, err := sessMigration.Where("id=?", federatedUser.UserID).Get(user)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 
 | |
| 			if !has {
 | |
| 				log.Debug("migration[30]: User missing for federated user: %v", federatedUser)
 | |
| 				_, err := sessMigration.Delete(federatedUser)
 | |
| 				if err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 			} else {
 | |
| 				// Migrate User.NormalizedFederatedURI -> FederatedUser.NormalizedOriginalUrl
 | |
| 				sql := "UPDATE `federated_user` SET `normalized_original_url` = ? WHERE `id` = ?"
 | |
| 				if _, err := sessMigration.Exec(sql, user.NormalizedFederatedURI, federatedUser.FederationHostID); err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 
 | |
| 				// Migrate (Port, Schema) FederatedUser.NormalizedOriginalUrl -> FederationHost.(Port, Schema)
 | |
| 				actorID, err := forgefed.NewActorID(user.NormalizedFederatedURI)
 | |
| 				if err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 				sql = "UPDATE `federation_host` SET `host_port` = ?, `host_schema` = ? WHERE `id` = ?"
 | |
| 				if _, err := sessMigration.Exec(sql, actorID.HostPort, actorID.HostSchema, federatedUser.FederationHostID); err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if err := sessMigration.Commit(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Drop User.NormalizedFederatedURI field in extra transaction
 | |
| 	sessSchema := x.NewSession()
 | |
| 	defer sessSchema.Close()
 | |
| 	if err := sessSchema.Begin(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := base.DropTableColumns(sessSchema, "user", "normalized_federated_uri"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return sessSchema.Commit()
 | |
| }
 |