mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-22 14:25:18 +02:00
before: gitrepo vs git packages after: git package fully handle all git operations by the way, use `WithRepo(repo)` instead of `WithDir(repo.Path)` to hide path details. benefits: 1. remove all unnecessary wrappers, developers no need to struggle with "which package should be used" 2. simplify code, RepositoryFacade can (will) be used everywhere, all "path" details are (will be) hidden
231 lines
6.8 KiB
Go
231 lines
6.8 KiB
Go
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package templates
|
|
|
|
import (
|
|
"context"
|
|
"html/template"
|
|
"mime"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
activities_model "gitea.dev/models/activities"
|
|
repo_model "gitea.dev/models/repo"
|
|
user_model "gitea.dev/models/user"
|
|
"gitea.dev/modules/git"
|
|
"gitea.dev/modules/json"
|
|
"gitea.dev/modules/log"
|
|
"gitea.dev/modules/repository"
|
|
"gitea.dev/modules/setting"
|
|
"gitea.dev/modules/svg"
|
|
|
|
"github.com/editorconfig/editorconfig-core-go/v2"
|
|
)
|
|
|
|
func sortArrow(normSort, revSort, urlSort string, isDefault bool) template.HTML {
|
|
// if needed
|
|
if len(normSort) == 0 || len(urlSort) == 0 {
|
|
return ""
|
|
}
|
|
|
|
if len(urlSort) == 0 && isDefault {
|
|
// if sort is sorted as default add arrow tho this table header
|
|
if isDefault {
|
|
return svg.RenderHTML("octicon-triangle-down", 16)
|
|
}
|
|
} else {
|
|
// if sort arg is in url test if it correlates with column header sort arguments
|
|
// the direction of the arrow should indicate the "current sort order", up means ASC(normal), down means DESC(rev)
|
|
switch urlSort {
|
|
case normSort:
|
|
// the table is sorted with this header normal
|
|
return svg.RenderHTML("octicon-triangle-up", 16)
|
|
case revSort:
|
|
// the table is sorted with this header reverse
|
|
return svg.RenderHTML("octicon-triangle-down", 16)
|
|
}
|
|
}
|
|
// the table is NOT sorted with this header
|
|
return ""
|
|
}
|
|
|
|
// Actioner describes an action
|
|
type Actioner interface {
|
|
GetOpType() activities_model.ActionType
|
|
GetActUserName(ctx context.Context) string
|
|
GetRepoUserName(ctx context.Context) string
|
|
GetRepoName(ctx context.Context) string
|
|
GetRepoPath(ctx context.Context) string
|
|
GetRepoLink(ctx context.Context) string
|
|
GetBranch() string
|
|
GetContent() string
|
|
GetCreate() time.Time
|
|
GetIssueInfos() []string
|
|
}
|
|
|
|
// actionIcon accepts an action operation type and returns an icon class name.
|
|
func actionIcon(opType activities_model.ActionType) string {
|
|
switch opType {
|
|
case activities_model.ActionCreateRepo, activities_model.ActionTransferRepo, activities_model.ActionRenameRepo:
|
|
return "repo"
|
|
case activities_model.ActionCommitRepo:
|
|
return "git-commit"
|
|
case activities_model.ActionDeleteBranch:
|
|
return "git-branch"
|
|
case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest:
|
|
return "git-merge"
|
|
case activities_model.ActionCreatePullRequest:
|
|
return "git-pull-request"
|
|
case activities_model.ActionClosePullRequest:
|
|
return "git-pull-request-closed"
|
|
case activities_model.ActionCreateIssue:
|
|
return "issue-opened"
|
|
case activities_model.ActionCloseIssue:
|
|
return "issue-closed"
|
|
case activities_model.ActionReopenIssue, activities_model.ActionReopenPullRequest:
|
|
return "issue-reopened"
|
|
case activities_model.ActionCommentIssue, activities_model.ActionCommentPull:
|
|
return "comment-discussion"
|
|
case activities_model.ActionMirrorSyncPush, activities_model.ActionMirrorSyncCreate, activities_model.ActionMirrorSyncDelete:
|
|
return "mirror"
|
|
case activities_model.ActionApprovePullRequest:
|
|
return "check"
|
|
case activities_model.ActionRejectPullRequest:
|
|
return "file-diff"
|
|
case activities_model.ActionPublishRelease, activities_model.ActionPushTag, activities_model.ActionDeleteTag:
|
|
return "tag"
|
|
case activities_model.ActionPullReviewDismissed:
|
|
return "x"
|
|
default:
|
|
return "question"
|
|
}
|
|
}
|
|
|
|
// ActionContent2Commits converts action content to push commits
|
|
func ActionContent2Commits(act Actioner) *repository.PushCommits {
|
|
push := repository.NewPushCommits()
|
|
|
|
if act == nil || act.GetContent() == "" {
|
|
return push
|
|
}
|
|
|
|
if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
|
|
log.Error("json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
|
|
}
|
|
|
|
if push.Len == 0 {
|
|
push.Len = len(push.Commits)
|
|
}
|
|
|
|
return push
|
|
}
|
|
|
|
// migrationIcon returns a SVG name matching the service an issue/comment was migrated from
|
|
func migrationIcon(hostname string) string {
|
|
switch hostname {
|
|
case "github.com":
|
|
return "octicon-mark-github"
|
|
default:
|
|
return "gitea-git"
|
|
}
|
|
}
|
|
|
|
type remoteAddress struct {
|
|
Address string
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress {
|
|
ret := remoteAddress{}
|
|
u, err := git.ParseRemoteAddressURL(ctx, m, remoteName)
|
|
if err != nil {
|
|
log.Error("GetRemoteURL %v", err)
|
|
return ret
|
|
}
|
|
|
|
if u.Scheme != "ssh" && u.Scheme != "file" {
|
|
if u.User != nil {
|
|
ret.Username = u.User.Username()
|
|
ret.Password, _ = u.User.Password()
|
|
}
|
|
}
|
|
|
|
// The URL stored in the git repo could contain authentication,
|
|
// erase it, or it will be shown in the UI.
|
|
u.User = nil
|
|
ret.Address = u.String()
|
|
// Why not use m.OriginalURL to set ret.Address?
|
|
// It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository.
|
|
// However, the old code has already stored authentication in m.OriginalURL when updating mirror settings.
|
|
// That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased.
|
|
// Instead of doing this, why not directly use the authentication-erased URL from the Git repository?
|
|
// It should be the same as long as there are no bugs.
|
|
|
|
return ret
|
|
}
|
|
|
|
func filenameIsImage(filename string) bool {
|
|
mimeType := mime.TypeByExtension(filepath.Ext(filename))
|
|
return strings.HasPrefix(mimeType, "image/")
|
|
}
|
|
|
|
func tabSizeClass(ec *editorconfig.Editorconfig, filename string) string {
|
|
if ec != nil {
|
|
def, err := ec.GetDefinitionForFilename(filename)
|
|
if err == nil && def.TabWidth >= 1 && def.TabWidth <= 16 {
|
|
return "tab-size-" + strconv.Itoa(def.TabWidth)
|
|
}
|
|
}
|
|
return "tab-size-4"
|
|
}
|
|
|
|
type MiscUtils struct {
|
|
ctx context.Context
|
|
}
|
|
|
|
func NewMiscUtils(ctx context.Context) *MiscUtils {
|
|
return &MiscUtils{ctx: ctx}
|
|
}
|
|
|
|
type MarkdownEditorContext struct {
|
|
PreviewMode string // "comment", "wiki", or empty for general
|
|
PreviewContext string // the path for resolving the links in the preview (repo preview already has default correct value)
|
|
PreviewLink string
|
|
MentionsLink string
|
|
}
|
|
|
|
func (m *MiscUtils) MarkdownEditorComment(repo *repo_model.Repository) *MarkdownEditorContext {
|
|
if repo == nil {
|
|
return nil
|
|
}
|
|
return &MarkdownEditorContext{
|
|
PreviewMode: "comment",
|
|
PreviewLink: repo.Link() + "/markup",
|
|
MentionsLink: repo.Link() + "/-/mentions-in-repo",
|
|
}
|
|
}
|
|
|
|
func (m *MiscUtils) MarkdownEditorWiki(repo *repo_model.Repository) *MarkdownEditorContext {
|
|
if repo == nil {
|
|
return nil
|
|
}
|
|
return &MarkdownEditorContext{
|
|
PreviewMode: "wiki",
|
|
PreviewLink: repo.Link() + "/markup",
|
|
MentionsLink: repo.Link() + "/-/mentions-in-repo",
|
|
}
|
|
}
|
|
|
|
func (m *MiscUtils) MarkdownEditorGeneral(owner *user_model.User) *MarkdownEditorContext {
|
|
ret := &MarkdownEditorContext{PreviewLink: setting.AppSubURL + "/-/markup"}
|
|
if owner != nil {
|
|
ret.PreviewContext = owner.HomeLink()
|
|
ret.MentionsLink = owner.HomeLink() + "/-/mentions-in-owner"
|
|
}
|
|
return ret
|
|
}
|