Merge remote-tracking branch 'upstream/main'

pull/20391/head
Anthony Wang 2022-07-16 20:35:16 -05:00
commit f1577c2f62
No known key found for this signature in database
GPG Key ID: BC96B00AEC5F2D76
75 changed files with 566 additions and 304 deletions

View File

@ -652,7 +652,8 @@ steps:
image: techknowlogick/xgo:go-1.18.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs
# Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
@ -771,7 +772,8 @@ steps:
image: techknowlogick/xgo:go-1.18.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs
# Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:

View File

@ -11,13 +11,8 @@ parserOptions:
plugins:
- eslint-plugin-unicorn
- eslint-plugin-import
- eslint-plugin-vue
- eslint-plugin-html
- eslint-plugin-jquery
extends:
- plugin:vue/recommended
env:
es2022: true
node: true
@ -25,18 +20,11 @@ env:
globals:
__webpack_public_path__: true
settings:
html/html-extensions: [".tmpl"]
overrides:
- files: ["web_src/**/*.js", "web_src/**/*.vue", "templates/**/*.tmpl"]
- files: ["web_src/**/*.js", "docs/**/*.js"]
env:
browser: true
node: false
- files: ["templates/**/*.tmpl"]
rules:
no-tabs: [0]
indent: [2, tab, {SwitchCase: 1}]
- files: ["web_src/**/*worker.js"]
env:
worker: true
@ -502,11 +490,6 @@ rules:
use-isnan: [2]
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
vue/attributes-order: [0]
vue/component-definition-name-casing: [0]
vue/html-closing-bracket-spacing: [0]
vue/max-attributes-per-line: [0]
vue/one-component-per-file: [0]
wrap-iife: [2, inside]
wrap-regex: [0]
yield-star-spacing: [2, after]

View File

@ -201,9 +201,9 @@ help:
.PHONY: go-check
go-check:
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9]+' go.mod | cut -d' ' -f2))
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
$(eval GO_VERSION := $(shell printf "%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9]+' | tr '.' ' ');))
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build. You can get it at https://go.dev/dl/"; \
exit 1; \
@ -310,7 +310,7 @@ lint: lint-frontend lint-backend
.PHONY: lint-frontend
lint-frontend: node_modules
npx eslint --color --max-warnings=0 web_src/js build templates *.config.js docs/assets/js
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js
npx stylelint --color --max-warnings=0 web_src/less
npx spectral lint -q -F hint $(SWAGGER_SPEC)

View File

@ -45,21 +45,21 @@
</p>
<p align="center">
<a href="README_ZH.md">View the chinese version of this document</a>
<a href="README_ZH.md">View this document in Chinese</a>
</p>
## Purpose
The goal of this project is to make the easiest, fastest, and most
painless way of setting up a self-hosted Git service.
Using Go, this can be done with an independent binary distribution across
**all platforms** which Go supports, including Linux, macOS, and Windows
on x86, amd64, ARM and PowerPC architectures.
Want to try it before doing anything else?
Do it [with the online demo](https://try.gitea.io/)!
As Gitea is written in Go, it works across **all** the platforms and
architectures that are supported by Go, including Linux, macOS, and
Windows on x86, amd64, ARM and PowerPC architectures.
You can try it out using [the online demo](https://try.gitea.io/).
This project has been
[forked](https://blog.gitea.io/2016/12/welcome-to-gitea/) from
[Gogs](https://gogs.io) since 2016.11 but changed a lot.
[Gogs](https://gogs.io) since November of 2016, but a lot has changed.
## Building
@ -114,7 +114,7 @@ For more information and instructions about how to install Gitea, please look at
If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://discourse.gitea.io/).
We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea).
The hugo-based documentation theme is hosted at [gitea/theme](https://gitea.com/gitea/theme).
The Hugo-based documentation theme is hosted at [gitea/theme](https://gitea.com/gitea/theme).
The official Gitea CLI is developed at [gitea/tea](https://gitea.com/gitea/tea).
## Authors

View File

@ -45,7 +45,7 @@
</p>
<p align="center">
<a href="README.md">View the english version of this document</a>
<a href="README.md">View this document in English</a>
</p>
## 目标

View File

@ -157,6 +157,10 @@ var (
Name: "email,e",
Usage: "Email of the user to delete",
},
cli.BoolFlag{
Name: "purge",
Usage: "Purge user, all their repositories, organizations and comments",
},
},
Action: runDeleteUser,
}
@ -675,7 +679,7 @@ func runDeleteUser(c *cli.Context) error {
return fmt.Errorf("The user %s does not match the provided id %d", user.Name, c.Int64("id"))
}
return user_service.DeleteUser(user)
return user_service.DeleteUser(ctx, user, c.Bool("purge"))
}
func runGenerateAccessToken(c *cli.Context) error {

View File

@ -7,6 +7,8 @@ package cmd
import (
"context"
"errors"
"fmt"
"os"
"strings"
"code.gitea.io/gitea/modules/convert"
@ -15,6 +17,7 @@ import (
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/migrations"
"github.com/urfave/cli"
@ -159,9 +162,23 @@ func runDumpRepository(ctx *cli.Context) error {
}
}
// the repo_dir will be removed if error occurs in DumpRepository
// make sure the directory doesn't exist or is empty, prevent from deleting user files
repoDir := ctx.String("repo_dir")
if exists, err := util.IsExist(repoDir); err != nil {
return fmt.Errorf("unable to stat repo_dir %q: %v", repoDir, err)
} else if exists {
if isDir, _ := util.IsDir(repoDir); !isDir {
return fmt.Errorf("repo_dir %q already exists but it's not a directory", repoDir)
}
if dir, _ := os.ReadDir(repoDir); len(dir) > 0 {
return fmt.Errorf("repo_dir %q is not empty", repoDir)
}
}
if err := migrations.DumpRepository(
context.Background(),
ctx.String("repo_dir"),
repoDir,
ctx.String("owner_name"),
opts,
); err != nil {

View File

@ -78,6 +78,13 @@ Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE
###
# In some cases, when using CapabilityBoundingSet and AmbientCapabilities option, you may want to
# set the following value to false to allow capabilities to be applied on gitea process. The following
# value if set to true sandboxes gitea service and prevent any processes from running with privileges
# in the host user namespace.
###
#PrivateUsers=false
###
[Install]
WantedBy=multi-user.target

View File

@ -24,7 +24,7 @@ embedded assets. This can be different for older releases.
## Download
Choose the file matching the destination platform from the [downloads page](https://dl.gitea.io/gitea/), copy the URL and replace the URL within the commands below:
Choose the file matching your platform from the [downloads page](https://dl.gitea.io/gitea/), copy the URL and replace the URL within the commands below:
```sh
wget -O gitea https://dl.gitea.io/gitea/{{< version >}}/gitea-{{< version >}}-linux-amd64
@ -56,7 +56,8 @@ Check that Git is installed on the server. If it is not, install it first. Gitea
git --version
```
Create user to run Gitea (ex. `git`)
Create a user to run Gitea (e.g. `git`)
```sh
adduser \
--system \
@ -79,29 +80,39 @@ chown root:git /etc/gitea
chmod 770 /etc/gitea
```
**NOTE:** `/etc/gitea` is temporary set with write rights for user `git` so that Web installer could write configuration file. After installation is done, it is recommended to set rights to read-only using:
```
**NOTE:** `/etc/gitea` is temporarily set with write permissions for user `git` so that the web installer can write the configuration file. After the installation is finished, it is recommended to set permissions to read-only using:
```sh
chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini
```
If you don't want the web installer to be able to write the config file at all, it is also possible to make the config file read-only for the Gitea user (owner/group `root:git`, mode `0640`), and set `INSTALL_LOCK = true`. In that case all database configuration details must be set beforehand in the config file, as well as the `SECRET_KEY` and `INTERNAL_TOKEN` values. See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret INTERNAL_TOKEN`.
If you don't want the web installer to be able to write to the config file, it is possible to make the config file read-only for the Gitea user (owner/group `root:git`, mode `0640`) however you will need to edit your config file manually to:
* Set `INSTALL_LOCK= true`,
* Ensure all database configuration details are set correctly
* Ensure that the `SECRET_KEY` and `INTERNAL_TOKEN` values are set. (You may want to use the `gitea generate secret` to generate these secret keys.)
* Ensure that any other secret keys you need are set.
See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret`.
### Configure Gitea's working directory
**NOTE:** If you plan on running Gitea as a Linux service, you can skip this step as the service file allows you to set `WorkingDirectory`. Otherwise, consider setting this environment variable (semi-)permanently so that Gitea consistently uses the correct working directory.
```
**NOTE:** If you plan on running Gitea as a Linux service, you can skip this step, as the service file allows you to set `WorkingDirectory`. Otherwise, consider setting this environment variable (semi-)permanently so that Gitea consistently uses the correct working directory.
```sh
export GITEA_WORK_DIR=/var/lib/gitea/
```
### Copy Gitea binary to global location
### Copy the Gitea binary to a global location
```
```sh
cp gitea /usr/local/bin/gitea
```
## Running Gitea
After the above steps, two options to run Gitea are:
After you complete the above steps, you can run Gitea two ways:
### 1. Creating a service file to start Gitea automatically (recommended)
@ -109,32 +120,31 @@ See how to create [Linux service]({{< relref "run-as-service-in-ubuntu.en-us.md"
### 2. Running from command-line/terminal
```
```sh
GITEA_WORK_DIR=/var/lib/gitea/ /usr/local/bin/gitea web -c /etc/gitea/app.ini
```
## Updating to a new version
You can update to a new version of Gitea by stopping Gitea, replacing the binary at `/usr/local/bin/gitea` and restarting the instance.
The binary file name should not be changed during the update to avoid problems
in existing repositories.
The binary file name should not be changed during the update to avoid problems in existing repositories.
It is recommended you do a [backup]({{< relref "doc/usage/backup-and-restore.en-us.md" >}}) before updating your installation.
It is recommended that you make a [backup]({{< relref "doc/usage/backup-and-restore.en-us.md" >}}) before updating your installation.
If you have carried out the installation steps as described above, the binary should
have the generic name `gitea`. Do not change this, i.e. to include the version number.
### 1. Restarting Gitea with systemd (recommended)
As explained before, we recommend to use systemd as service manager. In this case ```systemctl restart gitea``` should be enough.
As we explained before, we recommend to use systemd as the service manager. In this case, `systemctl restart gitea` should be fine.
### 2. Restarting Gitea without systemd
To restart your Gitea instance, we recommend to use SIGHUP signal. If you know your Gitea PID use ```kill -1 $GITEA_PID``` otherwise you can use ```killall -1 gitea``` or ```pkill -1 gitea```
To restart your Gitea instance, we recommend to use SIGHUP signal. If you know your Gitea PID, use `kill -1 $GITEA_PID`, otherwise you can use `killall -1 gitea`.
To gracefully stop the Gitea instance, a simple ```kill $GITEA_PID``` or ```killall gitea``` is enough.
To gracefully stop the Gitea instance, a simple `kill $GITEA_PID` or `killall gitea` is enough.
**NOTE:** We don't recommend to use SIGKILL signal (know also as `-9`), you may be forcefully stopping some of Gitea internal tasks and it will not gracefully stop (tasks in queues, indexers processes, etc.)
**NOTE:** We don't recommend to use the SIGKILL signal (`-9`); you may be forcefully stopping some of Gitea's internal tasks, and it will not gracefully stop (tasks in queues, indexers, etc.)
See below for troubleshooting instructions to repair broken repositories after
an update of your Gitea version.
@ -144,31 +154,31 @@ an update of your Gitea version.
### Old glibc versions
Older Linux distributions (such as Debian 7 and CentOS 6) may not be able to load the
Gitea binary, usually producing an error such as ```./gitea: /lib/x86_64-linux-gnu/libc.so.6:
version `GLIBC\_2.14' not found (required by ./gitea)```. This is due to the integrated
Gitea binary, usually producing an error such as `./gitea: /lib/x86_64-linux-gnu/libc.so.6:
version 'GLIBC\_2.14' not found (required by ./gitea)`. This is due to the integrated
SQLite support in the binaries provided by dl.gitea.io. In this situation, it is usually
possible to [install from source]({{< relref "from-source.en-us.md" >}}) without SQLite
support.
possible to [install from source]({{< relref "from-source.en-us.md" >}}), without including
SQLite support.
### Running Gitea on another port
For errors like `702 runWeb()] [E] Failed to start server: listen tcp 0.0.0.0:3000:
bind: address already in use` Gitea needs to be started on another free port. This
bind: address already in use`, Gitea needs to be started on another free port. This
is possible using `./gitea web -p $PORT`. It's possible another instance of Gitea
is already running.
### Running Gitea on Raspbian
As of v1.8, there is a problem with the arm7 version of Gitea and it doesn't run on Raspberry Pi and similar devices.
As of v1.8, there is a problem with the arm7 version of Gitea, and it doesn't run on Raspberry Pis and similar devices.
It is therefore recommended to switch to the arm6 version which has been tested and shown to work on Raspberry Pi and similar devices.
It is recommended to switch to the arm6 version, which has been tested and shown to work on Raspberry Pis and similar devices.
<!---
please remove after fixing the arm7 bug
--->
### Git error after updating to a new version of Gitea
If the binary file name has been changed during the update to a new version of Gitea,
If during the update, the binary file name has been changed to a new version of Gitea,
Git Hooks in existing repositories will not work any more. In that case, a Git
error will be displayed when pushing to the repository.
@ -181,9 +191,9 @@ binary.
To solve this, go to the admin options and run the task `Resynchronize pre-receive,
update and post-receive hooks of all repositories` to update all hooks to contain
the new binary path. Please note that this overwrite all Git Hooks including ones
the new binary path. Please note that this overwrites all Git Hooks, including ones
with customizations made.
If you aren't using the built-in to Gitea SSH server you will also need to re-write
If you aren't using the Gitea built-in SSH server, you will also need to re-write
the authorized key file by running the `Update the '.ssh/authorized_keys' file with
Gitea SSH keys.` task in the admin options.

View File

@ -17,9 +17,12 @@ blog post to read about the justification for a fork.
## Purpose
The goal of this project is to provide the easiest, fastest, and most painless way of setting
up a self-hosted Git service. With Go, this can be done with an independent binary distribution
across all platforms and architectures that Go supports. This support includes Linux, macOS, and
Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
up a self-hosted Git service.
With Go, this can be done platform-independently across
**all platforms** which Go supports, including Linux, macOS, and Windows,
on x86, amd64, ARM and PowerPC architectures.
You can try it out using [the online demo](https://try.gitea.io/).
## Features
@ -268,8 +271,8 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
- Gitea should be run with a dedicated non-root system account on UNIX-type systems.
- Note: Gitea manages the `~/.ssh/authorized_keys` file. Running Gitea as a regular user could break that user's ability to log in.
- [Git](https://git-scm.com/) version 2.0.0 or later is required.
- [Git Large File Storage](https://git-lfs.github.com/) will be available if enabled when Git >= 2.1.2.
- Git commit-graph rendering will be enabled automatically when Git >= 2.18.
- [Git Large File Storage](https://git-lfs.github.com/) will be available if enabled and if your Git version is >= 2.1.2
- Git commit-graph rendering will be enabled automatically if your Git version is >= 2.18
## Browser Support

2
go.mod
View File

@ -105,7 +105,7 @@ require (
mvdan.cc/xurls/v2 v2.4.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.11
xorm.io/xorm v1.3.1
xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f
)
require (

4
go.sum
View File

@ -2423,5 +2423,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.11 h1:naLkJitGyYW7ZZdncsh/JW+HF4HshmvTHTyUyPwJS00=
xorm.io/builder v0.3.11/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.1 h1:z5egKrDoOLqZFhMjcGF4FBHiTmE5/feQoHclfhNidfM=
xorm.io/xorm v1.3.1/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f h1:3NvNsM4lnttTsHpk8ODHqrwN1MCEjsO3bD/rpd8A47k=
xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=

View File

@ -76,7 +76,7 @@ func TestAdminDeleteUser(t *testing.T) {
req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
"_csrf": csrf,
})
session.MakeRequest(t, req, http.StatusOK)
session.MakeRequest(t, req, http.StatusSeeOther)
assertUserDeleted(t, 8)
unittest.CheckConsistencyFor(t, &user_model.User{})

View File

@ -188,8 +188,13 @@ func initIntegrationTest() {
switch {
case setting.Database.UseMySQL:
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
setting.Database.User, setting.Database.Passwd, setting.Database.Host))
connType := "tcp"
if len(setting.Database.Host) > 0 && setting.Database.Host[0] == '/' { // looks like a unix socket
connType = "unix"
}
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)

View File

@ -242,7 +242,7 @@ func (issues IssueList) loadAssignees(ctx context.Context) error {
}
rows, err := db.GetEngine(ctx).Table("issue_assignees").
Join("INNER", "`user`", "`user`.id = `issue_assignees`.assignee_id").
In("`issue_assignees`.issue_id", issueIDs[:limit]).
In("`issue_assignees`.issue_id", issueIDs[:limit]).OrderBy(user_model.GetOrderByName()).
Rows(new(AssigneeIssue))
if err != nil {
return err

View File

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
)

View File

@ -81,5 +81,6 @@ func GetTeamsWithAccessToRepo(ctx context.Context, orgID, repoID int64, mode per
Join("INNER", "team_repo", "team_repo.team_id = team.id").
And("team_repo.org_id = ?", orgID).
And("team_repo.repo_id = ?", repoID).
OrderBy("name").
Find(&teams)
}

View File

@ -107,7 +107,7 @@ func getVersionByNameAndVersion(ctx context.Context, ownerID int64, packageType
ExactMatch: true,
Value: version,
},
IsInternal: isInternal,
IsInternal: util.OptionalBoolOf(isInternal),
Paginator: db.NewAbsoluteListOptions(0, 1),
})
if err != nil {
@ -171,7 +171,7 @@ type PackageSearchOptions struct {
Name SearchValue // only results with the specific name are found
Version SearchValue // only results with the specific version are found
Properties map[string]string // only results are found which contain all listed version properties with the specific value
IsInternal bool
IsInternal util.OptionalBool
HasFileWithName string // only results are found which are associated with a file with the specific name
HasFiles util.OptionalBool // only results are found which have associated files
Sort string
@ -179,7 +179,10 @@ type PackageSearchOptions struct {
}
func (opts *PackageSearchOptions) toConds() builder.Cond {
var cond builder.Cond = builder.Eq{"package_version.is_internal": opts.IsInternal}
cond := builder.NewCond()
if !opts.IsInternal.IsNone() {
cond = builder.Eq{"package_version.is_internal": opts.IsInternal.IsTrue()}
}
if opts.OwnerID != 0 {
cond = cond.And(builder.Eq{"package.owner_id": opts.OwnerID})

View File

@ -330,3 +330,40 @@ func DeleteProjectByIDCtx(ctx context.Context, id int64) error {
return updateRepositoryProjectCount(ctx, p.RepoID)
}
func DeleteProjectByRepoIDCtx(ctx context.Context, repoID int64) error {
switch {
case setting.Database.UseSQLite3:
if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue WHERE project_issue.id IN (SELECT project_issue.id FROM project_issue INNER JOIN project WHERE project.id = project_issue.project_id AND project.repo_id = ?)", repoID); err != nil {
return err
}
if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_board WHERE project_board.id IN (SELECT project_board.id FROM project_board INNER JOIN project WHERE project.id = project_board.project_id AND project.repo_id = ?)", repoID); err != nil {
return err
}
if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
return err
}
case setting.Database.UsePostgreSQL:
if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue USING project WHERE project.id = project_issue.project_id AND project.repo_id = ? ", repoID); err != nil {
return err
}
if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_board USING project WHERE project.id = project_board.project_id AND project.repo_id = ? ", repoID); err != nil {
return err
}
if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
return err
}
default:
if _, err := db.GetEngine(ctx).Exec("DELETE project_issue FROM project_issue INNER JOIN project ON project.id = project_issue.project_id WHERE project.repo_id = ? ", repoID); err != nil {
return err
}
if _, err := db.GetEngine(ctx).Exec("DELETE project_board FROM project_board INNER JOIN project ON project.id = project_board.project_id WHERE project.repo_id = ? ", repoID); err != nil {
return err
}
if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
return err
}
}
return updateRepositoryProjectCount(ctx, repoID)
}

View File

@ -342,16 +342,8 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
}
}
projects, _, err := project_model.GetProjects(ctx, project_model.SearchOptions{
RepoID: repoID,
})
if err != nil {
return fmt.Errorf("get projects: %v", err)
}
for i := range projects {
if err := project_model.DeleteProjectByIDCtx(ctx, projects[i].ID); err != nil {
return fmt.Errorf("delete project [%d]: %v", projects[i].ID, err)
}
if err := project_model.DeleteProjectByRepoIDCtx(ctx, repoID); err != nil {
return fmt.Errorf("unable to delete projects for repo[%d]: %v", repoID, err)
}
// Remove LFS objects

View File

@ -109,7 +109,7 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
// and just waste 1 unit is cheaper than re-allocate memory once.
users := make([]*user_model.User, 0, len(userIDs)+1)
if len(userIDs) > 0 {
if err = e.In("id", userIDs).Find(&users); err != nil {
if err = e.In("id", userIDs).OrderBy(user_model.GetOrderByName()).Find(&users); err != nil {
return nil, err
}
}
@ -168,5 +168,5 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
}
users := make([]*user_model.User, 0, 8)
return users, db.GetEngine(ctx).Where(cond).OrderBy("name").Find(&users)
return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users)
}

View File

@ -27,7 +27,7 @@ import (
)
// DeleteUser deletes models associated to an user.
func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) {
e := db.GetEngine(ctx)
// ***** START: Watch *****
@ -95,8 +95,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
return err
}
if setting.Service.UserDeleteWithCommentsMaxTime != 0 &&
u.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now()) {
if purge || (setting.Service.UserDeleteWithCommentsMaxTime != 0 &&
u.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())) {
// Delete Comments
const batchSize = 50

View File

@ -1314,3 +1314,10 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
}
return false
}
func GetOrderByName() string {
if setting.UI.DefaultShowFullName {
return "full_name, name"
}
return "name"
}

View File

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
)
// Organization contains organization context
@ -69,6 +70,20 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return
}
org := ctx.Org.Organization
// Handle Visibility
if org.Visibility != structs.VisibleTypePublic && !ctx.IsSigned {
// We must be signed in to see limited or private organizations
ctx.NotFound("OrgAssignment", err)
return
}
if org.Visibility == structs.VisibleTypePrivate {
requireMember = true
} else if ctx.IsSigned && ctx.Doer.IsRestricted {
requireMember = true
}
ctx.ContextUser = org.AsUser()
ctx.Data["Org"] = org

View File

@ -78,6 +78,8 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
allowRebase := false
allowRebaseMerge := false
allowSquash := false
allowRebaseUpdate := false
defaultDeleteBranchAfterMerge := false
defaultMergeStyle := repo_model.MergeStyleMerge
if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
@ -87,6 +89,8 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
allowRebase = config.AllowRebase
allowRebaseMerge = config.AllowRebaseMerge
allowSquash = config.AllowSquash
allowRebaseUpdate = config.AllowRebaseUpdate
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
defaultMergeStyle = config.GetDefaultMergeStyle()
}
hasProjects := false
@ -175,6 +179,8 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
AllowRebase: allowRebase,
AllowRebaseMerge: allowRebaseMerge,
AllowSquash: allowSquash,
AllowRebaseUpdate: allowRebaseUpdate,
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
DefaultMergeStyle: string(defaultMergeStyle),
AvatarURL: repo.AvatarLink(),
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,

View File

@ -73,6 +73,7 @@ func toUser(user *user_model.User, signed, authed bool) *api.User {
// only site admin will get these information and possibly user himself
if authed {
result.IsAdmin = user.IsAdmin
result.LoginName = user.LoginName
result.LastLogin = user.LastLoginUnix.AsTime()
result.Language = user.Language
result.IsActive = user.IsActive

View File

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/hashicorp/go-version"
)

View File

@ -7,6 +7,7 @@ package git
import (
"context"
"errors"
"fmt"
"strings"
)
@ -72,7 +73,14 @@ func (repo *Repository) SetDefaultBranch(name string) error {
// GetDefaultBranch gets default branch of repository.
func (repo *Repository) GetDefaultBranch() (string, error) {
stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
return stdout, err
if err != nil {
return "", err
}
stdout = strings.TrimSpace(stdout)
if !strings.HasPrefix(stdout, BranchPrefix) {
return "", errors.New("the HEAD is not a branch: " + stdout)
}
return strings.TrimPrefix(stdout, BranchPrefix), nil
}
// GetBranch returns a branch by it's name

View File

@ -85,6 +85,12 @@ func createDefaultPolicy() *bluemonday.Policy {
// Allow icons, emojis, chroma syntax and keyword markup on span
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^((icon(\s+[\p{L}\p{N}_-]+)+)|(emoji))$|^([a-z][a-z0-9]{0,2})$|^` + keywordClass + `$`)).OnElements("span")
// Allow 'style' attribute on text elements.
policy.AllowAttrs("style").OnElements("span", "p")
// Allow 'color' property for the style attribute on text elements.
policy.AllowStyles("color").OnElements("span", "p")
// Allow generally safe attributes
generalSafeAttrs := []string{
"abbr", "accept", "accept-charset",

View File

@ -45,6 +45,14 @@ func Test_Sanitizer(t *testing.T) {
`<input type="checkbox" disabled=""/>unchecked`, `<input type="checkbox" disabled=""/>unchecked`,
`<span class="emoji dropdown">NAUGHTY</span>`, `<span>NAUGHTY</span>`,
`<span class="emoji">contents</span>`, `<span class="emoji">contents</span>`,
// Color property
`<span style="color: red">Hello World</span>`, `<span style="color: red">Hello World</span>`,
`<p style="color: red">Hello World</p>`, `<p style="color: red">Hello World</p>`,
`<code style="color: red">Hello World</code>`, `<code>Hello World</code>`,
`<span style="bad-color: red">Hello World</span>`, `<span>Hello World</span>`,
`<p style="bad-color: red">Hello World</p>`, `<p>Hello World</p>`,
`<code style="bad-color: red">Hello World</code>`, `<code>Hello World</code>`,
}
for i := 0; i < len(testCases); i += 2 {

View File

@ -91,6 +91,8 @@ type Repository struct {
AllowRebase bool `json:"allow_rebase"`
AllowRebaseMerge bool `json:"allow_rebase_explicit"`
AllowSquash bool `json:"allow_squash_merge"`
AllowRebaseUpdate bool `json:"allow_rebase_update"`
DefaultDeleteBranchAfterMerge bool `json:"default_delete_branch_after_merge"`
DefaultMergeStyle string `json:"default_merge_style"`
AvatarURL string `json:"avatar_url"`
Internal bool `json:"internal"`

View File

@ -17,6 +17,9 @@ type User struct {
ID int64 `json:"id"`
// the user's username
UserName string `json:"login"`
// the user's authentication sign-in name.
// default: empty
LoginName string `json:"login_name"`
// the user's full name
FullName string `json:"full_name"`
// swagger:strfmt email

View File

@ -6,7 +6,7 @@
/bazel-*
# Directories for the Bazel IntelliJ plugin containing the generated
# IntelliJ project files and plugin configuration. Separate directories are
# IntelliJ project files and plugin configuration. Seperate directories are
# for the IntelliJ, Android Studio and CLion versions of the plugin.
/.ijwb/
/.aswb/

View File

@ -0,0 +1 @@
The Totem project hereby grant permission for non-gpl compatible GStreamer plugins to be used and distributed together with GStreamer and Totem. This permission are above and beyond the permissions granted by the GPL license Totem is covered by.

View File

@ -0,0 +1 @@
This project hereby grants permission for non-GPL compatible GStreamer plugins to be used and distributed together with GStreamer and this project. This permission is above and beyond the permissions granted by the GPL license by which this project is covered. If you modify this code, you may extend this exception to your version of the code, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.

51
options/license/Minpack Normal file
View File

@ -0,0 +1,51 @@
Minpack Copyright Notice (1999) University of Chicago. 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 end-user documentation included with the
redistribution, if any, must include the following
acknowledgment:
"This product includes software developed by the
University of Chicago, as Operator of Argonne National
Laboratory.
Alternately, this acknowledgment may appear in the software
itself, if and wherever such third-party acknowledgments
normally appear.
4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
BE CORRECTED.
5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
POSSIBILITY OF SUCH LOSS OR DAMAGES.

View File

@ -1461,7 +1461,6 @@ pulls.remove_prefix=Odstranit prefix <strong>%s</strong>
pulls.data_broken=Tento požadavek na natažení je rozbitý kvůli chybějícím informacím o rozštěpení.
pulls.files_conflicted=Tento požadavek na natažení obsahuje změny, které kolidují s cílovou větví.
pulls.is_checking=Právě probíhá kontrola konfliktů při sloučení. Zkuste to za chvíli.
pulls.is_empty=Tato větev je stejná jako cílová větev.
pulls.required_status_check_failed=Některé požadované kontroly nebyly úspěšné.
pulls.required_status_check_missing=Některé požadované kontroly chybí.
pulls.required_status_check_administrator=Jako administrátor stále můžete sloučit tento požadavek na natažení.

View File

@ -1528,7 +1528,6 @@ pulls.remove_prefix=<strong>%s</strong> Präfix entfernen
pulls.data_broken=Dieser Pull-Requests ist kaputt, da Fork-Informationen gelöscht wurden.
pulls.files_conflicted=Dieser Pull-Request hat Änderungen, die im Widerspruch zum Ziel-Branch stehen.
pulls.is_checking=Die Konfliktprüfung läuft noch. Bitte aktualisiere die Seite in wenigen Augenblicken.
pulls.is_empty=Dieser Branch ist gleich mit dem Zielbranch.
pulls.required_status_check_failed=Einige erforderliche Prüfungen waren nicht erfolgreich.
pulls.required_status_check_missing=Einige erforderliche Prüfungen fehlen.
pulls.required_status_check_administrator=Als Administrator kannst du diesen Pull-Request weiterhin zusammenführen.

View File

@ -1528,7 +1528,6 @@ pulls.remove_prefix=Αφαίρεση <strong>%s</strong> προθέματος
pulls.data_broken=Αυτό το pull request είναι κατεστραμμένο λόγω των πληροφοριών του fork που λείπουν.
pulls.files_conflicted=Αυτό το pull request περιέχει αλλαγές που συγκρούονται με το κλάδο προορισμού.
pulls.is_checking=Ο έλεγχος συγκρούσεων κατά την συγχώνευση είναι σε εξέλιξη. Δοκιμάστε ξανά σε λίγα λεπτά.
pulls.is_empty=Αυτός ο κλάδος είναι ίσος με τον κλάδο-στόχο.
pulls.required_status_check_failed=Ορισμένοι απαιτούμενοι έλεγχοι δεν ήταν επιτυχείς.
pulls.required_status_check_missing=Λείπουν ορισμένοι απαιτούμενοι έλεγχοι.
pulls.required_status_check_administrator=Ως διαχειριστής, μπορείτε ακόμα να συγχωνεύσετε αυτό το pull request.

View File

@ -2540,6 +2540,8 @@ users.delete_account = Delete User Account
users.cannot_delete_self = "You cannot delete yourself"
users.still_own_repo = This user still owns one or more repositories. Delete or transfer these repositories first.
users.still_has_org = This user is a member of an organization. Remove the user from any organizations first.
users.purge = Purge User
users.purge_help = Forcibly delete user and any repositories, organizations, and packages owned by the user. All comments will be deleted too.
users.still_own_packages = This user still owns one or more packages. Delete these packages first.
users.deletion_success = The user account has been deleted.
users.reset_2fa = Reset 2FA

View File

@ -1530,7 +1530,6 @@ pulls.remove_prefix=Eliminar prefijo <strong>%s</strong>
pulls.data_broken=Este pull request está rota debido a que falta información del fork.
pulls.files_conflicted=Este pull request tiene cambios en conflicto con la rama de destino.
pulls.is_checking=La comprobación de conflicto de fusión está en progreso. Inténtalo de nuevo en unos momentos.
pulls.is_empty=Esta rama es igual a la rama objetivo.
pulls.required_status_check_failed=Algunos controles requeridos no han tenido éxito.
pulls.required_status_check_missing=Faltan algunos controles necesarios.
pulls.required_status_check_administrator=Como administrador, aún puede fusionar este Pull Request.

View File

@ -1410,7 +1410,6 @@ pulls.remove_prefix=حذف پیشوند <strong>%s</strong>
pulls.data_broken=این تقاضای واکشی به دلیل از دست رفتن اطلاعات انشعاب با شکست مواجه شد.
pulls.files_conflicted=این تقاضای واکشی دارای تغییراتی است که با شاخه هدف تداخل دارد.
pulls.is_checking=در حال پردازش تداخل در ادغام می‌باشد. لطفاً لحظاتی بعد امتحان کنید.
pulls.is_empty=این شاخه با شاخه مقصد برابر است.
pulls.required_status_check_failed=برخی بررسی های ضروری موفقیت آمیز نبود.
pulls.required_status_check_missing=برخی بررسی های موردنیاز از قلم افتاده است.
pulls.required_status_check_administrator=مثل یک مدیر، ممکن است شما این تقاضای واکشی را مسکوت بگذارید.

View File

@ -1404,7 +1404,6 @@ pulls.remove_prefix=Enlever le préfixe <strong>%s</strong>
pulls.data_broken=Cette demande de fusion est impossible par manque d'informations de bifurcation.
pulls.files_conflicted=Cette demande d'ajout contient des modifications en conflit avec la branche ciblée.
pulls.is_checking=Vérification des conflits de fusion en cours. Réessayez dans quelques instants.
pulls.is_empty=Cette branche est identique à la branche cible.
pulls.required_status_check_failed=Certains contrôles requis n'ont pas réussi.
pulls.required_status_check_missing=Certains contrôles requis sont manquants.
pulls.required_status_check_administrator=En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull.

View File

@ -1532,7 +1532,6 @@ pulls.remove_prefix=先頭の <strong>%s</strong> を除去
pulls.data_broken=このプルリクエストは、フォークの情報が見つからないため壊れています。
pulls.files_conflicted=このプルリクエストは、ターゲットブランチと競合する変更を含んでいます。
pulls.is_checking=マージのコンフリクトを確認中です。 少し待ってからもう一度実行してください。
pulls.is_empty=このブランチの内容はターゲットブランチと同じです。
pulls.required_status_check_failed=いくつかの必要なステータスチェックが成功していません。
pulls.required_status_check_missing=必要なステータスチェックが見つかりません。
pulls.required_status_check_administrator=管理者であるため、このプルリクエストをマージすることは可能です。

View File

@ -1528,7 +1528,6 @@ pulls.remove_prefix=Noņemt <strong>%s</strong> prefiksu
pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija.
pulls.files_conflicted=Šīs izmaiņu pieprasījuma izmaiņas konfliktē ar mērķa atzaru.
pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu.
pulls.is_empty=Šis atzars ir vienāds ar mērķa atzaru.
pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas.
pulls.required_status_check_missing=Trūkst dažu obligāto pārbaužu.
pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu.

View File

@ -1388,7 +1388,6 @@ pulls.remove_prefix=Usuń <strong>%s</strong> prefiks
pulls.data_broken=Ten Pull Request jest uszkodzony ze względu na brakujące informacje o forku.
pulls.files_conflicted=Ten Pull Request zawiera zmiany konfliktujące z docelową gałęzią.
pulls.is_checking=Sprawdzanie konfliktów ze scalaniem w toku. Spróbuj ponownie za chwilę.
pulls.is_empty=Ten branch jest równy z docelowym branch'em.
pulls.required_status_check_failed=Niektóre kontrole stanów nie były pomyślne.
pulls.required_status_check_missing=Brakuje pewnych wymaganych etapów.
pulls.required_status_check_administrator=Jako administrator, możesz wciąż scalić ten Pull Request.

View File

@ -862,6 +862,7 @@ default_branch_helper=O branch padrão é o branch base para pull requests e com
mirror_prune=Varrer
mirror_prune_desc=Remover referências obsoletas de controle remoto
mirror_interval_invalid=O intervalo do espelhamento não é válido.
mirror_sync_on_commit=Sincronizar quando commits forem enviados
mirror_address=Clonar de URL
mirror_address_desc=Coloque todas as credenciais necessárias na seção de autorização.
mirror_address_url_invalid=A url fornecida é inválida. Você deve escapar todos os componentes da url corretamente.
@ -930,6 +931,7 @@ form.name_pattern_not_allowed=O padrão de '%s' não é permitido em um nome de
need_auth=Autorização
migrate_options=Opções de Migração
migrate_service=Serviço de Migração
migrate_options_mirror_helper=Este repositório será um espelho
migrate_options_lfs=Migrar arquivos LFS
migrate_options_lfs_endpoint.label=Destino LFS
migrate_options_lfs_endpoint.description=A migração tentará usar seu controle remoto Git para <a target="_blank" rel="noopener noreferrer" href="%s">determinar o servidor LFS</a>. Você também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados em outro lugar.
@ -1300,6 +1302,7 @@ issues.previous=Anterior
issues.next=Próximo
issues.open_title=Aberto
issues.closed_title=Fechado
issues.draft_title=Rascunho
issues.num_comments=%d comentários
issues.commented_at=`comentou <a href="#%s">%s</a>`
issues.delete_comment_confirm=Tem certeza que deseja excluir este comentário?
@ -1490,6 +1493,7 @@ pulls.new=Novo pull request
pulls.view=Ver Pull Request
pulls.compare_changes=Novo pull request
pulls.allow_edits_from_maintainers=Permitir edições de mantenedores
pulls.allow_edits_from_maintainers_desc=Usuários com acesso de gravação para o branch base também podem fazer push para este branch
pulls.allow_edits_from_maintainers_err=Falha na atualização
pulls.compare_changes_desc=Selecione o branch de destino (push) e o branch de origem (pull) para o merge.
pulls.has_viewed_file=Visto
@ -1527,7 +1531,6 @@ pulls.remove_prefix=Remover o prefixo <strong>%s</strong>
pulls.data_broken=Este pull request está quebrado devido a falta de informação do fork.
pulls.files_conflicted=Este pull request tem alterações conflitantes com o branch de destino.
pulls.is_checking=Verificação de conflitos do merge está em andamento. Tente novamente em alguns momentos.
pulls.is_empty=Este branch é igual ao branch de destino.
pulls.required_status_check_failed=Algumas verificações necessárias não foram bem sucedidas.
pulls.required_status_check_missing=Estão faltando algumas verificações necessárias.
pulls.required_status_check_administrator=Como administrador, você ainda pode aplicar o merge deste pull request.
@ -1595,9 +1598,13 @@ pulls.merge_instruction_step1_desc=No repositório do seu projeto, crie um novo
pulls.merge_instruction_step2_desc=Faça merge das alterações e atualize no Gitea.
pulls.auto_merge_button_when_succeed=(Quando a verificação for bem-sucedida)
pulls.auto_merge_newly_scheduled=O merge do pull request foi agendado para quando todas as verificações forem bem-sucedidas.
pulls.auto_merge_cancel_schedule=Cancelar merge automático
pulls.delete.title=Excluir este pull request?
pulls.delete.text=Você realmente deseja excluir este pull request? (Isto irá remover permanentemente todo o conteúdo. Considere fechá-la em vez disso, se você pretende mantê-la arquivado)
milestones.new=Novo marco
milestones.closed=Fechado %s
@ -2268,6 +2275,8 @@ topic.done=Feito
topic.count_prompt=Você não pode selecionar mais de 25 tópicos
topic.format_prompt=Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
find_file.go_to_file=Ir para arquivo
find_file.no_matching=Nenhum arquivo correspondente encontrado
error.csv.too_large=Não é possível renderizar este arquivo porque ele é muito grande.
error.csv.unexpected=Não é possível renderizar este arquivo porque ele contém um caractere inesperado na linha %d e coluna %d.

View File

@ -1532,7 +1532,8 @@ pulls.remove_prefix=Remover o prefixo <strong>%s</strong>
pulls.data_broken=Este pedido de integração está danificado devido à falta de informação da derivação.
pulls.files_conflicted=Este pedido de integração contém modificações que entram em conflito com o ramo de destino.
pulls.is_checking=Está em andamento uma verificação de conflitos na integração. Tente novamente daqui a alguns momentos.
pulls.is_empty=Este ramo é igual ao ramo de destino.
pulls.is_ancestor=Este ramo já está incluído no ramo de destino. Não há nada a integrar.
pulls.is_empty=As modificações feitas neste ramo já existem no ramo de destino. Este cometimento ficará vazio.
pulls.required_status_check_failed=Algumas das verificações obrigatórias não foram bem sucedidas.
pulls.required_status_check_missing=Estão faltando algumas verificações necessárias.
pulls.required_status_check_administrator=Uma vez que é administrador, ainda pode realizar a integração deste pedido.
@ -2539,6 +2540,8 @@ users.delete_account=Eliminar conta de utilizador
users.cannot_delete_self=Não se pode eliminar a si próprio
users.still_own_repo=Este utilizador ainda possui um ou mais repositórios. Elimine ou transfira esses repositórios primeiro.
users.still_has_org=Este utilizador é membro de uma organização. Remova, primeiro, o utilizador de todas as organizações.
users.purge=Eliminar utilizador
users.purge_help=Eliminar o utilizador à força, juntamente com todos os seus repositórios, organizações e pacotes. Também serão eliminados todos os seus comentários.
users.still_own_packages=Este utilizador ainda possui um ou mais pacotes. Elimine esses pacotes primeiro.
users.deletion_success=A conta de utilizador foi eliminada.
users.reset_2fa=Reinicializar a autenticação em dois passos

View File

@ -1480,7 +1480,6 @@ pulls.remove_prefix=Удалить <strong>%s</strong> префикс
pulls.data_broken=Содержимое этого запроса было нарушено вследствие удаления информации форка.
pulls.files_conflicted=Этот запрос на слияние имеет изменения конфликтующие с целевой веткой.
pulls.is_checking=Продолжается проверка конфликтов, пожалуйста обновите страницу несколько позже.
pulls.is_empty=Ветвь идентична с целевой.
pulls.required_status_check_failed=Некоторые необходимые проверки не были пройдены.
pulls.required_status_check_missing=Отсутствуют некоторые обязательные проверки.
pulls.required_status_check_administrator=Как администратор, вы все равно можете принять этот запрос на слияние.

View File

@ -1355,7 +1355,6 @@ pulls.remove_prefix=<strong>%s</strong> උපසර්ගය ඉවත් ක
pulls.data_broken=අතුරුදහන් වූ දෙබලක තොරතුරු හේතුවෙන් මෙම අදින්න ඉල්ලීම කැඩී ඇත.
pulls.files_conflicted=මෙම අදින්න ඉල්ලීම ඉලක්කගත ශාඛාව සමග එකිනෙකට වෙනස් වෙනස්කම් ඇත.
pulls.is_checking=ගැටුම් පරීක්ෂා කිරීම ඒකාබද්ධ කිරීම ක්රියාත්මක වෙමින් පවතී. සුළු මොහොතකින් නැවත උත්සාහ කරන්න.
pulls.is_empty=මෙම ශාඛාව ඉලක්කගත ශාඛාව සමග සමාන වේ.
pulls.required_status_check_failed=සමහර අවශ්ය චෙක්පත් සාර්ථක නොවීය.
pulls.required_status_check_missing=සමහර අවශ්ය චෙක්පත් අස්ථානගත වී ඇත.
pulls.required_status_check_administrator=පරිපාලකයෙකු ලෙස, ඔබ තවමත් මෙම අදින්න ඉල්ලීම ඒකාබද්ධ කළ හැකිය.

View File

@ -1369,7 +1369,6 @@ pulls.remove_prefix=<strong>%s</strong> ön ekini kaldır
pulls.data_broken=Bu değişiklik isteği, çatallama bilgilerinin eksik olması nedeniyle bozuldu.
pulls.files_conflicted=Bu değişiklik isteğinde, hedef dalla çakışan değişiklikler var.
pulls.is_checking=Birleştirme çakışması denetimi devam ediyor. Birkaç dakika sonra tekrar deneyin.
pulls.is_empty=Bu dal, hedef dalla eşittir.
pulls.required_status_check_failed=Bazı gerekli denetimler başarılı olmadı.
pulls.required_status_check_missing=Gerekli bazı kontroller eksik.
pulls.required_status_check_administrator=Yönetici olarak, bu değişiklik isteğini yine de birleştirebilirsiniz.

View File

@ -1418,7 +1418,6 @@ pulls.remove_prefix=Видалити префікс <strong>%s</strong>
pulls.data_broken=Зміст цього запиту було порушено внаслідок видалення інформації Форком. Цей запит тягнеться через відсутність інформації про вилучення.
pulls.files_conflicted=Цей запит має зміни, що конфліктують з цільовою гілкою.
pulls.is_checking=Триває перевірка конфліктів, будь ласка обновіть сторінку дещо пізніше.
pulls.is_empty=Ця гілка ідентична з цільовою гілкою.
pulls.required_status_check_failed=Деякі необхідні перевірки виконані з помилками.
pulls.required_status_check_missing=Декілька з необхідних перевірок відсутні.
pulls.required_status_check_administrator=Як адміністратор ви все одно можете об'єднати цей запит на злиття.

View File

@ -1531,7 +1531,6 @@ pulls.remove_prefix=删除 <strong>%s</strong> 前缀
pulls.data_broken=此合并请求因为派生仓库信息缺失而中断。
pulls.files_conflicted=此合并请求有变更与目标分支冲突。
pulls.is_checking=正在进行合并冲突检测,请稍后再试。
pulls.is_empty=此分支与目标分支相同。
pulls.required_status_check_failed=一些必要的检查没有成功
pulls.required_status_check_missing=缺少一些必要的检查。
pulls.required_status_check_administrator=作为管理员,您仍可合并此合并请求

View File

@ -861,7 +861,9 @@ default_branch=預設分支
default_branch_helper=預設分支是合併請求和提交程式碼的基礎分支。
mirror_prune=裁減
mirror_prune_desc=刪除過時的遠端追蹤參考
mirror_interval=鏡像間隔 (有效時間單位為 'h'、'm'、's'),設為 0 以停用定期同步。(最小間隔: %s)
mirror_interval_invalid=鏡像週期無效
mirror_sync_on_commit=推送提交後進行同步
mirror_address=從 URL Clone
mirror_address_desc=在授權資訊中填入必要的資料。
mirror_address_url_invalid=提供的網址無效。請檢查您輸入的網址是否正確。
@ -1300,6 +1302,7 @@ issues.previous=上一頁
issues.next=下一頁
issues.open_title=開放中
issues.closed_title=已關閉
issues.draft_title=草稿
issues.num_comments=%d 則留言
issues.commented_at=`已留言 <a href="#%s"> %s</a>`
issues.delete_comment_confirm=您確定要刪除這則留言嗎?
@ -1528,7 +1531,6 @@ pulls.remove_prefix=移除 <strong>%s</strong> 前綴
pulls.data_broken=此合併請求已損毀,因為遺失 Fork 資訊。
pulls.files_conflicted=此合併請求有變更和目標分支衝突。
pulls.is_checking=正在進行合併衝突檢查,請稍後再試。
pulls.is_empty=此分支與目標分支相同。
pulls.required_status_check_failed=未通過某些必要的檢查。
pulls.required_status_check_missing=遺失某些必要的檢查。
pulls.required_status_check_administrator=身為系統管理員,您依然可以進行合併。

70
package-lock.json generated
View File

@ -47,7 +47,6 @@
"@happy-dom/jest-environment": "4.0.1",
"@stoplight/spectral-cli": "6.4.1",
"eslint": "8.15.0",
"eslint-plugin-html": "6.2.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-unicorn": "42.0.0",
@ -61,7 +60,7 @@
"updates": "13.0.5"
},
"engines": {
"node": ">= 14"
"node": ">= 14.0.0"
}
},
"node_modules/@ampproject/remapping": {
@ -4839,18 +4838,6 @@
"node": ">=10.13.0"
}
},
"node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/envinfo": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
@ -5231,15 +5218,6 @@
"ms": "^2.1.1"
}
},
"node_modules/eslint-plugin-html": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz",
"integrity": "sha512-vi3NW0E8AJombTvt8beMwkL1R/fdRWl4QSNRNMhVQKWm36/X0KF0unGNAY4mqUF06mnwVWZcIcerrCnfn9025g==",
"dev": true,
"dependencies": {
"htmlparser2": "^7.1.2"
}
},
"node_modules/eslint-plugin-import": {
"version": "2.26.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
@ -6262,25 +6240,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/htmlparser2": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
"dev": true,
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"dependencies": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.2",
"domutils": "^2.8.0",
"entities": "^3.0.1"
}
},
"node_modules/http-basic": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
@ -16221,12 +16180,6 @@
"tapable": "^2.2.0"
}
},
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"dev": true
},
"envinfo": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
@ -16519,15 +16472,6 @@
}
}
},
"eslint-plugin-html": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz",
"integrity": "sha512-vi3NW0E8AJombTvt8beMwkL1R/fdRWl4QSNRNMhVQKWm36/X0KF0unGNAY4mqUF06mnwVWZcIcerrCnfn9025g==",
"dev": true,
"requires": {
"htmlparser2": "^7.1.2"
}
},
"eslint-plugin-import": {
"version": "2.26.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
@ -17317,18 +17261,6 @@
"integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==",
"dev": true
},
"htmlparser2": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
"dev": true,
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.2",
"domutils": "^2.8.0",
"entities": "^3.0.1"
}
},
"http-basic": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",

View File

@ -4,7 +4,7 @@
"private": true,
"type": "module",
"engines": {
"node": ">= 14"
"node": ">= 14.0.0"
},
"dependencies": {
"@claviska/jquery-minicolors": "2.3.6",
@ -47,7 +47,6 @@
"@happy-dom/jest-environment": "4.0.1",
"@stoplight/spectral-cli": "6.4.1",
"eslint": "8.15.0",
"eslint-plugin-html": "6.2.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-unicorn": "42.0.0",

View File

@ -316,7 +316,7 @@ func DeleteUser(ctx *context.APIContext) {
return
}
if err := user_service.DeleteUser(ctx.ContextUser); err != nil {
if err := user_service.DeleteUser(ctx, ctx.ContextUser, ctx.FormBool("purge")); err != nil {
if models.IsErrUserOwnRepos(err) ||
models.IsErrUserHasOrgs(err) ||
models.IsErrUserOwnPackages(err) {

View File

@ -224,6 +224,7 @@ func CreateRelease(ctx *context.APIContext) {
rel.IsTag = false
rel.Repo = ctx.Repo.Repository
rel.Publisher = ctx.Doer
rel.Target = form.Target
if err = release_service.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateRelease", err)

View File

@ -141,7 +141,6 @@ func GlobalInitInstalled(ctx context.Context) {
mustInit(repo_service.Init)
// Booting long running goroutines.
cron.NewContext(ctx)
issue_indexer.InitIssueIndexer(false)
code_indexer.Init()
mustInit(stats_indexer.Init)
@ -160,6 +159,9 @@ func GlobalInitInstalled(ctx context.Context) {
auth.Init()
svg.Init()
// Finally start up the cron
cron.NewContext(ctx)
}
// NormalRoutes represents non install routes

View File

@ -419,29 +419,21 @@ func DeleteUser(ctx *context.Context) {
// admin should not delete themself
if u.ID == ctx.Doer.ID {
ctx.Flash.Error(ctx.Tr("admin.users.cannot_delete_self"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
return
}
if err = user_service.DeleteUser(u); err != nil {
if err = user_service.DeleteUser(ctx, u, ctx.FormBool("purge")); err != nil {
switch {
case models.IsErrUserOwnRepos(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
case models.IsErrUserHasOrgs(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_has_org"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
case models.IsErrUserOwnPackages(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"),
})
ctx.Redirect(setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"))
default:
ctx.ServerError("DeleteUser", err)
}
@ -450,9 +442,7 @@ func DeleteUser(ctx *context.Context) {
log.Trace("Account deleted by admin (%s): %s", ctx.Doer.Name, u.Name)
ctx.Flash.Success(ctx.Tr("admin.users.deletion_success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/admin/users",
})
ctx.Redirect(setting.AppSubURL + "/admin/users")
}
// AvatarPost response for change user's avatar request

View File

@ -39,11 +39,6 @@ func Home(ctx *context.Context) {
org := ctx.Org.Organization
if !organization.HasOrgOrUserVisible(ctx, org.AsUser(), ctx.Doer) {
ctx.NotFound("HasOrgOrUserVisible", nil)
return
}
ctx.Data["PageIsUserProfile"] = true
ctx.Data["Title"] = org.DisplayName()
if len(org.Description) != 0 {

View File

@ -854,15 +854,15 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
}
ctx.Data["LatestCommitVerification"] = verification
ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(latestCommit)
}
statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, ctx.Repo.Commit.ID.String(), db.ListOptions{})
statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{})
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
}
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["LatestCommitStatuses"] = statuses
}
branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
treeLink := branchLink

View File

@ -248,7 +248,7 @@ func DeleteAccount(ctx *context.Context) {
return
}
if err := user.DeleteUser(ctx.Doer); err != nil {
if err := user.DeleteUser(ctx, ctx.Doer, false); err != nil {
switch {
case models.IsErrUserOwnRepos(err):
ctx.Flash.Error(ctx.Tr("form.still_own_repo"))

View File

@ -610,6 +610,12 @@ func RegisterRoutes(m *web.Route) {
}
// ***** START: Organization *****
m.Group("/org", func() {
m.Group("/{org}", func() {
m.Get("/members", org.Members)
}, context.OrgAssignment())
}, ignSignIn)
m.Group("/org", func() {
m.Group("", func() {
m.Get("/create", org.Create)
@ -625,7 +631,6 @@ func RegisterRoutes(m *web.Route) {
m.Get("/pulls/{team}", user.Pulls)
m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones)
m.Get("/milestones/{team}", reqMilestonesDashboardPageEnabled, user.Milestones)
m.Get("/members", org.Members)
m.Post("/members/action/{action}", org.MembersAction)
m.Get("/teams", org.Teams)
}, context.OrgAssignment(true, false, true))

View File

@ -59,7 +59,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e
ExactMatch: true,
Value: container_model.UploadVersion,
},
IsInternal: true,
IsInternal: util.OptionalBoolTrue,
HasFiles: util.OptionalBoolFalse,
})
if err != nil {

View File

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
@ -451,3 +452,30 @@ func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (
}
return s, pf, err
}
// RemoveAllPackages for User
func RemoveAllPackages(ctx context.Context, userID int64) (int, error) {
count := 0
for {
pkgVersions, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
Paginator: &db.ListOptions{
PageSize: repo_model.RepositoryListDefaultPageSize,
Page: 1,
},
OwnerID: userID,
})
if err != nil {
return count, fmt.Errorf("GetOwnedPackages[%d]: %w", userID, err)
}
if len(pkgVersions) == 0 {
break
}
for _, pv := range pkgVersions {
if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
return count, fmt.Errorf("unable to delete package %d:%s[%d]. Error: %w", pv.PackageID, pv.Version, pv.ID, err)
}
count++
}
}
return count, nil
}

View File

@ -143,8 +143,6 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r
return fmt.Errorf("setDefaultBranch: %v", err)
}
}
repo.DefaultBranch = strings.TrimPrefix(repo.DefaultBranch, git.BranchPrefix)
}
branches, _, _ := gitRepo.GetBranchNames(0, 0)
found := false

View File

@ -21,19 +21,116 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/modules/eventsource"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/packages"
)
// DeleteUser completely and permanently deletes everything of a user,
// but issues/comments/pulls will be kept and shown as someone has been deleted,
// unless the user is younger than USER_DELETE_WITH_COMMENTS_MAX_DAYS.
func DeleteUser(u *user_model.User) error {
func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
if u.IsOrganization() {
return fmt.Errorf("%s is an organization not a user", u.Name)
}
if purge {
// Disable the user first
// NOTE: This is deliberately not within a transaction as it must disable the user immediately to prevent any further action by the user to be purged.
if err := user_model.UpdateUserCols(ctx, &user_model.User{
ID: u.ID,
IsActive: false,
IsRestricted: true,
IsAdmin: false,
ProhibitLogin: true,
Passwd: "",
Salt: "",
PasswdHashAlgo: "",
MaxRepoCreation: 0,
}, "is_active", "is_restricted", "is_admin", "prohibit_login", "max_repo_creation", "passwd", "salt", "passwd_hash_algo"); err != nil {
return fmt.Errorf("unable to disable user: %s[%d] prior to purge. UpdateUserCols: %w", u.Name, u.ID, err)
}
// Force any logged in sessions to log out
// FIXME: We also need to tell the session manager to log them out too.
eventsource.GetManager().SendMessage(u.ID, &eventsource.Event{
Name: "logout",
})
// Delete all repos belonging to this user
// Now this is not within a transaction because there are internal transactions within the DeleteRepository
// BUT: the db will still be consistent even if a number of repos have already been deleted.
// And in fact we want to capture any repositories that are being created in other transactions in the meantime
//
// An alternative option here would be write a DeleteAllRepositoriesForUserID function which would delete all of the repos
// but such a function would likely get out of date
for {
repos, _, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
PageSize: repo_model.RepositoryListDefaultPageSize,
Page: 1,
},
Private: true,
OwnerID: u.ID,
})
if err != nil {
return fmt.Errorf("SearchRepositoryByName: %v", err)
}
if len(repos) == 0 {
break
}
for _, repo := range repos {
if err := models.DeleteRepository(u, u.ID, repo.ID); err != nil {
return fmt.Errorf("unable to delete repository %s for %s[%d]. Error: %v", repo.Name, u.Name, u.ID, err)
}
}
}
// Remove from Organizations and delete last owner organizations
// Now this is not within a transaction because there are internal transactions within the DeleteOrganization
// BUT: the db will still be consistent even if a number of organizations memberships and organizations have already been deleted
// And in fact we want to capture any organization additions that are being created in other transactions in the meantime
//
// An alternative option here would be write a function which would delete all organizations but it seems
// but such a function would likely get out of date
for {
orgs, err := organization.FindOrgs(organization.FindOrgOptions{
ListOptions: db.ListOptions{
PageSize: repo_model.RepositoryListDefaultPageSize,
Page: 1,
},
UserID: u.ID,
IncludePrivate: true,
})
if err != nil {
return fmt.Errorf("unable to find org list for %s[%d]. Error: %v", u.Name, u.ID, err)
}
if len(orgs) == 0 {
break
}
for _, org := range orgs {
if err := models.RemoveOrgUser(org.ID, u.ID); err != nil {
if organization.IsErrLastOrgOwner(err) {
err = organization.DeleteOrganization(ctx, org)
}
if err != nil {
return fmt.Errorf("unable to remove user %s[%d] from org %s[%d]. Error: %v", u.Name, u.ID, org.Name, org.ID, err)
}
}
}
}
// Delete Packages
if setting.Packages.Enabled {
if _, err := packages.RemoveAllPackages(ctx, u.ID); err != nil {
return err
}
}
}
ctx, committer, err := db.TxContext()
if err != nil {
return err
@ -41,7 +138,8 @@ func DeleteUser(u *user_model.User) error {
defer committer.Close()
// Note: A user owns any repository or belongs to any organization
// cannot perform delete operation.
// cannot perform delete operation. This causes a race with the purge above
// however consistency requires that we ensure that this is the case
// Check ownership of repository.
count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: u.ID})
@ -66,7 +164,7 @@ func DeleteUser(u *user_model.User) error {
return models.ErrUserOwnPackages{UID: u.ID}
}
if err := models.DeleteUser(ctx, u); err != nil {
if err := models.DeleteUser(ctx, u, purge); err != nil {
return fmt.Errorf("DeleteUser: %v", err)
}
@ -117,7 +215,7 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error {
return db.ErrCancelledf("Before delete inactive user %s", u.Name)
default:
}
if err := DeleteUser(u); err != nil {
if err := DeleteUser(ctx, u, false); err != nil {
// Ignore users that were set inactive by admin.
if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || models.IsErrUserOwnPackages(err) {
continue

View File

@ -33,7 +33,7 @@ func TestDeleteUser(t *testing.T) {
ownedRepos := make([]*repo_model.Repository, 0, 10)
assert.NoError(t, db.GetEngine(db.DefaultContext).Find(&ownedRepos, &repo_model.Repository{OwnerID: userID}))
if len(ownedRepos) > 0 {
err := DeleteUser(user)
err := DeleteUser(db.DefaultContext, user, false)
assert.Error(t, err)
assert.True(t, models.IsErrUserOwnRepos(err))
return
@ -47,7 +47,7 @@ func TestDeleteUser(t *testing.T) {
return
}
}
assert.NoError(t, DeleteUser(user))
assert.NoError(t, DeleteUser(db.DefaultContext, user, false))
unittest.AssertNotExistsBean(t, &user_model.User{ID: userID})
unittest.CheckConsistencyFor(t, &user_model.User{}, &repo_model.Repository{})
}
@ -57,7 +57,7 @@ func TestDeleteUser(t *testing.T) {
test(11)
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
assert.Error(t, DeleteUser(org))
assert.Error(t, DeleteUser(db.DefaultContext, org, false))
}
func TestCreateUser(t *testing.T) {
@ -72,7 +72,7 @@ func TestCreateUser(t *testing.T) {
assert.NoError(t, user_model.CreateUser(user))
assert.NoError(t, DeleteUser(user))
assert.NoError(t, DeleteUser(db.DefaultContext, user, false))
}
func TestCreateUser_Issue5882(t *testing.T) {
@ -101,6 +101,6 @@ func TestCreateUser_Issue5882(t *testing.T) {
assert.Equal(t, !u.AllowCreateOrganization, v.disableOrgCreation)
assert.NoError(t, DeleteUser(v.user))
assert.NoError(t, DeleteUser(db.DefaultContext, v.user, false))
}
}

View File

@ -151,7 +151,7 @@
<div class="field">
<button class="ui green button">{{.locale.Tr "admin.users.update_profile"}}</button>
<div class="ui red button delete-button" data-url="{{$.Link}}/delete" data-id="{{.User.ID}}">{{.locale.Tr "admin.users.delete_account"}}</div>
<div class="ui red button show-modal" data-modal="#delete-user-modal" data-url="{{$.Link}}/delete" data-id="{{.User.ID}}">{{.locale.Tr "admin.users.delete_account"}}</div>
</div>
</form>
</div>
@ -196,7 +196,7 @@
</div>
</div>
<div class="ui small basic delete modal">
<div class="ui small basic delete modal" id="delete-user-modal">
<div class="ui icon header">
{{svg "octicon-trash"}}
{{.locale.Tr "settings.delete_account_title"}}
@ -204,6 +204,17 @@
<div class="content">
<p>{{.locale.Tr "settings.delete_account_desc"}}</p>
</div>
<form class="ui form" method="POST" action="{{.Link}}/delete">
{{$.CsrfTokenHtml}}
<input type="hidden" name="id">
<div class="field">
<div class="ui checkbox">
<label for="purge">{{.locale.Tr "admin.users.purge"}}</label>
<input name="purge" type="checkbox">
</div>
<p class="help">{{.locale.Tr "admin.users.purge_help"}}</p>
</div>
{{template "base/delete_modal_actions" .}}
</form>
</div>
{{template "base/footer" .}}

View File

@ -4,7 +4,6 @@ If you are customizing Gitea, please do not change this file.
If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
*/}}
<script>
<!-- /* eslint-disable */ -->
window.addEventListener('error', function(e) {window._globalHandlerErrors=window._globalHandlerErrors||[]; window._globalHandlerErrors.push(e);});
window.config = {
appVer: '{{AppVer}}',

View File

@ -41,11 +41,9 @@
{{end}}
<h4 class="ui top attached header df">
<strong class="f1">{{.locale.Tr "org.people"}}</strong>
{{if .IsOrganizationMember}}
<div class="ui">
<a class="text grey dif ac" href="{{.OrgLink}}/members"><span>{{.Org.NumMembers}}</span> {{svg "octicon-chevron-right"}}</a>
<a class="text grey dif ac" href="{{.OrgLink}}/members"><span>{{.MembersTotal}}</span> {{svg "octicon-chevron-right"}}</a>
</div>
{{end}}
</h4>
<div class="ui attached segment members">
{{$isMember := .IsOrganizationMember}}

View File

@ -340,7 +340,6 @@
{{end}}
<div class="ui divider"></div>
<script>
<!-- /* eslint-disable */ -->
(() => {
const defaultMergeTitle = {{.DefaultMergeMessage}};
const defaultSquashMergeTitle = {{.DefaultSquashMergeMessage}};

View File

@ -17923,6 +17923,10 @@
"type": "boolean",
"x-go-name": "AllowRebaseMerge"
},
"allow_rebase_update": {
"type": "boolean",
"x-go-name": "AllowRebaseUpdate"
},
"allow_squash_merge": {
"type": "boolean",
"x-go-name": "AllowSquash"
@ -17948,6 +17952,10 @@
"type": "string",
"x-go-name": "DefaultBranch"
},
"default_delete_branch_after_merge": {
"type": "boolean",
"x-go-name": "DefaultDeleteBranchAfterMerge"
},
"default_merge_style": {
"type": "string",
"x-go-name": "DefaultMergeStyle"
@ -18689,6 +18697,12 @@
"type": "string",
"x-go-name": "UserName"
},
"login_name": {
"description": "the user's authentication sign-in name.",
"type": "string",
"default": "empty",
"x-go-name": "LoginName"
},
"prohibit_login": {
"description": "Is user login prohibited",
"type": "boolean",

View File

@ -0,0 +1,16 @@
plugins:
- eslint-plugin-vue
extends:
- ../../../.eslintrc.yaml
- plugin:vue/recommended
env:
browser: true
rules:
vue/attributes-order: [0]
vue/component-definition-name-casing: [0]
vue/html-closing-bracket-spacing: [0]
vue/max-attributes-per-line: [0]
vue/one-component-per-file: [0]