mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Assignee back end
This commit is contained in:
		@@ -58,9 +58,10 @@ func UpdateAccessWithSession(sess *xorm.Session, access *Access) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasAccess returns true if someone can read or write to given repository.
 | 
			
		||||
func HasAccess(userName, repoName string, mode int) (bool, error) {
 | 
			
		||||
// The repoName should be in format <username>/<reponame>.
 | 
			
		||||
func HasAccess(uname, repoName string, mode int) (bool, error) {
 | 
			
		||||
	access := &Access{
 | 
			
		||||
		UserName: strings.ToLower(userName),
 | 
			
		||||
		UserName: strings.ToLower(uname),
 | 
			
		||||
		RepoName: strings.ToLower(repoName),
 | 
			
		||||
	}
 | 
			
		||||
	has, err := orm.Get(access)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ type Issue struct {
 | 
			
		||||
	Poster          *User `xorm:"-"`
 | 
			
		||||
	MilestoneId     int64
 | 
			
		||||
	AssigneeId      int64
 | 
			
		||||
	Assignee        *User `xorm:"-"`
 | 
			
		||||
	IsRead          bool  `xorm:"-"`
 | 
			
		||||
	IsPull          bool  // Indicates whether is a pull request or not.
 | 
			
		||||
	IsClosed        bool
 | 
			
		||||
@@ -46,6 +47,14 @@ func (i *Issue) GetPoster() (err error) {
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *Issue) GetAssignee() (err error) {
 | 
			
		||||
	if i.AssigneeId == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	i.Assignee, err = GetUserById(i.AssigneeId)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateIssue creates new issue for repository.
 | 
			
		||||
func NewIssue(issue *Issue) (err error) {
 | 
			
		||||
	sess := orm.NewSession()
 | 
			
		||||
@@ -159,38 +168,35 @@ type IssueUser struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewIssueUserPairs adds new issue-user pairs for new issue of repository.
 | 
			
		||||
func NewIssueUserPairs(rid, iid, oid, uid, aid int64) (err error) {
 | 
			
		||||
func NewIssueUserPairs(rid, iid, oid, pid, aid int64, repoName string) (err error) {
 | 
			
		||||
	iu := &IssueUser{IssueId: iid, RepoId: rid}
 | 
			
		||||
 | 
			
		||||
	ws, err := GetWatchers(rid)
 | 
			
		||||
	us, err := GetCollaborators(repoName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: check collaborators.
 | 
			
		||||
	// Add owner.
 | 
			
		||||
	ids := []int64{oid}
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		if IsWatching(id, rid) {
 | 
			
		||||
			continue
 | 
			
		||||
	isNeedAddPoster := true
 | 
			
		||||
	for _, u := range us {
 | 
			
		||||
		iu.Uid = u.Id
 | 
			
		||||
		iu.IsPoster = iu.Uid == pid
 | 
			
		||||
		if isNeedAddPoster && iu.IsPoster {
 | 
			
		||||
			isNeedAddPoster = false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// In case owner is not watching.
 | 
			
		||||
		ws = append(ws, &Watch{UserId: id})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, w := range ws {
 | 
			
		||||
		if w.UserId == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		iu.Uid = w.UserId
 | 
			
		||||
		iu.IsPoster = iu.Uid == uid
 | 
			
		||||
		iu.IsAssigned = iu.Uid == aid
 | 
			
		||||
		if _, err = orm.Insert(iu); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if isNeedAddPoster {
 | 
			
		||||
		iu.Uid = pid
 | 
			
		||||
		iu.IsPoster = true
 | 
			
		||||
		iu.IsAssigned = iu.Uid == aid
 | 
			
		||||
		if _, err = orm.Insert(iu); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -713,8 +713,8 @@ func GetRepositoryCount(user *User) (int64, error) {
 | 
			
		||||
	return orm.Count(&Repository{OwnerId: user.Id})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCollaborators returns a list of user name of repository's collaborators.
 | 
			
		||||
func GetCollaborators(repoName string) ([]string, error) {
 | 
			
		||||
// GetCollaboratorNames returns a list of user name of repository's collaborators.
 | 
			
		||||
func GetCollaboratorNames(repoName string) ([]string, error) {
 | 
			
		||||
	accesses := make([]*Access, 0, 10)
 | 
			
		||||
	if err := orm.Find(&accesses, &Access{RepoName: strings.ToLower(repoName)}); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -727,6 +727,23 @@ func GetCollaborators(repoName string) ([]string, error) {
 | 
			
		||||
	return names, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCollaborators returns a list of users of repository's collaborators.
 | 
			
		||||
func GetCollaborators(repoName string) (us []*User, err error) {
 | 
			
		||||
	accesses := make([]*Access, 0, 10)
 | 
			
		||||
	if err = orm.Find(&accesses, &Access{RepoName: strings.ToLower(repoName)}); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	us = make([]*User, len(accesses))
 | 
			
		||||
	for i := range accesses {
 | 
			
		||||
		us[i], err = GetUserByName(accesses[i].UserName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return us, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Watch is connection request for receiving repository notifycation.
 | 
			
		||||
type Watch struct {
 | 
			
		||||
	Id     int64
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ import (
 | 
			
		||||
 | 
			
		||||
func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 | 
			
		||||
	return func(ctx *Context, params martini.Params) {
 | 
			
		||||
		log.Trace(fmt.Sprint(args))
 | 
			
		||||
		// valid brachname
 | 
			
		||||
		var validBranch bool
 | 
			
		||||
		// display bare quick start if it is a bare repo
 | 
			
		||||
@@ -40,27 +41,34 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 | 
			
		||||
		var (
 | 
			
		||||
			user        *models.User
 | 
			
		||||
			err         error
 | 
			
		||||
			isTrueOwner bool
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		userName := params["username"]
 | 
			
		||||
		repoName := params["reponame"]
 | 
			
		||||
		refName := params["branchname"]
 | 
			
		||||
 | 
			
		||||
		// TODO: check collaborators
 | 
			
		||||
		// get repository owner
 | 
			
		||||
		ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName)
 | 
			
		||||
		// Collaborators who have write access can be seen as owners.
 | 
			
		||||
		if ctx.IsSigned {
 | 
			
		||||
			ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, repoName, models.AU_WRITABLE)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				ctx.Handle(500, "RepoAssignment(HasAccess)", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			isTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !ctx.Repo.IsOwner {
 | 
			
		||||
			user, err = models.GetUserByName(params["username"])
 | 
			
		||||
		if !isTrueOwner {
 | 
			
		||||
			user, err = models.GetUserByName(userName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				if err == models.ErrUserNotExist {
 | 
			
		||||
					ctx.Handle(404, "RepoAssignment", err)
 | 
			
		||||
					ctx.Handle(404, "RepoAssignment(GetUserByName)", err)
 | 
			
		||||
					return
 | 
			
		||||
				} else if redirect {
 | 
			
		||||
					ctx.Redirect("/")
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				ctx.Handle(500, "RepoAssignment", err)
 | 
			
		||||
				ctx.Handle(500, "RepoAssignment(GetUserByName)", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
 
 | 
			
		||||
@@ -114,6 +114,13 @@ func CreateIssue(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	ctx.Data["Title"] = "Create issue"
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssues"] = true
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssuesList"] = false
 | 
			
		||||
 | 
			
		||||
	us, err := models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["Collaborators"] = us
 | 
			
		||||
	ctx.HTML(200, "issue/create")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -122,6 +129,13 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssues"] = true
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssuesList"] = false
 | 
			
		||||
 | 
			
		||||
	us, err := models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["Collaborators"] = us
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		ctx.HTML(200, "issue/create")
 | 
			
		||||
		return
 | 
			
		||||
@@ -140,8 +154,8 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C
 | 
			
		||||
	if err := models.NewIssue(issue); err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.CreateIssue(NewIssue)", err)
 | 
			
		||||
		return
 | 
			
		||||
	} else if err := models.NewIssueUserPairs(issue.RepoId, issue.Id,
 | 
			
		||||
		ctx.Repo.Owner.Id, ctx.User.Id, form.AssigneeId); err != nil {
 | 
			
		||||
	} else if err := models.NewIssueUserPairs(issue.RepoId, issue.Id, ctx.Repo.Owner.Id,
 | 
			
		||||
		ctx.User.Id, form.AssigneeId, ctx.Repo.Repository.Name); err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.CreateIssue(NewIssueUserPairs)", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -219,13 +233,14 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get poster.
 | 
			
		||||
	u, err := models.GetUserById(issue.PosterId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.ViewIssue(GetUserById): %v", err)
 | 
			
		||||
	// Get poster and Assignee.
 | 
			
		||||
	if err = issue.GetPoster(); err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.ViewIssue(GetPoster): %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	} else if err = issue.GetAssignee(); err != nil {
 | 
			
		||||
		ctx.Handle(500, "issue.ViewIssue(GetAssignee): %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	issue.Poster = u
 | 
			
		||||
	issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
 | 
			
		||||
 | 
			
		||||
	// Get comments.
 | 
			
		||||
 
 | 
			
		||||
@@ -136,7 +136,7 @@ func Collaboration(ctx *middleware.Context) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	names, err := models.GetCollaborators(repoLink)
 | 
			
		||||
	names, err := models.GetCollaboratorNames(repoLink)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(500, "setting.Collaboration(GetCollaborators)", err)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group panel-body">
 | 
			
		||||
                    <span><strong id="assigned" data-no-assigned="No one">No one</strong> will be assigned</span>
 | 
			
		||||
                    <input type="hidden" name="assigned" value="0" id="assignee"/>  
 | 
			
		||||
                    <input type="hidden" name="assigneeid" value="0" id="assignee"/>  
 | 
			
		||||
                    <div style="display: inline-block;position: relative">
 | 
			
		||||
                        <button type="button" class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown">
 | 
			
		||||
                            <i class="fa fa-group"></i>
 | 
			
		||||
@@ -25,7 +25,9 @@
 | 
			
		||||
                        <div class="dropdown-menu assignee">
 | 
			
		||||
                            <ul class="list-unstyled">
 | 
			
		||||
                                <li data-uid="0" class="clear-assignee hidden"><i class="fa fa-times-circle-o"></i> Clear assignee</li>
 | 
			
		||||
                                <li data-uid="123"><img src="//1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132"><strong>fuxiaohei</strong> nickname</li>
 | 
			
		||||
                                {{range .Collaborators}}
 | 
			
		||||
                                <li data-uid="{{.Id}}"><img src="{{.AvatarLink}}"><strong>{{.Name}}</strong> {{.FullName}}</li>
 | 
			
		||||
                                {{end}}
 | 
			
		||||
                            </ul>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -98,10 +98,11 @@
 | 
			
		||||
                </div>{{else}}<div class="alert alert-warning"><a class="btn btn-success btn-lg" href="/user/sign_up">Sign up for free</a> to join this conversation. Already have an account? <a href="/user/login">Sign in to comment</a></div>{{end}}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="issue-bar col-md-2">
 | 
			
		||||
                <div class="assignee">
 | 
			
		||||
                    <h4>Assignee</h4>
 | 
			
		||||
                    <p><img src="//1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132"><strong>fuxiaohei</strong></p>
 | 
			
		||||
                    <p>{{if .Issue.Assignee}}<img src="{{.Issue.Assignee.AvatarLink}}"><strong>{{.Issue.Assignee.Name}}</strong>{{else}}No one assigned{{end}}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div><!--
 | 
			
		||||
            <div class="col-md-3">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user