Compare commits

...

9 Commits

Author SHA1 Message Date
Zettat123
5a12e95d2a
Fix 404 error viewing the LFS file (#22945)
Fix #22734.

According to
[`view_file.tmpl`](https://github.com/go-gitea/gitea/blob/main/templates/repo/view_file.tmpl#L82),
`lfs_file.tmpl` should use `AssetUrlPrefix` instead of `AppSubUrl`.

Co-authored-by: Jason Song <i@wolfogre.com>
2023-02-17 11:55:33 +08:00
gempir
d9c6cb71e1
Always go full width in PR view (#22844)
This is an alternative solution to #22824 
and would also close #22781

This makes the PR diff view always full width.
It makes sense to make use of that screen real estate. If you want a
more narrow view you can always resize your browser.
It also avoids cluttering the UI with another button + the database with
another column for the setting.

This is also how github and gitlab do it.
2023-02-16 13:25:00 -06:00
zeripath
52dd383b6d
Increase Content field size of gpg_key_import to MEDIUMTEXT (#22897)
Unfortunately #20896 does not completely prevent Data too long issues
and GPGKeyImport needs to be increased too.

Fix #22896

Signed-off-by: Andrew Thornton <art27@cantab.net>
2023-02-16 12:08:40 -06:00
Lunny Xiao
f196da12db
Fix context bug (#22940)
Fix https://try.gitea.io/wxiaoguang/test/issues/19
2023-02-16 11:20:53 -06:00
Sybren
aa45777c92
Allow custom "created" timestamps in user creation API (#22549)
Allow back-dating user creation via the `adminCreateUser` API operation.
`CreateUserOption` now has an optional field `created_at`, which can
contain a datetime-formatted string. If this field is present, the
user's `created_unix` database field will be updated to its value.

This is important for Blender's migration of users from Phabricator to
Gitea. There are many users, and the creation timestamp of their account
can give us some indication as to how long someone's been part of the
community.

The back-dating is done in a separate query that just updates the user's
`created_unix` field. This was the easiest and cleanest way I could
find, as in the initial `INSERT` query the field always is set to "now".
2023-02-16 10:32:01 -06:00
Dalai Felinto
a0b9767df8
Use "Title Case" for text "Reference in new issue" (#22936)
The "Reference in new issue" option shows up in a menu when looking at
pull requests. All the other options there follow the "Title case":

* Copy Link
* Quote Reply
* Edit

This patch makes sure this option also follow the Title case.

Screenshot of how it looks without this patch:

![image](https://user-images.githubusercontent.com/843498/219346003-728d07c1-d150-41a5-b084-faef118228b1.png)

Co-authored-by: Dalai Felinto <dalai@blender.org>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-02-16 23:06:07 +08:00
wxiaoguang
2e97a77e12
First step to refactor the .hide to .gt-hidden (#22916)
A separate PR from #22884 (without touching the jQuery methods)
2023-02-16 20:07:21 +08:00
zeripath
6c90f5e4c0
Add continue option to backport.go (#22930)
Sometimes it can be helpful to continue from a broken cherry-pick. This
PR adds another option which can be used to determine the version and pr
number from the current branch name instead of reading the config.yaml
file.

---------

Signed-off-by: Andrew Thornton <art27@cantab.net>
2023-02-16 10:48:08 +01:00
delvh
3361bbf058
Add title to PR file tree items (#22918)
Previously, a file/directory name was simply cut when it was too long.
Now, we display the browser-native tooltip (`title`) instead, so you can
still see it when hovering over it.
In this case, we don't use the normal `tippy` tooltips for three
reasons:
1. Vue components are not included in the global tooltip initialization
2. Vue components would need to initialize their tooltips themselves
whenever their content is changed
3. The tooltips are shown too long under the default configuration (the
tooltip one element above is still shown when hovering on the element
below)

Fixes #22915

## Appearance


![image](https://user-images.githubusercontent.com/51889757/219049642-43668a38-0e86-42bf-a1d0-3742c4dc7fd9.png)

## Room for future improvement

We could think about displaying the whole file path in the title, not
just its name.
This is not done at the moment:

![image](https://user-images.githubusercontent.com/51889757/219050689-1e6e3d57-f2bf-48be-8553-415e744a6e10.png)

---------

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2023-02-16 00:57:25 -05:00
20 changed files with 189 additions and 41 deletions

View File

@ -79,6 +79,10 @@ func main() {
Name: "no-xdg-open",
Usage: "Set this flag to not use xdg-open to open the PR URL",
},
cli.BoolFlag{
Name: "continue",
Usage: "Set this flag to continue from a git cherry-pick that has broken",
},
}
cli.AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
@ -104,7 +108,19 @@ func runBackport(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
continuing := c.Bool("continue")
var pr string
version := c.String("version")
if version == "" && continuing {
// determine version from current branch name
var err error
pr, version, err = readCurrentBranch(ctx)
if err != nil {
return err
}
}
if version == "" {
version = readVersion()
}
@ -135,13 +151,14 @@ func runBackport(c *cli.Context) error {
localReleaseBranch := path.Join(upstream, upstreamReleaseBranch)
args := c.Args()
if len(args) == 0 {
if len(args) == 0 && pr == "" {
return fmt.Errorf("no PR number provided\nProvide a PR number to backport")
} else if len(args) != 1 {
} else if len(args) != 1 && pr == "" {
return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args)
}
pr := args[0]
if pr == "" {
pr = args[0]
}
backportBranch := c.String("backport-branch")
if backportBranch == "" {
@ -168,8 +185,10 @@ func runBackport(c *cli.Context) error {
}
}
if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil {
return err
if !continuing {
if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil {
return err
}
}
if err := cherrypick(ctx, sha); err != nil {
@ -353,6 +372,22 @@ func determineRemote(ctx context.Context, forkUser string) (string, string, erro
return "", "", fmt.Errorf("unable to find appropriate remote in:\n%s", string(out))
}
func readCurrentBranch(ctx context.Context) (pr, version string, err error) {
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read current git branch:\n%s\n", string(out))
return "", "", fmt.Errorf("unable to read current git branch: %w", err)
}
parts := strings.Split(strings.TrimSpace(string(out)), "-")
if len(parts) != 3 || parts[0] != "backport" {
fmt.Fprintf(os.Stderr, "Unable to continue from git branch:\n%s\n", string(out))
return "", "", fmt.Errorf("unable to continue from git branch:\n%s", string(out))
}
return parts[1], parts[2], nil
}
func readVersion() string {
bs, err := os.ReadFile("docs/config.yaml")
if err != nil {

View File

@ -23,7 +23,7 @@ import "code.gitea.io/gitea/models/db"
// GPGKeyImport the original import of key
type GPGKeyImport struct {
KeyID string `xorm:"pk CHAR(16) NOT NULL"`
Content string `xorm:"TEXT NOT NULL"`
Content string `xorm:"MEDIUMTEXT NOT NULL"`
}
func init() {

View File

@ -457,6 +457,8 @@ var migrations = []Migration{
NewMigration("Add actions tables", v1_19.AddActionsTables),
// v241 -> v242
NewMigration("Add card_type column to project table", v1_19.AddCardTypeToProjectTable),
// v242 -> v243
NewMigration("Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText),
}
// GetCurrentDBVersion returns the current db version

View File

@ -0,0 +1,26 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_19 //nolint
import (
"code.gitea.io/gitea/modules/setting"
"xorm.io/xorm"
)
// AlterPublicGPGKeyImportContentFieldToMediumText: set GPGKeyImport Content field to MEDIUMTEXT
func AlterPublicGPGKeyImportContentFieldToMediumText(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if setting.Database.UseMySQL {
if _, err := sess.Exec("ALTER TABLE `gpg_key_import` CHANGE `content` `content` MEDIUMTEXT"); err != nil {
return err
}
}
return sess.Commit()
}

View File

@ -640,6 +640,11 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
u.IsRestricted = setting.Service.DefaultUserIsRestricted
u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm)
// Ensure consistency of the dates.
if u.UpdatedUnix < u.CreatedUnix {
u.UpdatedUnix = u.CreatedUnix
}
// overwrite defaults if set
if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
overwrite := overwriteDefault[0]
@ -717,7 +722,15 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
return err
}
if err = db.Insert(ctx, u); err != nil {
if u.CreatedUnix == 0 {
// Caller expects auto-time for creation & update timestamps.
err = db.Insert(ctx, u)
} else {
// Caller sets the timestamps themselves. They are responsible for ensuring
// both `CreatedUnix` and `UpdatedUnix` are set appropriately.
_, err = db.GetEngine(ctx).NoAutoTime().Insert(u)
}
if err != nil {
return err
}

View File

@ -4,9 +4,11 @@
package user_test
import (
"context"
"math/rand"
"strings"
"testing"
"time"
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
@ -14,6 +16,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
@ -252,6 +255,58 @@ func TestCreateUserEmailAlreadyUsed(t *testing.T) {
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}
func TestCreateUserCustomTimestamps(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// Add new user with a custom creation timestamp.
var creationTimestamp timeutil.TimeStamp = 12345
user.Name = "testuser"
user.LowerName = strings.ToLower(user.Name)
user.ID = 0
user.Email = "unique@example.com"
user.CreatedUnix = creationTimestamp
err := user_model.CreateUser(user)
assert.NoError(t, err)
fetched, err := user_model.GetUserByID(context.Background(), user.ID)
assert.NoError(t, err)
assert.Equal(t, creationTimestamp, fetched.CreatedUnix)
assert.Equal(t, creationTimestamp, fetched.UpdatedUnix)
}
func TestCreateUserWithoutCustomTimestamps(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// There is no way to use a mocked time for the XORM auto-time functionality,
// so use the real clock to approximate the expected timestamp.
timestampStart := time.Now().Unix()
// Add new user without a custom creation timestamp.
user.Name = "Testuser"
user.LowerName = strings.ToLower(user.Name)
user.ID = 0
user.Email = "unique@example.com"
user.CreatedUnix = 0
user.UpdatedUnix = 0
err := user_model.CreateUser(user)
assert.NoError(t, err)
timestampEnd := time.Now().Unix()
fetched, err := user_model.GetUserByID(context.Background(), user.ID)
assert.NoError(t, err)
assert.LessOrEqual(t, timestampStart, fetched.CreatedUnix)
assert.LessOrEqual(t, fetched.CreatedUnix, timestampEnd)
assert.LessOrEqual(t, timestampStart, fetched.UpdatedUnix)
assert.LessOrEqual(t, fetched.UpdatedUnix, timestampEnd)
}
func TestGetUserIDsByNames(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())

View File

@ -4,6 +4,8 @@
package structs
import "time"
// CreateUserOption create user options
type CreateUserOption struct {
SourceID int64 `json:"source_id"`
@ -20,6 +22,11 @@ type CreateUserOption struct {
SendNotify bool `json:"send_notify"`
Restricted *bool `json:"restricted"`
Visibility string `json:"visibility" binding:"In(,public,limited,private)"`
// For explicitly setting the user creation timestamp. Useful when users are
// migrated from other systems. When omitted, the user's creation timestamp
// will be set to "now".
Created *time.Time `json:"created_at"`
}
// EditUserOption edit user options

View File

@ -1361,7 +1361,7 @@ issues.commented_at = `commented <a href="#%s">%s</a>`
issues.delete_comment_confirm = Are you sure you want to delete this comment?
issues.context.copy_link = Copy Link
issues.context.quote_reply = Quote Reply
issues.context.reference_issue = Reference in new issue
issues.context.reference_issue = Reference in New Issue
issues.context.edit = Edit
issues.context.delete = Delete
issues.no_content = There is no content yet.

View File

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/password"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/user"
@ -120,6 +121,14 @@ func CreateUser(ctx *context.APIContext) {
overwriteDefault.Visibility = &visibility
}
// Update the user creation timestamp. This can only be done after the user
// record has been inserted into the database; the insert intself will always
// set the creation timestamp to "now".
if form.Created != nil {
u.CreatedUnix = timeutil.TimeStamp(form.Created.Unix())
u.UpdatedUnix = u.CreatedUnix
}
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
if user_model.IsErrUserAlreadyExist(err) ||
user_model.IsErrEmailAlreadyUsed(err) ||

View File

@ -1,7 +1,7 @@
{{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content repository diff">
{{template "repo/header" .}}
<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}">
<div class="ui container fluid padded">
{{$class := ""}}
{{if .Commit.Signature}}
{{$class = (printf "%s%s" $class " isSigned")}}

View File

@ -1,7 +1,7 @@
{{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content repository diff {{if .PageIsComparePull}}compare pull{{end}}">
{{template "repo/header" .}}
<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}">
<div class="ui container fluid padded">
<h2 class="ui header">
{{if and $.PageIsComparePull $.IsSigned (not .Repository.IsArchived)}}

View File

@ -213,7 +213,7 @@
{{end}}
</span>
{{else}}
{{template "shared/user/avatarlink" "user" .Assignee}}
{{template "shared/user/avatarlink" Dict "Context" $.Context "user" .Assignee}}
<span class="text grey muted-links">
{{template "shared/user/authorlink" .Assignee}}
{{if eq .Poster.ID .AssigneeID}}
@ -485,7 +485,7 @@
</div>
<div>
{{if or $invalid $resolved}}
<button id="show-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if not $resolved}}hide {{end}}ui compact right labeled button show-outdated gt-df gt-ac">
<button id="show-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if not $resolved}}gt-hidden {{end}}ui compact right labeled button show-outdated gt-df gt-ac">
{{svg "octicon-unfold" 16 "gt-mr-3"}}
{{if $resolved}}
{{$.locale.Tr "repo.issues.review.show_resolved"}}
@ -493,7 +493,7 @@
{{$.locale.Tr "repo.issues.review.show_outdated"}}
{{end}}
</button>
<button id="hide-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if $resolved}}hide {{end}}ui compact right labeled button hide-outdated gt-df gt-ac">
<button id="hide-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if $resolved}}gt-hidden {{end}}ui compact right labeled button hide-outdated gt-df gt-ac">
{{svg "octicon-fold" 16 "gt-mr-3"}}
{{if $resolved}}
{{$.locale.Tr "repo.issues.review.hide_resolved"}}
@ -507,7 +507,7 @@
{{$diff := (CommentMustAsDiff (index $comms 0))}}
{{if $diff}}
{{$file := (index $diff.Files 0)}}
<div id="code-preview-{{(index $comms 0).ID}}" class="ui table segment{{if $resolved}} hide{{end}}">
<div id="code-preview-{{(index $comms 0).ID}}" class="ui table segment{{if $resolved}} gt-hidden{{end}}">
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}">
<div class="file-body file-code code-view code-diff code-diff-unified unicode-escaped">
<table>
@ -519,7 +519,7 @@
</div>
</div>
{{end}}
<div id="code-comments-{{(index $comms 0).ID}}" class="comment-code-cloud ui segment{{if $resolved}} hide{{end}}">
<div id="code-comments-{{(index $comms 0).ID}}" class="comment-code-cloud ui segment{{if $resolved}} gt-hidden{{end}}">
<div class="ui comments gt-mb-0">
{{range $comms}}
{{$createdSubStr:= TimeSinceUnix .CreatedUnix $.locale}}

View File

@ -5,7 +5,7 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull files diff">
{{template "repo/header" .}}
<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}">
<div class="ui container fluid padded">
<div class="navbar">
{{template "repo/issue/navbar" .}}
<div class="ui right">

View File

@ -35,7 +35,7 @@
<strong>{{.locale.Tr "repo.audio_not_supported_in_browser"}}</strong>
</audio>
{{else if .IsPDFFile}}
<iframe width="100%" height="600px" src="{{AppSubUrl}}/vendor/plugins/pdfjs/web/viewer.html?file={{$.RawFileLink}}"></iframe>
<iframe width="100%" height="600px" src="{{AssetUrlPrefix}}/vendor/plugins/pdfjs/web/viewer.html?file={{$.RawFileLink}}"></iframe>
{{else}}
<a href="{{$.RawFileLink}}" rel="nofollow" class="btn btn-gray btn-radius">{{.locale.Tr "repo.file_view_raw"}}</a>
{{end}}

View File

@ -15809,6 +15809,12 @@
"password"
],
"properties": {
"created_at": {
"description": "For explicitly setting the user creation timestamp. Useful when users are\nmigrated from other systems. When omitted, the user's creation timestamp\nwill be set to \"now\".",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
},
"email": {
"type": "string",
"format": "email",

View File

@ -1,5 +1,6 @@
<template>
<div v-show="show">
<div v-show="show" class="tooltip" :title="item.name">
<!--title instead of tooltip above as the tooltip needs too much work with the current methods, i.e. not being loaded or staying open for "too long"-->
<div class="item" :class="item.isFile ? 'filewrapper gt-p-1' : ''">
<!-- Files -->
<SvgIcon

View File

@ -425,10 +425,10 @@ export function initRepoPullRequestReview() {
const groupID = commentDiv.closest('div[id^="code-comments-"]').attr('id');
if (groupID && groupID.startsWith('code-comments-')) {
const id = groupID.slice(14);
$(`#show-outdated-${id}`).addClass('hide');
$(`#code-comments-${id}`).removeClass('hide');
$(`#code-preview-${id}`).removeClass('hide');
$(`#hide-outdated-${id}`).removeClass('hide');
$(`#show-outdated-${id}`).addClass('gt-hidden');
$(`#code-comments-${id}`).removeClass('gt-hidden');
$(`#code-preview-${id}`).removeClass('gt-hidden');
$(`#hide-outdated-${id}`).removeClass('gt-hidden');
commentDiv[0].scrollIntoView();
}
}
@ -437,19 +437,19 @@ export function initRepoPullRequestReview() {
$(document).on('click', '.show-outdated', function (e) {
e.preventDefault();
const id = $(this).data('comment');
$(this).addClass('hide');
$(`#code-comments-${id}`).removeClass('hide');
$(`#code-preview-${id}`).removeClass('hide');
$(`#hide-outdated-${id}`).removeClass('hide');
$(this).addClass('gt-hidden');
$(`#code-comments-${id}`).removeClass('gt-hidden');
$(`#code-preview-${id}`).removeClass('gt-hidden');
$(`#hide-outdated-${id}`).removeClass('gt-hidden');
});
$(document).on('click', '.hide-outdated', function (e) {
e.preventDefault();
const id = $(this).data('comment');
$(this).addClass('hide');
$(`#code-comments-${id}`).addClass('hide');
$(`#code-preview-${id}`).addClass('hide');
$(`#show-outdated-${id}`).removeClass('hide');
$(this).addClass('gt-hidden');
$(`#code-comments-${id}`).addClass('gt-hidden');
$(`#code-preview-${id}`).addClass('gt-hidden');
$(`#show-outdated-${id}`).removeClass('gt-hidden');
});
$(document).on('click', 'button.comment-form-reply', async function (e) {

View File

@ -1807,16 +1807,9 @@ footer {
}
}
// TODO: refactor to use ".gt-hidden" instead (a simple search&replace should do the trick)
.hide {
display: none;
&.show-outdated {
display: none !important;
}
&.hide-outdated {
display: none !important;
}
}
.center:not(.popup) {

View File

@ -57,7 +57,6 @@
.show-outdated,
.hide-outdated {
&:extend(.unselectable);
display: block !important;
&:hover {
text-decoration: underline;

View File

@ -22,7 +22,6 @@
/* below class names match Tailwind CSS */
.gt-pointer-events-none { pointer-events: none !important; }
.gt-relative { position: relative !important; }
.gt-hidden { display: none !important; }
.gt-mono {
font-family: var(--fonts-monospace) !important;
@ -181,3 +180,6 @@
.gt-w-100-small { width: 100% !important; }
.gt-js-small { justify-content: flex-start !important; }
}
// gt-hidden must be placed after all other "display: xxx !important" classes to win the hidden chance
.gt-hidden { display: none !important; }