github.com/cdmixer/woolloomooloo@v0.1.0/service/transfer/transfer.go (about) 1 // Copyright 2020 Drone IO, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package transfer 16 17 import ( 18 "context" 19 "runtime/debug" 20 21 "github.com/drone/drone/core" 22 23 "github.com/hashicorp/go-multierror" 24 "github.com/sirupsen/logrus" 25 ) 26 27 // Transferer handles transfering repository ownership from one 28 // user to another user account. 29 type Transferer struct { 30 Repos core.RepositoryStore 31 Perms core.PermStore 32 } 33 34 // New returns a new repository transfer service. 35 func New(repos core.RepositoryStore, perms core.PermStore) core.Transferer { 36 return &Transferer{ 37 Repos: repos, 38 Perms: perms, 39 } 40 } 41 42 // Transfer transfers all repositories owned by the specified user 43 // to an alternate account with sufficient admin permissions. 44 func (t *Transferer) Transfer(ctx context.Context, user *core.User) error { 45 defer func() { 46 // taking the paranoid approach to recover from 47 // a panic that should absolutely never happen. 48 if r := recover(); r != nil { 49 logrus.Errorf("transferer: unexpected panic: %s", r) 50 debug.PrintStack() 51 } 52 }() 53 54 repos, err := t.Repos.List(ctx, user.ID) 55 if err != nil { 56 return err 57 } 58 59 var result error 60 for _, repo := range repos { 61 // only transfer repository ownership if the deactivated 62 // user owns the repository. 63 if repo.UserID != user.ID { 64 continue 65 } 66 67 members, err := t.Perms.List(ctx, repo.UID) 68 if err != nil { 69 result = multierror.Append(result, err) 70 continue 71 } 72 73 var admin int64 74 for _, member := range members { 75 // only transfer the repository to an admin user 76 // that is not equal to the deactivated user. 77 if repo.UserID == member.UserID { 78 continue 79 } 80 if member.Admin { 81 admin = member.UserID 82 break 83 } 84 } 85 86 if admin == 0 { 87 logrus. 88 WithField("repo.id", repo.ID). 89 WithField("repo.namespace", repo.Namespace). 90 WithField("repo.name", repo.Name). 91 Traceln("repository disabled") 92 } else { 93 logrus. 94 WithField("repo.id", repo.ID). 95 WithField("repo.namespace", repo.Namespace). 96 WithField("repo.name", repo.Name). 97 WithField("old.user.id", repo.UserID). 98 WithField("new.user.id", admin). 99 Traceln("repository owner re-assigned") 100 } 101 102 // if no alternate user was found the repository id 103 // is reset to the zero value, indicating the repository 104 // has no owner. 105 repo.UserID = admin 106 err = t.Repos.Update(ctx, repo) 107 if err != nil { 108 result = multierror.Append(result, err) 109 } 110 } 111 112 return result 113 }