Merge pull request '[gitea] cherry-pick' (#2397) from earl-warren/forgejo:wip-gitea-cherry-pick into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2397 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
commit
0533022d63
68 changed files with 810 additions and 350 deletions
4
Makefile
4
Makefile
|
@ -156,8 +156,8 @@ endif
|
||||||
FORGEJO_API_SPEC := public/assets/forgejo/api.v1.yml
|
FORGEJO_API_SPEC := public/assets/forgejo/api.v1.yml
|
||||||
|
|
||||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||||
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
|
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape}}/api/v1"|g
|
||||||
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
|
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePath": "/api/v1"|g
|
||||||
SWAGGER_EXCLUDE := code.gitea.io/sdk
|
SWAGGER_EXCLUDE := code.gitea.io/sdk
|
||||||
SWAGGER_NEWLINE_COMMAND := -e '$$a\'
|
SWAGGER_NEWLINE_COMMAND := -e '$$a\'
|
||||||
SWAGGER_SPEC_BRANDING := s|Gitea API|Forgejo API|g
|
SWAGGER_SPEC_BRANDING := s|Gitea API|Forgejo API|g
|
||||||
|
|
|
@ -55,7 +55,9 @@ func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEvent
|
||||||
case webhook_module.HookEventPullRequest,
|
case webhook_module.HookEventPullRequest,
|
||||||
webhook_module.HookEventPullRequestSync,
|
webhook_module.HookEventPullRequestSync,
|
||||||
webhook_module.HookEventPullRequestAssign,
|
webhook_module.HookEventPullRequestAssign,
|
||||||
webhook_module.HookEventPullRequestLabel:
|
webhook_module.HookEventPullRequestLabel,
|
||||||
|
webhook_module.HookEventPullRequestReviewRequest,
|
||||||
|
webhook_module.HookEventPullRequestMilestone:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -186,7 +186,9 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
|
||||||
webhook_module.HookEventPullRequest,
|
webhook_module.HookEventPullRequest,
|
||||||
webhook_module.HookEventPullRequestSync,
|
webhook_module.HookEventPullRequestSync,
|
||||||
webhook_module.HookEventPullRequestAssign,
|
webhook_module.HookEventPullRequestAssign,
|
||||||
webhook_module.HookEventPullRequestLabel:
|
webhook_module.HookEventPullRequestLabel,
|
||||||
|
webhook_module.HookEventPullRequestReviewRequest,
|
||||||
|
webhook_module.HookEventPullRequestMilestone:
|
||||||
return matchPullRequestEvent(gitRepo, commit, payload.(*api.PullRequestPayload), evt)
|
return matchPullRequestEvent(gitRepo, commit, payload.(*api.PullRequestPayload), evt)
|
||||||
|
|
||||||
case // pull_request_review
|
case // pull_request_review
|
||||||
|
@ -362,13 +364,13 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
|
||||||
} else {
|
} else {
|
||||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
|
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
|
||||||
// Actions with the same name:
|
// Actions with the same name:
|
||||||
// opened, edited, closed, reopened, assigned, unassigned
|
// opened, edited, closed, reopened, assigned, unassigned, review_requested, review_request_removed, milestoned, demilestoned
|
||||||
// Actions need to be converted:
|
// Actions need to be converted:
|
||||||
// synchronized -> synchronize
|
// synchronized -> synchronize
|
||||||
// label_updated -> labeled
|
// label_updated -> labeled
|
||||||
// label_cleared -> unlabeled
|
// label_cleared -> unlabeled
|
||||||
// Unsupported activity types:
|
// Unsupported activity types:
|
||||||
// converted_to_draft, ready_for_review, locked, unlocked, review_requested, review_request_removed, auto_merge_enabled, auto_merge_disabled
|
// converted_to_draft, ready_for_review, locked, unlocked, auto_merge_enabled, auto_merge_disabled, enqueued, dequeued
|
||||||
|
|
||||||
action := prPayload.Action
|
action := prPayload.Action
|
||||||
switch action {
|
switch action {
|
||||||
|
|
|
@ -90,6 +90,20 @@ func (ctx *Context) HTML(status int, name base.TplName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONTemplate renders the template as JSON response
|
||||||
|
// keep in mind that the template is processed in HTML context, so JSON-things should be handled carefully, eg: by JSEscape
|
||||||
|
func (ctx *Context) JSONTemplate(tmpl base.TplName) {
|
||||||
|
t, err := ctx.Render.TemplateLookup(string(tmpl), nil)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("unable to find template", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Resp.Header().Set("Content-Type", "application/json")
|
||||||
|
if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
|
||||||
|
ctx.ServerError("unable to execute template", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RenderToString renders the template content to a string
|
// RenderToString renders the template content to a string
|
||||||
func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
|
func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
|
|
|
@ -5,10 +5,7 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ context.Context = TemplateContext(nil)
|
var _ context.Context = TemplateContext(nil)
|
||||||
|
@ -36,14 +33,3 @@ func (c TemplateContext) Err() error {
|
||||||
func (c TemplateContext) Value(key any) any {
|
func (c TemplateContext) Value(key any) any {
|
||||||
return c.parentContext().Value(key)
|
return c.parentContext().Value(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataRaceCheck checks whether the template context function "ctx()" returns the consistent context
|
|
||||||
// as the current template's rendering context (request context), to help to find data race issues as early as possible.
|
|
||||||
// When the code is proven to be correct and stable, this function should be removed.
|
|
||||||
func (c TemplateContext) DataRaceCheck(dataCtx context.Context) (string, error) {
|
|
||||||
if c.parentContext() != dataCtx {
|
|
||||||
log.Error("TemplateContext.DataRaceCheck: parent context mismatch\n%s", log.Stack(2))
|
|
||||||
return "", errors.New("parent context mismatch")
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ func NewFuncMap() template.FuncMap {
|
||||||
"Safe": Safe,
|
"Safe": Safe,
|
||||||
"Escape": Escape,
|
"Escape": Escape,
|
||||||
"QueryEscape": url.QueryEscape,
|
"QueryEscape": url.QueryEscape,
|
||||||
"JSEscape": template.JSEscapeString,
|
"JSEscape": JSEscapeSafe,
|
||||||
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
|
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
|
||||||
"URLJoin": util.URLJoin,
|
"URLJoin": util.URLJoin,
|
||||||
"DotEscape": DotEscape,
|
"DotEscape": DotEscape,
|
||||||
|
@ -214,6 +214,10 @@ func Escape(s any) template.HTML {
|
||||||
panic(fmt.Sprintf("unexpected type %T", s))
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JSEscapeSafe(s string) template.HTML {
|
||||||
|
return template.HTML(template.JSEscapeString(s))
|
||||||
|
}
|
||||||
|
|
||||||
func RenderEmojiPlain(s any) any {
|
func RenderEmojiPlain(s any) any {
|
||||||
switch v := s.(type) {
|
switch v := s.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
|
|
@ -52,3 +52,7 @@ func TestSubjectBodySeparator(t *testing.T) {
|
||||||
"",
|
"",
|
||||||
"Insuficient\n--\nSeparators")
|
"Insuficient\n--\nSeparators")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJSEscapeSafe(t *testing.T) {
|
||||||
|
assert.EqualValues(t, `\u0026\u003C\u003E\'\"`, JSEscapeSafe(`&<>'"`))
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package i18n
|
package i18n
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -82,6 +83,71 @@ c=22
|
||||||
assert.Equal(t, "22", lang1.TrString("c"))
|
assert.Equal(t, "22", lang1.TrString("c"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stringerPointerReceiver struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stringerPointerReceiver) String() string {
|
||||||
|
return s.s
|
||||||
|
}
|
||||||
|
|
||||||
|
type stringerStructReceiver struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s stringerStructReceiver) String() string {
|
||||||
|
return s.s
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorStructReceiver struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e errorStructReceiver) Error() string {
|
||||||
|
return e.s
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorPointerReceiver struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errorPointerReceiver) Error() string {
|
||||||
|
return e.s
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocaleWithTemplate(t *testing.T) {
|
||||||
|
ls := NewLocaleStore()
|
||||||
|
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", []byte(`key=<a>%s</a>`), nil))
|
||||||
|
lang1, _ := ls.Locale("lang1")
|
||||||
|
|
||||||
|
tmpl := template.New("test").Funcs(template.FuncMap{"tr": lang1.TrHTML})
|
||||||
|
tmpl = template.Must(tmpl.Parse(`{{tr "key" .var}}`))
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
in any
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"<str>", "<a><str></a>"},
|
||||||
|
{[]byte("<bytes>"), "<a>[60 98 121 116 101 115 62]</a>"},
|
||||||
|
{template.HTML("<html>"), "<a><html></a>"},
|
||||||
|
{stringerPointerReceiver{"<stringerPointerReceiver>"}, "<a>{<stringerPointerReceiver>}</a>"},
|
||||||
|
{&stringerPointerReceiver{"<stringerPointerReceiver ptr>"}, "<a><stringerPointerReceiver ptr></a>"},
|
||||||
|
{stringerStructReceiver{"<stringerStructReceiver>"}, "<a><stringerStructReceiver></a>"},
|
||||||
|
{&stringerStructReceiver{"<stringerStructReceiver ptr>"}, "<a><stringerStructReceiver ptr></a>"},
|
||||||
|
{errorStructReceiver{"<errorStructReceiver>"}, "<a><errorStructReceiver></a>"},
|
||||||
|
{&errorStructReceiver{"<errorStructReceiver ptr>"}, "<a><errorStructReceiver ptr></a>"},
|
||||||
|
{errorPointerReceiver{"<errorPointerReceiver>"}, "<a>{<errorPointerReceiver>}</a>"},
|
||||||
|
{&errorPointerReceiver{"<errorPointerReceiver ptr>"}, "<a><errorPointerReceiver ptr></a>"},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &strings.Builder{}
|
||||||
|
for _, c := range cases {
|
||||||
|
buf.Reset()
|
||||||
|
assert.NoError(t, tmpl.Execute(buf, map[string]any{"var": c.in}))
|
||||||
|
assert.Equal(t, c.want, buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLocaleStoreQuirks(t *testing.T) {
|
func TestLocaleStoreQuirks(t *testing.T) {
|
||||||
const nl = "\n"
|
const nl = "\n"
|
||||||
q := func(q1, s string, q2 ...string) string {
|
q := func(q1, s string, q2 ...string) string {
|
||||||
|
|
|
@ -136,12 +136,14 @@ func (l *locale) TrHTML(trKey string, trArgs ...any) template.HTML {
|
||||||
args := slices.Clone(trArgs)
|
args := slices.Clone(trArgs)
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
|
case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML:
|
||||||
|
// for most basic types (including template.HTML which is safe), just do nothing and use it
|
||||||
case string:
|
case string:
|
||||||
args[i] = template.HTML(template.HTMLEscapeString(v))
|
args[i] = template.HTMLEscapeString(v)
|
||||||
case fmt.Stringer:
|
case fmt.Stringer:
|
||||||
args[i] = template.HTMLEscapeString(v.String())
|
args[i] = template.HTMLEscapeString(v.String())
|
||||||
default: // int, float, include template.HTML
|
default:
|
||||||
// do nothing, just use it
|
args[i] = template.HTMLEscapeString(fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return template.HTML(l.TrString(trKey, args...))
|
return template.HTML(l.TrString(trKey, args...))
|
||||||
|
|
17
options/license/Brian-Gladman-2-Clause
Normal file
17
options/license/Brian-Gladman-2-Clause
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Copyright (C) 1998-2013, Brian Gladman, Worcester, UK. All
|
||||||
|
rights reserved.
|
||||||
|
|
||||||
|
The redistribution and use of this software (with or without
|
||||||
|
changes) is allowed without the payment of fees or royalties
|
||||||
|
provided that:
|
||||||
|
|
||||||
|
source code distributions include the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer;
|
||||||
|
|
||||||
|
binary distributions include the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer in their
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
This software is provided 'as is' with no explicit or implied
|
||||||
|
warranties in respect of its operation, including, but not limited
|
||||||
|
to, correctness and fitness for purpose.
|
11
options/license/CMU-Mach-nodoc
Normal file
11
options/license/CMU-Mach-nodoc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Copyright (C) 2002 Naval Research Laboratory (NRL/CCS)
|
||||||
|
|
||||||
|
Permission to use, copy, modify and distribute this software and
|
||||||
|
its documentation is hereby granted, provided that both the
|
||||||
|
copyright notice and this permission notice appear in all copies of
|
||||||
|
the software, derivative works or modified versions, and any
|
||||||
|
portions thereof.
|
||||||
|
|
||||||
|
NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
|
||||||
|
DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
|
||||||
|
RESULTING FROM THE USE OF THIS SOFTWARE.
|
1
options/license/GNOME-examples-exception
Normal file
1
options/license/GNOME-examples-exception
Normal file
|
@ -0,0 +1 @@
|
||||||
|
As a special exception, the copyright holders give you permission to copy, modify, and distribute the example code contained in this document under the terms of your choosing, without restriction.
|
16
options/license/Gmsh-exception
Normal file
16
options/license/Gmsh-exception
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
The copyright holders of Gmsh give you permission to combine Gmsh
|
||||||
|
with code included in the standard release of Netgen (from Joachim
|
||||||
|
Sch"oberl), METIS (from George Karypis at the University of
|
||||||
|
Minnesota), OpenCASCADE (from Open CASCADE S.A.S) and ParaView
|
||||||
|
(from Kitware, Inc.) under their respective licenses. You may copy
|
||||||
|
and distribute such a system following the terms of the GNU GPL for
|
||||||
|
Gmsh and the licenses of the other code concerned, provided that
|
||||||
|
you include the source code of that other code when and as the GNU
|
||||||
|
GPL requires distribution of source code.
|
||||||
|
|
||||||
|
Note that people who make modified versions of Gmsh are not
|
||||||
|
obligated to grant this special exception for their modified
|
||||||
|
versions; it is their choice whether to do so. The GNU General
|
||||||
|
Public License gives permission to release a modified version
|
||||||
|
without this exception; this exception also makes it possible to
|
||||||
|
release a modified version which carries forward this exception.
|
13
options/license/HPND-Fenneberg-Livingston
Normal file
13
options/license/HPND-Fenneberg-Livingston
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright (C) 1995,1996,1997,1998 Lars Fenneberg <lf@elemental.net>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose and without fee is hereby granted, provided that this copyright and
|
||||||
|
permission notice appear on all copies and supporting documentation, the
|
||||||
|
name of Lars Fenneberg not be used in advertising or publicity pertaining to
|
||||||
|
distribution of the program without specific prior permission, and notice be
|
||||||
|
given in supporting documentation that copying and distribution is by
|
||||||
|
permission of Lars Fenneberg.
|
||||||
|
|
||||||
|
Lars Fenneberg makes no representations about the suitability of this
|
||||||
|
software for any purpose. It is provided "as is" without express or implied
|
||||||
|
warranty.
|
9
options/license/HPND-INRIA-IMAG
Normal file
9
options/license/HPND-INRIA-IMAG
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
This software is available with usual "research" terms with
|
||||||
|
the aim of retain credits of the software. Permission to use,
|
||||||
|
copy, modify and distribute this software for any purpose and
|
||||||
|
without fee is hereby granted, provided that the above copyright
|
||||||
|
notice and this permission notice appear in all copies, and
|
||||||
|
the name of INRIA, IMAG, or any contributor not be used in
|
||||||
|
advertising or publicity pertaining to this material without
|
||||||
|
the prior explicit permission. The software is provided "as
|
||||||
|
is" without any warranties, support or liabilities of any kind.
|
25
options/license/Mackerras-3-Clause
Normal file
25
options/license/Mackerras-3-Clause
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 1995 Eric Rosenquist. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
3. The name(s) of the authors of this software must not be used to
|
||||||
|
endorse or promote products derived from this software without
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
|
||||||
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||||
|
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
25
options/license/Mackerras-3-Clause-acknowledgment
Normal file
25
options/license/Mackerras-3-Clause-acknowledgment
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 1993-2002 Paul Mackerras. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. The name(s) of the authors of this software must not be used to
|
||||||
|
endorse or promote products derived from this software without
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
3. Redistributions of any form whatsoever must retain the following
|
||||||
|
acknowledgment:
|
||||||
|
"This product includes software developed by Paul Mackerras
|
||||||
|
<paulus@ozlabs.org>".
|
||||||
|
|
||||||
|
THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
|
||||||
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||||
|
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
33
options/license/OpenVision
Normal file
33
options/license/OpenVision
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
Copyright, OpenVision Technologies, Inc., 1993-1996, All Rights
|
||||||
|
Reserved
|
||||||
|
|
||||||
|
WARNING: Retrieving the OpenVision Kerberos Administration system
|
||||||
|
source code, as described below, indicates your acceptance of the
|
||||||
|
following terms. If you do not agree to the following terms, do
|
||||||
|
not retrieve the OpenVision Kerberos administration system.
|
||||||
|
|
||||||
|
You may freely use and distribute the Source Code and Object Code
|
||||||
|
compiled from it, with or without modification, but this Source
|
||||||
|
Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY,
|
||||||
|
INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER
|
||||||
|
EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY
|
||||||
|
FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING,
|
||||||
|
WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE
|
||||||
|
CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY
|
||||||
|
OTHER REASON.
|
||||||
|
|
||||||
|
OpenVision retains all copyrights in the donated Source Code.
|
||||||
|
OpenVision also retains copyright to derivative works of the Source
|
||||||
|
Code, whether created by OpenVision or by a third party. The
|
||||||
|
OpenVision copyright notice must be preserved if derivative works
|
||||||
|
are made based on the donated Source Code.
|
||||||
|
|
||||||
|
OpenVision Technologies, Inc. has donated this Kerberos
|
||||||
|
Administration system to MIT for inclusion in the standard Kerberos
|
||||||
|
5 distribution. This donation underscores our commitment to
|
||||||
|
continuing Kerberos technology development and our gratitude for
|
||||||
|
the valuable work which has been performed by MIT and the Kerberos
|
||||||
|
community.
|
13
options/license/Sun-PPP
Normal file
13
options/license/Sun-PPP
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright (c) 2001 by Sun Microsystems, Inc.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Non-exclusive rights to redistribute, modify, translate, and use
|
||||||
|
this software in source and binary forms, in whole or in part, is
|
||||||
|
hereby granted, provided that the above copyright notice is
|
||||||
|
duplicated in any source form, and that neither the name of the
|
||||||
|
copyright holder nor the author is used to endorse or promote
|
||||||
|
products derived from this software.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
19
options/license/UMich-Merit
Normal file
19
options/license/UMich-Merit
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[C] The Regents of the University of Michigan and Merit Network, Inc. 1992,
|
||||||
|
1993, 1994, 1995 All Rights Reserved
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software and its
|
||||||
|
documentation for any purpose and without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear in all
|
||||||
|
copies of the software and derivative works or modified versions thereof,
|
||||||
|
and that both the copyright notice and this permission and disclaimer
|
||||||
|
notice appear in supporting documentation.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF THE
|
||||||
|
UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INC. DO NOT WARRANT THAT THE
|
||||||
|
FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR
|
||||||
|
THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. The Regents of the
|
||||||
|
University of Michigan and Merit Network, Inc. shall not be liable for any
|
||||||
|
special, indirect, incidental or consequential damages with respect to any
|
||||||
|
claim by Licensee or any third party arising from use of the software.
|
11
options/license/bcrypt-Solar-Designer
Normal file
11
options/license/bcrypt-Solar-Designer
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Written by Solar Designer <solar at openwall.com> in 1998-2014.
|
||||||
|
No copyright is claimed, and the software is hereby placed in the public
|
||||||
|
domain. In case this attempt to disclaim copyright and place the software
|
||||||
|
in the public domain is deemed null and void, then the software is
|
||||||
|
Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
|
||||||
|
general public under the following terms:
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted.
|
||||||
|
|
||||||
|
There's ABSOLUTELY NO WARRANTY, express or implied.
|
6
options/license/gtkbook
Normal file
6
options/license/gtkbook
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Copyright 2005 Syd Logan, All Rights Reserved
|
||||||
|
|
||||||
|
This code is distributed without warranty. You are free to use
|
||||||
|
this code for any purpose, however, if this code is republished or
|
||||||
|
redistributed in its original form, as hardcopy or electronically,
|
||||||
|
then you must include this copyright notice along with the code.
|
6
options/license/softSurfer
Normal file
6
options/license/softSurfer
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Copyright 2001, softSurfer (www.softsurfer.com)
|
||||||
|
This code may be freely used and modified for any purpose
|
||||||
|
providing that this copyright notice is included with it.
|
||||||
|
SoftSurfer makes no warranty for this code, and cannot be held
|
||||||
|
liable for any real or imagined damage resulting from its use.
|
||||||
|
Users of this code must verify correctness for their application.
|
|
@ -2023,15 +2023,10 @@ activity.git_stats_and_deletions = and
|
||||||
activity.git_stats_deletion_1 = %d deletion
|
activity.git_stats_deletion_1 = %d deletion
|
||||||
activity.git_stats_deletion_n = %d deletions
|
activity.git_stats_deletion_n = %d deletions
|
||||||
|
|
||||||
contributors = Contributors
|
|
||||||
contributors.contribution_type.filter_label = Contribution type:
|
contributors.contribution_type.filter_label = Contribution type:
|
||||||
contributors.contribution_type.commits = Commits
|
contributors.contribution_type.commits = Commits
|
||||||
contributors.contribution_type.additions = Additions
|
contributors.contribution_type.additions = Additions
|
||||||
contributors.contribution_type.deletions = Deletions
|
contributors.contribution_type.deletions = Deletions
|
||||||
contributors.loading_title = Loading contributions...
|
|
||||||
contributors.loading_title_failed = Could not load contributions
|
|
||||||
contributors.loading_info = This might take a bit…
|
|
||||||
contributors.component_failed_to_load = An unexpected error happened.
|
|
||||||
|
|
||||||
search = Search
|
search = Search
|
||||||
search.search_repo = Search repository
|
search.search_repo = Search repository
|
||||||
|
@ -2652,6 +2647,13 @@ error.csv.too_large = Can't render this file because it is too large.
|
||||||
error.csv.unexpected = Can't render this file because it contains an unexpected character in line %d and column %d.
|
error.csv.unexpected = Can't render this file because it contains an unexpected character in line %d and column %d.
|
||||||
error.csv.invalid_field_count = Can't render this file because it has a wrong number of fields in line %d.
|
error.csv.invalid_field_count = Can't render this file because it has a wrong number of fields in line %d.
|
||||||
|
|
||||||
|
[graphs]
|
||||||
|
component_loading = Loading %s...
|
||||||
|
component_loading_failed = Could not load %s
|
||||||
|
component_loading_info = This might take a bit…
|
||||||
|
component_failed_to_load = An unexpected error happened.
|
||||||
|
contributors.what = contributions
|
||||||
|
|
||||||
[org]
|
[org]
|
||||||
org_name_holder = Organization Name
|
org_name_holder = Organization Name
|
||||||
org_full_name_holder = Organization Full Name
|
org_full_name_holder = Organization Full Name
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//
|
//
|
||||||
// Schemes: https, http
|
// Schemes: https, http
|
||||||
// BasePath: /api/v1
|
// BasePath: /api/v1
|
||||||
// Version: {{AppVer | JSEscape | Safe}}
|
// Version: {{AppVer | JSEscape}}
|
||||||
// License: MIT http://opensource.org/licenses/MIT
|
// License: MIT http://opensource.org/licenses/MIT
|
||||||
//
|
//
|
||||||
// Consumes:
|
// Consumes:
|
||||||
|
|
|
@ -579,16 +579,8 @@ func GrantApplicationOAuth(ctx *context.Context) {
|
||||||
|
|
||||||
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
|
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
|
||||||
func OIDCWellKnown(ctx *context.Context) {
|
func OIDCWellKnown(ctx *context.Context) {
|
||||||
t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown", nil)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("unable to find template", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Resp.Header().Set("Content-Type", "application/json")
|
|
||||||
ctx.Data["SigningKey"] = oauth2.DefaultSigningKey
|
ctx.Data["SigningKey"] = oauth2.DefaultSigningKey
|
||||||
if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
|
ctx.JSONTemplate("user/auth/oidc_wellknown")
|
||||||
ctx.ServerError("unable to execute template", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OIDCKeys generates the JSON Web Key Set
|
// OIDCKeys generates the JSON Web Key Set
|
||||||
|
|
|
@ -18,7 +18,7 @@ const (
|
||||||
|
|
||||||
// Contributors render the page to show repository contributors graph
|
// Contributors render the page to show repository contributors graph
|
||||||
func Contributors(ctx *context.Context) {
|
func Contributors(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.contributors")
|
ctx.Data["Title"] = ctx.Tr("repo.activity.navbar.contributors")
|
||||||
|
|
||||||
ctx.Data["PageIsActivity"] = true
|
ctx.Data["PageIsActivity"] = true
|
||||||
ctx.Data["PageIsContributors"] = true
|
ctx.Data["PageIsContributors"] = true
|
||||||
|
|
|
@ -662,6 +662,24 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
|
||||||
}
|
}
|
||||||
|
|
||||||
if pb != nil && pb.EnableStatusCheck {
|
if pb != nil && pb.EnableStatusCheck {
|
||||||
|
|
||||||
|
var missingRequiredChecks []string
|
||||||
|
for _, requiredContext := range pb.StatusCheckContexts {
|
||||||
|
contextFound := false
|
||||||
|
matchesRequiredContext := createRequiredContextMatcher(requiredContext)
|
||||||
|
for _, presentStatus := range commitStatuses {
|
||||||
|
if matchesRequiredContext(presentStatus.Context) {
|
||||||
|
contextFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contextFound {
|
||||||
|
missingRequiredChecks = append(missingRequiredChecks, requiredContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.Data["MissingRequiredChecks"] = missingRequiredChecks
|
||||||
|
|
||||||
ctx.Data["is_context_required"] = func(context string) bool {
|
ctx.Data["is_context_required"] = func(context string) bool {
|
||||||
for _, c := range pb.StatusCheckContexts {
|
for _, c := range pb.StatusCheckContexts {
|
||||||
if c == context {
|
if c == context {
|
||||||
|
@ -730,6 +748,18 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
|
||||||
return compareInfo
|
return compareInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createRequiredContextMatcher(requiredContext string) func(string) bool {
|
||||||
|
if gp, err := glob.Compile(requiredContext); err == nil {
|
||||||
|
return func(contextToCheck string) bool {
|
||||||
|
return gp.Match(contextToCheck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(contextToCheck string) bool {
|
||||||
|
return requiredContext == contextToCheck
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type pullCommitList struct {
|
type pullCommitList struct {
|
||||||
Commits []pull_service.CommitInfo `json:"commits"`
|
Commits []pull_service.CommitInfo `json:"commits"`
|
||||||
LastReviewCommitSha string `json:"last_review_commit_sha"`
|
LastReviewCommitSha string `json:"last_review_commit_sha"`
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -67,6 +68,88 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReleaseInfo struct {
|
||||||
|
Release *repo_model.Release
|
||||||
|
CommitStatus *git_model.CommitStatus
|
||||||
|
CommitStatuses []*git_model.CommitStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions) ([]*ReleaseInfo, error) {
|
||||||
|
releases, err := db.Find[repo_model.Release](ctx, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, release := range releases {
|
||||||
|
release.Repo = ctx.Repo.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = repo_model.GetReleaseAttachments(ctx, releases...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporary cache commits count of used branches to speed up.
|
||||||
|
countCache := make(map[string]int64)
|
||||||
|
cacheUsers := make(map[int64]*user_model.User)
|
||||||
|
if ctx.Doer != nil {
|
||||||
|
cacheUsers[ctx.Doer.ID] = ctx.Doer
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
canReadActions := ctx.Repo.CanRead(unit.TypeActions)
|
||||||
|
|
||||||
|
releaseInfos := make([]*ReleaseInfo, 0, len(releases))
|
||||||
|
for _, r := range releases {
|
||||||
|
if r.Publisher, ok = cacheUsers[r.PublisherID]; !ok {
|
||||||
|
r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID)
|
||||||
|
if err != nil {
|
||||||
|
if user_model.IsErrUserNotExist(err) {
|
||||||
|
r.Publisher = user_model.NewGhostUser()
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cacheUsers[r.PublisherID] = r.Publisher
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Note, err = markdown.RenderString(&markup.RenderContext{
|
||||||
|
Links: markup.Links{
|
||||||
|
Base: ctx.Repo.RepoLink,
|
||||||
|
},
|
||||||
|
Metas: ctx.Repo.Repository.ComposeMetas(ctx),
|
||||||
|
GitRepo: ctx.Repo.GitRepo,
|
||||||
|
Ctx: ctx,
|
||||||
|
}, r.Note)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r.IsDraft {
|
||||||
|
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &ReleaseInfo{
|
||||||
|
Release: r,
|
||||||
|
}
|
||||||
|
|
||||||
|
if canReadActions {
|
||||||
|
statuses, _, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptions{ListAll: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info.CommitStatus = git_model.CalcCommitStatus(statuses)
|
||||||
|
info.CommitStatuses = statuses
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseInfos = append(releaseInfos, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
return releaseInfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Releases render releases list page
|
// Releases render releases list page
|
||||||
func Releases(ctx *context.Context) {
|
func Releases(ctx *context.Context) {
|
||||||
ctx.Data["PageIsReleaseList"] = true
|
ctx.Data["PageIsReleaseList"] = true
|
||||||
|
@ -91,77 +174,21 @@ func Releases(ctx *context.Context) {
|
||||||
writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
|
writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
|
||||||
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
||||||
|
|
||||||
opts := repo_model.FindReleasesOptions{
|
releases, err := getReleaseInfos(ctx, &repo_model.FindReleasesOptions{
|
||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
||||||
IncludeDrafts: writeAccess,
|
IncludeDrafts: writeAccess,
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
}
|
})
|
||||||
|
|
||||||
releases, err := db.Find[repo_model.Release](ctx, opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetReleasesByRepoID", err)
|
ctx.ServerError("getReleaseInfos", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, release := range releases {
|
|
||||||
release.Repo = ctx.Repo.Repository
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = repo_model.GetReleaseAttachments(ctx, releases...); err != nil {
|
|
||||||
ctx.ServerError("GetReleaseAttachments", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary cache commits count of used branches to speed up.
|
|
||||||
countCache := make(map[string]int64)
|
|
||||||
cacheUsers := make(map[int64]*user_model.User)
|
|
||||||
if ctx.Doer != nil {
|
|
||||||
cacheUsers[ctx.Doer.ID] = ctx.Doer
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
for _, r := range releases {
|
|
||||||
if r.Publisher, ok = cacheUsers[r.PublisherID]; !ok {
|
|
||||||
r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID)
|
|
||||||
if err != nil {
|
|
||||||
if user_model.IsErrUserNotExist(err) {
|
|
||||||
r.Publisher = user_model.NewGhostUser()
|
|
||||||
} else {
|
|
||||||
ctx.ServerError("GetUserByID", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cacheUsers[r.PublisherID] = r.Publisher
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Note, err = markdown.RenderString(&markup.RenderContext{
|
|
||||||
Links: markup.Links{
|
|
||||||
Base: ctx.Repo.RepoLink,
|
|
||||||
},
|
|
||||||
Metas: ctx.Repo.Repository.ComposeMetas(ctx),
|
|
||||||
GitRepo: ctx.Repo.GitRepo,
|
|
||||||
Ctx: ctx,
|
|
||||||
}, r.Note)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("RenderString", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.IsDraft {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
|
|
||||||
ctx.ServerError("calReleaseNumCommitsBehind", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Releases"] = releases
|
ctx.Data["Releases"] = releases
|
||||||
|
|
||||||
numReleases := ctx.Data["NumReleases"].(int64)
|
numReleases := ctx.Data["NumReleases"].(int64)
|
||||||
pager := context.NewPagination(int(numReleases), opts.PageSize, opts.Page, 5)
|
pager := context.NewPagination(int(numReleases), listOptions.PageSize, listOptions.Page, 5)
|
||||||
pager.SetDefaultParams(ctx)
|
pager.SetDefaultParams(ctx)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
|
@ -249,15 +276,24 @@ func SingleRelease(ctx *context.Context) {
|
||||||
writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
|
writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
|
||||||
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
||||||
|
|
||||||
release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, ctx.Params("*"))
|
releases, err := getReleaseInfos(ctx, &repo_model.FindReleasesOptions{
|
||||||
|
ListOptions: db.ListOptions{Page: 1, PageSize: 1},
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
TagNames: []string{ctx.Params("*")},
|
||||||
|
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
||||||
|
IncludeDrafts: writeAccess,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrReleaseNotExist(err) {
|
ctx.ServerError("getReleaseInfos", err)
|
||||||
ctx.NotFound("GetRelease", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.ServerError("GetReleasesByRepoID", err)
|
if len(releases) != 1 {
|
||||||
|
ctx.NotFound("SingleRelease", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
release := releases[0].Release
|
||||||
|
|
||||||
ctx.Data["PageIsSingleTag"] = release.IsTag
|
ctx.Data["PageIsSingleTag"] = release.IsTag
|
||||||
if release.IsTag {
|
if release.IsTag {
|
||||||
ctx.Data["Title"] = release.TagName
|
ctx.Data["Title"] = release.TagName
|
||||||
|
@ -265,43 +301,7 @@ func SingleRelease(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = release.Title
|
ctx.Data["Title"] = release.Title
|
||||||
}
|
}
|
||||||
|
|
||||||
release.Repo = ctx.Repo.Repository
|
ctx.Data["Releases"] = releases
|
||||||
|
|
||||||
err = repo_model.GetReleaseAttachments(ctx, release)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetReleaseAttachments", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
release.Publisher, err = user_model.GetUserByID(ctx, release.PublisherID)
|
|
||||||
if err != nil {
|
|
||||||
if user_model.IsErrUserNotExist(err) {
|
|
||||||
release.Publisher = user_model.NewGhostUser()
|
|
||||||
} else {
|
|
||||||
ctx.ServerError("GetUserByID", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !release.IsDraft {
|
|
||||||
if err := calReleaseNumCommitsBehind(ctx.Repo, release, make(map[string]int64)); err != nil {
|
|
||||||
ctx.ServerError("calReleaseNumCommitsBehind", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
release.Note, err = markdown.RenderString(&markup.RenderContext{
|
|
||||||
Links: markup.Links{
|
|
||||||
Base: ctx.Repo.RepoLink,
|
|
||||||
},
|
|
||||||
Metas: ctx.Repo.Repository.ComposeMetas(ctx),
|
|
||||||
GitRepo: ctx.Repo.GitRepo,
|
|
||||||
Ctx: ctx,
|
|
||||||
}, release.Note)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("RenderString", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Releases"] = []*repo_model.Release{release}
|
|
||||||
ctx.HTML(http.StatusOK, tplReleasesList)
|
ctx.HTML(http.StatusOK, tplReleasesList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
|
@ -37,7 +39,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
|
||||||
ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
|
ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
|
||||||
ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlocked(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
|
ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlocked(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
|
||||||
ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate
|
ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate
|
||||||
ctx.Data["UserLocationMapURL"] = setting.Service.UserLocationMapURL
|
ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location)
|
||||||
|
|
||||||
// Show OpenID URIs
|
// Show OpenID URIs
|
||||||
openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID)
|
openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID)
|
||||||
|
|
|
@ -4,22 +4,10 @@
|
||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// tplSwaggerV1Json swagger v1 json template
|
|
||||||
const tplSwaggerV1Json base.TplName = "swagger/v1_json"
|
|
||||||
|
|
||||||
// SwaggerV1Json render swagger v1 json
|
// SwaggerV1Json render swagger v1 json
|
||||||
func SwaggerV1Json(ctx *context.Context) {
|
func SwaggerV1Json(ctx *context.Context) {
|
||||||
t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json), nil)
|
ctx.JSONTemplate("swagger/v1_json")
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("unable to find template", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Resp.Header().Set("Content-Type", "application/json")
|
|
||||||
if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
|
|
||||||
ctx.ServerError("unable to execute template", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,9 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
|
||||||
return fmt.Errorf("head of pull request is missing in event payload")
|
return fmt.Errorf("head of pull request is missing in event payload")
|
||||||
}
|
}
|
||||||
sha = payload.PullRequest.Head.Sha
|
sha = payload.PullRequest.Head.Sha
|
||||||
|
case webhook_module.HookEventRelease:
|
||||||
|
event = string(run.Event)
|
||||||
|
sha = run.CommitSHA
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,47 @@ func (n *actionsNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
|
||||||
}).Notify(withMethod(ctx, "NewIssue"))
|
}).Notify(withMethod(ctx, "NewIssue"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IssueChangeContent notifies change content of issue
|
||||||
|
func (n *actionsNotifier) IssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
||||||
|
ctx = withMethod(ctx, "IssueChangeContent")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if err = issue.LoadRepo(ctx); err != nil {
|
||||||
|
log.Error("LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
|
||||||
|
if issue.IsPull {
|
||||||
|
if err = issue.LoadPullRequest(ctx); err != nil {
|
||||||
|
log.Error("loadPullRequest: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequest).
|
||||||
|
WithDoer(doer).
|
||||||
|
WithPayload(&api.PullRequestPayload{
|
||||||
|
Action: api.HookIssueEdited,
|
||||||
|
Index: issue.Index,
|
||||||
|
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||||
|
Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}),
|
||||||
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
|
}).
|
||||||
|
WithPullRequest(issue.PullRequest).
|
||||||
|
Notify(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).
|
||||||
|
WithDoer(doer).
|
||||||
|
WithPayload(&api.IssuePayload{
|
||||||
|
Action: api.HookIssueEdited,
|
||||||
|
Index: issue.Index,
|
||||||
|
Issue: convert.ToAPIIssue(ctx, issue),
|
||||||
|
Repository: convert.ToRepo(ctx, issue.Repo, permission),
|
||||||
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
|
}).
|
||||||
|
Notify(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// IssueChangeStatus notifies close or reopen issue to notifiers
|
// IssueChangeStatus notifies close or reopen issue to notifiers
|
||||||
func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, _ *issues_model.Comment, isClosed bool) {
|
func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, _ *issues_model.Comment, isClosed bool) {
|
||||||
ctx = withMethod(ctx, "IssueChangeStatus")
|
ctx = withMethod(ctx, "IssueChangeStatus")
|
||||||
|
@ -101,11 +142,40 @@ func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode
|
||||||
Notify(ctx)
|
Notify(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IssueChangeAssignee notifies assigned or unassigned to notifiers
|
||||||
|
func (n *actionsNotifier) IssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
|
||||||
|
ctx = withMethod(ctx, "IssueChangeAssignee")
|
||||||
|
|
||||||
|
var action api.HookIssueAction
|
||||||
|
if removed {
|
||||||
|
action = api.HookIssueUnassigned
|
||||||
|
} else {
|
||||||
|
action = api.HookIssueAssigned
|
||||||
|
}
|
||||||
|
notifyIssueChange(ctx, doer, issue, webhook_module.HookEventPullRequestAssign, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueChangeMilestone notifies assignee to notifiers
|
||||||
|
func (n *actionsNotifier) IssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
|
||||||
|
ctx = withMethod(ctx, "IssueChangeMilestone")
|
||||||
|
|
||||||
|
var action api.HookIssueAction
|
||||||
|
if issue.MilestoneID > 0 {
|
||||||
|
action = api.HookIssueMilestoned
|
||||||
|
} else {
|
||||||
|
action = api.HookIssueDemilestoned
|
||||||
|
}
|
||||||
|
notifyIssueChange(ctx, doer, issue, webhook_module.HookEventPullRequestMilestone, action)
|
||||||
|
}
|
||||||
|
|
||||||
func (n *actionsNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
|
func (n *actionsNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
|
||||||
_, _ []*issues_model.Label,
|
_, _ []*issues_model.Label,
|
||||||
) {
|
) {
|
||||||
ctx = withMethod(ctx, "IssueChangeLabels")
|
ctx = withMethod(ctx, "IssueChangeLabels")
|
||||||
|
notifyIssueChange(ctx, doer, issue, webhook_module.HookEventPullRequestLabel, api.HookIssueLabelUpdated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, event webhook_module.HookEventType, action api.HookIssueAction) {
|
||||||
var err error
|
var err error
|
||||||
if err = issue.LoadRepo(ctx); err != nil {
|
if err = issue.LoadRepo(ctx); err != nil {
|
||||||
log.Error("LoadRepo: %v", err)
|
log.Error("LoadRepo: %v", err)
|
||||||
|
@ -117,20 +187,15 @@ func (n *actionsNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
|
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
if err = issue.LoadPullRequest(ctx); err != nil {
|
if err = issue.LoadPullRequest(ctx); err != nil {
|
||||||
log.Error("loadPullRequest: %v", err)
|
log.Error("loadPullRequest: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = issue.PullRequest.LoadIssue(ctx); err != nil {
|
newNotifyInputFromIssue(issue, event).
|
||||||
log.Error("LoadIssue: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequestLabel).
|
|
||||||
WithDoer(doer).
|
WithDoer(doer).
|
||||||
WithPayload(&api.PullRequestPayload{
|
WithPayload(&api.PullRequestPayload{
|
||||||
Action: api.HookIssueLabelUpdated,
|
Action: action,
|
||||||
Index: issue.Index,
|
Index: issue.Index,
|
||||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||||
Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}),
|
Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}),
|
||||||
|
@ -140,10 +205,11 @@ func (n *actionsNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode
|
||||||
Notify(ctx)
|
Notify(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newNotifyInputFromIssue(issue, webhook_module.HookEventIssueLabel).
|
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
|
||||||
|
newNotifyInputFromIssue(issue, event).
|
||||||
WithDoer(doer).
|
WithDoer(doer).
|
||||||
WithPayload(&api.IssuePayload{
|
WithPayload(&api.IssuePayload{
|
||||||
Action: api.HookIssueLabelUpdated,
|
Action: action,
|
||||||
Index: issue.Index,
|
Index: issue.Index,
|
||||||
Issue: convert.ToAPIIssue(ctx, issue),
|
Issue: convert.ToAPIIssue(ctx, issue),
|
||||||
Repository: convert.ToRepo(ctx, issue.Repo, permission),
|
Repository: convert.ToRepo(ctx, issue.Repo, permission),
|
||||||
|
@ -305,6 +371,39 @@ func (n *actionsNotifier) PullRequestReview(ctx context.Context, pr *issues_mode
|
||||||
}).Notify(ctx)
|
}).Notify(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *actionsNotifier) PullRequestReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
|
||||||
|
if !issue.IsPull {
|
||||||
|
log.Warn("PullRequestReviewRequest: issue is not a pull request: %v", issue.ID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = withMethod(ctx, "PullRequestReviewRequest")
|
||||||
|
|
||||||
|
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
|
||||||
|
if err := issue.LoadPullRequest(ctx); err != nil {
|
||||||
|
log.Error("LoadPullRequest failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var action api.HookIssueAction
|
||||||
|
if isRequest {
|
||||||
|
action = api.HookIssueReviewRequested
|
||||||
|
} else {
|
||||||
|
action = api.HookIssueReviewRequestRemoved
|
||||||
|
}
|
||||||
|
newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequestReviewRequest).
|
||||||
|
WithDoer(doer).
|
||||||
|
WithPayload(&api.PullRequestPayload{
|
||||||
|
Action: action,
|
||||||
|
Index: issue.Index,
|
||||||
|
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||||
|
RequestedReviewer: convert.ToUser(ctx, reviewer, nil),
|
||||||
|
Repository: convert.ToRepo(ctx, issue.Repo, permission),
|
||||||
|
Sender: convert.ToUser(ctx, doer, nil),
|
||||||
|
}).
|
||||||
|
WithPullRequest(issue.PullRequest).
|
||||||
|
Notify(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (*actionsNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
|
func (*actionsNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
|
||||||
ctx = withMethod(ctx, "MergePullRequest")
|
ctx = withMethod(ctx, "MergePullRequest")
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (source *Source) FromDB(bs []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports an SMTPConfig to a serialized format.
|
// ToDB exports the config to a byte slice to be saved into database (this method is just dummy and does nothing for DB source)
|
||||||
func (source *Source) ToDB() ([]byte, error) {
|
func (source *Source) ToDB() ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,10 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if matchedCount != len(requiredContexts) {
|
||||||
|
return structs.CommitStatusPending
|
||||||
|
}
|
||||||
|
|
||||||
if matchedCount == 0 {
|
if matchedCount == 0 {
|
||||||
status := git_model.CalcCommitStatus(commitStatuses)
|
status := git_model.CalcCommitStatus(commitStatuses)
|
||||||
if status != nil {
|
if status != nil {
|
||||||
|
|
|
@ -321,14 +321,9 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lowerTags := make([]string, 0, len(tags))
|
|
||||||
for _, tag := range tags {
|
|
||||||
lowerTags = append(lowerTags, strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
|
releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
TagNames: lowerTags,
|
TagNames: tags,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("db.Find[repo_model.Release]: %w", err)
|
return fmt.Errorf("db.Find[repo_model.Release]: %w", err)
|
||||||
|
@ -338,6 +333,11 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
|
||||||
relMap[rel.LowerTagName] = rel
|
relMap[rel.LowerTagName] = rel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lowerTags := make([]string, 0, len(tags))
|
||||||
|
for _, tag := range tags {
|
||||||
|
lowerTags = append(lowerTags, strings.ToLower(tag))
|
||||||
|
}
|
||||||
|
|
||||||
newReleases := make([]*repo_model.Release, 0, len(lowerTags)-len(relMap))
|
newReleases := make([]*repo_model.Release, 0, len(lowerTags)-len(relMap))
|
||||||
|
|
||||||
emailToUser := make(map[string]*user_model.User)
|
emailToUser := make(map[string]*user_model.User)
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
{{ctx.Locale.Tr "packages.settings.delete"}}
|
{{ctx.Locale.Tr "packages.settings.delete"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ctx.Locale.Tr "packages.settings.delete.notice" `<span class="name"></span>` `<span class="dataVersion"></span>` | Safe}}
|
{{ctx.Locale.Tr "packages.settings.delete.notice" (`<span class="name"></span>`|Safe) (`<span class="dataVersion"></span>`|Safe)}}
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p>
|
<p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p>
|
||||||
{{ctx.Locale.Tr "repo.settings.delete_notices_2" `<span class="name"></span>` | Safe}}<br>
|
{{ctx.Locale.Tr "repo.settings.delete_notices_2" (`<span class="name"></span>`|Safe)}}<br>
|
||||||
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}<br>
|
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}<br>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
{{ctx.Locale.Tr "admin.monitor.process.cancel"}}
|
{{ctx.Locale.Tr "admin.monitor.process.cancel"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "admin.monitor.process.cancel_notices" `<span class="name"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "admin.monitor.process.cancel_notices" (`<span class="name"></span>`|Safe)}}</p>
|
||||||
<p>{{ctx.Locale.Tr "admin.monitor.process.cancel_desc"}}</p>
|
<p>{{ctx.Locale.Tr "admin.monitor.process.cancel_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<div class="inline field {{if .Err_Visibility}}error{{end}}">
|
<div class="inline field {{if .Err_Visibility}}error{{end}}">
|
||||||
<span class="inline required field"><label for="visibility">{{ctx.Locale.Tr "settings.visibility"}}</label></span>
|
<span class="inline required field"><label for="visibility">{{ctx.Locale.Tr "settings.visibility"}}</label></span>
|
||||||
<div class="ui selection type dropdown">
|
<div class="ui selection type dropdown">
|
||||||
<input type="hidden" id="visibility" name="visibility" value="{{if .visibility}}{{.visibility}}{{else}}{{printf "%d" .DefaultUserVisibilityMode}}{{end}}">
|
<input type="hidden" id="visibility" name="visibility" value="{{if .visibility}}{{printf "%d" .visibility}}{{else}}{{printf "%d" .DefaultUserVisibilityMode}}{{end}}">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
{{if .DefaultUserVisibilityMode.IsPublic}}{{ctx.Locale.Tr "settings.visibility.public"}}{{end}}
|
{{if .DefaultUserVisibilityMode.IsPublic}}{{ctx.Locale.Tr "settings.visibility.public"}}{{end}}
|
||||||
{{if .DefaultUserVisibilityMode.IsLimited}}{{ctx.Locale.Tr "settings.visibility.limited"}}{{end}}
|
{{if .DefaultUserVisibilityMode.IsLimited}}{{ctx.Locale.Tr "settings.visibility.limited"}}{{end}}
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
<script src="{{AssetUrlPrefix}}/js/index.js?v={{AssetVersion}}" onerror="alert('Failed to load asset files from ' + this.src + '. Please make sure the asset files can be accessed.')"></script>
|
<script src="{{AssetUrlPrefix}}/js/index.js?v={{AssetVersion}}" onerror="alert('Failed to load asset files from ' + this.src + '. Please make sure the asset files can be accessed.')"></script>
|
||||||
|
|
||||||
{{template "custom/footer" .}}
|
{{template "custom/footer" .}}
|
||||||
{{ctx.DataRaceCheck $.Context}}
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
{{template "custom/header" .}}
|
{{template "custom/header" .}}
|
||||||
</head>
|
</head>
|
||||||
<body hx-headers='{"x-csrf-token": "{{.CsrfToken}}"}' hx-swap="outerHTML" hx-ext="morph" hx-push-url="false">
|
<body hx-headers='{"x-csrf-token": "{{.CsrfToken}}"}' hx-swap="outerHTML" hx-ext="morph" hx-push-url="false">
|
||||||
{{ctx.DataRaceCheck $.Context}}
|
|
||||||
{{template "custom/body_outer_pre" .}}
|
{{template "custom/body_outer_pre" .}}
|
||||||
|
|
||||||
<div class="full height">
|
<div class="full height">
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
{{ctx.Locale.Tr "org.members.leave"}}
|
{{ctx.Locale.Tr "org.members.leave"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "org.members.leave.detail" `<span class="dataOrganizationName"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|Safe)}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
{{ctx.Locale.Tr "org.members.remove"}}
|
{{ctx.Locale.Tr "org.members.remove"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "org.members.remove.detail" `<span class="name"></span>` `<span class="dataOrganizationName"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|Safe) (`<span class="dataOrganizationName"></span>`|Safe)}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
{{ctx.Locale.Tr "org.members.remove"}}
|
{{ctx.Locale.Tr "org.members.remove"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "org.members.remove.detail" `<span class="name"></span>` `<span class="dataTeamName"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|Safe) (`<span class="dataTeamName"></span>`|Safe)}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
{{ctx.Locale.Tr "org.teams.leave"}}
|
{{ctx.Locale.Tr "org.teams.leave"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "org.teams.leave.detail" `<span class="name"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|Safe)}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
{{ctx.Locale.Tr "org.teams.leave"}}
|
{{ctx.Locale.Tr "org.teams.leave"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "org.teams.leave.detail" `<span class="name"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|Safe)}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.branch.new_branch_from" `<span class="text" id="modal-create-branch-from-span"></span>` | Safe}}
|
{{ctx.Locale.Tr "repo.branch.new_branch_from" (`<span class="text" id="modal-create-branch-from-span"></span>`|Safe)}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
<input type="hidden" name="create_tag" value="true">
|
<input type="hidden" name="create_tag" value="true">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.tag.create_tag_from" `<span class="text" id="modal-create-tag-from-span"></span>` | Safe}}
|
{{ctx.Locale.Tr "repo.tag.create_tag_from" (`<span class="text" id="modal-create-tag-from-span"></span>`|Safe)}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{if .Commit.Signature}}
|
{{if .Commit.Signature}}
|
||||||
<div class="ui bottom attached message gt-text-left gt-df gt-ac gt-sb commit-header-row gt-fw {{$class}}">
|
<div class="ui bottom attached message gt-text-left gt-df gt-ac gt-sb commit-header-row gt-fw gt-mb-0 {{$class}}">
|
||||||
<div class="gt-df gt-ac">
|
<div class="gt-df gt-ac">
|
||||||
{{if .Verification.Verified}}
|
{{if .Verification.Verified}}
|
||||||
{{if ne .Verification.SigningUser.ID 0}}
|
{{if ne .Verification.SigningUser.ID 0}}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
{{if .Statuses}}
|
{{if .Statuses}}
|
||||||
{{if and (eq (len .Statuses) 1) .Status.TargetURL}}
|
{{if and (eq (len .Statuses) 1) .Status.TargetURL}}
|
||||||
<a class="gt-vm gt-no-underline" data-tippy="commit-statuses" href="{{.Status.TargetURL}}">
|
<a class="gt-vm {{.AdditionalClasses}} gt-no-underline" data-tippy="commit-statuses" href="{{.Status.TargetURL}}">
|
||||||
{{template "repo/commit_status" .Status}}
|
{{template "repo/commit_status" .Status}}
|
||||||
</a>
|
</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="gt-vm" data-tippy="commit-statuses" tabindex="0">
|
<span class="gt-vm {{.AdditionalClasses}}" data-tippy="commit-statuses" tabindex="0">
|
||||||
{{template "repo/commit_status" .Status}}
|
{{template "repo/commit_status" .Status}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
data-locale-contribution-type-commits="{{ctx.Locale.Tr "repo.contributors.contribution_type.commits"}}"
|
data-locale-contribution-type-commits="{{ctx.Locale.Tr "repo.contributors.contribution_type.commits"}}"
|
||||||
data-locale-contribution-type-additions="{{ctx.Locale.Tr "repo.contributors.contribution_type.additions"}}"
|
data-locale-contribution-type-additions="{{ctx.Locale.Tr "repo.contributors.contribution_type.additions"}}"
|
||||||
data-locale-contribution-type-deletions="{{ctx.Locale.Tr "repo.contributors.contribution_type.deletions"}}"
|
data-locale-contribution-type-deletions="{{ctx.Locale.Tr "repo.contributors.contribution_type.deletions"}}"
|
||||||
data-locale-loading-title="{{ctx.Locale.Tr "repo.contributors.loading_title"}}"
|
data-locale-loading-title="{{ctx.Locale.Tr "graphs.component_loading" (ctx.Locale.Tr "graphs.contributors.what")}}"
|
||||||
data-locale-loading-title-failed="{{ctx.Locale.Tr "repo.contributors.loading_title_failed"}}"
|
data-locale-loading-title-failed="{{ctx.Locale.Tr "graphs.component_loading_failed" (ctx.Locale.Tr "graphs.contributors.what")}}"
|
||||||
data-locale-loading-info="{{ctx.Locale.Tr "repo.contributors.loading_info"}}"
|
data-locale-loading-info="{{ctx.Locale.Tr "graphs.component_loading_info"}}"
|
||||||
data-locale-component-failed-to-load="{{ctx.Locale.Tr "repo.contributors.component_failed_to_load"}}"
|
data-locale-component-failed-to-load="{{ctx.Locale.Tr "graphs.component_failed_to_load"}}"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{$showFileTree := (and (not .DiffNotAvailable) (gt .Diff.NumFiles 1))}}
|
{{$showFileTree := (and (not .DiffNotAvailable) (gt .Diff.NumFiles 1))}}
|
||||||
<div>
|
<div>
|
||||||
<div class="diff-detail-box diff-box">
|
<div class="diff-detail-box diff-box">
|
||||||
<div class="gt-df gt-ac gt-fw">
|
<div class="gt-df gt-ac gt-fw gt-gap-3 gt-ml-1">
|
||||||
{{if $showFileTree}}
|
{{if $showFileTree}}
|
||||||
<button class="diff-toggle-file-tree-button not-mobile btn interact-fg" data-show-text="{{ctx.Locale.Tr "repo.diff.show_file_tree"}}" data-hide-text="{{ctx.Locale.Tr "repo.diff.hide_file_tree"}}">
|
<button class="diff-toggle-file-tree-button not-mobile btn interact-fg" data-show-text="{{ctx.Locale.Tr "repo.diff.show_file_tree"}}" data-hide-text="{{ctx.Locale.Tr "repo.diff.hide_file_tree"}}">
|
||||||
{{/* the icon meaning is reversed here, "octicon-sidebar-collapse" means show the file tree */}}
|
{{/* the icon meaning is reversed here, "octicon-sidebar-collapse" means show the file tree */}}
|
||||||
|
|
|
@ -112,9 +112,9 @@
|
||||||
{{template "shared/user/authorlink" .Poster}}
|
{{template "shared/user/authorlink" .Poster}}
|
||||||
{{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
|
{{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
|
||||||
{{if eq $.Issue.PullRequest.Status 3}}
|
{{if eq $.Issue.PullRequest.Status 3}}
|
||||||
{{ctx.Locale.Tr "repo.issues.comment_manually_pull_merged_at" (printf `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID)) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape)) $createdStr | Safe}}
|
{{ctx.Locale.Tr "repo.issues.comment_manually_pull_merged_at" (printf `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) | Safe) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape) | Safe) $createdStr}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{ctx.Locale.Tr "repo.issues.comment_pull_merged_at" (printf `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID)) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape)) $createdStr | Safe}}
|
{{ctx.Locale.Tr "repo.issues.comment_pull_merged_at" (printf `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) | Safe) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape) | Safe) $createdStr}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{{template "repo/pulls/status" (dict
|
{{template "repo/pulls/status" (dict
|
||||||
"CommitStatus" .LatestCommitStatus
|
"CommitStatus" .LatestCommitStatus
|
||||||
"CommitStatuses" .LatestCommitStatuses
|
"CommitStatuses" .LatestCommitStatuses
|
||||||
|
"MissingRequiredChecks" .MissingRequiredChecks
|
||||||
"ShowHideChecks" true
|
"ShowHideChecks" true
|
||||||
"is_context_required" .is_context_required
|
"is_context_required" .is_context_required
|
||||||
)}}
|
)}}
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
{{ctx.Locale.Tr "repo.pulls.merged_success"}}
|
{{ctx.Locale.Tr "repo.pulls.merged_success"}}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="merge-section-info">
|
<div class="merge-section-info">
|
||||||
{{ctx.Locale.Tr "repo.pulls.merged_info_text" (printf "<code>%s</code>" (.HeadTarget | Escape)) | Str2html}}
|
{{ctx.Locale.Tr "repo.pulls.merged_info_text" (printf "<code>%s</code>" (.HeadTarget | Escape) | Safe)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-section-right">
|
<div class="item-section-right">
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Template Attributes:
|
Template Attributes:
|
||||||
* CommitStatus: summary of all commit status state
|
* CommitStatus: summary of all commit status state
|
||||||
* CommitStatuses: all commit status elements
|
* CommitStatuses: all commit status elements
|
||||||
|
* MissingRequiredChecks: commit check contexts that are required by branch protection but not present
|
||||||
* ShowHideChecks: whether use a button to show/hide the checks
|
* ShowHideChecks: whether use a button to show/hide the checks
|
||||||
* is_context_required: Used in pull request commit status check table
|
* is_context_required: Used in pull request commit status check table
|
||||||
*/}}
|
*/}}
|
||||||
|
@ -9,7 +10,7 @@ Template Attributes:
|
||||||
{{if .CommitStatus}}
|
{{if .CommitStatus}}
|
||||||
<div class="commit-status-panel">
|
<div class="commit-status-panel">
|
||||||
<div class="ui top attached header commit-status-header">
|
<div class="ui top attached header commit-status-header">
|
||||||
{{if eq .CommitStatus.State "pending"}}
|
{{if or (eq .CommitStatus.State "pending") (.MissingRequiredChecks)}}
|
||||||
{{ctx.Locale.Tr "repo.pulls.status_checking"}}
|
{{ctx.Locale.Tr "repo.pulls.status_checking"}}
|
||||||
{{else if eq .CommitStatus.State "success"}}
|
{{else if eq .CommitStatus.State "success"}}
|
||||||
{{ctx.Locale.Tr "repo.pulls.status_checks_success"}}
|
{{ctx.Locale.Tr "repo.pulls.status_checks_success"}}
|
||||||
|
@ -46,6 +47,13 @@ Template Attributes:
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{range .MissingRequiredChecks}}
|
||||||
|
<div class="commit-status-item">
|
||||||
|
{{svg "octicon-dot-fill" 18 "commit-status icon text yellow"}}
|
||||||
|
<div class="status-context gt-ellipsis">{{.}}</div>
|
||||||
|
<div class="ui label">{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -5,22 +5,24 @@
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
{{template "repo/release_tag_header" .}}
|
{{template "repo/release_tag_header" .}}
|
||||||
<ul id="release-list">
|
<ul id="release-list">
|
||||||
{{range $idx, $release := .Releases}}
|
{{range $idx, $info := .Releases}}
|
||||||
|
{{$release := $info.Release}}
|
||||||
<li class="ui grid">
|
<li class="ui grid">
|
||||||
<div class="ui four wide column meta">
|
<div class="ui four wide column meta">
|
||||||
<a class="muted" href="{{if not (and .Sha1 ($.Permission.CanRead $.UnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "gt-mr-2"}}{{.TagName}}</a>
|
<a class="muted" href="{{if not (and $release.Sha1 ($.Permission.CanRead $.UnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{$release.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "gt-mr-2"}}{{$release.TagName}}</a>
|
||||||
{{if and .Sha1 ($.Permission.CanRead $.UnitTypeCode)}}
|
{{if and $release.Sha1 ($.Permission.CanRead $.UnitTypeCode)}}
|
||||||
<a class="muted gt-mono" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
|
<a class="muted gt-mono" href="{{$.RepoLink}}/src/commit/{{$release.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha $release.Sha1}}</a>
|
||||||
{{template "repo/branch_dropdown" dict "root" $ "release" .}}
|
{{template "repo/branch_dropdown" dict "root" $ "release" $release}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui twelve wide column detail">
|
<div class="ui twelve wide column detail">
|
||||||
<div class="gt-df gt-ac gt-sb gt-fw gt-mb-3">
|
<div class="gt-df gt-ac gt-sb gt-fw gt-mb-3">
|
||||||
<h4 class="release-list-title gt-word-break">
|
<h4 class="release-list-title gt-word-break">
|
||||||
<a href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}">{{.Title}}</a>
|
<a href="{{$.RepoLink}}/releases/tag/{{$release.TagName | PathEscapeSegments}}">{{$release.Title}}</a>
|
||||||
{{if .IsDraft}}
|
{{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "gt-df"}}
|
||||||
|
{{if $release.IsDraft}}
|
||||||
<span class="ui yellow label">{{ctx.Locale.Tr "repo.release.draft"}}</span>
|
<span class="ui yellow label">{{ctx.Locale.Tr "repo.release.draft"}}</span>
|
||||||
{{else if .IsPrerelease}}
|
{{else if $release.IsPrerelease}}
|
||||||
<span class="ui orange label">{{ctx.Locale.Tr "repo.release.prerelease"}}</span>
|
<span class="ui orange label">{{ctx.Locale.Tr "repo.release.prerelease"}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="ui green label">{{ctx.Locale.Tr "repo.release.stable"}}</span>
|
<span class="ui green label">{{ctx.Locale.Tr "repo.release.stable"}}</span>
|
||||||
|
@ -28,7 +30,7 @@
|
||||||
</h4>
|
</h4>
|
||||||
<div>
|
<div>
|
||||||
{{if $.CanCreateRelease}}
|
{{if $.CanCreateRelease}}
|
||||||
<a class="muted" data-tooltip-content="{{ctx.Locale.Tr "repo.release.edit"}}" href="{{$.RepoLink}}/releases/edit/{{.TagName | PathEscapeSegments}}" rel="nofollow">
|
<a class="muted" data-tooltip-content="{{ctx.Locale.Tr "repo.release.edit"}}" href="{{$.RepoLink}}/releases/edit/{{$release.TagName | PathEscapeSegments}}" rel="nofollow">
|
||||||
{{svg "octicon-pencil"}}
|
{{svg "octicon-pencil"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -36,11 +38,11 @@
|
||||||
</div>
|
</div>
|
||||||
<p class="text grey">
|
<p class="text grey">
|
||||||
<span class="author">
|
<span class="author">
|
||||||
{{if .OriginalAuthor}}
|
{{if $release.OriginalAuthor}}
|
||||||
{{svg (MigrationIcon .Repo.GetOriginalURLHostname) 20 "gt-mr-2"}}{{.OriginalAuthor}}
|
{{svg (MigrationIcon $release.Repo.GetOriginalURLHostname) 20 "gt-mr-2"}}{{$release.OriginalAuthor}}
|
||||||
{{else if .Publisher}}
|
{{else if $release.Publisher}}
|
||||||
{{ctx.AvatarUtils.Avatar .Publisher 20 "gt-mr-2"}}
|
{{ctx.AvatarUtils.Avatar $release.Publisher 20 "gt-mr-2"}}
|
||||||
<a href="{{.Publisher.HomeLink}}">{{.Publisher.GetDisplayName}}</a>
|
<a href="{{$release.Publisher.HomeLink}}">{{$release.Publisher.GetDisplayName}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
Ghost
|
Ghost
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -48,15 +50,15 @@
|
||||||
<span class="released">
|
<span class="released">
|
||||||
{{ctx.Locale.Tr "repo.released_this"}}
|
{{ctx.Locale.Tr "repo.released_this"}}
|
||||||
</span>
|
</span>
|
||||||
{{if .CreatedUnix}}
|
{{if $release.CreatedUnix}}
|
||||||
<span class="time">{{TimeSinceUnix .CreatedUnix ctx.Locale}}</span>
|
<span class="time">{{TimeSinceUnix $release.CreatedUnix ctx.Locale}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and (not .IsDraft) ($.Permission.CanRead $.UnitTypeCode)}}
|
{{if and (not $release.IsDraft) ($.Permission.CanRead $.UnitTypeCode)}}
|
||||||
| <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | PathEscapeSegments}}...{{.TargetBehind | PathEscapeSegments}}">{{ctx.Locale.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{ctx.Locale.Tr "repo.release.ahead.target" .TargetBehind}}</span>
|
| <span class="ahead"><a href="{{$.RepoLink}}/compare/{{$release.TagName | PathEscapeSegments}}...{{$release.TargetBehind | PathEscapeSegments}}">{{ctx.Locale.Tr "repo.release.ahead.commits" $release.NumCommitsBehind | Str2html}}</a> {{ctx.Locale.Tr "repo.release.ahead.target" $release.TargetBehind}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<div class="markup desc">
|
<div class="markup desc">
|
||||||
{{Str2html .Note}}
|
{{Str2html $release.Note}}
|
||||||
</div>
|
</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<details class="download" {{if eq $idx 0}}open{{end}}>
|
<details class="download" {{if eq $idx 0}}open{{end}}>
|
||||||
|
@ -64,16 +66,15 @@
|
||||||
{{ctx.Locale.Tr "repo.release.downloads"}}
|
{{ctx.Locale.Tr "repo.release.downloads"}}
|
||||||
</summary>
|
</summary>
|
||||||
<ul class="list">
|
<ul class="list">
|
||||||
{{if and (not $.DisableDownloadSourceArchives) (not .IsDraft) ($.Permission.CanRead $.UnitTypeCode)}}
|
{{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead $.UnitTypeCode)}}
|
||||||
<li>
|
<li>
|
||||||
<a class="archive-link" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a>
|
<a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="archive-link" href="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a>
|
<a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Attachments}}
|
{{range $release.Attachments}}
|
||||||
{{range .Attachments}}
|
|
||||||
<li>
|
<li>
|
||||||
<a target="_blank" rel="nofollow" href="{{.DownloadURL}}" download>
|
<a target="_blank" rel="nofollow" href="{{.DownloadURL}}" download>
|
||||||
<strong>{{svg "octicon-package" 16 "gt-mr-2"}}{{.Name}}</strong>
|
<strong>{{svg "octicon-package" 16 "gt-mr-2"}}{{.Name}}</strong>
|
||||||
|
@ -86,7 +87,6 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<div class="dot"></div>
|
<div class="dot"></div>
|
||||||
|
|
|
@ -263,7 +263,7 @@
|
||||||
<label for="authorization_header">{{ctx.Locale.Tr "repo.settings.authorization_header"}}</label>
|
<label for="authorization_header">{{ctx.Locale.Tr "repo.settings.authorization_header"}}</label>
|
||||||
<input id="authorization_header" name="authorization_header" type="text" value="{{.Webhook.HeaderAuthorization}}"{{if eq .HookType "matrix"}} placeholder="Bearer $access_token" required{{end}}>
|
<input id="authorization_header" name="authorization_header" type="text" value="{{.Webhook.HeaderAuthorization}}"{{if eq .HookType "matrix"}} placeholder="Bearer $access_token" required{{end}}>
|
||||||
{{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}}
|
{{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}}
|
||||||
<span class="help">{{ctx.Locale.Tr "repo.settings.authorization_header_desc" "<code>Bearer token123456</code>, <code>Basic YWxhZGRpbjpvcGVuc2VzYW1l</code>" | Str2html}}</span>
|
<span class="help">{{ctx.Locale.Tr "repo.settings.authorization_header_desc" ("<code>Bearer token123456</code>, <code>Basic YWxhZGRpbjpvcGVuc2VzYW1l</code>" | Safe)}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,8 @@
|
||||||
<li>
|
<li>
|
||||||
{{svg "octicon-location"}}
|
{{svg "octicon-location"}}
|
||||||
<span class="gt-f1">{{.ContextUser.Location}}</span>
|
<span class="gt-f1">{{.ContextUser.Location}}</span>
|
||||||
{{if .UserLocationMapURL}}
|
{{if .ContextUserLocationMapURL}}
|
||||||
{{/* We presume that the UserLocationMapURL is safe, as it is provided by the site administrator. */}}
|
<a href="{{.ContextUserLocationMapURL}}" rel="nofollow noreferrer" data-tooltip-content="{{ctx.Locale.Tr "user.show_on_map"}}">
|
||||||
<a href="{{.UserLocationMapURL | Safe}}{{.ContextUser.Location | QueryEscape}}" rel="nofollow noreferrer" data-tooltip-content="{{ctx.Locale.Tr "user.show_on_map"}}">
|
|
||||||
{{svg "octicon-link-external"}}
|
{{svg "octicon-link-external"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
4
templates/swagger/v1_json.tmpl
generated
4
templates/swagger/v1_json.tmpl
generated
|
@ -19,9 +19,9 @@
|
||||||
"name": "MIT",
|
"name": "MIT",
|
||||||
"url": "http://opensource.org/licenses/MIT"
|
"url": "http://opensource.org/licenses/MIT"
|
||||||
},
|
},
|
||||||
"version": "{{AppVer | JSEscape | Safe}}"
|
"version": "{{AppVer | JSEscape}}"
|
||||||
},
|
},
|
||||||
"basePath": "{{AppSubUrl | JSEscape | Safe}}/api/v1",
|
"basePath": "{{AppSubUrl | JSEscape}}/api/v1",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/activitypub/user-id/{user-id}": {
|
"/activitypub/user-id/{user-id}": {
|
||||||
"get": {
|
"get": {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"issuer": "{{AppUrl | JSEscape | Safe}}",
|
"issuer": "{{AppUrl | JSEscape}}",
|
||||||
"authorization_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/authorize",
|
"authorization_endpoint": "{{AppUrl | JSEscape}}login/oauth/authorize",
|
||||||
"token_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/access_token",
|
"token_endpoint": "{{AppUrl | JSEscape}}login/oauth/access_token",
|
||||||
"jwks_uri": "{{AppUrl | JSEscape | Safe}}login/oauth/keys",
|
"jwks_uri": "{{AppUrl | JSEscape}}login/oauth/keys",
|
||||||
"userinfo_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/userinfo",
|
"userinfo_endpoint": "{{AppUrl | JSEscape}}login/oauth/userinfo",
|
||||||
"introspection_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/introspect",
|
"introspection_endpoint": "{{AppUrl | JSEscape}}login/oauth/introspect",
|
||||||
"response_types_supported": [
|
"response_types_supported": [
|
||||||
"code",
|
"code",
|
||||||
"id_token"
|
"id_token"
|
||||||
],
|
],
|
||||||
"id_token_signing_alg_values_supported": [
|
"id_token_signing_alg_values_supported": [
|
||||||
"{{.SigningKey.SigningMethod.Alg | JSEscape | Safe}}"
|
"{{.SigningKey.SigningMethod.Alg | JSEscape}}"
|
||||||
],
|
],
|
||||||
"subject_types_supported": [
|
"subject_types_supported": [
|
||||||
"public"
|
"public"
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{{ctx.Locale.Tr "org.members.leave"}}
|
{{ctx.Locale.Tr "org.members.leave"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ctx.Locale.Tr "org.members.leave.detail" `<span class="dataOrganizationName"></span>` | Safe}}</p>
|
<p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|Safe)}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
--border-radius-circle: 50%;
|
--border-radius-circle: 50%;
|
||||||
--opacity-disabled: 0.55;
|
--opacity-disabled: 0.55;
|
||||||
--height-loading: 16rem;
|
--height-loading: 16rem;
|
||||||
|
--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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +493,11 @@ ol.ui.list li,
|
||||||
background: var(--color-active) !important;
|
background: var(--color-active) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui.form textarea:not([rows]) {
|
||||||
|
height: var(--min-height-textarea); /* override fomantic default 12em */
|
||||||
|
min-height: var(--min-height-textarea); /* override fomantic default 8em */
|
||||||
|
}
|
||||||
|
|
||||||
/* styles from removed fomantic transition module */
|
/* styles from removed fomantic transition module */
|
||||||
.hidden.transition {
|
.hidden.transition {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|
|
@ -37,13 +37,12 @@
|
||||||
.combo-markdown-editor textarea.markdown-text-editor {
|
.combo-markdown-editor textarea.markdown-text-editor {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 200px;
|
max-height: calc(100vh - var(--min-height-textarea));
|
||||||
max-height: calc(100vh - 200px);
|
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.combo-markdown-editor .CodeMirror-scroll {
|
.combo-markdown-editor .CodeMirror-scroll {
|
||||||
max-height: calc(100vh - 200px);
|
max-height: calc(100vh - var(--min-height-textarea));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use the same styles as markup/content.css */
|
/* use the same styles as markup/content.css */
|
||||||
|
|
|
@ -1498,12 +1498,6 @@
|
||||||
background: var(--color-body);
|
background: var(--color-body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 991.98px) {
|
|
||||||
.repository .diff-detail-box {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.repository .diff-detail-box {
|
.repository .diff-detail-box {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -1528,7 +1522,7 @@
|
||||||
color: var(--color-red);
|
color: var(--color-red);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 991.98px) {
|
@media (max-width: 800px) {
|
||||||
.repository .diff-detail-box .diff-detail-stats {
|
.repository .diff-detail-box .diff-detail-stats {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
@ -1538,7 +1532,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1548,15 +1541,6 @@
|
||||||
margin-right: 0 !important;
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.repository .diff-detail-box .diff-detail-actions {
|
|
||||||
padding-top: 0.25rem;
|
|
||||||
}
|
|
||||||
.repository .diff-detail-box .diff-detail-actions .ui.button:not(.btn-submit) {
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.repository .diff-detail-box span.status {
|
.repository .diff-detail-box span.status {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {POST} from '../../modules/fetch.js';
|
import {POST} from '../../modules/fetch.js';
|
||||||
|
import {imageInfo} from '../../utils/image.js';
|
||||||
|
|
||||||
async function uploadFile(file, uploadUrl) {
|
async function uploadFile(file, uploadUrl) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
@ -109,10 +111,22 @@ const uploadClipboardImage = async (editor, dropzone, e) => {
|
||||||
|
|
||||||
const placeholder = `![${name}](uploading ...)`;
|
const placeholder = `![${name}](uploading ...)`;
|
||||||
editor.insertPlaceholder(placeholder);
|
editor.insertPlaceholder(placeholder);
|
||||||
const data = await uploadFile(img, uploadUrl);
|
|
||||||
editor.replacePlaceholder(placeholder, `![${name}](/attachments/${data.uuid})`);
|
|
||||||
|
|
||||||
const $input = $(`<input name="files" type="hidden">`).attr('id', data.uuid).val(data.uuid);
|
const {uuid} = await uploadFile(img, uploadUrl);
|
||||||
|
const {width, dppx} = await imageInfo(img);
|
||||||
|
|
||||||
|
const url = `/attachments/${uuid}`;
|
||||||
|
let text;
|
||||||
|
if (width > 0 && dppx > 1) {
|
||||||
|
// Scale down images from HiDPI monitors. This uses the <img> tag because it's the only
|
||||||
|
// method to change image size in Markdown that is supported by all implementations.
|
||||||
|
text = `<img width="${Math.round(width / dppx)}" alt="${htmlEscape(name)}" src="${htmlEscape(url)}">`;
|
||||||
|
} else {
|
||||||
|
text = `![${name}](${url})`;
|
||||||
|
}
|
||||||
|
editor.replacePlaceholder(placeholder, text);
|
||||||
|
|
||||||
|
const $input = $(`<input name="files" type="hidden">`).attr('id', uuid).val(uuid);
|
||||||
$files.append($input);
|
$files.append($input);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import $ from 'jquery';
|
|
||||||
import {hideElem, showElem} from '../utils/dom.js';
|
import {hideElem, showElem} from '../utils/dom.js';
|
||||||
import {GET, POST} from '../modules/fetch.js';
|
import {GET, POST} from '../modules/fetch.js';
|
||||||
|
|
||||||
const {appSubUrl} = window.config;
|
const {appSubUrl} = window.config;
|
||||||
|
|
||||||
export function initRepoMigrationStatusChecker() {
|
export function initRepoMigrationStatusChecker() {
|
||||||
const $repoMigrating = $('#repo_migrating');
|
const repoMigrating = document.getElementById('repo_migrating');
|
||||||
if (!$repoMigrating.length) return;
|
if (!repoMigrating) return;
|
||||||
|
|
||||||
$('#repo_migrating_retry').on('click', doMigrationRetry);
|
document.getElementById('repo_migrating_retry').addEventListener('click', doMigrationRetry);
|
||||||
|
|
||||||
const task = $repoMigrating.attr('data-migrating-task-id');
|
const task = repoMigrating.getAttribute('data-migrating-task-id');
|
||||||
|
|
||||||
// returns true if the refresh still need to be called after a while
|
// returns true if the refresh still needs to be called after a while
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
const res = await GET(`${appSubUrl}/user/task/${task}`);
|
const res = await GET(`${appSubUrl}/user/task/${task}`);
|
||||||
if (res.status !== 200) return true; // continue to refresh if network error occurs
|
if (res.status !== 200) return true; // continue to refresh if network error occurs
|
||||||
|
@ -21,7 +20,7 @@ export function initRepoMigrationStatusChecker() {
|
||||||
|
|
||||||
// for all status
|
// for all status
|
||||||
if (data.message) {
|
if (data.message) {
|
||||||
$('#repo_migrating_progress_message').text(data.message);
|
document.getElementById('repo_migrating_progress_message').textContent = data.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TaskStatusFinished
|
// TaskStatusFinished
|
||||||
|
@ -37,7 +36,7 @@ export function initRepoMigrationStatusChecker() {
|
||||||
showElem('#repo_migrating_retry');
|
showElem('#repo_migrating_retry');
|
||||||
showElem('#repo_migrating_failed');
|
showElem('#repo_migrating_failed');
|
||||||
showElem('#repo_migrating_failed_image');
|
showElem('#repo_migrating_failed_image');
|
||||||
$('#repo_migrating_failed_error').text(data.message);
|
document.getElementById('repo_migrating_failed_error').textContent = data.message;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +58,6 @@ export function initRepoMigrationStatusChecker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doMigrationRetry(e) {
|
async function doMigrationRetry(e) {
|
||||||
await POST($(e.target).attr('data-migrating-task-retry-url'));
|
await POST(e.target.getAttribute('data-migrating-task-retry-url'));
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import $ from 'jquery';
|
|
||||||
import {checkAppUrl} from './common-global.js';
|
import {checkAppUrl} from './common-global.js';
|
||||||
|
|
||||||
export function initUserAuthOauth2() {
|
export function initUserAuthOauth2() {
|
||||||
|
@ -21,30 +20,3 @@ export function initUserAuthOauth2() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initUserAuthLinkAccountView() {
|
|
||||||
const $lnkUserPage = $('.page-content.user.link-account');
|
|
||||||
if ($lnkUserPage.length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $signinTab = $lnkUserPage.find('.item[data-tab="auth-link-signin-tab"]');
|
|
||||||
const $signUpTab = $lnkUserPage.find('.item[data-tab="auth-link-signup-tab"]');
|
|
||||||
const $signInView = $lnkUserPage.find('.tab[data-tab="auth-link-signin-tab"]');
|
|
||||||
const $signUpView = $lnkUserPage.find('.tab[data-tab="auth-link-signup-tab"]');
|
|
||||||
|
|
||||||
$signUpTab.on('click', () => {
|
|
||||||
$signinTab.removeClass('active');
|
|
||||||
$signInView.removeClass('active');
|
|
||||||
$signUpTab.addClass('active');
|
|
||||||
$signUpView.addClass('active');
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
$signinTab.on('click', () => {
|
|
||||||
$signUpTab.removeClass('active');
|
|
||||||
$signUpView.removeClass('active');
|
|
||||||
$signinTab.addClass('active');
|
|
||||||
$signInView.addClass('active');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import {initFindFileInRepo} from './features/repo-findfile.js';
|
||||||
import {initCommentContent, initMarkupContent} from './markup/content.js';
|
import {initCommentContent, initMarkupContent} from './markup/content.js';
|
||||||
import {initPdfViewer} from './render/pdf.js';
|
import {initPdfViewer} from './render/pdf.js';
|
||||||
|
|
||||||
import {initUserAuthLinkAccountView, initUserAuthOauth2} from './features/user-auth.js';
|
import {initUserAuthOauth2} from './features/user-auth.js';
|
||||||
import {
|
import {
|
||||||
initRepoIssueDue,
|
initRepoIssueDue,
|
||||||
initRepoIssueReferenceRepositorySearch,
|
initRepoIssueReferenceRepositorySearch,
|
||||||
|
@ -178,7 +178,6 @@ onDomReady(() => {
|
||||||
initCommitStatuses();
|
initCommitStatuses();
|
||||||
initCaptcha();
|
initCaptcha();
|
||||||
|
|
||||||
initUserAuthLinkAccountView();
|
|
||||||
initUserAuthOauth2();
|
initUserAuthOauth2();
|
||||||
initUserAuthWebAuthn();
|
initUserAuthWebAuthn();
|
||||||
initUserAuthWebAuthnRegister();
|
initUserAuthWebAuthnRegister();
|
||||||
|
|
47
web_src/js/utils/image.js
Normal file
47
web_src/js/utils/image.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
export async function pngChunks(blob) {
|
||||||
|
const uint8arr = new Uint8Array(await blob.arrayBuffer());
|
||||||
|
const chunks = [];
|
||||||
|
if (uint8arr.length < 12) return chunks;
|
||||||
|
const view = new DataView(uint8arr.buffer);
|
||||||
|
if (view.getBigUint64(0) !== 9894494448401390090n) return chunks;
|
||||||
|
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
let index = 8;
|
||||||
|
while (index < uint8arr.length) {
|
||||||
|
const len = view.getUint32(index);
|
||||||
|
chunks.push({
|
||||||
|
name: decoder.decode(uint8arr.slice(index + 4, index + 8)),
|
||||||
|
data: uint8arr.slice(index + 8, index + 8 + len),
|
||||||
|
});
|
||||||
|
index += len + 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode a image and try to obtain width and dppx. If will never throw but instead
|
||||||
|
// return default values.
|
||||||
|
export async function imageInfo(blob) {
|
||||||
|
let width = 0; // 0 means no width could be determined
|
||||||
|
let dppx = 1; // 1 dot per pixel for non-HiDPI screens
|
||||||
|
|
||||||
|
if (blob.type === 'image/png') { // only png is supported currently
|
||||||
|
try {
|
||||||
|
for (const {name, data} of await pngChunks(blob)) {
|
||||||
|
const view = new DataView(data.buffer);
|
||||||
|
if (name === 'IHDR' && data?.length) {
|
||||||
|
// extract width from mandatory IHDR chunk
|
||||||
|
width = view.getUint32(0);
|
||||||
|
} else if (name === 'pHYs' && data?.length) {
|
||||||
|
// extract dppx from optional pHYs chunk, assuming pixels are square
|
||||||
|
const unit = view.getUint8(8);
|
||||||
|
if (unit === 1) {
|
||||||
|
dppx = Math.round(view.getUint32(0) / 39.3701) / 72; // meter to inch to dppx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {width, dppx};
|
||||||
|
}
|
29
web_src/js/utils/image.test.js
Normal file
29
web_src/js/utils/image.test.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import {pngChunks, imageInfo} from './image.js';
|
||||||
|
|
||||||
|
const pngNoPhys = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAADUlEQVQIHQECAP3/AAAAAgABzePRKwAAAABJRU5ErkJggg==';
|
||||||
|
const pngPhys = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAEElEQVQI12OQNZcAIgYIBQAL8gGxdzzM0A==';
|
||||||
|
const pngEmpty = 'data:image/png;base64,';
|
||||||
|
|
||||||
|
async function dataUriToBlob(datauri) {
|
||||||
|
return await (await globalThis.fetch(datauri)).blob();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('pngChunks', async () => {
|
||||||
|
expect(await pngChunks(await dataUriToBlob(pngNoPhys))).toEqual([
|
||||||
|
{name: 'IHDR', data: new Uint8Array([0, 0, 0, 1, 0, 0, 0, 1, 8, 0, 0, 0, 0])},
|
||||||
|
{name: 'IDAT', data: new Uint8Array([8, 29, 1, 2, 0, 253, 255, 0, 0, 0, 2, 0, 1])},
|
||||||
|
{name: 'IEND', data: new Uint8Array([])},
|
||||||
|
]);
|
||||||
|
expect(await pngChunks(await dataUriToBlob(pngPhys))).toEqual([
|
||||||
|
{name: 'IHDR', data: new Uint8Array([0, 0, 0, 2, 0, 0, 0, 2, 8, 2, 0, 0, 0])},
|
||||||
|
{name: 'pHYs', data: new Uint8Array([0, 0, 22, 37, 0, 0, 22, 37, 1])},
|
||||||
|
{name: 'IDAT', data: new Uint8Array([8, 215, 99, 144, 53, 151, 0, 34, 6, 8, 5, 0, 11, 242, 1, 177])},
|
||||||
|
]);
|
||||||
|
expect(await pngChunks(await dataUriToBlob(pngEmpty))).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('imageInfo', async () => {
|
||||||
|
expect(await imageInfo(await dataUriToBlob(pngNoPhys))).toEqual({width: 1, dppx: 1});
|
||||||
|
expect(await imageInfo(await dataUriToBlob(pngPhys))).toEqual({width: 2, dppx: 2});
|
||||||
|
expect(await imageInfo(await dataUriToBlob(pngEmpty))).toEqual({width: 0, dppx: 1});
|
||||||
|
});
|
Loading…
Reference in a new issue