mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-09 03:11:51 +01:00
Almost done issue label #200
This commit is contained in:
parent
50ba08e2c6
commit
b1bdbd7f94
9 changed files with 266 additions and 96 deletions
|
@ -76,7 +76,6 @@ func runWeb(*cli.Context) {
|
||||||
m.Get("/issues", reqSignIn, user.Issues)
|
m.Get("/issues", reqSignIn, user.Issues)
|
||||||
m.Get("/pulls", reqSignIn, user.Pulls)
|
m.Get("/pulls", reqSignIn, user.Pulls)
|
||||||
m.Get("/stars", reqSignIn, user.Stars)
|
m.Get("/stars", reqSignIn, user.Stars)
|
||||||
m.Get("/help", routers.Help)
|
|
||||||
|
|
||||||
m.Group("/api", func(r martini.Router) {
|
m.Group("/api", func(r martini.Router) {
|
||||||
m.Group("/v1", func(r martini.Router) {
|
m.Group("/v1", func(r martini.Router) {
|
||||||
|
@ -191,9 +190,12 @@ func runWeb(*cli.Context) {
|
||||||
r.Get("/new", repo.CreateIssue)
|
r.Get("/new", repo.CreateIssue)
|
||||||
r.Post("/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost)
|
r.Post("/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost)
|
||||||
r.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
|
r.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
|
||||||
r.Post("/:index/assignee", repo.UpdateAssignee)
|
r.Post("/:index/label", repo.UpdateIssueLabel)
|
||||||
r.Post("/:index/milestone", repo.UpdateIssueMilestone)
|
r.Post("/:index/milestone", repo.UpdateIssueMilestone)
|
||||||
|
r.Post("/:index/assignee", repo.UpdateAssignee)
|
||||||
r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
||||||
|
r.Post("/labels/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
||||||
|
r.Post("/labels/delete", repo.DeleteLabel)
|
||||||
r.Get("/milestones", repo.Milestones)
|
r.Get("/milestones", repo.Milestones)
|
||||||
r.Get("/milestones/new", repo.NewMilestone)
|
r.Get("/milestones/new", repo.NewMilestone)
|
||||||
r.Post("/milestones/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
|
r.Post("/milestones/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
|
||||||
|
|
2
gogs.go
2
gogs.go
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VER = "0.3.5.0521 Alpha"
|
const APP_VER = "0.3.5.0523 Alpha"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.AppVer = APP_VER
|
base.AppVer = APP_VER
|
||||||
|
|
174
models/issue.go
174
models/issue.go
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrIssueNotExist = errors.New("Issue does not exist")
|
ErrIssueNotExist = errors.New("Issue does not exist")
|
||||||
|
ErrLabelNotExist = errors.New("Label does not exist")
|
||||||
ErrMilestoneNotExist = errors.New("Milestone does not exist")
|
ErrMilestoneNotExist = errors.New("Milestone does not exist")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,13 +30,14 @@ type Issue struct {
|
||||||
Repo *Repository `xorm:"-"`
|
Repo *Repository `xorm:"-"`
|
||||||
PosterId int64
|
PosterId int64
|
||||||
Poster *User `xorm:"-"`
|
Poster *User `xorm:"-"`
|
||||||
|
LabelIds string `xorm:"TEXT"`
|
||||||
|
Labels []*Label `xorm:"-"`
|
||||||
MilestoneId int64
|
MilestoneId int64
|
||||||
AssigneeId int64
|
AssigneeId int64
|
||||||
Assignee *User `xorm:"-"`
|
Assignee *User `xorm:"-"`
|
||||||
IsRead bool `xorm:"-"`
|
IsRead bool `xorm:"-"`
|
||||||
IsPull bool // Indicates whether is a pull request or not.
|
IsPull bool // Indicates whether is a pull request or not.
|
||||||
IsClosed bool
|
IsClosed bool
|
||||||
Labels string `xorm:"TEXT"`
|
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent string `xorm:"-"`
|
||||||
Priority int
|
Priority int
|
||||||
|
@ -54,11 +56,37 @@ func (i *Issue) GetPoster() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Issue) GetLabels() error {
|
||||||
|
if len(i.LabelIds) < 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
strIds := strings.Split(strings.TrimSuffix(i.LabelIds[1:], "|"), "|$")
|
||||||
|
i.Labels = make([]*Label, 0, len(strIds))
|
||||||
|
for _, strId := range strIds {
|
||||||
|
id, _ := base.StrTo(strId).Int64()
|
||||||
|
if id > 0 {
|
||||||
|
l, err := GetLabelById(id)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrLabelNotExist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.Labels = append(i.Labels, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Issue) GetAssignee() (err error) {
|
func (i *Issue) GetAssignee() (err error) {
|
||||||
if i.AssigneeId == 0 {
|
if i.AssigneeId == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
i.Assignee, err = GetUserById(i.AssigneeId)
|
i.Assignee, err = GetUserById(i.AssigneeId)
|
||||||
|
if err == ErrUserNotExist {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +136,7 @@ func GetIssueById(id int64) (*Issue, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssues returns a list of issues by given conditions.
|
// GetIssues returns a list of issues by given conditions.
|
||||||
func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labels, sortType string) ([]Issue, error) {
|
func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labelIds, sortType string) ([]Issue, error) {
|
||||||
sess := orm.Limit(20, (page-1)*20)
|
sess := orm.Limit(20, (page-1)*20)
|
||||||
|
|
||||||
if rid > 0 {
|
if rid > 0 {
|
||||||
|
@ -127,9 +155,9 @@ func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labels, sortTy
|
||||||
sess.And("milestone_id=?", mid)
|
sess.And("milestone_id=?", mid)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(labels) > 0 {
|
if len(labelIds) > 0 {
|
||||||
for _, label := range strings.Split(labels, ",") {
|
for _, label := range strings.Split(labelIds, ",") {
|
||||||
sess.And("labels like '%$" + label + "|%'")
|
sess.And("label_ids like '%$" + label + "|%'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +183,13 @@ func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labels, sortTy
|
||||||
return issues, err
|
return issues, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIssuesByLabel returns a list of issues by given label and repository.
|
||||||
|
func GetIssuesByLabel(repoId int64, label string) ([]*Issue, error) {
|
||||||
|
issues := make([]*Issue, 0, 10)
|
||||||
|
err := orm.Where("repo_id=?", repoId).And("label_ids like '%$" + label + "|%'").Find(&issues)
|
||||||
|
return issues, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetIssueCountByPoster returns number of issues of repository by poster.
|
// GetIssueCountByPoster returns number of issues of repository by poster.
|
||||||
func GetIssueCountByPoster(uid, rid int64, isClosed bool) int64 {
|
func GetIssueCountByPoster(uid, rid int64, isClosed bool) int64 {
|
||||||
count, _ := orm.Where("repo_id=?", rid).And("poster_id=?", uid).And("is_closed=?", isClosed).Count(new(Issue))
|
count, _ := orm.Where("repo_id=?", rid).And("poster_id=?", uid).And("is_closed=?", isClosed).Count(new(Issue))
|
||||||
|
@ -175,7 +210,6 @@ type IssueUser struct {
|
||||||
IssueId int64
|
IssueId int64
|
||||||
RepoId int64
|
RepoId int64
|
||||||
MilestoneId int64
|
MilestoneId int64
|
||||||
Labels string `xorm:"TEXT"`
|
|
||||||
IsRead bool
|
IsRead bool
|
||||||
IsAssigned bool
|
IsAssigned bool
|
||||||
IsMentioned bool
|
IsMentioned bool
|
||||||
|
@ -400,6 +434,98 @@ func UpdateIssueUserPairsByMentions(uids []int64, iid int64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .____ ___. .__
|
||||||
|
// | | _____ \_ |__ ____ | |
|
||||||
|
// | | \__ \ | __ \_/ __ \| |
|
||||||
|
// | |___ / __ \| \_\ \ ___/| |__
|
||||||
|
// |_______ (____ /___ /\___ >____/
|
||||||
|
// \/ \/ \/ \/
|
||||||
|
|
||||||
|
// Label represents a label of repository for issues.
|
||||||
|
type Label struct {
|
||||||
|
Id int64
|
||||||
|
RepoId int64 `xorm:"INDEX"`
|
||||||
|
Name string
|
||||||
|
Color string `xorm:"VARCHAR(7)"`
|
||||||
|
NumIssues int
|
||||||
|
NumClosedIssues int
|
||||||
|
NumOpenIssues int `xorm:"-"`
|
||||||
|
IsChecked bool `xorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalOpenIssues calculates the open issues of label.
|
||||||
|
func (m *Label) CalOpenIssues() {
|
||||||
|
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLabel creates new label of repository.
|
||||||
|
func NewLabel(l *Label) error {
|
||||||
|
_, err := orm.Insert(l)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLabelById returns a label by given ID.
|
||||||
|
func GetLabelById(id int64) (*Label, error) {
|
||||||
|
l := &Label{Id: id}
|
||||||
|
has, err := orm.Get(l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrLabelNotExist
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLabels returns a list of labels of given repository ID.
|
||||||
|
func GetLabels(repoId int64) ([]*Label, error) {
|
||||||
|
labels := make([]*Label, 0, 10)
|
||||||
|
err := orm.Where("repo_id=?", repoId).Find(&labels)
|
||||||
|
return labels, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateLabel updates label information.
|
||||||
|
func UpdateLabel(l *Label) error {
|
||||||
|
_, err := orm.Id(l.Id).Update(l)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteLabel delete a label of given repository.
|
||||||
|
func DeleteLabel(repoId int64, strId string) error {
|
||||||
|
id, _ := base.StrTo(strId).Int64()
|
||||||
|
l, err := GetLabelById(id)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrLabelNotExist {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
issues, err := GetIssuesByLabel(repoId, strId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := orm.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err = sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, issue := range issues {
|
||||||
|
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+strId+"|", "", -1)
|
||||||
|
if _, err = sess.Id(issue.Id).AllCols().Update(issue); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Delete(l); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
// _____ .__.__ __
|
// _____ .__.__ __
|
||||||
// / \ |__| | ____ _______/ |_ ____ ____ ____
|
// / \ |__| | ____ _______/ |_ ____ ____ ____
|
||||||
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
|
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
|
||||||
|
@ -611,42 +737,6 @@ func DeleteMilestone(m *Milestone) (err error) {
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// .____ ___. .__
|
|
||||||
// | | _____ \_ |__ ____ | |
|
|
||||||
// | | \__ \ | __ \_/ __ \| |
|
|
||||||
// | |___ / __ \| \_\ \ ___/| |__
|
|
||||||
// |_______ (____ /___ /\___ >____/
|
|
||||||
// \/ \/ \/ \/
|
|
||||||
|
|
||||||
// Label represents a label of repository for issues.
|
|
||||||
type Label struct {
|
|
||||||
Id int64
|
|
||||||
RepoId int64 `xorm:"INDEX"`
|
|
||||||
Name string
|
|
||||||
Color string `xorm:"VARCHAR(7)"`
|
|
||||||
NumIssues int
|
|
||||||
NumClosedIssues int
|
|
||||||
NumOpenIssues int `xorm:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CalOpenIssues calculates the open issues of label.
|
|
||||||
func (m *Label) CalOpenIssues() {
|
|
||||||
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLabel creates new label of repository.
|
|
||||||
func NewLabel(l *Label) error {
|
|
||||||
_, err := orm.Insert(l)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLabels returns a list of labels of given repository ID.
|
|
||||||
func GetLabels(repoId int64) ([]*Label, error) {
|
|
||||||
labels := make([]*Label, 0, 10)
|
|
||||||
err := orm.Where("repo_id=?", repoId).Find(&labels)
|
|
||||||
return labels, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// _________ __
|
// _________ __
|
||||||
// \_ ___ \ ____ _____ _____ ____ _____/ |_
|
// \_ ___ \ ____ _____ _____ ____ _____/ |_
|
||||||
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
|
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
|
||||||
|
|
|
@ -32,9 +32,8 @@ func Home(ctx *middleware.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
repo.Owner, err = models.GetUserById(repo.OwnerId)
|
if err = repo.GetOwner(); err != nil {
|
||||||
if err != nil {
|
ctx.Handle(500, "dashboard.Home(GetOwner)", err)
|
||||||
ctx.Handle(500, "dashboard.Home(GetUserById)", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,12 +42,6 @@ func Home(ctx *middleware.Context) {
|
||||||
ctx.HTML(200, "home")
|
ctx.HTML(200, "home")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Help(ctx *middleware.Context) {
|
|
||||||
ctx.Data["PageIsHelp"] = true
|
|
||||||
ctx.Data["Title"] = "Help"
|
|
||||||
ctx.HTML(200, "help")
|
|
||||||
}
|
|
||||||
|
|
||||||
func NotFound(ctx *middleware.Context) {
|
func NotFound(ctx *middleware.Context) {
|
||||||
ctx.Data["PageIsNotFound"] = true
|
ctx.Data["PageIsNotFound"] = true
|
||||||
ctx.Data["Title"] = "Page Not Found"
|
ctx.Data["Title"] = "Page Not Found"
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/gogits/gogs/modules/social"
|
"github.com/gogits/gogs/modules/social"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check run mode(Default of martini is Dev).
|
|
||||||
func checkRunMode() {
|
func checkRunMode() {
|
||||||
switch base.Cfg.MustValue("", "RUN_MODE") {
|
switch base.Cfg.MustValue("", "RUN_MODE") {
|
||||||
case "prod":
|
case "prod":
|
||||||
|
|
|
@ -197,7 +197,7 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C
|
||||||
PosterId: ctx.User.Id,
|
PosterId: ctx.User.Id,
|
||||||
MilestoneId: form.MilestoneId,
|
MilestoneId: form.MilestoneId,
|
||||||
AssigneeId: form.AssigneeId,
|
AssigneeId: form.AssigneeId,
|
||||||
Labels: form.Labels,
|
LabelIds: form.Labels,
|
||||||
Content: form.Content,
|
Content: form.Content,
|
||||||
}
|
}
|
||||||
if err := models.NewIssue(issue); err != nil {
|
if err := models.NewIssue(issue); err != nil {
|
||||||
|
@ -269,6 +269,17 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C
|
||||||
ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
|
ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkLabels(labels, allLabels []*models.Label) {
|
||||||
|
for _, l := range labels {
|
||||||
|
for _, l2 := range allLabels {
|
||||||
|
if l.Id == l2.Id {
|
||||||
|
l2.IsChecked = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
||||||
idx, _ := base.StrTo(params["index"]).Int64()
|
idx, _ := base.StrTo(params["index"]).Int64()
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
|
@ -286,6 +297,19 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get labels.
|
||||||
|
if err = issue.GetLabels(); err != nil {
|
||||||
|
ctx.Handle(500, "issue.ViewIssue(GetLabels)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
labels, err := models.GetLabels(ctx.Repo.Repository.Id)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "issue.ViewIssue(GetLabels.2)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
checkLabels(issue.Labels, labels)
|
||||||
|
ctx.Data["Labels"] = labels
|
||||||
|
|
||||||
// Get assigned milestone.
|
// Get assigned milestone.
|
||||||
if issue.MilestoneId > 0 {
|
if issue.MilestoneId > 0 {
|
||||||
ctx.Data["Milestone"], err = models.GetMilestoneById(issue.MilestoneId)
|
ctx.Data["Milestone"], err = models.GetMilestoneById(issue.MilestoneId)
|
||||||
|
@ -364,13 +388,13 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
|
func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
|
||||||
idx, err := base.StrTo(params["index"]).Int()
|
idx, _ := base.StrTo(params["index"]).Int64()
|
||||||
if err != nil {
|
if idx <= 0 {
|
||||||
ctx.Error(404)
|
ctx.Error(404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(idx))
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == models.ErrIssueNotExist {
|
if err == models.ErrIssueNotExist {
|
||||||
ctx.Handle(404, "issue.UpdateIssue", err)
|
ctx.Handle(404, "issue.UpdateIssue", err)
|
||||||
|
@ -381,14 +405,14 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
|
if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
|
||||||
ctx.Handle(404, "issue.UpdateIssue", nil)
|
ctx.Error(403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
issue.Name = form.IssueName
|
issue.Name = form.IssueName
|
||||||
issue.MilestoneId = form.MilestoneId
|
issue.MilestoneId = form.MilestoneId
|
||||||
issue.AssigneeId = form.AssigneeId
|
issue.AssigneeId = form.AssigneeId
|
||||||
issue.Labels = form.Labels
|
issue.LabelIds = form.Labels
|
||||||
issue.Content = form.Content
|
issue.Content = form.Content
|
||||||
// try get content from text, ignore conflict with preview ajax
|
// try get content from text, ignore conflict with preview ajax
|
||||||
if form.Content == "" {
|
if form.Content == "" {
|
||||||
|
@ -406,6 +430,55 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateIssueLabel(ctx *middleware.Context, params martini.Params) {
|
||||||
|
if !ctx.Repo.IsOwner {
|
||||||
|
ctx.Error(403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
idx, _ := base.StrTo(params["index"]).Int64()
|
||||||
|
if idx <= 0 {
|
||||||
|
ctx.Error(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
|
||||||
|
if err != nil {
|
||||||
|
if err == models.ErrIssueNotExist {
|
||||||
|
ctx.Handle(404, "issue.UpdateIssueLabel", err)
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, "issue.UpdateIssueLabel(GetIssueByIndex)", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isAttach := ctx.Query("action") == "attach"
|
||||||
|
labelStrId := ctx.Query("id")
|
||||||
|
isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|")
|
||||||
|
isNeedUpdate := false
|
||||||
|
if isAttach {
|
||||||
|
if !isHad {
|
||||||
|
issue.LabelIds += "$" + labelStrId + "|"
|
||||||
|
isNeedUpdate = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if isHad {
|
||||||
|
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1)
|
||||||
|
isNeedUpdate = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isNeedUpdate {
|
||||||
|
if err = models.UpdateIssue(issue); err != nil {
|
||||||
|
ctx.Handle(500, "issue.UpdateIssueLabel(UpdateIssue)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"ok": true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateIssueMilestone(ctx *middleware.Context) {
|
func UpdateIssueMilestone(ctx *middleware.Context) {
|
||||||
if !ctx.Repo.IsOwner {
|
if !ctx.Repo.IsOwner {
|
||||||
ctx.Error(403)
|
ctx.Error(403)
|
||||||
|
@ -622,8 +695,37 @@ func NewLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/issues")
|
ctx.Redirect(ctx.Repo.RepoLink + "/issues")
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateLabel(ctx *middleware.Context, params martini.Params) {
|
func UpdateLabel(ctx *middleware.Context, params martini.Params, form auth.CreateLabelForm) {
|
||||||
|
id, _ := base.StrTo(ctx.Query("id")).Int64()
|
||||||
|
if id == 0 {
|
||||||
|
ctx.Error(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := &models.Label{
|
||||||
|
Id: id,
|
||||||
|
Name: form.Title,
|
||||||
|
Color: form.Color,
|
||||||
|
}
|
||||||
|
if err := models.UpdateLabel(l); err != nil {
|
||||||
|
ctx.Handle(500, "issue.UpdateLabel(UpdateLabel)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/issues")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteLabel(ctx *middleware.Context) {
|
||||||
|
strIds := strings.Split(ctx.Query("remove"), ",")
|
||||||
|
for _, strId := range strIds {
|
||||||
|
if err := models.DeleteLabel(ctx.Repo.Repository.Id, strId); err != nil {
|
||||||
|
ctx.Handle(500, "issue.DeleteLabel(DeleteLabel)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"ok": true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Milestones(ctx *middleware.Context) {
|
func Milestones(ctx *middleware.Context) {
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
{{template "base/head" .}}
|
|
||||||
{{template "base/navbar" .}}
|
|
||||||
<div id="body-nav">
|
|
||||||
<div class="container">
|
|
||||||
<h3>Help</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body" class="container" data-page="user">
|
|
||||||
{{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
|
|
||||||
</div>
|
|
||||||
{{template "base/footer" .}}
|
|
|
@ -15,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="label-filter">
|
<div class="label-filter">
|
||||||
<h4>Label</h4>
|
<h4>Label</h4>
|
||||||
<ul class="list-unstyled" id="label-list" data-ajax="/{url}">
|
<ul class="list-unstyled" id="label-list" data-ajax="{{$.RepoLink}}/issues/labels/delete">
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
<li class="label-item" id="label-{{.Id}}" data-id="{{.Id}}"><a href="#">
|
<li class="label-item" id="label-{{.Id}}" data-id="{{.Id}}"><a href="#">
|
||||||
<span class="pull-right count">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</span>
|
<span class="pull-right count">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</span>
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}">{{..IssueStats.OpenCount}} Open</a>
|
<a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}">{{.IssueStats.OpenCount}} Open</a>
|
||||||
<a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}&state=closed">{{.IssueStats.ClosedCount}} Closed</a>
|
<a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}&state=closed">{{.IssueStats.ClosedCount}} Closed</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -118,7 +118,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="issue-bar col-md-2">
|
<div class="issue-bar col-md-2">
|
||||||
<div class="labels" data-ajax="{url}">
|
<div class="labels" data-ajax="{{.Issue.Index}}/label">
|
||||||
<div class="pull-right action">
|
<div class="pull-right action">
|
||||||
<button class="btn btn-default btn-sm" data-toggle="dropdown">
|
<button class="btn btn-default btn-sm" data-toggle="dropdown">
|
||||||
<i class="fa fa-tags"></i>
|
<i class="fa fa-tags"></i>
|
||||||
|
@ -126,26 +126,24 @@
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu dropdown-menu-right no">
|
<div class="dropdown-menu dropdown-menu-right no">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li class="checked" data-id="1">
|
{{range .Labels}}
|
||||||
<span class="check pull-left"><i class="fa fa-check"></i></span>
|
<li class="{{if not .IsChecked}}no-{{end}}checked" data-id="{{.Id}}">
|
||||||
<span class="color" style="background-color: #f59e00"></span>
|
{{if .IsChecked}}<span class="check pull-left"><i class="fa fa-check"></i></span>{{end}}
|
||||||
<span class="name">bug</span>
|
<span class="color" style="background-color: {{.Color}}"></span>
|
||||||
</li>
|
<span class="name">{{.Name}}</span>
|
||||||
<li class="no-checked" data-id="2">
|
|
||||||
<span class="color" style="background-color: #f59e00"></span>
|
|
||||||
<span class="name">bug</span>
|
|
||||||
</li>
|
|
||||||
<li class="no-checked" data-id="3">
|
|
||||||
<span class="color" style="background-color: #f59e00"></span>
|
|
||||||
<span class="name">bug</span>
|
|
||||||
</li>
|
</li>
|
||||||
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h4>Labels</h4>
|
<h4>Labels</h4>
|
||||||
<p id="label-1" class="label-item label-white" style="background-color: #e75316"><strong>bug</strong></p>
|
{{if .Issue.Labels}}
|
||||||
<p id="label-2" class="label-item label-white" style="background-color: #e8f0ff"><strong>bug</strong></p>
|
{{range .Issue.Labels}}
|
||||||
<p>Not yet</p>
|
<p id="label-{{.Id}}" class="label-item label-white" style="background-color: {{.Color}}"><strong>{{.Name}}</strong></p>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
<p>None yet</p>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="milestone" data-milestone="{{.Milestone.Id}}" data-ajax="{{.Issue.Index}}/milestone">
|
<div class="milestone" data-milestone="{{.Milestone.Id}}" data-ajax="{{.Issue.Index}}/milestone">
|
||||||
<div class="pull-right action">
|
<div class="pull-right action">
|
||||||
|
@ -223,10 +221,7 @@
|
||||||
<h4>Assignee</h4>
|
<h4>Assignee</h4>
|
||||||
<p>{{if .Issue.Assignee}}<img src="{{.Issue.Assignee.AvatarLink}}"><strong>{{.Issue.Assignee.Name}}</strong>{{else}}No one assigned{{end}}</p>
|
<p>{{if .Issue.Assignee}}<img src="{{.Issue.Assignee.AvatarLink}}"><strong>{{.Issue.Assignee.Name}}</strong>{{else}}No one assigned{{end}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div><!--
|
</div>
|
||||||
<div class="col-md-3">
|
|
||||||
label dashboard
|
|
||||||
</div>-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue