1
0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2024-12-22 12:54:53 -05:00

Merge pull request '[gitea] week 16 cherry pick' (#3212) from algernon/forgejo:wcp/week-16 into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/3212
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
Earl Warren 2024-04-15 20:07:37 +00:00
commit e4fa133c47
86 changed files with 545 additions and 459 deletions

View file

@ -94,6 +94,9 @@ cpu.out
/.air /.air
/.go-licenses /.go-licenses
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft # Snapcraft
snap/.snapcraft/ snap/.snapcraft/
parts/ parts/

1
.gitattributes vendored
View file

@ -1,5 +1,6 @@
* text=auto eol=lf * text=auto eol=lf
*.tmpl linguist-language=go-html-template *.tmpl linguist-language=go-html-template
*.pb.go linguist-generated
/assets/*.json linguist-generated /assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated /public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated /templates/swagger/v1_json.tmpl linguist-generated

3
.gitignore vendored
View file

@ -101,6 +101,9 @@ cpu.out
/.go-licenses /.go-licenses
/.cur-deadcode-out /.cur-deadcode-out
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft # Snapcraft
/gitea_a*.txt /gitea_a*.txt
snap/.snapcraft/ snap/.snapcraft/

View file

@ -312,7 +312,7 @@ clean:
.PHONY: fmt .PHONY: fmt
fmt: fmt:
GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}' @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl')) $(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only @# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
@# whitespace before it @# whitespace before it

View file

@ -69,6 +69,7 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`)) co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
@ -203,17 +204,6 @@ Example:
`, "file-batch-exec") `, "file-batch-exec")
} }
func getGoVersion() string {
goModFile, err := os.ReadFile("go.mod")
if err != nil {
log.Fatalf(`Faild to read "go.mod": %v`, err)
os.Exit(1)
}
goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`)
goModVersionLine := goModVersionRegex.Find(goModFile)
return string(goModVersionLine[3:])
}
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) { func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"] fileFilter := mainOptions["file-filter"]
if fileFilter == "" { if fileFilter == "" {
@ -278,7 +268,8 @@ func main() {
log.Print("the -d option is not supported by gitea-fmt") log.Print("the -d option is not supported by gitea-fmt")
} }
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w"))) cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...))) cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
default: default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs) log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
} }

View file

@ -114,7 +114,7 @@ func showWebStartupMessage(msg string) {
log.Info("* WorkPath: %s", setting.AppWorkPath) log.Info("* WorkPath: %s", setting.AppWorkPath)
log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* CustomPath: %s", setting.CustomPath)
log.Info("* ConfigFile: %s", setting.CustomConf) log.Info("* ConfigFile: %s", setting.CustomConf)
log.Info("%s", msg) log.Info("%s", msg) // show startup message
} }
func serveInstall(ctx *cli.Context) error { func serveInstall(ctx *cli.Context) error {

View file

@ -44,6 +44,9 @@ func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
schedule.TriggerUser = user_model.NewActionsUser() schedule.TriggerUser = user_model.NewActionsUser()
} else { } else {
schedule.TriggerUser = users[schedule.TriggerUserID] schedule.TriggerUser = users[schedule.TriggerUserID]
if schedule.TriggerUser == nil {
schedule.TriggerUser = user_model.NewGhostUser()
}
} }
} }
return nil return nil

View file

@ -11,6 +11,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -227,7 +228,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
if runner.RepoID != 0 { if runner.RepoID != 0 {
jobCond = builder.Eq{"repo_id": runner.RepoID} jobCond = builder.Eq{"repo_id": runner.RepoID}
} else if runner.OwnerID != 0 { } else if runner.OwnerID != 0 {
jobCond = builder.In("repo_id", builder.Select("id").From("repository").Where(builder.Eq{"owner_id": runner.OwnerID})) jobCond = builder.In("repo_id", builder.Select("`repository`.id").From("repository").
Join("INNER", "repo_unit", "`repository`.id = `repo_unit`.repo_id").
Where(builder.Eq{"`repository`.owner_id": runner.OwnerID, "`repo_unit`.type": unit.TypeActions}))
} }
if jobCond.IsValid() { if jobCond.IsValid() {
jobCond = builder.In("run_id", builder.Select("id").From("action_run").Where(jobCond)) jobCond = builder.In("run_id", builder.Select("id").From("action_run").Where(jobCond))

View file

@ -76,23 +76,14 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
// CalcFingerprint calculate public key's fingerprint // CalcFingerprint calculate public key's fingerprint
func CalcFingerprint(publicKeyContent string) (string, error) { func CalcFingerprint(publicKeyContent string) (string, error) {
// Call the method based on configuration // Call the method based on configuration
var ( useNative := setting.SSH.KeygenPath == ""
fnName, fp string calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
err error fp, err := calcFn(publicKeyContent)
)
if len(setting.SSH.KeygenPath) == 0 {
fnName = "calcFingerprintNative"
fp, err = calcFingerprintNative(publicKeyContent)
} else {
fnName = "calcFingerprintSSHKeygen"
fp, err = calcFingerprintSSHKeygen(publicKeyContent)
}
if err != nil { if err != nil {
if IsErrKeyUnableVerify(err) { if IsErrKeyUnableVerify(err) {
log.Info("%s", publicKeyContent)
return "", err return "", err
} }
return "", fmt.Errorf("%s: %w", fnName, err) return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err)
} }
return fp, nil return fp, nil
} }

View file

@ -144,6 +144,11 @@ func (app *OAuth2Application) TableName() string {
// ContainsRedirectURI checks if redirectURI is allowed for app // ContainsRedirectURI checks if redirectURI is allowed for app
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool { func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
// OAuth2 requires the redirect URI to be an exact match, no dynamic parts are allowed.
// https://stackoverflow.com/questions/55524480/should-dynamic-query-parameters-be-present-in-the-redirection-uri-for-an-oauth2
// https://www.rfc-editor.org/rfc/rfc6819#section-5.2.3.3
// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-12#section-3.1
contains := func(s string) bool { contains := func(s string) bool {
s = strings.TrimSuffix(strings.ToLower(s), "/") s = strings.TrimSuffix(strings.ToLower(s), "/")
for _, u := range app.RedirectURIs { for _, u := range app.RedirectURIs {

View file

@ -53,7 +53,7 @@ func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool {
var u *RepoUnit var u *RepoUnit
var err error var err error
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
log.Trace("%s", err) log.Trace("IsDependenciesEnabled: %v", err)
return setting.Service.DefaultEnableDependencies return setting.Service.DefaultEnableDependencies
} }
return u.IssuesConfig().EnableDependencies return u.IssuesConfig().EnableDependencies

View file

@ -35,7 +35,7 @@ func (o *Option[T]) UnmarshalYAML(value *yaml.Node) error {
return nil return nil
} }
func (o Option[T]) MarshalYAML() (interface{}, error) { func (o Option[T]) MarshalYAML() (any, error) {
if !o.Has() { if !o.Has() {
return nil, nil return nil, nil
} }

View file

@ -6,6 +6,9 @@ package session
import ( import (
"net/http" "net/http"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web/middleware"
"gitea.com/go-chi/session" "gitea.com/go-chi/session"
) )
@ -18,6 +21,10 @@ type Store interface {
// RegenerateSession regenerates the underlying session and returns the new store // RegenerateSession regenerates the underlying session and returns the new store
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) { func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
// Ensure that a cookie with a trailing slash does not take precedence over
// the cookie written by the middleware.
middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
s, err := session.RegenerateSession(resp, req) s, err := session.RegenerateSession(resp, req)
return s, err return s, err
} }

View file

@ -142,35 +142,39 @@ type remoteAddress struct {
Password string Password string
} }
func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress { func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress {
a := remoteAddress{} ret := remoteAddress{}
remoteURL, err := git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
remoteURL := m.OriginalURL
if ignoreOriginalURL || remoteURL == "" {
var err error
remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
if err != nil { if err != nil {
log.Error("GetRemoteURL %v", err) log.Error("GetRemoteURL %v", err)
return a return ret
}
} }
u, err := giturl.Parse(remoteURL) u, err := giturl.Parse(remoteURL)
if err != nil { if err != nil {
log.Error("giturl.Parse %v", err) log.Error("giturl.Parse %v", err)
return a return ret
} }
if u.Scheme != "ssh" && u.Scheme != "file" { if u.Scheme != "ssh" && u.Scheme != "file" {
if u.User != nil { if u.User != nil {
a.Username = u.User.Username() ret.Username = u.User.Username()
a.Password, _ = u.User.Password() ret.Password, _ = u.User.Password()
} }
u.User = nil
} }
a.Address = u.String()
return a // The URL stored in the git repo could contain authentication,
// erase it, or it will be shown in the UI.
u.User = nil
ret.Address = u.String()
// Why not use m.OriginalURL to set ret.Address?
// It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository.
// However, the old code has already stored authentication in m.OriginalURL when updating mirror settings.
// That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased.
// Instead of doing this, why not directly use the authentication-erased URL from the Git repository?
// It should be the same as long as there are no bugs.
return ret
} }
func FilenameIsImage(filename string) bool { func FilenameIsImage(filename string) bool {

View file

@ -213,6 +213,14 @@ func ToPointer[T any](val T) *T {
return &val return &val
} }
// Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal"
func Iif[T any](condition bool, trueVal, falseVal T) T {
if condition {
return trueVal
}
return falseVal
}
func ReserveLineBreakForTextarea(input string) string { func ReserveLineBreakForTextarea(input string) string {
// Since the content is from a form which is a textarea, the line endings are \r\n. // Since the content is from a form which is a textarea, the line endings are \r\n.
// It's a standard behavior of HTML. // It's a standard behavior of HTML.

View file

@ -45,10 +45,32 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) {
SameSite: setting.SessionConfig.SameSite, SameSite: setting.SessionConfig.SameSite,
} }
resp.Header().Add("Set-Cookie", cookie.String()) resp.Header().Add("Set-Cookie", cookie.String())
if maxAge < 0 { // Previous versions would use a cookie path with a trailing /.
// There was a bug in "setting.SessionConfig.CookiePath" code, the old default value of it was empty "". // These are more specific than cookies without a trailing /, so
// So we have to delete the cookie on path="" again, because some old code leaves cookies on path="". // we need to delete these if they exist.
cookie.Path = strings.TrimSuffix(setting.SessionConfig.CookiePath, "/") DeleteLegacySiteCookie(resp, name)
resp.Header().Add("Set-Cookie", cookie.String()) }
}
// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie
// path with a trailing /, which would unintentionally override the cookie.
func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) {
if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") {
// If the cookie path ends with /, no legacy cookies will take
// precedence, so do nothing. The exception is that cookies with no
// path could override other cookies, but it's complicated and we don't
// currently handle that.
return
}
cookie := &http.Cookie{
Name: name,
Value: "",
MaxAge: -1,
Path: setting.SessionConfig.CookiePath + "/",
Domain: setting.SessionConfig.Domain,
Secure: setting.SessionConfig.Secure,
HttpOnly: true,
SameSite: setting.SessionConfig.SameSite,
}
resp.Header().Add("Set-Cookie", cookie.String())
} }

View file

@ -210,21 +210,21 @@ PART 1: INITIAL CONTRIBUTOR AND DESIGNATED WEB SITE
The Initial Contributor is: The Initial Contributor is:
____________________________________________________ ____________________________________________________
 
[Enter full name of Initial Contributor] [Enter full name of Initial Contributor]
Address of Initial Contributor: Address of Initial Contributor:
________________________________________________ ________________________________________________
 
________________________________________________ ________________________________________________
 
________________________________________________ ________________________________________________
 
[Enter address above] [Enter address above]
The Designated Web Site is: The Designated Web Site is:
__________________________________________________ __________________________________________________
 
[Enter URL for Designated Web Site of Initial Contributor] [Enter URL for Designated Web Site of Initial Contributor]
NOTE: The Initial Contributor is to complete this Part 1, along with Parts 2, 3, and 5, and, if applicable, Parts 4 and 6. NOTE: The Initial Contributor is to complete this Part 1, along with Parts 2, 3, and 5, and, if applicable, Parts 4 and 6.
@ -237,27 +237,27 @@ The date on which the Initial Work was first available under this License: _____
PART 3: GOVERNING JURISDICTION PART 3: GOVERNING JURISDICTION
For the purposes of this License, the Governing Jurisdiction is _________________________________________________. [Initial Contributor to Enter Governing Jurisdiction here] For the purposes of this License, the Governing Jurisdiction is _________________________________________________. [Initial Contributor to Enter Governing Jurisdiction here]
PART 4: THIRD PARTIES PART 4: THIRD PARTIES
For the purposes of this License, "Third Party" has the definition set forth below in the ONE paragraph selected by the Initial Contributor from paragraphs A, B, C, D and E when the Initial Work is distributed or otherwise made available by the Initial Contributor. To select one of the following paragraphs, the Initial Contributor must place an "X" or "x" in the selection box alongside the one respective paragraph selected. For the purposes of this License, "Third Party" has the definition set forth below in the ONE paragraph selected by the Initial Contributor from paragraphs A, B, C, D and E when the Initial Work is distributed or otherwise made available by the Initial Contributor. To select one of the following paragraphs, the Initial Contributor must place an "X" or "x" in the selection box alongside the one respective paragraph selected.
SELECTION SELECTION
 
BOX PARAGRAPH BOX PARAGRAPH
[  ] A. "THIRD PARTY" means any third party. [ ] A. "THIRD PARTY" means any third party.
 
 
[  ] B. "THIRD PARTY" means any third party except for any of the following: (a) a wholly owned subsidiary of the Subsequent Contributor in question; (b) a legal entity (the "PARENT") that wholly owns the Subsequent Contributor in question; or (c) a wholly owned subsidiary of the wholly owned subsidiary in (a) or of the Parent in (b). [ ] B. "THIRD PARTY" means any third party except for any of the following: (a) a wholly owned subsidiary of the Subsequent Contributor in question; (b) a legal entity (the "PARENT") that wholly owns the Subsequent Contributor in question; or (c) a wholly owned subsidiary of the wholly owned subsidiary in (a) or of the Parent in (b).
 
 
[  ] C. "THIRD PARTY" means any third party except for any of the following: (a) any Person directly or indirectly owning a majority of the voting interest in the Subsequent Contributor or (b) any Person in which the Subsequent Contributor directly or indirectly owns a majority voting interest. [ ] C. "THIRD PARTY" means any third party except for any of the following: (a) any Person directly or indirectly owning a majority of the voting interest in the Subsequent Contributor or (b) any Person in which the Subsequent Contributor directly or indirectly owns a majority voting interest.
 
 
[  ] D. "THIRD PARTY" means any third party except for any Person directly or indirectly controlled by the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise. [ ] D. "THIRD PARTY" means any third party except for any Person directly or indirectly controlled by the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise.
 
 
[  ] E. "THIRD PARTY" means any third party except for any Person directly or indirectly controlling, controlled by, or under common control with the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise. [ ] E. "THIRD PARTY" means any third party except for any Person directly or indirectly controlling, controlled by, or under common control with the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise.
The default definition of "THIRD PARTY" is the definition set forth in paragraph A, if NONE OR MORE THAN ONE of paragraphs A, B, C, D or E in this Part 4 are selected by the Initial Contributor. The default definition of "THIRD PARTY" is the definition set forth in paragraph A, if NONE OR MORE THAN ONE of paragraphs A, B, C, D or E in this Part 4 are selected by the Initial Contributor.
PART 5: NOTICE PART 5: NOTICE
@ -271,8 +271,8 @@ PART 6: PATENT LICENSING TERMS
For the purposes of this License, paragraphs A, B, C, D and E of this Part 6 of Exhibit A are only incorporated and form part of the terms of the License if the Initial Contributor places an "X" or "x" in the selection box alongside the YES answer to the question immediately below. For the purposes of this License, paragraphs A, B, C, D and E of this Part 6 of Exhibit A are only incorporated and form part of the terms of the License if the Initial Contributor places an "X" or "x" in the selection box alongside the YES answer to the question immediately below.
Is this a Patents-Included License pursuant to Section 2.2 of the License? Is this a Patents-Included License pursuant to Section 2.2 of the License?
YES [      ] YES [ ]
NO [      ] NO [ ]
By default, if YES is not selected by the Initial Contributor, the answer is NO. By default, if YES is not selected by the Initial Contributor, the answer is NO.

View file

@ -4,5 +4,5 @@ Any user of this software should understand that IBM cannot provide technical su
Any person who transfers this source code or any derivative work must include the IBM copyright notice, this paragraph, and the preceding two paragraphs in the transferred software. Any person who transfers this source code or any derivative work must include the IBM copyright notice, this paragraph, and the preceding two paragraphs in the transferred software.
COPYRIGHT   I B M   CORPORATION 2002 COPYRIGHT I B M CORPORATION 2002
LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M LICENSED MATERIAL - PROGRAM PROPERTY OF I B M

View file

@ -12,15 +12,15 @@ The Licensor grants you a worldwide, royalty-free, perpetual, non-exclusive lice
This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations. This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations.
You are free to: You are free to:
copy, publish, distribute and transmit the Information; copy, publish, distribute and transmit the Information;
adapt the Information; adapt the Information;
exploit the Information for Non-Commercial purposes for example, by combining it with other information in your own product or application. exploit the Information for Non-Commercial purposes for example, by combining it with other information in your own product or application.
You are not permitted to: You are not permitted to:
exercise any of the rights granted to you by this licence in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. exercise any of the rights granted to you by this licence in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation.
You must, where you do any of the above: You must, where you do any of the above:
acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence; acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence;
If the Information Provider does not provide a specific attribution statement, you must use the following: If the Information Provider does not provide a specific attribution statement, you must use the following:
Contains information licensed under the Non-Commercial Government Licence v2.0. Contains information licensed under the Non-Commercial Government Licence v2.0.

View file

@ -2,7 +2,7 @@ Netscape Public LIcense version 1.1
AMENDMENTS AMENDMENTS
The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License.  Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1. The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License. Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1.
Additional Terms applicable to the Netscape Public License. Additional Terms applicable to the Netscape Public License.
@ -28,7 +28,7 @@ Additional Terms applicable to the Netscape Public License.
Notwithstanding the limitations of Section 11 above, the provisions regarding litigation in Section 11(a), (b) and (c) of the License shall apply to all disputes relating to this License. Notwithstanding the limitations of Section 11 above, the provisions regarding litigation in Section 11(a), (b) and (c) of the License shall apply to all disputes relating to this License.
EXHIBIT A-Netscape Public License. EXHIBIT A-Netscape Public License.
 
"The contents of this file are subject to the Netscape Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/NPL/ "The contents of this file are subject to the Netscape Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License.
@ -37,8 +37,8 @@ The Original Code is Mozilla Communicator client code, released March 31, 1998.
The Initial Developer of the Original Code is Netscape Communications Corporation. Portions created by Netscape are Copyright (C) 1998-1999 Netscape Communications Corporation. All Rights Reserved. The Initial Developer of the Original Code is Netscape Communications Corporation. Portions created by Netscape are Copyright (C) 1998-1999 Netscape Communications Corporation. All Rights Reserved.
Contributor(s): ______________________________________. Contributor(s): ______________________________________.
 
Alternatively, the contents of this file may be used under the terms of the _____ license (the  "[___] License"), in which case the provisions of [______] License are applicable  instead of those above.  If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting  the provisions above and replace  them with the notice and other provisions required by the [___] License.  If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License." Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License."
Mozilla Public License Version 1.1 Mozilla Public License Version 1.1

View file

@ -6,7 +6,7 @@ OPEN CASCADE releases and makes publicly available the source code of the softwa
It is not the purpose of this license to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this license has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. It is not the purpose of this license to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this license has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
Please read this license carefully and completely before downloading this software. By downloading, using, modifying, distributing and sublicensing this software, you indicate your acceptance to be bound by the terms and conditions of this license. If you do not want to accept or cannot accept for any reasons the terms and conditions of this license, please do not download or use in any manner this software. Please read this license carefully and completely before downloading this software. By downloading, using, modifying, distributing and sublicensing this software, you indicate your acceptance to be bound by the terms and conditions of this license. If you do not want to accept or cannot accept for any reasons the terms and conditions of this license, please do not download or use in any manner this software.
 
1. Definitions 1. Definitions
Unless there is something in the subject matter or in the context inconsistent therewith, the capitalized terms used in this License shall have the following meaning. Unless there is something in the subject matter or in the context inconsistent therewith, the capitalized terms used in this License shall have the following meaning.
@ -26,13 +26,13 @@ Unless there is something in the subject matter or in the context inconsistent t
"Software": means the Original Code, the Modifications, the combination of Original Code and any Modifications or any respective portions thereof. "Software": means the Original Code, the Modifications, the combination of Original Code and any Modifications or any respective portions thereof.
"You" or "Your": means an individual or a legal entity exercising rights under this License "You" or "Your": means an individual or a legal entity exercising rights under this License
 
2. Acceptance of license 2. Acceptance of license
By using, reproducing, modifying, distributing or sublicensing the Software or any portion thereof, You expressly indicate Your acceptance of the terms and conditions of this License and undertake to act in accordance with all the provisions of this License applicable to You. By using, reproducing, modifying, distributing or sublicensing the Software or any portion thereof, You expressly indicate Your acceptance of the terms and conditions of this License and undertake to act in accordance with all the provisions of this License applicable to You.
 
3. Scope and purpose 3. Scope and purpose
This License applies to the Software and You may not use, reproduce, modify, distribute, sublicense or circulate the Software, or any portion thereof, except as expressly provided under this License. Any attempt to otherwise use, reproduce, modify, distribute or sublicense the Software is void and will automatically terminate Your rights under this License. This License applies to the Software and You may not use, reproduce, modify, distribute, sublicense or circulate the Software, or any portion thereof, except as expressly provided under this License. Any attempt to otherwise use, reproduce, modify, distribute or sublicense the Software is void and will automatically terminate Your rights under this License.
 
4. Contributor license 4. Contributor license
Subject to the terms and conditions of this License, the Initial Developer and each of the Contributors hereby grant You a world-wide, royalty-free, irrevocable and non-exclusive license under the Applicable Intellectual Property Rights they own or control, to use, reproduce, modify, distribute and sublicense the Software provided that: Subject to the terms and conditions of this License, the Initial Developer and each of the Contributors hereby grant You a world-wide, royalty-free, irrevocable and non-exclusive license under the Applicable Intellectual Property Rights they own or control, to use, reproduce, modify, distribute and sublicense the Software provided that:

View file

@ -10,20 +10,20 @@ The Licensor grants you a worldwide, royalty-free, perpetual, non-exclusive lice
This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations. This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations.
You are free to: You are free to:
copy, publish, distribute and transmit the Information; copy, publish, distribute and transmit the Information;
adapt the Information; adapt the Information;
exploit the Information commercially for example, by combining it with other Information, or by including it in your own product or application. exploit the Information commercially for example, by combining it with other Information, or by including it in your own product or application.
You must, where you do any of the above: You must, where you do any of the above:
acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence; acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence;
 If the Information Provider does not provide a specific attribution statement, or if you are using Information from several Information Providers and multiple attributions are not practical in your product or application, you may consider using the following: Contains public sector information licensed under the Open Government Licence v1.0. If the Information Provider does not provide a specific attribution statement, or if you are using Information from several Information Providers and multiple attributions are not practical in your product or application, you may consider using the following: Contains public sector information licensed under the Open Government Licence v1.0.
ensure that you do not use the Information in a way that suggests any official status or that the Information Provider endorses you or your use of the Information; ensure that you do not use the Information in a way that suggests any official status or that the Information Provider endorses you or your use of the Information;
ensure that you do not mislead others or misrepresent the Information or its source; ensure that you do not mislead others or misrepresent the Information or its source;
ensure that your use of the Information does not breach the Data Protection Act 1998 or the Privacy and Electronic Communications (EC Directive) Regulations 2003. ensure that your use of the Information does not breach the Data Protection Act 1998 or the Privacy and Electronic Communications (EC Directive) Regulations 2003.
These are important conditions of this licence and if you fail to comply with them the rights granted to you under this licence, or any similar licence granted by the Licensor, will end automatically. These are important conditions of this licence and if you fail to comply with them the rights granted to you under this licence, or any similar licence granted by the Licensor, will end automatically.
 Exemptions Exemptions
This licence does not cover the use of: This licence does not cover the use of:
- personal data in the Information; - personal data in the Information;
@ -48,22 +48,22 @@ Definitions
In this licence, the terms below have the following meanings: In this licence, the terms below have the following meanings:
Informationmeans information protected by copyright or by database right (for example, literary and artistic works, content, data and source code) offered for use under the terms of this licence. Information means information protected by copyright or by database right (for example, literary and artistic works, content, data and source code) offered for use under the terms of this licence.
Information Providermeans the person or organisation providing the Information under this licence. Information Provider means the person or organisation providing the Information under this licence.
Licensormeans any Information Provider which has the authority to offer Information under the terms of this licence or the Controller of Her Majestys Stationery Office, who has the authority to offer Information subject to Crown copyright and Crown database rights and Information subject to copyright and database right that has been assigned to or acquired by the Crown, under the terms of this licence. Licensor means any Information Provider which has the authority to offer Information under the terms of this licence or the Controller of Her Majestys Stationery Office, who has the authority to offer Information subject to Crown copyright and Crown database rights and Information subject to copyright and database right that has been assigned to or acquired by the Crown, under the terms of this licence.
Useas a verb, means doing any act which is restricted by copyright or database right, whether in the original medium or in any other medium, and includes without limitation distributing, copying, adapting, modifying as may be technically necessary to use it in a different mode or format. Use as a verb, means doing any act which is restricted by copyright or database right, whether in the original medium or in any other medium, and includes without limitation distributing, copying, adapting, modifying as may be technically necessary to use it in a different mode or format.
Youmeans the natural or legal person, or body of persons corporate or incorporate, acquiring rights under this licence. You means the natural or legal person, or body of persons corporate or incorporate, acquiring rights under this licence.
About the Open Government Licence About the Open Government Licence
The Controller of Her Majestys Stationery Office (HMSO) has developed this licence as a tool to enable Information Providers in the public sector to license the use and re-use of their Information under a common open licence. The Controller invites public sector bodies owning their own copyright and database rights to permit the use of their Information under this licence. The Controller of Her Majestys Stationery Office (HMSO) has developed this licence as a tool to enable Information Providers in the public sector to license the use and re-use of their Information under a common open licence. The Controller invites public sector bodies owning their own copyright and database rights to permit the use of their Information under this licence.
The Controller of HMSO has authority to license Information subject to copyright and database right owned by the Crown. The extent of the Controllers offer to license this Information under the terms of this licence is set out in the UK Government Licensing Framework. The Controller of HMSO has authority to license Information subject to copyright and database right owned by the Crown. The extent of the Controllers offer to license this Information under the terms of this licence is set out in the UK Government Licensing Framework.
This is version 1.0 of the Open Government Licence. The Controller of HMSO may, from time to time, issue new versions of the Open Government Licence. However, you may continue to use Information licensed under this version should you wish to do so. This is version 1.0 of the Open Government Licence. The Controller of HMSO may, from time to time, issue new versions of the Open Government Licence. However, you may continue to use Information licensed under this version should you wish to do so.
These terms have been aligned to be interoperable with any Creative Commons Attribution Licence, which covers copyright, and Open Data Commons Attribution License, which covers database rights and applicable copyrights. These terms have been aligned to be interoperable with any Creative Commons Attribution Licence, which covers copyright, and Open Data Commons Attribution License, which covers database rights and applicable copyrights.
Further context, best practice and guidance can be found in the UK Government Licensing Framework section on The National Archives website. Further context, best practice and guidance can be found in the UK Government Licensing Framework section on The National Archives website.

View file

@ -100,7 +100,8 @@ If it is impossible for You to comply with any of the terms of this License with
5.1 Failure to Comply 5.1 Failure to Comply
The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60-days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30-days after Your receipt of the notice. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60-days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30-days after Your receipt of the notice.
5.2 Patent Infringement Claims If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.2 Patent Infringement Claims
If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.
5.3 Additional Compliance Terms 5.3 Additional Compliance Terms
Notwithstanding the foregoing in this Section 5, for purposes of this Section, if You breach Section 3.1 (Distribution of Source Form), Section 3.2 (Distribution of Executable Form), Section 3.3 (Distribution of a Larger Work), or Section 3.4 (Notices), then becoming compliant as described in Section 5.1 must also include, no later than 30 days after receipt by You of notice of such violation by a Contributor, making the Covered Software available in Source Code Form as required by this License on a publicly available computer network for a period of no less than three (3) years. Notwithstanding the foregoing in this Section 5, for purposes of this Section, if You breach Section 3.1 (Distribution of Source Form), Section 3.2 (Distribution of Executable Form), Section 3.3 (Distribution of a Larger Work), or Section 3.4 (Notices), then becoming compliant as described in Section 5.1 must also include, no later than 30 days after receipt by You of notice of such violation by a Contributor, making the Covered Software available in Source Code Form as required by this License on a publicly available computer network for a period of no less than three (3) years.

View file

@ -1,22 +1,22 @@
# Solderpad Hardware Licence Version 2.0 # Solderpad Hardware Licence Version 2.0
This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation. This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation.
1. The definitions set out in the Apache License are modified as follows: 1. The definitions set out in the Apache License are modified as follows:
Copyright any reference to copyright (whether capitalised or not) includes Rights (as defined below). Copyright any reference to copyright (whether capitalised or not) includes Rights (as defined below).
Contribution also includes any design, as well as any work of authorship. Contribution also includes any design, as well as any work of authorship.
Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof. Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof.
Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works). Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works).
Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks). Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks).
Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files. Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files.
Work also includes a design or work of authorship, whether in Source form or other Object form. Work also includes a design or work of authorship, whether in Source form or other Object form.
2. Grant of Licence 2. Grant of Licence
2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist. 2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist.

View file

@ -19,7 +19,7 @@ The following definitions shall replace the corresponding definitions in the Apa
"License" shall mean this Solderpad Hardware License version 2.1, being the terms and conditions for use, manufacture, instantiation, adaptation, reproduction, and distribution as defined by Sections 1 through 9 of this document. "License" shall mean this Solderpad Hardware License version 2.1, being the terms and conditions for use, manufacture, instantiation, adaptation, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the Rights owner or entity authorized by the Rights owner that is granting the License. "Licensor" shall mean the Rights owner or entity authorized by the Rights owner that is granting the License.
 
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship or design. For the purposes of this License, Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the Work and Derivative Works thereof. "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship or design. For the purposes of this License, Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the Work and Derivative Works thereof.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object or material and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works). "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object or material and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works).

View file

@ -36,13 +36,13 @@ Sun Industry Standards Source License - Version 1.1
2.0 SOURCE CODE LICENSE 2.0 SOURCE CODE LICENSE
2.1 The Initial Developer Grant The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims:  2.1 The Initial Developer Grant The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims:
(a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices, including but not limited to Modifications.  (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices, including but not limited to Modifications.
3.0 DISTRIBUTION OBLIGATIONS 3.0 DISTRIBUTION OBLIGATIONS
@ -92,14 +92,14 @@ This License represents the complete agreement concerning subject matter hereof.
EXHIBIT A - Sun Standards License EXHIBIT A - Sun Standards License
"The contents of this file are subject to the Sun Standards License Version 1.1 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at _______________________________. "The contents of this file are subject to the Sun Standards License Version 1.1 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at _______________________________.
Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the License for the specific language governing rights and limitations under the License. express or implied. See the License for the specific language governing rights and limitations under the License.
The Original Code is ______________________________________. The Original Code is ______________________________________.
The Initial Developer of the Original Code is:  The Initial Developer of the Original Code is:
Sun Microsystems, Inc.. Sun Microsystems, Inc..
Portions created by: _______________________________________ Portions created by: _______________________________________

View file

@ -4,7 +4,7 @@ Copyright (c) 1994-2002 World Wide Web Consortium, (Massachusetts Institute of T
This W3C work (including software, documents, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: This W3C work (including software, documents, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its documentation, with or without modification,  for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make:
1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. 1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.

View file

@ -311,7 +311,7 @@ func SearchIssues(ctx *context.APIContext) {
ctx.SetLinkHeader(int(total), limit) ctx.SetLinkHeader(int(total), limit)
ctx.SetTotalCountHeader(total) ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
} }
// ListIssues list the issues of a repository // ListIssues list the issues of a repository
@ -548,7 +548,7 @@ func ListIssues(ctx *context.APIContext) {
ctx.SetLinkHeader(int(total), listOptions.PageSize) ctx.SetLinkHeader(int(total), listOptions.PageSize)
ctx.SetTotalCountHeader(total) ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
} }
func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 { func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 {
@ -614,7 +614,7 @@ func GetIssue(ctx *context.APIContext) {
ctx.NotFound() ctx.NotFound()
return return
} }
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue)) ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue))
} }
// CreateIssue create an issue of a repository // CreateIssue create an issue of a repository
@ -737,7 +737,7 @@ func CreateIssue(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "GetIssueByID", err) ctx.Error(http.StatusInternalServerError, "GetIssueByID", err)
return return
} }
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue))
} }
// EditIssue modify an issue of a repository // EditIssue modify an issue of a repository
@ -913,7 +913,7 @@ func EditIssue(ctx *context.APIContext) {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
} }
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue))
} }
func DeleteIssue(ctx *context.APIContext) { func DeleteIssue(ctx *context.APIContext) {

View file

@ -108,7 +108,7 @@ func ListIssueAttachments(ctx *context.APIContext) {
return return
} }
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments) ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue).Attachments)
} }
// CreateIssueAttachment creates an attachment and saves the given file // CreateIssueAttachment creates an attachment and saves the given file

View file

@ -153,7 +153,7 @@ func GetIssueDependencies(ctx *context.APIContext) {
blockerIssues = append(blockerIssues, &blocker.Issue) blockerIssues = append(blockerIssues, &blocker.Issue)
} }
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, blockerIssues)) ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, blockerIssues))
} }
// CreateIssueDependency create a new issue dependencies // CreateIssueDependency create a new issue dependencies
@ -214,7 +214,7 @@ func CreateIssueDependency(ctx *context.APIContext) {
return return
} }
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target)) ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target))
} }
// RemoveIssueDependency remove an issue dependency // RemoveIssueDependency remove an issue dependency
@ -275,7 +275,7 @@ func RemoveIssueDependency(ctx *context.APIContext) {
return return
} }
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target)) ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target))
} }
// GetIssueBlocks list issues that are blocked by this issue // GetIssueBlocks list issues that are blocked by this issue
@ -381,7 +381,7 @@ func GetIssueBlocks(ctx *context.APIContext) {
issues = append(issues, &depMeta.Issue) issues = append(issues, &depMeta.Issue)
} }
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
} }
// CreateIssueBlocking block the issue given in the body by the issue in path // CreateIssueBlocking block the issue given in the body by the issue in path
@ -438,7 +438,7 @@ func CreateIssueBlocking(ctx *context.APIContext) {
return return
} }
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency)) ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency))
} }
// RemoveIssueBlocking unblock the issue given in the body by the issue in path // RemoveIssueBlocking unblock the issue given in the body by the issue in path
@ -495,7 +495,7 @@ func RemoveIssueBlocking(ctx *context.APIContext) {
return return
} }
ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency)) ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency))
} }
func getParamsIssue(ctx *context.APIContext) *issues_model.Issue { func getParamsIssue(ctx *context.APIContext) *issues_model.Issue {

View file

@ -207,7 +207,7 @@ func ListPinnedIssues(ctx *context.APIContext) {
return return
} }
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
} }
// ListPinnedPullRequests returns a list of all pinned PRs // ListPinnedPullRequests returns a list of all pinned PRs

View file

@ -138,7 +138,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
} }
ctx.SetTotalCountHeader(count) ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
} }
// AddTime add time manual to the given issue // AddTime add time manual to the given issue
@ -225,7 +225,7 @@ func AddTime(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, trackedTime)) ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, user, trackedTime))
} }
// ResetIssueTime reset time manual to the given issue // ResetIssueTime reset time manual to the given issue
@ -455,7 +455,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return return
} }
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
} }
// ListTrackedTimesByRepository lists all tracked times of the repository // ListTrackedTimesByRepository lists all tracked times of the repository
@ -567,7 +567,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
} }
ctx.SetTotalCountHeader(count) ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
} }
// ListMyTrackedTimes lists all tracked times of the current user // ListMyTrackedTimes lists all tracked times of the current user
@ -629,5 +629,5 @@ func ListMyTrackedTimes(ctx *context.APIContext) {
} }
ctx.SetTotalCountHeader(count) ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
} }

View file

@ -27,7 +27,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
defer rd.Close() defer rd.Close()
if err := json.NewDecoder(rd).Decode(&genRequest); err != nil { if err := json.NewDecoder(rd).Decode(&genRequest); err != nil {
log.Error("%v", err) log.Error("JSON Decode failed: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(), Err: err.Error(),
}) })
@ -36,7 +36,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
owner, repo, err := parseScope(ctx, genRequest.Scope) owner, repo, err := parseScope(ctx, genRequest.Scope)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("parseScope failed: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(), Err: err.Error(),
}) })
@ -46,18 +46,18 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) {
token, err = actions_model.NewRunnerToken(ctx, owner, repo) token, err = actions_model.NewRunnerToken(ctx, owner, repo)
if err != nil { if err != nil {
err := fmt.Sprintf("error while creating runner token: %v", err) errMsg := fmt.Sprintf("error while creating runner token: %v", err)
log.Error("%v", err) log.Error("NewRunnerToken failed: %v", errMsg)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err, Err: errMsg,
}) })
return return
} }
} else if err != nil { } else if err != nil {
err := fmt.Sprintf("could not get unactivated runner token: %v", err) errMsg := fmt.Sprintf("could not get unactivated runner token: %v", err)
log.Error("%v", err) log.Error("GetLatestRunnerToken failed: %v", errMsg)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err, Err: errMsg,
}) })
return return
} }

View file

@ -47,7 +47,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
_ = stdoutWriter.Close() _ = stdoutWriter.Close()
err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env) err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("readAndVerifyCommitsFromShaReader failed: %v", err)
cancel() cancel()
} }
_ = stdoutReader.Close() _ = stdoutReader.Close()
@ -66,7 +66,6 @@ func readAndVerifyCommitsFromShaReader(input io.ReadCloser, repo *git.Repository
line := scanner.Text() line := scanner.Text()
err := readAndVerifyCommit(line, repo, env) err := readAndVerifyCommit(line, repo, env)
if err != nil { if err != nil {
log.Error("%v", err)
return err return err
} }
} }

View file

@ -35,7 +35,7 @@ func SendEmail(ctx *context.PrivateContext) {
defer rd.Close() defer rd.Close()
if err := json.NewDecoder(rd).Decode(&mail); err != nil { if err := json.NewDecoder(rd).Decode(&mail); err != nil {
log.Error("%v", err) log.Error("JSON Decode failed: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(), Err: err.Error(),
}) })

View file

@ -403,7 +403,6 @@ func EditUserPost(ctx *context.Context) {
ctx.Data["Err_Password"] = true ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplUserEdit, &form) ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplUserEdit, &form)
case password.IsErrIsPwnedRequest(err): case password.IsErrIsPwnedRequest(err):
log.Error("%s", err.Error())
ctx.Data["Err_Password"] = true ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form) ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form)
default: default:

View file

@ -214,7 +214,6 @@ func ResetPasswdPost(ctx *context.Context) {
case errors.Is(err, password.ErrIsPwned): case errors.Is(err, password.ErrIsPwned):
ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplResetPassword, nil) ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplResetPassword, nil)
case password.IsErrIsPwnedRequest(err): case password.IsErrIsPwnedRequest(err):
log.Error("%s", err.Error())
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil) ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil)
default: default:
ctx.ServerError("UpdateAuth", err) ctx.ServerError("UpdateAuth", err)
@ -298,7 +297,6 @@ func MustChangePasswordPost(ctx *context.Context) {
ctx.Data["Err_Password"] = true ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplMustChangePassword, &form) ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplMustChangePassword, &form)
case password.IsErrIsPwnedRequest(err): case password.IsErrIsPwnedRequest(err):
log.Error("%s", err.Error())
ctx.Data["Err_Password"] = true ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form) ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form)
default: default:

View file

@ -7,7 +7,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"strings" "strings"
@ -195,14 +194,15 @@ func NewProjectPost(ctx *context.Context) {
// ChangeProjectStatus updates the status of a project between "open" and "close" // ChangeProjectStatus updates the status of a project between "open" and "close"
func ChangeProjectStatus(ctx *context.Context) { func ChangeProjectStatus(ctx *context.Context) {
toClose := false var toClose bool
switch ctx.Params(":action") { switch ctx.Params(":action") {
case "open": case "open":
toClose = false toClose = false
case "close": case "close":
toClose = true toClose = true
default: default:
ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects") ctx.JSONRedirect(ctx.ContextUser.HomeLink() + "/-/projects")
return
} }
id := ctx.ParamsInt64(":id") id := ctx.ParamsInt64(":id")
@ -210,7 +210,7 @@ func ChangeProjectStatus(ctx *context.Context) {
ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
return return
} }
ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects?state=" + url.QueryEscape(ctx.Params(":action"))) ctx.JSONRedirect(fmt.Sprintf("%s/-/projects/%d", ctx.ContextUser.HomeLink(), id))
} }
// DeleteProject delete a project // DeleteProject delete a project

View file

@ -2174,7 +2174,7 @@ func GetIssueInfo(ctx *context.Context) {
} }
} }
ctx.JSON(http.StatusOK, convert.ToIssue(ctx, issue)) ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue))
} }
// UpdateIssueTitle change issue's title // UpdateIssueTitle change issue's title
@ -2708,7 +2708,7 @@ func SearchIssues(ctx *context.Context) {
} }
ctx.SetTotalCountHeader(total) ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues)) ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues))
} }
func getUserIDForFilter(ctx *context.Context, queryName string) int64 { func getUserIDForFilter(ctx *context.Context, queryName string) int64 {
@ -2878,7 +2878,7 @@ func ListIssues(ctx *context.Context) {
} }
ctx.SetTotalCountHeader(total) ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues)) ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues))
} }
func BatchDeleteIssues(ctx *context.Context) { func BatchDeleteIssues(ctx *context.Context) {

View file

@ -7,7 +7,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"strings" "strings"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@ -180,14 +179,10 @@ func ChangeProjectStatus(ctx *context.Context) {
id := ctx.ParamsInt64(":id") id := ctx.ParamsInt64(":id")
if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil {
if project_model.IsErrProjectNotExist(err) { ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
ctx.NotFound("", err)
} else {
ctx.ServerError("ChangeProjectStatusByIDAndRepoID", err)
}
return return
} }
ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects?state=" + url.QueryEscape(ctx.Params(":action"))) ctx.JSONRedirect(fmt.Sprintf("%s/projects/%d", ctx.Repo.RepoLink, id))
} }
// DeleteProject delete a project // DeleteProject delete a project

View file

@ -376,7 +376,7 @@ func Action(ctx *context.Context) {
} }
if redirectViaJSON { if redirectViaJSON {
ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]any{
"redirect": ctx.ContextUser.HomeLink(), "redirect": ctx.ContextUser.HomeLink(),
}) })
return return

View file

@ -74,7 +74,6 @@ func AccountPost(ctx *context.Context) {
case errors.Is(err, password.ErrIsPwned): case errors.Is(err, password.ErrIsPwned):
ctx.Flash.Error(ctx.Tr("auth.password_pwned")) ctx.Flash.Error(ctx.Tr("auth.password_pwned"))
case password.IsErrIsPwnedRequest(err): case password.IsErrIsPwnedRequest(err):
log.Error("%s", err.Error())
ctx.Flash.Error(ctx.Tr("auth.password_pwned_err")) ctx.Flash.Error(ctx.Tr("auth.password_pwned_err"))
default: default:
ctx.ServerError("UpdateAuth", err) ctx.ServerError("UpdateAuth", err)

View file

@ -20,7 +20,7 @@ func TestCreateAuthorizationToken(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.NotEqual(t, "", token) assert.NotEqual(t, "", token)
claims := jwt.MapClaims{} claims := jwt.MapClaims{}
_, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) { _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (any, error) {
return setting.GetGeneralTokenSigningSecret(), nil return setting.GetGeneralTokenSigningSecret(), nil
}) })
assert.Nil(t, err) assert.Nil(t, err)

View file

@ -49,7 +49,7 @@ func (n *actionsNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).WithPayload(&api.IssuePayload{ newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).WithPayload(&api.IssuePayload{
Action: api.HookIssueOpened, Action: api.HookIssueOpened,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue.Poster, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, issue.Poster, nil), Sender: convert.ToUser(ctx, issue.Poster, nil),
}).Notify(withMethod(ctx, "NewIssue")) }).Notify(withMethod(ctx, "NewIssue"))
@ -89,7 +89,7 @@ func (n *actionsNotifier) IssueChangeContent(ctx context.Context, doer *user_mod
WithPayload(&api.IssuePayload{ WithPayload(&api.IssuePayload{
Action: api.HookIssueEdited, Action: api.HookIssueEdited,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}). }).
@ -127,7 +127,7 @@ func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode
} }
apiIssue := &api.IssuePayload{ apiIssue := &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
} }
@ -229,7 +229,7 @@ func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues
WithPayload(&api.IssuePayload{ WithPayload(&api.IssuePayload{
Action: action, Action: action,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}). }).
@ -293,7 +293,7 @@ func notifyIssueCommentChange(ctx context.Context, doer *user_model.User, commen
payload := &api.IssueCommentPayload{ payload := &api.IssueCommentPayload{
Action: action, Action: action,
Issue: convert.ToAPIIssue(ctx, comment.Issue), Issue: convert.ToAPIIssue(ctx, doer, comment.Issue),
Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, 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),

View file

@ -560,12 +560,9 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
} }
// We need a notifyInput to call handleSchedules // We need a notifyInput to call handleSchedules
// Here we use the commit author as the Doer of the notifyInput // if repo is a mirror, commit author maybe an external user,
commitUser, err := user_model.GetUserByEmail(ctx, commit.Author.Email) // so we use action user as the Doer of the notifyInput
if err != nil { notifyInput := newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule)
return fmt.Errorf("get user by email: %w", err)
}
notifyInput := newNotifyInput(repo, commitUser, webhook_module.HookEventSchedule)
return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch)
} }

View file

@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
session_module "code.gitea.io/gitea/modules/session"
chiSession "gitea.com/go-chi/session" chiSession "gitea.com/go-chi/session"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
@ -65,7 +66,7 @@ func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *s
chiStore := chiSession.GetSession(r) chiStore := chiSession.GetSession(r)
if session.IsNew { if session.IsNew {
_, _ = chiSession.RegenerateSession(w, r) _, _ = session_module.RegenerateSession(w, r)
session.IsNew = false session.IsNew = false
} }

View file

@ -79,11 +79,11 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) {
case setting.CfTurnstile: case setting.CfTurnstile:
valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField)) valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField))
default: default:
ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType))
return return
} }
if err != nil { if err != nil {
log.Debug("%v", err) log.Debug("Captcha Verify failed: %v", err)
} }
if !valid { if !valid {

View file

@ -18,19 +18,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 { func ToIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue {
return toIssue(ctx, issue, WebAssetDownloadURL) return toIssue(ctx, doer, 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, doer *user_model.User, issue *issues_model.Issue) *api.Issue {
return toIssue(ctx, issue, APIAssetDownloadURL) return toIssue(ctx, doer, issue, APIAssetDownloadURL)
} }
func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue { func toIssue(ctx context.Context, doer *user_model.User, 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{}
} }
@ -44,7 +44,7 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func
apiIssue := &api.Issue{ apiIssue := &api.Issue{
ID: issue.ID, ID: issue.ID,
Index: issue.Index, Index: issue.Index,
Poster: ToUser(ctx, issue.Poster, nil), Poster: ToUser(ctx, issue.Poster, doer),
Title: issue.Title, Title: issue.Title,
Body: issue.Content, Body: issue.Content,
Attachments: toAttachments(issue.Repo, issue.Attachments, getDownloadURL), Attachments: toAttachments(issue.Repo, issue.Attachments, getDownloadURL),
@ -114,25 +114,25 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func
} }
// ToIssueList converts an IssueList to API format // ToIssueList converts an IssueList to API format
func ToIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue { func ToIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue {
result := make([]*api.Issue, len(il)) result := make([]*api.Issue, len(il))
for i := range il { for i := range il {
result[i] = ToIssue(ctx, il[i]) result[i] = ToIssue(ctx, doer, il[i])
} }
return result 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, doer *user_model.User, il issues_model.IssueList) []*api.Issue {
result := make([]*api.Issue, len(il)) result := make([]*api.Issue, len(il))
for i := range il { for i := range il {
result[i] = ToAPIIssue(ctx, il[i]) result[i] = ToAPIIssue(ctx, doer, il[i])
} }
return result return result
} }
// ToTrackedTime converts TrackedTime to API format // ToTrackedTime converts TrackedTime to API format
func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { func ToTrackedTime(ctx context.Context, doer *user_model.User, t *issues_model.TrackedTime) (apiT *api.TrackedTime) {
apiT = &api.TrackedTime{ apiT = &api.TrackedTime{
ID: t.ID, ID: t.ID,
IssueID: t.IssueID, IssueID: t.IssueID,
@ -141,7 +141,7 @@ func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.
Created: t.Created, Created: t.Created,
} }
if t.Issue != nil { if t.Issue != nil {
apiT.Issue = ToAPIIssue(ctx, t.Issue) apiT.Issue = ToAPIIssue(ctx, doer, t.Issue)
} }
if t.User != nil { if t.User != nil {
apiT.UserName = t.User.Name apiT.UserName = t.User.Name
@ -192,10 +192,10 @@ func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.Stop
} }
// ToTrackedTimeList converts TrackedTimeList to API format // ToTrackedTimeList converts TrackedTimeList to API format
func ToTrackedTimeList(ctx context.Context, tl issues_model.TrackedTimeList) api.TrackedTimeList { func ToTrackedTimeList(ctx context.Context, doer *user_model.User, tl issues_model.TrackedTimeList) api.TrackedTimeList {
result := make([]*api.TrackedTime, 0, len(tl)) result := make([]*api.TrackedTime, 0, len(tl))
for _, t := range tl { for _, t := range tl {
result = append(result, ToTrackedTime(ctx, t)) result = append(result, ToTrackedTime(ctx, doer, t))
} }
return result return result
} }

View file

@ -120,7 +120,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
return nil return nil
} }
comment.TrackedTime = ToTrackedTime(ctx, c.Time) comment.TrackedTime = ToTrackedTime(ctx, doer, c.Time)
} }
if c.RefIssueID != 0 { if c.RefIssueID != 0 {
@ -129,7 +129,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
log.Error("GetIssueByID(%d): %v", c.RefIssueID, err) log.Error("GetIssueByID(%d): %v", c.RefIssueID, err)
return nil return nil
} }
comment.RefIssue = ToAPIIssue(ctx, issue) comment.RefIssue = ToAPIIssue(ctx, doer, issue)
} }
if c.RefCommentID != 0 { if c.RefCommentID != 0 {
@ -180,7 +180,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
} }
if c.DependentIssue != nil { if c.DependentIssue != nil {
comment.DependentIssue = ToAPIIssue(ctx, c.DependentIssue) comment.DependentIssue = ToAPIIssue(ctx, doer, c.DependentIssue)
} }
return comment return comment

View file

@ -33,7 +33,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
return nil return nil
} }
apiIssue := ToAPIIssue(ctx, pr.Issue) apiIssue := ToAPIIssue(ctx, doer, pr.Issue)
if err := pr.LoadBaseRepo(ctx); err != nil { if err := pr.LoadBaseRepo(ctx); err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.ID, err) log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
return nil return nil

View file

@ -72,6 +72,11 @@ func (g *GitBucketDownloader) LogString() string {
// NewGitBucketDownloader creates a GitBucket downloader // NewGitBucketDownloader creates a GitBucket downloader
func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader { func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader {
githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName) githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName)
// Gitbucket 4.40 uses different internal hard-coded perPage values.
// Issues, PRs, and other major parts use 25. Release page uses 10.
// Some API doesn't support paging yet. Sounds difficult, but using
// minimum number among them worked out very well.
githubDownloader.maxPerPage = 10
githubDownloader.SkipReactions = true githubDownloader.SkipReactions = true
githubDownloader.SkipReviews = true githubDownloader.SkipReviews = true
return &GitBucketDownloader{ return &GitBucketDownloader{

View file

@ -13,6 +13,7 @@ import (
system_model "code.gitea.io/gitea/models/system" system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
giturl "code.gitea.io/gitea/modules/git/url"
"code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -30,10 +31,15 @@ const gitShortEmptySha = "0000000"
// UpdateAddress writes new address to Git repository and database // UpdateAddress writes new address to Git repository and database
func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error { func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error {
u, err := giturl.Parse(addr)
if err != nil {
return fmt.Errorf("invalid addr: %v", err)
}
remoteName := m.GetRemoteName() remoteName := m.GetRemoteName()
repoPath := m.GetRepository(ctx).RepoPath() repoPath := m.GetRepository(ctx).RepoPath()
// Remove old remote // Remove old remote
_, _, err := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) _, _, err = git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err return err
} }
@ -70,7 +76,9 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
} }
} }
m.Repo.OriginalURL = addr // erase authentication before storing in database
u.User = nil
m.Repo.OriginalURL = u.String()
return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url") return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url")
} }
@ -449,19 +457,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
return false return false
} }
var gitRepo *git.Repository gitRepo, err := gitrepo.OpenRepository(ctx, m.Repo)
if len(results) == 0 {
log.Trace("SyncMirrors [repo: %-v]: no branches updated", m.Repo)
} else {
log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
gitRepo, err = gitrepo.OpenRepository(ctx, m.Repo)
if err != nil { if err != nil {
log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err) log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
return false return false
} }
defer gitRepo.Close() defer gitRepo.Close()
log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
if len(results) > 0 {
if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok { if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok {
log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err)
return false return false
} }
} }
@ -534,6 +540,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
} }
log.Trace("SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time", m.Repo) log.Trace("SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time", m.Repo)
isEmpty, err := gitRepo.IsEmpty()
if err != nil {
log.Error("SyncMirrors [repo: %-v]: unable to check empty git repo: %v", m.Repo, err)
return false
}
if !isEmpty {
// Get latest commit date and update to current repository updated time // Get latest commit date and update to current repository updated time
commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath()) commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath())
if err != nil { if err != nil {
@ -546,6 +558,8 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
return false return false
} }
}
log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo) log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo)
return true return true

View file

@ -91,7 +91,7 @@ func AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues
// NewPullRequest notifies new pull request to notifiers // NewPullRequest notifies new pull request to notifiers
func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) {
if err := pr.LoadIssue(ctx); err != nil { if err := pr.LoadIssue(ctx); err != nil {
log.Error("%v", err) log.Error("LoadIssue failed: %v", err)
return return
} }
if err := pr.Issue.LoadPoster(ctx); err != nil { if err := pr.Issue.LoadPoster(ctx); err != nil {
@ -112,7 +112,7 @@ func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *iss
// PullRequestReview notifies new pull request review // PullRequestReview notifies new pull request review
func PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { func PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
if err := review.LoadReviewer(ctx); err != nil { if err := review.LoadReviewer(ctx); err != nil {
log.Error("%v", err) log.Error("LoadReviewer failed: %v", err)
return return
} }
for _, notifier := range notifiers { for _, notifier := range notifiers {

View file

@ -28,7 +28,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
t, err := NewTemporaryUploadRepository(ctx, repo) t, err := NewTemporaryUploadRepository(ctx, repo)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("NewTemporaryUploadRepository failed: %v", err)
} }
defer t.Close() defer t.Close()
if err := t.Clone(opts.OldBranch, false); err != nil { if err := t.Clone(opts.OldBranch, false); err != nil {

View file

@ -111,7 +111,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
t, err := NewTemporaryUploadRepository(ctx, repo) t, err := NewTemporaryUploadRepository(ctx, repo)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("NewTemporaryUploadRepository failed: %v", err)
} }
defer t.Close() defer t.Close()
if err := t.Clone(opts.OldBranch, true); err != nil { if err := t.Clone(opts.OldBranch, true); err != nil {

View file

@ -143,7 +143,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
t, err := NewTemporaryUploadRepository(ctx, repo) t, err := NewTemporaryUploadRepository(ctx, repo)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("NewTemporaryUploadRepository failed: %v", err)
} }
defer t.Close() defer t.Close()
hasOldBranch := true hasOldBranch := true

View file

@ -67,7 +67,7 @@ func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{
Action: api.HookIssueLabelCleared, Action: api.HookIssueLabelCleared,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}) })
@ -168,7 +168,7 @@ func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
apiIssue := &api.IssuePayload{ apiIssue := &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
} }
@ -214,7 +214,7 @@ func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model
From: oldTitle, From: oldTitle,
}, },
}, },
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}) })
@ -250,7 +250,7 @@ func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode
} else { } else {
apiIssue := &api.IssuePayload{ apiIssue := &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
CommitID: commitID, CommitID: commitID,
@ -281,7 +281,7 @@ func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{
Action: api.HookIssueOpened, Action: api.HookIssueOpened,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue.Poster, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, issue.Poster, nil), Sender: convert.ToUser(ctx, issue.Poster, nil),
}); err != nil { }); err != nil {
@ -349,7 +349,7 @@ func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_mod
From: oldContent, From: oldContent,
}, },
}, },
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}) })
@ -384,7 +384,7 @@ func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.Us
permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer) permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer)
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, doer, c.Issue),
Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c), Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c),
Changes: &api.ChangesPayload{ Changes: &api.ChangesPayload{
Body: &api.ChangesFromPayload{ Body: &api.ChangesFromPayload{
@ -412,7 +412,7 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod
permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer)
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, doer, issue),
Comment: convert.ToAPIComment(ctx, repo, 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),
@ -449,7 +449,7 @@ func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.Us
permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer) permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer)
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, doer, comment.Issue),
Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, 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),
@ -533,7 +533,7 @@ func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{
Action: api.HookIssueLabelUpdated, Action: api.HookIssueLabelUpdated,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}) })
@ -575,7 +575,7 @@ func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{ err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{
Action: hookAction, Action: hookAction,
Index: issue.Index, Index: issue.Index,
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission), Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil), Sender: convert.ToUser(ctx, doer, nil),
}) })

View file

@ -209,7 +209,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
if isOldWikiExist { if isOldWikiExist {
err := gitRepo.RemoveFilesFromIndex(oldWikiPath) err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("RemoveFilesFromIndex failed: %v", err)
return err return err
} }
} }
@ -219,18 +219,18 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
objectHash, err := gitRepo.HashObject(strings.NewReader(content)) objectHash, err := gitRepo.HashObject(strings.NewReader(content))
if err != nil { if err != nil {
log.Error("%v", err) log.Error("HashObject failed: %v", err)
return err return err
} }
if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil { if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
log.Error("%v", err) log.Error("AddObjectToIndex failed: %v", err)
return err return err
} }
tree, err := gitRepo.WriteTree() tree, err := gitRepo.WriteTree()
if err != nil { if err != nil {
log.Error("%v", err) log.Error("WriteTree failed: %v", err)
return err return err
} }
@ -255,7 +255,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), committer, tree, commitTreeOpts) commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), committer, tree, commitTreeOpts)
if err != nil { if err != nil {
log.Error("%v", err) log.Error("CommitTree failed: %v", err)
return err return err
} }
@ -270,11 +270,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
0, 0,
), ),
}); err != nil { }); err != nil {
log.Error("%v", err) log.Error("Push failed: %v", err)
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) { if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
return err return err
} }
return fmt.Errorf("Push: %w", err) return fmt.Errorf("failed to push: %w", err)
} }
return nil return nil

View file

@ -62,10 +62,7 @@
<div class="ui modal admin" id="detail-modal"> <div class="ui modal admin" id="detail-modal">
<div class="header">{{ctx.Locale.Tr "admin.notices.view_detail_header"}}</div> <div class="header">{{ctx.Locale.Tr "admin.notices.view_detail_header"}}</div>
<div class="content"> <div class="content"><pre></pre></div>
<div class="sub header"></div>
<pre></pre>
</div>
</div> </div>
{{template "admin/layout_footer" .}} {{template "admin/layout_footer" .}}

View file

@ -13,10 +13,8 @@
<div class="ui four wide column"> <div class="ui four wide column">
{{template "shared/user/profile_big_avatar" .}} {{template "shared/user/profile_big_avatar" .}}
</div> </div>
<div class="ui twelve wide column"> <div class="ui twelve wide column tw-mb-4">
<div class="tw-mb-4">
{{template "user/overview/header" .}} {{template "user/overview/header" .}}
</div>
{{template "projects/list" .}} {{template "projects/list" .}}
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
{{template "base/head" .}} {{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content repository projects view-project"> <div role="main" aria-label="{{.Title}}" class="page-content repository projects view-project">
{{template "shared/user/org_profile_avatar" .}} {{template "shared/user/org_profile_avatar" .}}
<div class="ui container"> <div class="ui container tw-mb-4">
{{template "user/overview/header" .}} {{template "user/overview/header" .}}
</div> </div>
<div class="ui container fluid padded"> <div class="ui container fluid padded">

View file

@ -18,10 +18,10 @@
{{end}} {{end}}
{{end}} {{end}}
<div class="ui top attached header clearing segment tw-relative commit-header {{$class}}"> <div class="ui top attached header clearing segment tw-relative commit-header {{$class}}">
<div class="tw-flex tw-mb-4 tw-flex-wrap"> <div class="tw-flex tw-mb-4 tw-gap-1">
<h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3> <h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3>
{{if not $.PageIsWiki}} {{if not $.PageIsWiki}}
<div> <div class="commit-header-buttons">
<a class="ui primary tiny button" href="{{.SourcePath}}"> <a class="ui primary tiny button" href="{{.SourcePath}}">
{{ctx.Locale.Tr "repo.diff.browse_source"}} {{ctx.Locale.Tr "repo.diff.browse_source"}}
</a> </a>

View file

@ -111,7 +111,7 @@
{{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.IsArchived) $.IsShowingAllCommits}} {{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.IsArchived) $.IsShowingAllCommits}}
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} tw-mt-0" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if or ($file.ShouldBeHidden) (not $isExpandable)}}data-folded="true"{{end}}> <div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} tw-mt-0" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if or ($file.ShouldBeHidden) (not $isExpandable)}}data-folded="true"{{end}}>
<h4 class="diff-file-header sticky-2nd-row ui top attached header tw-font-normal tw-flex tw-items-center tw-justify-between tw-flex-wrap"> <h4 class="diff-file-header sticky-2nd-row ui top attached header tw-font-normal tw-flex tw-items-center tw-justify-between tw-flex-wrap">
<div class="diff-file-name tw-flex tw-items-center gt-gap-2 tw-flex-wrap"> <div class="diff-file-name tw-flex tw-flex-1 tw-items-center tw-gap-1 tw-flex-wrap">
<button class="fold-file btn interact-bg tw-p-1{{if not $isExpandable}} tw-invisible{{end}}"> <button class="fold-file btn interact-bg tw-p-1{{if not $isExpandable}} tw-invisible{{end}}">
{{if $file.ShouldBeHidden}} {{if $file.ShouldBeHidden}}
{{svg "octicon-chevron-right" 18}} {{svg "octicon-chevron-right" 18}}
@ -128,7 +128,8 @@
{{template "repo/diff/stats" dict "file" . "root" $}} {{template "repo/diff/stats" dict "file" . "root" $}}
{{end}} {{end}}
</div> </div>
<span class="file tw-font-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}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}}</span> <span class="file tw-flex tw-items-center tw-font-mono tw-flex-1"><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}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}}
<button class="btn interact-fg tw-p-2" data-clipboard-text="{{$file.Name}}">{{svg "octicon-copy" 14}}</button> <button class="btn interact-fg tw-p-2" data-clipboard-text="{{$file.Name}}">{{svg "octicon-copy" 14}}</button>
{{if $file.IsGenerated}} {{if $file.IsGenerated}}
<span class="ui label">{{ctx.Locale.Tr "repo.diff.generated"}}</span> <span class="ui label">{{ctx.Locale.Tr "repo.diff.generated"}}</span>
@ -139,10 +140,11 @@
{{if and $file.Mode $file.OldMode}} {{if and $file.Mode $file.OldMode}}
{{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}} {{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}}
{{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} {{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}}
<span class="tw-ml-4 tw-font-mono">{{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}}</span> <span class="tw-mx-2 tw-font-mono tw-whitespace-nowrap">{{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}}</span>
{{else if $file.Mode}} {{else if $file.Mode}}
<span class="tw-ml-4 tw-font-mono">{{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}}</span> <span class="tw-mx-2 tw-font-mono tw-whitespace-nowrap">{{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}}</span>
{{end}} {{end}}
</span>
</div> </div>
<div class="diff-file-header-actions tw-flex tw-items-center tw-gap-1 tw-flex-wrap"> <div class="diff-file-header-actions tw-flex tw-items-center tw-gap-1 tw-flex-wrap">
{{if $showFileViewToggle}} {{if $showFileViewToggle}}

View file

@ -58,8 +58,11 @@
</div> </div>
{{end}} {{end}}
{{template "repo/sub_menu" .}} {{template "repo/sub_menu" .}}
{{$n := len .TreeNames}}
{{$l := Eval $n "-" 1}}
{{$isHomepage := (eq $n 0)}}
<div class="repo-button-row"> <div class="repo-button-row">
<div class="tw-flex tw-items-center tw-flex-wrap tw-gap-y-2"> <div class="tw-flex tw-items-center tw-gap-y-2">
{{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}}
{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}}
{{$cmpBranch := ""}} {{$cmpBranch := ""}}
@ -74,9 +77,7 @@
</a> </a>
{{end}} {{end}}
<!-- Show go to file and breadcrumbs if not on home page --> <!-- Show go to file and breadcrumbs if not on home page -->
{{$n := len .TreeNames}} {{if $isHomepage}}
{{$l := Eval $n "-" 1}}
{{if eq $n 0}}
<a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">{{ctx.Locale.Tr "repo.find_file.go_to_file"}}</a> <a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">{{ctx.Locale.Tr "repo.find_file.go_to_file"}}</a>
{{end}} {{end}}
@ -100,20 +101,20 @@
</button> </button>
{{end}} {{end}}
{{if and (eq $n 0) (.Repository.IsTemplate)}} {{if and $isHomepage (.Repository.IsTemplate)}}
<a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}"> <a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}">
{{ctx.Locale.Tr "repo.use_template"}} {{ctx.Locale.Tr "repo.use_template"}}
</a> </a>
{{end}} {{end}}
{{if ne $n 0}} {{if (not $isHomepage)}}
<span class="breadcrumb repo-path tw-ml-1"> <span class="breadcrumb repo-path tw-ml-1">
<a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a> <a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a>
{{- range $i, $v := .TreeNames -}} {{- range $i, $v := .TreeNames -}}
<span class="breadcrumb-divider">/</span> <span class="breadcrumb-divider">/</span>
{{- if eq $i $l -}} {{- if eq $i $l -}}
<span class="active section" title="{{$v}}">{{StringUtils.EllipsisString $v 30}}</span> <span class="active section" title="{{$v}}">{{$v}}</span>
{{- else -}} {{- else -}}
{{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{StringUtils.EllipsisString $v 30}}</a></span> {{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{$v}}</a></span>
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
</span> </span>
@ -121,7 +122,7 @@
</div> </div>
<div class="tw-flex tw-items-center"> <div class="tw-flex tw-items-center">
<!-- Only show clone panel in repository home page --> <!-- Only show clone panel in repository home page -->
{{if eq $n 0}} {{if $isHomepage}}
<div class="clone-panel ui action tiny input"> <div class="clone-panel ui action tiny input">
{{template "repo/clone_buttons" .}} {{template "repo/clone_buttons" .}}
<button class="ui small jump dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}"> <button class="ui small jump dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}">
@ -144,7 +145,7 @@
</div> </div>
{{template "repo/cite/cite_modal" .}} {{template "repo/cite/cite_modal" .}}
{{end}} {{end}}
{{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}} {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}}
<a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}"> <a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}">
{{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}}
</a> </a>

View file

@ -156,7 +156,7 @@
<label for="interval">{{ctx.Locale.Tr "repo.mirror_interval" .MinimumMirrorInterval}}</label> <label for="interval">{{ctx.Locale.Tr "repo.mirror_interval" .MinimumMirrorInterval}}</label>
<input id="interval" name="interval" value="{{.PullMirror.Interval}}"> <input id="interval" name="interval" value="{{.PullMirror.Interval}}">
</div> </div>
{{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false}} {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName}}
<div class="field {{if .Err_MirrorAddress}}error{{end}}"> <div class="field {{if .Err_MirrorAddress}}error{{end}}">
<label for="mirror_address">{{ctx.Locale.Tr "repo.mirror_address"}}</label> <label for="mirror_address">{{ctx.Locale.Tr "repo.mirror_address"}}</label>
<input id="mirror_address" name="mirror_address" value="{{$address.Address}}" required> <input id="mirror_address" name="mirror_address" value="{{$address.Address}}" required>

View file

@ -11,13 +11,13 @@
{{end}} {{end}}
{{if not .ReadmeInList}} {{if not .ReadmeInList}}
<div id="repo-file-commit-box" class="ui top attached header list-header tw-mb-4"> <div id="repo-file-commit-box" class="ui top attached header list-header tw-mb-4 tw-flex tw-justify-between">
<div> <div class="latest-commit">
{{template "repo/latest_commit" .}} {{template "repo/latest_commit" .}}
</div> </div>
{{if .LatestCommit}} {{if .LatestCommit}}
{{if .LatestCommit.Committer}} {{if .LatestCommit.Committer}}
<div class="ui text grey right age"> <div class="text grey age">
{{TimeSince .LatestCommit.Committer.When ctx.Locale}} {{TimeSince .LatestCommit.Committer.When ctx.Locale}}
</div> </div>
{{end}} {{end}}

View file

@ -1,8 +1,12 @@
<table id="repo-files-table" class="ui single line table tw-mt-0" {{if .HasFilesWithoutLatestCommit}}hx-indicator="tr.notready td.message span" hx-trigger="load" hx-swap="morph" hx-post="{{.LastCommitLoaderURL}}"{{end}}> <table id="repo-files-table" class="ui single line table tw-mt-0" {{if .HasFilesWithoutLatestCommit}}hx-indicator="tr.notready td.message span" hx-trigger="load" hx-swap="morph" hx-post="{{.LastCommitLoaderURL}}"{{end}}>
<thead> <thead>
<tr class="commit-list"> <tr class="commit-list">
<th colspan="2"> <th class="tw-overflow-hidden" colspan="2">
<div class="tw-flex">
<div class="latest-commit">
{{template "repo/latest_commit" .}} {{template "repo/latest_commit" .}}
</div>
</div>
</th> </th>
<th class="text grey right age">{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When ctx.Locale}}{{end}}{{end}}</th> <th class="text grey right age">{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When ctx.Locale}}{{end}}{{end}}</th>
</tr> </tr>

View file

@ -1,7 +1,7 @@
<div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_div" 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="tw-flex tw-items-center tw-justify-between tw-mb-4"> <div class="tw-flex tw-items-center tw-justify-between tw-mb-[--page-spacing]">
<div class="small-menu-items ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="{{if eq .Status 1}}active {{end}}item" href="{{AppSubUrl}}/notifications?q=unread"> <a class="{{if eq .Status 1}}active {{end}}item" href="{{AppSubUrl}}/notifications?q=unread">
{{ctx.Locale.Tr "notification.unread"}} {{ctx.Locale.Tr "notification.unread"}}

View file

@ -13,10 +13,8 @@
<div class="ui four wide column"> <div class="ui four wide column">
{{template "shared/user/profile_big_avatar" .}} {{template "shared/user/profile_big_avatar" .}}
</div> </div>
<div class="ui twelve wide column"> <div class="ui twelve wide column tw-mb-4">
<div class="tw-mb-4">
{{template "user/overview/header" .}} {{template "user/overview/header" .}}
</div>
{{template "package/shared/versionlist" .}} {{template "package/shared/versionlist" .}}
</div> </div>
</div> </div>

View file

@ -13,10 +13,8 @@
<div class="ui four wide column"> <div class="ui four wide column">
{{template "shared/user/profile_big_avatar" .}} {{template "shared/user/profile_big_avatar" .}}
</div> </div>
<div class="ui twelve wide column"> <div class="ui twelve wide column tw-mb-4">
<div class="tw-mb-4">
{{template "user/overview/header" .}} {{template "user/overview/header" .}}
</div>
{{template "package/shared/list" .}} {{template "package/shared/list" .}}
</div> </div>
</div> </div>

View file

@ -6,11 +6,8 @@
<div class="ui four wide column"> <div class="ui four wide column">
{{template "shared/user/profile_big_avatar" .}} {{template "shared/user/profile_big_avatar" .}}
</div> </div>
<div class="ui twelve wide column"> <div class="ui twelve wide column tw-mb-4">
<div class="tw-mb-4">
{{template "user/overview/header" .}} {{template "user/overview/header" .}}
</div>
{{if eq .TabName "activity"}} {{if eq .TabName "activity"}}
{{if .ContextUser.KeepActivityPrivate}} {{if .ContextUser.KeepActivityPrivate}}
<div class="ui info message"> <div class="ui info message">

View file

@ -621,7 +621,7 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile
schema, err := jsonschema.Compile(schemaFilePath) schema, err := jsonschema.Compile(schemaFilePath)
assert.NoError(t, err) assert.NoError(t, err)
var data interface{} var data any
err = json.Unmarshal(resp.Body.Bytes(), &data) err = json.Unmarshal(resp.Body.Bytes(), &data)
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -44,7 +44,7 @@
} }
.run-list-item-right { .run-list-item-right {
flex: 0 0 15%; flex: 0 0 min(20%, 130px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 3px; gap: 3px;

View file

@ -24,7 +24,21 @@
--repo-header-issue-min-height: 41px; --repo-header-issue-min-height: 41px;
--min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */ --min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */
--tab-size: 4; --tab-size: 4;
--checkbox-size: 16px; /* height and width of checkbox and radio inputs */ --checkbox-size: 15px; /* height and width of checkbox and radio inputs */
--page-spacing: 16px; /* space between page elements */
--page-margin-x: 32px; /* minimum space on left and right side of page */
}
@media (min-width: 768px) and (max-width: 1200px) {
:root {
--page-margin-x: 16px;
}
}
@media (max-width: 767.98px) {
:root {
--page-margin-x: 8px;
}
} }
:root * { :root * {
@ -594,11 +608,14 @@ img.ui.avatar,
margin-bottom: 14px; margin-bottom: 14px;
} }
/* add padding to all content when there is no .secondary.nav. this uses padding instead of /* add margin to all pages when there is no .secondary.nav */
margin because with the negative margin on .ui.grid we would have to set margin-top: 0,
but that does not work universally for all pages */
.page-content > :first-child:not(.secondary-nav) { .page-content > :first-child:not(.secondary-nav) {
padding-top: 14px; margin-top: var(--page-spacing);
}
/* if .ui.grid is the first child the first grid-column has 'padding-top: 1rem' which we need
to compensate here */
.page-content > :first-child.ui.grid {
margin-top: calc(var(--page-spacing) - 1rem);
} }
.ui.pagination.menu .active.item { .ui.pagination.menu .active.item {
@ -1256,6 +1273,7 @@ overflow-menu .ui.label {
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-all; word-break: break-all;
overflow-wrap: anywhere; overflow-wrap: anywhere;
line-height: inherit; /* needed for inline code preview in markup */
} }
.blame .code-inner { .blame .code-inner {

View file

@ -249,21 +249,6 @@ textarea:focus,
.user.signup form .optional .title { .user.signup form .optional .title {
margin-left: 250px !important; margin-left: 250px !important;
} }
.user.activate form .inline.field > input,
.user.forgot.password form .inline.field > input,
.user.reset.password form .inline.field > input,
.user.link-account form .inline.field > input,
.user.signin form .inline.field > input,
.user.signup form .inline.field > input,
.user.activate form .inline.field > textarea,
.user.forgot.password form .inline.field > textarea,
.user.reset.password form .inline.field > textarea,
.user.link-account form .inline.field > textarea,
.user.signin form .inline.field > textarea,
.user.signup form .inline.field > textarea,
.oauth-login-link {
width: 50%;
}
} }
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
@ -310,14 +295,7 @@ textarea:focus,
.user.reset.password form .inline.field > label, .user.reset.password form .inline.field > label,
.user.link-account form .inline.field > label, .user.link-account form .inline.field > label,
.user.signin form .inline.field > label, .user.signin form .inline.field > label,
.user.signup form .inline.field > label, .user.signup form .inline.field > label {
.user.activate form input,
.user.forgot.password form input,
.user.reset.password form input,
.user.link-account form input,
.user.signin form input,
.user.signup form input,
.oauth-login-link {
width: 100% !important; width: 100% !important;
} }
} }
@ -435,9 +413,9 @@ textarea:focus,
.repository.new.repo form label, .repository.new.repo form label,
.repository.new.migrate form label, .repository.new.migrate form label,
.repository.new.fork form label, .repository.new.fork form label,
.repository.new.repo form input, .repository.new.repo form .inline.field > input,
.repository.new.migrate form input, .repository.new.migrate form .inline.field > input,
.repository.new.fork form input, .repository.new.fork form .inline.field > input,
.repository.new.fork form .field a, .repository.new.fork form .field a,
.repository.new.repo form .selection.dropdown, .repository.new.repo form .selection.dropdown,
.repository.new.migrate form .selection.dropdown, .repository.new.migrate form .selection.dropdown,

View file

@ -20,7 +20,7 @@ input[type="radio"] {
.ui.checkbox input[type="checkbox"], .ui.checkbox input[type="checkbox"],
.ui.checkbox input[type="radio"] { .ui.checkbox input[type="radio"] {
position: absolute; position: absolute;
top: 0; top: 1px;
left: 0; left: 0;
width: var(--checkbox-size); width: var(--checkbox-size);
height: var(--checkbox-size); height: var(--checkbox-size);

View file

@ -49,30 +49,11 @@
/* overwrite width of containers inside the main page content div (div with class "page-content") */ /* overwrite width of containers inside the main page content div (div with class "page-content") */
.page-content .ui.ui.ui.container:not(.fluid) { .page-content .ui.ui.ui.container:not(.fluid) {
width: 1280px; width: 1280px;
max-width: calc(100% - 64px); max-width: calc(100% - calc(2 * var(--page-margin-x)));
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
.ui.container.fluid.padded { .ui.container.fluid.padded {
padding: 0 32px; padding: 0 var(--page-margin-x);
}
/* enable fluid page widths for medium size viewports */
@media (min-width: 768px) and (max-width: 1200px) {
.page-content .ui.ui.ui.container:not(.fluid) {
max-width: calc(100% - 32px);
}
.ui.container.fluid.padded {
padding: 0 16px;
}
}
@media (max-width: 767.98px) {
.page-content .ui.ui.ui.container:not(.fluid) {
max-width: calc(100% - 16px);
}
.ui.container.fluid.padded {
padding: 0 8px;
}
} }

View file

@ -2,7 +2,8 @@
.flex-container { .flex-container {
display: flex !important; display: flex !important;
gap: 16px; gap: var(--page-spacing);
margin-top: var(--page-spacing);
} }
.flex-container-nav { .flex-container-nav {

View file

@ -126,6 +126,12 @@
cursor: pointer; cursor: pointer;
} }
.ui.list .list > .item [class*="right floated"],
.ui.list > .item [class*="right floated"] {
float: right;
margin: 0 0 0 1em;
}
.ui.menu .ui.list > .item, .ui.menu .ui.list > .item,
.ui.menu .ui.list .list > .item { .ui.menu .ui.list .list > .item {
display: list-item; display: list-item;

View file

@ -177,12 +177,44 @@
} }
} }
.repository.file.list .repo-path { .commit-summary {
word-break: break-word; flex: 1;
overflow-wrap: anywhere;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
.repository.file.list #repo-files-table { .commit-header .commit-summary,
table-layout: fixed; td .commit-summary {
white-space: normal;
}
.latest-commit {
display: flex;
flex: 1;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 767.98px) {
.latest-commit .sha {
display: none;
}
.latest-commit .commit-summary {
margin-left: 8px;
}
}
.repo-path {
display: flex;
overflow-wrap: anywhere;
}
/* this is what limits the commit table width to a value that works on all viewport sizes */
#repo-files-table th:first-of-type {
max-width: calc(calc(min(100vw, 1280px)) - 145px - calc(2 * var(--page-margin-x)));
} }
.repository.file.list #repo-files-table thead th { .repository.file.list #repo-files-table thead th {
@ -262,7 +294,6 @@
} }
.repository.file.list #repo-files-table td.age { .repository.file.list #repo-files-table td.age {
width: 120px;
color: var(--color-text-light-1); color: var(--color-text-light-1);
} }
@ -1223,10 +1254,6 @@
margin: 0; margin: 0;
} }
.repository #commits-table td.message {
text-overflow: unset;
}
.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { .repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) {
background-color: var(--color-light) !important; background-color: var(--color-light) !important;
} }
@ -2153,6 +2180,20 @@
display: inline-block !important; display: inline-block !important;
} }
.commit-header-buttons {
display: flex;
gap: 4px;
align-items: flex-start;
white-space: nowrap;
}
@media (max-width: 767.98px) {
.commit-header-buttons {
flex-direction: column;
align-items: stretch;
}
}
.settings.webhooks .list > .item:not(:first-child), .settings.webhooks .list > .item:not(:first-child),
.settings.githooks .list > .item:not(:first-child), .settings.githooks .list > .item:not(:first-child),
.settings.actions .list > .item:not(:first-child) { .settings.actions .list > .item:not(:first-child) {
@ -2384,7 +2425,7 @@ tbody.commit-list {
.author-wrapper { .author-wrapper {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: calc(100% - 50px); max-width: 100%;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }
@ -2409,10 +2450,6 @@ tbody.commit-list {
tr.commit-list { tr.commit-list {
width: 100%; width: 100%;
} }
th .message-wrapper {
display: block;
max-width: calc(100vw - 70px);
}
.author-wrapper { .author-wrapper {
max-width: 80px; max-width: 80px;
} }
@ -2422,27 +2459,18 @@ tbody.commit-list {
tr.commit-list { tr.commit-list {
width: 723px; width: 723px;
} }
th .message-wrapper {
max-width: 120px;
}
} }
@media (min-width: 992px) and (max-width: 1200px) { @media (min-width: 992px) and (max-width: 1200px) {
tr.commit-list { tr.commit-list {
width: 933px; width: 933px;
} }
th .message-wrapper {
max-width: 350px;
}
} }
@media (min-width: 1201px) { @media (min-width: 1201px) {
tr.commit-list { tr.commit-list {
width: 1127px; width: 1127px;
} }
th .message-wrapper {
max-width: 525px;
}
} }
.commit-list .commit-status-link { .commit-list .commit-status-link {
@ -2770,7 +2798,7 @@ tbody.commit-list {
.repository.file.list #repo-files-table .entry td.message, .repository.file.list #repo-files-table .entry td.message,
.repository.file.list #repo-files-table .commit-list td.message, .repository.file.list #repo-files-table .commit-list td.message,
.repository.file.list #repo-files-table .entry span.commit-summary, .repository.file.list #repo-files-table .entry span.commit-summary,
.repository.file.list #repo-files-table .commit-list span.commit-summary { .repository.file.list #repo-files-table .commit-list tr span.commit-summary {
display: none !important; display: none !important;
} }
.repository.view.issue .comment-list .timeline, .repository.view.issue .comment-list .timeline,

View file

@ -65,7 +65,7 @@
--color-console-fg-subtle: #bec4c8; --color-console-fg-subtle: #bec4c8;
--color-console-bg: #171b1e; --color-console-bg: #171b1e;
--color-console-border: #2e353b; --color-console-border: #2e353b;
--color-console-hover-bg: #e8e8ff16; --color-console-hover-bg: #292d31;
--color-console-active-bg: #2e353b; --color-console-active-bg: #2e353b;
--color-console-menu-bg: #252b30; --color-console-menu-bg: #252b30;
--color-console-menu-border: #424b51; --color-console-menu-border: #424b51;

View file

@ -63,12 +63,12 @@
/* console colors - used for actions console and console files */ /* console colors - used for actions console and console files */
--color-console-fg: #f8f8f9; --color-console-fg: #f8f8f9;
--color-console-fg-subtle: #bec4c8; --color-console-fg-subtle: #bec4c8;
--color-console-bg: #181b1d; --color-console-bg: #171b1e;
--color-console-border: #313538; --color-console-border: #2e353b;
--color-console-hover-bg: #ffffff16; --color-console-hover-bg: #292d31;
--color-console-active-bg: #313538; --color-console-active-bg: #2e353b;
--color-console-menu-bg: #272b2e; --color-console-menu-bg: #252b30;
--color-console-menu-border: #464a4d; --color-console-menu-border: #424b51;
/* named colors */ /* named colors */
--color-red: #db2828; --color-red: #db2828;
--color-orange: #f2711c; --color-orange: #f2711c;

View file

@ -526,8 +526,16 @@ export function initRepositoryActionView() {
.action-summary { .action-summary {
display: flex; display: flex;
flex-wrap: wrap;
gap: 5px; gap: 5px;
margin: 0 0 0 28px; margin-left: 28px;
}
@media (max-width: 767.98px) {
.action-commit-summary {
margin-left: 0;
margin-top: 8px;
}
} }
/* ================ */ /* ================ */
@ -540,6 +548,14 @@ export function initRepositoryActionView() {
top: 12px; top: 12px;
max-height: 100vh; max-height: 100vh;
overflow-y: auto; overflow-y: auto;
background: var(--color-body);
z-index: 2; /* above .job-info-header */
}
@media (max-width: 767.98px) {
.action-view-left {
position: static; /* can not sticky because multiple jobs would overlap into right view */
}
} }
.job-artifacts-title { .job-artifacts-title {
@ -701,7 +717,9 @@ export function initRepositoryActionView() {
position: sticky; position: sticky;
top: 0; top: 0;
height: 60px; height: 60px;
z-index: 1; z-index: 1; /* above .job-step-container */
background: var(--color-console-bg);
border-radius: 3px;
} }
.job-info-header:has(+ .job-step-container) { .job-info-header:has(+ .job-step-container) {
@ -739,7 +757,7 @@ export function initRepositoryActionView() {
.job-step-container .job-step-summary.step-expandable:hover { .job-step-container .job-step-summary.step-expandable:hover {
color: var(--color-console-fg); color: var(--color-console-fg);
background-color: var(--color-console-hover-bg); background: var(--color-console-hover-bg);
} }
.job-step-container .job-step-summary .step-summary-msg { .job-step-container .job-step-summary .step-summary-msg {
@ -757,17 +775,15 @@ export function initRepositoryActionView() {
top: 60px; top: 60px;
} }
@media (max-width: 768px) { @media (max-width: 767.98px) {
.action-view-body { .action-view-body {
flex-direction: column; flex-direction: column;
} }
.action-view-left, .action-view-right { .action-view-left, .action-view-right {
width: 100%; width: 100%;
} }
.action-view-left { .action-view-left {
max-width: none; max-width: none;
overflow-y: hidden;
} }
} }
</style> </style>

View file

@ -207,13 +207,13 @@ export function initAdminCommon() {
// Notice // Notice
if (document.querySelector('.admin.notice')) { if (document.querySelector('.admin.notice')) {
const $detailModal = document.getElementById('detail-modal'); const detailModal = document.getElementById('detail-modal');
// Attach view detail modals // Attach view detail modals
$('.view-detail').on('click', function () { $('.view-detail').on('click', function () {
$detailModal.find('.content pre').text($(this).parents('tr').find('.notice-description').text()); const description = this.closest('tr').querySelector('.notice-description').textContent;
$detailModal.find('.sub.header').text(this.closest('tr')?.querySelector('relative-time')?.getAttribute('title')); detailModal.querySelector('.content pre').textContent = description;
$detailModal.modal('show'); $(detailModal).modal('show');
return false; return false;
}); });

View file

@ -1,14 +1,16 @@
import $ from 'jquery'; import $ from 'jquery';
import {hideElem, showElem} from '../utils/dom.js';
import {GET} from '../modules/fetch.js'; import {GET} from '../modules/fetch.js';
export function initRepoGraphGit() { export function initRepoGraphGit() {
const graphContainer = document.getElementById('git-graph-container'); const graphContainer = document.getElementById('git-graph-container');
if (!graphContainer) return; if (!graphContainer) return;
$('#flow-color-monochrome').on('click', () => { document.getElementById('flow-color-monochrome')?.addEventListener('click', () => {
$('#flow-color-monochrome').addClass('active'); document.getElementById('flow-color-monochrome').classList.add('active');
$('#flow-color-colored').removeClass('active'); document.getElementById('flow-color-colored')?.classList.remove('active');
$('#git-graph-container').removeClass('colored').addClass('monochrome'); graphContainer.classList.remove('colored');
graphContainer.classList.add('monochrome');
const params = new URLSearchParams(window.location.search); const params = new URLSearchParams(window.location.search);
params.set('mode', 'monochrome'); params.set('mode', 'monochrome');
const queryString = params.toString(); const queryString = params.toString();
@ -17,29 +19,31 @@ export function initRepoGraphGit() {
} else { } else {
window.history.replaceState({}, '', window.location.pathname); window.history.replaceState({}, '', window.location.pathname);
} }
$('.pagination a').each((_, that) => { for (const link of document.querySelectorAll('.pagination a')) {
const href = that.getAttribute('href'); const href = link.getAttribute('href');
if (!href) return; if (!href) continue;
const url = new URL(href, window.location); const url = new URL(href, window.location);
const params = url.searchParams; const params = url.searchParams;
params.set('mode', 'monochrome'); params.set('mode', 'monochrome');
url.search = `?${params.toString()}`; url.search = `?${params.toString()}`;
that.setAttribute('href', url.href); link.setAttribute('href', url.href);
}
}); });
});
$('#flow-color-colored').on('click', () => { document.getElementById('flow-color-colored')?.addEventListener('click', () => {
$('#flow-color-colored').addClass('active'); document.getElementById('flow-color-colored').classList.add('active');
$('#flow-color-monochrome').removeClass('active'); document.getElementById('flow-color-monochrome')?.classList.remove('active');
$('#git-graph-container').addClass('colored').removeClass('monochrome'); graphContainer.classList.add('colored');
$('.pagination a').each((_, that) => { graphContainer.classList.remove('monochrome');
const href = that.getAttribute('href'); for (const link of document.querySelectorAll('.pagination a')) {
if (!href) return; const href = link.getAttribute('href');
if (!href) continue;
const url = new URL(href, window.location); const url = new URL(href, window.location);
const params = url.searchParams; const params = url.searchParams;
params.delete('mode'); params.delete('mode');
url.search = `?${params.toString()}`; url.search = `?${params.toString()}`;
that.setAttribute('href', url.href); link.setAttribute('href', url.href);
}); }
const params = new URLSearchParams(window.location.search); const params = new URLSearchParams(window.location.search);
params.delete('mode'); params.delete('mode');
const queryString = params.toString(); const queryString = params.toString();
@ -56,20 +60,21 @@ export function initRepoGraphGit() {
const ajaxUrl = new URL(url); const ajaxUrl = new URL(url);
ajaxUrl.searchParams.set('div-only', 'true'); ajaxUrl.searchParams.set('div-only', 'true');
window.history.replaceState({}, '', queryString ? `?${queryString}` : window.location.pathname); window.history.replaceState({}, '', queryString ? `?${queryString}` : window.location.pathname);
$('#pagination').empty(); document.getElementById('pagination').innerHTML = '';
$('#rel-container').addClass('tw-hidden'); hideElem('#rel-container');
$('#rev-container').addClass('tw-hidden'); hideElem('#rev-container');
$('#loading-indicator').removeClass('tw-hidden'); showElem('#loading-indicator');
(async () => { (async () => {
const response = await GET(String(ajaxUrl)); const response = await GET(String(ajaxUrl));
const html = await response.text(); const html = await response.text();
const $div = $(html); const div = document.createElement('div');
$('#pagination').html($div.find('#pagination').html()); div.innerHTML = html;
$('#rel-container').html($div.find('#rel-container').html()); document.getElementById('pagination').innerHTML = div.getElementById('pagination').innerHTML;
$('#rev-container').html($div.find('#rev-container').html()); document.getElementById('rel-container').innerHTML = div.getElementById('rel-container').innerHTML;
$('#loading-indicator').addClass('tw-hidden'); document.getElementById('rev-container').innerHTML = div.getElementById('rev-container').innerHTML;
$('#rel-container').removeClass('tw-hidden'); hideElem('#loading-indicator');
$('#rev-container').removeClass('tw-hidden'); showElem('#rel-container');
showElem('#rev-container');
})(); })();
}; };
const dropdownSelected = params.getAll('branch'); const dropdownSelected = params.getAll('branch');
@ -77,8 +82,9 @@ export function initRepoGraphGit() {
dropdownSelected.splice(0, 0, '...flow-hide-pr-refs'); dropdownSelected.splice(0, 0, '...flow-hide-pr-refs');
} }
$('#flow-select-refs-dropdown').dropdown('set selected', dropdownSelected); const flowSelectRefsDropdown = document.getElementById('flow-select-refs-dropdown');
$('#flow-select-refs-dropdown').dropdown({ $(flowSelectRefsDropdown).dropdown('set selected', dropdownSelected);
$(flowSelectRefsDropdown).dropdown({
clearable: true, clearable: true,
fullTextSeach: 'exact', fullTextSeach: 'exact',
onRemove(toRemove) { onRemove(toRemove) {
@ -104,36 +110,46 @@ export function initRepoGraphGit() {
updateGraph(); updateGraph();
}, },
}); });
$('#git-graph-container').on('mouseenter', '#rev-list li', (e) => {
const flow = $(e.currentTarget).data('flow'); graphContainer.addEventListener('mouseenter', (e) => {
if (flow === 0) return; if (e.target.matches('#rev-list li')) {
$(`#flow-${flow}`).addClass('highlight'); const flow = e.target.getAttribute('data-flow');
$(e.currentTarget).addClass('hover'); if (flow === '0') return;
$(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); document.getElementById(`flow-${flow}`)?.classList.add('highlight');
e.target.classList.add('hover');
for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
item.classList.add('highlight');
}
} else if (e.target.matches('#rel-container .flow-group')) {
e.target.classList.add('highlight');
const flow = e.target.getAttribute('data-flow');
for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
item.classList.add('highlight');
}
} else if (e.target.matches('#rel-container .flow-commit')) {
const rev = e.target.getAttribute('data-rev');
document.querySelector(`#rev-list li#commit-${rev}`)?.classList.add('hover');
}
}); });
$('#git-graph-container').on('mouseleave', '#rev-list li', (e) => {
const flow = $(e.currentTarget).data('flow'); graphContainer.addEventListener('mouseleave', (e) => {
if (flow === 0) return; if (e.target.matches('#rev-list li')) {
$(`#flow-${flow}`).removeClass('highlight'); const flow = e.target.getAttribute('data-flow');
$(e.currentTarget).removeClass('hover'); if (flow === '0') return;
$(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); document.getElementById(`flow-${flow}`)?.classList.remove('highlight');
}); e.target.classList.remove('hover');
$('#git-graph-container').on('mouseenter', '#rel-container .flow-group', (e) => { for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
$(e.currentTarget).addClass('highlight'); item.classList.remove('highlight');
const flow = $(e.currentTarget).data('flow'); }
$(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); } else if (e.target.matches('#rel-container .flow-group')) {
}); e.target.classList.remove('highlight');
$('#git-graph-container').on('mouseleave', '#rel-container .flow-group', (e) => { const flow = e.target.getAttribute('data-flow');
$(e.currentTarget).removeClass('highlight'); for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
const flow = $(e.currentTarget).data('flow'); item.classList.remove('highlight');
$(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); }
}); } else if (e.target.matches('#rel-container .flow-commit')) {
$('#git-graph-container').on('mouseenter', '#rel-container .flow-commit', (e) => { const rev = e.target.getAttribute('data-rev');
const rev = $(e.currentTarget).data('rev'); document.querySelector(`#rev-list li#commit-${rev}`)?.classList.remove('hover');
$(`#rev-list li#commit-${rev}`).addClass('hover'); }
});
$('#git-graph-container').on('mouseleave', '#rel-container .flow-commit', (e) => {
const rev = $(e.currentTarget).data('rev');
$(`#rev-list li#commit-${rev}`).removeClass('hover');
}); });
} }

View file

@ -449,12 +449,10 @@ export function initRepoPullRequestReview() {
offset += $('.diff-detail-box').outerHeight() + $(diffHeader).outerHeight(); offset += $('.diff-detail-box').outerHeight() + $(diffHeader).outerHeight();
} }
document.getElementById(`show-outdated-${id}`).classList.add('tw-hidden'); hideElem(`#show-outdated-${id}`);
document.getElementById(`code-comments-${id}`).classList.remove('tw-hidden'); showElem(`#code-comments-${id}, #code-preview-${id}, #hide-outdated-${id}`);
document.getElementById(`code-preview-${id}`).classList.remove('tw-hidden');
document.getElementById(`hide-outdated-${id}`).classList.remove('tw-hidden');
// if the comment box is folded, expand it // if the comment box is folded, expand it
if (ancestorDiffBox.getAttribute('data-folded') === 'true') { if (ancestorDiffBox?.getAttribute('data-folded') === 'true') {
setFileFolding(ancestorDiffBox, ancestorDiffBox.querySelector('.fold-file'), false); setFileFolding(ancestorDiffBox, ancestorDiffBox.querySelector('.fold-file'), false);
} }