mirror of
https://github.com/go-gitea/gitea
synced 2024-12-21 17:27:50 +01:00
Merge branch 'main' into gitlab-comment-reactions
This commit is contained in:
commit
8f74ed3b42
3
.github/workflows/cron-lock.yml
vendored
3
.github/workflows/cron-lock.yml
vendored
@ -19,4 +19,5 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v5
|
- uses: dessant/lock-threads@v5
|
||||||
with:
|
with:
|
||||||
issue-inactive-days: 45
|
issue-inactive-days: 10
|
||||||
|
pr-inactive-days: 7
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,7 +15,7 @@ _test
|
|||||||
|
|
||||||
# MS VSCode
|
# MS VSCode
|
||||||
.vscode
|
.vscode
|
||||||
__debug_bin
|
__debug_bin*
|
||||||
|
|
||||||
*.cgo1.go
|
*.cgo1.go
|
||||||
*.cgo2.c
|
*.cgo2.c
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
- [How to report issues](#how-to-report-issues)
|
- [How to report issues](#how-to-report-issues)
|
||||||
- [Types of issues](#types-of-issues)
|
- [Types of issues](#types-of-issues)
|
||||||
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
|
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
|
||||||
|
- [Issue locking](#issue-locking)
|
||||||
- [Building Gitea](#building-gitea)
|
- [Building Gitea](#building-gitea)
|
||||||
- [Dependencies](#dependencies)
|
- [Dependencies](#dependencies)
|
||||||
- [Backend](#backend)
|
- [Backend](#backend)
|
||||||
@ -103,6 +104,13 @@ the goals for the project and tools.
|
|||||||
|
|
||||||
Pull requests should not be the place for architecture discussions.
|
Pull requests should not be the place for architecture discussions.
|
||||||
|
|
||||||
|
### Issue locking
|
||||||
|
|
||||||
|
Commenting on closed or merged issues/PRs is strongly discouraged.
|
||||||
|
Such comments will likely be overlooked as some maintainers may not view notifications on closed issues, thinking that the item is resolved.
|
||||||
|
As such, commenting on closed/merged issues/PRs may be disabled prior to the scheduled auto-locking if a discussion starts or if unrelated comments are posted.
|
||||||
|
If further discussion is needed, we encourage you to open a new issue instead and we recommend linking to the issue/PR in question for context.
|
||||||
|
|
||||||
## Building Gitea
|
## Building Gitea
|
||||||
|
|
||||||
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
|
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
|
||||||
|
@ -956,6 +956,12 @@ LEVEL = Info
|
|||||||
;GO_GET_CLONE_URL_PROTOCOL = https
|
;GO_GET_CLONE_URL_PROTOCOL = https
|
||||||
;;
|
;;
|
||||||
;; Close issues as long as a commit on any branch marks it as fixed
|
;; Close issues as long as a commit on any branch marks it as fixed
|
||||||
|
;DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false
|
||||||
|
;;
|
||||||
|
;; Allow users to push local repositories to Gitea and have them automatically created for a user or an org
|
||||||
|
;ENABLE_PUSH_CREATE_USER = false
|
||||||
|
;ENABLE_PUSH_CREATE_ORG = false
|
||||||
|
;;
|
||||||
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
|
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
|
||||||
;DISABLED_REPO_UNITS =
|
;DISABLED_REPO_UNITS =
|
||||||
;;
|
;;
|
||||||
@ -1474,8 +1480,9 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
|
;; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
|
||||||
;DEFAULT_EMAIL_NOTIFICATIONS = enabled
|
;DEFAULT_EMAIL_NOTIFICATIONS = enabled
|
||||||
;; Disabled features for users, could be "deletion", more features can be disabled in future
|
;; Disabled features for users, could be "deletion","manage_gpg_keys" more features can be disabled in future
|
||||||
;; - deletion: a user cannot delete their own account
|
;; - deletion: a user cannot delete their own account
|
||||||
|
;; - manage_gpg_keys: a user cannot configure gpg keys
|
||||||
;USER_DISABLED_FEATURES =
|
;USER_DISABLED_FEATURES =
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -518,8 +518,9 @@ And the following unique queues:
|
|||||||
|
|
||||||
- `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**: Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
|
- `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**: Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
|
||||||
- `DISABLE_REGULAR_ORG_CREATION`: **false**: Disallow regular (non-admin) users from creating organizations.
|
- `DISABLE_REGULAR_ORG_CREATION`: **false**: Disallow regular (non-admin) users from creating organizations.
|
||||||
- `USER_DISABLED_FEATURES`: **_empty_** Disabled features for users, could be `deletion` and more features can be added in future.
|
- `USER_DISABLED_FEATURES`: **_empty_** Disabled features for users, could be `deletion`, `manage_gpg_keys` and more features can be added in future.
|
||||||
- `deletion`: User cannot delete their own account.
|
- `deletion`: User cannot delete their own account.
|
||||||
|
- `manage_gpg_keys`: User cannot configure gpg keys
|
||||||
|
|
||||||
## Security (`security`)
|
## Security (`security`)
|
||||||
|
|
||||||
|
@ -497,8 +497,9 @@ Gitea 创建以下非唯一队列:
|
|||||||
|
|
||||||
- `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**:用户电子邮件通知的默认配置(用户可配置)。选项:enabled、onmention、disabled
|
- `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**:用户电子邮件通知的默认配置(用户可配置)。选项:enabled、onmention、disabled
|
||||||
- `DISABLE_REGULAR_ORG_CREATION`: **false**:禁止普通(非管理员)用户创建组织。
|
- `DISABLE_REGULAR_ORG_CREATION`: **false**:禁止普通(非管理员)用户创建组织。
|
||||||
- `USER_DISABLED_FEATURES`:**_empty_** 禁用的用户特性,当前允许为空或者 `deletion`, 未来可以增加更多设置。
|
- `USER_DISABLED_FEATURES`:**_empty_** 禁用的用户特性,当前允许为空或者 `deletion`,`manage_gpg_keys` 未来可以增加更多设置。
|
||||||
- `deletion`: 用户不能通过界面或者API删除他自己。
|
- `deletion`: 用户不能通过界面或者API删除他自己。
|
||||||
|
- `manage_gpg_keys`: 用户不能配置 GPG 密钥
|
||||||
|
|
||||||
## 安全性 (`security`)
|
## 安全性 (`security`)
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ Please check [Gitea's logs](administration/logging-config.md) for error messages
|
|||||||
{{if not (eq .Body "")}}
|
{{if not (eq .Body "")}}
|
||||||
<h3>Message content</h3>
|
<h3>Message content</h3>
|
||||||
<hr>
|
<hr>
|
||||||
{{.Body | Str2html}}
|
{{.Body | SanitizeHTML}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
@ -260,19 +260,19 @@ The template system contains several functions that can be used to further proce
|
|||||||
the messages. Here's a list of some of them:
|
the messages. Here's a list of some of them:
|
||||||
|
|
||||||
| Name | Parameters | Available | Usage |
|
| Name | Parameters | Available | Usage |
|
||||||
| ---------------- | ----------- | --------- | --------------------------------------------------------------------------- |
|
| ---------------- | ----------- | --------- |-----------------------------------------------------------------------------|
|
||||||
| `AppUrl` | - | Any | Gitea's URL |
|
| `AppUrl` | - | Any | Gitea's URL |
|
||||||
| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" |
|
| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" |
|
||||||
| `AppDomain` | - | Any | Gitea's host name |
|
| `AppDomain` | - | Any | Gitea's host name |
|
||||||
| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed |
|
| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed |
|
||||||
| `Str2html` | string | Body only | Sanitizes text by removing any HTML tags from it. |
|
| `SanitizeHTML` | string | Body only | Sanitizes text by removing any dangerous HTML tags from it. |
|
||||||
| `SafeHTML` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. |
|
| `SafeHTML` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. |
|
||||||
|
|
||||||
These are _functions_, not metadata, so they have to be used:
|
These are _functions_, not metadata, so they have to be used:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
Like this: {{Str2html "Escape<my>text"}}
|
Like this: {{SanitizeHTML "Escape<my>text"}}
|
||||||
Or this: {{"Escape<my>text" | Str2html}}
|
Or this: {{"Escape<my>text" | SanitizeHTML}}
|
||||||
Or this: {{AppUrl}}
|
Or this: {{AppUrl}}
|
||||||
But not like this: {{.AppUrl}}
|
But not like this: {{.AppUrl}}
|
||||||
```
|
```
|
||||||
|
@ -207,7 +207,7 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/
|
|||||||
{{if not (eq .Body "")}}
|
{{if not (eq .Body "")}}
|
||||||
<h3>消息内容:</h3>
|
<h3>消息内容:</h3>
|
||||||
<hr>
|
<hr>
|
||||||
{{.Body | Str2html}}
|
{{.Body | SanitizeHTML}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
@ -242,20 +242,20 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/
|
|||||||
|
|
||||||
模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:
|
模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:
|
||||||
|
|
||||||
| 函数名 | 参数 | 可用于 | 用法 |
|
| 函数名 | 参数 | 可用于 | 用法 |
|
||||||
|------------------| ----------- | ------------ | --------------------------------------------------------------------------------- |
|
|------------------| ----------- | ------------ |---------------------------------------------------------|
|
||||||
| `AppUrl` | - | 任何地方 | Gitea 的 URL |
|
| `AppUrl` | - | 任何地方 | Gitea 的 URL |
|
||||||
| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" |
|
| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" |
|
||||||
| `AppDomain` | - | 任何地方 | Gitea 的主机名 |
|
| `AppDomain` | - | 任何地方 | Gitea 的主机名 |
|
||||||
| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 |
|
| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 |
|
||||||
| `Str2html` | string | 仅正文部分 | 通过删除其中的 HTML 标签对文本进行清理 |
|
| `SanitizeHTML` | string | 仅正文部分 | 通过删除其中的危险 HTML 标签对文本进行清理 |
|
||||||
| `SafeHTML` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于 `.ReviewComments.RenderedContent` 等字段 |
|
| `SafeHTML` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于 `.ReviewComments.RenderedContent` 等字段 |
|
||||||
|
|
||||||
这些都是 _函数_,而不是元数据,因此必须按以下方式使用:
|
这些都是 _函数_,而不是元数据,因此必须按以下方式使用:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
像这样使用: {{Str2html "Escape<my>text"}}
|
像这样使用: {{SanitizeHTML "Escape<my>text"}}
|
||||||
或者这样使用: {{"Escape<my>text" | Str2html}}
|
或者这样使用: {{"Escape<my>text" | SanitizeHTML}}
|
||||||
或者这样使用: {{AppUrl}}
|
或者这样使用: {{AppUrl}}
|
||||||
但不要像这样使用: {{.AppUrl}}
|
但不要像这样使用: {{.AppUrl}}
|
||||||
```
|
```
|
||||||
|
@ -221,9 +221,11 @@ Our translations are currently crowd-sourced on our [Crowdin project](https://cr
|
|||||||
|
|
||||||
Whether you want to change a translation or add a new one, it will need to be there as all translations are overwritten in our CI via the Crowdin integration.
|
Whether you want to change a translation or add a new one, it will need to be there as all translations are overwritten in our CI via the Crowdin integration.
|
||||||
|
|
||||||
## Push Hook / Webhook aren't running
|
## Push Hook / Webhook / Actions aren't running
|
||||||
|
|
||||||
If you can push but can't see push activities on the home dashboard, or the push doesn't trigger webhook, there are a few possibilities:
|
If you can push but can't see push activities on the home dashboard, or the push doesn't trigger webhook and Actions workflows, it's likely that the git hooks are not working.
|
||||||
|
|
||||||
|
There are a few possibilities:
|
||||||
|
|
||||||
1. The git hooks are out of sync: run "Resynchronize pre-receive, update and post-receive hooks of all repositories" on the site admin panel
|
1. The git hooks are out of sync: run "Resynchronize pre-receive, update and post-receive hooks of all repositories" on the site admin panel
|
||||||
2. The git repositories (and hooks) are stored on some filesystems (ex: mounted by NAS) which don't support script execution, make sure the filesystem supports `chmod a+x any-script`
|
2. The git repositories (and hooks) are stored on some filesystems (ex: mounted by NAS) which don't support script execution, make sure the filesystem supports `chmod a+x any-script`
|
||||||
|
@ -225,9 +225,11 @@ Gitea还提供了自己的SSH服务器,用于在SSHD不可用时使用。
|
|||||||
|
|
||||||
无论您想要更改翻译还是添加新的翻译,都需要在Crowdin集成中进行,因为所有翻译都会被CI覆盖。
|
无论您想要更改翻译还是添加新的翻译,都需要在Crowdin集成中进行,因为所有翻译都会被CI覆盖。
|
||||||
|
|
||||||
## 推送钩子/ Webhook未运行
|
## 推送钩子/ Webhook / Actions 未运行
|
||||||
|
|
||||||
如果您可以推送但无法在主页仪表板上看到推送活动,或者推送不触发Webhook,有几种可能性:
|
如果您可以推送但无法在主页仪表板上看到推送活动,或者推送不触发 Webhook 和 Actions,可能是 git 钩子不工作而导致的。
|
||||||
|
|
||||||
|
这可能是由于以下原因:
|
||||||
|
|
||||||
1. Git钩子不同步:在站点管理面板上运行“重新同步所有仓库的pre-receive、update和post-receive钩子”
|
1. Git钩子不同步:在站点管理面板上运行“重新同步所有仓库的pre-receive、update和post-receive钩子”
|
||||||
2. Git仓库(和钩子)存储在一些不支持脚本执行的文件系统上(例如由NAS挂载),请确保文件系统支持`chmod a+x any-script`
|
2. Git仓库(和钩子)存储在一些不支持脚本执行的文件系统上(例如由NAS挂载),请确保文件系统支持`chmod a+x any-script`
|
||||||
|
@ -45,25 +45,24 @@ It is technically possible to implement, but we need to discuss whether it is ne
|
|||||||
|
|
||||||
## Where will the runner download scripts when using actions such as `actions/checkout@v4`?
|
## Where will the runner download scripts when using actions such as `actions/checkout@v4`?
|
||||||
|
|
||||||
You may be aware that there are tens of thousands of [marketplace actions](https://github.com/marketplace?type=actions) in GitHub.
|
There are tens of thousands of [actions scripts](https://github.com/marketplace?type=actions) in GitHub, and when you write `uses: actions/checkout@v4`, it downloads the scripts from [github.com/actions/checkout](http://github.com/actions/checkout) by default.
|
||||||
However, when you write `uses: actions/checkout@v4`, it actually downloads the scripts from [gitea.com/actions/checkout](http://gitea.com/actions/checkout) by default (not GitHub).
|
But what if you want to use actions from other places such as gitea.com instead of GitHub?
|
||||||
This is a mirror of [github.com/actions/checkout](http://github.com/actions/checkout), but it's impossible to mirror all of them.
|
|
||||||
That's why you may encounter failures when trying to use some actions that haven't been mirrored.
|
|
||||||
|
|
||||||
The good news is that you can specify the URL prefix to use actions from anywhere.
|
The good news is that you can specify the URL prefix to use actions from anywhere.
|
||||||
This is an extra syntax in Gitea Actions.
|
This is an extra syntax in Gitea Actions.
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
- `uses: https://github.com/xxx/xxx@xxx`
|
|
||||||
- `uses: https://gitea.com/xxx/xxx@xxx`
|
- `uses: https://gitea.com/xxx/xxx@xxx`
|
||||||
|
- `uses: https://github.com/xxx/xxx@xxx`
|
||||||
- `uses: http://your_gitea_instance.com/xxx@xxx`
|
- `uses: http://your_gitea_instance.com/xxx@xxx`
|
||||||
|
|
||||||
Be careful, the `https://` or `http://` prefix is necessary!
|
Be careful, the `https://` or `http://` prefix is necessary!
|
||||||
|
|
||||||
Alternatively, if you want your runners to download actions from GitHub or your own Gitea instance by default, you can configure it by setting `[actions].DEFAULT_ACTIONS_URL`.
|
This is one of the differences from GitHub Actions which supports actions scripts only from GitHub.
|
||||||
See [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions).
|
But it should allow users much more flexibility in how they run Actions.
|
||||||
|
|
||||||
This is one of the differences from GitHub Actions, but it should allow users much more flexibility in how they run Actions.
|
Alternatively, if you want your runners to download actions from your own Gitea instance by default, you can configure it by setting `[actions].DEFAULT_ACTIONS_URL`.
|
||||||
|
See [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions).
|
||||||
|
|
||||||
## How to limit the permission of the runners?
|
## How to limit the permission of the runners?
|
||||||
|
|
||||||
|
@ -45,25 +45,25 @@ DEFAULT_REPO_UNITS = ...,repo.actions
|
|||||||
|
|
||||||
## 使用`actions/checkout@v4`等Actions时,Job容器会从何处下载脚本?
|
## 使用`actions/checkout@v4`等Actions时,Job容器会从何处下载脚本?
|
||||||
|
|
||||||
您可能知道GitHub上有成千上万个[Actions市场](https://github.com/marketplace?type=actions)。
|
GitHub 上有成千上万个 [Actions 脚本](https://github.com/marketplace?type=actions)。
|
||||||
然而,当您编写`uses: actions/checkout@v4`时,它实际上默认从[gitea.com/actions/checkout](http://gitea.com/actions/checkout)下载脚本(而不是从GitHub下载)。
|
当您编写 `uses: actions/checkout@v4` 时,它默认会从 [github.com/actions/checkout](https://github.com/actions/checkout) 下载脚本。
|
||||||
这是[github.com/actions/checkout](http://github.com/actions/checkout)的镜像,但无法将它们全部镜像。
|
那如果您想使用一些托管在其它平台上的脚本呢,比如在 gitea.com 上的?
|
||||||
这就是为什么在尝试使用尚未镜像的某些Actions时可能会遇到失败的原因。
|
|
||||||
|
|
||||||
好消息是,您可以指定要从任何位置使用Actions的URL前缀。
|
好消息是,您可以指定要从任何位置使用Actions的URL前缀。
|
||||||
这是Gitea Actions中的额外语法。
|
这是Gitea Actions中的额外语法。
|
||||||
例如:
|
例如:
|
||||||
|
|
||||||
- `uses: https://github.com/xxx/xxx@xxx`
|
|
||||||
- `uses: https://gitea.com/xxx/xxx@xxx`
|
- `uses: https://gitea.com/xxx/xxx@xxx`
|
||||||
|
- `uses: https://github.com/xxx/xxx@xxx`
|
||||||
- `uses: http://your_gitea_instance.com/xxx@xxx`
|
- `uses: http://your_gitea_instance.com/xxx@xxx`
|
||||||
|
|
||||||
注意,`https://`或`http://`前缀是必需的!
|
注意,`https://`或`http://`前缀是必需的!
|
||||||
|
|
||||||
另外,如果您希望您的Runner默认从GitHub或您自己的Gitea实例下载Actions,可以通过设置 `[actions].DEFAULT_ACTIONS_URL`进行配置。
|
这是与 GitHub Actions 的一个区别,GitHub Actions 只允许使用托管在 GitHub 上的 actions 脚本。
|
||||||
参见[配置速查表](administration/config-cheat-sheet.md#actions-actions)。
|
但用户理应拥有权利去灵活决定如何运行 Actions。
|
||||||
|
|
||||||
这是与GitHub Actions的一个区别,但它应该允许用户以更灵活的方式运行Actions。
|
另外,如果您希望您的 Runner 默认从您自己的 Gitea 实例下载 Actions,可以通过设置 `[actions].DEFAULT_ACTIONS_URL`进行配置。
|
||||||
|
参见[配置速查表](administration/config-cheat-sheet.md#actions-actions)。
|
||||||
|
|
||||||
## 如何限制Runner的权限?
|
## 如何限制Runner的权限?
|
||||||
|
|
||||||
|
37
docs/content/usage/badge.en-us.md
Normal file
37
docs/content/usage/badge.en-us.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
date: "2023-02-25T00:00:00+00:00"
|
||||||
|
title: "Badge"
|
||||||
|
slug: "badge"
|
||||||
|
sidebar_position: 11
|
||||||
|
toc: false
|
||||||
|
draft: false
|
||||||
|
aliases:
|
||||||
|
- /en-us/badge
|
||||||
|
menu:
|
||||||
|
sidebar:
|
||||||
|
parent: "usage"
|
||||||
|
name: "Badge"
|
||||||
|
sidebar_position: 11
|
||||||
|
identifier: "Badge"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Badge
|
||||||
|
|
||||||
|
Gitea has its builtin Badge system which allows you to display the status of your repository in other places. You can use the following badges:
|
||||||
|
|
||||||
|
## Workflow Badge
|
||||||
|
|
||||||
|
The Gitea Actions workflow badge is a badge that shows the status of the latest workflow run.
|
||||||
|
It is designed to be compatible with [GitHub Actions workflow badge](https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/adding-a-workflow-status-badge).
|
||||||
|
|
||||||
|
You can use the following URL to get the badge:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://your-gitea-instance.com/{owner}/{repo}/actions/workflows/{workflow_file}?branch={branch}&event={event}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `{owner}`: The owner of the repository.
|
||||||
|
- `{repo}`: The name of the repository.
|
||||||
|
- `{workflow_file}`: The name of the workflow file.
|
||||||
|
- `{branch}`: Optional. The branch of the workflow. Default to your repository's default branch.
|
||||||
|
- `{event}`: Optional. The event of the workflow. Default to none.
|
@ -339,6 +339,23 @@ func GetRunByIndex(ctx context.Context, repoID, index int64) (*ActionRun, error)
|
|||||||
return run, nil
|
return run, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetWorkflowLatestRun(ctx context.Context, repoID int64, workflowFile, branch, event string) (*ActionRun, error) {
|
||||||
|
var run ActionRun
|
||||||
|
q := db.GetEngine(ctx).Where("repo_id=?", repoID).
|
||||||
|
And("ref = ?", branch).
|
||||||
|
And("workflow_id = ?", workflowFile)
|
||||||
|
if event != "" {
|
||||||
|
q.And("event = ?", event)
|
||||||
|
}
|
||||||
|
has, err := q.Desc("id").Get(&run)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, util.NewNotExistErrorf("run with repo_id %d, ref %s, workflow_id %s", repoID, branch, workflowFile)
|
||||||
|
}
|
||||||
|
return &run, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateRun updates a run.
|
// UpdateRun updates a run.
|
||||||
// It requires the inputted run has Version set.
|
// It requires the inputted run has Version set.
|
||||||
// It will return error if the version is not matched (it means the run has been changed after loaded).
|
// It will return error if the version is not matched (it means the run has been changed after loaded).
|
||||||
|
@ -8,6 +8,7 @@ package issues
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"strconv"
|
"strconv"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@ -259,8 +260,8 @@ type Comment struct {
|
|||||||
CommitID int64
|
CommitID int64
|
||||||
Line int64 // - previous line / + proposed line
|
Line int64 // - previous line / + proposed line
|
||||||
TreePath string
|
TreePath string
|
||||||
Content string `xorm:"LONGTEXT"`
|
Content string `xorm:"LONGTEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent template.HTML `xorm:"-"`
|
||||||
|
|
||||||
// Path represents the 4 lines of code cemented by this comment
|
// Path represents the 4 lines of code cemented by this comment
|
||||||
Patch string `xorm:"-"`
|
Patch string `xorm:"-"`
|
||||||
|
@ -172,13 +172,9 @@ func FetchIssueContentHistoryList(dbCtx context.Context, issueID, commentID int6
|
|||||||
|
|
||||||
// HasIssueContentHistory check if a ContentHistory entry exists
|
// HasIssueContentHistory check if a ContentHistory entry exists
|
||||||
func HasIssueContentHistory(dbCtx context.Context, issueID, commentID int64) (bool, error) {
|
func HasIssueContentHistory(dbCtx context.Context, issueID, commentID int64) (bool, error) {
|
||||||
exists, err := db.GetEngine(dbCtx).Cols("id").Exist(&ContentHistory{
|
exists, err := db.GetEngine(dbCtx).Where(builder.Eq{"issue_id": issueID, "comment_id": commentID}).Exist(&ContentHistory{})
|
||||||
IssueID: issueID,
|
|
||||||
CommentID: commentID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("can not fetch issue content history. err=%v", err)
|
return false, fmt.Errorf("can not check issue content history. err: %w", err)
|
||||||
return false, err
|
|
||||||
}
|
}
|
||||||
return exists, err
|
return exists, err
|
||||||
}
|
}
|
||||||
|
@ -78,3 +78,22 @@ func TestContentHistory(t *testing.T) {
|
|||||||
assert.EqualValues(t, 7, list2[1].HistoryID)
|
assert.EqualValues(t, 7, list2[1].HistoryID)
|
||||||
assert.EqualValues(t, 4, list2[2].HistoryID)
|
assert.EqualValues(t, 4, list2[2].HistoryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHasIssueContentHistoryForCommentOnly(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
_ = db.TruncateBeans(db.DefaultContext, &issues_model.ContentHistory{})
|
||||||
|
|
||||||
|
hasHistory1, _ := issues_model.HasIssueContentHistory(db.DefaultContext, 10, 0)
|
||||||
|
assert.False(t, hasHistory1)
|
||||||
|
hasHistory2, _ := issues_model.HasIssueContentHistory(db.DefaultContext, 10, 100)
|
||||||
|
assert.False(t, hasHistory2)
|
||||||
|
|
||||||
|
_ = issues_model.SaveIssueContentHistory(db.DefaultContext, 1, 10, 100, timeutil.TimeStampNow(), "c-a", true)
|
||||||
|
_ = issues_model.SaveIssueContentHistory(db.DefaultContext, 1, 10, 100, timeutil.TimeStampNow().Add(5), "c-b", false)
|
||||||
|
|
||||||
|
hasHistory1, _ = issues_model.HasIssueContentHistory(db.DefaultContext, 10, 0)
|
||||||
|
assert.False(t, hasHistory1)
|
||||||
|
hasHistory2, _ = issues_model.HasIssueContentHistory(db.DefaultContext, 10, 100)
|
||||||
|
assert.True(t, hasHistory2)
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ package issues
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
@ -105,7 +106,7 @@ type Issue struct {
|
|||||||
OriginalAuthorID int64 `xorm:"index"`
|
OriginalAuthorID int64 `xorm:"index"`
|
||||||
Title string `xorm:"name"`
|
Title string `xorm:"name"`
|
||||||
Content string `xorm:"LONGTEXT"`
|
Content string `xorm:"LONGTEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent template.HTML `xorm:"-"`
|
||||||
Labels []*Label `xorm:"-"`
|
Labels []*Label `xorm:"-"`
|
||||||
MilestoneID int64 `xorm:"INDEX"`
|
MilestoneID int64 `xorm:"INDEX"`
|
||||||
Milestone *Milestone `xorm:"-"`
|
Milestone *Milestone `xorm:"-"`
|
||||||
|
@ -6,6 +6,7 @@ package issues
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -47,8 +48,8 @@ type Milestone struct {
|
|||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `xorm:"INDEX"`
|
||||||
Repo *repo_model.Repository `xorm:"-"`
|
Repo *repo_model.Repository `xorm:"-"`
|
||||||
Name string
|
Name string
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent template.HTML `xorm:"-"`
|
||||||
IsClosed bool
|
IsClosed bool
|
||||||
NumIssues int
|
NumIssues int
|
||||||
NumClosedIssues int
|
NumClosedIssues int
|
||||||
|
@ -558,6 +558,8 @@ var migrations = []Migration{
|
|||||||
NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
|
NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
|
||||||
// v286 -> v287
|
// v286 -> v287
|
||||||
NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
|
NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
|
||||||
|
// v287 -> v288
|
||||||
|
NewMigration("Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
46
models/migrations/v1_22/v287.go
Normal file
46
models/migrations/v1_22/v287.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BadgeUnique struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
Slug string `xorm:"UNIQUE"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (BadgeUnique) TableName() string {
|
||||||
|
return "badge"
|
||||||
|
}
|
||||||
|
|
||||||
|
func UseSlugInsteadOfIDForBadges(x *xorm.Engine) error {
|
||||||
|
type Badge struct {
|
||||||
|
Slug string
|
||||||
|
}
|
||||||
|
|
||||||
|
err := x.Sync(new(Badge))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = sess.Exec("UPDATE `badge` SET `slug` = `id` Where `slug` IS NULL")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sess.Sync(new(BadgeUnique))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
57
models/migrations/v1_22/v287_test.go
Normal file
57
models/migrations/v1_22/v287_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/migrations/base"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_UpdateBadgeColName(t *testing.T) {
|
||||||
|
type Badge struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
Description string
|
||||||
|
ImageURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare and load the testing database
|
||||||
|
x, deferable := base.PrepareTestEnv(t, 0, new(BadgeUnique), new(Badge))
|
||||||
|
defer deferable()
|
||||||
|
if x == nil || t.Failed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oldBadges := []Badge{
|
||||||
|
{ID: 1, Description: "Test Badge 1", ImageURL: "https://example.com/badge1.png"},
|
||||||
|
{ID: 2, Description: "Test Badge 2", ImageURL: "https://example.com/badge2.png"},
|
||||||
|
{ID: 3, Description: "Test Badge 3", ImageURL: "https://example.com/badge3.png"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, badge := range oldBadges {
|
||||||
|
_, err := x.Insert(&badge)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := UseSlugInsteadOfIDForBadges(x); err != nil {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []BadgeUnique{}
|
||||||
|
if err := x.Table("badge").Asc("id").Find(&got); !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := range oldBadges {
|
||||||
|
got := got[i]
|
||||||
|
assert.Equal(t, e.ID, got.ID)
|
||||||
|
assert.Equal(t, fmt.Sprintf("%d", e.ID), got.Slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if badges have been updated
|
||||||
|
}
|
@ -6,6 +6,7 @@ package project
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
@ -100,7 +101,7 @@ type Project struct {
|
|||||||
CardType CardType
|
CardType CardType
|
||||||
Type Type
|
Type Type
|
||||||
|
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent template.HTML `xorm:"-"`
|
||||||
|
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
|
@ -7,6 +7,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -15,6 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -79,7 +81,7 @@ type Release struct {
|
|||||||
NumCommits int64
|
NumCommits int64
|
||||||
NumCommitsBehind int64 `xorm:"-"`
|
NumCommitsBehind int64 `xorm:"-"`
|
||||||
Note string `xorm:"TEXT"`
|
Note string `xorm:"TEXT"`
|
||||||
RenderedNote string `xorm:"-"`
|
RenderedNote template.HTML `xorm:"-"`
|
||||||
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
|
IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
|
||||||
@ -228,10 +230,10 @@ type FindReleasesOptions struct {
|
|||||||
RepoID int64
|
RepoID int64
|
||||||
IncludeDrafts bool
|
IncludeDrafts bool
|
||||||
IncludeTags bool
|
IncludeTags bool
|
||||||
IsPreRelease util.OptionalBool
|
IsPreRelease optional.Option[bool]
|
||||||
IsDraft util.OptionalBool
|
IsDraft optional.Option[bool]
|
||||||
TagNames []string
|
TagNames []string
|
||||||
HasSha1 util.OptionalBool // useful to find draft releases which are created with existing tags
|
HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts FindReleasesOptions) ToConds() builder.Cond {
|
func (opts FindReleasesOptions) ToConds() builder.Cond {
|
||||||
@ -246,14 +248,14 @@ func (opts FindReleasesOptions) ToConds() builder.Cond {
|
|||||||
if len(opts.TagNames) > 0 {
|
if len(opts.TagNames) > 0 {
|
||||||
cond = cond.And(builder.In("tag_name", opts.TagNames))
|
cond = cond.And(builder.In("tag_name", opts.TagNames))
|
||||||
}
|
}
|
||||||
if !opts.IsPreRelease.IsNone() {
|
if opts.IsPreRelease.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_prerelease": opts.IsPreRelease.IsTrue()})
|
cond = cond.And(builder.Eq{"is_prerelease": opts.IsPreRelease.Value()})
|
||||||
}
|
}
|
||||||
if !opts.IsDraft.IsNone() {
|
if opts.IsDraft.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
|
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.Value()})
|
||||||
}
|
}
|
||||||
if !opts.HasSha1.IsNone() {
|
if opts.HasSha1.Has() {
|
||||||
if opts.HasSha1.IsTrue() {
|
if opts.HasSha1.Value() {
|
||||||
cond = cond.And(builder.Neq{"sha1": ""})
|
cond = cond.And(builder.Neq{"sha1": ""})
|
||||||
} else {
|
} else {
|
||||||
cond = cond.And(builder.Eq{"sha1": ""})
|
cond = cond.And(builder.Eq{"sha1": ""})
|
||||||
@ -275,7 +277,7 @@ func GetTagNamesByRepoID(ctx context.Context, repoID int64) ([]string, error) {
|
|||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
IncludeDrafts: true,
|
IncludeDrafts: true,
|
||||||
IncludeTags: true,
|
IncludeTags: true,
|
||||||
HasSha1: util.OptionalBoolTrue,
|
HasSha1: optional.Some(true),
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -125,11 +126,11 @@ type SearchRepoOptions struct {
|
|||||||
// None -> include public and private
|
// None -> include public and private
|
||||||
// True -> include just private
|
// True -> include just private
|
||||||
// False -> include just public
|
// False -> include just public
|
||||||
IsPrivate util.OptionalBool
|
IsPrivate optional.Option[bool]
|
||||||
// None -> include collaborative AND non-collaborative
|
// None -> include collaborative AND non-collaborative
|
||||||
// True -> include just collaborative
|
// True -> include just collaborative
|
||||||
// False -> include just non-collaborative
|
// False -> include just non-collaborative
|
||||||
Collaborate util.OptionalBool
|
Collaborate optional.Option[bool]
|
||||||
// What type of unit the user can be collaborative in,
|
// What type of unit the user can be collaborative in,
|
||||||
// it is ignored if Collaborate is False.
|
// it is ignored if Collaborate is False.
|
||||||
// TypeInvalid means any unit type.
|
// TypeInvalid means any unit type.
|
||||||
@ -137,19 +138,19 @@ type SearchRepoOptions struct {
|
|||||||
// None -> include forks AND non-forks
|
// None -> include forks AND non-forks
|
||||||
// True -> include just forks
|
// True -> include just forks
|
||||||
// False -> include just non-forks
|
// False -> include just non-forks
|
||||||
Fork util.OptionalBool
|
Fork optional.Option[bool]
|
||||||
// None -> include templates AND non-templates
|
// None -> include templates AND non-templates
|
||||||
// True -> include just templates
|
// True -> include just templates
|
||||||
// False -> include just non-templates
|
// False -> include just non-templates
|
||||||
Template util.OptionalBool
|
Template optional.Option[bool]
|
||||||
// None -> include mirrors AND non-mirrors
|
// None -> include mirrors AND non-mirrors
|
||||||
// True -> include just mirrors
|
// True -> include just mirrors
|
||||||
// False -> include just non-mirrors
|
// False -> include just non-mirrors
|
||||||
Mirror util.OptionalBool
|
Mirror optional.Option[bool]
|
||||||
// None -> include archived AND non-archived
|
// None -> include archived AND non-archived
|
||||||
// True -> include just archived
|
// True -> include just archived
|
||||||
// False -> include just non-archived
|
// False -> include just non-archived
|
||||||
Archived util.OptionalBool
|
Archived optional.Option[bool]
|
||||||
// only search topic name
|
// only search topic name
|
||||||
TopicOnly bool
|
TopicOnly bool
|
||||||
// only search repositories with specified primary language
|
// only search repositories with specified primary language
|
||||||
@ -159,7 +160,7 @@ type SearchRepoOptions struct {
|
|||||||
// None -> include has milestones AND has no milestone
|
// None -> include has milestones AND has no milestone
|
||||||
// True -> include just has milestones
|
// True -> include just has milestones
|
||||||
// False -> include just has no milestone
|
// False -> include just has no milestone
|
||||||
HasMilestones util.OptionalBool
|
HasMilestones optional.Option[bool]
|
||||||
// LowerNames represents valid lower names to restrict to
|
// LowerNames represents valid lower names to restrict to
|
||||||
LowerNames []string
|
LowerNames []string
|
||||||
// When specified true, apply some filters over the conditions:
|
// When specified true, apply some filters over the conditions:
|
||||||
@ -359,12 +360,12 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.IsPrivate != util.OptionalBoolNone {
|
if opts.IsPrivate.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()})
|
cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Template != util.OptionalBoolNone {
|
if opts.Template.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_template": opts.Template == util.OptionalBoolTrue})
|
cond = cond.And(builder.Eq{"is_template": opts.Template.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restrict to starred repositories
|
// Restrict to starred repositories
|
||||||
@ -380,11 +381,11 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
|||||||
// Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate
|
// Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate
|
||||||
if opts.OwnerID > 0 {
|
if opts.OwnerID > 0 {
|
||||||
accessCond := builder.NewCond()
|
accessCond := builder.NewCond()
|
||||||
if opts.Collaborate != util.OptionalBoolTrue {
|
if !opts.Collaborate.Value() {
|
||||||
accessCond = builder.Eq{"owner_id": opts.OwnerID}
|
accessCond = builder.Eq{"owner_id": opts.OwnerID}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Collaborate != util.OptionalBoolFalse {
|
if opts.Collaborate.ValueOrDefault(true) {
|
||||||
// A Collaboration is:
|
// A Collaboration is:
|
||||||
|
|
||||||
collaborateCond := builder.NewCond()
|
collaborateCond := builder.NewCond()
|
||||||
@ -472,31 +473,32 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
|||||||
Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true})))
|
Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true})))
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Fork != util.OptionalBoolNone || opts.OnlyShowRelevant {
|
if opts.Fork.Has() || opts.OnlyShowRelevant {
|
||||||
if opts.OnlyShowRelevant && opts.Fork == util.OptionalBoolNone {
|
if opts.OnlyShowRelevant && !opts.Fork.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_fork": false})
|
cond = cond.And(builder.Eq{"is_fork": false})
|
||||||
} else {
|
} else {
|
||||||
cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue})
|
cond = cond.And(builder.Eq{"is_fork": opts.Fork.Value()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Mirror != util.OptionalBoolNone {
|
if opts.Mirror.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue})
|
cond = cond.And(builder.Eq{"is_mirror": opts.Mirror.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Actor != nil && opts.Actor.IsRestricted {
|
if opts.Actor != nil && opts.Actor.IsRestricted {
|
||||||
cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid))
|
cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid))
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Archived != util.OptionalBoolNone {
|
if opts.Archived.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_archived": opts.Archived == util.OptionalBoolTrue})
|
cond = cond.And(builder.Eq{"is_archived": opts.Archived.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
switch opts.HasMilestones {
|
if opts.HasMilestones.Has() {
|
||||||
case util.OptionalBoolTrue:
|
if opts.HasMilestones.Value() {
|
||||||
cond = cond.And(builder.Gt{"num_milestones": 0})
|
cond = cond.And(builder.Gt{"num_milestones": 0})
|
||||||
case util.OptionalBoolFalse:
|
} else {
|
||||||
cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"}))
|
cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.OnlyShowRelevant {
|
if opts.OnlyShowRelevant {
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -27,62 +27,62 @@ func getTestCases() []struct {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "PublicRepositoriesByName",
|
name: "PublicRepositoriesByName",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: optional.Some(false)},
|
||||||
count: 7,
|
count: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesByName",
|
name: "PublicAndPrivateRepositoriesByName",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 14,
|
count: 14,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage",
|
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 14,
|
count: 14,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage",
|
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 14,
|
count: 14,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage",
|
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 14,
|
count: 14,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage",
|
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 14,
|
count: 14,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicRepositoriesOfUser",
|
name: "PublicRepositoriesOfUser",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: optional.Some(false)},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicRepositoriesOfUser2",
|
name: "PublicRepositoriesOfUser2",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: optional.Some(false)},
|
||||||
count: 0,
|
count: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicRepositoriesOfOrg3",
|
name: "PublicRepositoriesOfOrg3",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: optional.Some(false)},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesOfUser",
|
name: "PublicAndPrivateRepositoriesOfUser",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 4,
|
count: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesOfUser2",
|
name: "PublicAndPrivateRepositoriesOfUser2",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 0,
|
count: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesOfOrg3",
|
name: "PublicAndPrivateRepositoriesOfOrg3",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 4,
|
count: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -117,32 +117,32 @@ func getTestCases() []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicRepositoriesOfOrganization",
|
name: "PublicRepositoriesOfOrganization",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: optional.Some(false)},
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PublicAndPrivateRepositoriesOfOrganization",
|
name: "PublicAndPrivateRepositoriesOfOrganization",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: optional.Some(false)},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AllPublic/PublicRepositoriesByName",
|
name: "AllPublic/PublicRepositoriesByName",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: optional.Some(false)},
|
||||||
count: 7,
|
count: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AllPublic/PublicAndPrivateRepositoriesByName",
|
name: "AllPublic/PublicAndPrivateRepositoriesByName",
|
||||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: optional.Some(false)},
|
||||||
count: 14,
|
count: 14,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: optional.Some(false)},
|
||||||
count: 33,
|
count: 33,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: optional.Some(false)},
|
||||||
count: 38,
|
count: 38,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -157,12 +157,12 @@ func getTestCases() []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AllPublic/PublicRepositoriesOfOrganization",
|
name: "AllPublic/PublicRepositoriesOfOrganization",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: optional.Some(false), Template: optional.Some(false)},
|
||||||
count: 33,
|
count: 33,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AllTemplates",
|
name: "AllTemplates",
|
||||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue},
|
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: optional.Some(true)},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -190,7 +190,7 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
PageSize: 10,
|
PageSize: 10,
|
||||||
},
|
},
|
||||||
Keyword: "repo_12",
|
Keyword: "repo_12",
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -205,7 +205,7 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
PageSize: 10,
|
PageSize: 10,
|
||||||
},
|
},
|
||||||
Keyword: "test_repo",
|
Keyword: "test_repo",
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -220,7 +220,7 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Keyword: "repo_13",
|
Keyword: "repo_13",
|
||||||
Private: true,
|
Private: true,
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -236,7 +236,7 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Keyword: "test_repo",
|
Keyword: "test_repo",
|
||||||
Private: true,
|
Private: true,
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -257,7 +257,7 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
PageSize: 10,
|
PageSize: 10,
|
||||||
},
|
},
|
||||||
Keyword: "description_14",
|
Keyword: "description_14",
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
IncludeDescription: true,
|
IncludeDescription: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
PageSize: 10,
|
PageSize: 10,
|
||||||
},
|
},
|
||||||
Keyword: "description_14",
|
Keyword: "description_14",
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
IncludeDescription: false,
|
IncludeDescription: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -327,30 +327,25 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
assert.False(t, repo.IsPrivate)
|
assert.False(t, repo.IsPrivate)
|
||||||
}
|
}
|
||||||
|
|
||||||
if testCase.opts.Fork == util.OptionalBoolTrue && testCase.opts.Mirror == util.OptionalBoolTrue {
|
if testCase.opts.Fork.Value() && testCase.opts.Mirror.Value() {
|
||||||
assert.True(t, repo.IsFork || repo.IsMirror)
|
assert.True(t, repo.IsFork && repo.IsMirror)
|
||||||
} else {
|
} else {
|
||||||
switch testCase.opts.Fork {
|
if testCase.opts.Fork.Has() {
|
||||||
case util.OptionalBoolFalse:
|
assert.Equal(t, testCase.opts.Fork.Value(), repo.IsFork)
|
||||||
assert.False(t, repo.IsFork)
|
|
||||||
case util.OptionalBoolTrue:
|
|
||||||
assert.True(t, repo.IsFork)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch testCase.opts.Mirror {
|
if testCase.opts.Mirror.Has() {
|
||||||
case util.OptionalBoolFalse:
|
assert.Equal(t, testCase.opts.Mirror.Value(), repo.IsMirror)
|
||||||
assert.False(t, repo.IsMirror)
|
|
||||||
case util.OptionalBoolTrue:
|
|
||||||
assert.True(t, repo.IsMirror)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if testCase.opts.OwnerID > 0 && !testCase.opts.AllPublic {
|
if testCase.opts.OwnerID > 0 && !testCase.opts.AllPublic {
|
||||||
switch testCase.opts.Collaborate {
|
if testCase.opts.Collaborate.Has() {
|
||||||
case util.OptionalBoolFalse:
|
if testCase.opts.Collaborate.Value() {
|
||||||
assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID)
|
assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID)
|
||||||
case util.OptionalBoolTrue:
|
} else {
|
||||||
assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID)
|
assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,15 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Badge represents a user badge
|
// Badge represents a user badge
|
||||||
type Badge struct {
|
type Badge struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
Slug string `xorm:"UNIQUE"`
|
||||||
Description string
|
Description string
|
||||||
ImageURL string
|
ImageURL string
|
||||||
}
|
}
|
||||||
@ -39,3 +41,84 @@ func GetUserBadges(ctx context.Context, u *User) ([]*Badge, int64, error) {
|
|||||||
count, err := sess.FindAndCount(&badges)
|
count, err := sess.FindAndCount(&badges)
|
||||||
return badges, count, err
|
return badges, count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateBadge creates a new badge.
|
||||||
|
func CreateBadge(ctx context.Context, badge *Badge) error {
|
||||||
|
_, err := db.GetEngine(ctx).Insert(badge)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBadge returns a badge
|
||||||
|
func GetBadge(ctx context.Context, slug string) (*Badge, error) {
|
||||||
|
badge := new(Badge)
|
||||||
|
has, err := db.GetEngine(ctx).Where("slug=?", slug).Get(badge)
|
||||||
|
if !has {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return badge, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateBadge updates a badge based on its slug.
|
||||||
|
func UpdateBadge(ctx context.Context, badge *Badge) error {
|
||||||
|
_, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Update(badge)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBadge deletes a badge.
|
||||||
|
func DeleteBadge(ctx context.Context, badge *Badge) error {
|
||||||
|
_, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Delete(badge)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUserBadge adds a badge to a user.
|
||||||
|
func AddUserBadge(ctx context.Context, u *User, badge *Badge) error {
|
||||||
|
return AddUserBadges(ctx, u, []*Badge{badge})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUserBadges adds badges to a user.
|
||||||
|
func AddUserBadges(ctx context.Context, u *User, badges []*Badge) error {
|
||||||
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
for _, badge := range badges {
|
||||||
|
// hydrate badge and check if it exists
|
||||||
|
has, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Get(badge)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
|
return fmt.Errorf("badge with slug %s doesn't exist", badge.Slug)
|
||||||
|
}
|
||||||
|
if err := db.Insert(ctx, &UserBadge{
|
||||||
|
BadgeID: badge.ID,
|
||||||
|
UserID: u.ID,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveUserBadge removes a badge from a user.
|
||||||
|
func RemoveUserBadge(ctx context.Context, u *User, badge *Badge) error {
|
||||||
|
return RemoveUserBadges(ctx, u, []*Badge{badge})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveUserBadges removes badges from a user.
|
||||||
|
func RemoveUserBadges(ctx context.Context, u *User, badges []*Badge) error {
|
||||||
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
for _, badge := range badges {
|
||||||
|
if _, err := db.GetEngine(ctx).
|
||||||
|
Join("INNER", "badge", "badge.id = `user_badge`.badge_id").
|
||||||
|
Where("`user_badge`.user_id=? AND `badge`.slug=?", u.ID, badge.Slug).
|
||||||
|
Delete(&UserBadge{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAllUserBadges removes all badges from a user.
|
||||||
|
func RemoveAllUserBadges(ctx context.Context, u *User) error {
|
||||||
|
_, err := db.GetEngine(ctx).Where("user_id=?", u.ID).Delete(&UserBadge{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/validation"
|
"code.gitea.io/gitea/modules/validation"
|
||||||
@ -21,9 +22,6 @@ import (
|
|||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrEmailNotActivated e-mail address has not been activated error
|
|
||||||
var ErrEmailNotActivated = util.NewInvalidArgumentErrorf("e-mail address has not been activated")
|
|
||||||
|
|
||||||
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
|
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
|
||||||
type ErrEmailCharIsNotSupported struct {
|
type ErrEmailCharIsNotSupported struct {
|
||||||
Email string
|
Email string
|
||||||
@ -313,27 +311,27 @@ func updateActivation(ctx context.Context, email *EmailAddress, activate bool) e
|
|||||||
return UpdateUserCols(ctx, user, "rands")
|
return UpdateUserCols(ctx, user, "rands")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeEmailPrimary sets primary email address of given user.
|
func MakeActiveEmailPrimary(ctx context.Context, emailID int64) error {
|
||||||
func MakeEmailPrimary(ctx context.Context, email *EmailAddress) error {
|
return makeEmailPrimaryInternal(ctx, emailID, true)
|
||||||
has, err := db.GetEngine(ctx).Get(email)
|
}
|
||||||
if err != nil {
|
|
||||||
|
func MakeInactiveEmailPrimary(ctx context.Context, emailID int64) error {
|
||||||
|
return makeEmailPrimaryInternal(ctx, emailID, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeEmailPrimaryInternal(ctx context.Context, emailID int64, isActive bool) error {
|
||||||
|
email := &EmailAddress{}
|
||||||
|
if has, err := db.GetEngine(ctx).ID(emailID).Where(builder.Eq{"is_activated": isActive}).Get(email); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return ErrEmailAddressNotExist{Email: email.Email}
|
return ErrEmailAddressNotExist{}
|
||||||
}
|
|
||||||
|
|
||||||
if !email.IsActivated {
|
|
||||||
return ErrEmailNotActivated
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user := &User{}
|
user := &User{}
|
||||||
has, err = db.GetEngine(ctx).ID(email.UID).Get(user)
|
if has, err := db.GetEngine(ctx).ID(email.UID).Get(user); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return ErrUserNotExist{
|
return ErrUserNotExist{UID: email.UID}
|
||||||
UID: email.UID,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
@ -365,6 +363,21 @@ func MakeEmailPrimary(ctx context.Context, email *EmailAddress) error {
|
|||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeInactivePrimaryEmail replaces the inactive primary email of a given user
|
||||||
|
func ChangeInactivePrimaryEmail(ctx context.Context, uid int64, oldEmailAddr, newEmailAddr string) error {
|
||||||
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
_, err := db.GetEngine(ctx).Where(builder.Eq{"uid": uid, "lower_email": strings.ToLower(oldEmailAddr)}).Delete(&EmailAddress{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newEmail, err := InsertEmailAddress(ctx, &EmailAddress{UID: uid, Email: newEmailAddr})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return MakeInactiveEmailPrimary(ctx, newEmail.ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyActiveEmailCode verifies active email code when active account
|
// VerifyActiveEmailCode verifies active email code when active account
|
||||||
func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress {
|
func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress {
|
||||||
minutes := setting.Service.ActiveCodeLives
|
minutes := setting.Service.ActiveCodeLives
|
||||||
@ -404,8 +417,8 @@ type SearchEmailOptions struct {
|
|||||||
db.ListOptions
|
db.ListOptions
|
||||||
Keyword string
|
Keyword string
|
||||||
SortType SearchEmailOrderBy
|
SortType SearchEmailOrderBy
|
||||||
IsPrimary util.OptionalBool
|
IsPrimary optional.Option[bool]
|
||||||
IsActivated util.OptionalBool
|
IsActivated optional.Option[bool]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchEmailResult is an e-mail address found in the user or email_address table
|
// SearchEmailResult is an e-mail address found in the user or email_address table
|
||||||
@ -432,18 +445,12 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
if opts.IsPrimary.Has() {
|
||||||
case opts.IsPrimary.IsTrue():
|
cond = cond.And(builder.Eq{"email_address.is_primary": opts.IsPrimary.Value()})
|
||||||
cond = cond.And(builder.Eq{"email_address.is_primary": true})
|
|
||||||
case opts.IsPrimary.IsFalse():
|
|
||||||
cond = cond.And(builder.Eq{"email_address.is_primary": false})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
if opts.IsActivated.Has() {
|
||||||
case opts.IsActivated.IsTrue():
|
cond = cond.And(builder.Eq{"email_address.is_activated": opts.IsActivated.Value()})
|
||||||
cond = cond.And(builder.Eq{"email_address.is_activated": true})
|
|
||||||
case opts.IsActivated.IsFalse():
|
|
||||||
cond = cond.And(builder.Eq{"email_address.is_activated": false})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.ID = email_address.uid").
|
count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.ID = email_address.uid").
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -45,31 +45,22 @@ func TestIsEmailUsed(t *testing.T) {
|
|||||||
func TestMakeEmailPrimary(t *testing.T) {
|
func TestMakeEmailPrimary(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
email := &user_model.EmailAddress{
|
err := user_model.MakeActiveEmailPrimary(db.DefaultContext, 9999999)
|
||||||
Email: "user567890@example.com",
|
|
||||||
}
|
|
||||||
err := user_model.MakeEmailPrimary(db.DefaultContext, email)
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.EqualError(t, err, user_model.ErrEmailAddressNotExist{Email: email.Email}.Error())
|
assert.ErrorIs(t, err, user_model.ErrEmailAddressNotExist{})
|
||||||
|
|
||||||
email = &user_model.EmailAddress{
|
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{Email: "user11@example.com"})
|
||||||
Email: "user11@example.com",
|
err = user_model.MakeActiveEmailPrimary(db.DefaultContext, email.ID)
|
||||||
}
|
|
||||||
err = user_model.MakeEmailPrimary(db.DefaultContext, email)
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.EqualError(t, err, user_model.ErrEmailNotActivated.Error())
|
assert.ErrorIs(t, err, user_model.ErrEmailAddressNotExist{}) // inactive email is considered as not exist for "MakeActiveEmailPrimary"
|
||||||
|
|
||||||
email = &user_model.EmailAddress{
|
email = unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{Email: "user9999999@example.com"})
|
||||||
Email: "user9999999@example.com",
|
err = user_model.MakeActiveEmailPrimary(db.DefaultContext, email.ID)
|
||||||
}
|
|
||||||
err = user_model.MakeEmailPrimary(db.DefaultContext, email)
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, user_model.IsErrUserNotExist(err))
|
assert.True(t, user_model.IsErrUserNotExist(err))
|
||||||
|
|
||||||
email = &user_model.EmailAddress{
|
email = unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{Email: "user101@example.com"})
|
||||||
Email: "user101@example.com",
|
err = user_model.MakeActiveEmailPrimary(db.DefaultContext, email.ID)
|
||||||
}
|
|
||||||
err = user_model.MakeEmailPrimary(db.DefaultContext, email)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
user, _ := user_model.GetUserByID(db.DefaultContext, int64(10))
|
user, _ := user_model.GetUserByID(db.DefaultContext, int64(10))
|
||||||
@ -137,14 +128,14 @@ func TestListEmails(t *testing.T) {
|
|||||||
assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.UID == 27 }))
|
assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.UID == 27 }))
|
||||||
|
|
||||||
// Must find only primary addresses (i.e. from the `user` table)
|
// Must find only primary addresses (i.e. from the `user` table)
|
||||||
opts = &user_model.SearchEmailOptions{IsPrimary: util.OptionalBoolTrue}
|
opts = &user_model.SearchEmailOptions{IsPrimary: optional.Some(true)}
|
||||||
emails, _, err = user_model.SearchEmails(db.DefaultContext, opts)
|
emails, _, err = user_model.SearchEmails(db.DefaultContext, opts)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.IsPrimary }))
|
assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.IsPrimary }))
|
||||||
assert.False(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsPrimary }))
|
assert.False(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsPrimary }))
|
||||||
|
|
||||||
// Must find only inactive addresses (i.e. not validated)
|
// Must find only inactive addresses (i.e. not validated)
|
||||||
opts = &user_model.SearchEmailOptions{IsActivated: util.OptionalBoolFalse}
|
opts = &user_model.SearchEmailOptions{IsActivated: optional.Some(false)}
|
||||||
emails, _, err = user_model.SearchEmails(db.DefaultContext, opts)
|
emails, _, err = user_model.SearchEmails(db.DefaultContext, opts)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsActivated }))
|
assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsActivated }))
|
||||||
|
@ -9,8 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
@ -30,11 +31,13 @@ type SearchUserOptions struct {
|
|||||||
Actor *User // The user doing the search
|
Actor *User // The user doing the search
|
||||||
SearchByEmail bool // Search by email as well as username/full name
|
SearchByEmail bool // Search by email as well as username/full name
|
||||||
|
|
||||||
IsActive util.OptionalBool
|
SupportedSortOrders container.Set[string] // if not nil, only allow to use the sort orders in this set
|
||||||
IsAdmin util.OptionalBool
|
|
||||||
IsRestricted util.OptionalBool
|
IsActive optional.Option[bool]
|
||||||
IsTwoFactorEnabled util.OptionalBool
|
IsAdmin optional.Option[bool]
|
||||||
IsProhibitLogin util.OptionalBool
|
IsRestricted optional.Option[bool]
|
||||||
|
IsTwoFactorEnabled optional.Option[bool]
|
||||||
|
IsProhibitLogin optional.Option[bool]
|
||||||
IncludeReserved bool
|
IncludeReserved bool
|
||||||
|
|
||||||
ExtraParamStrings map[string]string
|
ExtraParamStrings map[string]string
|
||||||
@ -86,24 +89,24 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
|
|||||||
cond = cond.And(builder.Eq{"login_name": opts.LoginName})
|
cond = cond.And(builder.Eq{"login_name": opts.LoginName})
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.IsActive.IsNone() {
|
if opts.IsActive.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_active": opts.IsActive.IsTrue()})
|
cond = cond.And(builder.Eq{"is_active": opts.IsActive.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.IsAdmin.IsNone() {
|
if opts.IsAdmin.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.IsTrue()})
|
cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.IsRestricted.IsNone() {
|
if opts.IsRestricted.Has() {
|
||||||
cond = cond.And(builder.Eq{"is_restricted": opts.IsRestricted.IsTrue()})
|
cond = cond.And(builder.Eq{"is_restricted": opts.IsRestricted.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.IsProhibitLogin.IsNone() {
|
if opts.IsProhibitLogin.Has() {
|
||||||
cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.IsTrue()})
|
cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.Value()})
|
||||||
}
|
}
|
||||||
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
if opts.IsTwoFactorEnabled.IsNone() {
|
if !opts.IsTwoFactorEnabled.Has() {
|
||||||
return e.Where(cond)
|
return e.Where(cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +114,7 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
|
|||||||
// While using LEFT JOIN, sometimes the performance might not be good, but it won't be a problem now, such SQL is seldom executed.
|
// While using LEFT JOIN, sometimes the performance might not be good, but it won't be a problem now, such SQL is seldom executed.
|
||||||
// There are some possible methods to refactor this SQL in future when we really need to optimize the performance (but not now):
|
// There are some possible methods to refactor this SQL in future when we really need to optimize the performance (but not now):
|
||||||
// (1) add a column in user table (2) add a setting value in user_setting table (3) use search engines (bleve/elasticsearch)
|
// (1) add a column in user table (2) add a setting value in user_setting table (3) use search engines (bleve/elasticsearch)
|
||||||
if opts.IsTwoFactorEnabled.IsTrue() {
|
if opts.IsTwoFactorEnabled.Value() {
|
||||||
cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL"))
|
cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL"))
|
||||||
} else {
|
} else {
|
||||||
cond = cond.And(builder.Expr("two_factor.uid IS NULL"))
|
cond = cond.And(builder.Expr("two_factor.uid IS NULL"))
|
||||||
@ -128,7 +131,7 @@ func SearchUsers(ctx context.Context, opts *SearchUserOptions) (users []*User, _
|
|||||||
defer sessCount.Close()
|
defer sessCount.Close()
|
||||||
count, err := sessCount.Count(new(User))
|
count, err := sessCount.Count(new(User))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("Count: %w", err)
|
return nil, 0, fmt.Errorf("count: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.OrderBy) == 0 {
|
if len(opts.OrderBy) == 0 {
|
||||||
|
@ -16,10 +16,10 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -103,29 +103,29 @@ func TestSearchUsers(t *testing.T) {
|
|||||||
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
|
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
|
||||||
[]int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
|
[]int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse},
|
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(false)},
|
||||||
[]int64{9})
|
[]int64{9})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
|
||||||
[]int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
|
[]int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
|
||||||
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
|
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
|
||||||
|
|
||||||
// order by name asc default
|
// order by name asc default
|
||||||
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
|
||||||
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
|
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: optional.Some(true)},
|
||||||
[]int64{1})
|
[]int64{1})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: optional.Some(true)},
|
||||||
[]int64{29})
|
[]int64{29})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: optional.Some(true)},
|
||||||
[]int64{37})
|
[]int64{37})
|
||||||
|
|
||||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: util.OptionalBoolTrue},
|
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)},
|
||||||
[]int64{24})
|
[]int64{24})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,9 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
|
|||||||
} else if task.Status.IsDone() {
|
} else if task.Status.IsDone() {
|
||||||
preStep.Stopped = task.Stopped
|
preStep.Stopped = task.Stopped
|
||||||
preStep.Status = actions_model.StatusFailure
|
preStep.Status = actions_model.StatusFailure
|
||||||
|
if task.Status.IsSkipped() {
|
||||||
|
preStep.Status = actions_model.StatusSkipped
|
||||||
|
}
|
||||||
}
|
}
|
||||||
logIndex += preStep.LogLength
|
logIndex += preStep.LogLength
|
||||||
|
|
||||||
|
@ -441,6 +441,9 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
|
|||||||
// all acts conditions should be satisfied
|
// all acts conditions should be satisfied
|
||||||
for cond, vals := range acts {
|
for cond, vals := range acts {
|
||||||
switch cond {
|
switch cond {
|
||||||
|
case "types":
|
||||||
|
// types have been checked
|
||||||
|
continue
|
||||||
case "branches":
|
case "branches":
|
||||||
refName := git.RefName(prPayload.PullRequest.Base.Ref)
|
refName := git.RefName(prPayload.PullRequest.Base.Ref)
|
||||||
patterns, err := workflowpattern.CompilePatterns(vals...)
|
patterns, err := workflowpattern.CompilePatterns(vals...)
|
||||||
|
104
modules/badge/badge.go
Normal file
104
modules/badge/badge.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package badge
|
||||||
|
|
||||||
|
import (
|
||||||
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The Badge layout: |offset|label|message|
|
||||||
|
// We use 10x scale to calculate more precisely
|
||||||
|
// Then scale down to normal size in tmpl file
|
||||||
|
|
||||||
|
type Label struct {
|
||||||
|
text string
|
||||||
|
width int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Label) Text() string {
|
||||||
|
return l.text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Label) Width() int {
|
||||||
|
return l.width
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Label) TextLength() int {
|
||||||
|
return int(float64(l.width-defaultOffset) * 9.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Label) X() int {
|
||||||
|
return l.width*5 + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
text string
|
||||||
|
width int
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) Text() string {
|
||||||
|
return m.text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) Width() int {
|
||||||
|
return m.width
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) X() int {
|
||||||
|
return m.x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) TextLength() int {
|
||||||
|
return int(float64(m.width-defaultOffset) * 9.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Badge struct {
|
||||||
|
Color string
|
||||||
|
FontSize int
|
||||||
|
Label Label
|
||||||
|
Message Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Badge) Width() int {
|
||||||
|
return b.Label.width + b.Message.width
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultOffset = 9
|
||||||
|
defaultFontSize = 11
|
||||||
|
DefaultColor = "#9f9f9f" // Grey
|
||||||
|
defaultFontWidth = 7 // approximate speculation
|
||||||
|
)
|
||||||
|
|
||||||
|
var StatusColorMap = map[actions_model.Status]string{
|
||||||
|
actions_model.StatusSuccess: "#4c1", // Green
|
||||||
|
actions_model.StatusSkipped: "#dfb317", // Yellow
|
||||||
|
actions_model.StatusUnknown: "#97ca00", // Light Green
|
||||||
|
actions_model.StatusFailure: "#e05d44", // Red
|
||||||
|
actions_model.StatusCancelled: "#fe7d37", // Orange
|
||||||
|
actions_model.StatusWaiting: "#dfb317", // Yellow
|
||||||
|
actions_model.StatusRunning: "#dfb317", // Yellow
|
||||||
|
actions_model.StatusBlocked: "#dfb317", // Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateBadge generates badge with given template
|
||||||
|
func GenerateBadge(label, message, color string) Badge {
|
||||||
|
lw := defaultFontWidth*len(label) + defaultOffset
|
||||||
|
mw := defaultFontWidth*len(message) + defaultOffset
|
||||||
|
x := lw*10 + mw*5 - 10
|
||||||
|
return Badge{
|
||||||
|
Label: Label{
|
||||||
|
text: label,
|
||||||
|
width: lw,
|
||||||
|
},
|
||||||
|
Message: Message{
|
||||||
|
text: message,
|
||||||
|
width: mw,
|
||||||
|
x: x,
|
||||||
|
},
|
||||||
|
FontSize: defaultFontSize * 10,
|
||||||
|
Color: color,
|
||||||
|
}
|
||||||
|
}
|
@ -20,10 +20,10 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/indexer/issues/internal"
|
"code.gitea.io/gitea/modules/indexer/issues/internal"
|
||||||
"code.gitea.io/gitea/modules/indexer/issues/meilisearch"
|
"code.gitea.io/gitea/modules/indexer/issues/meilisearch"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/queue"
|
"code.gitea.io/gitea/modules/queue"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IndexerMetadata is used to send data to the queue, so it contains only the ids.
|
// IndexerMetadata is used to send data to the queue, so it contains only the ids.
|
||||||
@ -220,7 +220,7 @@ func PopulateIssueIndexer(ctx context.Context) error {
|
|||||||
ListOptions: db_model.ListOptions{Page: page, PageSize: repo_model.RepositoryListDefaultPageSize},
|
ListOptions: db_model.ListOptions{Page: page, PageSize: repo_model.RepositoryListDefaultPageSize},
|
||||||
OrderBy: db_model.SearchOrderByID,
|
OrderBy: db_model.SearchOrderByID,
|
||||||
Private: true,
|
Private: true,
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: optional.Some(false),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("SearchRepositoryByName: %v", err)
|
log.Error("SearchRepositoryByName: %v", err)
|
||||||
|
@ -397,7 +397,7 @@ func TestRender_ShortLinks(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
|
||||||
buffer, err = markdown.RenderString(&markup.RenderContext{
|
buffer, err = markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
@ -407,7 +407,7 @@ func TestRender_ShortLinks(t *testing.T) {
|
|||||||
IsWiki: true,
|
IsWiki: true,
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
mediatree := util.URLJoin(markup.TestRepoURL, "media", "master")
|
mediatree := util.URLJoin(markup.TestRepoURL, "media", "master")
|
||||||
@ -510,7 +510,7 @@ func TestRender_RelativeImages(t *testing.T) {
|
|||||||
Metas: localMetas,
|
Metas: localMetas,
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
|
||||||
buffer, err = markdown.RenderString(&markup.RenderContext{
|
buffer, err = markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
@ -520,7 +520,7 @@ func TestRender_RelativeImages(t *testing.T) {
|
|||||||
IsWiki: true,
|
IsWiki: true,
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw")
|
rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw")
|
||||||
|
@ -6,6 +6,7 @@ package markdown
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -262,12 +263,12 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RenderString renders Markdown string to HTML with all specific handling stuff and return string
|
// RenderString renders Markdown string to HTML with all specific handling stuff and return string
|
||||||
func RenderString(ctx *markup.RenderContext, content string) (string, error) {
|
func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) {
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return buf.String(), nil
|
return template.HTML(buf.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderRaw renders Markdown to HTML without handling special links.
|
// RenderRaw renders Markdown to HTML without handling special links.
|
||||||
|
@ -5,6 +5,7 @@ package markdown_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -21,12 +22,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AppURL = "http://localhost:3000/"
|
AppURL = "http://localhost:3000/"
|
||||||
Repo = "gogits/gogs"
|
FullURL = AppURL + "gogits/gogs/"
|
||||||
AppSubURL = AppURL + Repo + "/"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// these values should match the Repo const above
|
// these values should match the const above
|
||||||
var localMetas = map[string]string{
|
var localMetas = map[string]string{
|
||||||
"user": "gogits",
|
"user": "gogits",
|
||||||
"repo": "gogs",
|
"repo": "gogs",
|
||||||
@ -48,34 +48,33 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
func TestRender_StandardLinks(t *testing.T) {
|
func TestRender_StandardLinks(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
setting.AppSubURL = AppSubURL
|
|
||||||
|
|
||||||
test := func(input, expected, expectedWiki string) {
|
test := func(input, expected, expectedWiki string) {
|
||||||
buffer, err := markdown.RenderString(&markup.RenderContext{
|
buffer, err := markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: setting.AppSubURL,
|
Base: FullURL,
|
||||||
},
|
},
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
|
||||||
|
|
||||||
buffer, err = markdown.RenderString(&markup.RenderContext{
|
buffer, err = markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: setting.AppSubURL,
|
Base: FullURL,
|
||||||
},
|
},
|
||||||
IsWiki: true,
|
IsWiki: true,
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
googleRendered := `<p><a href="https://google.com/" rel="nofollow">https://google.com/</a></p>`
|
googleRendered := `<p><a href="https://google.com/" rel="nofollow">https://google.com/</a></p>`
|
||||||
test("<https://google.com/>", googleRendered, googleRendered)
|
test("<https://google.com/>", googleRendered, googleRendered)
|
||||||
|
|
||||||
lnk := util.URLJoin(AppSubURL, "WikiPage")
|
lnk := util.URLJoin(FullURL, "WikiPage")
|
||||||
lnkWiki := util.URLJoin(AppSubURL, "wiki", "WikiPage")
|
lnkWiki := util.URLJoin(FullURL, "wiki", "WikiPage")
|
||||||
test("[WikiPage](WikiPage)",
|
test("[WikiPage](WikiPage)",
|
||||||
`<p><a href="`+lnk+`" rel="nofollow">WikiPage</a></p>`,
|
`<p><a href="`+lnk+`" rel="nofollow">WikiPage</a></p>`,
|
||||||
`<p><a href="`+lnkWiki+`" rel="nofollow">WikiPage</a></p>`)
|
`<p><a href="`+lnkWiki+`" rel="nofollow">WikiPage</a></p>`)
|
||||||
@ -83,23 +82,22 @@ func TestRender_StandardLinks(t *testing.T) {
|
|||||||
|
|
||||||
func TestRender_Images(t *testing.T) {
|
func TestRender_Images(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
setting.AppSubURL = AppSubURL
|
|
||||||
|
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
buffer, err := markdown.RenderString(&markup.RenderContext{
|
buffer, err := markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: setting.AppSubURL,
|
Base: FullURL,
|
||||||
},
|
},
|
||||||
}, input)
|
}, input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
url := "../../.images/src/02/train.jpg"
|
url := "../../.images/src/02/train.jpg"
|
||||||
title := "Train"
|
title := "Train"
|
||||||
href := "https://gitea.io"
|
href := "https://gitea.io"
|
||||||
result := util.URLJoin(AppSubURL, url)
|
result := util.URLJoin(FullURL, url)
|
||||||
// hint: With Markdown v2.5.2, there is a new syntax: [link](URL){:target="_blank"} , but we do not support it now
|
// hint: With Markdown v2.5.2, there is a new syntax: [link](URL){:target="_blank"} , but we do not support it now
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@ -289,33 +287,32 @@ This PR has been generated by [Renovate Bot](https://github.com/renovatebot/reno
|
|||||||
|
|
||||||
func TestTotal_RenderWiki(t *testing.T) {
|
func TestTotal_RenderWiki(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
setting.AppSubURL = AppSubURL
|
|
||||||
|
|
||||||
answers := testAnswers(util.URLJoin(AppSubURL, "wiki"), util.URLJoin(AppSubURL, "wiki", "raw"))
|
answers := testAnswers(util.URLJoin(FullURL, "wiki"), util.URLJoin(FullURL, "wiki", "raw"))
|
||||||
|
|
||||||
for i := 0; i < len(sameCases); i++ {
|
for i := 0; i < len(sameCases); i++ {
|
||||||
line, err := markdown.RenderString(&markup.RenderContext{
|
line, err := markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: setting.AppSubURL,
|
Base: FullURL,
|
||||||
},
|
},
|
||||||
Metas: localMetas,
|
Metas: localMetas,
|
||||||
IsWiki: true,
|
IsWiki: true,
|
||||||
}, sameCases[i])
|
}, sameCases[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, answers[i], line)
|
assert.Equal(t, template.HTML(answers[i]), line)
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []string{
|
testCases := []string{
|
||||||
// Guard wiki sidebar: special syntax
|
// Guard wiki sidebar: special syntax
|
||||||
`[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`,
|
`[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`,
|
||||||
// rendered
|
// rendered
|
||||||
`<p><a href="` + AppSubURL + `wiki/Guardfile-DSL---Configuring-Guard" rel="nofollow">Guardfile-DSL / Configuring-Guard</a></p>
|
`<p><a href="` + FullURL + `wiki/Guardfile-DSL---Configuring-Guard" rel="nofollow">Guardfile-DSL / Configuring-Guard</a></p>
|
||||||
`,
|
`,
|
||||||
// special syntax
|
// special syntax
|
||||||
`[[Name|Link]]`,
|
`[[Name|Link]]`,
|
||||||
// rendered
|
// rendered
|
||||||
`<p><a href="` + AppSubURL + `wiki/Link" rel="nofollow">Name</a></p>
|
`<p><a href="` + FullURL + `wiki/Link" rel="nofollow">Name</a></p>
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,32 +320,31 @@ func TestTotal_RenderWiki(t *testing.T) {
|
|||||||
line, err := markdown.RenderString(&markup.RenderContext{
|
line, err := markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: setting.AppSubURL,
|
Base: FullURL,
|
||||||
},
|
},
|
||||||
IsWiki: true,
|
IsWiki: true,
|
||||||
}, testCases[i])
|
}, testCases[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, testCases[i+1], line)
|
assert.Equal(t, template.HTML(testCases[i+1]), line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTotal_RenderString(t *testing.T) {
|
func TestTotal_RenderString(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
setting.AppSubURL = AppSubURL
|
|
||||||
|
|
||||||
answers := testAnswers(util.URLJoin(AppSubURL, "src", "master"), util.URLJoin(AppSubURL, "media", "master"))
|
answers := testAnswers(util.URLJoin(FullURL, "src", "master"), util.URLJoin(FullURL, "media", "master"))
|
||||||
|
|
||||||
for i := 0; i < len(sameCases); i++ {
|
for i := 0; i < len(sameCases); i++ {
|
||||||
line, err := markdown.RenderString(&markup.RenderContext{
|
line, err := markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: AppSubURL,
|
Base: FullURL,
|
||||||
BranchPath: "master",
|
BranchPath: "master",
|
||||||
},
|
},
|
||||||
Metas: localMetas,
|
Metas: localMetas,
|
||||||
}, sameCases[i])
|
}, sameCases[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, answers[i], line)
|
assert.Equal(t, template.HTML(answers[i]), line)
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []string{}
|
testCases := []string{}
|
||||||
@ -357,11 +353,11 @@ func TestTotal_RenderString(t *testing.T) {
|
|||||||
line, err := markdown.RenderString(&markup.RenderContext{
|
line, err := markdown.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
Links: markup.Links{
|
Links: markup.Links{
|
||||||
Base: AppSubURL,
|
Base: FullURL,
|
||||||
},
|
},
|
||||||
}, testCases[i])
|
}, testCases[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, testCases[i+1], line)
|
assert.Equal(t, template.HTML(testCases[i+1]), line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,7 +424,7 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) {
|
|||||||
`
|
`
|
||||||
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
|
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expected, res)
|
assert.Equal(t, template.HTML(expected), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColorPreview(t *testing.T) {
|
func TestColorPreview(t *testing.T) {
|
||||||
@ -462,7 +458,7 @@ func TestColorPreview(t *testing.T) {
|
|||||||
for _, test := range positiveTests {
|
for _, test := range positiveTests {
|
||||||
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
||||||
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
||||||
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
|
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +525,7 @@ func TestMathBlock(t *testing.T) {
|
|||||||
for _, test := range testcases {
|
for _, test := range testcases {
|
||||||
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
||||||
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
||||||
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
|
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,12 +563,12 @@ foo: bar
|
|||||||
for _, test := range testcases {
|
for _, test := range testcases {
|
||||||
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
||||||
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
||||||
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
|
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderLinks(t *testing.T) {
|
func TestRenderLinks(t *testing.T) {
|
||||||
input := ` space @mention-user
|
input := ` space @mention-user${SPACE}${SPACE}
|
||||||
/just/a/path.bin
|
/just/a/path.bin
|
||||||
https://example.com/file.bin
|
https://example.com/file.bin
|
||||||
[local link](file.bin)
|
[local link](file.bin)
|
||||||
@ -593,8 +589,9 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
|
|||||||
mail@domain.com
|
mail@domain.com
|
||||||
@mention-user test
|
@mention-user test
|
||||||
#123
|
#123
|
||||||
space
|
space${SPACE}${SPACE}
|
||||||
`
|
`
|
||||||
|
input = strings.ReplaceAll(input, "${SPACE}", " ") // replace ${SPACE} with " ", to avoid some editor's auto-trimming
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Links markup.Links
|
Links markup.Links
|
||||||
IsWiki bool
|
IsWiki bool
|
||||||
@ -957,6 +954,6 @@ space</p>
|
|||||||
for i, c := range cases {
|
for i, c := range cases {
|
||||||
result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input)
|
result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input)
|
||||||
assert.NoError(t, err, "Unexpected error in testcase: %v", i)
|
assert.NoError(t, err, "Unexpected error in testcase: %v", i)
|
||||||
assert.Equal(t, c.Expected, result, "Unexpected result in testcase %v", i)
|
assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,16 @@ func TestOption(t *testing.T) {
|
|||||||
assert.Equal(t, int(1), some.Value())
|
assert.Equal(t, int(1), some.Value())
|
||||||
assert.Equal(t, int(1), some.ValueOrDefault(2))
|
assert.Equal(t, int(1), some.ValueOrDefault(2))
|
||||||
|
|
||||||
|
noneBool := optional.None[bool]()
|
||||||
|
assert.False(t, noneBool.Has())
|
||||||
|
assert.False(t, noneBool.Value())
|
||||||
|
assert.True(t, noneBool.ValueOrDefault(true))
|
||||||
|
|
||||||
|
someBool := optional.Some(true)
|
||||||
|
assert.True(t, someBool.Has())
|
||||||
|
assert.True(t, someBool.Value())
|
||||||
|
assert.True(t, someBool.ValueOrDefault(false))
|
||||||
|
|
||||||
var ptr *int
|
var ptr *int
|
||||||
assert.False(t, optional.FromPtr(ptr).Has())
|
assert.False(t, optional.FromPtr(ptr).Has())
|
||||||
|
|
||||||
|
@ -6,22 +6,18 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/label"
|
"code.gitea.io/gitea/modules/label"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/options"
|
"code.gitea.io/gitea/modules/options"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OptionFile struct {
|
type OptionFile struct {
|
||||||
@ -124,70 +120,6 @@ func LoadRepoConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitRepoCommit temporarily changes with work directory.
|
|
||||||
func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) {
|
|
||||||
commitTimeStr := time.Now().Format(time.RFC3339)
|
|
||||||
|
|
||||||
sig := u.NewGitSig()
|
|
||||||
// Because this may call hooks we should pass in the environment
|
|
||||||
env := append(os.Environ(),
|
|
||||||
"GIT_AUTHOR_NAME="+sig.Name,
|
|
||||||
"GIT_AUTHOR_EMAIL="+sig.Email,
|
|
||||||
"GIT_AUTHOR_DATE="+commitTimeStr,
|
|
||||||
"GIT_COMMITTER_DATE="+commitTimeStr,
|
|
||||||
)
|
|
||||||
committerName := sig.Name
|
|
||||||
committerEmail := sig.Email
|
|
||||||
|
|
||||||
if stdout, _, err := git.NewCommand(ctx, "add", "--all").
|
|
||||||
SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)).
|
|
||||||
RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil {
|
|
||||||
log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err)
|
|
||||||
return fmt.Errorf("git add --all: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := git.NewCommand(ctx, "commit", "--message=Initial commit").
|
|
||||||
AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email)
|
|
||||||
|
|
||||||
sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
|
|
||||||
if sign {
|
|
||||||
cmd.AddOptionFormat("-S%s", keyID)
|
|
||||||
|
|
||||||
if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
|
|
||||||
// need to set the committer to the KeyID owner
|
|
||||||
committerName = signer.Name
|
|
||||||
committerEmail = signer.Email
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmd.AddArguments("--no-gpg-sign")
|
|
||||||
}
|
|
||||||
|
|
||||||
env = append(env,
|
|
||||||
"GIT_COMMITTER_NAME="+committerName,
|
|
||||||
"GIT_COMMITTER_EMAIL="+committerEmail,
|
|
||||||
)
|
|
||||||
|
|
||||||
if stdout, _, err := cmd.
|
|
||||||
SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)).
|
|
||||||
RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil {
|
|
||||||
log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.String(), stdout, err)
|
|
||||||
return fmt.Errorf("git commit: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(defaultBranch) == 0 {
|
|
||||||
defaultBranch = setting.Repository.DefaultBranch
|
|
||||||
}
|
|
||||||
|
|
||||||
if stdout, _, err := git.NewCommand(ctx, "push", "origin").AddDynamicArguments("HEAD:" + defaultBranch).
|
|
||||||
SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)).
|
|
||||||
RunStdString(&git.RunOpts{Dir: tmpPath, Env: InternalPushingEnvironment(u, repo)}); err != nil {
|
|
||||||
log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err)
|
|
||||||
return fmt.Errorf("git push: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) {
|
func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) {
|
||||||
// Somehow the directory could exist.
|
// Somehow the directory could exist.
|
||||||
repoPath := repo_model.RepoPath(owner, name)
|
repoPath := repo_model.RepoPath(owner, name)
|
||||||
|
@ -5,16 +5,13 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
"code.gitea.io/gitea/models/organization"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
@ -22,10 +19,8 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/migration"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -47,244 +42,6 @@ func WikiRemoteURL(ctx context.Context, remote string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// MigrateRepositoryGitData starts migrating git related data after created migrating repository
|
|
||||||
func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
|
||||||
repo *repo_model.Repository, opts migration.MigrateOptions,
|
|
||||||
httpTransport *http.Transport,
|
|
||||||
) (*repo_model.Repository, error) {
|
|
||||||
repoPath := repo_model.RepoPath(u.Name, opts.RepoName)
|
|
||||||
|
|
||||||
if u.IsOrganization() {
|
|
||||||
t, err := organization.OrgFromUser(u).GetOwnerTeam(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repo.NumWatches = t.NumMembers
|
|
||||||
} else {
|
|
||||||
repo.NumWatches = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if err = util.RemoveAll(repoPath); err != nil {
|
|
||||||
return repo, fmt.Errorf("Failed to remove %s: %w", repoPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = git.Clone(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{
|
|
||||||
Mirror: true,
|
|
||||||
Quiet: true,
|
|
||||||
Timeout: migrateTimeout,
|
|
||||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
|
||||||
}); err != nil {
|
|
||||||
if errors.Is(err, context.DeadlineExceeded) {
|
|
||||||
return repo, fmt.Errorf("Clone timed out. Consider increasing [git.timeout] MIGRATE in app.ini. Underlying Error: %w", err)
|
|
||||||
}
|
|
||||||
return repo, fmt.Errorf("Clone: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := git.WriteCommitGraph(ctx, repoPath); err != nil {
|
|
||||||
return repo, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Wiki {
|
|
||||||
wikiPath := repo_model.WikiPath(u.Name, opts.RepoName)
|
|
||||||
wikiRemotePath := WikiRemoteURL(ctx, opts.CloneAddr)
|
|
||||||
if len(wikiRemotePath) > 0 {
|
|
||||||
if err := util.RemoveAll(wikiPath); err != nil {
|
|
||||||
return repo, fmt.Errorf("Failed to remove %s: %w", wikiPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := git.Clone(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
|
||||||
Mirror: true,
|
|
||||||
Quiet: true,
|
|
||||||
Timeout: migrateTimeout,
|
|
||||||
Branch: "master",
|
|
||||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
|
||||||
}); err != nil {
|
|
||||||
log.Warn("Clone wiki: %v", err)
|
|
||||||
if err := util.RemoveAll(wikiPath); err != nil {
|
|
||||||
return repo, fmt.Errorf("Failed to remove %s: %w", wikiPath, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := git.WriteCommitGraph(ctx, wikiPath); err != nil {
|
|
||||||
return repo, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if repo.OwnerID == u.ID {
|
|
||||||
repo.Owner = u
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = CheckDaemonExportOK(ctx, repo); err != nil {
|
|
||||||
return repo, fmt.Errorf("checkDaemonExportOK: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if stdout, _, err := git.NewCommand(ctx, "update-server-info").
|
|
||||||
SetDescription(fmt.Sprintf("MigrateRepositoryGitData(git update-server-info): %s", repoPath)).
|
|
||||||
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
|
|
||||||
log.Error("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
|
|
||||||
return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepository(ctx, repoPath)
|
|
||||||
if err != nil {
|
|
||||||
return repo, fmt.Errorf("OpenRepository: %w", err)
|
|
||||||
}
|
|
||||||
defer gitRepo.Close()
|
|
||||||
|
|
||||||
repo.IsEmpty, err = gitRepo.IsEmpty()
|
|
||||||
if err != nil {
|
|
||||||
return repo, fmt.Errorf("git.IsEmpty: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !repo.IsEmpty {
|
|
||||||
if len(repo.DefaultBranch) == 0 {
|
|
||||||
// Try to get HEAD branch and set it as default branch.
|
|
||||||
headBranch, err := gitRepo.GetHEADBranch()
|
|
||||||
if err != nil {
|
|
||||||
return repo, fmt.Errorf("GetHEADBranch: %w", err)
|
|
||||||
}
|
|
||||||
if headBranch != nil {
|
|
||||||
repo.DefaultBranch = headBranch.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := SyncRepoBranchesWithRepo(ctx, repo, gitRepo, u.ID); err != nil {
|
|
||||||
return repo, fmt.Errorf("SyncRepoBranchesWithRepo: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !opts.Releases {
|
|
||||||
// note: this will greatly improve release (tag) sync
|
|
||||||
// for pull-mirrors with many tags
|
|
||||||
repo.IsMirror = opts.Mirror
|
|
||||||
if err = SyncReleasesWithTags(ctx, repo, gitRepo); err != nil {
|
|
||||||
log.Error("Failed to synchronize tags to releases for repository: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.LFS {
|
|
||||||
endpoint := lfs.DetermineEndpoint(opts.CloneAddr, opts.LFSEndpoint)
|
|
||||||
lfsClient := lfs.NewClient(endpoint, httpTransport)
|
|
||||||
if err = StoreMissingLfsObjectsInRepository(ctx, repo, gitRepo, lfsClient); err != nil {
|
|
||||||
log.Error("Failed to store missing LFS objects for repository: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
if opts.Mirror {
|
|
||||||
remoteAddress, err := util.SanitizeURL(opts.CloneAddr)
|
|
||||||
if err != nil {
|
|
||||||
return repo, err
|
|
||||||
}
|
|
||||||
mirrorModel := repo_model.Mirror{
|
|
||||||
RepoID: repo.ID,
|
|
||||||
Interval: setting.Mirror.DefaultInterval,
|
|
||||||
EnablePrune: true,
|
|
||||||
NextUpdateUnix: timeutil.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval),
|
|
||||||
LFS: opts.LFS,
|
|
||||||
RemoteAddress: remoteAddress,
|
|
||||||
}
|
|
||||||
if opts.LFS {
|
|
||||||
mirrorModel.LFSEndpoint = opts.LFSEndpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.MirrorInterval != "" {
|
|
||||||
parsedInterval, err := time.ParseDuration(opts.MirrorInterval)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to set Interval: %v", err)
|
|
||||||
return repo, err
|
|
||||||
}
|
|
||||||
if parsedInterval == 0 {
|
|
||||||
mirrorModel.Interval = 0
|
|
||||||
mirrorModel.NextUpdateUnix = 0
|
|
||||||
} else if parsedInterval < setting.Mirror.MinInterval {
|
|
||||||
err := fmt.Errorf("interval %s is set below Minimum Interval of %s", parsedInterval, setting.Mirror.MinInterval)
|
|
||||||
log.Error("Interval: %s is too frequent", opts.MirrorInterval)
|
|
||||||
return repo, err
|
|
||||||
} else {
|
|
||||||
mirrorModel.Interval = parsedInterval
|
|
||||||
mirrorModel.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(parsedInterval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = repo_model.InsertMirror(ctx, &mirrorModel); err != nil {
|
|
||||||
return repo, fmt.Errorf("InsertOne: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.IsMirror = true
|
|
||||||
if err = UpdateRepository(ctx, repo, false); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is necessary for sync local tags from remote
|
|
||||||
configName := fmt.Sprintf("remote.%s.fetch", mirrorModel.GetRemoteName())
|
|
||||||
if stdout, _, err := git.NewCommand(ctx, "config").
|
|
||||||
AddOptionValues("--add", configName, `+refs/tags/*:refs/tags/*`).
|
|
||||||
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
|
|
||||||
log.Error("MigrateRepositoryGitData(git config --add <remote> +refs/tags/*:refs/tags/*) in %v: Stdout: %s\nError: %v", repo, stdout, err)
|
|
||||||
return repo, fmt.Errorf("error in MigrateRepositoryGitData(git config --add <remote> +refs/tags/*:refs/tags/*): %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err = UpdateRepoSize(ctx, repo); err != nil {
|
|
||||||
log.Error("Failed to update size for repository: %v", err)
|
|
||||||
}
|
|
||||||
if repo, err = CleanUpMigrateInfo(ctx, repo); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
|
|
||||||
// This also removes possible user credentials.
|
|
||||||
func cleanUpMigrateGitConfig(ctx context.Context, repoPath string) error {
|
|
||||||
cmd := git.NewCommand(ctx, "remote", "rm", "origin")
|
|
||||||
// if the origin does not exist
|
|
||||||
_, stderr, err := cmd.RunStdString(&git.RunOpts{
|
|
||||||
Dir: repoPath,
|
|
||||||
})
|
|
||||||
if err != nil && !strings.HasPrefix(stderr, "fatal: No such remote") {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors.
|
|
||||||
func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo_model.Repository, error) {
|
|
||||||
repoPath := repo.RepoPath()
|
|
||||||
if err := CreateDelegateHooks(repoPath); err != nil {
|
|
||||||
return repo, fmt.Errorf("createDelegateHooks: %w", err)
|
|
||||||
}
|
|
||||||
if repo.HasWiki() {
|
|
||||||
if err := CreateDelegateHooks(repo.WikiPath()); err != nil {
|
|
||||||
return repo, fmt.Errorf("createDelegateHooks.(wiki): %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, err := git.NewCommand(ctx, "remote", "rm", "origin").RunStdString(&git.RunOpts{Dir: repoPath})
|
|
||||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
|
||||||
return repo, fmt.Errorf("CleanUpMigrateInfo: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if repo.HasWiki() {
|
|
||||||
if err := cleanUpMigrateGitConfig(ctx, repo.WikiPath()); err != nil {
|
|
||||||
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo, UpdateRepository(ctx, repo, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncRepoTags synchronizes releases table with repository tags
|
// SyncRepoTags synchronizes releases table with repository tags
|
||||||
func SyncRepoTags(ctx context.Context, repoID int64) error {
|
func SyncRepoTags(ctx context.Context, repoID int64) error {
|
||||||
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
|
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
|
||||||
|
@ -20,5 +20,6 @@ func loadAdminFrom(rootCfg ConfigProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UserFeatureDeletion = "deletion"
|
UserFeatureDeletion = "deletion"
|
||||||
|
UserFeatureManageGPGKeys = "manage_gpg_keys"
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package structs
|
package structs
|
||||||
@ -108,3 +109,33 @@ type UpdateUserAvatarOption struct {
|
|||||||
// image must be base64 encoded
|
// image must be base64 encoded
|
||||||
Image string `json:"image" binding:"Required"`
|
Image string `json:"image" binding:"Required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Badge represents a user badge
|
||||||
|
// swagger:model
|
||||||
|
type Badge struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ImageURL string `json:"image_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserBadge represents a user badge
|
||||||
|
// swagger:model
|
||||||
|
type UserBadge struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
BadgeID int64 `json:"badge_id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserBadgeOption options for link between users and badges
|
||||||
|
type UserBadgeOption struct {
|
||||||
|
// example: ["badge1","badge2"]
|
||||||
|
BadgeSlugs []string `json:"badge_slugs" binding:"Required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BadgeList
|
||||||
|
// swagger:response BadgeList
|
||||||
|
type BadgeList struct {
|
||||||
|
// in:body
|
||||||
|
Body []Badge `json:"body"`
|
||||||
|
}
|
||||||
|
@ -33,16 +33,16 @@ func NewFuncMap() template.FuncMap {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// html/template related functions
|
// html/template related functions
|
||||||
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
||||||
"Eval": Eval,
|
"Eval": Eval,
|
||||||
"SafeHTML": SafeHTML,
|
"SafeHTML": SafeHTML,
|
||||||
"HTMLFormat": HTMLFormat,
|
"HTMLFormat": HTMLFormat,
|
||||||
"HTMLEscape": HTMLEscape,
|
"HTMLEscape": HTMLEscape,
|
||||||
"QueryEscape": url.QueryEscape,
|
"QueryEscape": url.QueryEscape,
|
||||||
"JSEscape": JSEscapeSafe,
|
"JSEscape": JSEscapeSafe,
|
||||||
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
|
"SanitizeHTML": SanitizeHTML,
|
||||||
"URLJoin": util.URLJoin,
|
"URLJoin": util.URLJoin,
|
||||||
"DotEscape": DotEscape,
|
"DotEscape": DotEscape,
|
||||||
|
|
||||||
"PathEscape": url.PathEscape,
|
"PathEscape": url.PathEscape,
|
||||||
"PathEscapeSegments": util.PathEscapeSegments,
|
"PathEscapeSegments": util.PathEscapeSegments,
|
||||||
@ -207,8 +207,8 @@ func SafeHTML(s any) template.HTML {
|
|||||||
panic(fmt.Sprintf("unexpected type %T", s))
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Str2html sanitizes the input by pre-defined markdown rules
|
// SanitizeHTML sanitizes the input by pre-defined markdown rules
|
||||||
func Str2html(s any) template.HTML {
|
func SanitizeHTML(s any) template.HTML {
|
||||||
switch v := s.(type) {
|
switch v := s.(type) {
|
||||||
case string:
|
case string:
|
||||||
return template.HTML(markup.Sanitize(v))
|
return template.HTML(markup.Sanitize(v))
|
||||||
|
@ -61,3 +61,8 @@ func TestJSEscapeSafe(t *testing.T) {
|
|||||||
func TestHTMLFormat(t *testing.T) {
|
func TestHTMLFormat(t *testing.T) {
|
||||||
assert.Equal(t, template.HTML("<a>< < 1</a>"), HTMLFormat("<a>%s %s %d</a>", "<", template.HTML("<"), 1))
|
assert.Equal(t, template.HTML("<a>< < 1</a>"), HTMLFormat("<a>%s %s %d</a>", "<", template.HTML("<"), 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSanitizeHTML(t *testing.T) {
|
||||||
|
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`))
|
||||||
|
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(template.HTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`)))
|
||||||
|
}
|
||||||
|
@ -44,11 +44,17 @@ func buildSubjectBodyTemplate(stpl *texttmpl.Template, btpl *template.Template,
|
|||||||
}
|
}
|
||||||
if _, err := stpl.New(name).
|
if _, err := stpl.New(name).
|
||||||
Parse(string(subjectContent)); err != nil {
|
Parse(string(subjectContent)); err != nil {
|
||||||
log.Warn("Failed to parse template [%s/subject]: %v", name, err)
|
log.Error("Failed to parse template [%s/subject]: %v", name, err)
|
||||||
|
if !setting.IsProd {
|
||||||
|
log.Fatal("Please fix the mail template error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if _, err := btpl.New(name).
|
if _, err := btpl.New(name).
|
||||||
Parse(string(bodyContent)); err != nil {
|
Parse(string(bodyContent)); err != nil {
|
||||||
log.Warn("Failed to parse template [%s/body]: %v", name, err)
|
log.Error("Failed to parse template [%s/body]: %v", name, err)
|
||||||
|
if !setting.IsProd {
|
||||||
|
log.Fatal("Please fix the mail template error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("RenderString: %v", err)
|
log.Error("RenderString: %v", err)
|
||||||
}
|
}
|
||||||
return template.HTML(output)
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML {
|
func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML {
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
@ -17,6 +19,19 @@ func NewStringUtils() *StringUtils {
|
|||||||
return &stringUtils
|
return &stringUtils
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (su *StringUtils) ToString(v any) string {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case template.HTML:
|
||||||
|
return string(v)
|
||||||
|
case fmt.Stringer:
|
||||||
|
return v.String()
|
||||||
|
default:
|
||||||
|
return fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (su *StringUtils) HasPrefix(s, prefix string) bool {
|
func (su *StringUtils) HasPrefix(s, prefix string) bool {
|
||||||
return strings.HasPrefix(s, prefix)
|
return strings.HasPrefix(s, prefix)
|
||||||
}
|
}
|
||||||
|
@ -68,13 +68,13 @@ func OptionalBoolOf(b bool) OptionalBool {
|
|||||||
return OptionalBoolFalse
|
return OptionalBoolFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionalBoolParse get the corresponding OptionalBool of a string using strconv.ParseBool
|
// OptionalBoolParse get the corresponding optional.Option[bool] of a string using strconv.ParseBool
|
||||||
func OptionalBoolParse(s string) OptionalBool {
|
func OptionalBoolParse(s string) optional.Option[bool] {
|
||||||
b, e := strconv.ParseBool(s)
|
v, e := strconv.ParseBool(s)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return OptionalBoolNone
|
return optional.None[bool]()
|
||||||
}
|
}
|
||||||
return OptionalBoolOf(b)
|
return optional.Some(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmptyString checks if the provided string is empty
|
// IsEmptyString checks if the provided string is empty
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -173,17 +175,17 @@ func Test_RandomBytes(t *testing.T) {
|
|||||||
assert.NotEqual(t, bytes3, bytes4)
|
assert.NotEqual(t, bytes3, bytes4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_OptionalBool(t *testing.T) {
|
func TestOptionalBoolParse(t *testing.T) {
|
||||||
assert.Equal(t, OptionalBoolNone, OptionalBoolParse(""))
|
assert.Equal(t, optional.None[bool](), OptionalBoolParse(""))
|
||||||
assert.Equal(t, OptionalBoolNone, OptionalBoolParse("x"))
|
assert.Equal(t, optional.None[bool](), OptionalBoolParse("x"))
|
||||||
|
|
||||||
assert.Equal(t, OptionalBoolFalse, OptionalBoolParse("0"))
|
assert.Equal(t, optional.Some(false), OptionalBoolParse("0"))
|
||||||
assert.Equal(t, OptionalBoolFalse, OptionalBoolParse("f"))
|
assert.Equal(t, optional.Some(false), OptionalBoolParse("f"))
|
||||||
assert.Equal(t, OptionalBoolFalse, OptionalBoolParse("False"))
|
assert.Equal(t, optional.Some(false), OptionalBoolParse("False"))
|
||||||
|
|
||||||
assert.Equal(t, OptionalBoolTrue, OptionalBoolParse("1"))
|
assert.Equal(t, optional.Some(true), OptionalBoolParse("1"))
|
||||||
assert.Equal(t, OptionalBoolTrue, OptionalBoolParse("t"))
|
assert.Equal(t, optional.Some(true), OptionalBoolParse("t"))
|
||||||
assert.Equal(t, OptionalBoolTrue, OptionalBoolParse("True"))
|
assert.Equal(t, optional.Some(true), OptionalBoolParse("True"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test case for any function which accepts and returns a single string.
|
// Test case for any function which accepts and returns a single string.
|
||||||
|
@ -123,6 +123,7 @@ pin=Připnout
|
|||||||
unpin=Odepnout
|
unpin=Odepnout
|
||||||
|
|
||||||
artifacts=Artefakty
|
artifacts=Artefakty
|
||||||
|
confirm_delete_artifact=Jste si jisti, že chcete odstranit artefakt „%s“?
|
||||||
|
|
||||||
archived=Archivováno
|
archived=Archivováno
|
||||||
|
|
||||||
@ -423,6 +424,7 @@ authorization_failed_desc=Autorizace selhala, protože jsme detekovali neplatný
|
|||||||
sspi_auth_failed=SSPI autentizace selhala
|
sspi_auth_failed=SSPI autentizace selhala
|
||||||
password_pwned=Heslo, které jste zvolili, je na <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">seznamu odcizených hesel</a>, která byla dříve odhalena při narušení veřejných dat. Zkuste to prosím znovu s jiným heslem.
|
password_pwned=Heslo, které jste zvolili, je na <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">seznamu odcizených hesel</a>, která byla dříve odhalena při narušení veřejných dat. Zkuste to prosím znovu s jiným heslem.
|
||||||
password_pwned_err=Nelze dokončit požadavek na HaveIBeenPwned
|
password_pwned_err=Nelze dokončit požadavek na HaveIBeenPwned
|
||||||
|
last_admin=Nelze odstranit posledního správce. Musí existovat alespoň jeden správce.
|
||||||
|
|
||||||
[mail]
|
[mail]
|
||||||
view_it_on=Zobrazit na %s
|
view_it_on=Zobrazit na %s
|
||||||
@ -588,6 +590,7 @@ org_still_own_packages=Organizace stále vlastní jeden nebo více balíčků. N
|
|||||||
|
|
||||||
target_branch_not_exist=Cílová větev neexistuje.
|
target_branch_not_exist=Cílová větev neexistuje.
|
||||||
|
|
||||||
|
admin_cannot_delete_self=Nemůžete se smazat, dokud jste správce. Nejdříve prosím odeberte svá administrátorská oprávnění.
|
||||||
|
|
||||||
[user]
|
[user]
|
||||||
change_avatar=Změnit váš avatar…
|
change_avatar=Změnit váš avatar…
|
||||||
@ -967,6 +970,8 @@ issue_labels_helper=Vyberte sadu štítků úkolů.
|
|||||||
license=Licence
|
license=Licence
|
||||||
license_helper=Vyberte licenční soubor.
|
license_helper=Vyberte licenční soubor.
|
||||||
license_helper_desc=Licence řídí, co ostatní mohou a nemohou dělat s vaším kódem. Nejste si jisti, která je pro váš projekt správná? Podívejte se na <a target="_blank" rel="noopener noreferrer" href="%s">Zvolte licenci</a>
|
license_helper_desc=Licence řídí, co ostatní mohou a nemohou dělat s vaším kódem. Nejste si jisti, která je pro váš projekt správná? Podívejte se na <a target="_blank" rel="noopener noreferrer" href="%s">Zvolte licenci</a>
|
||||||
|
object_format=Formát objektu
|
||||||
|
object_format_helper=Objektový formát repozitáře. Nelze později změnit. SHA1 je nejvíce kompatibilní.
|
||||||
readme=README
|
readme=README
|
||||||
readme_helper=Vyberte šablonu souboru README.
|
readme_helper=Vyberte šablonu souboru README.
|
||||||
readme_helper_desc=Toto je místo, kde můžete napsat úplný popis vašeho projektu.
|
readme_helper_desc=Toto je místo, kde můžete napsat úplný popis vašeho projektu.
|
||||||
@ -1033,6 +1038,7 @@ desc.public=Veřejný
|
|||||||
desc.template=Šablona
|
desc.template=Šablona
|
||||||
desc.internal=Interní
|
desc.internal=Interní
|
||||||
desc.archived=Archivováno
|
desc.archived=Archivováno
|
||||||
|
desc.sha256=SHA256
|
||||||
|
|
||||||
template.items=Položky šablony
|
template.items=Položky šablony
|
||||||
template.git_content=Obsah gitu (výchozí větev)
|
template.git_content=Obsah gitu (výchozí větev)
|
||||||
@ -1183,6 +1189,8 @@ audio_not_supported_in_browser=Váš prohlížeč nepodporuje značku pro HTML5
|
|||||||
stored_lfs=Uloženo pomocí Git LFS
|
stored_lfs=Uloženo pomocí Git LFS
|
||||||
symbolic_link=Symbolický odkaz
|
symbolic_link=Symbolický odkaz
|
||||||
executable_file=Spustitelný soubor
|
executable_file=Spustitelný soubor
|
||||||
|
vendored=Vendorováno
|
||||||
|
generated=Generováno
|
||||||
commit_graph=Graf commitů
|
commit_graph=Graf commitů
|
||||||
commit_graph.select=Vybrat větve
|
commit_graph.select=Vybrat větve
|
||||||
commit_graph.hide_pr_refs=Skrýt požadavky na natažení
|
commit_graph.hide_pr_refs=Skrýt požadavky na natažení
|
||||||
@ -1518,7 +1526,11 @@ issues.label_title=Název štítku
|
|||||||
issues.label_description=Popis štítku
|
issues.label_description=Popis štítku
|
||||||
issues.label_color=Barva štítku
|
issues.label_color=Barva štítku
|
||||||
issues.label_exclusive=Exkluzivní
|
issues.label_exclusive=Exkluzivní
|
||||||
|
issues.label_archive=Archivovat štítek
|
||||||
issues.label_archived_filter=Zobrazit archivované popisky
|
issues.label_archived_filter=Zobrazit archivované popisky
|
||||||
|
issues.label_archive_tooltip=Archivované štítky jsou ve výchozím nastavení vyloučeny z návrhů při hledání podle popisku.
|
||||||
|
issues.label_exclusive_desc=Pojmenujte štítek <code>rozsah/položka</code>, aby se stal vzájemně exkluzivním s jinými štítky <code>rozsah/</code>.
|
||||||
|
issues.label_exclusive_warning=Jakékoliv protichůdné rozsahy štítků budou odstraněny při úpravě štítků u úkolů nebo u požadavku na natažení.
|
||||||
issues.label_count=%d štítků
|
issues.label_count=%d štítků
|
||||||
issues.label_open_issues=%d otevřených úkolů
|
issues.label_open_issues=%d otevřených úkolů
|
||||||
issues.label_edit=Upravit
|
issues.label_edit=Upravit
|
||||||
@ -1619,6 +1631,7 @@ issues.dependency.issue_closing_blockedby=Uzavření tohoto úkolu je blokováno
|
|||||||
issues.dependency.issue_close_blocks=Tento úkol blokuje uzavření následujících úkolů
|
issues.dependency.issue_close_blocks=Tento úkol blokuje uzavření následujících úkolů
|
||||||
issues.dependency.pr_close_blocks=Tento požadavek na natažení blokuje uzavření následujících úkolů
|
issues.dependency.pr_close_blocks=Tento požadavek na natažení blokuje uzavření následujících úkolů
|
||||||
issues.dependency.issue_close_blocked=Musíte zavřít všechny úkoly, které blokují tento úkol, aby jej bylo možné zavřít.
|
issues.dependency.issue_close_blocked=Musíte zavřít všechny úkoly, které blokují tento úkol, aby jej bylo možné zavřít.
|
||||||
|
issues.dependency.issue_batch_close_blocked=Nelze uzavřít úkoly, které jste vybrali, protože úkol #%d má stále otevřené závislosti
|
||||||
issues.dependency.pr_close_blocked=Musíte zavřít všechny úkoly, které blokují tento požadavek na natažení, aby jej bylo možné sloučit.
|
issues.dependency.pr_close_blocked=Musíte zavřít všechny úkoly, které blokují tento požadavek na natažení, aby jej bylo možné sloučit.
|
||||||
issues.dependency.blocks_short=Blokuje
|
issues.dependency.blocks_short=Blokuje
|
||||||
issues.dependency.blocked_by_short=Závisí na
|
issues.dependency.blocked_by_short=Závisí na
|
||||||
@ -1700,6 +1713,7 @@ pulls.select_commit_hold_shift_for_range=Vyberte commit. Podržte klávesu shift
|
|||||||
pulls.review_only_possible_for_full_diff=Posouzení je možné pouze při zobrazení plného rozlišení
|
pulls.review_only_possible_for_full_diff=Posouzení je možné pouze při zobrazení plného rozlišení
|
||||||
pulls.filter_changes_by_commit=Filtrovat podle commitu
|
pulls.filter_changes_by_commit=Filtrovat podle commitu
|
||||||
pulls.nothing_to_compare=Tyto větve jsou stejné. Není potřeba vytvářet požadavek na natažení.
|
pulls.nothing_to_compare=Tyto větve jsou stejné. Není potřeba vytvářet požadavek na natažení.
|
||||||
|
pulls.nothing_to_compare_have_tag=Vybraná větev/značka je stejná.
|
||||||
pulls.nothing_to_compare_and_allow_empty_pr=Tyto větve jsou stejné. Tento požadavek na natažení bude prázdný.
|
pulls.nothing_to_compare_and_allow_empty_pr=Tyto větve jsou stejné. Tento požadavek na natažení bude prázdný.
|
||||||
pulls.has_pull_request=`Požadavek na natažení mezi těmito větvemi již existuje: <a href="%[1]s">%[2]s#%[3]d</a>`
|
pulls.has_pull_request=`Požadavek na natažení mezi těmito větvemi již existuje: <a href="%[1]s">%[2]s#%[3]d</a>`
|
||||||
pulls.create=Vytvořit požadavek na natažení
|
pulls.create=Vytvořit požadavek na natažení
|
||||||
@ -1822,6 +1836,7 @@ milestones.update_ago=Aktualizováno %s
|
|||||||
milestones.no_due_date=Bez lhůty dokončení
|
milestones.no_due_date=Bez lhůty dokončení
|
||||||
milestones.open=Otevřít
|
milestones.open=Otevřít
|
||||||
milestones.close=Zavřít
|
milestones.close=Zavřít
|
||||||
|
milestones.new_subheader=Milníky vám pomohou organizovat úkoly a sledovat jejich pokrok.
|
||||||
milestones.completeness=%d%% Dokončeno
|
milestones.completeness=%d%% Dokončeno
|
||||||
milestones.create=Vytvořit milník
|
milestones.create=Vytvořit milník
|
||||||
milestones.title=Název
|
milestones.title=Název
|
||||||
@ -1955,6 +1970,7 @@ activity.git_stats_and_deletions=a
|
|||||||
activity.git_stats_deletion_1=%d odebrání
|
activity.git_stats_deletion_1=%d odebrání
|
||||||
activity.git_stats_deletion_n=%d odebrání
|
activity.git_stats_deletion_n=%d odebrání
|
||||||
|
|
||||||
|
contributors.contribution_type.filter_label=Typ příspěvku:
|
||||||
contributors.contribution_type.commits=Commity
|
contributors.contribution_type.commits=Commity
|
||||||
|
|
||||||
search=Vyhledat
|
search=Vyhledat
|
||||||
@ -2341,6 +2357,7 @@ settings.matrix.room_id=ID místnosti
|
|||||||
settings.matrix.message_type=Typ zprávy
|
settings.matrix.message_type=Typ zprávy
|
||||||
settings.archive.button=Archivovat repozitář
|
settings.archive.button=Archivovat repozitář
|
||||||
settings.archive.header=Archivovat tento repozitář
|
settings.archive.header=Archivovat tento repozitář
|
||||||
|
settings.archive.text=Archivace repozitáře způsobí, že bude zcela určen pouze pro čtení. Bude skryt z ovládacího panelu. Nikdo (ani vy!) nebude moci vytvářet nové revize ani otevírat nové úkoly nebo žádosti o natažení.
|
||||||
settings.archive.success=Repozitář byl úspěšně archivován.
|
settings.archive.success=Repozitář byl úspěšně archivován.
|
||||||
settings.archive.error=Nastala chyba při archivování repozitáře. Prohlédněte si záznam pro více detailů.
|
settings.archive.error=Nastala chyba při archivování repozitáře. Prohlédněte si záznam pro více detailů.
|
||||||
settings.archive.error_ismirror=Nemůžete archivovat zrcadlený repozitář.
|
settings.archive.error_ismirror=Nemůžete archivovat zrcadlený repozitář.
|
||||||
@ -2545,6 +2562,11 @@ error.csv.unexpected=Tento soubor nelze vykreslit, protože obsahuje neočekáva
|
|||||||
error.csv.invalid_field_count=Soubor nelze vykreslit, protože má nesprávný počet polí na řádku %d.
|
error.csv.invalid_field_count=Soubor nelze vykreslit, protože má nesprávný počet polí na řádku %d.
|
||||||
|
|
||||||
[graphs]
|
[graphs]
|
||||||
|
component_loading=Načítání %s...
|
||||||
|
component_loading_failed=Nelze načíst %s
|
||||||
|
component_loading_info=Může to chvíli trvat…
|
||||||
|
component_failed_to_load=Došlo k neočekávané chybě.
|
||||||
|
contributors.what=příspěvky
|
||||||
|
|
||||||
[org]
|
[org]
|
||||||
org_name_holder=Název organizace
|
org_name_holder=Název organizace
|
||||||
@ -2715,6 +2737,7 @@ dashboard.delete_repo_archives.started=Spuštěna úloha smazání všech archiv
|
|||||||
dashboard.delete_missing_repos=Smazat všechny repozitáře, které nemají Git soubory
|
dashboard.delete_missing_repos=Smazat všechny repozitáře, které nemají Git soubory
|
||||||
dashboard.delete_missing_repos.started=Spuštěna úloha mazání všech repozitářů, které nemají Git soubory.
|
dashboard.delete_missing_repos.started=Spuštěna úloha mazání všech repozitářů, které nemají Git soubory.
|
||||||
dashboard.delete_generated_repository_avatars=Odstranit vygenerované avatary repozitářů
|
dashboard.delete_generated_repository_avatars=Odstranit vygenerované avatary repozitářů
|
||||||
|
dashboard.sync_repo_tags=Synchronizovat značky z git dat do databáze
|
||||||
dashboard.update_mirrors=Aktualizovat zrcadla
|
dashboard.update_mirrors=Aktualizovat zrcadla
|
||||||
dashboard.repo_health_check=Kontrola stavu všech repozitářů
|
dashboard.repo_health_check=Kontrola stavu všech repozitářů
|
||||||
dashboard.check_repo_stats=Zkontrolovat všechny statistiky repositáře
|
dashboard.check_repo_stats=Zkontrolovat všechny statistiky repositáře
|
||||||
@ -2762,11 +2785,14 @@ dashboard.delete_old_actions=Odstranit všechny staré akce z databáze
|
|||||||
dashboard.delete_old_actions.started=Začalo odstraňování všech starých akcí z databáze.
|
dashboard.delete_old_actions.started=Začalo odstraňování všech starých akcí z databáze.
|
||||||
dashboard.update_checker=Kontrola aktualizací
|
dashboard.update_checker=Kontrola aktualizací
|
||||||
dashboard.delete_old_system_notices=Odstranit všechna stará systémová upozornění z databáze
|
dashboard.delete_old_system_notices=Odstranit všechna stará systémová upozornění z databáze
|
||||||
|
dashboard.gc_lfs=Úklid LFS meta objektů
|
||||||
dashboard.stop_zombie_tasks=Zastavit zombie úlohy
|
dashboard.stop_zombie_tasks=Zastavit zombie úlohy
|
||||||
dashboard.stop_endless_tasks=Zastavit nekonečné úlohy
|
dashboard.stop_endless_tasks=Zastavit nekonečné úlohy
|
||||||
dashboard.cancel_abandoned_jobs=Zrušit opuštěné úlohy
|
dashboard.cancel_abandoned_jobs=Zrušit opuštěné úlohy
|
||||||
dashboard.start_schedule_tasks=Spustit naplánované úlohy
|
dashboard.start_schedule_tasks=Spustit naplánované úlohy
|
||||||
dashboard.sync_branch.started=Synchronizace větví byla spuštěna
|
dashboard.sync_branch.started=Synchronizace větví byla spuštěna
|
||||||
|
dashboard.sync_tag.started=Synchronizace značek spuštěna
|
||||||
|
dashboard.rebuild_issue_indexer=Znovu sestavit index úkolů
|
||||||
|
|
||||||
users.user_manage_panel=Správa uživatelských účtů
|
users.user_manage_panel=Správa uživatelských účtů
|
||||||
users.new_account=Vytvořit uživatelský účet
|
users.new_account=Vytvořit uživatelský účet
|
||||||
@ -3184,6 +3210,12 @@ notices.desc=Popis
|
|||||||
notices.op=Akce
|
notices.op=Akce
|
||||||
notices.delete_success=Systémové upozornění bylo smazáno.
|
notices.delete_success=Systémové upozornění bylo smazáno.
|
||||||
|
|
||||||
|
self_check.no_problem_found=Zatím nebyl nalezen žádný problém.
|
||||||
|
self_check.database_collation_mismatch=Očekávejte, že databáze použije collation: %s
|
||||||
|
self_check.database_collation_case_insensitive=Databáze používá collation %s, což je collation nerozlišující velká a malá písmena. Ačkoli s ní Gitea může pracovat, mohou se vyskytnout vzácné případy, kdy nebude fungovat podle očekávání.
|
||||||
|
self_check.database_inconsistent_collation_columns=Databáze používá collation %s, ale tyto sloupce používají chybné collation. To může způsobit neočekávané problémy.
|
||||||
|
self_check.database_fix_mysql=Pro uživatele MySQL/MariaDB můžete použít příkaz "gitea doctor convert", který opraví problémy s collation, nebo můžete také problém vyřešit příkazem "ALTER ... COLLATE ..." SQL ručně.
|
||||||
|
self_check.database_fix_mssql=Uživatelé MSSQL mohou problém vyřešit pouze pomocí příkazu "ALTER ... COLLATE ..." SQL ručně.
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo=vytvořil/a repozitář <a href="%s">%s</a>
|
create_repo=vytvořil/a repozitář <a href="%s">%s</a>
|
||||||
@ -3371,6 +3403,7 @@ rpm.distros.suse=na distribuce založené na SUSE
|
|||||||
rpm.install=Pro instalaci balíčku spusťte následující příkaz:
|
rpm.install=Pro instalaci balíčku spusťte následující příkaz:
|
||||||
rpm.repository=Informace o repozitáři
|
rpm.repository=Informace o repozitáři
|
||||||
rpm.repository.architectures=Architektury
|
rpm.repository.architectures=Architektury
|
||||||
|
rpm.repository.multiple_groups=Tento balíček je k dispozici ve více skupinách.
|
||||||
rubygems.install=Pro instalaci balíčku pomocí gem spusťte následující příkaz:
|
rubygems.install=Pro instalaci balíčku pomocí gem spusťte následující příkaz:
|
||||||
rubygems.install2=nebo ho přidejte do Gemfie:
|
rubygems.install2=nebo ho přidejte do Gemfie:
|
||||||
rubygems.dependencies.runtime=Běhové závislosti
|
rubygems.dependencies.runtime=Běhové závislosti
|
||||||
@ -3498,6 +3531,8 @@ runs.actors_no_select=Všichni aktéři
|
|||||||
runs.status_no_select=Všechny stavy
|
runs.status_no_select=Všechny stavy
|
||||||
runs.no_results=Nebyly nalezeny žádné výsledky.
|
runs.no_results=Nebyly nalezeny žádné výsledky.
|
||||||
runs.no_workflows=Zatím neexistují žádné pracovní postupy.
|
runs.no_workflows=Zatím neexistují žádné pracovní postupy.
|
||||||
|
runs.no_workflows.quick_start=Nevíte jak začít s Gitea Actions? Podívejte se na <a target="_blank" rel="noopener noreferrer" href="%s">průvodce rychlým startem</a>.
|
||||||
|
runs.no_workflows.documentation=Další informace o Gitea Actions naleznete v <a target="_blank" rel="noopener noreferrer" href="%s">dokumentaci</a>.
|
||||||
runs.no_runs=Pracovní postup zatím nebyl spuštěn.
|
runs.no_runs=Pracovní postup zatím nebyl spuštěn.
|
||||||
runs.empty_commit_message=(prázdná zpráva commitu)
|
runs.empty_commit_message=(prázdná zpráva commitu)
|
||||||
|
|
||||||
@ -3515,6 +3550,7 @@ variables.none=Zatím nejsou žádné proměnné.
|
|||||||
variables.deletion=Odstranit proměnnou
|
variables.deletion=Odstranit proměnnou
|
||||||
variables.deletion.description=Odstranění proměnné je trvalé a nelze jej vrátit zpět. Pokračovat?
|
variables.deletion.description=Odstranění proměnné je trvalé a nelze jej vrátit zpět. Pokračovat?
|
||||||
variables.description=Proměnné budou předány určitým akcím a nelze je přečíst jinak.
|
variables.description=Proměnné budou předány určitým akcím a nelze je přečíst jinak.
|
||||||
|
variables.id_not_exist=Proměnná s ID %d neexistuje.
|
||||||
variables.edit=Upravit proměnnou
|
variables.edit=Upravit proměnnou
|
||||||
variables.deletion.failed=Nepodařilo se odstranit proměnnou.
|
variables.deletion.failed=Nepodařilo se odstranit proměnnou.
|
||||||
variables.deletion.success=Proměnná byla odstraněna.
|
variables.deletion.success=Proměnná byla odstraněna.
|
||||||
|
@ -368,7 +368,7 @@ forgot_password_title= Forgot Password
|
|||||||
forgot_password = Forgot password?
|
forgot_password = Forgot password?
|
||||||
sign_up_now = Need an account? Register now.
|
sign_up_now = Need an account? Register now.
|
||||||
sign_up_successful = Account was successfully created. Welcome!
|
sign_up_successful = Account was successfully created. Welcome!
|
||||||
confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the registration process.
|
confirmation_mail_sent_prompt_ex = A new confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the registration process. If your registration email address is incorrect, you can sign in again and change it.
|
||||||
must_change_password = Update your password
|
must_change_password = Update your password
|
||||||
allow_password_change = Require user to change password (recommended)
|
allow_password_change = Require user to change password (recommended)
|
||||||
reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the account recovery process.
|
reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the account recovery process.
|
||||||
@ -378,6 +378,7 @@ prohibit_login = Sign In Prohibited
|
|||||||
prohibit_login_desc = Your account is prohibited from signing in, please contact your site administrator.
|
prohibit_login_desc = Your account is prohibited from signing in, please contact your site administrator.
|
||||||
resent_limit_prompt = You have already requested an activation email recently. Please wait 3 minutes and try again.
|
resent_limit_prompt = You have already requested an activation email recently. Please wait 3 minutes and try again.
|
||||||
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
|
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
|
||||||
|
change_unconfirmed_mail_address = If your registration email address is incorrect, you can change it here and resend a new confirmation email.
|
||||||
resend_mail = Click here to resend your activation email
|
resend_mail = Click here to resend your activation email
|
||||||
email_not_associate = The email address is not associated with any account.
|
email_not_associate = The email address is not associated with any account.
|
||||||
send_reset_mail = Send Account Recovery Email
|
send_reset_mail = Send Account Recovery Email
|
||||||
|
@ -424,6 +424,7 @@ authorization_failed_desc=L'autorisation a échoué car nous avons détecté une
|
|||||||
sspi_auth_failed=Échec de l'authentification SSPI
|
sspi_auth_failed=Échec de l'authentification SSPI
|
||||||
password_pwned=Le mot de passe que vous avez choisi se trouve sur la liste <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">des mots de passe ayant fuité</a> sur internet. Veuillez réessayer avec un mot de passe différent et considérer remplacer ce mot de passe si vous l'utilisez ailleurs.
|
password_pwned=Le mot de passe que vous avez choisi se trouve sur la liste <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">des mots de passe ayant fuité</a> sur internet. Veuillez réessayer avec un mot de passe différent et considérer remplacer ce mot de passe si vous l'utilisez ailleurs.
|
||||||
password_pwned_err=Impossible d'envoyer la demande à HaveIBeenPwned
|
password_pwned_err=Impossible d'envoyer la demande à HaveIBeenPwned
|
||||||
|
last_admin=Vous ne pouvez pas supprimer ce compte car au moins un administrateur est requis.
|
||||||
|
|
||||||
[mail]
|
[mail]
|
||||||
view_it_on=Voir sur %s
|
view_it_on=Voir sur %s
|
||||||
@ -1714,6 +1715,7 @@ pulls.select_commit_hold_shift_for_range=Maintenir Maj et cliquer sur des révis
|
|||||||
pulls.review_only_possible_for_full_diff=Une évaluation n'est possible que lorsque vous affichez le différentiel complet.
|
pulls.review_only_possible_for_full_diff=Une évaluation n'est possible que lorsque vous affichez le différentiel complet.
|
||||||
pulls.filter_changes_by_commit=Filtrer par révision
|
pulls.filter_changes_by_commit=Filtrer par révision
|
||||||
pulls.nothing_to_compare=Ces branches sont identiques. Il n’y a pas besoin de créer une demande d'ajout.
|
pulls.nothing_to_compare=Ces branches sont identiques. Il n’y a pas besoin de créer une demande d'ajout.
|
||||||
|
pulls.nothing_to_compare_have_tag=Les branches/étiquettes sélectionnées sont équivalentes.
|
||||||
pulls.nothing_to_compare_and_allow_empty_pr=Ces branches sont égales. Cette demande d'ajout sera vide.
|
pulls.nothing_to_compare_and_allow_empty_pr=Ces branches sont égales. Cette demande d'ajout sera vide.
|
||||||
pulls.has_pull_request='Il existe déjà une demande d'ajout entre ces deux branches : <a href="%[1]s">%[2]s#%[3]d</a>'
|
pulls.has_pull_request='Il existe déjà une demande d'ajout entre ces deux branches : <a href="%[1]s">%[2]s#%[3]d</a>'
|
||||||
pulls.create=Créer une demande d'ajout
|
pulls.create=Créer une demande d'ajout
|
||||||
|
@ -2119,7 +2119,7 @@ settings.trust_model.collaborator.long=协作者:信任协作者的签名
|
|||||||
settings.trust_model.collaborator.desc=此仓库中协作者的有效签名将被标记为「可信」(无论它们是否是提交者),签名只符合提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。
|
settings.trust_model.collaborator.desc=此仓库中协作者的有效签名将被标记为「可信」(无论它们是否是提交者),签名只符合提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。
|
||||||
settings.trust_model.committer=提交者
|
settings.trust_model.committer=提交者
|
||||||
settings.trust_model.committer.long=提交者: 信任与提交者相符的签名 (此特性类似 GitHub,这会强制采用 Gitea 作为提交者和签名者)
|
settings.trust_model.committer.long=提交者: 信任与提交者相符的签名 (此特性类似 GitHub,这会强制采用 Gitea 作为提交者和签名者)
|
||||||
settings.trust_model.committer.desc=有效签名只有和提交者相匹配才会被标记为“受信任”,否则它们将被标记为“不匹配”。这强制 Gitea 成为签名提交的提交者,而实际提交者被加上 Co-authored-by: 和 Co-committed-by: 的标记。 默认的 Gitea 密钥必须撇撇数据库种的一名用户。
|
settings.trust_model.committer.desc=有效签名只有和提交者相匹配才会被标记为“受信任”,否则它们将被标记为“不匹配”。这强制 Gitea 成为签名提交的提交者,而实际提交者被加上 Co-authored-by: 和 Co-committed-by: 的标记。 默认的 Gitea 密钥必须匹配数据库中的一名用户。
|
||||||
settings.trust_model.collaboratorcommitter=协作者+提交者
|
settings.trust_model.collaboratorcommitter=协作者+提交者
|
||||||
settings.trust_model.collaboratorcommitter.long=协作者+提交者:信任协作者同时是提交者的签名
|
settings.trust_model.collaboratorcommitter.long=协作者+提交者:信任协作者同时是提交者的签名
|
||||||
settings.trust_model.collaboratorcommitter.desc=此仓库中协作者的有效签名在他同时是提交者时将被标记为「可信」,签名只匹配了提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。这会强制 Gitea 成为签名者和提交者,实际的提交者将被标记于提交消息结尾处的「Co-Authored-By:」和「Co-Committed-By:」。默认的 Gitea 签名密钥必须匹配数据库中的一个用户密钥。
|
settings.trust_model.collaboratorcommitter.desc=此仓库中协作者的有效签名在他同时是提交者时将被标记为「可信」,签名只匹配了提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。这会强制 Gitea 成为签名者和提交者,实际的提交者将被标记于提交消息结尾处的「Co-Authored-By:」和「Co-Committed-By:」。默认的 Gitea 签名密钥必须匹配数据库中的一个用户密钥。
|
||||||
@ -3250,7 +3250,9 @@ notices.delete_success=系统通知已被删除。
|
|||||||
self_check.no_problem_found=尚未发现问题。
|
self_check.no_problem_found=尚未发现问题。
|
||||||
self_check.database_collation_mismatch=期望数据库使用的校验方式:%s
|
self_check.database_collation_mismatch=期望数据库使用的校验方式:%s
|
||||||
self_check.database_collation_case_insensitive=数据库正在使用一个校验 %s, 这是一个不敏感的校验. 虽然Gitea可以与它合作,但可能有一些罕见的情况不如预期的那样起作用。
|
self_check.database_collation_case_insensitive=数据库正在使用一个校验 %s, 这是一个不敏感的校验. 虽然Gitea可以与它合作,但可能有一些罕见的情况不如预期的那样起作用。
|
||||||
|
self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。
|
||||||
self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。
|
self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。
|
||||||
|
self_check.database_fix_mssql=对于MSSQL用户,您现在只能通过"ALTER ... COLLATE ..."SQLs手动解决这个问题。
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo=创建了仓库 <a href="%s">%s</a>
|
create_repo=创建了仓库 <a href="%s">%s</a>
|
||||||
|
@ -71,7 +71,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/actions"
|
"code.gitea.io/gitea/models/actions"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -80,6 +79,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
web_types "code.gitea.io/gitea/modules/web/types"
|
web_types "code.gitea.io/gitea/modules/web/types"
|
||||||
actions_service "code.gitea.io/gitea/services/actions"
|
actions_service "code.gitea.io/gitea/services/actions"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
const artifactRouteBase = "/_apis/pipelines/workflows/{run_id}/artifacts"
|
const artifactRouteBase = "/_apis/pipelines/workflows/{run_id}/artifacts"
|
||||||
|
@ -14,12 +14,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
alpine_module "code.gitea.io/gitea/modules/packages/alpine"
|
alpine_module "code.gitea.io/gitea/modules/packages/alpine"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
alpine_service "code.gitea.io/gitea/services/packages/alpine"
|
alpine_service "code.gitea.io/gitea/services/packages/alpine"
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
@ -36,7 +35,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/packages/swift"
|
"code.gitea.io/gitea/routers/api/packages/swift"
|
||||||
"code.gitea.io/gitea/routers/api/packages/vagrant"
|
"code.gitea.io/gitea/routers/api/packages/vagrant"
|
||||||
"code.gitea.io/gitea/services/auth"
|
"code.gitea.io/gitea/services/auth"
|
||||||
context_service "code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
|
func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
|
||||||
@ -642,7 +641,7 @@ func CommonRoutes() *web.Route {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, reqPackageAccess(perm.AccessModeRead))
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
}, context_service.UserAssignmentWeb(), context.PackageAssignment())
|
}, context.UserAssignmentWeb(), context.PackageAssignment())
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@ -812,7 +811,7 @@ func ContainerRoutes() *web.Route {
|
|||||||
|
|
||||||
ctx.Status(http.StatusNotFound)
|
ctx.Status(http.StatusNotFound)
|
||||||
})
|
})
|
||||||
}, container.ReqContainerAccess, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
}, container.ReqContainerAccess, context.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
cargo_module "code.gitea.io/gitea/modules/packages/cargo"
|
cargo_module "code.gitea.io/gitea/modules/packages/cargo"
|
||||||
@ -20,6 +19,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
cargo_service "code.gitea.io/gitea/services/packages/cargo"
|
cargo_service "code.gitea.io/gitea/services/packages/cargo"
|
||||||
|
@ -15,12 +15,12 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
chef_module "code.gitea.io/gitea/modules/packages/chef"
|
chef_module "code.gitea.io/gitea/modules/packages/chef"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,12 +14,12 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
|
@ -15,13 +15,13 @@ import (
|
|||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
conan_model "code.gitea.io/gitea/models/packages/conan"
|
conan_model "code.gitea.io/gitea/models/packages/conan"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
notify_service "code.gitea.io/gitea/services/notify"
|
notify_service "code.gitea.io/gitea/services/notify"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
conan_model "code.gitea.io/gitea/models/packages/conan"
|
conan_model "code.gitea.io/gitea/models/packages/conan"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SearchResult contains the found recipe names
|
// SearchResult contains the found recipe names
|
||||||
|
@ -12,13 +12,13 @@ import (
|
|||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
conda_model "code.gitea.io/gitea/models/packages/conda"
|
conda_model "code.gitea.io/gitea/models/packages/conda"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
conda_module "code.gitea.io/gitea/modules/packages/conda"
|
conda_module "code.gitea.io/gitea/modules/packages/conda"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
"github.com/dsnet/compress/bzip2"
|
"github.com/dsnet/compress/bzip2"
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
container_model "code.gitea.io/gitea/models/packages/container"
|
container_model "code.gitea.io/gitea/models/packages/container"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
@ -25,6 +24,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
container_service "code.gitea.io/gitea/services/packages/container"
|
container_service "code.gitea.io/gitea/services/packages/container"
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
cran_model "code.gitea.io/gitea/models/packages/cran"
|
cran_model "code.gitea.io/gitea/models/packages/cran"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
cran_module "code.gitea.io/gitea/modules/packages/cran"
|
cran_module "code.gitea.io/gitea/modules/packages/cran"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
debian_module "code.gitea.io/gitea/modules/packages/debian"
|
debian_module "code.gitea.io/gitea/modules/packages/debian"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
notify_service "code.gitea.io/gitea/services/notify"
|
notify_service "code.gitea.io/gitea/services/notify"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
debian_service "code.gitea.io/gitea/services/packages/debian"
|
debian_service "code.gitea.io/gitea/services/packages/debian"
|
||||||
|
@ -10,10 +10,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
goproxy_module "code.gitea.io/gitea/modules/packages/goproxy"
|
goproxy_module "code.gitea.io/gitea/modules/packages/goproxy"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
@ -21,6 +20,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
@ -10,9 +10,9 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogAndProcessError logs an error and calls a custom callback with the processed error message.
|
// LogAndProcessError logs an error and calls a custom callback with the processed error message.
|
||||||
|
@ -20,12 +20,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
maven_module "code.gitea.io/gitea/modules/packages/maven"
|
maven_module "code.gitea.io/gitea/modules/packages/maven"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,12 +17,12 @@ import (
|
|||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
npm_module "code.gitea.io/gitea/modules/packages/npm"
|
npm_module "code.gitea.io/gitea/modules/packages/npm"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
|
@ -17,13 +17,13 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
nuget_model "code.gitea.io/gitea/models/packages/nuget"
|
nuget_model "code.gitea.io/gitea/models/packages/nuget"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
@ -22,6 +21,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
pypi_module "code.gitea.io/gitea/modules/packages/pypi"
|
pypi_module "code.gitea.io/gitea/modules/packages/pypi"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/validation"
|
"code.gitea.io/gitea/modules/validation"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,13 +13,13 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
|
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
notify_service "code.gitea.io/gitea/services/notify"
|
notify_service "code.gitea.io/gitea/services/notify"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
rpm_service "code.gitea.io/gitea/services/packages/rpm"
|
rpm_service "code.gitea.io/gitea/services/packages/rpm"
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
rubygems_module "code.gitea.io/gitea/modules/packages/rubygems"
|
rubygems_module "code.gitea.io/gitea/modules/packages/rubygems"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
@ -21,6 +20,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
|
@ -12,11 +12,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
vagrant_module "code.gitea.io/gitea/modules/packages/vagrant"
|
vagrant_module "code.gitea.io/gitea/modules/packages/vagrant"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
|
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
|
@ -9,9 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/activitypub"
|
"code.gitea.io/gitea/modules/activitypub"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/go-ap/jsonld"
|
"github.com/go-ap/jsonld"
|
||||||
|
@ -13,9 +13,9 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/activitypub"
|
"code.gitea.io/gitea/modules/activitypub"
|
||||||
gitea_context "code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/httplib"
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
gitea_context "code.gitea.io/gitea/services/context"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/go-fed/httpsig"
|
"github.com/go-fed/httpsig"
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
repo_service "code.gitea.io/gitea/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/cron"
|
"code.gitea.io/gitea/services/cron"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
webhook_service "code.gitea.io/gitea/services/webhook"
|
webhook_service "code.gitea.io/gitea/services/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/repo"
|
"code.gitea.io/gitea/routers/api/v1/repo"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateRepo api for creating a repository
|
// CreateRepo api for creating a repository
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/routers/api/v1/shared"
|
"code.gitea.io/gitea/routers/api/v1/shared"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
|
// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/auth/password"
|
"code.gitea.io/gitea/modules/auth/password"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -25,6 +24,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
"code.gitea.io/gitea/routers/api/v1/user"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
"code.gitea.io/gitea/services/mailer"
|
"code.gitea.io/gitea/services/mailer"
|
||||||
user_service "code.gitea.io/gitea/services/user"
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
|
124
routers/api/v1/admin/user_badge.go
Normal file
124
routers/api/v1/admin/user_badge.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListUserBadges lists all badges belonging to a user
|
||||||
|
func ListUserBadges(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /admin/users/{username}/badges admin adminListUserBadges
|
||||||
|
// ---
|
||||||
|
// summary: List a user's badges
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/BadgeList"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
badges, maxResults, err := user_model.GetUserBadges(ctx, ctx.ContextUser)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetUserBadges", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetTotalCountHeader(maxResults)
|
||||||
|
ctx.JSON(http.StatusOK, &badges)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUserBadges add badges to a user
|
||||||
|
func AddUserBadges(ctx *context.APIContext) {
|
||||||
|
// swagger:operation POST /admin/users/{username}/badges admin adminAddUserBadges
|
||||||
|
// ---
|
||||||
|
// summary: Add a badge to a user
|
||||||
|
// consumes:
|
||||||
|
// - application/json
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/UserBadgeOption"
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
|
form := web.GetForm(ctx).(*api.UserBadgeOption)
|
||||||
|
badges := prepareBadgesForReplaceOrAdd(ctx, *form)
|
||||||
|
|
||||||
|
if err := user_model.AddUserBadges(ctx, ctx.ContextUser, badges); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserBadges delete a badge from a user
|
||||||
|
func DeleteUserBadges(ctx *context.APIContext) {
|
||||||
|
// swagger:operation DELETE /admin/users/{username}/badges admin adminDeleteUserBadges
|
||||||
|
// ---
|
||||||
|
// summary: Remove a badge from a user
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/UserBadgeOption"
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
// "422":
|
||||||
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
|
form := web.GetForm(ctx).(*api.UserBadgeOption)
|
||||||
|
badges := prepareBadgesForReplaceOrAdd(ctx, *form)
|
||||||
|
|
||||||
|
if err := user_model.RemoveUserBadges(ctx, ctx.ContextUser, badges); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareBadgesForReplaceOrAdd(ctx *context.APIContext, form api.UserBadgeOption) []*user_model.Badge {
|
||||||
|
badges := make([]*user_model.Badge, len(form.BadgeSlugs))
|
||||||
|
for i, badge := range form.BadgeSlugs {
|
||||||
|
badges[i] = &user_model.Badge{
|
||||||
|
Slug: badge,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return badges
|
||||||
|
}
|
@ -79,7 +79,6 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
@ -95,7 +94,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
"code.gitea.io/gitea/routers/api/v1/user"
|
||||||
"code.gitea.io/gitea/routers/common"
|
"code.gitea.io/gitea/routers/common"
|
||||||
"code.gitea.io/gitea/services/auth"
|
"code.gitea.io/gitea/services/auth"
|
||||||
context_service "code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
|
||||||
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
|
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
|
||||||
@ -855,11 +854,11 @@ func Routes() *web.Route {
|
|||||||
m.Group("/user/{username}", func() {
|
m.Group("/user/{username}", func() {
|
||||||
m.Get("", activitypub.Person)
|
m.Get("", activitypub.Person)
|
||||||
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
|
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
|
||||||
}, context_service.UserAssignmentAPI())
|
}, context.UserAssignmentAPI())
|
||||||
m.Group("/user-id/{user-id}", func() {
|
m.Group("/user-id/{user-id}", func() {
|
||||||
m.Get("", activitypub.Person)
|
m.Get("", activitypub.Person)
|
||||||
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
|
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
|
||||||
}, context_service.UserIDAssignmentAPI())
|
}, context.UserIDAssignmentAPI())
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub))
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -915,7 +914,7 @@ func Routes() *web.Route {
|
|||||||
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
|
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
|
||||||
|
|
||||||
m.Get("/activities/feeds", user.ListUserActivityFeeds)
|
m.Get("/activities/feeds", user.ListUserActivityFeeds)
|
||||||
}, context_service.UserAssignmentAPI(), individualPermsChecker)
|
}, context.UserAssignmentAPI(), individualPermsChecker)
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
|
||||||
|
|
||||||
// Users (requires user scope)
|
// Users (requires user scope)
|
||||||
@ -933,7 +932,7 @@ func Routes() *web.Route {
|
|||||||
m.Get("/starred", user.GetStarredRepos)
|
m.Get("/starred", user.GetStarredRepos)
|
||||||
|
|
||||||
m.Get("/subscriptions", user.GetWatchedRepos)
|
m.Get("/subscriptions", user.GetWatchedRepos)
|
||||||
}, context_service.UserAssignmentAPI())
|
}, context.UserAssignmentAPI())
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
|
||||||
|
|
||||||
// Users (requires user scope)
|
// Users (requires user scope)
|
||||||
@ -968,7 +967,7 @@ func Routes() *web.Route {
|
|||||||
m.Get("", user.CheckMyFollowing)
|
m.Get("", user.CheckMyFollowing)
|
||||||
m.Put("", user.Follow)
|
m.Put("", user.Follow)
|
||||||
m.Delete("", user.Unfollow)
|
m.Delete("", user.Unfollow)
|
||||||
}, context_service.UserAssignmentAPI())
|
}, context.UserAssignmentAPI())
|
||||||
})
|
})
|
||||||
|
|
||||||
// (admin:public_key scope)
|
// (admin:public_key scope)
|
||||||
@ -1415,14 +1414,14 @@ func Routes() *web.Route {
|
|||||||
m.Get("/files", reqToken(), packages.ListPackageFiles)
|
m.Get("/files", reqToken(), packages.ListPackageFiles)
|
||||||
})
|
})
|
||||||
m.Get("/", reqToken(), packages.ListPackages)
|
m.Get("/", reqToken(), packages.ListPackages)
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
|
||||||
|
|
||||||
// Organizations
|
// Organizations
|
||||||
m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
|
m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
|
||||||
m.Group("/users/{username}/orgs", func() {
|
m.Group("/users/{username}/orgs", func() {
|
||||||
m.Get("", reqToken(), org.ListUserOrgs)
|
m.Get("", reqToken(), org.ListUserOrgs)
|
||||||
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
|
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context_service.UserAssignmentAPI())
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI())
|
||||||
m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create)
|
m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create)
|
||||||
m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
|
m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
|
||||||
m.Group("/orgs/{org}", func() {
|
m.Group("/orgs/{org}", func() {
|
||||||
@ -1520,7 +1519,10 @@ func Routes() *web.Route {
|
|||||||
m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
|
m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
|
||||||
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
|
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
|
||||||
m.Post("/rename", bind(api.RenameUserOption{}), admin.RenameUser)
|
m.Post("/rename", bind(api.RenameUserOption{}), admin.RenameUser)
|
||||||
}, context_service.UserAssignmentAPI())
|
m.Get("/badges", admin.ListUserBadges)
|
||||||
|
m.Post("/badges", bind(api.UserBadgeOption{}), admin.AddUserBadges)
|
||||||
|
m.Delete("/badges", bind(api.UserBadgeOption{}), admin.DeleteUserBadges)
|
||||||
|
}, context.UserAssignmentAPI())
|
||||||
})
|
})
|
||||||
m.Group("/emails", func() {
|
m.Group("/emails", func() {
|
||||||
m.Get("", admin.GetAllEmails)
|
m.Get("", admin.GetAllEmails)
|
||||||
|
@ -6,11 +6,11 @@ package misc
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/options"
|
"code.gitea.io/gitea/modules/options"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Shows a list of all Gitignore templates
|
// Shows a list of all Gitignore templates
|
||||||
|
@ -6,9 +6,9 @@ package misc
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/options"
|
"code.gitea.io/gitea/modules/options"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns a list of all License templates
|
// Returns a list of all License templates
|
||||||
|
@ -6,12 +6,12 @@ package misc
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/common"
|
"code.gitea.io/gitea/routers/common"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Markup render markup document to HTML
|
// Markup render markup document to HTML
|
||||||
|
@ -10,19 +10,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/contexttest"
|
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"code.gitea.io/gitea/services/contexttest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AppURL = "http://localhost:3000/"
|
AppURL = "http://localhost:3000/"
|
||||||
Repo = "gogits/gogs"
|
Repo = "gogits/gogs"
|
||||||
AppSubURL = AppURL + Repo + "/"
|
FullURL = AppURL + Repo + "/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) {
|
func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) {
|
||||||
@ -74,20 +74,20 @@ func TestAPI_RenderGFM(t *testing.T) {
|
|||||||
// rendered
|
// rendered
|
||||||
`<p>Wiki! Enjoy :)</p>
|
`<p>Wiki! Enjoy :)</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
|
<li><a href="` + FullURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
|
||||||
<li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li>
|
<li><a href="` + FullURL + `wiki/Tips" rel="nofollow">Tips</a></li>
|
||||||
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="https://github.com/ocornut/imgui/issues/786" rel="nofollow">https://github.com/ocornut/imgui/issues/786</a></li>
|
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="https://github.com/ocornut/imgui/issues/786" rel="nofollow">https://github.com/ocornut/imgui/issues/786</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
// Guard wiki sidebar: special syntax
|
// Guard wiki sidebar: special syntax
|
||||||
`[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`,
|
`[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`,
|
||||||
// rendered
|
// rendered
|
||||||
`<p><a href="` + AppSubURL + `wiki/Guardfile-DSL---Configuring-Guard" rel="nofollow">Guardfile-DSL / Configuring-Guard</a></p>
|
`<p><a href="` + FullURL + `wiki/Guardfile-DSL---Configuring-Guard" rel="nofollow">Guardfile-DSL / Configuring-Guard</a></p>
|
||||||
`,
|
`,
|
||||||
// special syntax
|
// special syntax
|
||||||
`[[Name|Link]]`,
|
`[[Name|Link]]`,
|
||||||
// rendered
|
// rendered
|
||||||
`<p><a href="` + AppSubURL + `wiki/Link" rel="nofollow">Name</a></p>
|
`<p><a href="` + FullURL + `wiki/Link" rel="nofollow">Name</a></p>
|
||||||
`,
|
`,
|
||||||
// empty
|
// empty
|
||||||
``,
|
``,
|
||||||
@ -111,8 +111,8 @@ Here are some links to the most important topics. You can find the full list of
|
|||||||
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
|
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
|
||||||
<h2 id="user-content-quick-links">Quick Links</h2>
|
<h2 id="user-content-quick-links">Quick Links</h2>
|
||||||
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
|
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
|
||||||
<p><a href="` + AppSubURL + `wiki/Configuration" rel="nofollow">Configuration</a>
|
<p><a href="` + FullURL + `wiki/Configuration" rel="nofollow">Configuration</a>
|
||||||
<a href="` + AppSubURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + AppSubURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt="images/icon-bug.png"/></a></p>
|
<a href="` + FullURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + FullURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt="images/icon-bug.png"/></a></p>
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cacheKeyNodeInfoUsage = "API_NodeInfoUsage"
|
const cacheKeyNodeInfoUsage = "API_NodeInfoUsage"
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SigningKey returns the public key of the default signing key if it exists
|
// SigningKey returns the public key of the default signing key if it exists
|
||||||
|
@ -6,9 +6,9 @@ package misc
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version shows the version of the Gitea server
|
// Version shows the version of the Gitea server
|
||||||
|
@ -9,9 +9,9 @@ import (
|
|||||||
|
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/context"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAvailable check if unread notifications exist
|
// NewAvailable check if unread notifications exist
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user