Repository transfer has to be confirmed, if user can not create repo for new owner (#14792)

* make repo as "pending transfer" if on transfer start doer has no right to create repo in new destination

* if new pending transfer ocured, create UI & Mail notifications
This commit is contained in:
6543 2021-03-01 01:47:30 +01:00 committed by GitHub
parent e0900310c4
commit a4148c0f12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 898 additions and 167 deletions

View file

@ -39,6 +39,8 @@ const (
NotificationSourcePullRequest
// NotificationSourceCommit is a notification of a commit
NotificationSourceCommit
// NotificationSourceRepository is a notification for a repository
NotificationSourceRepository
)
// Notification represents a notification
@ -119,6 +121,46 @@ func GetNotifications(opts FindNotificationOptions) (NotificationList, error) {
return getNotifications(x, opts)
}
// CreateRepoTransferNotification creates notification for the user a repository was transferred to
func CreateRepoTransferNotification(doer, newOwner *User, repo *Repository) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
var notify []*Notification
if newOwner.IsOrganization() {
users, err := getUsersWhoCanCreateOrgRepo(sess, newOwner.ID)
if err != nil || len(users) == 0 {
return err
}
for i := range users {
notify = append(notify, &Notification{
UserID: users[i].ID,
RepoID: repo.ID,
Status: NotificationStatusUnread,
UpdatedBy: doer.ID,
Source: NotificationSourceRepository,
})
}
} else {
notify = []*Notification{{
UserID: newOwner.ID,
RepoID: repo.ID,
Status: NotificationStatusUnread,
UpdatedBy: doer.ID,
Source: NotificationSourceRepository,
}}
}
if _, err := sess.InsertMulti(notify); err != nil {
return err
}
return sess.Commit()
}
// CreateOrUpdateIssueNotifications creates an issue notification
// for each watcher, or updates it if already exists
// receiverID > 0 just send to reciver, else send to all watcher
@ -363,7 +405,7 @@ func (n *Notification) loadRepo(e Engine) (err error) {
}
func (n *Notification) loadIssue(e Engine) (err error) {
if n.Issue == nil {
if n.Issue == nil && n.IssueID != 0 {
n.Issue, err = getIssueByID(e, n.IssueID)
if err != nil {
return fmt.Errorf("getIssueByID [%d]: %v", n.IssueID, err)
@ -374,7 +416,7 @@ func (n *Notification) loadIssue(e Engine) (err error) {
}
func (n *Notification) loadComment(e Engine) (err error) {
if n.Comment == nil && n.CommentID > 0 {
if n.Comment == nil && n.CommentID != 0 {
n.Comment, err = getCommentByID(e, n.CommentID)
if err != nil {
return fmt.Errorf("GetCommentByID [%d] for issue ID [%d]: %v", n.CommentID, n.IssueID, err)
@ -405,10 +447,18 @@ func (n *Notification) GetIssue() (*Issue, error) {
// HTMLURL formats a URL-string to the notification
func (n *Notification) HTMLURL() string {
if n.Comment != nil {
return n.Comment.HTMLURL()
switch n.Source {
case NotificationSourceIssue, NotificationSourcePullRequest:
if n.Comment != nil {
return n.Comment.HTMLURL()
}
return n.Issue.HTMLURL()
case NotificationSourceCommit:
return n.Repository.HTMLURL() + "/commit/" + n.CommitID
case NotificationSourceRepository:
return n.Repository.HTMLURL()
}
return n.Issue.HTMLURL()
return ""
}
// APIURL formats a URL-string to the notification
@ -562,8 +612,10 @@ func (nl NotificationList) LoadIssues() ([]int, error) {
if notification.Issue == nil {
notification.Issue = issues[notification.IssueID]
if notification.Issue == nil {
log.Error("Notification[%d]: IssueID: %d Not Found", notification.ID, notification.IssueID)
failures = append(failures, i)
if notification.IssueID != 0 {
log.Error("Notification[%d]: IssueID: %d Not Found", notification.ID, notification.IssueID)
failures = append(failures, i)
}
continue
}
notification.Issue.Repo = notification.Repository
@ -683,7 +735,7 @@ func GetUIDsAndNotificationCounts(since, until timeutil.TimeStamp) ([]UserIDCoun
return res, x.SQL(sql, since, until, NotificationStatusUnread).Find(&res)
}
func setNotificationStatusReadIfUnread(e Engine, userID, issueID int64) error {
func setIssueNotificationStatusReadIfUnread(e Engine, userID, issueID int64) error {
notification, err := getIssueNotification(e, userID, issueID)
// ignore if not exists
if err != nil {
@ -700,6 +752,16 @@ func setNotificationStatusReadIfUnread(e Engine, userID, issueID int64) error {
return err
}
func setRepoNotificationStatusReadIfUnread(e Engine, userID, repoID int64) error {
_, err := e.Where(builder.Eq{
"user_id": userID,
"status": NotificationStatusUnread,
"source": NotificationSourceRepository,
"repo_id": repoID,
}).Cols("status").Update(&Notification{Status: NotificationStatusRead})
return err
}
// SetNotificationStatus change the notification status
func SetNotificationStatus(notificationID int64, user *User, status NotificationStatus) error {
notification, err := getNotificationByID(x, notificationID)