mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-06 00:01:01 -04:00
Compare commits
2 Commits
8fb1e53ca2
...
2779d47ad3
Author | SHA1 | Date | |
---|---|---|---|
|
2779d47ad3 | ||
|
3c59d31bc6 |
@ -875,6 +875,8 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
|
|||||||
return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err)
|
return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
comment.Attachments = attachments
|
||||||
case CommentTypeReopen, CommentTypeClose:
|
case CommentTypeReopen, CommentTypeClose:
|
||||||
if err = repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.Issue.IsPull, true); err != nil {
|
if err = repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.Issue.IsPull, true); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,19 +30,19 @@ func DeleteOrphanedAttachments(x *xorm.Engine) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
attachements := make([]Attachment, 0, limit)
|
attachments := make([]Attachment, 0, limit)
|
||||||
if err := sess.Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").
|
if err := sess.Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").
|
||||||
Cols("id, uuid").Limit(limit).
|
Cols("id, uuid").Limit(limit).
|
||||||
Asc("id").
|
Asc("id").
|
||||||
Find(&attachements); err != nil {
|
Find(&attachments); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(attachements) == 0 {
|
if len(attachments) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ids := make([]int64, 0, limit)
|
ids := make([]int64, 0, limit)
|
||||||
for _, attachment := range attachements {
|
for _, attachment := range attachments {
|
||||||
ids = append(ids, attachment.ID)
|
ids = append(ids, attachment.ID)
|
||||||
}
|
}
|
||||||
if len(ids) > 0 {
|
if len(ids) > 0 {
|
||||||
@ -51,13 +51,13 @@ func DeleteOrphanedAttachments(x *xorm.Engine) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, attachment := range attachements {
|
for _, attachment := range attachments {
|
||||||
uuid := attachment.UUID
|
uuid := attachment.UUID
|
||||||
if err := util.RemoveAll(filepath.Join(setting.Attachment.Path, uuid[0:1], uuid[1:2], uuid)); err != nil {
|
if err := util.RemoveAll(filepath.Join(setting.Attachment.Path, uuid[0:1], uuid[1:2], uuid)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(attachements) < limit {
|
if len(attachments) < limit {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
modules/convert/attachment.go
Normal file
30
modules/convert/attachment.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToAttachment converts models.Attachment to api.Attachment
|
||||||
|
func ToAttachment(a *repo_model.Attachment) *api.Attachment {
|
||||||
|
return &api.Attachment{
|
||||||
|
ID: a.ID,
|
||||||
|
Name: a.Name,
|
||||||
|
Created: a.CreatedUnix.AsTime(),
|
||||||
|
DownloadCount: a.DownloadCount,
|
||||||
|
Size: a.Size,
|
||||||
|
UUID: a.UUID,
|
||||||
|
DownloadURL: a.DownloadURL(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToAttachments(attachments []*repo_model.Attachment) []*api.Attachment {
|
||||||
|
converted := make([]*api.Attachment, 0, len(attachments))
|
||||||
|
for _, attachment := range attachments {
|
||||||
|
converted = append(converted, ToAttachment(attachment))
|
||||||
|
}
|
||||||
|
return converted
|
||||||
|
}
|
@ -37,20 +37,21 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apiIssue := &api.Issue{
|
apiIssue := &api.Issue{
|
||||||
ID: issue.ID,
|
ID: issue.ID,
|
||||||
URL: issue.APIURL(),
|
URL: issue.APIURL(),
|
||||||
HTMLURL: issue.HTMLURL(),
|
HTMLURL: issue.HTMLURL(),
|
||||||
Index: issue.Index,
|
Index: issue.Index,
|
||||||
Poster: ToUser(issue.Poster, nil),
|
Poster: ToUser(issue.Poster, nil),
|
||||||
Title: issue.Title,
|
Title: issue.Title,
|
||||||
Body: issue.Content,
|
Body: issue.Content,
|
||||||
Ref: issue.Ref,
|
Attachments: ToAttachments(issue.Attachments),
|
||||||
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
|
Ref: issue.Ref,
|
||||||
State: issue.State(),
|
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
|
||||||
IsLocked: issue.IsLocked,
|
State: issue.State(),
|
||||||
Comments: issue.NumComments,
|
IsLocked: issue.IsLocked,
|
||||||
Created: issue.CreatedUnix.AsTime(),
|
Comments: issue.NumComments,
|
||||||
Updated: issue.UpdatedUnix.AsTime(),
|
Created: issue.CreatedUnix.AsTime(),
|
||||||
|
Updated: issue.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
apiIssue.Repo = &api.RepositoryMeta{
|
apiIssue.Repo = &api.RepositoryMeta{
|
||||||
|
@ -16,14 +16,15 @@ import (
|
|||||||
// ToComment converts a issues_model.Comment to the api.Comment format
|
// ToComment converts a issues_model.Comment to the api.Comment format
|
||||||
func ToComment(c *issues_model.Comment) *api.Comment {
|
func ToComment(c *issues_model.Comment) *api.Comment {
|
||||||
return &api.Comment{
|
return &api.Comment{
|
||||||
ID: c.ID,
|
ID: c.ID,
|
||||||
Poster: ToUser(c.Poster, nil),
|
Poster: ToUser(c.Poster, nil),
|
||||||
HTMLURL: c.HTMLURL(),
|
HTMLURL: c.HTMLURL(),
|
||||||
IssueURL: c.IssueURL(),
|
IssueURL: c.IssueURL(),
|
||||||
PRURL: c.PRURL(),
|
PRURL: c.PRURL(),
|
||||||
Body: c.Content,
|
Body: c.Content,
|
||||||
Created: c.CreatedUnix.AsTime(),
|
Attachments: ToAttachments(c.Attachments),
|
||||||
Updated: c.UpdatedUnix.AsTime(),
|
Created: c.CreatedUnix.AsTime(),
|
||||||
|
Updated: c.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,6 @@ import (
|
|||||||
|
|
||||||
// ToRelease convert a repo_model.Release to api.Release
|
// ToRelease convert a repo_model.Release to api.Release
|
||||||
func ToRelease(r *repo_model.Release) *api.Release {
|
func ToRelease(r *repo_model.Release) *api.Release {
|
||||||
assets := make([]*api.Attachment, 0)
|
|
||||||
for _, att := range r.Attachments {
|
|
||||||
assets = append(assets, ToReleaseAttachment(att))
|
|
||||||
}
|
|
||||||
return &api.Release{
|
return &api.Release{
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
TagName: r.TagName,
|
TagName: r.TagName,
|
||||||
@ -29,19 +25,6 @@ func ToRelease(r *repo_model.Release) *api.Release {
|
|||||||
CreatedAt: r.CreatedUnix.AsTime(),
|
CreatedAt: r.CreatedUnix.AsTime(),
|
||||||
PublishedAt: r.CreatedUnix.AsTime(),
|
PublishedAt: r.CreatedUnix.AsTime(),
|
||||||
Publisher: ToUser(r.Publisher, nil),
|
Publisher: ToUser(r.Publisher, nil),
|
||||||
Attachments: assets,
|
Attachments: ToAttachments(r.Attachments),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToReleaseAttachment converts models.Attachment to api.Attachment
|
|
||||||
func ToReleaseAttachment(a *repo_model.Attachment) *api.Attachment {
|
|
||||||
return &api.Attachment{
|
|
||||||
ID: a.ID,
|
|
||||||
Name: a.Name,
|
|
||||||
Created: a.CreatedUnix.AsTime(),
|
|
||||||
DownloadCount: a.DownloadCount,
|
|
||||||
Size: a.Size,
|
|
||||||
UUID: a.UUID,
|
|
||||||
DownloadURL: a.DownloadURL(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,6 +314,11 @@ func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
||||||
|
if err := issue.LoadRepo(ctx); err != nil {
|
||||||
|
log.Error("LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||||
var err error
|
var err error
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
|
@ -41,18 +41,19 @@ type RepositoryMeta struct {
|
|||||||
// Issue represents an issue in a repository
|
// Issue represents an issue in a repository
|
||||||
// swagger:model
|
// swagger:model
|
||||||
type Issue struct {
|
type Issue struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
HTMLURL string `json:"html_url"`
|
HTMLURL string `json:"html_url"`
|
||||||
Index int64 `json:"number"`
|
Index int64 `json:"number"`
|
||||||
Poster *User `json:"user"`
|
Poster *User `json:"user"`
|
||||||
OriginalAuthor string `json:"original_author"`
|
OriginalAuthor string `json:"original_author"`
|
||||||
OriginalAuthorID int64 `json:"original_author_id"`
|
OriginalAuthorID int64 `json:"original_author_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
Labels []*Label `json:"labels"`
|
Attachments []*Attachment `json:"assets"`
|
||||||
Milestone *Milestone `json:"milestone"`
|
Labels []*Label `json:"labels"`
|
||||||
|
Milestone *Milestone `json:"milestone"`
|
||||||
// deprecated
|
// deprecated
|
||||||
Assignee *User `json:"assignee"`
|
Assignee *User `json:"assignee"`
|
||||||
Assignees []*User `json:"assignees"`
|
Assignees []*User `json:"assignees"`
|
||||||
|
@ -9,14 +9,15 @@ import (
|
|||||||
|
|
||||||
// Comment represents a comment on a commit or issue
|
// Comment represents a comment on a commit or issue
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
HTMLURL string `json:"html_url"`
|
HTMLURL string `json:"html_url"`
|
||||||
PRURL string `json:"pull_request_url"`
|
PRURL string `json:"pull_request_url"`
|
||||||
IssueURL string `json:"issue_url"`
|
IssueURL string `json:"issue_url"`
|
||||||
Poster *User `json:"user"`
|
Poster *User `json:"user"`
|
||||||
OriginalAuthor string `json:"original_author"`
|
OriginalAuthor string `json:"original_author"`
|
||||||
OriginalAuthorID int64 `json:"original_author_id"`
|
OriginalAuthorID int64 `json:"original_author_id"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
|
Attachments []*Attachment `json:"assets"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Created time.Time `json:"created_at"`
|
Created time.Time `json:"created_at"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
|
@ -567,6 +567,13 @@ func mustNotBeArchived(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustEnableAttachments(ctx *context.APIContext) {
|
||||||
|
if !setting.Attachment.Enabled {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// bind binding an obj to a func(ctx *context.APIContext)
|
// bind binding an obj to a func(ctx *context.APIContext)
|
||||||
func bind(obj interface{}) http.HandlerFunc {
|
func bind(obj interface{}) http.HandlerFunc {
|
||||||
tp := reflect.TypeOf(obj)
|
tp := reflect.TypeOf(obj)
|
||||||
@ -892,6 +899,15 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||||||
Get(repo.GetIssueCommentReactions).
|
Get(repo.GetIssueCommentReactions).
|
||||||
Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueCommentReaction).
|
Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueCommentReaction).
|
||||||
Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueCommentReaction)
|
Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueCommentReaction)
|
||||||
|
m.Group("/assets", func() {
|
||||||
|
m.Combo("").
|
||||||
|
Get(repo.ListIssueCommentAttachments).
|
||||||
|
Post(reqToken(), mustNotBeArchived, repo.CreateIssueCommentAttachment)
|
||||||
|
m.Combo("/{asset}").
|
||||||
|
Get(repo.GetIssueCommentAttachment).
|
||||||
|
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
|
||||||
|
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueCommentAttachment)
|
||||||
|
}, mustEnableAttachments)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
m.Group("/{index}", func() {
|
m.Group("/{index}", func() {
|
||||||
@ -935,6 +951,15 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||||||
Get(repo.GetIssueReactions).
|
Get(repo.GetIssueReactions).
|
||||||
Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueReaction).
|
Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueReaction).
|
||||||
Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueReaction)
|
Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueReaction)
|
||||||
|
m.Group("/assets", func() {
|
||||||
|
m.Combo("").
|
||||||
|
Get(repo.ListIssueAttachments).
|
||||||
|
Post(reqToken(), mustNotBeArchived, repo.CreateIssueAttachment)
|
||||||
|
m.Combo("/{asset}").
|
||||||
|
Get(repo.GetIssueAttachment).
|
||||||
|
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
|
||||||
|
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueAttachment)
|
||||||
|
}, mustEnableAttachments)
|
||||||
})
|
})
|
||||||
}, mustEnableIssuesOrPulls)
|
}, mustEnableIssuesOrPulls)
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
|
372
routers/api/v1/repo/issue_attachment.go
Normal file
372
routers/api/v1/repo/issue_attachment.go
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/convert"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"code.gitea.io/gitea/services/attachment"
|
||||||
|
issue_service "code.gitea.io/gitea/services/issue"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetIssueAttachment gets a single attachment of the issue
|
||||||
|
func GetIssueAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueGetIssueAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Get an issue attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: index
|
||||||
|
// in: path
|
||||||
|
// description: index of the issue
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: attachment_id
|
||||||
|
// in: path
|
||||||
|
// description: id of the attachment to get
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/Attachment"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
issue := getIssueFromContext(ctx)
|
||||||
|
if issue == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attach := getIssueAttachmentSafeRead(ctx, issue)
|
||||||
|
if attach == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, convert.ToAttachment(attach))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIssueAttachments lists all attachments of the issue
|
||||||
|
func ListIssueAttachments(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/assets issue issueListIssueAttachments
|
||||||
|
// ---
|
||||||
|
// summary: List issue's attachments
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: index
|
||||||
|
// in: path
|
||||||
|
// description: index of the issue
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/AttachmentList"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
issue := getIssueFromContext(ctx)
|
||||||
|
if issue == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := issue.LoadAttributes(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueAttachment creates an attachment and saves the given file
|
||||||
|
func CreateIssueAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/assets issue issueCreateIssueAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Create an issue attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// consumes:
|
||||||
|
// - multipart/form-data
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: index
|
||||||
|
// in: path
|
||||||
|
// description: index of the issue
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: name
|
||||||
|
// in: query
|
||||||
|
// description: name of the attachment
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
|
// - name: attachment
|
||||||
|
// in: formData
|
||||||
|
// description: attachment to upload
|
||||||
|
// type: file
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "201":
|
||||||
|
// "$ref": "#/responses/Attachment"
|
||||||
|
// "400":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
issue := getIssueFromContext(ctx)
|
||||||
|
if issue == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !canUserWriteIssueAttachment(ctx, issue) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get uploaded file from request
|
||||||
|
file, header, err := ctx.Req.FormFile("attachment")
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "FormFile", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
filename := header.Filename
|
||||||
|
if query := ctx.FormString("name"); query != "" {
|
||||||
|
filename = query
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
|
||||||
|
Name: filename,
|
||||||
|
UploaderID: ctx.Doer.ID,
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
IssueID: issue.ID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
issue.Attachments = append(issue.Attachments, attachment)
|
||||||
|
|
||||||
|
if err := issue_service.ChangeContent(issue, ctx.Doer, issue.Content); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "ChangeContent", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditIssueAttachment updates the given attachment
|
||||||
|
func EditIssueAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation PATCH /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueEditIssueAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Edit an issue attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// consumes:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: index
|
||||||
|
// in: path
|
||||||
|
// description: index of the issue
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: attachment_id
|
||||||
|
// in: path
|
||||||
|
// description: id of the attachment to edit
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/EditAttachmentOptions"
|
||||||
|
// responses:
|
||||||
|
// "201":
|
||||||
|
// "$ref": "#/responses/Attachment"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
attachment := getIssueAttachmentSafeWrite(ctx)
|
||||||
|
if attachment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// do changes to attachment. only meaningful change is name.
|
||||||
|
form := web.GetForm(ctx).(*api.EditAttachmentOptions)
|
||||||
|
if form.Name != "" {
|
||||||
|
attachment.Name = form.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo_model.UpdateAttachment(ctx, attachment); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssueAttachment delete a given attachment
|
||||||
|
func DeleteIssueAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueDeleteIssueAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Delete an issue attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: index
|
||||||
|
// in: path
|
||||||
|
// description: index of the issue
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: attachment_id
|
||||||
|
// in: path
|
||||||
|
// description: id of the attachment to delete
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
attachment := getIssueAttachmentSafeWrite(ctx)
|
||||||
|
if attachment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo_model.DeleteAttachment(attachment, true); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueFromContext(ctx *context.APIContext) *issues_model.Issue {
|
||||||
|
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64("index"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.NotFoundOrServerError("GetIssueByIndex", issues_model.IsErrIssueNotExist, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
issue.Repo = ctx.Repo.Repository
|
||||||
|
|
||||||
|
return issue
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment {
|
||||||
|
issue := getIssueFromContext(ctx)
|
||||||
|
if issue == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !canUserWriteIssueAttachment(ctx, issue) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return getIssueAttachmentSafeRead(ctx, issue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueAttachmentSafeRead(ctx *context.APIContext, issue *issues_model.Issue) *repo_model.Attachment {
|
||||||
|
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !attachmentBelongsToRepoOrIssue(ctx, attachment, issue) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
func canUserWriteIssueAttachment(ctx *context.APIContext, issue *issues_model.Issue) bool {
|
||||||
|
canEditIssue := ctx.IsSigned && (ctx.Doer.ID == issue.PosterID || ctx.IsUserRepoAdmin() || ctx.IsUserSiteAdmin()) && ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
||||||
|
if !canEditIssue {
|
||||||
|
ctx.Error(http.StatusForbidden, "", "user should have permission to write issue")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func attachmentBelongsToRepoOrIssue(ctx *context.APIContext, attachment *repo_model.Attachment, issue *issues_model.Issue) bool {
|
||||||
|
if attachment.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
log.Debug("Requested attachment[%d] does not belong to repo[%-v].", attachment.ID, ctx.Repo.Repository)
|
||||||
|
ctx.NotFound("no such attachment in repo")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if attachment.IssueID == 0 {
|
||||||
|
log.Debug("Requested attachment[%d] is not in an issue.", attachment.ID)
|
||||||
|
ctx.NotFound("no such attachment in issue")
|
||||||
|
return false
|
||||||
|
} else if issue != nil && attachment.IssueID != issue.ID {
|
||||||
|
log.Debug("Requested attachment[%d] does not belong to issue[%d, #%d].", attachment.ID, issue.ID, issue.Index)
|
||||||
|
ctx.NotFound("no such attachment in issue")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -95,6 +95,11 @@ func ListIssueComments(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := issues_model.CommentList(comments).LoadAttachments(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
apiComments := make([]*api.Comment, len(comments))
|
apiComments := make([]*api.Comment, len(comments))
|
||||||
for i, comment := range comments {
|
for i, comment := range comments {
|
||||||
comment.Issue = issue
|
comment.Issue = issue
|
||||||
@ -294,6 +299,10 @@ func ListRepoIssueComments(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadPosters", err)
|
ctx.Error(http.StatusInternalServerError, "LoadPosters", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err := issues_model.CommentList(comments).LoadAttachments(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
if _, err := issues_model.CommentList(comments).Issues().LoadRepositories(ctx); err != nil {
|
if _, err := issues_model.CommentList(comments).Issues().LoadRepositories(ctx); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "LoadRepositories", err)
|
ctx.Error(http.StatusInternalServerError, "LoadRepositories", err)
|
||||||
return
|
return
|
||||||
|
383
routers/api/v1/repo/issue_comment_attachment.go
Normal file
383
routers/api/v1/repo/issue_comment_attachment.go
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/convert"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"code.gitea.io/gitea/services/attachment"
|
||||||
|
comment_service "code.gitea.io/gitea/services/comments"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetIssueCommentAttachment gets a single attachment of the comment
|
||||||
|
func GetIssueCommentAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueGetIssueCommentAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Get a comment attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: id
|
||||||
|
// in: path
|
||||||
|
// description: id of the comment
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: attachment_id
|
||||||
|
// in: path
|
||||||
|
// description: id of the attachment to get
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/Attachment"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
comment := getIssueCommentSafe(ctx)
|
||||||
|
if comment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
attachment := getIssueCommentAttachmentSafeRead(ctx, comment)
|
||||||
|
if attachment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if attachment.CommentID != comment.ID {
|
||||||
|
log.Debug("User requested attachment[%d] is not in comment[%d].", attachment.ID, comment.ID)
|
||||||
|
ctx.NotFound("attachment not in comment")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, convert.ToAttachment(attachment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIssueCommentAttachments lists all attachments of the comment
|
||||||
|
func ListIssueCommentAttachments(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/assets issue issueListIssueCommentAttachments
|
||||||
|
// ---
|
||||||
|
// summary: List comment's attachments
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: id
|
||||||
|
// in: path
|
||||||
|
// description: id of the comment
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/AttachmentList"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
comment := getIssueCommentSafe(ctx)
|
||||||
|
if comment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := comment.LoadAttachments(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, convert.ToAttachments(comment.Attachments))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIssueCommentAttachment creates an attachment and saves the given file
|
||||||
|
func CreateIssueCommentAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation POST /repos/{owner}/{repo}/issues/comments/{id}/assets issue issueCreateIssueCommentAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Create a comment attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// consumes:
|
||||||
|
// - multipart/form-data
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: id
|
||||||
|
// in: path
|
||||||
|
// description: id of the comment
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: name
|
||||||
|
// in: query
|
||||||
|
// description: name of the attachment
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
|
// - name: attachment
|
||||||
|
// in: formData
|
||||||
|
// description: attachment to upload
|
||||||
|
// type: file
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "201":
|
||||||
|
// "$ref": "#/responses/Attachment"
|
||||||
|
// "400":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
// Check if comment exists and load comment
|
||||||
|
comment := getIssueCommentSafe(ctx)
|
||||||
|
if comment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !canUserWriteIssueCommentAttachment(ctx, comment) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get uploaded file from request
|
||||||
|
file, header, err := ctx.Req.FormFile("attachment")
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "FormFile", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
filename := header.Filename
|
||||||
|
if query := ctx.FormString("name"); query != "" {
|
||||||
|
filename = query
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
|
||||||
|
Name: filename,
|
||||||
|
UploaderID: ctx.Doer.ID,
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
IssueID: comment.IssueID,
|
||||||
|
CommentID: comment.ID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := comment.LoadAttachments(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, comment.Content); err != nil {
|
||||||
|
ctx.ServerError("UpdateComment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditIssueCommentAttachment updates the given attachment
|
||||||
|
func EditIssueCommentAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation PATCH /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueEditIssueCommentAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Edit a comment attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// consumes:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: id
|
||||||
|
// in: path
|
||||||
|
// description: id of the comment
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: attachment_id
|
||||||
|
// in: path
|
||||||
|
// description: id of the attachment to edit
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/EditAttachmentOptions"
|
||||||
|
// responses:
|
||||||
|
// "201":
|
||||||
|
// "$ref": "#/responses/Attachment"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
attach := getIssueCommentAttachmentSafeWrite(ctx)
|
||||||
|
if attach == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
form := web.GetForm(ctx).(*api.EditAttachmentOptions)
|
||||||
|
if form.Name != "" {
|
||||||
|
attach.Name = form.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo_model.UpdateAttachment(ctx, attach); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIssueCommentAttachment delete a given attachment
|
||||||
|
func DeleteIssueCommentAttachment(ctx *context.APIContext) {
|
||||||
|
// swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueDeleteIssueCommentAttachment
|
||||||
|
// ---
|
||||||
|
// summary: Delete a comment attachment
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: id
|
||||||
|
// in: path
|
||||||
|
// description: id of the comment
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: attachment_id
|
||||||
|
// in: path
|
||||||
|
// description: id of the attachment to delete
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
|
||||||
|
attach := getIssueCommentAttachmentSafeWrite(ctx)
|
||||||
|
if attach == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo_model.DeleteAttachment(attach, true); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueCommentSafe(ctx *context.APIContext) *issues_model.Comment {
|
||||||
|
comment, err := issues_model.GetCommentByID(ctx, ctx.ParamsInt64("id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := comment.LoadIssue(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if comment.Issue == nil || comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.Error(http.StatusNotFound, "", "no matching issue comment found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
comment.Issue.Repo = ctx.Repo.Repository
|
||||||
|
|
||||||
|
return comment
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueCommentAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment {
|
||||||
|
comment := getIssueCommentSafe(ctx)
|
||||||
|
if comment == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !canUserWriteIssueCommentAttachment(ctx, comment) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return getIssueCommentAttachmentSafeRead(ctx, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canUserWriteIssueCommentAttachment(ctx *context.APIContext, comment *issues_model.Comment) bool {
|
||||||
|
canEditComment := ctx.IsSigned && (ctx.Doer.ID == comment.PosterID || ctx.IsUserRepoAdmin() || ctx.IsUserSiteAdmin()) && ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)
|
||||||
|
if !canEditComment {
|
||||||
|
ctx.Error(http.StatusForbidden, "", "user should have permission to edit comment")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueCommentAttachmentSafeRead(ctx *context.APIContext, comment *issues_model.Comment) *repo_model.Attachment {
|
||||||
|
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !attachmentBelongsToRepoOrComment(ctx, attachment, comment) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
func attachmentBelongsToRepoOrComment(ctx *context.APIContext, attachment *repo_model.Attachment, comment *issues_model.Comment) bool {
|
||||||
|
if attachment.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
log.Debug("Requested attachment[%d] does not belong to repo[%-v].", attachment.ID, ctx.Repo.Repository)
|
||||||
|
ctx.NotFound("no such attachment in repo")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if attachment.IssueID == 0 || attachment.CommentID == 0 {
|
||||||
|
log.Debug("Requested attachment[%d] is not in a comment.", attachment.ID)
|
||||||
|
ctx.NotFound("no such attachment in comment")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if comment != nil && attachment.CommentID != comment.ID {
|
||||||
|
log.Debug("Requested attachment[%d] does not belong to comment[%d].", attachment.ID, comment.ID)
|
||||||
|
ctx.NotFound("no such attachment in comment")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -68,7 +68,7 @@ func GetReleaseAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests
|
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests
|
||||||
ctx.JSON(http.StatusOK, convert.ToReleaseAttachment(attach))
|
ctx.JSON(http.StatusOK, convert.ToAttachment(attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListReleaseAttachments lists all attachments of the release
|
// ListReleaseAttachments lists all attachments of the release
|
||||||
@ -194,7 +194,12 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new attachment and save the file
|
// Create a new attachment and save the file
|
||||||
attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, release.RepoID, releaseID, filename, setting.Repository.Release.AllowedTypes)
|
attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{
|
||||||
|
Name: filename,
|
||||||
|
UploaderID: ctx.Doer.ID,
|
||||||
|
RepoID: release.RepoID,
|
||||||
|
ReleaseID: releaseID,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if upload.IsErrFileTypeForbidden(err) {
|
if upload.IsErrFileTypeForbidden(err) {
|
||||||
ctx.Error(http.StatusBadRequest, "DetectContentType", err)
|
ctx.Error(http.StatusBadRequest, "DetectContentType", err)
|
||||||
@ -204,7 +209,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach))
|
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditReleaseAttachment updates the given attachment
|
// EditReleaseAttachment updates the given attachment
|
||||||
@ -274,7 +279,7 @@ func EditReleaseAttachment(ctx *context.APIContext) {
|
|||||||
if err := repo_model.UpdateAttachment(ctx, attach); err != nil {
|
if err := repo_model.UpdateAttachment(ctx, attach); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
|
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach))
|
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteReleaseAttachment delete a given attachment
|
// DeleteReleaseAttachment delete a given attachment
|
||||||
|
@ -44,7 +44,11 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, repoID, 0, header.Filename, allowedTypes)
|
attach, err := attachment.UploadAttachment(file, allowedTypes, &repo_model.Attachment{
|
||||||
|
Name: header.Filename,
|
||||||
|
UploaderID: ctx.Doer.ID,
|
||||||
|
RepoID: repoID,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if upload.IsErrFileTypeForbidden(err) {
|
if upload.IsErrFileTypeForbidden(err) {
|
||||||
ctx.Error(http.StatusBadRequest, err.Error())
|
ctx.Error(http.StatusBadRequest, err.Error())
|
||||||
@ -82,7 +86,7 @@ func DeleteAttachment(ctx *context.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAttachment serve attachements
|
// GetAttachment serve attachments
|
||||||
func GetAttachment(ctx *context.Context) {
|
func GetAttachment(ctx *context.Context) {
|
||||||
attach, err := repo_model.GetAttachmentByUUID(ctx, ctx.Params(":uuid"))
|
attach, err := repo_model.GetAttachmentByUUID(ctx, ctx.Params(":uuid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2749,6 +2749,7 @@ func UpdateCommentContent(ctx *context.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
|
if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
|
||||||
ctx.ServerError("UpdateComment", err)
|
ctx.ServerError("UpdateComment", err)
|
||||||
return
|
return
|
||||||
@ -3050,7 +3051,7 @@ func GetIssueAttachments(ctx *context.Context) {
|
|||||||
issue := GetActionIssue(ctx)
|
issue := GetActionIssue(ctx)
|
||||||
attachments := make([]*api.Attachment, len(issue.Attachments))
|
attachments := make([]*api.Attachment, len(issue.Attachments))
|
||||||
for i := 0; i < len(issue.Attachments); i++ {
|
for i := 0; i < len(issue.Attachments); i++ {
|
||||||
attachments[i] = convert.ToReleaseAttachment(issue.Attachments[i])
|
attachments[i] = convert.ToAttachment(issue.Attachments[i])
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, attachments)
|
ctx.JSON(http.StatusOK, attachments)
|
||||||
}
|
}
|
||||||
@ -3069,7 +3070,7 @@ func GetCommentAttachments(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := 0; i < len(comment.Attachments); i++ {
|
for i := 0; i < len(comment.Attachments); i++ {
|
||||||
attachments = append(attachments, convert.ToReleaseAttachment(comment.Attachments[i]))
|
attachments = append(attachments, convert.ToAttachment(comment.Attachments[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, attachments)
|
ctx.JSON(http.StatusOK, attachments)
|
||||||
|
@ -39,19 +39,14 @@ func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UploadAttachment upload new attachment into storage and update database
|
// UploadAttachment upload new attachment into storage and update database
|
||||||
func UploadAttachment(file io.Reader, actorID, repoID, releaseID int64, fileName, allowedTypes string) (*repo_model.Attachment, error) {
|
func UploadAttachment(file io.Reader, allowedTypes string, opts *repo_model.Attachment) (*repo_model.Attachment, error) {
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
n, _ := util.ReadAtMost(file, buf)
|
n, _ := util.ReadAtMost(file, buf)
|
||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
|
|
||||||
if err := upload.Verify(buf, fileName, allowedTypes); err != nil {
|
if err := upload.Verify(buf, opts.Name, allowedTypes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewAttachment(&repo_model.Attachment{
|
return NewAttachment(opts, io.MultiReader(bytes.NewReader(buf), file))
|
||||||
RepoID: repoID,
|
|
||||||
UploaderID: actorID,
|
|
||||||
ReleaseID: releaseID,
|
|
||||||
Name: fileName,
|
|
||||||
}, io.MultiReader(bytes.NewReader(buf), file))
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/repository"
|
"code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) {
|
func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) {
|
||||||
@ -218,7 +219,10 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
|
|||||||
}
|
}
|
||||||
for _, attach := range attachments {
|
for _, attach := range attachments {
|
||||||
if attach.ReleaseID != rel.ID {
|
if attach.ReleaseID != rel.ID {
|
||||||
return errors.New("delete attachement of release permission denied")
|
return util.SilentWrap{
|
||||||
|
Message: "delete attachment of release permission denied",
|
||||||
|
Err: util.ErrPermissionDenied,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
deletedUUIDs.Add(attach.UUID)
|
deletedUUIDs.Add(attach.UUID)
|
||||||
}
|
}
|
||||||
@ -240,7 +244,10 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
|
|||||||
}
|
}
|
||||||
for _, attach := range attachments {
|
for _, attach := range attachments {
|
||||||
if attach.ReleaseID != rel.ID {
|
if attach.ReleaseID != rel.ID {
|
||||||
return errors.New("update attachement of release permission denied")
|
return util.SilentWrap{
|
||||||
|
Message: "update attachment of release permission denied",
|
||||||
|
Err: util.ErrPermissionDenied,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "email") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=email&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.email"}}</a>
|
<a class="{{if or (eq .SortType "email") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=email&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.email"}}</a>
|
||||||
<a class="{{if eq .SortType "reverseemail"}}active{{end}} item" href="{{$.Link}}?sort=reverseemail&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.email_reverse"}}</a>
|
<a class="{{if eq .SortType "reverseemail"}}active {{end}}item" href="{{$.Link}}?sort=reverseemail&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.email_reverse"}}</a>
|
||||||
<a class="{{if eq .SortType "username"}}active{{end}} item" href="{{$.Link}}?sort=username&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.name"}}</a>
|
<a class="{{if eq .SortType "username"}}active {{end}}item" href="{{$.Link}}?sort=username&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.name"}}</a>
|
||||||
<a class="{{if eq .SortType "reverseusername"}}active{{end}} item" href="{{$.Link}}?sort=reverseusername&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.name_reverse"}}</a>
|
<a class="{{if eq .SortType "reverseusername"}}active {{end}}item" href="{{$.Link}}?sort=reverseusername&q={{$.Keyword}}">{{.locale.Tr "admin.emails.filter_sort.name_reverse"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,45 +1,45 @@
|
|||||||
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar">
|
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar">
|
||||||
<div class="new-menu-inner">
|
<div class="new-menu-inner">
|
||||||
<a class="{{if .PageIsAdminDashboard}}active{{end}} item" href="{{AppSubUrl}}/admin">
|
<a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/admin">
|
||||||
{{.locale.Tr "admin.dashboard"}}
|
{{.locale.Tr "admin.dashboard"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminUsers}}active{{end}} item" href="{{AppSubUrl}}/admin/users">
|
<a class="{{if .PageIsAdminUsers}}active {{end}}item" href="{{AppSubUrl}}/admin/users">
|
||||||
{{.locale.Tr "admin.users"}}
|
{{.locale.Tr "admin.users"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminOrganizations}}active{{end}} item" href="{{AppSubUrl}}/admin/orgs">
|
<a class="{{if .PageIsAdminOrganizations}}active {{end}}item" href="{{AppSubUrl}}/admin/orgs">
|
||||||
{{.locale.Tr "admin.organizations"}}
|
{{.locale.Tr "admin.organizations"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminRepositories}}active{{end}} item" href="{{AppSubUrl}}/admin/repos">
|
<a class="{{if .PageIsAdminRepositories}}active {{end}}item" href="{{AppSubUrl}}/admin/repos">
|
||||||
{{.locale.Tr "admin.repositories"}}
|
{{.locale.Tr "admin.repositories"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .EnablePackages}}
|
{{if .EnablePackages}}
|
||||||
<a class="{{if .PageIsAdminPackages}}active{{end}} item" href="{{AppSubUrl}}/admin/packages">
|
<a class="{{if .PageIsAdminPackages}}active {{end}}item" href="{{AppSubUrl}}/admin/packages">
|
||||||
{{.locale.Tr "packages.title"}}
|
{{.locale.Tr "packages.title"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not DisableWebhooks}}
|
{{if not DisableWebhooks}}
|
||||||
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks">
|
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/admin/hooks">
|
||||||
{{.locale.Tr "admin.hooks"}}
|
{{.locale.Tr "admin.hooks"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsAdminAuthentications}}active{{end}} item" href="{{AppSubUrl}}/admin/auths">
|
<a class="{{if .PageIsAdminAuthentications}}active {{end}}item" href="{{AppSubUrl}}/admin/auths">
|
||||||
{{.locale.Tr "admin.authentication"}}
|
{{.locale.Tr "admin.authentication"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminEmails}}active{{end}} item" href="{{AppSubUrl}}/admin/emails">
|
<a class="{{if .PageIsAdminEmails}}active {{end}}item" href="{{AppSubUrl}}/admin/emails">
|
||||||
{{.locale.Tr "admin.emails"}}
|
{{.locale.Tr "admin.emails"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .EnableOAuth2}}
|
{{if .EnableOAuth2}}
|
||||||
<a class="{{if .PageIsAdminApplications}}active{{end}} item" href="{{AppSubUrl}}/admin/applications">
|
<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/admin/applications">
|
||||||
{{.locale.Tr "settings.applications"}}
|
{{.locale.Tr "settings.applications"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsAdminConfig}}active{{end}} item" href="{{AppSubUrl}}/admin/config">
|
<a class="{{if .PageIsAdminConfig}}active {{end}}item" href="{{AppSubUrl}}/admin/config">
|
||||||
{{.locale.Tr "admin.config"}}
|
{{.locale.Tr "admin.config"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminNotices}}active{{end}} item" href="{{AppSubUrl}}/admin/notices">
|
<a class="{{if .PageIsAdminNotices}}active {{end}}item" href="{{AppSubUrl}}/admin/notices">
|
||||||
{{.locale.Tr "admin.notices"}}
|
{{.locale.Tr "admin.notices"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsAdminMonitor}}active{{end}} item" href="{{AppSubUrl}}/admin/monitor">
|
<a class="{{if .PageIsAdminMonitor}}active {{end}}item" href="{{AppSubUrl}}/admin/monitor">
|
||||||
{{.locale.Tr "admin.monitor"}}
|
{{.locale.Tr "admin.monitor"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,18 +6,18 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.moststars"}}</a>
|
<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.moststars"}}</a>
|
||||||
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
|
<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
|
||||||
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
|
<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
|
||||||
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
|
<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
|
||||||
<a class="{{if eq .SortType "size"}}active{{end}} item" href="{{$.Link}}?sort=size&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.by_size"}}</a>
|
<a class="{{if eq .SortType "size"}}active {{end}}item" href="{{$.Link}}?sort=size&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.by_size"}}</a>
|
||||||
<a class="{{if eq .SortType "reversesize"}}active{{end}} item" href="{{$.Link}}?sort=reversesize&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_by_size"}}</a>
|
<a class="{{if eq .SortType "reversesize"}}active {{end}}item" href="{{$.Link}}?sort=reversesize&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_by_size"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -175,7 +175,7 @@
|
|||||||
{{svg "octicon-bell"}}
|
{{svg "octicon-bell"}}
|
||||||
{{.locale.Tr "notification.subscriptions"}}<!-- Subscriptions -->
|
{{.locale.Tr "notification.subscriptions"}}<!-- Subscriptions -->
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings">
|
<a class="{{if .PageIsUserSettings}}active {{end}}item" href="{{AppSubUrl}}/user/settings">
|
||||||
{{svg "octicon-tools"}}
|
{{svg "octicon-tools"}}
|
||||||
{{.locale.Tr "your_settings"}}<!-- Your settings -->
|
{{.locale.Tr "your_settings"}}<!-- Your settings -->
|
||||||
</a>
|
</a>
|
||||||
@ -186,7 +186,7 @@
|
|||||||
{{if .IsAdmin}}
|
{{if .IsAdmin}}
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<a class="{{if .PageIsAdmin}}active{{end}} item" href="{{AppSubUrl}}/admin">
|
<a class="{{if .PageIsAdmin}}active {{end}}item" href="{{AppSubUrl}}/admin">
|
||||||
{{svg "octicon-server"}}
|
{{svg "octicon-server"}}
|
||||||
{{.locale.Tr "admin_panel"}}<!-- Admin Panel -->
|
{{.locale.Tr "admin_panel"}}<!-- Admin Panel -->
|
||||||
</a>
|
</a>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
{{if eq .Num -1}}
|
{{if eq .Num -1}}
|
||||||
<a class="disabled item">...</a>
|
<a class="disabled item">...</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="{{if .IsCurrent}}active{{end}} item content-center" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}>{{.Num}}</a>
|
<a class="{{if .IsCurrent}}active {{end}}item content-center" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}>{{.Num}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if not .HasNext}}disabled{{end}} item navigation" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}>
|
<a class="{{if not .HasNext}}disabled{{end}} item navigation" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}>
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
<div class="ui secondary pointing tabular top attached borderless stackable menu new-menu navbar">
|
<div class="ui secondary pointing tabular top attached borderless stackable menu new-menu navbar">
|
||||||
<a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore/repos">
|
<a class="{{if .PageIsExploreRepositories}}active {{end}}item" href="{{AppSubUrl}}/explore/repos">
|
||||||
{{svg "octicon-repo"}} {{.locale.Tr "explore.repos"}}
|
{{svg "octicon-repo"}} {{.locale.Tr "explore.repos"}}
|
||||||
</a>
|
</a>
|
||||||
{{if not .UsersIsDisabled}}
|
{{if not .UsersIsDisabled}}
|
||||||
<a class="{{if .PageIsExploreUsers}}active{{end}} item" href="{{AppSubUrl}}/explore/users">
|
<a class="{{if .PageIsExploreUsers}}active {{end}}item" href="{{AppSubUrl}}/explore/users">
|
||||||
{{svg "octicon-person"}} {{.locale.Tr "explore.users"}}
|
{{svg "octicon-person"}} {{.locale.Tr "explore.users"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsExploreOrganizations}}active{{end}} item" href="{{AppSubUrl}}/explore/organizations">
|
<a class="{{if .PageIsExploreOrganizations}}active {{end}}item" href="{{AppSubUrl}}/explore/organizations">
|
||||||
{{svg "octicon-organization"}} {{.locale.Tr "explore.organizations"}}
|
{{svg "octicon-organization"}} {{.locale.Tr "explore.organizations"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .IsRepoIndexerEnabled}}
|
{{if .IsRepoIndexerEnabled}}
|
||||||
<a class="{{if .PageIsExploreCode}}active{{end}} item" href="{{AppSubUrl}}/explore/code">
|
<a class="{{if .PageIsExploreCode}}active {{end}}item" href="{{AppSubUrl}}/explore/code">
|
||||||
{{svg "octicon-code"}} {{.locale.Tr "explore.code"}}
|
{{svg "octicon-code"}} {{.locale.Tr "explore.code"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -6,18 +6,18 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
{{if not .DisableStars}}
|
{{if not .DisableStars}}
|
||||||
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.moststars"}}</a>
|
<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.moststars"}}</a>
|
||||||
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
|
<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
|
<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
|
||||||
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
|
<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{.locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
<div class="four wide column">
|
<div class="four wide column">
|
||||||
<div class="ui fluid vertical menu">
|
<div class="ui fluid vertical menu">
|
||||||
<div class="header item">{{.locale.Tr "org.settings"}}</div>
|
<div class="header item">{{.locale.Tr "org.settings"}}</div>
|
||||||
<a class="{{if .PageIsSettingsOptions}}active{{end}} item" href="{{.OrgLink}}/settings">
|
<a class="{{if .PageIsSettingsOptions}}active {{end}}item" href="{{.OrgLink}}/settings">
|
||||||
{{.locale.Tr "org.settings.options"}}
|
{{.locale.Tr "org.settings.options"}}
|
||||||
</a>
|
</a>
|
||||||
{{if not DisableWebhooks}}
|
{{if not DisableWebhooks}}
|
||||||
<a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.OrgLink}}/settings/hooks">
|
<a class="{{if .PageIsSettingsHooks}}active {{end}}item" href="{{.OrgLink}}/settings/hooks">
|
||||||
{{.locale.Tr "repo.settings.hooks"}}
|
{{.locale.Tr "repo.settings.hooks"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsOrgSettingsLabels}}active{{end}} item" href="{{.OrgLink}}/settings/labels">
|
<a class="{{if .PageIsOrgSettingsLabels}}active {{end}}item" href="{{.OrgLink}}/settings/labels">
|
||||||
{{.locale.Tr "repo.labels"}}
|
{{.locale.Tr "repo.labels"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .EnableOAuth2}}
|
{{if .EnableOAuth2}}
|
||||||
<a class="{{if .PageIsSettingsApplications}}active{{end}} item" href="{{.OrgLink}}/settings/applications">
|
<a class="{{if .PageIsSettingsApplications}}active {{end}}item" href="{{.OrgLink}}/settings/applications">
|
||||||
{{.locale.Tr "settings.applications"}}
|
{{.locale.Tr "settings.applications"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .EnablePackages}}
|
{{if .EnablePackages}}
|
||||||
<a class="{{if .PageIsSettingsPackages}}active{{end}} item" href="{{.OrgLink}}/settings/packages">
|
<a class="{{if .PageIsSettingsPackages}}active {{end}}item" href="{{.OrgLink}}/settings/packages">
|
||||||
{{.locale.Tr "packages.title"}}
|
{{.locale.Tr "packages.title"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsSettingsDelete}}active{{end}} item" href="{{.OrgLink}}/settings/delete">
|
<a class="{{if .PageIsSettingsDelete}}active {{end}}item" href="{{.OrgLink}}/settings/delete">
|
||||||
{{.locale.Tr "org.settings.delete"}}
|
{{.locale.Tr "org.settings.delete"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -154,13 +154,13 @@
|
|||||||
{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
|
{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
|
||||||
<div class="ui tabular stackable menu navbar">
|
<div class="ui tabular stackable menu navbar">
|
||||||
{{if .Permission.CanRead $.UnitTypeCode}}
|
{{if .Permission.CanRead $.UnitTypeCode}}
|
||||||
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}">
|
<a class="{{if .PageIsViewCode}}active {{end}}item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}">
|
||||||
{{svg "octicon-code"}} {{.locale.Tr "repo.code"}}
|
{{svg "octicon-code"}} {{.locale.Tr "repo.code"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .Permission.CanRead $.UnitTypeIssues}}
|
{{if .Permission.CanRead $.UnitTypeIssues}}
|
||||||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
|
<a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoLink}}/issues">
|
||||||
{{svg "octicon-issue-opened"}} {{.locale.Tr "repo.issues"}}
|
{{svg "octicon-issue-opened"}} {{.locale.Tr "repo.issues"}}
|
||||||
{{if .Repository.NumOpenIssues}}
|
{{if .Repository.NumOpenIssues}}
|
||||||
<span class="ui primary small label">{{CountFmt .Repository.NumOpenIssues}}</span>
|
<span class="ui primary small label">{{CountFmt .Repository.NumOpenIssues}}</span>
|
||||||
@ -169,13 +169,13 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .Permission.CanRead $.UnitTypeExternalTracker}}
|
{{if .Permission.CanRead $.UnitTypeExternalTracker}}
|
||||||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer">
|
<a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer">
|
||||||
{{svg "octicon-link-external"}} {{.locale.Tr "repo.issues"}} </span>
|
{{svg "octicon-link-external"}} {{.locale.Tr "repo.issues"}} </span>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}}
|
{{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}}
|
||||||
<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
|
<a class="{{if .PageIsPullList}}active {{end}}item" href="{{.RepoLink}}/pulls">
|
||||||
{{svg "octicon-git-pull-request"}} {{.locale.Tr "repo.pulls"}}
|
{{svg "octicon-git-pull-request"}} {{.locale.Tr "repo.pulls"}}
|
||||||
{{if .Repository.NumOpenPulls}}
|
{{if .Repository.NumOpenPulls}}
|
||||||
<span class="ui primary small label">{{CountFmt .Repository.NumOpenPulls}}</span>
|
<span class="ui primary small label">{{CountFmt .Repository.NumOpenPulls}}</span>
|
||||||
@ -184,13 +184,13 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .Permission.CanRead $.UnitTypePackages}}
|
{{if .Permission.CanRead $.UnitTypePackages}}
|
||||||
<a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active{{end}} item">
|
<a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active {{end}}item">
|
||||||
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
|
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead $.UnitTypeProjects)}}
|
{{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead $.UnitTypeProjects)}}
|
||||||
<a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active{{end}} item">
|
<a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item">
|
||||||
{{svg "octicon-project"}} {{.locale.Tr "repo.project_board"}}
|
{{svg "octicon-project"}} {{.locale.Tr "repo.project_board"}}
|
||||||
{{if .Repository.NumOpenProjects}}
|
{{if .Repository.NumOpenProjects}}
|
||||||
<span class="ui primary small label">{{CountFmt .Repository.NumOpenProjects}}</span>
|
<span class="ui primary small label">{{CountFmt .Repository.NumOpenProjects}}</span>
|
||||||
@ -199,7 +199,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo)}}
|
{{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo)}}
|
||||||
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
|
<a class="{{if .PageIsReleaseList}}active {{end}}item" href="{{.RepoLink}}/releases">
|
||||||
{{svg "octicon-tag"}} {{.locale.Tr "repo.releases"}}
|
{{svg "octicon-tag"}} {{.locale.Tr "repo.releases"}}
|
||||||
{{if .NumReleases}}
|
{{if .NumReleases}}
|
||||||
<span class="ui primary small label">{{CountFmt .NumReleases}}</span>
|
<span class="ui primary small label">{{CountFmt .NumReleases}}</span>
|
||||||
@ -208,13 +208,13 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}}
|
{{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}}
|
||||||
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if and (.Permission.CanRead $.UnitTypeExternalWiki) (not (HasPrefix ((.Repository.MustGetUnit $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL) (.Repository.HTMLURL)))}} target="_blank" rel="noopener noreferrer" {{end}}>
|
<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki" {{if and (.Permission.CanRead $.UnitTypeExternalWiki) (not (HasPrefix ((.Repository.MustGetUnit $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL) (.Repository.HTMLURL)))}} target="_blank" rel="noopener noreferrer" {{end}}>
|
||||||
{{svg "octicon-book"}} {{.locale.Tr "repo.wiki"}}
|
{{svg "octicon-book"}} {{.locale.Tr "repo.wiki"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if and (.Permission.CanReadAny $.UnitTypePullRequests $.UnitTypeIssues $.UnitTypeReleases) (not .IsEmptyRepo)}}
|
{{if and (.Permission.CanReadAny $.UnitTypePullRequests $.UnitTypeIssues $.UnitTypeReleases) (not .IsEmptyRepo)}}
|
||||||
<a class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity">
|
<a class="{{if .PageIsActivity}}active {{end}}item" href="{{.RepoLink}}/activity">
|
||||||
{{svg "octicon-pulse"}} {{.locale.Tr "repo.activity"}}
|
{{svg "octicon-pulse"}} {{.locale.Tr "repo.activity"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -223,7 +223,7 @@
|
|||||||
|
|
||||||
{{if .Permission.IsAdmin}}
|
{{if .Permission.IsAdmin}}
|
||||||
<div class="right menu">
|
<div class="right menu">
|
||||||
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">
|
<a class="{{if .PageIsSettings}}active {{end}}item" href="{{.RepoLink}}/settings">
|
||||||
{{svg "octicon-tools"}} {{.locale.Tr "repo.settings"}}
|
{{svg "octicon-tools"}} {{.locale.Tr "repo.settings"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -232,7 +232,7 @@
|
|||||||
{{else if .Permission.IsAdmin}}
|
{{else if .Permission.IsAdmin}}
|
||||||
<div class="ui tabular stackable menu navbar">
|
<div class="ui tabular stackable menu navbar">
|
||||||
<div class="right menu">
|
<div class="right menu">
|
||||||
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">
|
<a class="{{if .PageIsSettings}}active {{end}}item" href="{{.RepoLink}}/settings">
|
||||||
{{svg "octicon-tools"}} {{.locale.Tr "repo.settings"}}
|
{{svg "octicon-tools"}} {{.locale.Tr "repo.settings"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "alphabetically") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&state={{$.State}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
<a class="{{if or (eq .SortType "alphabetically") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&state={{$.State}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&state={{$.State}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&state={{$.State}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?sort=leastissues&state={{$.State}}">{{.locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="{{$.Link}}?sort=leastissues&state={{$.State}}">{{.locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
||||||
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?sort=mostissues&state={{$.State}}">{{.locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="{{$.Link}}?sort=mostissues&state={{$.State}}">{{.locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -123,12 +123,12 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.all_issues"}}</a>
|
<a class="{{if eq .ViewType "all"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.all_issues"}}</a>
|
||||||
<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
|
<a class="{{if eq .ViewType "assigned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
|
||||||
<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
|
<a class="{{if eq .ViewType "created_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
|
||||||
<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
|
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
|
||||||
{{if .PageIsPullList}}
|
{{if .PageIsPullList}}
|
||||||
<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.review_requested"}}</a>
|
<a class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.review_requested"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -141,14 +141,14 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomment"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomment"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "nearduedate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
||||||
<a class="{{if eq .SortType "farduedate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=farduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=farduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -108,11 +108,11 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.all_issues"}}</a>
|
<a class="{{if eq .ViewType "all"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.all_issues"}}</a>
|
||||||
<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
|
<a class="{{if eq .ViewType "assigned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
|
||||||
<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
|
<a class="{{if eq .ViewType "created_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
|
||||||
<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
|
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
|
||||||
<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.review_requested"}}</a>
|
<a class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_type.review_requested"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -124,12 +124,12 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomment"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomment"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,12 +46,12 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
||||||
<a class="{{if eq .SortType "furthestduedate"}}active{{end}} item" href="{{$.Link}}?sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
<a class="{{if eq .SortType "furthestduedate"}}active {{end}}item" href="{{$.Link}}?sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomplete"}}active{{end}} item" href="{{$.Link}}?sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
<a class="{{if eq .SortType "leastcomplete"}}active {{end}}item" href="{{$.Link}}?sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomplete"}}active{{end}} item" href="{{$.Link}}?sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
<a class="{{if eq .SortType "mostcomplete"}}active {{end}}item" href="{{$.Link}}?sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
||||||
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="{{$.Link}}?sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
||||||
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="{{$.Link}}?sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="ui compact left small menu">
|
<div class="ui compact left small menu">
|
||||||
<a class="{{if .PageIsLabels}}active{{end}} item" href="{{.RepoLink}}/labels">{{.locale.Tr "repo.labels"}}</a>
|
<a class="{{if .PageIsLabels}}active {{end}}item" href="{{.RepoLink}}/labels">{{.locale.Tr "repo.labels"}}</a>
|
||||||
<a class="{{if .PageIsMilestones}}active{{end}} item" href="{{.RepoLink}}/milestones">{{.locale.Tr "repo.milestones"}}</a>
|
<a class="{{if .PageIsMilestones}}active {{end}}item" href="{{.RepoLink}}/milestones">{{.locale.Tr "repo.milestones"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="ui compact tiny menu">
|
<div class="ui compact tiny menu">
|
||||||
<a class="{{if not .IsShowClosed}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state=open&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}">
|
<a class="{{if not .IsShowClosed}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state=open&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}">
|
||||||
{{if .PageIsPullList}}
|
{{if .PageIsPullList}}
|
||||||
{{svg "octicon-git-pull-request" 16 "mr-3"}}
|
{{svg "octicon-git-pull-request" 16 "mr-3"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{JsPrettyNumber .IssueStats.OpenCount}} {{.locale.Tr "repo.issues.open_title"}}
|
{{JsPrettyNumber .IssueStats.OpenCount}} {{.locale.Tr "repo.issues.open_title"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .IsShowClosed}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type={{.ViewType}}&sort={{$.SortType}}&state=closed&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}">
|
<a class="{{if .IsShowClosed}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{.ViewType}}&sort={{$.SortType}}&state=closed&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}">
|
||||||
{{svg "octicon-check" 16 "mr-3"}}
|
{{svg "octicon-check" 16 "mr-3"}}
|
||||||
{{JsPrettyNumber .IssueStats.ClosedCount}} {{.locale.Tr "repo.issues.closed_title"}}
|
{{JsPrettyNumber .IssueStats.ClosedCount}} {{.locale.Tr "repo.issues.closed_title"}}
|
||||||
</a>
|
</a>
|
||||||
|
@ -31,9 +31,9 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&sort=oldest&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=oldest&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&sort=recentupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=recentupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&sort=leastupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=leastupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<h2 class="ui compact small menu header">
|
<h2 class="ui compact small menu header">
|
||||||
{{if .Permission.CanRead $.UnitTypeReleases}}
|
{{if .Permission.CanRead $.UnitTypeReleases}}
|
||||||
<a class="{{if (not .PageIsTagList)}}active{{end}} item" href="{{.RepoLink}}/releases">{{.locale.Tr "repo.release.releases"}}</a>
|
<a class="{{if (not .PageIsTagList)}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.Tr "repo.release.releases"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Permission.CanRead $.UnitTypeCode}}
|
{{if .Permission.CanRead $.UnitTypeCode}}
|
||||||
<a class="{{if .PageIsTagList}}active{{end}} item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a>
|
<a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</h2>
|
</h2>
|
||||||
{{if (and .CanCreateRelease (not .PageIsTagList))}}
|
{{if (and .CanCreateRelease (not .PageIsTagList))}}
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar shadow-body">
|
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar shadow-body">
|
||||||
<div class="new-menu-inner">
|
<div class="new-menu-inner">
|
||||||
<a class="{{if .PageIsSettingsOptions}}active{{end}} item" href="{{.RepoLink}}/settings">
|
<a class="{{if .PageIsSettingsOptions}}active {{end}}item" href="{{.RepoLink}}/settings">
|
||||||
{{.locale.Tr "repo.settings.options"}}
|
{{.locale.Tr "repo.settings.options"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsCollaboration}}active{{end}} item" href="{{.RepoLink}}/settings/collaboration">
|
<a class="{{if .PageIsSettingsCollaboration}}active {{end}}item" href="{{.RepoLink}}/settings/collaboration">
|
||||||
{{.locale.Tr "repo.settings.collaboration"}}
|
{{.locale.Tr "repo.settings.collaboration"}}
|
||||||
</a>
|
</a>
|
||||||
{{if not .Repository.IsEmpty}}
|
{{if not .Repository.IsEmpty}}
|
||||||
<a class="{{if .PageIsSettingsBranches}}active{{end}} item" href="{{.RepoLink}}/settings/branches">
|
<a class="{{if .PageIsSettingsBranches}}active {{end}}item" href="{{.RepoLink}}/settings/branches">
|
||||||
{{.locale.Tr "repo.settings.branches"}}
|
{{.locale.Tr "repo.settings.branches"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsSettingsTags}}active{{end}} item" href="{{.RepoLink}}/settings/tags">
|
<a class="{{if .PageIsSettingsTags}}active {{end}}item" href="{{.RepoLink}}/settings/tags">
|
||||||
{{.locale.Tr "repo.settings.tags"}}
|
{{.locale.Tr "repo.settings.tags"}}
|
||||||
</a>
|
</a>
|
||||||
{{if not DisableWebhooks}}
|
{{if not DisableWebhooks}}
|
||||||
<a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks">
|
<a class="{{if .PageIsSettingsHooks}}active {{end}}item" href="{{.RepoLink}}/settings/hooks">
|
||||||
{{.locale.Tr "repo.settings.hooks"}}
|
{{.locale.Tr "repo.settings.hooks"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .SignedUser.CanEditGitHook}}
|
{{if .SignedUser.CanEditGitHook}}
|
||||||
<a class="{{if .PageIsSettingsGitHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks/git">
|
<a class="{{if .PageIsSettingsGitHooks}}active {{end}}item" href="{{.RepoLink}}/settings/hooks/git">
|
||||||
{{.locale.Tr "repo.settings.githooks"}}
|
{{.locale.Tr "repo.settings.githooks"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsSettingsKeys}}active{{end}} item" href="{{.RepoLink}}/settings/keys">
|
<a class="{{if .PageIsSettingsKeys}}active {{end}}item" href="{{.RepoLink}}/settings/keys">
|
||||||
{{.locale.Tr "repo.settings.deploy_keys"}}
|
{{.locale.Tr "repo.settings.deploy_keys"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .LFSStartServer}}
|
{{if .LFSStartServer}}
|
||||||
<a class="{{if .PageIsSettingsLFS}}active{{end}} item" href="{{.RepoLink}}/settings/lfs">
|
<a class="{{if .PageIsSettingsLFS}}active {{end}}item" href="{{.RepoLink}}/settings/lfs">
|
||||||
{{.locale.Tr "repo.settings.lfs"}}
|
{{.locale.Tr "repo.settings.lfs"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -5095,6 +5095,273 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/repos/{owner}/{repo}/issues/comments/{id}/assets": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "List comment's attachments",
|
||||||
|
"operationId": "issueListIssueCommentAttachments",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the comment",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/AttachmentList"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"multipart/form-data"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Create a comment attachment",
|
||||||
|
"operationId": "issueCreateIssueCommentAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the comment",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the attachment",
|
||||||
|
"name": "name",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"description": "attachment to upload",
|
||||||
|
"name": "attachment",
|
||||||
|
"in": "formData",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"$ref": "#/responses/Attachment"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id}": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Get a comment attachment",
|
||||||
|
"operationId": "issueGetIssueCommentAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the comment",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the attachment to get",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/Attachment"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Delete a comment attachment",
|
||||||
|
"operationId": "issueDeleteIssueCommentAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the comment",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the attachment to delete",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Edit a comment attachment",
|
||||||
|
"operationId": "issueEditIssueCommentAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the comment",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the attachment to edit",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/EditAttachmentOptions"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"$ref": "#/responses/Attachment"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/repos/{owner}/{repo}/issues/comments/{id}/reactions": {
|
"/repos/{owner}/{repo}/issues/comments/{id}/reactions": {
|
||||||
"get": {
|
"get": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
@ -5393,6 +5660,273 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/repos/{owner}/{repo}/issues/{index}/assets": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "List issue's attachments",
|
||||||
|
"operationId": "issueListIssueAttachments",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "index of the issue",
|
||||||
|
"name": "index",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/AttachmentList"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"multipart/form-data"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Create an issue attachment",
|
||||||
|
"operationId": "issueCreateIssueAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "index of the issue",
|
||||||
|
"name": "index",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the attachment",
|
||||||
|
"name": "name",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"description": "attachment to upload",
|
||||||
|
"name": "attachment",
|
||||||
|
"in": "formData",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"$ref": "#/responses/Attachment"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/repos/{owner}/{repo}/issues/{index}/assets/{attachment_id}": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Get an issue attachment",
|
||||||
|
"operationId": "issueGetIssueAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "index of the issue",
|
||||||
|
"name": "index",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the attachment to get",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/Attachment"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Delete an issue attachment",
|
||||||
|
"operationId": "issueDeleteIssueAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "index of the issue",
|
||||||
|
"name": "index",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the attachment to delete",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "Edit an issue attachment",
|
||||||
|
"operationId": "issueEditIssueAttachment",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "index of the issue",
|
||||||
|
"name": "index",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "id of the attachment to edit",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/EditAttachmentOptions"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"$ref": "#/responses/Attachment"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/repos/{owner}/{repo}/issues/{index}/comments": {
|
"/repos/{owner}/{repo}/issues/{index}/comments": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
@ -13882,6 +14416,13 @@
|
|||||||
"description": "Comment represents a comment on a commit or issue",
|
"description": "Comment represents a comment on a commit or issue",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"assets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Attachment"
|
||||||
|
},
|
||||||
|
"x-go-name": "Attachments"
|
||||||
|
},
|
||||||
"body": {
|
"body": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Body"
|
"x-go-name": "Body"
|
||||||
@ -16634,6 +17175,13 @@
|
|||||||
"description": "Issue represents an issue in a repository",
|
"description": "Issue represents an issue in a repository",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"assets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Attachment"
|
||||||
|
},
|
||||||
|
"x-go-name": "Attachments"
|
||||||
|
},
|
||||||
"assignee": {
|
"assignee": {
|
||||||
"$ref": "#/definitions/User"
|
"$ref": "#/definitions/User"
|
||||||
},
|
},
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{{if or .EnableOpenIDSignIn .EnableSSPI}}
|
{{if or .EnableOpenIDSignIn .EnableSSPI}}
|
||||||
<div class="ui secondary pointing tabular top attached borderless menu new-menu navbar">
|
<div class="ui secondary pointing tabular top attached borderless menu new-menu navbar">
|
||||||
<div class="new-menu-inner">
|
<div class="new-menu-inner">
|
||||||
<a class="{{if .PageIsLogin}}active{{end}} item" rel="nofollow" href="{{AppSubUrl}}/user/login">
|
<a class="{{if .PageIsLogin}}active {{end}}item" rel="nofollow" href="{{AppSubUrl}}/user/login">
|
||||||
{{.locale.Tr "auth.login_userpass"}}
|
{{.locale.Tr "auth.login_userpass"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .EnableOpenIDSignIn}}
|
{{if .EnableOpenIDSignIn}}
|
||||||
<a class="{{if .PageIsLoginOpenID}}active{{end}} item" rel="nofollow" href="{{AppSubUrl}}/user/login/openid">
|
<a class="{{if .PageIsLoginOpenID}}active {{end}}item" rel="nofollow" href="{{AppSubUrl}}/user/login/openid">
|
||||||
{{svg "fontawesome-openid"}}
|
{{svg "fontawesome-openid"}}
|
||||||
OpenID
|
OpenID
|
||||||
</a>
|
</a>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar">
|
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar">
|
||||||
<div class="new-menu-inner">
|
<div class="new-menu-inner">
|
||||||
<a class="{{if .PageIsOpenIDConnect}}active{{end}} item" href="{{AppSubUrl}}/user/openid/connect">
|
<a class="{{if .PageIsOpenIDConnect}}active {{end}}item" href="{{AppSubUrl}}/user/openid/connect">
|
||||||
{{.locale.Tr "auth.openid_connect_title"}}
|
{{.locale.Tr "auth.openid_connect_title"}}
|
||||||
</a>
|
</a>
|
||||||
{{if and .EnableOpenIDSignUp (not .AllowOnlyInternalRegistration)}}
|
{{if and .EnableOpenIDSignUp (not .AllowOnlyInternalRegistration)}}
|
||||||
<a class="{{if .PageIsOpenIDRegister}}active{{end}} item" href="{{AppSubUrl}}/user/openid/register">
|
<a class="{{if .PageIsOpenIDRegister}}active {{end}}item" href="{{AppSubUrl}}/user/openid/register">
|
||||||
{{.locale.Tr "auth.openid_register_title"}}
|
{{.locale.Tr "auth.openid_register_title"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -89,14 +89,14 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=latest&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=latest&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=oldest&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=oldest&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomment"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomment"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "nearduedate"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
||||||
<a class="{{if eq .SortType "farduedate"}}active{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=farduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=farduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{if .SingleRepoLink}}
|
{{if .SingleRepoLink}}
|
||||||
|
@ -67,12 +67,12 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.closest_due_date"}}</a>
|
||||||
<a class="{{if eq .SortType "furthestduedate"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
<a class="{{if eq .SortType "furthestduedate"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.furthest_due_date"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomplete"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
<a class="{{if eq .SortType "leastcomplete"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomplete"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
<a class="{{if eq .SortType "mostcomplete"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
|
||||||
<a class="{{if eq .SortType "mostissues"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
|
||||||
<a class="{{if eq .SortType "leastissues"}}active{{end}} item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{.locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -76,21 +76,21 @@
|
|||||||
|
|
||||||
{{if .ContextUser.IsOrganization}}
|
{{if .ContextUser.IsOrganization}}
|
||||||
<div class="right stackable menu">
|
<div class="right stackable menu">
|
||||||
<a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
<a class="{{if .PageIsNews}}active {{end}}item" style="margin-left: auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
||||||
{{svg "octicon-rss"}} {{.locale.Tr "activities"}}
|
{{svg "octicon-rss"}} {{.locale.Tr "activities"}}
|
||||||
</a>
|
</a>
|
||||||
{{if not .UnitIssuesGlobalDisabled}}
|
{{if not .UnitIssuesGlobalDisabled}}
|
||||||
<a class="{{if .PageIsIssues}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/issues{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
<a class="{{if .PageIsIssues}}active {{end}}item" href="{{.ContextUser.OrganisationLink}}/issues{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
||||||
{{svg "octicon-issue-opened"}} {{.locale.Tr "issues"}}
|
{{svg "octicon-issue-opened"}} {{.locale.Tr "issues"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not .UnitPullsGlobalDisabled}}
|
{{if not .UnitPullsGlobalDisabled}}
|
||||||
<a class="{{if .PageIsPulls}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/pulls{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
<a class="{{if .PageIsPulls}}active {{end}}item" href="{{.ContextUser.OrganisationLink}}/pulls{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
||||||
{{svg "octicon-git-pull-request"}} {{.locale.Tr "pull_requests"}}
|
{{svg "octicon-git-pull-request"}} {{.locale.Tr "pull_requests"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and .ShowMilestonesDashboardPage (not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled))}}
|
{{if and .ShowMilestonesDashboardPage (not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled))}}
|
||||||
<a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/milestones{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
<a class="{{if .PageIsMilestonesDashboard}}active {{end}}item" href="{{.ContextUser.OrganisationLink}}/milestones{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
|
||||||
{{svg "octicon-milestone"}} {{.locale.Tr "milestones"}}
|
{{svg "octicon-milestone"}} {{.locale.Tr "milestones"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
<h1 class="ui dividing header">{{.locale.Tr "notification.notifications"}}</h1>
|
<h1 class="ui dividing header">{{.locale.Tr "notification.notifications"}}</h1>
|
||||||
<div class="ui top attached tabular menu">
|
<div class="ui top attached tabular menu">
|
||||||
{{$notificationUnreadCount := call .NotificationUnreadCount}}
|
{{$notificationUnreadCount := call .NotificationUnreadCount}}
|
||||||
<a href="{{AppSubUrl}}/notifications?q=unread" class="{{if eq .Status 1}}active{{end}} item">
|
<a href="{{AppSubUrl}}/notifications?q=unread" class="{{if eq .Status 1}}active {{end}}item">
|
||||||
{{.locale.Tr "notification.unread"}}
|
{{.locale.Tr "notification.unread"}}
|
||||||
<div class="ui label {{if not $notificationUnreadCount}}hidden{{end}}">{{$notificationUnreadCount}}</div>
|
<div class="ui label {{if not $notificationUnreadCount}}hidden{{end}}">{{$notificationUnreadCount}}</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{AppSubUrl}}/notifications?q=read" class="{{if eq .Status 2}}active{{end}} item">
|
<a href="{{AppSubUrl}}/notifications?q=read" class="{{if eq .Status 2}}active {{end}}item">
|
||||||
{{.locale.Tr "notification.read"}}
|
{{.locale.Tr "notification.read"}}
|
||||||
</a>
|
</a>
|
||||||
{{if and (eq .Status 1)}}
|
{{if and (eq .Status 1)}}
|
||||||
|
@ -103,31 +103,31 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ui eleven wide column">
|
<div class="ui eleven wide column">
|
||||||
<div class="ui secondary stackable pointing tight menu">
|
<div class="ui secondary stackable pointing tight menu">
|
||||||
<a class='{{if and (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars") (ne .TabName "watching") (ne .TabName "projects") (ne .TabName "code")}}active{{end}} item' href="{{.Owner.HomeLink}}">
|
<a class='{{if and (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars") (ne .TabName "watching") (ne .TabName "projects") (ne .TabName "code")}}active {{end}}item' href="{{.Owner.HomeLink}}">
|
||||||
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
|
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .IsPackageEnabled}}
|
{{if .IsPackageEnabled}}
|
||||||
<a class='{{if eq .TabName "packages"}}active{{end}} item' href="{{.Owner.HomeLink}}/-/packages">
|
<a class='{{if eq .TabName "packages"}}active {{end}}item' href="{{.Owner.HomeLink}}/-/packages">
|
||||||
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
|
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsRepoIndexerEnabled}}
|
{{if .IsRepoIndexerEnabled}}
|
||||||
<a class='{{if eq .TabName "code"}}active{{end}} item' href="{{.Owner.HomeLink}}/-/code">
|
<a class='{{if eq .TabName "code"}}active {{end}}item' href="{{.Owner.HomeLink}}/-/code">
|
||||||
{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
|
{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity">
|
<a class='{{if eq .TabName "activity"}}active {{end}}item' href="{{.Owner.HomeLink}}?tab=activity">
|
||||||
{{svg "octicon-rss"}} {{.locale.Tr "user.activity"}}
|
{{svg "octicon-rss"}} {{.locale.Tr "user.activity"}}
|
||||||
</a>
|
</a>
|
||||||
{{if not .DisableStars}}
|
{{if not .DisableStars}}
|
||||||
<a class='{{if eq .TabName "stars"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=stars">
|
<a class='{{if eq .TabName "stars"}}active {{end}}item' href="{{.Owner.HomeLink}}?tab=stars">
|
||||||
{{svg "octicon-star"}} {{.locale.Tr "user.starred"}}
|
{{svg "octicon-star"}} {{.locale.Tr "user.starred"}}
|
||||||
{{if .Owner.NumStars}}
|
{{if .Owner.NumStars}}
|
||||||
<div class="ui primary label">{{.Owner.NumStars}}</div>
|
<div class="ui primary label">{{.Owner.NumStars}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</a>
|
</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class='{{if eq .TabName "watching"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=watching">
|
<a class='{{if eq .TabName "watching"}}active {{end}}item' href="{{.Owner.HomeLink}}?tab=watching">
|
||||||
{{svg "octicon-eye"}} {{.locale.Tr "user.watched"}}
|
{{svg "octicon-eye"}} {{.locale.Tr "user.watched"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar">
|
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar">
|
||||||
<div class="new-menu-inner">
|
<div class="new-menu-inner">
|
||||||
<a class="{{if .PageIsSettingsProfile}}active{{end}} item" href="{{AppSubUrl}}/user/settings">
|
<a class="{{if .PageIsSettingsProfile}}active {{end}}item" href="{{AppSubUrl}}/user/settings">
|
||||||
{{.locale.Tr "settings.profile"}}
|
{{.locale.Tr "settings.profile"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsAccount}}active{{end}} item" href="{{AppSubUrl}}/user/settings/account">
|
<a class="{{if .PageIsSettingsAccount}}active {{end}}item" href="{{AppSubUrl}}/user/settings/account">
|
||||||
{{.locale.Tr "settings.account"}}
|
{{.locale.Tr "settings.account"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsAppearance}}active{{end}} item" href="{{AppSubUrl}}/user/settings/appearance">
|
<a class="{{if .PageIsSettingsAppearance}}active {{end}}item" href="{{AppSubUrl}}/user/settings/appearance">
|
||||||
{{.locale.Tr "settings.appearance"}}
|
{{.locale.Tr "settings.appearance"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsSecurity}}active{{end}} item" href="{{AppSubUrl}}/user/settings/security">
|
<a class="{{if .PageIsSettingsSecurity}}active {{end}}item" href="{{AppSubUrl}}/user/settings/security">
|
||||||
{{.locale.Tr "settings.security"}}
|
{{.locale.Tr "settings.security"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsApplications}}active{{end}} item" href="{{AppSubUrl}}/user/settings/applications">
|
<a class="{{if .PageIsSettingsApplications}}active {{end}}item" href="{{AppSubUrl}}/user/settings/applications">
|
||||||
{{.locale.Tr "settings.applications"}}
|
{{.locale.Tr "settings.applications"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsKeys}}active{{end}} item" href="{{AppSubUrl}}/user/settings/keys">
|
<a class="{{if .PageIsSettingsKeys}}active {{end}}item" href="{{AppSubUrl}}/user/settings/keys">
|
||||||
{{.locale.Tr "settings.ssh_gpg_keys"}}
|
{{.locale.Tr "settings.ssh_gpg_keys"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .EnablePackages}}
|
{{if .EnablePackages}}
|
||||||
<a class="{{if .PageIsSettingsPackages}}active{{end}} item" href="{{AppSubUrl}}/user/settings/packages">
|
<a class="{{if .PageIsSettingsPackages}}active {{end}}item" href="{{AppSubUrl}}/user/settings/packages">
|
||||||
{{.locale.Tr "packages.title"}}
|
{{.locale.Tr "packages.title"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if .PageIsSettingsOrganization}}active{{end}} item" href="{{AppSubUrl}}/user/settings/organization">
|
<a class="{{if .PageIsSettingsOrganization}}active {{end}}item" href="{{AppSubUrl}}/user/settings/organization">
|
||||||
{{.locale.Tr "settings.organization"}}
|
{{.locale.Tr "settings.organization"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .PageIsSettingsRepos}}active{{end}} item" href="{{AppSubUrl}}/user/settings/repos">
|
<a class="{{if .PageIsSettingsRepos}}active {{end}}item" href="{{AppSubUrl}}/user/settings/repos">
|
||||||
{{.locale.Tr "settings.repos"}}
|
{{.locale.Tr "settings.repos"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
154
tests/integration/api_comment_attachment_test.go
Normal file
154
tests/integration/api_comment_attachment_test.go
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// Copyright 2021 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 integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/convert"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIGetCommentAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
|
||||||
|
assert.NoError(t, comment.LoadIssue(db.DefaultContext))
|
||||||
|
assert.NoError(t, comment.LoadAttachments(db.DefaultContext))
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: comment.Attachments[0].ID})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d/assets/%d", repoOwner.Name, repo.Name, comment.ID, attachment.ID)
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d/assets/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, attachment.ID, token)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var apiAttachment api.Attachment
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
expect := convert.ToAttachment(attachment)
|
||||||
|
assert.Equal(t, expect.ID, apiAttachment.ID)
|
||||||
|
assert.Equal(t, expect.Name, apiAttachment.Name)
|
||||||
|
assert.Equal(t, expect.UUID, apiAttachment.UUID)
|
||||||
|
assert.Equal(t, expect.Created.Unix(), apiAttachment.Created.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIListCommentAttachments(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d/assets",
|
||||||
|
repoOwner.Name, repo.Name, comment.ID)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var apiAttachments []*api.Attachment
|
||||||
|
DecodeJSON(t, resp, &apiAttachments)
|
||||||
|
expectedCount := unittest.GetCount(t, &repo_model.Attachment{CommentID: comment.ID})
|
||||||
|
assert.EqualValues(t, expectedCount, len(apiAttachments))
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachments[0].ID, CommentID: comment.ID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPICreateCommentAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/assets?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, comment.ID, token)
|
||||||
|
|
||||||
|
filename := "image.png"
|
||||||
|
buff := generateImg()
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
|
||||||
|
// Setup multi-part
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
part, err := writer.CreateFormFile("attachment", filename)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = io.Copy(part, &buff)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = writer.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
req := NewRequestWithBody(t, "POST", urlStr, body)
|
||||||
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||||
|
|
||||||
|
apiAttachment := new(api.Attachment)
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, CommentID: comment.ID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIEditCommentAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
const newAttachmentName = "newAttachmentName"
|
||||||
|
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 6})
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: attachment.CommentID})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/assets/%d?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, comment.ID, attachment.ID, token)
|
||||||
|
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
||||||
|
"name": newAttachmentName,
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||||
|
apiAttachment := new(api.Attachment)
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, CommentID: comment.ID, Name: apiAttachment.Name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIDeleteCommentAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 6})
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: attachment.CommentID})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/assets/%d?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, comment.ID, attachment.ID, token)
|
||||||
|
|
||||||
|
req := NewRequestf(t, "DELETE", urlStr)
|
||||||
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
|
unittest.AssertNotExistsBean(t, &repo_model.Attachment{ID: attachment.ID, CommentID: comment.ID})
|
||||||
|
}
|
143
tests/integration/api_issue_attachment_test.go
Normal file
143
tests/integration/api_issue_attachment_test.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// Copyright 2021 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 integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIGetIssueAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 1})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: attachment.RepoID})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: attachment.IssueID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets/%d?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, issue.Index, attachment.ID, token)
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", urlStr)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
apiAttachment := new(api.Attachment)
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, IssueID: issue.ID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIListIssueAttachments(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 1})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: attachment.RepoID})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: attachment.IssueID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, issue.Index, token)
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", urlStr)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
apiAttachment := new([]api.Attachment)
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: (*apiAttachment)[0].ID, IssueID: issue.ID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPICreateIssueAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, issue.Index, token)
|
||||||
|
|
||||||
|
filename := "image.png"
|
||||||
|
buff := generateImg()
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
|
||||||
|
// Setup multi-part
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
part, err := writer.CreateFormFile("attachment", filename)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = io.Copy(part, &buff)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = writer.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
req := NewRequestWithBody(t, "POST", urlStr, body)
|
||||||
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||||
|
|
||||||
|
apiAttachment := new(api.Attachment)
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, IssueID: issue.ID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIEditIssueAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
const newAttachmentName = "newAttachmentName"
|
||||||
|
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 1})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: attachment.RepoID})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: attachment.IssueID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets/%d?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, issue.Index, attachment.ID, token)
|
||||||
|
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
||||||
|
"name": newAttachmentName,
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||||
|
apiAttachment := new(api.Attachment)
|
||||||
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, IssueID: issue.ID, Name: apiAttachment.Name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIDeleteIssueAttachment(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
attachment := unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 1})
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: attachment.RepoID})
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: attachment.IssueID})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets/%d?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, issue.Index, attachment.ID, token)
|
||||||
|
|
||||||
|
req := NewRequest(t, "DELETE", urlStr)
|
||||||
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
|
unittest.AssertNotExistsBean(t, &repo_model.Attachment{ID: attachment.ID, IssueID: issue.ID})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user