mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-01 14:56:30 +00:00
Merge branch 'go-gitea:main' into pacman-packages
This commit is contained in:
commit
73fe874862
@ -5,7 +5,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -13,9 +12,6 @@ import (
|
|||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnvironmentPrefix environment variables prefixed with this represent ini values to write
|
|
||||||
const EnvironmentPrefix = "GITEA"
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "environment-to-ini"
|
app.Name = "environment-to-ini"
|
||||||
@ -70,15 +66,6 @@ func main() {
|
|||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Destination file to write to",
|
Usage: "Destination file to write to",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
|
||||||
Name: "clear",
|
|
||||||
Usage: "Clears the matched variables from the environment",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "prefix, p",
|
|
||||||
Value: EnvironmentPrefix,
|
|
||||||
Usage: "Environment prefix to look for - will be suffixed by __ (2 underscores)",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
app.Action = runEnvironmentToIni
|
app.Action = runEnvironmentToIni
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
@ -99,9 +86,7 @@ func runEnvironmentToIni(c *cli.Context) error {
|
|||||||
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixGitea := c.String("prefix") + "__"
|
changed := setting.EnvironmentToConfig(cfg, os.Environ())
|
||||||
suffixFile := "__FILE"
|
|
||||||
changed := setting.EnvironmentToConfig(cfg, prefixGitea, suffixFile, os.Environ())
|
|
||||||
|
|
||||||
// try to save the config file
|
// try to save the config file
|
||||||
destination := c.String("out")
|
destination := c.String("out")
|
||||||
@ -116,19 +101,5 @@ func runEnvironmentToIni(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear Gitea's specific environment variables if requested
|
|
||||||
if c.Bool("clear") {
|
|
||||||
for _, kv := range os.Environ() {
|
|
||||||
idx := strings.IndexByte(kv, '=')
|
|
||||||
if idx < 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
eKey := kv[:idx]
|
|
||||||
if strings.HasPrefix(eKey, prefixGitea) {
|
|
||||||
_ = os.Unsetenv(eKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#
|
#
|
||||||
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
||||||
GITEA="/app/gitea/gitea"
|
GITEA="/app/gitea/gitea"
|
||||||
WORK_DIR="/app/gitea"
|
WORK_DIR="/data/gitea"
|
||||||
CUSTOM_PATH="/data/gitea"
|
CUSTOM_PATH="/data/gitea"
|
||||||
|
|
||||||
# Provide docker defaults
|
# Provide docker defaults
|
||||||
|
@ -288,7 +288,7 @@ docker-compose up -d
|
|||||||
|
|
||||||
In addition to the environment variables above, any settings in `app.ini` can be set
|
In addition to the environment variables above, any settings in `app.ini` can be set
|
||||||
or overridden with an environment variable of the form: `GITEA__SECTION_NAME__KEY_NAME`.
|
or overridden with an environment variable of the form: `GITEA__SECTION_NAME__KEY_NAME`.
|
||||||
These settings are applied each time the docker container starts.
|
These settings are applied each time the docker container starts, and won't be passed into Gitea's sub-processes.
|
||||||
Full information [here](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini).
|
Full information [here](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini).
|
||||||
|
|
||||||
These environment variables can be passed to the docker container in `docker-compose.yml`.
|
These environment variables can be passed to the docker container in `docker-compose.yml`.
|
||||||
|
@ -289,7 +289,7 @@ docker-compose up -d
|
|||||||
|
|
||||||
In addition to the environment variables above, any settings in `app.ini` can be set
|
In addition to the environment variables above, any settings in `app.ini` can be set
|
||||||
or overridden with an environment variable of the form: `GITEA__SECTION_NAME__KEY_NAME`.
|
or overridden with an environment variable of the form: `GITEA__SECTION_NAME__KEY_NAME`.
|
||||||
These settings are applied each time the docker container starts.
|
These settings are applied each time the docker container starts, and won't be passed into Gitea's sub-processes.
|
||||||
Full information [here](https://github.com/go-gitea/gitea/tree/master/contrib/environment-to-ini).
|
Full information [here](https://github.com/go-gitea/gitea/tree/master/contrib/environment-to-ini).
|
||||||
|
|
||||||
These environment variables can be passed to the docker container in `docker-compose.yml`.
|
These environment variables can be passed to the docker container in `docker-compose.yml`.
|
||||||
|
@ -81,3 +81,21 @@
|
|||||||
uid: 5
|
uid: 5
|
||||||
org_id: 23
|
org_id: 23
|
||||||
is_public: false
|
is_public: false
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 15
|
||||||
|
uid: 1
|
||||||
|
org_id: 35
|
||||||
|
is_public: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 16
|
||||||
|
uid: 1
|
||||||
|
org_id: 36
|
||||||
|
is_public: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 17
|
||||||
|
uid: 5
|
||||||
|
org_id: 36
|
||||||
|
is_public: true
|
||||||
|
@ -184,3 +184,36 @@
|
|||||||
num_members: 1
|
num_members: 1
|
||||||
includes_all_repositories: false
|
includes_all_repositories: false
|
||||||
can_create_org_repo: true
|
can_create_org_repo: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 18
|
||||||
|
org_id: 35
|
||||||
|
lower_name: owners
|
||||||
|
name: Owners
|
||||||
|
authorize: 4 # owner
|
||||||
|
num_repos: 0
|
||||||
|
num_members: 1
|
||||||
|
includes_all_repositories: false
|
||||||
|
can_create_org_repo: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 19
|
||||||
|
org_id: 36
|
||||||
|
lower_name: owners
|
||||||
|
name: Owners
|
||||||
|
authorize: 4 # owner
|
||||||
|
num_repos: 0
|
||||||
|
num_members: 1
|
||||||
|
includes_all_repositories: false
|
||||||
|
can_create_org_repo: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 20
|
||||||
|
org_id: 36
|
||||||
|
lower_name: team20writepackage
|
||||||
|
name: team20writepackage
|
||||||
|
authorize: 1
|
||||||
|
num_repos: 0
|
||||||
|
num_members: 1
|
||||||
|
includes_all_repositories: false
|
||||||
|
can_create_org_repo: true
|
||||||
|
@ -273,4 +273,10 @@
|
|||||||
id: 46
|
id: 46
|
||||||
team_id: 17
|
team_id: 17
|
||||||
type: 9 # package
|
type: 9 # package
|
||||||
access_mode: 0
|
access_mode: 2
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 47
|
||||||
|
team_id: 20
|
||||||
|
type: 9 # package
|
||||||
|
access_mode: 2
|
||||||
|
@ -105,3 +105,21 @@
|
|||||||
org_id: 23
|
org_id: 23
|
||||||
team_id: 17
|
team_id: 17
|
||||||
uid: 5
|
uid: 5
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 19
|
||||||
|
org_id: 35
|
||||||
|
team_id: 18
|
||||||
|
uid: 1
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 20
|
||||||
|
org_id: 36
|
||||||
|
team_id: 19
|
||||||
|
uid: 1
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 21
|
||||||
|
org_id: 36
|
||||||
|
team_id: 20
|
||||||
|
uid: 5
|
||||||
|
@ -1258,3 +1258,77 @@
|
|||||||
repo_admin_change_team_access: false
|
repo_admin_change_team_access: false
|
||||||
theme: ""
|
theme: ""
|
||||||
keep_activity_private: false
|
keep_activity_private: false
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 35
|
||||||
|
lower_name: private_org35
|
||||||
|
name: private_org35
|
||||||
|
full_name: Private Org 35
|
||||||
|
email: private_org35@example.com
|
||||||
|
keep_email_private: false
|
||||||
|
email_notifications_preference: enabled
|
||||||
|
passwd: ZogKvWdyEx:password
|
||||||
|
passwd_hash_algo: dummy
|
||||||
|
must_change_password: false
|
||||||
|
login_source: 0
|
||||||
|
login_name: private_org35
|
||||||
|
type: 1
|
||||||
|
salt: ZogKvWdyEx
|
||||||
|
max_repo_creation: -1
|
||||||
|
is_active: true
|
||||||
|
is_admin: false
|
||||||
|
is_restricted: false
|
||||||
|
allow_git_hook: false
|
||||||
|
allow_import_local: false
|
||||||
|
allow_create_organization: true
|
||||||
|
prohibit_login: false
|
||||||
|
avatar: avatar35
|
||||||
|
avatar_email: private_org35@example.com
|
||||||
|
use_custom_avatar: false
|
||||||
|
num_followers: 0
|
||||||
|
num_following: 0
|
||||||
|
num_stars: 0
|
||||||
|
num_repos: 0
|
||||||
|
num_teams: 1
|
||||||
|
num_members: 1
|
||||||
|
visibility: 2
|
||||||
|
repo_admin_change_team_access: false
|
||||||
|
theme: ""
|
||||||
|
keep_activity_private: false
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 36
|
||||||
|
lower_name: limited_org36
|
||||||
|
name: limited_org36
|
||||||
|
full_name: Limited Org 36
|
||||||
|
email: limited_org36@example.com
|
||||||
|
keep_email_private: false
|
||||||
|
email_notifications_preference: enabled
|
||||||
|
passwd: ZogKvWdyEx:password
|
||||||
|
passwd_hash_algo: dummy
|
||||||
|
must_change_password: false
|
||||||
|
login_source: 0
|
||||||
|
login_name: limited_org36
|
||||||
|
type: 1
|
||||||
|
salt: ZogKvWdyEx
|
||||||
|
max_repo_creation: -1
|
||||||
|
is_active: true
|
||||||
|
is_admin: false
|
||||||
|
is_restricted: false
|
||||||
|
allow_git_hook: false
|
||||||
|
allow_import_local: false
|
||||||
|
allow_create_organization: true
|
||||||
|
prohibit_login: false
|
||||||
|
avatar: avatar22
|
||||||
|
avatar_email: limited_org36@example.com
|
||||||
|
use_custom_avatar: false
|
||||||
|
num_followers: 0
|
||||||
|
num_following: 0
|
||||||
|
num_stars: 0
|
||||||
|
num_repos: 0
|
||||||
|
num_teams: 2
|
||||||
|
num_members: 2
|
||||||
|
visibility: 1
|
||||||
|
repo_admin_change_team_access: false
|
||||||
|
theme: ""
|
||||||
|
keep_activity_private: false
|
||||||
|
@ -382,7 +382,8 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 6 hours which has no opened PRs created
|
// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 6 hours which has no opened PRs created
|
||||||
func FindRecentlyPushedNewBranches(ctx context.Context, repoID, userID int64) (BranchList, error) {
|
// except the indicate branch
|
||||||
|
func FindRecentlyPushedNewBranches(ctx context.Context, repoID, userID int64, excludeBranchName string) (BranchList, error) {
|
||||||
branches := make(BranchList, 0, 2)
|
branches := make(BranchList, 0, 2)
|
||||||
subQuery := builder.Select("head_branch").From("pull_request").
|
subQuery := builder.Select("head_branch").From("pull_request").
|
||||||
InnerJoin("issue", "issue.id = pull_request.issue_id").
|
InnerJoin("issue", "issue.id = pull_request.issue_id").
|
||||||
@ -392,6 +393,7 @@ func FindRecentlyPushedNewBranches(ctx context.Context, repoID, userID int64) (B
|
|||||||
})
|
})
|
||||||
err := db.GetEngine(ctx).
|
err := db.GetEngine(ctx).
|
||||||
Where("pusher_id=? AND is_deleted=?", userID, false).
|
Where("pusher_id=? AND is_deleted=?", userID, false).
|
||||||
|
And("name <> ?", excludeBranchName).
|
||||||
And("updated_unix >= ?", time.Now().Add(-time.Hour*6).Unix()).
|
And("updated_unix >= ?", time.Now().Add(-time.Hour*6).Unix()).
|
||||||
NotIn("name", subQuery).
|
NotIn("name", subQuery).
|
||||||
OrderBy("branch.updated_unix DESC").
|
OrderBy("branch.updated_unix DESC").
|
||||||
|
@ -65,13 +65,6 @@ func (a *Attachment) DownloadURL() string {
|
|||||||
return setting.AppURL + "attachments/" + url.PathEscape(a.UUID)
|
return setting.AppURL + "attachments/" + url.PathEscape(a.UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// _____ __ __ .__ __
|
|
||||||
// / _ \_/ |__/ |______ ____ | |__ _____ ____ _____/ |_
|
|
||||||
// / /_\ \ __\ __\__ \ _/ ___\| | \ / \_/ __ \ / \ __\
|
|
||||||
// / | \ | | | / __ \\ \___| Y \ Y Y \ ___/| | \ |
|
|
||||||
// \____|__ /__| |__| (____ /\___ >___| /__|_| /\___ >___| /__|
|
|
||||||
// \/ \/ \/ \/ \/ \/ \/
|
|
||||||
|
|
||||||
// ErrAttachmentNotExist represents a "AttachmentNotExist" kind of error.
|
// ErrAttachmentNotExist represents a "AttachmentNotExist" kind of error.
|
||||||
type ErrAttachmentNotExist struct {
|
type ErrAttachmentNotExist struct {
|
||||||
ID int64
|
ID int64
|
||||||
|
@ -11,7 +11,7 @@ type MergeStyle string
|
|||||||
const (
|
const (
|
||||||
// MergeStyleMerge create merge commit
|
// MergeStyleMerge create merge commit
|
||||||
MergeStyleMerge MergeStyle = "merge"
|
MergeStyleMerge MergeStyle = "merge"
|
||||||
// MergeStyleRebase rebase before merging
|
// MergeStyleRebase rebase before merging, and fast-forward
|
||||||
MergeStyleRebase MergeStyle = "rebase"
|
MergeStyleRebase MergeStyle = "rebase"
|
||||||
// MergeStyleRebaseMerge rebase before merging with merge commit (--no-ff)
|
// MergeStyleRebaseMerge rebase before merging with merge commit (--no-ff)
|
||||||
MergeStyleRebaseMerge MergeStyle = "rebase-merge"
|
MergeStyleRebaseMerge MergeStyle = "rebase-merge"
|
||||||
|
@ -215,6 +215,7 @@ func (l *LayeredFS) WatchLocalChanges(ctx context.Context, callback func()) {
|
|||||||
log.Error("Unable to list directories for asset local file-system %q: %v", layer.localPath, err)
|
log.Error("Unable to list directories for asset local file-system %q: %v", layer.localPath, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
layerDirs = append(layerDirs, ".")
|
||||||
for _, dir := range layerDirs {
|
for _, dir := range layerDirs {
|
||||||
if err = watcher.Add(util.FilePathJoinAbs(layer.localPath, dir)); err != nil {
|
if err = watcher.Add(util.FilePathJoinAbs(layer.localPath, dir)); err != nil {
|
||||||
log.Error("Unable to watch directory %s: %v", dir, err)
|
log.Error("Unable to watch directory %s: %v", dir, err)
|
||||||
|
@ -108,18 +108,28 @@ func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.A
|
|||||||
|
|
||||||
if doer != nil && !doer.IsGhost() {
|
if doer != nil && !doer.IsGhost() {
|
||||||
// 1. If user is logged in, check all team packages permissions
|
// 1. If user is logged in, check all team packages permissions
|
||||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
|
var err error
|
||||||
|
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(doer.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return accessMode, err
|
return accessMode, err
|
||||||
}
|
}
|
||||||
for _, t := range teams {
|
// If access mode is less than write check every team for more permissions
|
||||||
perm := t.UnitAccessMode(ctx, unit.TypePackages)
|
// The minimum possible access mode is read for org members
|
||||||
if accessMode < perm {
|
if accessMode < perm.AccessModeWrite {
|
||||||
accessMode = perm
|
teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
|
||||||
|
if err != nil {
|
||||||
|
return accessMode, err
|
||||||
|
}
|
||||||
|
for _, t := range teams {
|
||||||
|
perm := t.UnitAccessMode(ctx, unit.TypePackages)
|
||||||
|
if accessMode < perm {
|
||||||
|
accessMode = perm
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if organization.HasOrgOrUserVisible(ctx, pkg.Owner, doer) {
|
}
|
||||||
// 2. If user is non-login, check if org is visible to non-login user
|
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, pkg.Owner, doer) {
|
||||||
|
// 2. If user is unauthorized or no org member, check if org is visible
|
||||||
accessMode = perm.AccessModeRead
|
accessMode = perm.AccessModeRead
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -12,10 +12,31 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
EnvConfigKeyPrefixGitea = "GITEA__"
|
||||||
|
EnvConfigKeySuffixFile = "__FILE"
|
||||||
|
)
|
||||||
|
|
||||||
const escapeRegexpString = "_0[xX](([0-9a-fA-F][0-9a-fA-F])+)_"
|
const escapeRegexpString = "_0[xX](([0-9a-fA-F][0-9a-fA-F])+)_"
|
||||||
|
|
||||||
var escapeRegex = regexp.MustCompile(escapeRegexpString)
|
var escapeRegex = regexp.MustCompile(escapeRegexpString)
|
||||||
|
|
||||||
|
func CollectEnvConfigKeys() (keys []string) {
|
||||||
|
for _, env := range os.Environ() {
|
||||||
|
if strings.HasPrefix(env, EnvConfigKeyPrefixGitea) {
|
||||||
|
k, _, _ := strings.Cut(env, "=")
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearEnvConfigKeys() {
|
||||||
|
for _, k := range CollectEnvConfigKeys() {
|
||||||
|
_ = os.Unsetenv(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// decodeEnvSectionKey will decode a portable string encoded Section__Key pair
|
// decodeEnvSectionKey will decode a portable string encoded Section__Key pair
|
||||||
// Portable strings are considered to be of the form [A-Z0-9_]*
|
// Portable strings are considered to be of the form [A-Z0-9_]*
|
||||||
// We will encode a disallowed value as the UTF8 byte string preceded by _0X and
|
// We will encode a disallowed value as the UTF8 byte string preceded by _0X and
|
||||||
@ -87,7 +108,7 @@ func decodeEnvironmentKey(prefixGitea, suffixFile, envKey string) (ok bool, sect
|
|||||||
return ok, section, key, useFileValue
|
return ok, section, key, useFileValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, envs []string) (changed bool) {
|
func EnvironmentToConfig(cfg ConfigProvider, envs []string) (changed bool) {
|
||||||
for _, kv := range envs {
|
for _, kv := range envs {
|
||||||
idx := strings.IndexByte(kv, '=')
|
idx := strings.IndexByte(kv, '=')
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
@ -97,7 +118,7 @@ func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, env
|
|||||||
// parse the environment variable to config section name and key name
|
// parse the environment variable to config section name and key name
|
||||||
envKey := kv[:idx]
|
envKey := kv[:idx]
|
||||||
envValue := kv[idx+1:]
|
envValue := kv[idx+1:]
|
||||||
ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixGitea, suffixFile, envKey)
|
ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(EnvConfigKeyPrefixGitea, EnvConfigKeySuffixFile, envKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ func TestDecodeEnvironmentKey(t *testing.T) {
|
|||||||
func TestEnvironmentToConfig(t *testing.T) {
|
func TestEnvironmentToConfig(t *testing.T) {
|
||||||
cfg, _ := NewConfigProviderFromData("")
|
cfg, _ := NewConfigProviderFromData("")
|
||||||
|
|
||||||
changed := EnvironmentToConfig(cfg, "GITEA__", "__FILE", nil)
|
changed := EnvironmentToConfig(cfg, nil)
|
||||||
assert.False(t, changed)
|
assert.False(t, changed)
|
||||||
|
|
||||||
cfg, err := NewConfigProviderFromData(`
|
cfg, err := NewConfigProviderFromData(`
|
||||||
@ -81,16 +81,16 @@ key = old
|
|||||||
`)
|
`)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key=new"})
|
changed = EnvironmentToConfig(cfg, []string{"GITEA__sec__key=new"})
|
||||||
assert.True(t, changed)
|
assert.True(t, changed)
|
||||||
assert.Equal(t, "new", cfg.Section("sec").Key("key").String())
|
assert.Equal(t, "new", cfg.Section("sec").Key("key").String())
|
||||||
|
|
||||||
changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key=new"})
|
changed = EnvironmentToConfig(cfg, []string{"GITEA__sec__key=new"})
|
||||||
assert.False(t, changed)
|
assert.False(t, changed)
|
||||||
|
|
||||||
tmpFile := t.TempDir() + "/the-file"
|
tmpFile := t.TempDir() + "/the-file"
|
||||||
_ = os.WriteFile(tmpFile, []byte("value-from-file"), 0o644)
|
_ = os.WriteFile(tmpFile, []byte("value-from-file"), 0o644)
|
||||||
changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key__FILE=" + tmpFile})
|
changed = EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
|
||||||
assert.True(t, changed)
|
assert.True(t, changed)
|
||||||
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
|
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,9 @@ func InitWorkPathAndCfgProvider(getEnvFn func(name string) string, args ArgWorkP
|
|||||||
|
|
||||||
// only read the config but do not load/init anything more, because the AppWorkPath and CustomPath are not ready
|
// only read the config but do not load/init anything more, because the AppWorkPath and CustomPath are not ready
|
||||||
InitCfgProvider(tmpCustomConf.Value)
|
InitCfgProvider(tmpCustomConf.Value)
|
||||||
|
if HasInstallLock(CfgProvider) {
|
||||||
|
ClearEnvConfigKeys() // if the instance has been installed, do not pass the environment variables to sub-processes
|
||||||
|
}
|
||||||
configWorkPath := ConfigSectionKeyString(CfgProvider.Section(""), "WORK_PATH")
|
configWorkPath := ConfigSectionKeyString(CfgProvider.Section(""), "WORK_PATH")
|
||||||
if configWorkPath != "" {
|
if configWorkPath != "" {
|
||||||
if !filepath.IsAbs(configWorkPath) {
|
if !filepath.IsAbs(configWorkPath) {
|
||||||
|
@ -102,7 +102,7 @@ func generateSaveInternalToken(rootCfg ConfigProvider) {
|
|||||||
|
|
||||||
func loadSecurityFrom(rootCfg ConfigProvider) {
|
func loadSecurityFrom(rootCfg ConfigProvider) {
|
||||||
sec := rootCfg.Section("security")
|
sec := rootCfg.Section("security")
|
||||||
InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
|
InstallLock = HasInstallLock(rootCfg)
|
||||||
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
|
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
|
||||||
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
|
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
|
||||||
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
|
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
|
||||||
|
@ -183,10 +183,14 @@ func loadRunModeFrom(rootCfg ConfigProvider) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasInstallLock checks the install-lock in ConfigProvider directly, because sometimes the config file is not loaded into setting variables yet.
|
||||||
|
func HasInstallLock(rootCfg ConfigProvider) bool {
|
||||||
|
return rootCfg.Section("security").Key("INSTALL_LOCK").MustBool(false)
|
||||||
|
}
|
||||||
|
|
||||||
func mustCurrentRunUserMatch(rootCfg ConfigProvider) {
|
func mustCurrentRunUserMatch(rootCfg ConfigProvider) {
|
||||||
// Does not check run user when the "InstallLock" is off.
|
// Does not check run user when the "InstallLock" is off.
|
||||||
installLock := rootCfg.Section("security").Key("INSTALL_LOCK").MustBool(false)
|
if HasInstallLock(rootCfg) {
|
||||||
if installLock {
|
|
||||||
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
||||||
if !match {
|
if !match {
|
||||||
log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
|
log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
|
||||||
|
@ -296,6 +296,8 @@ invalid_password_algorithm = Invalid password hash algorithm
|
|||||||
password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. The argon2 algorithm is rather secure but uses a lot of memory and may be inappropriate for small systems.
|
password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. The argon2 algorithm is rather secure but uses a lot of memory and may be inappropriate for small systems.
|
||||||
enable_update_checker = Enable Update Checker
|
enable_update_checker = Enable Update Checker
|
||||||
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
|
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
|
||||||
|
env_config_keys = Environment Configuration
|
||||||
|
env_config_keys_prompt = The following environment variables will also be applied to your configuration file:
|
||||||
|
|
||||||
[home]
|
[home]
|
||||||
uname_holder = Username or Email Address
|
uname_holder = Username or Email Address
|
||||||
|
@ -12,4 +12,4 @@ djlint = "1.31.1"
|
|||||||
|
|
||||||
[tool.djlint]
|
[tool.djlint]
|
||||||
profile="golang"
|
profile="golang"
|
||||||
ignore="H005,H006,H008,H013,H014,H016,H020,H021,H023,H026,H030,H031,T027"
|
ignore="H005,H006,H008,H013,H016,H020,H021,H026,H030,H031,T027"
|
||||||
|
@ -1034,7 +1034,7 @@ func Routes() *web.Route {
|
|||||||
m.Group("/assets", func() {
|
m.Group("/assets", func() {
|
||||||
m.Combo("").Get(repo.ListReleaseAttachments).
|
m.Combo("").Get(repo.ListReleaseAttachments).
|
||||||
Post(reqToken(), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
|
Post(reqToken(), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
|
||||||
m.Combo("/{asset}").Get(repo.GetReleaseAttachment).
|
m.Combo("/{attachment_id}").Get(repo.GetReleaseAttachment).
|
||||||
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
|
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
|
||||||
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseAttachment)
|
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseAttachment)
|
||||||
})
|
})
|
||||||
@ -1179,7 +1179,7 @@ func Routes() *web.Route {
|
|||||||
m.Combo("").
|
m.Combo("").
|
||||||
Get(repo.ListIssueCommentAttachments).
|
Get(repo.ListIssueCommentAttachments).
|
||||||
Post(reqToken(), mustNotBeArchived, repo.CreateIssueCommentAttachment)
|
Post(reqToken(), mustNotBeArchived, repo.CreateIssueCommentAttachment)
|
||||||
m.Combo("/{asset}").
|
m.Combo("/{attachment_id}").
|
||||||
Get(repo.GetIssueCommentAttachment).
|
Get(repo.GetIssueCommentAttachment).
|
||||||
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
|
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
|
||||||
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueCommentAttachment)
|
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueCommentAttachment)
|
||||||
@ -1231,7 +1231,7 @@ func Routes() *web.Route {
|
|||||||
m.Combo("").
|
m.Combo("").
|
||||||
Get(repo.ListIssueAttachments).
|
Get(repo.ListIssueAttachments).
|
||||||
Post(reqToken(), mustNotBeArchived, repo.CreateIssueAttachment)
|
Post(reqToken(), mustNotBeArchived, repo.CreateIssueAttachment)
|
||||||
m.Combo("/{asset}").
|
m.Combo("/{attachment_id}").
|
||||||
Get(repo.GetIssueAttachment).
|
Get(repo.GetIssueAttachment).
|
||||||
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
|
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
|
||||||
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueAttachment)
|
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueAttachment)
|
||||||
|
@ -64,7 +64,7 @@ func GetIssueAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToAttachment(attach))
|
ctx.JSON(http.StatusOK, convert.ToAPIAttachment(ctx.Repo.Repository, attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListIssueAttachments lists all attachments of the issue
|
// ListIssueAttachments lists all attachments of the issue
|
||||||
@ -194,7 +194,7 @@ func CreateIssueAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
|
ctx.JSON(http.StatusCreated, convert.ToAPIAttachment(ctx.Repo.Repository, attachment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditIssueAttachment updates the given attachment
|
// EditIssueAttachment updates the given attachment
|
||||||
@ -254,7 +254,7 @@ func EditIssueAttachment(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", err)
|
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
|
ctx.JSON(http.StatusCreated, convert.ToAPIAttachment(ctx.Repo.Repository, attachment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueAttachment delete a given attachment
|
// DeleteIssueAttachment delete a given attachment
|
||||||
@ -332,7 +332,7 @@ func getIssueAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getIssueAttachmentSafeRead(ctx *context.APIContext, issue *issues_model.Issue) *repo_model.Attachment {
|
func getIssueAttachmentSafeRead(ctx *context.APIContext, issue *issues_model.Issue) *repo_model.Attachment {
|
||||||
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset"))
|
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("attachment_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
|
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -103,7 +103,7 @@ func ListIssueComments(ctx *context.APIContext) {
|
|||||||
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
|
||||||
apiComments[i] = convert.ToComment(ctx, comments[i])
|
apiComments[i] = convert.ToAPIComment(ctx, ctx.Repo.Repository, comments[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetTotalCountHeader(totalCount)
|
ctx.SetTotalCountHeader(totalCount)
|
||||||
@ -191,7 +191,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) {
|
|||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if comment.Type != issues_model.CommentTypeCode && isXRefCommentAccessible(ctx, ctx.Doer, comment, issue.RepoID) {
|
if comment.Type != issues_model.CommentTypeCode && isXRefCommentAccessible(ctx, ctx.Doer, comment, issue.RepoID) {
|
||||||
comment.Issue = issue
|
comment.Issue = issue
|
||||||
apiComments = append(apiComments, convert.ToTimelineComment(ctx, comment, ctx.Doer))
|
apiComments = append(apiComments, convert.ToTimelineComment(ctx, issue.Repo, comment, ctx.Doer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ func ListRepoIssueComments(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := range comments {
|
for i := range comments {
|
||||||
apiComments[i] = convert.ToComment(ctx, comments[i])
|
apiComments[i] = convert.ToAPIComment(ctx, ctx.Repo.Repository, comments[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetTotalCountHeader(totalCount)
|
ctx.SetTotalCountHeader(totalCount)
|
||||||
@ -368,7 +368,7 @@ func CreateIssueComment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToComment(ctx, comment))
|
ctx.JSON(http.StatusCreated, convert.ToAPIComment(ctx, ctx.Repo.Repository, comment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueComment Get a comment by ID
|
// GetIssueComment Get a comment by ID
|
||||||
@ -436,7 +436,7 @@ func GetIssueComment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToComment(ctx, comment))
|
ctx.JSON(http.StatusOK, convert.ToAPIComment(ctx, ctx.Repo.Repository, comment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditIssueComment modify a comment of an issue
|
// EditIssueComment modify a comment of an issue
|
||||||
@ -561,7 +561,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToComment(ctx, comment))
|
ctx.JSON(http.StatusOK, convert.ToAPIComment(ctx, ctx.Repo.Repository, comment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueComment delete a comment from an issue
|
// DeleteIssueComment delete a comment from an issue
|
||||||
|
@ -68,7 +68,7 @@ func GetIssueCommentAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToAttachment(attachment))
|
ctx.JSON(http.StatusOK, convert.ToAPIAttachment(ctx.Repo.Repository, attachment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListIssueCommentAttachments lists all attachments of the comment
|
// ListIssueCommentAttachments lists all attachments of the comment
|
||||||
@ -110,7 +110,7 @@ func ListIssueCommentAttachments(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToAttachments(comment.Attachments))
|
ctx.JSON(http.StatusOK, convert.ToAPIAttachments(ctx.Repo.Repository, comment.Attachments))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIssueCommentAttachment creates an attachment and saves the given file
|
// CreateIssueCommentAttachment creates an attachment and saves the given file
|
||||||
@ -201,7 +201,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment))
|
ctx.JSON(http.StatusCreated, convert.ToAPIAttachment(ctx.Repo.Repository, attachment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditIssueCommentAttachment updates the given attachment
|
// EditIssueCommentAttachment updates the given attachment
|
||||||
@ -259,7 +259,7 @@ func EditIssueCommentAttachment(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.ToAttachment(attach))
|
ctx.JSON(http.StatusCreated, convert.ToAPIAttachment(ctx.Repo.Repository, attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueCommentAttachment delete a given attachment
|
// DeleteIssueCommentAttachment delete a given attachment
|
||||||
@ -352,7 +352,7 @@ func canUserWriteIssueCommentAttachment(ctx *context.APIContext, comment *issues
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getIssueCommentAttachmentSafeRead(ctx *context.APIContext, comment *issues_model.Comment) *repo_model.Attachment {
|
func getIssueCommentAttachmentSafeRead(ctx *context.APIContext, comment *issues_model.Comment) *repo_model.Attachment {
|
||||||
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset"))
|
attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("attachment_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
|
ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -64,7 +64,7 @@ func GetRelease(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release))
|
ctx.JSON(http.StatusOK, convert.ToAPIRelease(ctx, ctx.Repo.Repository, release))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLatestRelease gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at
|
// GetLatestRelease gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at
|
||||||
@ -105,7 +105,7 @@ func GetLatestRelease(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release))
|
ctx.JSON(http.StatusOK, convert.ToAPIRelease(ctx, ctx.Repo.Repository, release))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListReleases list a repository's releases
|
// ListReleases list a repository's releases
|
||||||
@ -174,7 +174,7 @@ func ListReleases(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rels[i] = convert.ToRelease(ctx, release)
|
rels[i] = convert.ToAPIRelease(ctx, ctx.Repo.Repository, release)
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredCount, err := repo_model.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts)
|
filteredCount, err := repo_model.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts)
|
||||||
@ -272,7 +272,7 @@ func CreateRelease(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusCreated, convert.ToRelease(ctx, rel))
|
ctx.JSON(http.StatusCreated, convert.ToAPIRelease(ctx, ctx.Repo.Repository, rel))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditRelease edit a release
|
// EditRelease edit a release
|
||||||
@ -357,7 +357,7 @@ func EditRelease(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, rel))
|
ctx.JSON(http.StatusOK, convert.ToAPIRelease(ctx, ctx.Repo.Repository, rel))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRelease delete a release from a repository
|
// DeleteRelease delete a release from a repository
|
||||||
|
@ -52,7 +52,7 @@ func GetReleaseAttachment(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/Attachment"
|
// "$ref": "#/responses/Attachment"
|
||||||
|
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
attachID := ctx.ParamsInt64(":asset")
|
attachID := ctx.ParamsInt64(":attachment_id")
|
||||||
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrAttachmentNotExist(err) {
|
if repo_model.IsErrAttachmentNotExist(err) {
|
||||||
@ -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.ToAttachment(attach))
|
ctx.JSON(http.StatusOK, convert.ToAPIAttachment(ctx.Repo.Repository, attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListReleaseAttachments lists all attachments of the release
|
// ListReleaseAttachments lists all attachments of the release
|
||||||
@ -117,7 +117,7 @@ func ListReleaseAttachments(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release).Attachments)
|
ctx.JSON(http.StatusOK, convert.ToAPIRelease(ctx, ctx.Repo.Repository, release).Attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateReleaseAttachment creates an attachment and saves the given file
|
// CreateReleaseAttachment creates an attachment and saves the given file
|
||||||
@ -209,7 +209,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusCreated, convert.ToAttachment(attach))
|
ctx.JSON(http.StatusCreated, convert.ToAPIAttachment(ctx.Repo.Repository, attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditReleaseAttachment updates the given attachment
|
// EditReleaseAttachment updates the given attachment
|
||||||
@ -256,7 +256,7 @@ func EditReleaseAttachment(ctx *context.APIContext) {
|
|||||||
|
|
||||||
// Check if release exists an load release
|
// Check if release exists an load release
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
attachID := ctx.ParamsInt64(":asset")
|
attachID := ctx.ParamsInt64(":attachment_id")
|
||||||
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrAttachmentNotExist(err) {
|
if repo_model.IsErrAttachmentNotExist(err) {
|
||||||
@ -279,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.ToAttachment(attach))
|
ctx.JSON(http.StatusCreated, convert.ToAPIAttachment(ctx.Repo.Repository, attach))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteReleaseAttachment delete a given attachment
|
// DeleteReleaseAttachment delete a given attachment
|
||||||
@ -318,7 +318,7 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
|
|||||||
|
|
||||||
// Check if release exists an load release
|
// Check if release exists an load release
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
attachID := ctx.ParamsInt64(":asset")
|
attachID := ctx.ParamsInt64(":attachment_id")
|
||||||
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrAttachmentNotExist(err) {
|
if repo_model.IsErrAttachmentNotExist(err) {
|
||||||
|
@ -63,7 +63,7 @@ func GetReleaseByTag(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToRelease(ctx, release))
|
ctx.JSON(http.StatusOK, convert.ToAPIRelease(ctx, ctx.Repo.Repository, release))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteReleaseByTag delete a release from a repository by tag name
|
// DeleteReleaseByTag delete a release from a repository by tag name
|
||||||
|
@ -56,6 +56,7 @@ func getSupportedDbTypeNames() (dbTypeNames []map[string]string) {
|
|||||||
func Contexter() func(next http.Handler) http.Handler {
|
func Contexter() func(next http.Handler) http.Handler {
|
||||||
rnd := templates.HTMLRenderer()
|
rnd := templates.HTMLRenderer()
|
||||||
dbTypeNames := getSupportedDbTypeNames()
|
dbTypeNames := getSupportedDbTypeNames()
|
||||||
|
envConfigKeys := setting.CollectEnvConfigKeys()
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||||
base, baseCleanUp := context.NewBaseContext(resp, req)
|
base, baseCleanUp := context.NewBaseContext(resp, req)
|
||||||
@ -70,11 +71,13 @@ func Contexter() func(next http.Handler) http.Handler {
|
|||||||
ctx.AppendContextValue(context.WebContextKey, ctx)
|
ctx.AppendContextValue(context.WebContextKey, ctx)
|
||||||
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
|
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
|
||||||
ctx.Data.MergeFrom(middleware.ContextData{
|
ctx.Data.MergeFrom(middleware.ContextData{
|
||||||
"locale": ctx.Locale,
|
"locale": ctx.Locale,
|
||||||
"Title": ctx.Locale.Tr("install.install"),
|
"Title": ctx.Locale.Tr("install.install"),
|
||||||
"PageIsInstall": true,
|
"PageIsInstall": true,
|
||||||
"DbTypeNames": dbTypeNames,
|
"DbTypeNames": dbTypeNames,
|
||||||
"AllLangs": translation.AllLangs(),
|
"EnvConfigKeys": envConfigKeys,
|
||||||
|
"CustomConfFile": setting.CustomConf,
|
||||||
|
"AllLangs": translation.AllLangs(),
|
||||||
|
|
||||||
"PasswordHashAlgorithms": hash.RecommendedHashAlgorithms,
|
"PasswordHashAlgorithms": hash.RecommendedHashAlgorithms,
|
||||||
})
|
})
|
||||||
@ -218,7 +221,7 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("User confirmed reinstallation of Gitea into a pre-existing database")
|
log.Info("User confirmed re-installation of Gitea into a pre-existing database")
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasPostInstallationUser || dbMigrationVersion > 0 {
|
if hasPostInstallationUser || dbMigrationVersion > 0 {
|
||||||
@ -502,6 +505,8 @@ func SubmitInstall(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setting.EnvironmentToConfig(cfg, os.Environ())
|
||||||
|
|
||||||
if err = cfg.SaveTo(setting.CustomConf); err != nil {
|
if err = cfg.SaveTo(setting.CustomConf); err != nil {
|
||||||
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
|
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
|
||||||
return
|
return
|
||||||
@ -568,6 +573,7 @@ func SubmitInstall(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setting.ClearEnvConfigKeys()
|
||||||
log.Info("First-time run install finished!")
|
log.Info("First-time run install finished!")
|
||||||
InstallDone(ctx)
|
InstallDone(ctx)
|
||||||
|
|
||||||
|
@ -2058,7 +2058,7 @@ func GetIssueInfo(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue))
|
ctx.JSON(http.StatusOK, convert.ToIssue(ctx, issue))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssueTitle change issue's title
|
// UpdateIssueTitle change issue's title
|
||||||
@ -2563,7 +2563,7 @@ func SearchIssues(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetTotalCountHeader(filteredCount)
|
ctx.SetTotalCountHeader(filteredCount)
|
||||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
|
ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserIDForFilter(ctx *context.Context, queryName string) int64 {
|
func getUserIDForFilter(ctx *context.Context, queryName string) int64 {
|
||||||
@ -2724,7 +2724,7 @@ func ListIssues(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetTotalCountHeader(filteredCount)
|
ctx.SetTotalCountHeader(filteredCount)
|
||||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
|
ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues))
|
||||||
}
|
}
|
||||||
|
|
||||||
func BatchDeleteIssues(ctx *context.Context) {
|
func BatchDeleteIssues(ctx *context.Context) {
|
||||||
@ -3290,7 +3290,7 @@ func GetIssueAttachments(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
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.ToAttachment(issue.Attachments[i])
|
attachments[i] = convert.ToAttachment(ctx.Repo.Repository, issue.Attachments[i])
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, attachments)
|
ctx.JSON(http.StatusOK, attachments)
|
||||||
}
|
}
|
||||||
@ -3314,7 +3314,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.ToAttachment(comment.Attachments[i]))
|
attachments = append(attachments, convert.ToAttachment(ctx.Repo.Repository, comment.Attachments[i]))
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, attachments)
|
ctx.JSON(http.StatusOK, attachments)
|
||||||
}
|
}
|
||||||
|
@ -723,6 +723,9 @@ func ViewPullCommits(ctx *context.Context) {
|
|||||||
ctx.Data["Commits"] = commits
|
ctx.Data["Commits"] = commits
|
||||||
ctx.Data["CommitCount"] = len(commits)
|
ctx.Data["CommitCount"] = len(commits)
|
||||||
|
|
||||||
|
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
||||||
|
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.Doer.ID)
|
||||||
|
|
||||||
getBranchData(ctx, issue)
|
getBranchData(ctx, issue)
|
||||||
ctx.HTML(http.StatusOK, tplPullCommits)
|
ctx.HTML(http.StatusOK, tplPullCommits)
|
||||||
}
|
}
|
||||||
|
@ -982,7 +982,7 @@ func renderCode(ctx *context.Context) {
|
|||||||
ctx.ServerError("GetBaseRepo", err)
|
ctx.ServerError("GetBaseRepo", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID)
|
ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID, ctx.Repo.Repository.DefaultBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetRecentlyPushedBranches", err)
|
ctx.ServerError("GetRecentlyPushedBranches", err)
|
||||||
return
|
return
|
||||||
|
@ -186,7 +186,7 @@ func NotificationStatusPost(ctx *context.Context) {
|
|||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["Link"] = setting.AppURL + "notifications"
|
ctx.Data["Link"] = setting.AppSubURL + "/notifications"
|
||||||
ctx.Data["SequenceNumber"] = ctx.Req.PostFormValue("sequence-number")
|
ctx.Data["SequenceNumber"] = ctx.Req.PostFormValue("sequence-number")
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplNotificationDiv)
|
ctx.HTML(http.StatusOK, tplNotificationDiv)
|
||||||
|
@ -171,7 +171,7 @@ func (n *actionsNotifier) NotifyCreateIssueComment(ctx context.Context, doer *us
|
|||||||
WithPayload(&api.IssueCommentPayload{
|
WithPayload(&api.IssueCommentPayload{
|
||||||
Action: api.HookIssueCommentCreated,
|
Action: api.HookIssueCommentCreated,
|
||||||
Issue: convert.ToAPIIssue(ctx, issue),
|
Issue: convert.ToAPIIssue(ctx, issue),
|
||||||
Comment: convert.ToComment(ctx, comment),
|
Comment: convert.ToAPIComment(ctx, repo, comment),
|
||||||
Repository: convert.ToRepo(ctx, repo, permission),
|
Repository: convert.ToRepo(ctx, repo, permission),
|
||||||
Sender: convert.ToUser(ctx, doer, nil),
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
IsPull: true,
|
IsPull: true,
|
||||||
@ -185,7 +185,7 @@ func (n *actionsNotifier) NotifyCreateIssueComment(ctx context.Context, doer *us
|
|||||||
WithPayload(&api.IssueCommentPayload{
|
WithPayload(&api.IssueCommentPayload{
|
||||||
Action: api.HookIssueCommentCreated,
|
Action: api.HookIssueCommentCreated,
|
||||||
Issue: convert.ToAPIIssue(ctx, issue),
|
Issue: convert.ToAPIIssue(ctx, issue),
|
||||||
Comment: convert.ToComment(ctx, comment),
|
Comment: convert.ToAPIComment(ctx, repo, comment),
|
||||||
Repository: convert.ToRepo(ctx, repo, permission),
|
Repository: convert.ToRepo(ctx, repo, permission),
|
||||||
Sender: convert.ToUser(ctx, doer, nil),
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
IsPull: false,
|
IsPull: false,
|
||||||
|
@ -260,7 +260,7 @@ func notifyRelease(ctx context.Context, doer *user_model.User, rel *repo_model.R
|
|||||||
WithRef(git.RefNameFromTag(rel.TagName).String()).
|
WithRef(git.RefNameFromTag(rel.TagName).String()).
|
||||||
WithPayload(&api.ReleasePayload{
|
WithPayload(&api.ReleasePayload{
|
||||||
Action: action,
|
Action: action,
|
||||||
Release: convert.ToRelease(ctx, rel),
|
Release: convert.ToAPIRelease(ctx, rel.Repo, rel),
|
||||||
Repository: convert.ToRepo(ctx, rel.Repo, permission),
|
Repository: convert.ToRepo(ctx, rel.Repo, permission),
|
||||||
Sender: convert.ToUser(ctx, doer, nil),
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
}).
|
}).
|
||||||
|
@ -37,7 +37,7 @@ func ToActivity(ctx context.Context, ac *activities_model.Action, doer *user_mod
|
|||||||
|
|
||||||
if ac.Comment != nil {
|
if ac.Comment != nil {
|
||||||
result.CommentID = ac.CommentID
|
result.CommentID = ac.CommentID
|
||||||
result.Comment = ToComment(ctx, ac.Comment)
|
result.Comment = ToAPIComment(ctx, ac.Repo, ac.Comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -4,12 +4,38 @@
|
|||||||
package convert
|
package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToAttachment converts models.Attachment to api.Attachment
|
func WebAssetDownloadURL(repo *repo_model.Repository, attach *repo_model.Attachment) string {
|
||||||
func ToAttachment(a *repo_model.Attachment) *api.Attachment {
|
return attach.DownloadURL()
|
||||||
|
}
|
||||||
|
|
||||||
|
func APIAssetDownloadURL(repo *repo_model.Repository, attach *repo_model.Attachment) string {
|
||||||
|
if attach.CustomDownloadURL != "" {
|
||||||
|
return attach.CustomDownloadURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id}
|
||||||
|
return setting.AppURL + "api/repos/" + repo.FullName() + "/releases/" + strconv.FormatInt(attach.ReleaseID, 10) + "/assets/" + strconv.FormatInt(attach.ID, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToAttachment converts models.Attachment to api.Attachment for API usage
|
||||||
|
func ToAttachment(repo *repo_model.Repository, a *repo_model.Attachment) *api.Attachment {
|
||||||
|
return toAttachment(repo, a, WebAssetDownloadURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToAPIAttachment converts models.Attachment to api.Attachment for API usage
|
||||||
|
func ToAPIAttachment(repo *repo_model.Repository, a *repo_model.Attachment) *api.Attachment {
|
||||||
|
return toAttachment(repo, a, APIAssetDownloadURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toAttachment converts models.Attachment to api.Attachment for API usage
|
||||||
|
func toAttachment(repo *repo_model.Repository, a *repo_model.Attachment, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Attachment {
|
||||||
return &api.Attachment{
|
return &api.Attachment{
|
||||||
ID: a.ID,
|
ID: a.ID,
|
||||||
Name: a.Name,
|
Name: a.Name,
|
||||||
@ -17,14 +43,18 @@ func ToAttachment(a *repo_model.Attachment) *api.Attachment {
|
|||||||
DownloadCount: a.DownloadCount,
|
DownloadCount: a.DownloadCount,
|
||||||
Size: a.Size,
|
Size: a.Size,
|
||||||
UUID: a.UUID,
|
UUID: a.UUID,
|
||||||
DownloadURL: a.DownloadURL(),
|
DownloadURL: getDownloadURL(repo, a), // for web request json and api request json, return different download urls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToAttachments(attachments []*repo_model.Attachment) []*api.Attachment {
|
func ToAPIAttachments(repo *repo_model.Repository, attachments []*repo_model.Attachment) []*api.Attachment {
|
||||||
|
return toAttachments(repo, attachments, APIAssetDownloadURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toAttachments(repo *repo_model.Repository, attachments []*repo_model.Attachment, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) []*api.Attachment {
|
||||||
converted := make([]*api.Attachment, 0, len(attachments))
|
converted := make([]*api.Attachment, 0, len(attachments))
|
||||||
for _, attachment := range attachments {
|
for _, attachment := range attachments {
|
||||||
converted = append(converted, ToAttachment(attachment))
|
converted = append(converted, toAttachment(repo, attachment, getDownloadURL))
|
||||||
}
|
}
|
||||||
return converted
|
return converted
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,19 @@ import (
|
|||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ToIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
||||||
|
return toIssue(ctx, issue, WebAssetDownloadURL)
|
||||||
|
}
|
||||||
|
|
||||||
// ToAPIIssue converts an Issue to API format
|
// ToAPIIssue converts an Issue to API format
|
||||||
// it assumes some fields assigned with values:
|
// it assumes some fields assigned with values:
|
||||||
// Required - Poster, Labels,
|
// Required - Poster, Labels,
|
||||||
// Optional - Milestone, Assignee, PullRequest
|
// Optional - Milestone, Assignee, PullRequest
|
||||||
func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
||||||
|
return toIssue(ctx, issue, APIAssetDownloadURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue {
|
||||||
if err := issue.LoadLabels(ctx); err != nil {
|
if err := issue.LoadLabels(ctx); err != nil {
|
||||||
return &api.Issue{}
|
return &api.Issue{}
|
||||||
}
|
}
|
||||||
@ -40,7 +48,7 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
|||||||
Poster: ToUser(ctx, issue.Poster, nil),
|
Poster: ToUser(ctx, issue.Poster, nil),
|
||||||
Title: issue.Title,
|
Title: issue.Title,
|
||||||
Body: issue.Content,
|
Body: issue.Content,
|
||||||
Attachments: ToAttachments(issue.Attachments),
|
Attachments: toAttachments(issue.Repo, issue.Attachments, getDownloadURL),
|
||||||
Ref: issue.Ref,
|
Ref: issue.Ref,
|
||||||
State: issue.State(),
|
State: issue.State(),
|
||||||
IsLocked: issue.IsLocked,
|
IsLocked: issue.IsLocked,
|
||||||
@ -105,6 +113,15 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
|||||||
return apiIssue
|
return apiIssue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToIssueList converts an IssueList to API format
|
||||||
|
func ToIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue {
|
||||||
|
result := make([]*api.Issue, len(il))
|
||||||
|
for i := range il {
|
||||||
|
result[i] = ToIssue(ctx, il[i])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// ToAPIIssueList converts an IssueList to API format
|
// ToAPIIssueList converts an IssueList to API format
|
||||||
func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue {
|
func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue {
|
||||||
result := make([]*api.Issue, len(il))
|
result := make([]*api.Issue, len(il))
|
||||||
|
@ -14,8 +14,8 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToComment converts a issues_model.Comment to the api.Comment format
|
// ToAPIComment converts a issues_model.Comment to the api.Comment format for API usage
|
||||||
func ToComment(ctx context.Context, c *issues_model.Comment) *api.Comment {
|
func ToAPIComment(ctx context.Context, repo *repo_model.Repository, c *issues_model.Comment) *api.Comment {
|
||||||
return &api.Comment{
|
return &api.Comment{
|
||||||
ID: c.ID,
|
ID: c.ID,
|
||||||
Poster: ToUser(ctx, c.Poster, nil),
|
Poster: ToUser(ctx, c.Poster, nil),
|
||||||
@ -23,14 +23,14 @@ func ToComment(ctx context.Context, c *issues_model.Comment) *api.Comment {
|
|||||||
IssueURL: c.IssueURL(),
|
IssueURL: c.IssueURL(),
|
||||||
PRURL: c.PRURL(),
|
PRURL: c.PRURL(),
|
||||||
Body: c.Content,
|
Body: c.Content,
|
||||||
Attachments: ToAttachments(c.Attachments),
|
Attachments: ToAPIAttachments(repo, c.Attachments),
|
||||||
Created: c.CreatedUnix.AsTime(),
|
Created: c.CreatedUnix.AsTime(),
|
||||||
Updated: c.UpdatedUnix.AsTime(),
|
Updated: c.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTimelineComment converts a issues_model.Comment to the api.TimelineComment format
|
// ToTimelineComment converts a issues_model.Comment to the api.TimelineComment format
|
||||||
func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_model.User) *api.TimelineComment {
|
func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issues_model.Comment, doer *user_model.User) *api.TimelineComment {
|
||||||
err := c.LoadMilestone(ctx)
|
err := c.LoadMilestone(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LoadMilestone: %v", err)
|
log.Error("LoadMilestone: %v", err)
|
||||||
@ -143,7 +143,7 @@ func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_
|
|||||||
log.Error("LoadPoster: %v", err)
|
log.Error("LoadPoster: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
comment.RefComment = ToComment(ctx, com)
|
comment.RefComment = ToAPIComment(ctx, repo, com)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Label != nil {
|
if c.Label != nil {
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToRelease convert a repo_model.Release to api.Release
|
// ToAPIRelease convert a repo_model.Release to api.Release
|
||||||
func ToRelease(ctx context.Context, r *repo_model.Release) *api.Release {
|
func ToAPIRelease(ctx context.Context, repo *repo_model.Repository, r *repo_model.Release) *api.Release {
|
||||||
return &api.Release{
|
return &api.Release{
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
TagName: r.TagName,
|
TagName: r.TagName,
|
||||||
@ -27,6 +27,6 @@ func ToRelease(ctx context.Context, r *repo_model.Release) *api.Release {
|
|||||||
CreatedAt: r.CreatedUnix.AsTime(),
|
CreatedAt: r.CreatedUnix.AsTime(),
|
||||||
PublishedAt: r.CreatedUnix.AsTime(),
|
PublishedAt: r.CreatedUnix.AsTime(),
|
||||||
Publisher: ToUser(ctx, r.Publisher, nil),
|
Publisher: ToUser(ctx, r.Publisher, nil),
|
||||||
Attachments: ToAttachments(r.Attachments),
|
Attachments: ToAPIAttachments(repo, r.Attachments),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,11 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mergeStyle == repo_model.MergeStyleRebase {
|
||||||
|
// for fast-forward rebase, do not amend the last commit if there is no template
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// Squash merge has a different from other styles.
|
// Squash merge has a different from other styles.
|
||||||
if mergeStyle == repo_model.MergeStyleSquash {
|
if mergeStyle == repo_model.MergeStyleSquash {
|
||||||
return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), "", nil
|
return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), "", nil
|
||||||
|
@ -386,7 +386,7 @@ func (m *webhookNotifier) NotifyUpdateComment(ctx context.Context, doer *user_mo
|
|||||||
if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{
|
if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{
|
||||||
Action: api.HookIssueCommentEdited,
|
Action: api.HookIssueCommentEdited,
|
||||||
Issue: convert.ToAPIIssue(ctx, c.Issue),
|
Issue: convert.ToAPIIssue(ctx, c.Issue),
|
||||||
Comment: convert.ToComment(ctx, c),
|
Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c),
|
||||||
Changes: &api.ChangesPayload{
|
Changes: &api.ChangesPayload{
|
||||||
Body: &api.ChangesFromPayload{
|
Body: &api.ChangesFromPayload{
|
||||||
From: oldContent,
|
From: oldContent,
|
||||||
@ -414,7 +414,7 @@ func (m *webhookNotifier) NotifyCreateIssueComment(ctx context.Context, doer *us
|
|||||||
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{
|
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{
|
||||||
Action: api.HookIssueCommentCreated,
|
Action: api.HookIssueCommentCreated,
|
||||||
Issue: convert.ToAPIIssue(ctx, issue),
|
Issue: convert.ToAPIIssue(ctx, issue),
|
||||||
Comment: convert.ToComment(ctx, comment),
|
Comment: convert.ToAPIComment(ctx, repo, comment),
|
||||||
Repository: convert.ToRepo(ctx, repo, permission),
|
Repository: convert.ToRepo(ctx, repo, permission),
|
||||||
Sender: convert.ToUser(ctx, doer, nil),
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
IsPull: issue.IsPull,
|
IsPull: issue.IsPull,
|
||||||
@ -451,7 +451,7 @@ func (m *webhookNotifier) NotifyDeleteComment(ctx context.Context, doer *user_mo
|
|||||||
if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{
|
if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{
|
||||||
Action: api.HookIssueCommentDeleted,
|
Action: api.HookIssueCommentDeleted,
|
||||||
Issue: convert.ToAPIIssue(ctx, comment.Issue),
|
Issue: convert.ToAPIIssue(ctx, comment.Issue),
|
||||||
Comment: convert.ToComment(ctx, comment),
|
Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment),
|
||||||
Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission),
|
Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission),
|
||||||
Sender: convert.ToUser(ctx, doer, nil),
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
IsPull: comment.Issue.IsPull,
|
IsPull: comment.Issue.IsPull,
|
||||||
@ -808,7 +808,7 @@ func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model
|
|||||||
permission, _ := access_model.GetUserRepoPermission(ctx, rel.Repo, doer)
|
permission, _ := access_model.GetUserRepoPermission(ctx, rel.Repo, doer)
|
||||||
if err := PrepareWebhooks(ctx, EventSource{Repository: rel.Repo}, webhook_module.HookEventRelease, &api.ReleasePayload{
|
if err := PrepareWebhooks(ctx, EventSource{Repository: rel.Repo}, webhook_module.HookEventRelease, &api.ReleasePayload{
|
||||||
Action: action,
|
Action: action,
|
||||||
Release: convert.ToRelease(ctx, rel),
|
Release: convert.ToAPIRelease(ctx, rel.Repo, rel),
|
||||||
Repository: convert.ToRepo(ctx, rel.Repo, permission),
|
Repository: convert.ToRepo(ctx, rel.Repo, permission),
|
||||||
Sender: convert.ToUser(ctx, doer, nil),
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -106,7 +106,6 @@
|
|||||||
<input id="attribute_avatar" name="attribute_avatar" value="{{$cfg.AttributeAvatar}}" placeholder="jpegPhoto">
|
<input id="attribute_avatar" name="attribute_avatar" value="{{$cfg.AttributeAvatar}}" placeholder="jpegPhoto">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- ldap group begin -->
|
<!-- ldap group begin -->
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
<button class="item gt-w-auto ui icon mini button gt-p-3 gt-m-0" id="navbar-expand-toggle">{{svg "octicon-three-bars"}}</button>
|
<button class="item gt-w-auto ui icon mini button gt-p-3 gt-m-0" id="navbar-expand-toggle">{{svg "octicon-three-bars"}}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- navbar links non-mobile -->
|
<!-- navbar links non-mobile -->
|
||||||
{{if and .IsSigned .MustChangePassword}}
|
{{if and .IsSigned .MustChangePassword}}
|
||||||
{{/* No links */}}
|
{{/* No links */}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
<div role="main" aria-label="{{.Title}}" class="page-content install">
|
<div role="main" aria-label="{{.Title}}" class="page-content install">
|
||||||
<div class="ui middle very relaxed page grid">
|
<div class="ui grid install-config-container">
|
||||||
<div class="sixteen wide center aligned centered column">
|
<div class="sixteen wide center aligned centered column">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{.locale.Tr "install.title"}}
|
{{.locale.Tr "install.title"}}
|
||||||
@ -149,19 +149,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<label for="enable_update_checker">{{.locale.Tr "install.enable_update_checker"}}</label>
|
<label>{{.locale.Tr "install.enable_update_checker"}}</label>
|
||||||
<input name="enable_update_checker" type="checkbox">
|
<input name="enable_update_checker" type="checkbox">
|
||||||
</div>
|
</div>
|
||||||
<span class="help">{{.locale.Tr "install.enable_update_checker_helper"}}</span>
|
<span class="help">{{.locale.Tr "install.enable_update_checker_helper"}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Optional Settings -->
|
<!-- Optional Settings -->
|
||||||
<h4 class="ui dividing header">{{.locale.Tr "install.optional_title"}}</h4>
|
<h4 class="ui dividing header">{{.locale.Tr "install.optional_title"}}</h4>
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<details class="optional field">
|
<details class="optional field">
|
||||||
<summary class="title gt-py-3{{if .Err_SMTP}} text red{{end}}">
|
<summary class="right-content gt-py-3{{if .Err_SMTP}} text red{{end}}">
|
||||||
{{.locale.Tr "install.email_title"}}
|
{{.locale.Tr "install.email_title"}}
|
||||||
</summary>
|
</summary>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
@ -201,7 +200,7 @@
|
|||||||
|
|
||||||
<!-- Server and other services -->
|
<!-- Server and other services -->
|
||||||
<details class="optional field">
|
<details class="optional field">
|
||||||
<summary class="title gt-py-3{{if .Err_Services}} text red{{end}}">
|
<summary class="right-content gt-py-3{{if .Err_Services}} text red{{end}}">
|
||||||
{{.locale.Tr "install.server_service_title"}}
|
{{.locale.Tr "install.server_service_title"}}
|
||||||
</summary>
|
</summary>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
@ -299,7 +298,7 @@
|
|||||||
|
|
||||||
<!-- Admin -->
|
<!-- Admin -->
|
||||||
<details class="optional field">
|
<details class="optional field">
|
||||||
<summary class="title gt-py-3{{if .Err_Admin}} text red{{end}}">
|
<summary class="right-content gt-py-3{{if .Err_Admin}} text red{{end}}">
|
||||||
{{.locale.Tr "install.admin_title"}}
|
{{.locale.Tr "install.admin_title"}}
|
||||||
</summary>
|
</summary>
|
||||||
<p class="center">{{.locale.Tr "install.admin_setting_desc"}}</p>
|
<p class="center">{{.locale.Tr "install.admin_setting_desc"}}</p>
|
||||||
@ -321,10 +320,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
{{if .EnvConfigKeys}}
|
||||||
|
<!-- Environment Config -->
|
||||||
|
<h4 class="ui dividing header">{{.locale.Tr "install.env_config_keys"}}</h4>
|
||||||
|
<div class="inline field">
|
||||||
|
<div class="right-content">
|
||||||
|
{{.locale.Tr "install.env_config_keys_prompt"}}
|
||||||
|
</div>
|
||||||
|
<div class="right-content gt-mt-3">
|
||||||
|
{{range .EnvConfigKeys}}<span class="ui label">{{.}}</span>{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
<div class="right-content">
|
||||||
<button class="ui primary button">{{.locale.Tr "install.install_btn_confirm"}}</button>
|
These configuration options will be written into: {{.CustomConfFile}}
|
||||||
|
</div>
|
||||||
|
<div class="right-content gt-mt-3">
|
||||||
|
<button class="ui primary button">{{.locale.Tr "install.install_btn_confirm"}}</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
</form>
|
</form>
|
||||||
<div class="ui {{if .PackageDescriptors}}issue list{{end}}">
|
<div class="ui {{if .PackageDescriptors}}issue list{{end}}">
|
||||||
{{range .PackageDescriptors}}
|
{{range .PackageDescriptors}}
|
||||||
<li class="item gt-df gt-py-3">
|
<li class="item">
|
||||||
<div class="issue-item-main">
|
<div class="issue-item-main">
|
||||||
<div class="issue-item-top-row">
|
<div class="issue-item-title">
|
||||||
<a class="title" href="{{.FullWebLink}}">{{.Package.Name}}</a>
|
<a class="title" href="{{.FullWebLink}}">{{.Package.Name}}</a>
|
||||||
<span class="ui label">{{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}</span>
|
<span class="ui label">{{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="desc issue-item-bottom-row">
|
<div class="issue-item-body">
|
||||||
{{$timeStr := TimeSinceUnix .Version.CreatedUnix $.locale}}
|
{{$timeStr := TimeSinceUnix .Version.CreatedUnix $.locale}}
|
||||||
{{$hasRepositoryAccess := false}}
|
{{$hasRepositoryAccess := false}}
|
||||||
{{if .Repository}}
|
{{if .Repository}}
|
||||||
|
@ -20,12 +20,12 @@
|
|||||||
</form>
|
</form>
|
||||||
<div class="ui {{if .PackageDescriptors}}issue list{{end}}">
|
<div class="ui {{if .PackageDescriptors}}issue list{{end}}">
|
||||||
{{range .PackageDescriptors}}
|
{{range .PackageDescriptors}}
|
||||||
<li class="item gt-df gt-py-3">
|
<li class="item">
|
||||||
<div class="issue-item-main">
|
<div class="issue-item-main">
|
||||||
<div class="issue-item-top-row">
|
<div class="issue-item-title">
|
||||||
<a class="title" href="{{.FullWebLink}}">{{.Version.LowerVersion}}</a>
|
<a class="title" href="{{.FullWebLink}}">{{.Version.LowerVersion}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="desc issue-item-bottom-row">
|
<div class="issue-item-body">
|
||||||
{{$.locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix $.locale) .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}}
|
{{$.locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix $.locale) .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,17 +6,17 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range .Runs}}
|
{{range .Runs}}
|
||||||
<li class="item gt-df gt-py-3">
|
<li class="item action-item">
|
||||||
<div class="issue-item-left issue-item-icon gt-df gt-items-start">
|
<div class="issue-item-left issue-item-icon">
|
||||||
{{template "repo/actions/status" (dict "status" .Status.String "locale" $.locale)}}
|
{{template "repo/actions/status" (dict "status" .Status.String "locale" $.locale)}}
|
||||||
</div>
|
</div>
|
||||||
<div class="issue-item-main action-item-main">
|
<div class="issue-item-main action-item-main">
|
||||||
<div class="issue-item-top-row">
|
<div class="issue-item-title">
|
||||||
<a class="index gt-no-underline title action-item-title" title="{{.Title}}" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
|
<a class="index gt-no-underline title action-item-title" title="{{.Title}}" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
|
||||||
{{- .Title -}}
|
{{- .Title -}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="desc issue-item-bottom-row">
|
<div class="issue-item-body">
|
||||||
<b>{{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}</b>
|
<b>{{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}</b>
|
||||||
: {{$.locale.Tr "actions.runs.commit"}}
|
: {{$.locale.Tr "actions.runs.commit"}}
|
||||||
<a href="{{$.RepoLink}}/commit/{{.CommitSHA}}">{{ShortSha .CommitSHA}}</a>
|
<a href="{{$.RepoLink}}/commit/{{.CommitSHA}}">{{ShortSha .CommitSHA}}</a>
|
||||||
@ -32,8 +32,8 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="action-item-right">
|
<div class="action-item-right">
|
||||||
<div>{{svg "octicon-calendar" 16 "gt-mr-2"}}{{TimeSinceUnix .Updated $.locale}}</div>
|
<div class="flex-text-block">{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated $.locale}}</div>
|
||||||
<div>{{svg "octicon-stopwatch" 16 "gt-mr-2"}}{{.Duration}}</div>
|
<div class="flex-text-block">{{svg "octicon-stopwatch" 16}}{{.Duration}}</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
{{template "repo/diff/stats" dict "file" . "root" $}}
|
{{template "repo/diff/stats" dict "file" . "root" $}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<span class="file gt-mono"><a class="muted file-link" title="{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}" href="#diff-{{$file.NameHash}}">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</a>{{if .IsLFSFile}} ({{$.locale.Tr "repo.stored_lfs"}}){{end}}</span>
|
<span class="file gt-mono"><a class="muted file-link" title="{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}" href="#diff-{{$file.NameHash}}">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</a>{{if .IsLFSFile}} ({{$.locale.Tr "repo.stored_lfs"}}){{end}}</span>
|
||||||
<button class="btn interact-fg gt-p-3" data-clipboard-text="{{$file.Name}}">{{svg "octicon-copy" 14}}</button>
|
<button class="btn interact-fg gt-p-3" data-clipboard-text="{{$file.Name}}">{{svg "octicon-copy" 14}}</button>
|
||||||
{{if $file.IsGenerated}}
|
{{if $file.IsGenerated}}
|
||||||
<span class="ui label">{{$.locale.Tr "repo.diff.generated"}}</span>
|
<span class="ui label">{{$.locale.Tr "repo.diff.generated"}}</span>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
<span class="ui label">{{$.locale.Tr "repo.diff.vendored"}}</span>
|
<span class="ui label">{{$.locale.Tr "repo.diff.vendored"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and $file.Mode $file.OldMode}}
|
{{if and $file.Mode $file.OldMode}}
|
||||||
<span class="gt-ml-4 gt-mono">{{$file.OldMode}} → {{$file.Mode}}</span>
|
<span class="gt-ml-4 gt-mono">{{$file.OldMode}} → {{$file.Mode}}</span>
|
||||||
{{else if $file.Mode}}
|
{{else if $file.Mode}}
|
||||||
<span class="gt-ml-4 gt-mono">{{$file.Mode}}</span>
|
<span class="gt-ml-4 gt-mono">{{$file.Mode}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -52,8 +52,6 @@
|
|||||||
{{template "repo/editor/commit_form" .}}
|
{{template "repo/editor/commit_form" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="edit-empty-content-modal">
|
<div class="ui g-modal-confirm modal" id="edit-empty-content-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-file"}}
|
{{svg "octicon-file"}}
|
||||||
@ -73,6 +71,5 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -44,30 +44,25 @@
|
|||||||
<label for="website">{{.locale.Tr "repo.settings.site"}}</label>
|
<label for="website">{{.locale.Tr "repo.settings.site"}}</label>
|
||||||
<input id="website" name="website" type="url" maxlength="1024" value="{{.Repository.Website}}">
|
<input id="website" name="website" type="url" maxlength="1024" value="{{.Repository.Website}}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui green button">{{$.locale.Tr "repo.settings.update_settings"}}</button>
|
<button class="ui green button">{{$.locale.Tr "repo.settings.update_settings"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
|
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label for="avatar">{{.locale.Tr "settings.choose_new_avatar"}}</label>
|
<label for="avatar">{{.locale.Tr "settings.choose_new_avatar"}}</label>
|
||||||
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
||||||
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{{/* These variables exist to make the logic in the Settings window easier to comprehend and are not used later on. */}}
|
{{/* These variables exist to make the logic in the Settings window easier to comprehend and are not used later on. */}}
|
||||||
{{$newMirrorsPartiallyEnabled := or (not .DisableNewPullMirrors) (not .DisableNewPushMirrors)}}
|
{{$newMirrorsPartiallyEnabled := or (not .DisableNewPullMirrors) (not .DisableNewPushMirrors)}}
|
||||||
{{/* .Repository.IsMirror is not always reliable if the repository is not actively acting as a mirror because of errors. */}}
|
{{/* .Repository.IsMirror is not always reliable if the repository is not actively acting as a mirror because of errors. */}}
|
||||||
|
@ -75,5 +75,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -30,16 +30,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
{{if and .Commits (gt .CommitCount 0)}}
|
{{if and .Commits (gt .CommitCount 0)}}
|
||||||
{{template "repo/commits_list" .}}
|
{{template "repo/commits_list" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<div class="issue list">
|
<div class="issue list">
|
||||||
{{$approvalCounts := .ApprovalCounts}}
|
{{$approvalCounts := .ApprovalCounts}}
|
||||||
{{range .Issues}}
|
{{range .Issues}}
|
||||||
<li class="item gt-df gt-py-3">
|
<li class="item">
|
||||||
<div class="issue-item-left gt-df gt-items-start">
|
<div class="issue-item-left">
|
||||||
{{if $.CanWriteIssuesOrPulls}}
|
{{if $.CanWriteIssuesOrPulls}}
|
||||||
<input type="checkbox" autocomplete="off" class="issue-checkbox gt-mt-2 gt-mr-4" data-issue-id={{.ID}} aria-label="{{$.locale.Tr "repo.issues.action_check"}} "{{.Title}}"">
|
<input type="checkbox" autocomplete="off" class="issue-checkbox gt-mt-2 gt-mr-4" data-issue-id={{.ID}} aria-label="{{$.locale.Tr "repo.issues.action_check"}} "{{.Title}}"">
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -11,21 +11,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="issue-item-main">
|
<div class="issue-item-main">
|
||||||
<div class="issue-item-top-row">
|
<div class="issue-item-header">
|
||||||
<a class="title gt-no-underline issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji $.Context .Title | RenderCodeBlock}}</a>
|
<div class="issue-item-title">
|
||||||
{{if .IsPull}}
|
<a class="title gt-no-underline issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji $.Context .Title | RenderCodeBlock}}</a>
|
||||||
{{if (index $.CommitStatuses .PullRequest.ID)}}
|
{{if .IsPull}}
|
||||||
{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}}
|
{{if (index $.CommitStatuses .PullRequest.ID)}}
|
||||||
|
{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
<span class="labels-list gt-ml-2">
|
||||||
|
{{range .Labels}}
|
||||||
|
<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{RenderLabel $.Context .}}</a>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{if or .TotalTrackedTime .Assignees .NumComments}}
|
||||||
|
<div class="issue-item-right">
|
||||||
|
{{if .TotalTrackedTime}}
|
||||||
|
<div class="text grey flex-text-block">
|
||||||
|
{{svg "octicon-clock" 16}}
|
||||||
|
{{.TotalTrackedTime | Sec2Time}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if .Assignees}}
|
||||||
|
<div class="text grey">
|
||||||
|
{{range .Assignees}}
|
||||||
|
<a class="ui assignee gt-no-underline" href="{{.HomeLink}}" data-tooltip-content="{{.GetDisplayName}}">
|
||||||
|
{{avatar $.Context . 20}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if .NumComments}}
|
||||||
|
<div class="text grey">
|
||||||
|
<a class="gt-no-underline muted flex-text-inline" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
|
||||||
|
{{svg "octicon-comment" 16}}{{.NumComments}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span class="labels-list gt-ml-2">
|
|
||||||
{{range .Labels}}
|
|
||||||
<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{RenderLabel $.Context .}}</a>
|
|
||||||
{{end}}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="desc issue-item-bottom-row">
|
<div class="issue-item-body">
|
||||||
<a class="index gt-ml-0 gt-mr-2" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
|
<a class="index" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
|
||||||
{{if eq $.listType "dashboard"}}
|
{{if eq $.listType "dashboard"}}
|
||||||
{{.Repo.FullName}}#{{.Index}}
|
{{.Repo.FullName}}#{{.Index}}
|
||||||
{{else}}
|
{{else}}
|
||||||
@ -41,14 +69,14 @@
|
|||||||
{{$.locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}}
|
{{$.locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsPull}}
|
{{if .IsPull}}
|
||||||
<div class="branches gt-df gt-ac">
|
<div class="branches flex-text-inline">
|
||||||
<div class="branch">
|
<div class="branch">
|
||||||
<a href="{{.PullRequest.BaseRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.BaseBranch}}">
|
<a href="{{.PullRequest.BaseRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.BaseBranch}}">
|
||||||
{{/* inline to remove the spaces between spans */}}
|
{{/* inline to remove the spaces between spans */}}
|
||||||
{{if ne .RepoID .PullRequest.BaseRepoID}}<span class="truncated-name">{{.PullRequest.BaseRepo.OwnerName}}</span>:{{end}}<span class="truncated-name">{{.PullRequest.BaseBranch}}</span>
|
{{if ne .RepoID .PullRequest.BaseRepoID}}<span class="truncated-name">{{.PullRequest.BaseRepo.OwnerName}}</span>:{{end}}<span class="truncated-name">{{.PullRequest.BaseBranch}}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{svg "gitea-double-chevron-left" 12 "gt-mx-1"}}
|
{{svg "gitea-double-chevron-left" 12}}
|
||||||
{{if .PullRequest.HeadRepo}}
|
{{if .PullRequest.HeadRepo}}
|
||||||
<div class="branch">
|
<div class="branch">
|
||||||
<a href="{{.PullRequest.HeadRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.HeadBranch}}">
|
<a href="{{.PullRequest.HeadRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.HeadBranch}}">
|
||||||
@ -60,32 +88,32 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and .Milestone (ne $.listType "milestone")}}
|
{{if and .Milestone (ne $.listType "milestone")}}
|
||||||
<a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}>
|
<a class="milestone flex-text-inline" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}>
|
||||||
{{svg "octicon-milestone" 14 "gt-mr-2"}}{{.Milestone.Name}}
|
{{svg "octicon-milestone" 14}}{{.Milestone.Name}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Project}}
|
{{if .Project}}
|
||||||
<a class="project" href="{{.Project.Link}}">
|
<a class="project flex-text-inline" href="{{.Project.Link}}">
|
||||||
{{svg .Project.IconName 14 "gt-mr-2"}}{{.Project.Title}}
|
{{svg .Project.IconName 14}}{{.Project.Title}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Ref}}
|
{{if .Ref}}
|
||||||
<a class="ref" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}>
|
<a class="ref flex-text-inline" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}>
|
||||||
{{svg "octicon-git-branch" 14 "gt-mr-2"}}{{index $.IssueRefEndNames .ID}}
|
{{svg "octicon-git-branch" 14}}{{index $.IssueRefEndNames .ID}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{$tasks := .GetTasks}}
|
{{$tasks := .GetTasks}}
|
||||||
{{if gt $tasks 0}}
|
{{if gt $tasks 0}}
|
||||||
{{$tasksDone := .GetTasksDone}}
|
{{$tasksDone := .GetTasksDone}}
|
||||||
<span class="checklist">
|
<span class="checklist flex-text-inline">
|
||||||
{{svg "octicon-checklist" 14 "gt-mr-2"}}{{$tasksDone}} / {{$tasks}}
|
{{svg "octicon-checklist" 14}}{{$tasksDone}} / {{$tasks}}
|
||||||
<progress value="{{$tasksDone}}" max="{{$tasks}}"></progress>
|
<progress value="{{$tasksDone}}" max="{{$tasks}}"></progress>
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if ne .DeadlineUnix 0}}
|
{{if ne .DeadlineUnix 0}}
|
||||||
<span class="due-date" data-tooltip-content="{{$.locale.Tr "repo.issues.due_date"}}">
|
<span class="due-date flex-text-inline" data-tooltip-content="{{$.locale.Tr "repo.issues.due_date"}}">
|
||||||
<span{{if .IsOverdue}} class="text red"{{end}}>
|
<span{{if .IsOverdue}} class="text red"{{end}}>
|
||||||
{{svg "octicon-calendar" 14 "gt-mr-2"}}
|
{{svg "octicon-calendar" 14}}
|
||||||
{{DateTime "short" .DeadlineUnix}}
|
{{DateTime "short" .DeadlineUnix}}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -95,25 +123,25 @@
|
|||||||
{{$rejectOfficial := call $approvalCounts .ID "reject"}}
|
{{$rejectOfficial := call $approvalCounts .ID "reject"}}
|
||||||
{{$waitingOfficial := call $approvalCounts .ID "waiting"}}
|
{{$waitingOfficial := call $approvalCounts .ID "waiting"}}
|
||||||
{{if gt $approveOfficial 0}}
|
{{if gt $approveOfficial 0}}
|
||||||
<span class="approvals gt-df gt-ac green">
|
<span class="approvals green flex-text-inline">
|
||||||
{{svg "octicon-check" 14 "gt-mr-1"}}
|
{{svg "octicon-check" 14}}
|
||||||
{{$.locale.TrN $approveOfficial "repo.pulls.approve_count_1" "repo.pulls.approve_count_n" $approveOfficial}}
|
{{$.locale.TrN $approveOfficial "repo.pulls.approve_count_1" "repo.pulls.approve_count_n" $approveOfficial}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if gt $rejectOfficial 0}}
|
{{if gt $rejectOfficial 0}}
|
||||||
<span class="rejects gt-df gt-ac red">
|
<span class="rejects red flex-text-inline">
|
||||||
{{svg "octicon-diff" 14 "gt-mr-2"}}
|
{{svg "octicon-diff" 14}}
|
||||||
{{$.locale.TrN $rejectOfficial "repo.pulls.reject_count_1" "repo.pulls.reject_count_n" $rejectOfficial}}
|
{{$.locale.TrN $rejectOfficial "repo.pulls.reject_count_1" "repo.pulls.reject_count_n" $rejectOfficial}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if gt $waitingOfficial 0}}
|
{{if gt $waitingOfficial 0}}
|
||||||
<span class="waiting gt-df gt-ac">
|
<span class="waiting flex-text-inline">
|
||||||
{{svg "octicon-eye" 14 "gt-mr-2"}}
|
{{svg "octicon-eye" 14}}
|
||||||
{{$.locale.TrN $waitingOfficial "repo.pulls.waiting_count_1" "repo.pulls.waiting_count_n" $waitingOfficial}}
|
{{$.locale.TrN $waitingOfficial "repo.pulls.waiting_count_1" "repo.pulls.waiting_count_n" $waitingOfficial}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and (not .PullRequest.HasMerged) (gt (len .PullRequest.ConflictedFiles) 0)}}
|
{{if and (not .PullRequest.HasMerged) (gt (len .PullRequest.ConflictedFiles) 0)}}
|
||||||
<span class="conflicting gt-df gt-ac">
|
<span class="conflicting flex-text-inline">
|
||||||
{{svg "octicon-x" 14}}
|
{{svg "octicon-x" 14}}
|
||||||
{{$.locale.TrN (len .PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n" (len .PullRequest.ConflictedFiles)}}
|
{{$.locale.TrN (len .PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n" (len .PullRequest.ConflictedFiles)}}
|
||||||
</span>
|
</span>
|
||||||
@ -121,32 +149,6 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{if or .TotalTrackedTime .Assignees .NumComments}}
|
|
||||||
<div class="issue-item-icons-right gt-df gt-p-2">
|
|
||||||
{{if .TotalTrackedTime}}
|
|
||||||
<div class="issue-item-icon-right text grey">
|
|
||||||
{{svg "octicon-clock" 16 "gt-mr-2"}}
|
|
||||||
{{.TotalTrackedTime | Sec2Time}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
{{if .Assignees}}
|
|
||||||
<div class="issue-item-icon-right text grey">
|
|
||||||
{{range .Assignees}}
|
|
||||||
<a class="ui assignee gt-no-underline" href="{{.HomeLink}}" data-tooltip-content="{{.GetDisplayName}}">
|
|
||||||
{{avatar $.Context . 20}}
|
|
||||||
</a>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
{{if .NumComments}}
|
|
||||||
<div class="issue-item-icon-right text grey">
|
|
||||||
<a class="gt-no-underline muted" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
|
|
||||||
{{svg "octicon-comment" 16 "gt-mr-2"}}{{.NumComments}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IssueIndexerUnavailable}}
|
{{if .IssueIndexerUnavailable}}
|
||||||
|
@ -11,13 +11,10 @@
|
|||||||
<label for="password">{{.locale.Tr "password"}}</label>
|
<label for="password">{{.locale.Tr "password"}}</label>
|
||||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="new-password" required>
|
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="new-password" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||||
<label for="retype">{{.locale.Tr "re_type"}}</label>
|
<label for="retype">{{.locale.Tr "re_type"}}</label>
|
||||||
<input id="retype" name="retype" type="password" autocomplete="new-password" required>
|
<input id="retype" name="retype" type="password" autocomplete="new-password" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
<label></label>
|
||||||
<button class="ui green button">{{.locale.Tr "settings.change_password"}}</button>
|
<button class="ui green button">{{.locale.Tr "settings.change_password"}}</button>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_div" data-params="{{.Page.GetParams}}" data-sequence-number="{{.SequenceNumber}}">
|
<div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_div" data-sequence-number="{{.SequenceNumber}}">
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
{{$notificationUnreadCount := call .NotificationUnreadCount}}
|
{{$notificationUnreadCount := call .NotificationUnreadCount}}
|
||||||
<div class="gt-df gt-ac gt-sb gt-mb-4">
|
<div class="gt-df gt-ac gt-sb gt-mb-4">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
<div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_subscriptions" data-params="{{.Page.GetParams}}" data-sequence-number="{{.SequenceNumber}}">
|
<div role="main" aria-label="{{.Title}}" class="page-content user notification">
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
<div class="ui top attached tabular menu">
|
<div class="ui top attached tabular menu">
|
||||||
<a href="{{AppSubUrl}}/notifications/subscriptions" class="{{if eq .Status 1}}active {{end}}item">
|
<a href="{{AppSubUrl}}/notifications/subscriptions" class="{{if eq .Status 1}}active {{end}}item">
|
||||||
|
@ -45,11 +45,12 @@ func TestAPIGetCommentAttachment(t *testing.T) {
|
|||||||
var apiAttachment api.Attachment
|
var apiAttachment api.Attachment
|
||||||
DecodeJSON(t, resp, &apiAttachment)
|
DecodeJSON(t, resp, &apiAttachment)
|
||||||
|
|
||||||
expect := convert.ToAttachment(attachment)
|
expect := convert.ToAPIAttachment(repo, attachment)
|
||||||
assert.Equal(t, expect.ID, apiAttachment.ID)
|
assert.Equal(t, expect.ID, apiAttachment.ID)
|
||||||
assert.Equal(t, expect.Name, apiAttachment.Name)
|
assert.Equal(t, expect.Name, apiAttachment.Name)
|
||||||
assert.Equal(t, expect.UUID, apiAttachment.UUID)
|
assert.Equal(t, expect.UUID, apiAttachment.UUID)
|
||||||
assert.Equal(t, expect.Created.Unix(), apiAttachment.Created.Unix())
|
assert.Equal(t, expect.Created.Unix(), apiAttachment.Created.Unix())
|
||||||
|
assert.Equal(t, expect.DownloadURL, apiAttachment.DownloadURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIListCommentAttachments(t *testing.T) {
|
func TestAPIListCommentAttachments(t *testing.T) {
|
||||||
|
@ -128,7 +128,7 @@ func TestAPIGetComment(t *testing.T) {
|
|||||||
DecodeJSON(t, resp, &apiComment)
|
DecodeJSON(t, resp, &apiComment)
|
||||||
|
|
||||||
assert.NoError(t, comment.LoadPoster(db.DefaultContext))
|
assert.NoError(t, comment.LoadPoster(db.DefaultContext))
|
||||||
expect := convert.ToComment(db.DefaultContext, comment)
|
expect := convert.ToAPIComment(db.DefaultContext, repo, comment)
|
||||||
|
|
||||||
assert.Equal(t, expect.ID, apiComment.ID)
|
assert.Equal(t, expect.ID, apiComment.ID)
|
||||||
assert.Equal(t, expect.Poster.FullName, apiComment.Poster.FullName)
|
assert.Equal(t, expect.Poster.FullName, apiComment.Poster.FullName)
|
||||||
|
@ -170,9 +170,9 @@ func TestAPIGetAll(t *testing.T) {
|
|||||||
var apiOrgList []*api.Organization
|
var apiOrgList []*api.Organization
|
||||||
|
|
||||||
DecodeJSON(t, resp, &apiOrgList)
|
DecodeJSON(t, resp, &apiOrgList)
|
||||||
assert.Len(t, apiOrgList, 9)
|
assert.Len(t, apiOrgList, 11)
|
||||||
assert.Equal(t, "org25", apiOrgList[1].FullName)
|
assert.Equal(t, "Limited Org 36", apiOrgList[1].FullName)
|
||||||
assert.Equal(t, "public", apiOrgList[1].Visibility)
|
assert.Equal(t, "limited", apiOrgList[1].Visibility)
|
||||||
|
|
||||||
// accessing without a token will return only public orgs
|
// accessing without a token will return only public orgs
|
||||||
req = NewRequestf(t, "GET", "/api/v1/orgs")
|
req = NewRequestf(t, "GET", "/api/v1/orgs")
|
||||||
|
@ -157,29 +157,227 @@ func TestPackageAccess(t *testing.T) {
|
|||||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||||
inactive := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 9})
|
inactive := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 9})
|
||||||
privatedOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23})
|
limitedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 33})
|
||||||
|
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31})
|
||||||
|
privateOrgMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23}) // user has package write access
|
||||||
|
limitedOrgMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 36}) // user has package write access
|
||||||
|
publicOrgMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 25}) // user has package read access
|
||||||
|
privateOrgNoMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 35})
|
||||||
|
limitedOrgNoMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 22})
|
||||||
|
publicOrgNoMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
|
||||||
|
|
||||||
uploadPackage := func(doer, owner *user_model.User, expectedStatus int) {
|
uploadPackage := func(doer, owner *user_model.User, filename string, expectedStatus int) {
|
||||||
url := fmt.Sprintf("/api/packages/%s/generic/test-package/1.0/file.bin", owner.Name)
|
url := fmt.Sprintf("/api/packages/%s/generic/test-package/1.0/%s.bin", owner.Name, filename)
|
||||||
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{1}))
|
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{1}))
|
||||||
AddBasicAuthHeader(req, doer.Name)
|
if doer != nil {
|
||||||
|
AddBasicAuthHeader(req, doer.Name)
|
||||||
|
}
|
||||||
MakeRequest(t, req, expectedStatus)
|
MakeRequest(t, req, expectedStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadPackage(user, inactive, http.StatusUnauthorized)
|
downloadPackage := func(doer, owner *user_model.User, expectedStatus int) {
|
||||||
uploadPackage(inactive, inactive, http.StatusUnauthorized)
|
url := fmt.Sprintf("/api/packages/%s/generic/test-package/1.0/admin.bin", owner.Name)
|
||||||
uploadPackage(inactive, user, http.StatusUnauthorized)
|
req := NewRequest(t, "GET", url)
|
||||||
uploadPackage(admin, inactive, http.StatusCreated)
|
if doer != nil {
|
||||||
uploadPackage(admin, user, http.StatusCreated)
|
AddBasicAuthHeader(req, doer.Name)
|
||||||
|
}
|
||||||
|
MakeRequest(t, req, expectedStatus)
|
||||||
|
}
|
||||||
|
|
||||||
// team.authorize is write, but team_unit.access_mode is none
|
type Target struct {
|
||||||
// so the user can not upload packages or get package list
|
Owner *user_model.User
|
||||||
uploadPackage(user, privatedOrg, http.StatusUnauthorized)
|
ExpectedStatus int
|
||||||
|
}
|
||||||
|
|
||||||
session := loginUser(t, user.Name)
|
t.Run("Upload", func(t *testing.T) {
|
||||||
tokenReadPackage := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadPackage)
|
defer tests.PrintCurrentTest(t)()
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?token=%s", privatedOrg.Name, tokenReadPackage))
|
|
||||||
MakeRequest(t, req, http.StatusForbidden)
|
cases := []struct {
|
||||||
|
Doer *user_model.User
|
||||||
|
Filename string
|
||||||
|
Targets []Target
|
||||||
|
}{
|
||||||
|
{ // Admins can upload to every owner
|
||||||
|
Doer: admin,
|
||||||
|
Filename: "admin",
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusCreated},
|
||||||
|
{inactive, http.StatusCreated},
|
||||||
|
{user, http.StatusCreated},
|
||||||
|
{limitedUser, http.StatusCreated},
|
||||||
|
{privateUser, http.StatusCreated},
|
||||||
|
{privateOrgMember, http.StatusCreated},
|
||||||
|
{limitedOrgMember, http.StatusCreated},
|
||||||
|
{publicOrgMember, http.StatusCreated},
|
||||||
|
{privateOrgNoMember, http.StatusCreated},
|
||||||
|
{limitedOrgNoMember, http.StatusCreated},
|
||||||
|
{publicOrgNoMember, http.StatusCreated},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Without credentials no upload should be possible
|
||||||
|
Doer: nil,
|
||||||
|
Filename: "nil",
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusUnauthorized},
|
||||||
|
{inactive, http.StatusUnauthorized},
|
||||||
|
{user, http.StatusUnauthorized},
|
||||||
|
{limitedUser, http.StatusUnauthorized},
|
||||||
|
{privateUser, http.StatusUnauthorized},
|
||||||
|
{privateOrgMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgMember, http.StatusUnauthorized},
|
||||||
|
{privateOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgNoMember, http.StatusUnauthorized},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Inactive users can't upload anywhere
|
||||||
|
Doer: inactive,
|
||||||
|
Filename: "inactive",
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusUnauthorized},
|
||||||
|
{inactive, http.StatusUnauthorized},
|
||||||
|
{user, http.StatusUnauthorized},
|
||||||
|
{limitedUser, http.StatusUnauthorized},
|
||||||
|
{privateUser, http.StatusUnauthorized},
|
||||||
|
{privateOrgMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgMember, http.StatusUnauthorized},
|
||||||
|
{privateOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgNoMember, http.StatusUnauthorized},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Normal users can upload to self and orgs in which they are members and have package write access
|
||||||
|
Doer: user,
|
||||||
|
Filename: "user",
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusUnauthorized},
|
||||||
|
{inactive, http.StatusUnauthorized},
|
||||||
|
{user, http.StatusCreated},
|
||||||
|
{limitedUser, http.StatusUnauthorized},
|
||||||
|
{privateUser, http.StatusUnauthorized},
|
||||||
|
{privateOrgMember, http.StatusCreated},
|
||||||
|
{limitedOrgMember, http.StatusCreated},
|
||||||
|
{publicOrgMember, http.StatusUnauthorized},
|
||||||
|
{privateOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgNoMember, http.StatusUnauthorized},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
for _, t := range c.Targets {
|
||||||
|
uploadPackage(c.Doer, t.Owner, c.Filename, t.ExpectedStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Download", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Doer *user_model.User
|
||||||
|
Filename string
|
||||||
|
Targets []Target
|
||||||
|
}{
|
||||||
|
{ // Admins can access everything
|
||||||
|
Doer: admin,
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusOK},
|
||||||
|
{inactive, http.StatusOK},
|
||||||
|
{user, http.StatusOK},
|
||||||
|
{limitedUser, http.StatusOK},
|
||||||
|
{privateUser, http.StatusOK},
|
||||||
|
{privateOrgMember, http.StatusOK},
|
||||||
|
{limitedOrgMember, http.StatusOK},
|
||||||
|
{publicOrgMember, http.StatusOK},
|
||||||
|
{privateOrgNoMember, http.StatusOK},
|
||||||
|
{limitedOrgNoMember, http.StatusOK},
|
||||||
|
{publicOrgNoMember, http.StatusOK},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Without credentials only public owners are accessible
|
||||||
|
Doer: nil,
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusOK},
|
||||||
|
{inactive, http.StatusOK},
|
||||||
|
{user, http.StatusOK},
|
||||||
|
{limitedUser, http.StatusUnauthorized},
|
||||||
|
{privateUser, http.StatusUnauthorized},
|
||||||
|
{privateOrgMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgMember, http.StatusOK},
|
||||||
|
{privateOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgNoMember, http.StatusOK},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Inactive users have no access
|
||||||
|
Doer: inactive,
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusUnauthorized},
|
||||||
|
{inactive, http.StatusUnauthorized},
|
||||||
|
{user, http.StatusUnauthorized},
|
||||||
|
{limitedUser, http.StatusUnauthorized},
|
||||||
|
{privateUser, http.StatusUnauthorized},
|
||||||
|
{privateOrgMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgMember, http.StatusUnauthorized},
|
||||||
|
{privateOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{publicOrgNoMember, http.StatusUnauthorized},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Normal users can access self, public or limited users/orgs and private orgs in which they are members
|
||||||
|
Doer: user,
|
||||||
|
Targets: []Target{
|
||||||
|
{admin, http.StatusOK},
|
||||||
|
{inactive, http.StatusOK},
|
||||||
|
{user, http.StatusOK},
|
||||||
|
{limitedUser, http.StatusOK},
|
||||||
|
{privateUser, http.StatusUnauthorized},
|
||||||
|
{privateOrgMember, http.StatusOK},
|
||||||
|
{limitedOrgMember, http.StatusOK},
|
||||||
|
{publicOrgMember, http.StatusOK},
|
||||||
|
{privateOrgNoMember, http.StatusUnauthorized},
|
||||||
|
{limitedOrgNoMember, http.StatusOK},
|
||||||
|
{publicOrgNoMember, http.StatusOK},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
for _, target := range c.Targets {
|
||||||
|
downloadPackage(c.Doer, target.Owner, target.ExpectedStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("API", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
session := loginUser(t, user.Name)
|
||||||
|
tokenReadPackage := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadPackage)
|
||||||
|
|
||||||
|
for _, target := range []Target{
|
||||||
|
{admin, http.StatusOK},
|
||||||
|
{inactive, http.StatusOK},
|
||||||
|
{user, http.StatusOK},
|
||||||
|
{limitedUser, http.StatusOK},
|
||||||
|
{privateUser, http.StatusForbidden},
|
||||||
|
{privateOrgMember, http.StatusOK},
|
||||||
|
{limitedOrgMember, http.StatusOK},
|
||||||
|
{publicOrgMember, http.StatusOK},
|
||||||
|
{privateOrgNoMember, http.StatusForbidden},
|
||||||
|
{limitedOrgNoMember, http.StatusOK},
|
||||||
|
{publicOrgNoMember, http.StatusOK},
|
||||||
|
} {
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?token=%s", target.Owner.Name, tokenReadPackage))
|
||||||
|
MakeRequest(t, req, target.ExpectedStatus)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPackageQuota(t *testing.T) {
|
func TestPackageQuota(t *testing.T) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.page-content.install {
|
.page-content.install .install-config-container {
|
||||||
padding-top: 45px;
|
max-width: 900px;
|
||||||
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.install form.ui.form .inline.field > label {
|
.page-content.install form.ui.form .inline.field > label {
|
||||||
@ -9,26 +10,20 @@
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.install form.ui.form .inline.field > .ui.checkbox:first-child {
|
.page-content.install .ui.form .field > .help,
|
||||||
|
.page-content.install .ui.form .field > .ui.checkbox:first-child,
|
||||||
|
.page-content.install .ui.form .field > .right-content {
|
||||||
margin-left: 30%;
|
margin-left: 30%;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.page-content.install form.ui.form .inline.field > .ui.checkbox:first-child label {
|
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.install form.ui.form .title {
|
|
||||||
margin-left: 30%;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-content.install form.ui.form input {
|
.page-content.install form.ui.form input {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.install form.ui.form details.optional.field[open] {
|
.page-content.install form.ui.form details.optional.field[open] {
|
||||||
border-bottom: 1px solid var(--color-secondary);
|
border-bottom: 1px dashed var(--color-secondary);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,12 +39,6 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.install form.ui.form .field .help {
|
|
||||||
margin-left: 30%;
|
|
||||||
padding-left: 5px;
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-content.install .ui .reinstall-message {
|
.page-content.install .ui .reinstall-message {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
|
@ -3,6 +3,30 @@
|
|||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.issue.list .item {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue.list .item .issue-item-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue.list .item .issue-item-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue.list .item .issue-item-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.issue.list a:not(.label):hover {
|
.issue.list a:not(.label):hover {
|
||||||
color: var(--color-primary) !important;
|
color: var(--color-primary) !important;
|
||||||
}
|
}
|
||||||
@ -12,14 +36,13 @@
|
|||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .issue-item-icons-right > * + * {
|
.issue.list .item .issue-item-right {
|
||||||
margin-left: 0.5rem;
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .issue-item-main {
|
.issue.list > .action-item {
|
||||||
flex: 1;
|
align-items: normal;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .action-item-center {
|
.issue.list > .item .action-item-center {
|
||||||
@ -37,7 +60,7 @@
|
|||||||
color: var(--color-text-light);
|
color: var(--color-text-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .issue-item-top-row {
|
.issue.list > .item .issue-item-title {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -45,7 +68,7 @@
|
|||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .issue-item-top-row a.index {
|
.issue.list > .item .issue-item-title a.index {
|
||||||
max-width: fit-content;
|
max-width: fit-content;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
@ -54,108 +77,49 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .labels-list {
|
.issue.list > .item .title {
|
||||||
position: relative;
|
color: var(--color-text);
|
||||||
top: -1.5px;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .issue-item-bottom-row {
|
.issue.list > .item .issue-item-body {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: .125rem 0;
|
gap: .25rem;
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .title {
|
|
||||||
color: var(--color-text);
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .issue-item-icon-right {
|
|
||||||
min-width: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .assignee {
|
|
||||||
position: relative;
|
|
||||||
top: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .assignee img {
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc {
|
|
||||||
color: var(--color-text-light-2);
|
color: var(--color-text-light-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .desc a {
|
.issue.list > .item .issue-item-body a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .desc .time-since,
|
.issue.list > .item .issue-item-body .checklist progress {
|
||||||
.issue.list > .item .desc a {
|
|
||||||
margin-left: 0.25rem;
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc .waiting,
|
|
||||||
.issue.list > .item .desc .approvals,
|
|
||||||
.issue.list > .item .desc .rejects {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc .checklist {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc .checklist progress {
|
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
vertical-align: 2px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .desc .checklist progress::-webkit-progress-value {
|
.issue.list > .item .issue-item-body .checklist progress::-webkit-progress-value {
|
||||||
background-color: var(--color-secondary-dark-4);
|
background-color: var(--color-secondary-dark-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .desc .checklist progress::-moz-progress-bar {
|
.issue.list > .item .issue-item-body .checklist progress::-moz-progress-bar {
|
||||||
background-color: var(--color-secondary-dark-4);
|
background-color: var(--color-secondary-dark-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list > .item .desc .conflicting {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc .due-date {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc a.milestone,
|
|
||||||
.issue.list > .item .desc a.project {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc a.ref {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list > .item .desc a.ref span {
|
|
||||||
margin-right: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.issue.list .branches {
|
.issue.list .branches {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
padding: 0 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list .branches .branch {
|
.issue.list .branches .branch {
|
||||||
background-color: var(--color-secondary-alpha-40);
|
background-color: var(--color-secondary-alpha-40);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
padding: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue.list .branches .truncated-name {
|
.issue.list .branches .truncated-name {
|
||||||
|
@ -165,7 +165,7 @@ async function updateNotificationTable() {
|
|||||||
if (notificationDiv.length > 0) {
|
if (notificationDiv.length > 0) {
|
||||||
const data = await $.ajax({
|
const data = await $.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: `${appSubUrl}/notifications?${notificationDiv.data('params')}`,
|
url: `${appSubUrl}/notifications${window.location.search}`,
|
||||||
data: {
|
data: {
|
||||||
'div-only': true,
|
'div-only': true,
|
||||||
'sequence-number': ++notificationSequenceNumber,
|
'sequence-number': ++notificationSequenceNumber,
|
||||||
|
Loading…
Reference in New Issue
Block a user