Added delete Dependency function

+ Improved Event Comments

Signed-off-by: Konrad <konrad@kola-entertainments.de>
This commit is contained in:
Konrad Langenberg 2017-08-29 17:10:40 +02:00 committed by Jonas Franz
parent b89a9e9d2e
commit ab17606372
10 changed files with 149 additions and 191 deletions

2
conf/app.ini vendored
View File

@ -389,7 +389,7 @@ MODE = console
; Buffer length of channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
LEVEL = Debug
LEVEL = Trace
; For "console" mode only
[log.console]

View File

@ -62,6 +62,8 @@ const (
CommentTypeCancelTracking
// Dependency added
CommentTypeAddedDependency
//Dependency removed
CommentTypeRemovedDependency
)
// CommentTag defines comment tag type

View File

@ -6,18 +6,19 @@ package models
import (
"time"
"strconv"
)
// IssueDependency is connection request for receiving issue notification.
type IssueDependency struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"UNIQUE(watch) NOT NULL"`
IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"`
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"UNIQUE(watch) NOT NULL"`
IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"`
DependencyID int64 `xorm:"UNIQUE(watch) NOT NULL"`
Created time.Time `xorm:"-"`
CreatedUnix int64 `xorm:"NOT NULL"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64 `xorm:"NOT NULL"`
Created time.Time `xorm:"-"`
CreatedUnix int64 `xorm:"NOT NULL"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64 `xorm:"NOT NULL"`
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
@ -43,61 +44,70 @@ func (iw *IssueDependency) BeforeUpdate() {
}
// CreateIssueDependency creates a new dependency for an issue
func CreateIssueDependency(user *User, issue, dep *Issue) (err error, exists bool, depExists bool) {
sess := x.NewSession()
// TODO: Move this to the appropriate place
// TODO: prevent issues having itself as dependency
func CreateIssueDependency(userID, issueID int64, depID int64) (err error, exists bool, depExists bool) {
err = x.Sync(new(IssueDependency))
if err != nil {
return err, exists, false
}
// Check if it aleready exists
exists, err = issueDepExists(x, issue.ID, dep.ID)
exists, err = issueDepExists(x, issueID, depID)
if err != nil {
return err, exists, false
}
// If it not exists, create it, otherwise show an error message
if !exists {
newId := new(IssueDependency)
newId.UserID = user.ID
newId.IssueID = issue.ID
newId.DependencyID = dep.ID
// Check if the other issue exists
var issue = Issue{}
issueExists, err := x.Id(depID).Get(&issue)
if issueExists {
newId := new(IssueDependency)
newId.UserID = userID
newId.IssueID = issueID
newId.DependencyID = depID
if _, err := x.Insert(newId); err != nil {
return err, exists, false
}
// Add comment referencing the new dependency
_, err = createIssueDependencyComment(sess, user, issue, dep, true)
if err != nil {
return err, exists, false
}
// Create a new comment for the dependent issue
_, err = createIssueDependencyComment(sess, user, dep, issue, true)
if err != nil {
return err, exists, false
if _, err := x.Insert(newId); err != nil {
return err, exists, false
}
// Add comment referencing the new dependency
comment := &Comment{
IssueID: issueID,
PosterID: userID,
Type: CommentTypeAddedDependency,
Content: strconv.FormatInt(depID, 10),
}
if _, err := x.Insert(comment); err != nil {
return err, exists, false
}
comment = &Comment{
IssueID: depID,
PosterID: userID,
Type: CommentTypeAddedDependency,
Content: strconv.FormatInt(issueID, 10),
}
if _, err := x.Insert(comment); err != nil {
return err, exists, false
}
}
return err, exists, true
}
return nil, exists, true
return nil, exists, false
}
// Removes a dependency from an issue
func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType int64) (err error) {
sess := x.NewSession()
// TODO: Same as above
func RemoveIssueDependency(userID, issueID int64, depID int64, depType int64) (err error) {
err = x.Sync(new(IssueDependency))
if err != nil {
return err
}
// Check if it exists
exists, err := issueDepExists(x, issue.ID, dep.ID)
exists, err := issueDepExists(x, issueID, depID)
if err != nil {
return err
}
@ -105,31 +115,40 @@ func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType int64)
// If it exists, remove it, otherwise show an error message
if exists {
if depType == 1 {
_, err := x.Delete(&IssueDependency{IssueID: issue.ID, DependencyID: dep.ID})
if depType == 1{
_, err := x.Delete(&IssueDependency{IssueID: issueID, DependencyID: depID})
if err != nil {
return err
}
}
if depType == 2 {
_, err := x.Delete(&IssueDependency{IssueID: dep.ID, DependencyID: issue.ID})
if depType == 2{
_, err := x.Delete(&IssueDependency{IssueID: depID, DependencyID: issueID})
if err != nil {
return err
}
}
// Add comment referencing the removed dependency
_, err = createIssueDependencyComment(sess, user, issue, dep, false)
comment := &Comment{
IssueID: issueID,
PosterID: userID,
Type: CommentTypeRemovedDependency,
Content: strconv.FormatInt(depID, 10),
}
if err != nil {
if _, err := x.Insert(comment); err != nil {
return err
}
// Create a new comment for the dependent issue
_, err = createIssueDependencyComment(sess, user, dep, issue, false)
comment = &Comment{
IssueID: depID,
PosterID: userID,
Type: CommentTypeRemovedDependency,
Content: strconv.FormatInt(issueID, 10),
}
if err != nil {
if _, err := x.Insert(comment); err != nil {
return err
}
}
@ -152,34 +171,3 @@ func issueDepExists(e Engine, issueID int64, depID int64) (exists bool, err erro
return
}
// check if issue can be closed
func IssueNoDependenciesLeft(issue *Issue) bool {
// Check if the Repo is allowed to have dependencies, if not return true (= issue can be closed)
// Otherwise check for all open dependencies
r, err := getRepositoryByID(x, issue.RepoID)
if err != nil {
return false
}
if !r.UnitEnabled(UnitTypeIssueDependencies) {
return true
}
var issueDeps []IssueDependency
err = x.Where("issue_id = ?", issue.ID).Find(&issueDeps)
for _, issueDep := range issueDeps {
issueDetails, _ := getIssueByID(x, issueDep.DependencyID)
if !issueDetails.IsClosed {
return false
}
}
if err != nil {
return false
}
return true
}

View File

@ -1,98 +0,0 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"time"
)
// IssueDependency is connection request for receiving issue notification.
type IssueDependency struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"UNIQUE(watch) NOT NULL"`
IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"`
DependencyID int64 `xorm:"UNIQUE(watch) NOT NULL"`
Created time.Time `xorm:"-"`
CreatedUnix int64 `xorm:"NOT NULL"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64 `xorm:"NOT NULL"`
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (iw *IssueDependency) BeforeInsert() {
var (
t = time.Now()
u = t.Unix()
)
iw.Created = t
iw.CreatedUnix = u
iw.Updated = t
iw.UpdatedUnix = u
}
// BeforeUpdate is invoked from XORM before updating an object of this type.
func (iw *IssueDependency) BeforeUpdate() {
var (
t = time.Now()
u = t.Unix()
)
iw.Updated = t
iw.UpdatedUnix = u
}
// CreateOrUpdateIssueDependency creates a new dependency for an issue
func CreateOrUpdateIssueDependency(userID, issueID int64, depID int64) (err error, exists bool) {
err = x.Sync(new(IssueDependency))
if err != nil {
return err, exists
}
// Check if it aleready exists
exists, err = issueDepExists(x, issueID, depID)
if err != nil {
return err, exists
}
// If it not exists, create it, otherwise show an error message
if !exists {
newId := new(IssueDependency)
newId.UserID = userID
newId.IssueID = issueID
newId.DependencyID = depID
if _, err := x.Insert(newId); err != nil {
return err, exists
}
// Add comment referencing to the stopwatch
comment := &Comment{
IssueID: issueID,
PosterID: userID,
Type: CommentTypeAddedDependency,
}
if _, err := x.Insert(comment); err != nil {
return err, exists
}
}
return nil, exists
}
// Check if the dependency already exists
func issueDepExists(e Engine, issueID int64, depID int64) (exists bool, err error) {
var Dependencies = IssueDependency{IssueID: issueID, DependencyID: depID}
exists, err = e.Get(&Dependencies)
// Check for dependencies the other way around
// Otherwise two issues could block each other which would result in none of them could be closed.
if !exists {
Dependencies.IssueID = depID
Dependencies.DependencyID = issueID
exists, err = e.Get(&Dependencies)
}
return
}

View File

@ -732,6 +732,7 @@ issues.dependency.cancel = Cancel
issues.dependency.add_header = Add New Dependency
issues.dependency.issue_number = Issuenumber
issues.dependency.added_dependency = `<a href="%[1]s">%[2]s</a> added a new dependency %[3]s`
issues.dependency.removed_dependency = `<a href="%[1]s">%[2]s</a> removed a dependency %[3]s`
pulls.desc = Pulls management your code review and merge requests

View File

@ -28,12 +28,16 @@ func AddDependency(c *context.Context) {
return
}
err, exists := models.CreateOrUpdateIssueDependency(c.User.ID, issue.ID, dep);
err, exists, depExists := models.CreateIssueDependency(c.User.ID, issue.ID, dep);
if err != nil {
c.Handle(http.StatusInternalServerError, "CreateOrUpdateIssueDependency", err)
return
}
if !depExists {
c.Flash.Error("Dependend issue does not exist!")
}
if exists {
c.Flash.Error("Dependency already exists!")
}

View File

@ -15,7 +15,7 @@ import (
// IssueWatch sets issue watching
func RemoveDependency(c *context.Context) {
depID, err := strconv.ParseInt(c.Req.PostForm.Get("removeDependencyID"), 10, 64)
dep, err := strconv.ParseInt(c.Req.PostForm.Get("removeDependencyID"), 10, 64)
if err != nil {
c.Handle(http.StatusBadRequest, "issue ID is not int", err)
return
@ -41,14 +41,7 @@ func RemoveDependency(c *context.Context) {
return
}
// Dependency
dep, err := models.GetIssueByID(depID)
if err != nil {
c.Handle(http.StatusInternalServerError, "GetIssueByID", err)
return
}
err = models.RemoveIssueDependency(c.User, issue, dep, depType)
err = models.RemoveIssueDependency(c.User.ID, issue.ID, dep, depType)
if err != nil {
c.Handle(http.StatusInternalServerError, "CreateOrUpdateIssueDependency", err)
return

View File

@ -485,6 +485,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/content", repo.UpdateIssueContent)
m.Post("/watch", repo.IssueWatch)
m.Post("/addDependency", repo.AddDependency)
m.Post("/removeDependency", repo.RemoveDependency)
m.Group("/times", func() {
m.Post("/add", bindIgnErr(auth.AddTimeManuallyForm{}), repo.AddTimeManually)
m.Group("/stopwatch", func() {

View File

@ -193,5 +193,33 @@
{{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink .Poster.Name $createdStr | Safe}}
</span>
{{end}}
{{else if eq .Type 17}}
<div class="event">
<span class="octicon octicon-primitive-dot"></span>
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
<img src="{{.Poster.RelAvatarLink}}">
</a>
<span class="text grey">
{{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink .Poster.Name $createdStr | Safe}}
</span>
<div class="detail">
<span class="octicon octicon-plus"></span>
<span class="text grey">{{.Content}}</span>
</div>
</div>
{{else if eq .Type 18}}
<div class="event">
<span class="octicon octicon-primitive-dot"></span>
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
<img src="{{.Poster.RelAvatarLink}}">
</a>
<span class="text grey">
{{$.i18n.Tr "repo.issues.dependency.removed_dependency" .Poster.HomeLink .Poster.Name $createdStr | Safe}}
</span>
<div class="detail">
<span class="text grey octicon octicon-trashcan"></span>
<span class="text grey">{{.Content}}&nbsp;</span>
</div>
</div>
{{end}}
{{end}}

View File

@ -196,11 +196,15 @@
<div class="ui depending">
<span class="text"><strong>{{.i18n.Tr "repo.issues.dependency.title"}}</strong></span>
<br>
{{if .BlockedByDependencies}}
<span class="text">This issue is blocked by:</span>
<div class="ui relaxed divided list">
{{range .BlockedByDependencies}}
<div class="item">
<div class="right floated content">
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.ID}}, 1);">
<i class="delete icon text red"></i>
</a>
{{if .IsClosed}}
<div class="ui red mini label">
<i class="octicon octicon-issue-closed"></i>
@ -216,14 +220,19 @@
</div>
{{end}}
</div>
{{end}}
{{if .BlockingDependencies}}
<div class="ui relaxed divided list">
<span class="text">This issue blocks the following issues:</span>
{{range .BlockingDependencies}}
<div class="item">
<div class="right floated content">
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.ID}}, 2);">
<i class="delete icon text red"></i>
</a>
{{if .IsClosed}}
<div class="ui red mini label">
<div class="ui red tiny label">
<i class="octicon octicon-issue-closed"></i>
</div>
{{else}}
@ -236,8 +245,12 @@
<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
</div>
{{end}}
<p>{{.i18n.Tr "repo.issues.dependency.no_dependencies"}}</p>
</div>
{{end}}
{{if (and (not .BlockedByDependencies) (not .BlockingDependencies))}}
<p>{{.i18n.Tr "repo.issues.dependency.no_dependencies"}}</p>
{{end}}
<div>
<button class="fluid green ui button" onclick="showAddDependencyModal();">
{{.i18n.Tr "repo.issues.dependency.add"}}
@ -248,7 +261,7 @@
</div>
<div class="ui tiny modal">
<div class="ui mini modal add-dependency">
<div class="header">
{{.i18n.Tr "repo.issues.dependency.add_header"}}
</div>
@ -270,3 +283,29 @@
</div>
</div>
</div>
<div class="ui basic modal remove-dependency">
<div class="ui icon header">
<i class="trash icon"></i>
Remove Dependency
</div>
<div class="content">
<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/removeDependency" id="removeDependencyForm">
{{$.CsrfTokenHtml}}
<input type="hidden" value="" name="removeDependencyID" id="removeDependencyID"/>
<input type="hidden" value="" name="dependencyType" id="dependencyType"/>
</form>
<p>This will remove the dependency to this issue. Are you sure? You cannot undo this!</p>
</div>
<div class="actions">
<div class="ui basic red cancel inverted button">
<i class="remove icon"></i>
Cancel
</div>
<div class="ui basic green ok inverted button">
<i class="checkmark icon"></i>
Delete
</div>
</div>
</div>