mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-24 13:25:01 +09:00
Compare commits
71 Commits
v1.26.4
...
v1.21.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b670d83e1 | |||
| 9207331f4d | |||
| 44aca6a65a | |||
| aaf35ee49c | |||
| a9d547f55b | |||
| 51001d9ffe | |||
| 1ff6b7783c | |||
| 99e2071eeb | |||
| 1dd84ec3a1 | |||
| 290440e1ee | |||
| 881a844c9d | |||
| d5da0e622c | |||
| 8c6464e39b | |||
| 4f02b4a7b9 | |||
| 7dc5ab2e95 | |||
| 28d970e4a6 | |||
| 4e824a735e | |||
| eea79ce586 | |||
| e9340ce9bc | |||
| de387102b4 | |||
| 79c17d8b6a | |||
| 006c15fb5f | |||
| 0c4f97c112 | |||
| f9395eaa08 | |||
| f13a294b47 | |||
| 84ee02faa7 | |||
| f77b4cb4a2 | |||
| 7ea7f2b37f | |||
| c61b9c5f3c | |||
| e719bf8ead | |||
| 9903b8d7ec | |||
| 77ccd215e2 | |||
| 71d1bfea7f | |||
| b00489886d | |||
| 9b698362a3 | |||
| 1a923c95dd | |||
| a6a79add68 | |||
| d74fba8175 | |||
| e4cf9d22a7 | |||
| 755369df56 | |||
| 42f7c2ad89 | |||
| fee8522052 | |||
| 34c440996d | |||
| 283b19bad5 | |||
| f0045f4113 | |||
| 0abd78e6a8 | |||
| fc7d3f7315 | |||
| 597b04fe2f | |||
| 2774a2afc6 | |||
| 89b6f20bf8 | |||
| 37c7780e85 | |||
| e0832da7fa | |||
| daaf0ad473 | |||
| 9fc24a8f5e | |||
| a1029cb2ca | |||
| 134c7636ef | |||
| 88271167d6 | |||
| a8086f6148 | |||
| f4f6885c1f | |||
| 64c0a6a4e2 | |||
| 2181b3713e | |||
| 2084c3933d | |||
| b6dab855f5 | |||
| e9fcdf822c | |||
| 7750a7313d | |||
| 81ae35aa4f | |||
| 2e49a4da48 | |||
| 8d9e2d07f3 | |||
| b34727c632 | |||
| 0ca233258d | |||
| c3b7120042 |
+4
-1
@@ -44,7 +44,10 @@ steps:
|
|||||||
image: techknowlogick/xgo:go-1.21.x
|
image: techknowlogick/xgo:go-1.21.x
|
||||||
pull: always
|
pull: always
|
||||||
commands:
|
commands:
|
||||||
- curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get -qqy install nodejs
|
- apt-get update && apt-get -qqy install ca-certificates curl gnupg
|
||||||
|
- mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||||
|
- echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
|
||||||
|
- apt-get update && apt-get -qqy install nodejs
|
||||||
- export PATH=$PATH:$GOPATH/bin
|
- export PATH=$PATH:$GOPATH/bin
|
||||||
- make release
|
- make release
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
+18
-15
@@ -11,7 +11,6 @@ parserOptions:
|
|||||||
plugins:
|
plugins:
|
||||||
- "@eslint-community/eslint-plugin-eslint-comments"
|
- "@eslint-community/eslint-plugin-eslint-comments"
|
||||||
- eslint-plugin-array-func
|
- eslint-plugin-array-func
|
||||||
- eslint-plugin-custom-elements
|
|
||||||
- eslint-plugin-import
|
- eslint-plugin-import
|
||||||
- eslint-plugin-jquery
|
- eslint-plugin-jquery
|
||||||
- eslint-plugin-no-jquery
|
- eslint-plugin-no-jquery
|
||||||
@@ -19,6 +18,7 @@ plugins:
|
|||||||
- eslint-plugin-regexp
|
- eslint-plugin-regexp
|
||||||
- eslint-plugin-sonarjs
|
- eslint-plugin-sonarjs
|
||||||
- eslint-plugin-unicorn
|
- eslint-plugin-unicorn
|
||||||
|
- eslint-plugin-vitest-globals
|
||||||
- eslint-plugin-wc
|
- eslint-plugin-wc
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@@ -46,6 +46,9 @@ overrides:
|
|||||||
- files: ["*.config.*"]
|
- files: ["*.config.*"]
|
||||||
rules:
|
rules:
|
||||||
import/no-unused-modules: [0]
|
import/no-unused-modules: [0]
|
||||||
|
- files: ["**/*.test.*", "web_src/js/test/setup.js"]
|
||||||
|
env:
|
||||||
|
vitest-globals/env: true
|
||||||
- files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"]
|
- files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"]
|
||||||
rules:
|
rules:
|
||||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
|
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
|
||||||
@@ -88,19 +91,6 @@ rules:
|
|||||||
consistent-this: [0]
|
consistent-this: [0]
|
||||||
constructor-super: [2]
|
constructor-super: [2]
|
||||||
curly: [0]
|
curly: [0]
|
||||||
custom-elements/expose-class-on-global: [0]
|
|
||||||
custom-elements/extends-correct-class: [2]
|
|
||||||
custom-elements/file-name-matches-element: [2]
|
|
||||||
custom-elements/no-constructor: [2]
|
|
||||||
custom-elements/no-customized-built-in-elements: [2]
|
|
||||||
custom-elements/no-dom-traversal-in-attributechangedcallback: [2]
|
|
||||||
custom-elements/no-dom-traversal-in-connectedcallback: [2]
|
|
||||||
custom-elements/no-exports-with-element: [2]
|
|
||||||
custom-elements/no-method-prefixed-with-on: [2]
|
|
||||||
custom-elements/no-unchecked-define: [0]
|
|
||||||
custom-elements/one-element-per-file: [0]
|
|
||||||
custom-elements/tag-name-matches-class: [2]
|
|
||||||
custom-elements/valid-tag-name: [2]
|
|
||||||
default-case-last: [2]
|
default-case-last: [2]
|
||||||
default-case: [0]
|
default-case: [0]
|
||||||
default-param-last: [0]
|
default-param-last: [0]
|
||||||
@@ -740,14 +730,27 @@ rules:
|
|||||||
valid-typeof: [2, {requireStringLiterals: true}]
|
valid-typeof: [2, {requireStringLiterals: true}]
|
||||||
vars-on-top: [0]
|
vars-on-top: [0]
|
||||||
wc/attach-shadow-constructor: [2]
|
wc/attach-shadow-constructor: [2]
|
||||||
|
wc/define-tag-after-class-definition: [0]
|
||||||
|
wc/expose-class-on-global: [0]
|
||||||
|
wc/file-name-matches-element: [2]
|
||||||
|
wc/guard-define-call: [0]
|
||||||
wc/guard-super-call: [2]
|
wc/guard-super-call: [2]
|
||||||
|
wc/max-elements-per-file: [0]
|
||||||
|
wc/no-child-traversal-in-attributechangedcallback: [2]
|
||||||
|
wc/no-child-traversal-in-connectedcallback: [2]
|
||||||
wc/no-closed-shadow-root: [2]
|
wc/no-closed-shadow-root: [2]
|
||||||
wc/no-constructor-attributes: [2]
|
wc/no-constructor-attributes: [2]
|
||||||
wc/no-constructor-params: [2]
|
wc/no-constructor-params: [2]
|
||||||
wc/no-invalid-element-name: [0] # covered by custom-elements/valid-tag-name
|
wc/no-constructor: [2]
|
||||||
|
wc/no-customized-built-in-elements: [2]
|
||||||
|
wc/no-exports-with-element: [2]
|
||||||
|
wc/no-invalid-element-name: [2]
|
||||||
|
wc/no-invalid-extends: [2]
|
||||||
|
wc/no-method-prefixed-with-on: [2]
|
||||||
wc/no-self-class: [2]
|
wc/no-self-class: [2]
|
||||||
wc/no-typos: [2]
|
wc/no-typos: [2]
|
||||||
wc/require-listener-teardown: [2]
|
wc/require-listener-teardown: [2]
|
||||||
|
wc/tag-name-matches-class: [2]
|
||||||
wrap-iife: [2, inside]
|
wrap-iife: [2, inside]
|
||||||
wrap-regex: [0]
|
wrap-regex: [0]
|
||||||
yield-star-spacing: [2, after]
|
yield-star-spacing: [2, after]
|
||||||
|
|||||||
@@ -44,5 +44,3 @@ rules:
|
|||||||
ignore: |
|
ignore: |
|
||||||
.venv
|
.venv
|
||||||
node_modules
|
node_modules
|
||||||
/models/fixtures
|
|
||||||
/models/migrations/fixtures
|
|
||||||
|
|||||||
@@ -4,6 +4,33 @@ This changelog goes through all the changes that have been made in each release
|
|||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.com).
|
been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||||
|
|
||||||
|
## [1.20.5](https://github.com/go-gitea/gitea/releases/tag/v1.20.5) - 2023-10-03
|
||||||
|
|
||||||
|
* ENHANCEMENTS
|
||||||
|
* Fix z-index on markdown completion (#27237) (#27242 & #27238)
|
||||||
|
* Use secure cookie for HTTPS sites (#26999) (#27013)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix git 2.11 error when checking IsEmpty (#27393) (#27396)
|
||||||
|
* Allow get release download files and lfs files with oauth2 token format (#26430) (#27378)
|
||||||
|
* Fix orphan check for deleted branch (#27310) (#27320)
|
||||||
|
* Quote table `release` in sql queries (#27205) (#27219)
|
||||||
|
* Fix release URL in webhooks (#27182) (#27184)
|
||||||
|
* Fix successful return value for `SyncAndGetUserSpecificDiff` (#27152) (#27156)
|
||||||
|
* fix pagination for followers and following (#27127) (#27138)
|
||||||
|
* Fix issue templates when blank isses are disabled (#27061) (#27082)
|
||||||
|
* Fix context cache bug & enable context cache for dashabord commits' authors(#26991) (#27017)
|
||||||
|
* Fix INI parsing for value with trailing slash (#26995) (#27001)
|
||||||
|
* Fix PushEvent NullPointerException jenkinsci/github-plugin (#27203) (#27249)
|
||||||
|
* Fix organization field being null in POST /orgs/{orgid}/teams (#27150) (#27167 & #27162)
|
||||||
|
* Fix bug of review request number (#27406) (#27104)
|
||||||
|
* TESTING
|
||||||
|
* services/wiki: Close() after error handling (#27129) (#27137)
|
||||||
|
* DOCS
|
||||||
|
* Improve actions docs related to `pull_request` event (#27126) (#27145)
|
||||||
|
* MISC
|
||||||
|
* Add logs for data broken of comment review (#27326) (#27344)
|
||||||
|
* Load reviewer before sending notification (#27063) (#27064)
|
||||||
|
|
||||||
## [1.20.4](https://github.com/go-gitea/gitea/releases/tag/v1.20.4) - 2023-09-08
|
## [1.20.4](https://github.com/go-gitea/gitea/releases/tag/v1.20.4) - 2023-09-08
|
||||||
|
|
||||||
* SECURITY
|
* SECURITY
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ help:
|
|||||||
@echo " - test-frontend test frontend files"
|
@echo " - test-frontend test frontend files"
|
||||||
@echo " - test-backend test backend files"
|
@echo " - test-backend test backend files"
|
||||||
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
|
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
|
||||||
|
@echo " - update update js and py dependencies"
|
||||||
@echo " - update-js update js dependencies"
|
@echo " - update-js update js dependencies"
|
||||||
@echo " - update-py update py dependencies"
|
@echo " - update-py update py dependencies"
|
||||||
@echo " - webpack build webpack files"
|
@echo " - webpack build webpack files"
|
||||||
@@ -924,6 +925,9 @@ node_modules: package-lock.json
|
|||||||
poetry install
|
poetry install
|
||||||
@touch .venv
|
@touch .venv
|
||||||
|
|
||||||
|
.PHONY: update
|
||||||
|
update: update-js update-py
|
||||||
|
|
||||||
.PHONY: update-js
|
.PHONY: update-js
|
||||||
update-js: node-check | node_modules
|
update-js: node-check | node_modules
|
||||||
npx updates -u -f package.json
|
npx updates -u -f package.json
|
||||||
|
|||||||
+2
-2
@@ -389,7 +389,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||||||
}
|
}
|
||||||
log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum)
|
log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum)
|
||||||
|
|
||||||
if err = repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil {
|
if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil {
|
||||||
log.Warn(" SyncReleasesWithTags: %v", err)
|
log.Warn(" SyncReleasesWithTags: %v", err)
|
||||||
gitRepo.Close()
|
gitRepo.Close()
|
||||||
continue
|
continue
|
||||||
@@ -438,7 +438,7 @@ func runRegenerateKeys(_ *cli.Context) error {
|
|||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return asymkey_model.RewriteAllPublicKeys()
|
return asymkey_model.RewriteAllPublicKeys(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/packages"
|
"code.gitea.io/gitea/models/packages"
|
||||||
"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"
|
||||||
@@ -30,7 +31,7 @@ func TestMigratePackages(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer buf.Close()
|
defer buf.Close()
|
||||||
|
|
||||||
v, f, err := packages_service.CreatePackageAndAddFile(&packages_service.PackageCreationInfo{
|
v, f, err := packages_service.CreatePackageAndAddFile(db.DefaultContext, &packages_service.PackageCreationInfo{
|
||||||
PackageInfo: packages_service.PackageInfo{
|
PackageInfo: packages_service.PackageInfo{
|
||||||
Owner: creator,
|
Owner: creator,
|
||||||
PackageType: packages.TypeGeneric,
|
PackageType: packages.TypeGeneric,
|
||||||
|
|||||||
@@ -2568,6 +2568,12 @@ LEVEL = Info
|
|||||||
;DEFAULT_ACTIONS_URL = github
|
;DEFAULT_ACTIONS_URL = github
|
||||||
;; Default artifact retention time in days, default is 90 days
|
;; Default artifact retention time in days, default is 90 days
|
||||||
;ARTIFACT_RETENTION_DAYS = 90
|
;ARTIFACT_RETENTION_DAYS = 90
|
||||||
|
;; Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||||
|
;ZOMBIE_TASK_TIMEOUT = 10m
|
||||||
|
;; Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
||||||
|
;ENDLESS_TASK_TIMEOUT = 3h
|
||||||
|
;; Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||||
|
;ABANDONED_JOB_TIMEOUT = 24h
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|||||||
@@ -1389,6 +1389,9 @@ PROXY_HOSTS = *.github.com
|
|||||||
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
||||||
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
||||||
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.
|
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.
|
||||||
|
- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||||
|
- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
||||||
|
- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||||
|
|
||||||
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
|
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
|
||||||
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
|
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ menu:
|
|||||||
|
|
||||||
# Database Preparation
|
# Database Preparation
|
||||||
|
|
||||||
You need a database to use Gitea. Gitea supports PostgreSQL (>=10), MySQL (>=5.7), SQLite, and MSSQL (>=2008R2 SP3). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter.
|
You need a database to use Gitea. Gitea supports PostgreSQL (>=10), MySQL (>=5.7), MariaDB, SQLite, and MSSQL (>=2008R2 SP3). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter.
|
||||||
|
|
||||||
Database instance can be on same machine as Gitea (local database setup), or on different machine (remote database).
|
Database instance can be on same machine as Gitea (local database setup), or on different machine (remote database).
|
||||||
|
|
||||||
Note: All steps below requires that the database engine of your choice is installed on your system. For remote database setup, install the server application on database instance and client program on your Gitea server. The client program is used to test connection to the database from Gitea server, while Gitea itself use database driver provided by Go to accomplish the same thing. In addition, make sure you use same engine version for both server and client for some engine features to work. For security reason, protect `root` (MySQL) or `postgres` (PostgreSQL) database superuser with secure password. The steps assumes that you run Linux for both database and Gitea servers.
|
Note: All steps below requires that the database engine of your choice is installed on your system. For remote database setup, install the server application on database instance and client program on your Gitea server. The client program is used to test connection to the database from Gitea server, while Gitea itself use database driver provided by Go to accomplish the same thing. In addition, make sure you use same engine version for both server and client for some engine features to work. For security reason, protect `root` (MySQL) or `postgres` (PostgreSQL) database superuser with secure password. The steps assumes that you run Linux for both database and Gitea servers.
|
||||||
|
|
||||||
## MySQL
|
## MySQL/MariaDB
|
||||||
|
|
||||||
1. For remote database setup, you will need to make MySQL listen to your IP address. Edit `bind-address` option on `/etc/mysql/my.cnf` on database instance to:
|
1. For remote database setup, you will need to make MySQL listen to your IP address. Edit `bind-address` option on `/etc/mysql/my.cnf` on database instance to:
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Note: All steps below requires that the database engine of your choice is instal
|
|||||||
|
|
||||||
```sql
|
```sql
|
||||||
SET old_passwords=0;
|
SET old_passwords=0;
|
||||||
CREATE USER 'gitea' IDENTIFIED BY 'gitea';
|
CREATE USER 'gitea'@'%' IDENTIFIED BY 'gitea';
|
||||||
```
|
```
|
||||||
|
|
||||||
For remote database:
|
For remote database:
|
||||||
|
|||||||
@@ -128,8 +128,6 @@ If pre-built frontend files are present it is possible to only build the backend
|
|||||||
TAGS="bindata" make backend
|
TAGS="bindata" make backend
|
||||||
```
|
```
|
||||||
|
|
||||||
Webpack source maps are by default enabled in development builds and disabled in production builds. They can be enabled by setting the `ENABLE_SOURCEMAP=true` environment variable.
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
After following the steps above, a `gitea` binary will be available in the working directory.
|
After following the steps above, a `gitea` binary will be available in the working directory.
|
||||||
@@ -260,3 +258,11 @@ GOARCH=amd64 \
|
|||||||
TAGS="bindata sqlite sqlite_unlock_notify" \
|
TAGS="bindata sqlite sqlite_unlock_notify" \
|
||||||
make build
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Source Maps
|
||||||
|
|
||||||
|
By default, gitea generates reduced source maps for frontend files to conserve space. This can be controlled with the `ENABLE_SOURCEMAP` environment variable:
|
||||||
|
|
||||||
|
- `ENABLE_SOURCEMAP=true` generates all source maps, the default for development builds
|
||||||
|
- `ENABLE_SOURCEMAP=reduced` generates limited source maps, the default for production builds
|
||||||
|
- `ENABLE_SOURCEMAP=false` generates no source maps
|
||||||
|
|||||||
@@ -100,8 +100,6 @@ TAGS="bindata sqlite sqlite_unlock_notify" make build
|
|||||||
TAGS="bindata" make backend
|
TAGS="bindata" make backend
|
||||||
```
|
```
|
||||||
|
|
||||||
在开发构建中,默认启用 Webpack 源映射,在生产构建中禁用。可以通过设置`ENABLE_SOURCEMAP=true`环境变量来启用它们。
|
|
||||||
|
|
||||||
## 测试
|
## 测试
|
||||||
|
|
||||||
按照上述步骤完成后,工作目录中将会有一个`gitea`二进制文件。可以从该目录进行测试,或将其移动到带有测试数据的目录中。当手动从命令行启动 Gitea 时,可以通过按下`Ctrl + C`来停止程序。
|
按照上述步骤完成后,工作目录中将会有一个`gitea`二进制文件。可以从该目录进行测试,或将其移动到带有测试数据的目录中。当手动从命令行启动 Gitea 时,可以通过按下`Ctrl + C`来停止程序。
|
||||||
@@ -221,3 +219,11 @@ GOARCH=amd64 \
|
|||||||
TAGS="bindata sqlite sqlite_unlock_notify" \
|
TAGS="bindata sqlite sqlite_unlock_notify" \
|
||||||
make build
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 源映射
|
||||||
|
|
||||||
|
默认情况下,gitea 会为前端文件生成精简的源映射以节省空间。 这可以通过“ENABLE_SOURCEMAP”环境变量进行控制:
|
||||||
|
|
||||||
|
- `ENABLE_SOURCEMAP=true` 生成所有源映射,这是开发版本的默认设置
|
||||||
|
- `ENABLE_SOURCEMAP=reduced` 生成有限的源映射,这是生产版本的默认设置
|
||||||
|
- `ENABLE_SOURCEMAP=false` 不生成源映射
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ require (
|
|||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.8.1
|
||||||
github.com/alecthomas/chroma/v2 v2.9.1
|
github.com/alecthomas/chroma/v2 v2.9.1
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||||
github.com/blevesearch/bleve/v2 v2.3.9
|
github.com/blevesearch/bleve/v2 v2.3.10
|
||||||
github.com/bufbuild/connect-go v1.10.0
|
github.com/bufbuild/connect-go v1.10.0
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.9.1
|
github.com/buildkite/terminal-to-html/v3 v3.9.1
|
||||||
github.com/caddyserver/certmagic v0.19.2
|
github.com/caddyserver/certmagic v0.19.2
|
||||||
@@ -42,7 +42,7 @@ require (
|
|||||||
github.com/go-chi/chi/v5 v5.0.10
|
github.com/go-chi/chi/v5 v5.0.10
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-co-op/gocron v1.31.1
|
github.com/go-co-op/gocron v1.31.1
|
||||||
github.com/go-enry/go-enry/v2 v2.8.4
|
github.com/go-enry/go-enry/v2 v2.8.5
|
||||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
||||||
github.com/go-git/go-billy/v5 v5.4.1
|
github.com/go-git/go-billy/v5 v5.4.1
|
||||||
github.com/go-git/go-git/v5 v5.8.1
|
github.com/go-git/go-git/v5 v5.8.1
|
||||||
@@ -145,22 +145,22 @@ require (
|
|||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
github.com/bits-and-blooms/bitset v1.9.0 // indirect
|
||||||
github.com/blevesearch/bleve_index_api v1.0.5 // indirect
|
github.com/blevesearch/bleve_index_api v1.0.6 // indirect
|
||||||
github.com/blevesearch/geo v0.1.17 // indirect
|
github.com/blevesearch/geo v0.1.18 // indirect
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.5 // indirect
|
github.com/blevesearch/scorch_segment_api/v2 v2.1.6 // indirect
|
||||||
github.com/blevesearch/segment v0.9.1 // indirect
|
github.com/blevesearch/segment v0.9.1 // indirect
|
||||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||||
github.com/blevesearch/vellum v1.0.10 // indirect
|
github.com/blevesearch/vellum v1.0.10 // indirect
|
||||||
github.com/blevesearch/zapx/v11 v11.3.9 // indirect
|
github.com/blevesearch/zapx/v11 v11.3.10 // indirect
|
||||||
github.com/blevesearch/zapx/v12 v12.3.9 // indirect
|
github.com/blevesearch/zapx/v12 v12.3.10 // indirect
|
||||||
github.com/blevesearch/zapx/v13 v13.3.9 // indirect
|
github.com/blevesearch/zapx/v13 v13.3.10 // indirect
|
||||||
github.com/blevesearch/zapx/v14 v14.3.9 // indirect
|
github.com/blevesearch/zapx/v14 v14.3.10 // indirect
|
||||||
github.com/blevesearch/zapx/v15 v15.3.12 // indirect
|
github.com/blevesearch/zapx/v15 v15.3.13 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1 // indirect
|
github.com/boombuler/barcode v1.0.1 // indirect
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20230611145640-acc696258285 // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20230611145640-acc696258285 // indirect
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||||
|
|||||||
@@ -149,18 +149,18 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE=
|
github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE=
|
||||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
github.com/bits-and-blooms/bitset v1.9.0 h1:g1YivPG8jOtrN013Fe8OBXubkiTwvm7/vG2vXz03ANU=
|
||||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.9.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM=
|
github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM=
|
||||||
github.com/blevesearch/bleve/v2 v2.3.9 h1:pUMvK0mxAexqasZcVj8lazmWnEW5XiV0tASIqANiNTQ=
|
github.com/blevesearch/bleve/v2 v2.3.10 h1:z8V0wwGoL4rp7nG/O3qVVLYxUqCbEwskMt4iRJsPLgg=
|
||||||
github.com/blevesearch/bleve/v2 v2.3.9/go.mod h1:1PibElcjlQMQHF9uS9mRv58ODQgj4pCWHA1Wfd+qagU=
|
github.com/blevesearch/bleve/v2 v2.3.10/go.mod h1:RJzeoeHC+vNHsoLR54+crS1HmOWpnH87fL70HAUCzIA=
|
||||||
github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
|
github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
|
||||||
github.com/blevesearch/bleve_index_api v1.0.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw=
|
github.com/blevesearch/bleve_index_api v1.0.6 h1:gyUUxdsrvmW3jVhhYdCVL6h9dCjNT/geNU7PxGn37p8=
|
||||||
github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
github.com/blevesearch/bleve_index_api v1.0.6/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||||
github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA=
|
github.com/blevesearch/geo v0.1.18 h1:Np8jycHTZ5scFe7VEPLrDoHnnb9C4j636ue/CGrhtDw=
|
||||||
github.com/blevesearch/geo v0.1.17/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
|
github.com/blevesearch/geo v0.1.18/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||||
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
|
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
|
||||||
@@ -169,8 +169,8 @@ github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+
|
|||||||
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
||||||
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU=
|
github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.5 h1:1g713kpCQZ8u4a3stRGBfrwVOuGRnmxOVU5MQkUPrHU=
|
github.com/blevesearch/scorch_segment_api/v2 v2.1.6 h1:CdekX/Ob6YCYmeHzD72cKpwzBjvkOGegHOqhAkXp6yA=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.5/go.mod h1:f2nOkKS1HcjgIWZgDAErgBdxmr2eyt0Kn7IY+FU1Xe4=
|
github.com/blevesearch/scorch_segment_api/v2 v2.1.6/go.mod h1:nQQYlp51XvoSVxcciBjtvuHPIVjlWrN1hX4qwK2cqdc=
|
||||||
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
|
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
|
||||||
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||||
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
||||||
@@ -184,20 +184,20 @@ github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRv
|
|||||||
github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI=
|
github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI=
|
||||||
github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
||||||
github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM=
|
github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM=
|
||||||
github.com/blevesearch/zapx/v11 v11.3.9 h1:y3ijS4h4MJdmQ07MHASxat4owAixreK2xdo76w9ncrw=
|
github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk=
|
||||||
github.com/blevesearch/zapx/v11 v11.3.9/go.mod h1:jcAYnQwlr+LqD2vLjDWjWiZDXDXGFqPbpPDRTd3XmS4=
|
github.com/blevesearch/zapx/v11 v11.3.10/go.mod h1:0+gW+FaE48fNxoVtMY5ugtNHHof/PxCqh7CnhYdnMzQ=
|
||||||
github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A=
|
github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A=
|
||||||
github.com/blevesearch/zapx/v12 v12.3.9 h1:MXGLlZ03oxXH3DMJTZaBaRj2xb6t4wQVZeZK/wu1M6w=
|
github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s=
|
||||||
github.com/blevesearch/zapx/v12 v12.3.9/go.mod h1:QXCMwmOkdLnMDgTN1P4CcuX5F851iUOtOwXbw0HMBYs=
|
github.com/blevesearch/zapx/v12 v12.3.10/go.mod h1:0yeZg6JhaGxITlsS5co73aqPtM04+ycnI6D1v0mhbCs=
|
||||||
github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ=
|
github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ=
|
||||||
github.com/blevesearch/zapx/v13 v13.3.9 h1:+VAz9V0VmllHXlZV4DCvfYj0nqaZHgF3MeEHwOyRBwQ=
|
github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIqMGahDE8=
|
||||||
github.com/blevesearch/zapx/v13 v13.3.9/go.mod h1:s+WjNp4WSDtrBVBpa37DUOd7S/Gr/jTZ7ST/MbCVj/0=
|
github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk=
|
||||||
github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g=
|
github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g=
|
||||||
github.com/blevesearch/zapx/v14 v14.3.9 h1:wuqxATgsTCNHM9xsOFOeFp8H2heZ/gMX/tsl9lRK8U4=
|
github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU=
|
||||||
github.com/blevesearch/zapx/v14 v14.3.9/go.mod h1:MWZ4v8AzFBRurhDzkLvokFW8ljcq9Evm27mkWe8OGbM=
|
github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns=
|
||||||
github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A=
|
github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A=
|
||||||
github.com/blevesearch/zapx/v15 v15.3.12 h1:w/kU9aHyfMDEdwHGZzCiakC3HZ9z5gYlXaALDC4Dct8=
|
github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ=
|
||||||
github.com/blevesearch/zapx/v15 v15.3.12/go.mod h1:tx53gDJS/7Oa3Je820cmVurqCuJ4dqdAy1kiDMV/IUo=
|
github.com/blevesearch/zapx/v15 v15.3.13/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
@@ -347,8 +347,8 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
|||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||||
github.com/go-co-op/gocron v1.31.1 h1:LZAuBlU0t3SPGUMJGhrJ6VuCc3CsrYzkzicygvVWlfA=
|
github.com/go-co-op/gocron v1.31.1 h1:LZAuBlU0t3SPGUMJGhrJ6VuCc3CsrYzkzicygvVWlfA=
|
||||||
github.com/go-co-op/gocron v1.31.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
|
github.com/go-co-op/gocron v1.31.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
|
||||||
github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs=
|
github.com/go-enry/go-enry/v2 v2.8.5 h1:jtYXblst2+d9k7ZgEgkv6Q5hKRKPf0qHRjt715BZEX4=
|
||||||
github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
github.com/go-enry/go-enry/v2 v2.8.5/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||||
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
||||||
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
|
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
|
||||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type ActionRunnerToken struct {
|
|||||||
Owner *user_model.User `xorm:"-"`
|
Owner *user_model.User `xorm:"-"`
|
||||||
RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global
|
RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global
|
||||||
Repo *repo_model.Repository `xorm:"-"`
|
Repo *repo_model.Repository `xorm:"-"`
|
||||||
IsActive bool
|
IsActive bool // true means it can be used
|
||||||
|
|
||||||
Created timeutil.TimeStamp `xorm:"created"`
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
@@ -57,7 +57,7 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRunnerToken creates a new runner token
|
// NewRunnerToken creates a new active runner token and invalidate all old tokens
|
||||||
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||||
token, err := util.CryptoRandomString(40)
|
token, err := util.CryptoRandomString(40)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -66,17 +66,27 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo
|
|||||||
runnerToken := &ActionRunnerToken{
|
runnerToken := &ActionRunnerToken{
|
||||||
OwnerID: ownerID,
|
OwnerID: ownerID,
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
IsActive: false,
|
IsActive: true,
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
_, err = db.GetEngine(ctx).Insert(runnerToken)
|
|
||||||
return runnerToken, err
|
return runnerToken, db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
if _, err := db.GetEngine(ctx).Where("owner_id =? AND repo_id = ?", ownerID, repoID).Cols("is_active").Update(&ActionRunnerToken{
|
||||||
|
IsActive: false,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.GetEngine(ctx).Insert(runnerToken)
|
||||||
|
return err
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUnactivatedRunnerToken returns a unactivated runner token
|
// GetLastestRunnerToken returns the latest runner token
|
||||||
func GetUnactivatedRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
func GetLastestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||||
var runnerToken ActionRunnerToken
|
var runnerToken ActionRunnerToken
|
||||||
has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=? AND is_active=?", ownerID, repoID, false).OrderBy("id DESC").Get(&runnerToken)
|
has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=?", ownerID, repoID).
|
||||||
|
OrderBy("id DESC").Get(&runnerToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
|
|||||||
+47
-48
@@ -140,7 +140,7 @@ func (at ActionType) InActions(actions ...string) bool {
|
|||||||
// used in template render.
|
// used in template render.
|
||||||
type Action struct {
|
type Action struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UserID int64 // Receiver user id.
|
UserID int64 `xorm:"INDEX"` // Receiver user id.
|
||||||
OpType ActionType
|
OpType ActionType
|
||||||
ActUserID int64 // Action user id.
|
ActUserID int64 // Action user id.
|
||||||
ActUser *user_model.User `xorm:"-"`
|
ActUser *user_model.User `xorm:"-"`
|
||||||
@@ -208,91 +208,91 @@ func (a *Action) loadRepo(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetActFullName gets the action's user full name.
|
// GetActFullName gets the action's user full name.
|
||||||
func (a *Action) GetActFullName() string {
|
func (a *Action) GetActFullName(ctx context.Context) string {
|
||||||
a.LoadActUser(db.DefaultContext)
|
a.LoadActUser(ctx)
|
||||||
return a.ActUser.FullName
|
return a.ActUser.FullName
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActUserName gets the action's user name.
|
// GetActUserName gets the action's user name.
|
||||||
func (a *Action) GetActUserName() string {
|
func (a *Action) GetActUserName(ctx context.Context) string {
|
||||||
a.LoadActUser(db.DefaultContext)
|
a.LoadActUser(ctx)
|
||||||
return a.ActUser.Name
|
return a.ActUser.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShortActUserName gets the action's user name trimmed to max 20
|
// ShortActUserName gets the action's user name trimmed to max 20
|
||||||
// chars.
|
// chars.
|
||||||
func (a *Action) ShortActUserName() string {
|
func (a *Action) ShortActUserName(ctx context.Context) string {
|
||||||
return base.EllipsisString(a.GetActUserName(), 20)
|
return base.EllipsisString(a.GetActUserName(ctx), 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
|
// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
|
||||||
func (a *Action) GetDisplayName() string {
|
func (a *Action) GetDisplayName(ctx context.Context) string {
|
||||||
if setting.UI.DefaultShowFullName {
|
if setting.UI.DefaultShowFullName {
|
||||||
trimmedFullName := strings.TrimSpace(a.GetActFullName())
|
trimmedFullName := strings.TrimSpace(a.GetActFullName(ctx))
|
||||||
if len(trimmedFullName) > 0 {
|
if len(trimmedFullName) > 0 {
|
||||||
return trimmedFullName
|
return trimmedFullName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return a.ShortActUserName()
|
return a.ShortActUserName(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
|
// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
|
||||||
func (a *Action) GetDisplayNameTitle() string {
|
func (a *Action) GetDisplayNameTitle(ctx context.Context) string {
|
||||||
if setting.UI.DefaultShowFullName {
|
if setting.UI.DefaultShowFullName {
|
||||||
return a.ShortActUserName()
|
return a.ShortActUserName(ctx)
|
||||||
}
|
}
|
||||||
return a.GetActFullName()
|
return a.GetActFullName(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoUserName returns the name of the action repository owner.
|
// GetRepoUserName returns the name of the action repository owner.
|
||||||
func (a *Action) GetRepoUserName() string {
|
func (a *Action) GetRepoUserName(ctx context.Context) string {
|
||||||
a.loadRepo(db.DefaultContext)
|
a.loadRepo(ctx)
|
||||||
return a.Repo.OwnerName
|
return a.Repo.OwnerName
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShortRepoUserName returns the name of the action repository owner
|
// ShortRepoUserName returns the name of the action repository owner
|
||||||
// trimmed to max 20 chars.
|
// trimmed to max 20 chars.
|
||||||
func (a *Action) ShortRepoUserName() string {
|
func (a *Action) ShortRepoUserName(ctx context.Context) string {
|
||||||
return base.EllipsisString(a.GetRepoUserName(), 20)
|
return base.EllipsisString(a.GetRepoUserName(ctx), 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoName returns the name of the action repository.
|
// GetRepoName returns the name of the action repository.
|
||||||
func (a *Action) GetRepoName() string {
|
func (a *Action) GetRepoName(ctx context.Context) string {
|
||||||
a.loadRepo(db.DefaultContext)
|
a.loadRepo(ctx)
|
||||||
return a.Repo.Name
|
return a.Repo.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShortRepoName returns the name of the action repository
|
// ShortRepoName returns the name of the action repository
|
||||||
// trimmed to max 33 chars.
|
// trimmed to max 33 chars.
|
||||||
func (a *Action) ShortRepoName() string {
|
func (a *Action) ShortRepoName(ctx context.Context) string {
|
||||||
return base.EllipsisString(a.GetRepoName(), 33)
|
return base.EllipsisString(a.GetRepoName(ctx), 33)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoPath returns the virtual path to the action repository.
|
// GetRepoPath returns the virtual path to the action repository.
|
||||||
func (a *Action) GetRepoPath() string {
|
func (a *Action) GetRepoPath(ctx context.Context) string {
|
||||||
return path.Join(a.GetRepoUserName(), a.GetRepoName())
|
return path.Join(a.GetRepoUserName(ctx), a.GetRepoName(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShortRepoPath returns the virtual path to the action repository
|
// ShortRepoPath returns the virtual path to the action repository
|
||||||
// trimmed to max 20 + 1 + 33 chars.
|
// trimmed to max 20 + 1 + 33 chars.
|
||||||
func (a *Action) ShortRepoPath() string {
|
func (a *Action) ShortRepoPath(ctx context.Context) string {
|
||||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
return path.Join(a.ShortRepoUserName(ctx), a.ShortRepoName(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoLink returns relative link to action repository.
|
// GetRepoLink returns relative link to action repository.
|
||||||
func (a *Action) GetRepoLink() string {
|
func (a *Action) GetRepoLink(ctx context.Context) string {
|
||||||
// path.Join will skip empty strings
|
// path.Join will skip empty strings
|
||||||
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
|
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName(ctx)), url.PathEscape(a.GetRepoName(ctx)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoAbsoluteLink returns the absolute link to action repository.
|
// GetRepoAbsoluteLink returns the absolute link to action repository.
|
||||||
func (a *Action) GetRepoAbsoluteLink() string {
|
func (a *Action) GetRepoAbsoluteLink(ctx context.Context) string {
|
||||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
|
return setting.AppURL + url.PathEscape(a.GetRepoUserName(ctx)) + "/" + url.PathEscape(a.GetRepoName(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentHTMLURL returns link to action comment.
|
// GetCommentHTMLURL returns link to action comment.
|
||||||
func (a *Action) GetCommentHTMLURL() string {
|
func (a *Action) GetCommentHTMLURL(ctx context.Context) string {
|
||||||
return a.getCommentHTMLURL(db.DefaultContext)
|
return a.getCommentHTMLURL(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Action) loadComment(ctx context.Context) (err error) {
|
func (a *Action) loadComment(ctx context.Context) (err error) {
|
||||||
@@ -309,7 +309,7 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string {
|
|||||||
}
|
}
|
||||||
_ = a.loadComment(ctx)
|
_ = a.loadComment(ctx)
|
||||||
if a.Comment != nil {
|
if a.Comment != nil {
|
||||||
return a.Comment.HTMLURL()
|
return a.Comment.HTMLURL(ctx)
|
||||||
}
|
}
|
||||||
if len(a.GetIssueInfos()) == 0 {
|
if len(a.GetIssueInfos()) == 0 {
|
||||||
return "#"
|
return "#"
|
||||||
@@ -334,8 +334,8 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentLink returns link to action comment.
|
// GetCommentLink returns link to action comment.
|
||||||
func (a *Action) GetCommentLink() string {
|
func (a *Action) GetCommentLink(ctx context.Context) string {
|
||||||
return a.getCommentLink(db.DefaultContext)
|
return a.getCommentLink(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Action) getCommentLink(ctx context.Context) string {
|
func (a *Action) getCommentLink(ctx context.Context) string {
|
||||||
@@ -344,7 +344,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
|
|||||||
}
|
}
|
||||||
_ = a.loadComment(ctx)
|
_ = a.loadComment(ctx)
|
||||||
if a.Comment != nil {
|
if a.Comment != nil {
|
||||||
return a.Comment.Link()
|
return a.Comment.Link(ctx)
|
||||||
}
|
}
|
||||||
if len(a.GetIssueInfos()) == 0 {
|
if len(a.GetIssueInfos()) == 0 {
|
||||||
return "#"
|
return "#"
|
||||||
@@ -374,8 +374,8 @@ func (a *Action) GetBranch() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRefLink returns the action's ref link.
|
// GetRefLink returns the action's ref link.
|
||||||
func (a *Action) GetRefLink() string {
|
func (a *Action) GetRefLink(ctx context.Context) string {
|
||||||
return git.RefURL(a.GetRepoLink(), a.RefName)
|
return git.RefURL(a.GetRepoLink(ctx), a.RefName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTag returns the action's repository tag.
|
// GetTag returns the action's repository tag.
|
||||||
@@ -399,11 +399,10 @@ func (a *Action) GetIssueInfos() []string {
|
|||||||
return strings.SplitN(a.Content, "|", 3)
|
return strings.SplitN(a.Content, "|", 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueTitle returns the title of first issue associated
|
// GetIssueTitle returns the title of first issue associated with the action.
|
||||||
// with the action. This function will be invoked in template so keep db.DefaultContext here
|
func (a *Action) GetIssueTitle(ctx context.Context) string {
|
||||||
func (a *Action) GetIssueTitle() string {
|
|
||||||
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
||||||
issue, err := issues_model.GetIssueByIndex(db.DefaultContext, a.RepoID, index)
|
issue, err := issues_model.GetIssueByIndex(ctx, a.RepoID, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetIssueByIndex: %v", err)
|
log.Error("GetIssueByIndex: %v", err)
|
||||||
return "500 when get issue"
|
return "500 when get issue"
|
||||||
@@ -442,7 +441,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
|
|||||||
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||||
}
|
}
|
||||||
|
|
||||||
cond, err := activityQueryCondition(opts)
|
cond, err := activityQueryCondition(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -473,11 +472,11 @@ func ActivityReadable(user, doer *user_model.User) bool {
|
|||||||
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
|
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
|
func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
|
|
||||||
if opts.RequestedTeam != nil && opts.RequestedUser == nil {
|
if opts.RequestedTeam != nil && opts.RequestedUser == nil {
|
||||||
org, err := user_model.GetUserByID(db.DefaultContext, opts.RequestedTeam.OrgID)
|
org, err := user_model.GetUserByID(ctx, opts.RequestedTeam.OrgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -564,12 +563,12 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOldActions deletes all old actions from database.
|
// DeleteOldActions deletes all old actions from database.
|
||||||
func DeleteOldActions(olderThan time.Duration) (err error) {
|
func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error) {
|
||||||
if olderThan <= 0 {
|
if olderThan <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
|
_, err = db.GetEngine(ctx).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,8 +678,8 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||||
func NotifyWatchersActions(acts []*Action) error {
|
func NotifyWatchersActions(ctx context.Context, acts []*Action) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func TestAction_GetRepoPath(t *testing.T) {
|
|||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
action := &activities_model.Action{RepoID: repo.ID}
|
action := &activities_model.Action{RepoID: repo.ID}
|
||||||
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
|
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath(db.DefaultContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAction_GetRepoLink(t *testing.T) {
|
func TestAction_GetRepoLink(t *testing.T) {
|
||||||
@@ -35,9 +35,9 @@ func TestAction_GetRepoLink(t *testing.T) {
|
|||||||
action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID}
|
action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID}
|
||||||
setting.AppSubURL = "/suburl"
|
setting.AppSubURL = "/suburl"
|
||||||
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
||||||
assert.Equal(t, expected, action.GetRepoLink())
|
assert.Equal(t, expected, action.GetRepoLink(db.DefaultContext))
|
||||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
|
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink(db.DefaultContext))
|
||||||
assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL())
|
assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetFeeds(t *testing.T) {
|
func TestGetFeeds(t *testing.T) {
|
||||||
|
|||||||
@@ -175,8 +175,8 @@ func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_mo
|
|||||||
// CreateOrUpdateIssueNotifications creates an issue notification
|
// CreateOrUpdateIssueNotifications creates an issue notification
|
||||||
// for each watcher, or updates it if already exists
|
// for each watcher, or updates it if already exists
|
||||||
// receiverID > 0 just send to receiver, else send to all watcher
|
// receiverID > 0 just send to receiver, else send to all watcher
|
||||||
func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, receiverID int64) error {
|
func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -435,21 +435,21 @@ func (n *Notification) loadUser(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRepo returns the repo of the notification
|
// GetRepo returns the repo of the notification
|
||||||
func (n *Notification) GetRepo() (*repo_model.Repository, error) {
|
func (n *Notification) GetRepo(ctx context.Context) (*repo_model.Repository, error) {
|
||||||
return n.Repository, n.loadRepo(db.DefaultContext)
|
return n.Repository, n.loadRepo(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssue returns the issue of the notification
|
// GetIssue returns the issue of the notification
|
||||||
func (n *Notification) GetIssue() (*issues_model.Issue, error) {
|
func (n *Notification) GetIssue(ctx context.Context) (*issues_model.Issue, error) {
|
||||||
return n.Issue, n.loadIssue(db.DefaultContext)
|
return n.Issue, n.loadIssue(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLURL formats a URL-string to the notification
|
// HTMLURL formats a URL-string to the notification
|
||||||
func (n *Notification) HTMLURL() string {
|
func (n *Notification) HTMLURL(ctx context.Context) string {
|
||||||
switch n.Source {
|
switch n.Source {
|
||||||
case NotificationSourceIssue, NotificationSourcePullRequest:
|
case NotificationSourceIssue, NotificationSourcePullRequest:
|
||||||
if n.Comment != nil {
|
if n.Comment != nil {
|
||||||
return n.Comment.HTMLURL()
|
return n.Comment.HTMLURL(ctx)
|
||||||
}
|
}
|
||||||
return n.Issue.HTMLURL()
|
return n.Issue.HTMLURL()
|
||||||
case NotificationSourceCommit:
|
case NotificationSourceCommit:
|
||||||
@@ -461,11 +461,11 @@ func (n *Notification) HTMLURL() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Link formats a relative URL-string to the notification
|
// Link formats a relative URL-string to the notification
|
||||||
func (n *Notification) Link() string {
|
func (n *Notification) Link(ctx context.Context) string {
|
||||||
switch n.Source {
|
switch n.Source {
|
||||||
case NotificationSourceIssue, NotificationSourcePullRequest:
|
case NotificationSourceIssue, NotificationSourcePullRequest:
|
||||||
if n.Comment != nil {
|
if n.Comment != nil {
|
||||||
return n.Comment.Link()
|
return n.Comment.Link(ctx)
|
||||||
}
|
}
|
||||||
return n.Issue.Link()
|
return n.Issue.Link()
|
||||||
case NotificationSourceCommit:
|
case NotificationSourceCommit:
|
||||||
@@ -733,12 +733,12 @@ type UserIDCount struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetUIDsAndNotificationCounts between the two provided times
|
// GetUIDsAndNotificationCounts between the two provided times
|
||||||
func GetUIDsAndNotificationCounts(since, until timeutil.TimeStamp) ([]UserIDCount, error) {
|
func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) {
|
||||||
sql := `SELECT user_id, count(*) AS count FROM notification ` +
|
sql := `SELECT user_id, count(*) AS count FROM notification ` +
|
||||||
`WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
|
`WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
|
||||||
`updated_unix < ?) AND status = ? GROUP BY user_id`
|
`updated_unix < ?) AND status = ? GROUP BY user_id`
|
||||||
var res []UserIDCount
|
var res []UserIDCount
|
||||||
return res, db.GetEngine(db.DefaultContext).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
|
return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetIssueReadBy sets issue to be read by given user.
|
// SetIssueReadBy sets issue to be read by given user.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||||
|
|
||||||
assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0))
|
assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(db.DefaultContext, issue.ID, 0, 2, 0))
|
||||||
|
|
||||||
// User 9 is inactive, thus notifications for user 1 and 4 are created
|
// User 9 is inactive, thus notifications for user 1 and 4 are created
|
||||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 1, IssueID: issue.ID})
|
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 1, IssueID: issue.ID})
|
||||||
@@ -50,7 +50,7 @@ func TestNotificationsForUser(t *testing.T) {
|
|||||||
func TestNotification_GetRepo(t *testing.T) {
|
func TestNotification_GetRepo(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
||||||
repo, err := notf.GetRepo()
|
repo, err := notf.GetRepo(db.DefaultContext)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, repo, notf.Repository)
|
assert.Equal(t, repo, notf.Repository)
|
||||||
assert.EqualValues(t, notf.RepoID, repo.ID)
|
assert.EqualValues(t, notf.RepoID, repo.ID)
|
||||||
@@ -59,7 +59,7 @@ func TestNotification_GetRepo(t *testing.T) {
|
|||||||
func TestNotification_GetIssue(t *testing.T) {
|
func TestNotification_GetIssue(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
||||||
issue, err := notf.GetIssue()
|
issue, err := notf.GetIssue(db.DefaultContext)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, issue, notf.Issue)
|
assert.Equal(t, issue, notf.Issue)
|
||||||
assert.EqualValues(t, notf.IssueID, issue.ID)
|
assert.EqualValues(t, notf.IssueID, issue.ID)
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
|||||||
|
|
||||||
// Published releases list
|
// Published releases list
|
||||||
sess := releasesForActivityStatement(ctx, repoID, fromTime)
|
sess := releasesForActivityStatement(ctx, repoID, fromTime)
|
||||||
sess.OrderBy("release.created_unix DESC")
|
sess.OrderBy("`release`.created_unix DESC")
|
||||||
stats.PublishedReleases = make([]*repo_model.Release, 0)
|
stats.PublishedReleases = make([]*repo_model.Release, 0)
|
||||||
if err = sess.Find(&stats.PublishedReleases); err != nil {
|
if err = sess.Find(&stats.PublishedReleases); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -350,7 +350,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
|||||||
|
|
||||||
// Published releases authors
|
// Published releases authors
|
||||||
sess = releasesForActivityStatement(ctx, repoID, fromTime)
|
sess = releasesForActivityStatement(ctx, repoID, fromTime)
|
||||||
if _, err = sess.Select("count(distinct release.publisher_id) as `count`").Table("release").Get(&count); err != nil {
|
if _, err = sess.Select("count(distinct `release`.publisher_id) as `count`").Table("release").Get(&count); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stats.PublishedReleaseAuthorCount = count
|
stats.PublishedReleaseAuthorCount = count
|
||||||
@@ -359,7 +359,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
|||||||
}
|
}
|
||||||
|
|
||||||
func releasesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
|
func releasesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
|
||||||
return db.GetEngine(ctx).Where("release.repo_id = ?", repoID).
|
return db.GetEngine(ctx).Where("`release`.repo_id = ?", repoID).
|
||||||
And("release.is_draft = ?", false).
|
And("`release`.is_draft = ?", false).
|
||||||
And("release.created_unix >= ?", fromTime.Unix())
|
And("`release`.created_unix >= ?", fromTime.Unix())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
package activities
|
package activities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"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"
|
||||||
@@ -18,16 +20,16 @@ type UserHeatmapData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
|
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
|
||||||
func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData, error) {
|
func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||||
return getUserHeatmapData(user, nil, doer)
|
return getUserHeatmapData(ctx, user, nil, doer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
|
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
|
||||||
func GetUserHeatmapDataByUserTeam(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||||
return getUserHeatmapData(user, team, doer)
|
return getUserHeatmapData(ctx, user, team, doer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||||
hdata := make([]*UserHeatmapData, 0)
|
hdata := make([]*UserHeatmapData, 0)
|
||||||
|
|
||||||
if !ActivityReadable(user, doer) {
|
if !ActivityReadable(user, doer) {
|
||||||
@@ -45,7 +47,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
|
|||||||
groupByName = groupBy
|
groupByName = groupBy
|
||||||
}
|
}
|
||||||
|
|
||||||
cond, err := activityQueryCondition(GetFeedsOptions{
|
cond, err := activityQueryCondition(ctx, GetFeedsOptions{
|
||||||
RequestedUser: user,
|
RequestedUser: user,
|
||||||
RequestedTeam: team,
|
RequestedTeam: team,
|
||||||
Actor: doer,
|
Actor: doer,
|
||||||
@@ -60,7 +62,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdata, db.GetEngine(db.DefaultContext).
|
return hdata, db.GetEngine(ctx).
|
||||||
Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
||||||
Table("action").
|
Table("action").
|
||||||
Where(cond).
|
Where(cond).
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Get the heatmap and compare
|
// Get the heatmap and compare
|
||||||
heatmap, err := activities_model.GetUserHeatmapDataByUser(user, doer)
|
heatmap, err := activities_model.GetUserHeatmapDataByUser(db.DefaultContext, user, doer)
|
||||||
var contributions int
|
var contributions int
|
||||||
for _, hm := range heatmap {
|
for _, hm := range heatmap {
|
||||||
contributions += int(hm.Contributions)
|
contributions += int(hm.Contributions)
|
||||||
|
|||||||
@@ -88,14 +88,14 @@ func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountUserGPGKeys return number of gpg keys a user own
|
// CountUserGPGKeys return number of gpg keys a user own
|
||||||
func CountUserGPGKeys(userID int64) (int64, error) {
|
func CountUserGPGKeys(ctx context.Context, userID int64) (int64, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGPGKeyByID returns public key by given ID.
|
// GetGPGKeyByID returns public key by given ID.
|
||||||
func GetGPGKeyByID(keyID int64) (*GPGKey, error) {
|
func GetGPGKeyByID(ctx context.Context, keyID int64) (*GPGKey, error) {
|
||||||
key := new(GPGKey)
|
key := new(GPGKey)
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(keyID).Get(key)
|
has, err := db.GetEngine(ctx).ID(keyID).Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
@@ -105,9 +105,9 @@ func GetGPGKeyByID(keyID int64) (*GPGKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetGPGKeysByKeyID returns public key by given ID.
|
// GetGPGKeysByKeyID returns public key by given ID.
|
||||||
func GetGPGKeysByKeyID(keyID string) ([]*GPGKey, error) {
|
func GetGPGKeysByKeyID(ctx context.Context, keyID string) ([]*GPGKey, error) {
|
||||||
keys := make([]*GPGKey, 0, 1)
|
keys := make([]*GPGKey, 0, 1)
|
||||||
return keys, db.GetEngine(db.DefaultContext).Where("key_id=?", keyID).Find(&keys)
|
return keys, db.GetEngine(ctx).Where("key_id=?", keyID).Find(&keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GPGKeyToEntity retrieve the imported key and the traducted entity
|
// GPGKeyToEntity retrieve the imported key and the traducted entity
|
||||||
@@ -224,8 +224,8 @@ func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteGPGKey deletes GPG key information in database.
|
// DeleteGPGKey deletes GPG key information in database.
|
||||||
func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
||||||
key, err := GetGPGKeyByID(id)
|
key, err := GetGPGKeyByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrGPGKeyNotExist(err) {
|
if IsErrGPGKeyNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
@@ -238,7 +238,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
|||||||
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddGPGKey adds new public key to database.
|
// AddGPGKey adds new public key to database.
|
||||||
func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, error) {
|
func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) {
|
||||||
ekeys, err := checkArmoredGPGKeyString(content)
|
ekeys, err := checkArmoredGPGKeyString(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
|
|||||||
if keyID == "" {
|
if keyID == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
keys, err := GetGPGKeysByKeyID(keyID)
|
keys, err := GetGPGKeysByKeyID(ctx, keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||||
return &CommitVerification{
|
return &CommitVerification{
|
||||||
@@ -407,7 +407,7 @@ func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
|
|||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
var primaryKeys []*GPGKey
|
var primaryKeys []*GPGKey
|
||||||
if key.PrimaryKeyID != "" {
|
if key.PrimaryKeyID != "" {
|
||||||
primaryKeys, err = GetGPGKeysByKeyID(key.PrimaryKeyID)
|
primaryKeys, err = GetGPGKeysByKeyID(ctx, key.PrimaryKeyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||||
return &CommitVerification{
|
return &CommitVerification{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"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/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
@@ -228,7 +229,7 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL
|
|||||||
=zHo9
|
=zHo9
|
||||||
-----END PGP PUBLIC KEY BLOCK-----`
|
-----END PGP PUBLIC KEY BLOCK-----`
|
||||||
|
|
||||||
keys, err := AddGPGKey(1, testEmailWithUpperCaseLetters, "", "")
|
keys, err := AddGPGKey(db.DefaultContext, 1, testEmailWithUpperCaseLetters, "", "")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.NotEmpty(t, keys) {
|
if assert.NotEmpty(t, keys) {
|
||||||
key := keys[0]
|
key := keys[0]
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
|||||||
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
|
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
|
||||||
// Note: db.GetEngine(db.DefaultContext).Iterate does not get latest data after insert/delete, so we have to call this function
|
// Note: db.GetEngine(db.DefaultContext).Iterate does not get latest data after insert/delete, so we have to call this function
|
||||||
// outside any session scope independently.
|
// outside any session scope independently.
|
||||||
func RewriteAllPublicKeys() error {
|
func RewriteAllPublicKeys(ctx context.Context) error {
|
||||||
// Don't rewrite key if internal server
|
// Don't rewrite key if internal server
|
||||||
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
|
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
|
||||||
return nil
|
return nil
|
||||||
@@ -165,7 +165,7 @@ func RewriteAllPublicKeys() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := RegeneratePublicKeys(db.DefaultContext, t); err != nil {
|
if err := RegeneratePublicKeys(ctx, t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+58
-23
@@ -5,18 +5,20 @@ package avatars
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"strk.kbt.io/projects/go/libravatar"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -36,24 +38,54 @@ func init() {
|
|||||||
db.RegisterModel(new(EmailHash))
|
db.RegisterModel(new(EmailHash))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
type avatarSettingStruct struct {
|
||||||
defaultAvatarLink string
|
defaultAvatarLink string
|
||||||
once sync.Once
|
gravatarSource string
|
||||||
)
|
gravatarSourceURL *url.URL
|
||||||
|
libravatar *libravatar.Libravatar
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultAvatarLink the default avatar link
|
var avatarSettingAtomic atomic.Pointer[avatarSettingStruct]
|
||||||
func DefaultAvatarLink() string {
|
|
||||||
once.Do(func() {
|
func loadAvatarSetting() (*avatarSettingStruct, error) {
|
||||||
|
s := avatarSettingAtomic.Load()
|
||||||
|
if s == nil || s.gravatarSource != setting.GravatarSource {
|
||||||
|
s = &avatarSettingStruct{}
|
||||||
u, err := url.Parse(setting.AppSubURL)
|
u, err := url.Parse(setting.AppSubURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Can not parse AppSubURL: %v", err)
|
return nil, fmt.Errorf("unable to parse AppSubURL: %w", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Path = path.Join(u.Path, "/assets/img/avatar_default.png")
|
u.Path = path.Join(u.Path, "/assets/img/avatar_default.png")
|
||||||
defaultAvatarLink = u.String()
|
s.defaultAvatarLink = u.String()
|
||||||
})
|
|
||||||
return defaultAvatarLink
|
s.gravatarSourceURL, err = url.Parse(setting.GravatarSource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to parse GravatarSource %q: %w", setting.GravatarSource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.libravatar = libravatar.New()
|
||||||
|
if s.gravatarSourceURL.Scheme == "https" {
|
||||||
|
s.libravatar.SetUseHTTPS(true)
|
||||||
|
s.libravatar.SetSecureFallbackHost(s.gravatarSourceURL.Host)
|
||||||
|
} else {
|
||||||
|
s.libravatar.SetUseHTTPS(false)
|
||||||
|
s.libravatar.SetFallbackHost(s.gravatarSourceURL.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarSettingAtomic.Store(s)
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultAvatarLink the default avatar link
|
||||||
|
func DefaultAvatarLink() string {
|
||||||
|
a, err := loadAvatarSetting()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to loadAvatarSetting: %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return a.defaultAvatarLink
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
|
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
|
||||||
@@ -76,7 +108,11 @@ func GetEmailForHash(md5Sum string) (string, error) {
|
|||||||
// LibravatarURL returns the URL for the given email. Slow due to the DNS lookup.
|
// LibravatarURL returns the URL for the given email. Slow due to the DNS lookup.
|
||||||
// This function should only be called if a federated avatar service is enabled.
|
// This function should only be called if a federated avatar service is enabled.
|
||||||
func LibravatarURL(email string) (*url.URL, error) {
|
func LibravatarURL(email string) (*url.URL, error) {
|
||||||
urlStr, err := system_model.LibravatarService.FromEmail(email)
|
a, err := loadAvatarSetting()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
urlStr, err := a.libravatar.FromEmail(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LibravatarService.FromEmail(email=%s): error %v", email, err)
|
log.Error("LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -153,15 +189,13 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
|
|||||||
return DefaultAvatarLink()
|
return DefaultAvatarLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar,
|
avatarSetting, err := loadAvatarSetting()
|
||||||
setting.GetDefaultDisableGravatar(),
|
if err != nil {
|
||||||
)
|
return DefaultAvatarLink()
|
||||||
|
}
|
||||||
|
|
||||||
enableFederatedAvatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureEnableFederatedAvatar,
|
enableFederatedAvatar := setting.Config().Picture.EnableFederatedAvatar.Value(ctx)
|
||||||
setting.GetDefaultEnableFederatedAvatar(disableGravatar))
|
if enableFederatedAvatar {
|
||||||
|
|
||||||
var err error
|
|
||||||
if enableFederatedAvatar && system_model.LibravatarService != nil {
|
|
||||||
emailHash := saveEmailHash(email)
|
emailHash := saveEmailHash(email)
|
||||||
if final {
|
if final {
|
||||||
// for final link, we can spend more time on slow external query
|
// for final link, we can spend more time on slow external query
|
||||||
@@ -179,9 +213,10 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
|
|||||||
return urlStr
|
return urlStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableGravatar := setting.Config().Picture.DisableGravatar.Value(ctx)
|
||||||
if !disableGravatar {
|
if !disableGravatar {
|
||||||
// copy GravatarSourceURL, because we will modify its Path.
|
// copy GravatarSourceURL, because we will modify its Path.
|
||||||
avatarURLCopy := *system_model.GravatarSourceURL
|
avatarURLCopy := *avatarSetting.gravatarSourceURL
|
||||||
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))
|
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))
|
||||||
return generateRecognizedAvatarURL(avatarURLCopy, size)
|
return generateRecognizedAvatarURL(avatarURLCopy, size)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/setting/config"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -17,19 +18,16 @@ import (
|
|||||||
const gravatarSource = "https://secure.gravatar.com/avatar/"
|
const gravatarSource = "https://secure.gravatar.com/avatar/"
|
||||||
|
|
||||||
func disableGravatar(t *testing.T) {
|
func disableGravatar(t *testing.T) {
|
||||||
err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureEnableFederatedAvatar, "false")
|
err := system_model.SetSettings(db.DefaultContext, map[string]string{setting.Config().Picture.EnableFederatedAvatar.DynKey(): "false"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "true")
|
err = system_model.SetSettings(db.DefaultContext, map[string]string{setting.Config().Picture.DisableGravatar.DynKey(): "true"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
system_model.LibravatarService = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func enableGravatar(t *testing.T) {
|
func enableGravatar(t *testing.T) {
|
||||||
err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "false")
|
err := system_model.SetSettings(db.DefaultContext, map[string]string{setting.Config().Picture.DisableGravatar.DynKey(): "false"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setting.GravatarSource = gravatarSource
|
setting.GravatarSource = gravatarSource
|
||||||
err = system_model.Init(db.DefaultContext)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHashEmail(t *testing.T) {
|
func TestHashEmail(t *testing.T) {
|
||||||
@@ -47,10 +45,12 @@ func TestSizedAvatarLink(t *testing.T) {
|
|||||||
setting.AppSubURL = "/testsuburl"
|
setting.AppSubURL = "/testsuburl"
|
||||||
|
|
||||||
disableGravatar(t)
|
disableGravatar(t)
|
||||||
|
config.GetDynGetter().InvalidateCache()
|
||||||
assert.Equal(t, "/testsuburl/assets/img/avatar_default.png",
|
assert.Equal(t, "/testsuburl/assets/img/avatar_default.png",
|
||||||
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100))
|
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100))
|
||||||
|
|
||||||
enableGravatar(t)
|
enableGravatar(t)
|
||||||
|
config.GetDynGetter().InvalidateCache()
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100",
|
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100",
|
||||||
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100),
|
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100),
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ func GetYamlFixturesAccess() (string, error) {
|
|||||||
fmt.Fprintf(&b, " user_id: %d\n", a.UserID)
|
fmt.Fprintf(&b, " user_id: %d\n", a.UserID)
|
||||||
fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID)
|
fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID)
|
||||||
fmt.Fprintf(&b, " mode: %d\n", a.Mode)
|
fmt.Fprintf(&b, " mode: %d\n", a.Mode)
|
||||||
fmt.Fprintf(&b, "\n")
|
if i < len(accesses)-1 {
|
||||||
|
fmt.Fprintf(&b, "\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.String(), nil
|
return b.String(), nil
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ func TestFixtureGeneration(t *testing.T) {
|
|||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bytes, err := os.ReadFile(filepath.Join(unittest.FixturesDir(), name+".yml"))
|
p := filepath.Join(unittest.FixturesDir(), name+".yml")
|
||||||
|
bytes, err := os.ReadFile(p)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := string(util.NormalizeEOL(bytes))
|
data := string(util.NormalizeEOL(bytes))
|
||||||
assert.True(t, data == expected, "Differences detected for %s.yml", name)
|
assert.EqualValues(t, expected, data, "Differences detected for %s", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
test(GetYamlFixturesAccess, "access")
|
test(GetYamlFixturesAccess, "access")
|
||||||
|
|||||||
@@ -135,4 +135,3 @@
|
|||||||
user_id: 31
|
user_id: 31
|
||||||
repo_id: 28
|
repo_id: 28
|
||||||
mode: 4
|
mode: 4
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
id: 1
|
id: 1
|
||||||
uid: 1
|
uid: 1
|
||||||
name: Token A
|
name: Token A
|
||||||
#token: d2c6c1ba3890b309189a8e618c72a162e4efbf36
|
# token: d2c6c1ba3890b309189a8e618c72a162e4efbf36
|
||||||
token_hash: 2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f
|
token_hash: 2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f
|
||||||
token_salt: QuSiZr1byZ
|
token_salt: QuSiZr1byZ
|
||||||
token_last_eight: e4efbf36
|
token_last_eight: e4efbf36
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
id: 2
|
id: 2
|
||||||
uid: 1
|
uid: 1
|
||||||
name: Token B
|
name: Token B
|
||||||
#token: 4c6f36e6cf498e2a448662f915d932c09c5a146c
|
# token: 4c6f36e6cf498e2a448662f915d932c09c5a146c
|
||||||
token_hash: 1a0e32a231ebbd582dc626c1543a42d3c63d4fa76c07c72862721467c55e8f81c923d60700f0528b5f5f443f055559d3a279
|
token_hash: 1a0e32a231ebbd582dc626c1543a42d3c63d4fa76c07c72862721467c55e8f81c923d60700f0528b5f5f443f055559d3a279
|
||||||
token_salt: Lfwopukrq5
|
token_salt: Lfwopukrq5
|
||||||
token_last_eight: 9c5a146c
|
token_last_eight: 9c5a146c
|
||||||
@@ -24,10 +24,10 @@
|
|||||||
id: 3
|
id: 3
|
||||||
uid: 2
|
uid: 2
|
||||||
name: Token A
|
name: Token A
|
||||||
#token: 90a18faa671dc43924b795806ffe4fd169d28c91
|
# token: 90a18faa671dc43924b795806ffe4fd169d28c91
|
||||||
token_hash: d6d404048048812d9e911d93aefbe94fc768d4876fdf75e3bef0bdc67828e0af422846d3056f2f25ec35c51dc92075685ec5
|
token_hash: d6d404048048812d9e911d93aefbe94fc768d4876fdf75e3bef0bdc67828e0af422846d3056f2f25ec35c51dc92075685ec5
|
||||||
token_salt: 99ArgXKlQQ
|
token_salt: 99ArgXKlQQ
|
||||||
token_last_eight: 69d28c91
|
token_last_eight: 69d28c91
|
||||||
created_unix: 946687980
|
created_unix: 946687980
|
||||||
updated_unix: 946687980
|
updated_unix: 946687980
|
||||||
#commented out tokens so you can see what they are in plaintext
|
# commented out tokens so you can see what they are in plaintext
|
||||||
|
|||||||
@@ -140,3 +140,16 @@
|
|||||||
download_count: 0
|
download_count: 0
|
||||||
size: 0
|
size: 0
|
||||||
created_unix: 946684800
|
created_unix: 946684800
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 12
|
||||||
|
uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a22
|
||||||
|
repo_id: 2
|
||||||
|
issue_id: 0
|
||||||
|
release_id: 11
|
||||||
|
uploader_id: 2
|
||||||
|
comment_id: 0
|
||||||
|
name: README.md
|
||||||
|
download_count: 0
|
||||||
|
size: 0
|
||||||
|
created_unix: 946684800
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
id: 1
|
id: 1
|
||||||
repo_id: 1
|
repo_id: 1
|
||||||
sha: "1234123412341234123412341234123412341234"
|
sha: "1234123412341234123412341234123412341234"
|
||||||
max_index: 5
|
max_index: 5
|
||||||
|
|||||||
@@ -321,3 +321,20 @@
|
|||||||
created_unix: 946684830
|
created_unix: 946684830
|
||||||
updated_unix: 978307200
|
updated_unix: 978307200
|
||||||
is_locked: false
|
is_locked: false
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 20
|
||||||
|
repo_id: 23
|
||||||
|
index: 1
|
||||||
|
poster_id: 2
|
||||||
|
original_author_id: 0
|
||||||
|
name: issue for pr
|
||||||
|
content: content
|
||||||
|
milestone_id: 0
|
||||||
|
priority: 0
|
||||||
|
is_closed: false
|
||||||
|
is_pull: true
|
||||||
|
num_comments: 0
|
||||||
|
created_unix: 978307210
|
||||||
|
updated_unix: 978307210
|
||||||
|
is_locked: false
|
||||||
|
|||||||
@@ -8,4 +8,4 @@
|
|||||||
type: 1
|
type: 1
|
||||||
created_unix: 1559593109
|
created_unix: 1559593109
|
||||||
updated_unix: 1565224552
|
updated_unix: 1565224552
|
||||||
login_source_id: 0
|
login_source_id: 0
|
||||||
|
|||||||
@@ -89,3 +89,12 @@
|
|||||||
base_branch: main
|
base_branch: main
|
||||||
merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6
|
merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6
|
||||||
has_merged: false
|
has_merged: false
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 8
|
||||||
|
type: 0 # gitea pull request
|
||||||
|
status: 2 # mergable
|
||||||
|
issue_id: 20
|
||||||
|
index: 1
|
||||||
|
head_repo_id: 23
|
||||||
|
base_repo_id: 23
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
-
|
-
|
||||||
id: 1 #issue reaction
|
id: 1 # issue reaction
|
||||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||||
issue_id: 1
|
issue_id: 1
|
||||||
comment_id: 0
|
comment_id: 0
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
created_unix: 1573248001
|
created_unix: 1573248001
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 2 #issue reaction
|
id: 2 # issue reaction
|
||||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||||
issue_id: 1
|
issue_id: 1
|
||||||
comment_id: 0
|
comment_id: 0
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
created_unix: 1573248002
|
created_unix: 1573248002
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 3 #issue reaction
|
id: 3 # issue reaction
|
||||||
type: eyes # allowed reaction
|
type: eyes # allowed reaction
|
||||||
issue_id: 1
|
issue_id: 1
|
||||||
comment_id: 0
|
comment_id: 0
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
created_unix: 1573248003
|
created_unix: 1573248003
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 4 #comment reaction
|
id: 4 # comment reaction
|
||||||
type: laugh # allowed reaction
|
type: laugh # allowed reaction
|
||||||
issue_id: 1
|
issue_id: 1
|
||||||
comment_id: 2
|
comment_id: 2
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
created_unix: 1573248004
|
created_unix: 1573248004
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 5 #comment reaction
|
id: 5 # comment reaction
|
||||||
type: laugh # allowed reaction
|
type: laugh # allowed reaction
|
||||||
issue_id: 1
|
issue_id: 1
|
||||||
comment_id: 2
|
comment_id: 2
|
||||||
|
|||||||
@@ -136,3 +136,17 @@
|
|||||||
is_prerelease: false
|
is_prerelease: false
|
||||||
is_tag: false
|
is_tag: false
|
||||||
created_unix: 946684803
|
created_unix: 946684803
|
||||||
|
|
||||||
|
- id: 11
|
||||||
|
repo_id: 2
|
||||||
|
publisher_id: 2
|
||||||
|
tag_name: "v1.1"
|
||||||
|
lower_tag_name: "v1.1"
|
||||||
|
target: ""
|
||||||
|
title: "v1.1"
|
||||||
|
sha1: "205ac761f3326a7ebe416e8673760016450b5cec"
|
||||||
|
num_commits: 2
|
||||||
|
is_draft: false
|
||||||
|
is_prerelease: false
|
||||||
|
is_tag: false
|
||||||
|
created_unix: 946684803
|
||||||
|
|||||||
@@ -679,7 +679,7 @@
|
|||||||
num_forks: 0
|
num_forks: 0
|
||||||
num_issues: 0
|
num_issues: 0
|
||||||
num_closed_issues: 0
|
num_closed_issues: 0
|
||||||
num_pulls: 0
|
num_pulls: 1
|
||||||
num_closed_pulls: 0
|
num_closed_pulls: 0
|
||||||
num_milestones: 0
|
num_milestones: 0
|
||||||
num_closed_milestones: 0
|
num_closed_milestones: 0
|
||||||
|
|||||||
@@ -132,3 +132,41 @@
|
|||||||
content: "singular review from org6 and final review for this pr"
|
content: "singular review from org6 and final review for this pr"
|
||||||
updated_unix: 946684831
|
updated_unix: 946684831
|
||||||
created_unix: 946684831
|
created_unix: 946684831
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 16
|
||||||
|
type: 4
|
||||||
|
reviewer_id: 20
|
||||||
|
issue_id: 20
|
||||||
|
content: "review request for user20"
|
||||||
|
updated_unix: 946684832
|
||||||
|
created_unix: 946684832
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 17
|
||||||
|
type: 1
|
||||||
|
reviewer_id: 20
|
||||||
|
issue_id: 20
|
||||||
|
content: "review approved by user20"
|
||||||
|
updated_unix: 946684833
|
||||||
|
created_unix: 946684833
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 18
|
||||||
|
type: 4
|
||||||
|
reviewer_id: 0
|
||||||
|
reviewer_team_id: 5
|
||||||
|
issue_id: 20
|
||||||
|
content: "review request for team5"
|
||||||
|
updated_unix: 946684834
|
||||||
|
created_unix: 946684834
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 19
|
||||||
|
type: 4
|
||||||
|
reviewer_id: 15
|
||||||
|
reviewer_team_id: 0
|
||||||
|
issue_id: 20
|
||||||
|
content: "review request for user15"
|
||||||
|
updated_unix: 946684835
|
||||||
|
created_unix: 946684835
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
name: review_team
|
name: review_team
|
||||||
authorize: 1 # read
|
authorize: 1 # read
|
||||||
num_repos: 1
|
num_repos: 1
|
||||||
num_members: 2
|
num_members: 3
|
||||||
includes_all_repositories: false
|
includes_all_repositories: false
|
||||||
can_create_org_repo: false
|
can_create_org_repo: false
|
||||||
|
|
||||||
|
|||||||
@@ -62,4 +62,4 @@
|
|||||||
id: 11
|
id: 11
|
||||||
org_id: 17
|
org_id: 17
|
||||||
team_id: 9
|
team_id: 9
|
||||||
repo_id: 24
|
repo_id: 24
|
||||||
|
|||||||
@@ -123,3 +123,9 @@
|
|||||||
org_id: 36
|
org_id: 36
|
||||||
team_id: 20
|
team_id: 20
|
||||||
uid: 5
|
uid: 5
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 22
|
||||||
|
org_id: 17
|
||||||
|
team_id: 9
|
||||||
|
uid: 15
|
||||||
|
|||||||
@@ -26,4 +26,4 @@
|
|||||||
id: 5
|
id: 5
|
||||||
user_id: 11
|
user_id: 11
|
||||||
repo_id: 1
|
repo_id: 1
|
||||||
mode: 3 # auto
|
mode: 3 # auto
|
||||||
|
|||||||
@@ -514,7 +514,7 @@ func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo
|
|||||||
user_model.ValidateCommitsWithEmails(ctx, commits),
|
user_model.ValidateCommitsWithEmails(ctx, commits),
|
||||||
repo.GetTrustModel(),
|
repo.GetTrustModel(),
|
||||||
func(user *user_model.User) (bool, error) {
|
func(user *user_model.User) (bool, error) {
|
||||||
return repo_model.IsOwnerMemberCollaborator(repo, user.ID)
|
return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
repo,
|
repo,
|
||||||
|
|||||||
+52
-52
@@ -246,7 +246,7 @@ type Comment struct {
|
|||||||
NewTitle string
|
NewTitle string
|
||||||
OldRef string
|
OldRef string
|
||||||
NewRef string
|
NewRef string
|
||||||
DependentIssueID int64
|
DependentIssueID int64 `xorm:"index"` // This is used by issue_service.deleteIssue
|
||||||
DependentIssue *Issue `xorm:"-"`
|
DependentIssue *Issue `xorm:"-"`
|
||||||
|
|
||||||
CommitID int64
|
CommitID int64
|
||||||
@@ -371,42 +371,42 @@ func (c *Comment) AfterDelete(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HTMLURL formats a URL-string to the issue-comment
|
// HTMLURL formats a URL-string to the issue-comment
|
||||||
func (c *Comment) HTMLURL() string {
|
func (c *Comment) HTMLURL(ctx context.Context) string {
|
||||||
err := c.LoadIssue(db.DefaultContext)
|
err := c.LoadIssue(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
err = c.Issue.LoadRepo(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return c.Issue.HTMLURL() + c.hashLink()
|
return c.Issue.HTMLURL() + c.hashLink(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link formats a relative URL-string to the issue-comment
|
// Link formats a relative URL-string to the issue-comment
|
||||||
func (c *Comment) Link() string {
|
func (c *Comment) Link(ctx context.Context) string {
|
||||||
err := c.LoadIssue(db.DefaultContext)
|
err := c.LoadIssue(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
err = c.Issue.LoadRepo(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return c.Issue.Link() + c.hashLink()
|
return c.Issue.Link() + c.hashLink(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) hashLink() string {
|
func (c *Comment) hashLink(ctx context.Context) string {
|
||||||
if c.Type == CommentTypeCode {
|
if c.Type == CommentTypeCode {
|
||||||
if c.ReviewID == 0 {
|
if c.ReviewID == 0 {
|
||||||
return "/files#" + c.HashTag()
|
return "/files#" + c.HashTag()
|
||||||
}
|
}
|
||||||
if c.Review == nil {
|
if c.Review == nil {
|
||||||
if err := c.LoadReview(); err != nil {
|
if err := c.LoadReview(ctx); err != nil {
|
||||||
log.Warn("LoadReview(%d): %v", c.ReviewID, err)
|
log.Warn("LoadReview(%d): %v", c.ReviewID, err)
|
||||||
return "/files#" + c.HashTag()
|
return "/files#" + c.HashTag()
|
||||||
}
|
}
|
||||||
@@ -419,13 +419,13 @@ func (c *Comment) hashLink() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// APIURL formats a API-string to the issue-comment
|
// APIURL formats a API-string to the issue-comment
|
||||||
func (c *Comment) APIURL() string {
|
func (c *Comment) APIURL(ctx context.Context) string {
|
||||||
err := c.LoadIssue(db.DefaultContext)
|
err := c.LoadIssue(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
err = c.Issue.LoadRepo(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||||
return ""
|
return ""
|
||||||
@@ -435,8 +435,8 @@ func (c *Comment) APIURL() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IssueURL formats a URL-string to the issue
|
// IssueURL formats a URL-string to the issue
|
||||||
func (c *Comment) IssueURL() string {
|
func (c *Comment) IssueURL(ctx context.Context) string {
|
||||||
err := c.LoadIssue(db.DefaultContext)
|
err := c.LoadIssue(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||||
return ""
|
return ""
|
||||||
@@ -446,7 +446,7 @@ func (c *Comment) IssueURL() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
err = c.Issue.LoadRepo(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||||
return ""
|
return ""
|
||||||
@@ -455,14 +455,14 @@ func (c *Comment) IssueURL() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PRURL formats a URL-string to the pull-request
|
// PRURL formats a URL-string to the pull-request
|
||||||
func (c *Comment) PRURL() string {
|
func (c *Comment) PRURL(ctx context.Context) string {
|
||||||
err := c.LoadIssue(db.DefaultContext)
|
err := c.LoadIssue(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
err = c.Issue.LoadRepo(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||||
return ""
|
return ""
|
||||||
@@ -490,9 +490,9 @@ func (c *Comment) EventTag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadLabel if comment.Type is CommentTypeLabel, then load Label
|
// LoadLabel if comment.Type is CommentTypeLabel, then load Label
|
||||||
func (c *Comment) LoadLabel() error {
|
func (c *Comment) LoadLabel(ctx context.Context) error {
|
||||||
var label Label
|
var label Label
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(c.LabelID).Get(&label)
|
has, err := db.GetEngine(ctx).ID(c.LabelID).Get(&label)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if has {
|
} else if has {
|
||||||
@@ -506,10 +506,10 @@ func (c *Comment) LoadLabel() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadProject if comment.Type is CommentTypeProject, then load project.
|
// LoadProject if comment.Type is CommentTypeProject, then load project.
|
||||||
func (c *Comment) LoadProject() error {
|
func (c *Comment) LoadProject(ctx context.Context) error {
|
||||||
if c.OldProjectID > 0 {
|
if c.OldProjectID > 0 {
|
||||||
var oldProject project_model.Project
|
var oldProject project_model.Project
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(c.OldProjectID).Get(&oldProject)
|
has, err := db.GetEngine(ctx).ID(c.OldProjectID).Get(&oldProject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if has {
|
} else if has {
|
||||||
@@ -519,7 +519,7 @@ func (c *Comment) LoadProject() error {
|
|||||||
|
|
||||||
if c.ProjectID > 0 {
|
if c.ProjectID > 0 {
|
||||||
var project project_model.Project
|
var project project_model.Project
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(c.ProjectID).Get(&project)
|
has, err := db.GetEngine(ctx).ID(c.ProjectID).Get(&project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if has {
|
} else if has {
|
||||||
@@ -569,8 +569,8 @@ func (c *Comment) LoadAttachments(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAttachments update attachments by UUIDs for the comment
|
// UpdateAttachments update attachments by UUIDs for the comment
|
||||||
func (c *Comment) UpdateAttachments(uuids []string) error {
|
func (c *Comment) UpdateAttachments(ctx context.Context, uuids []string) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -591,11 +591,11 @@ func (c *Comment) UpdateAttachments(uuids []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees
|
// LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees
|
||||||
func (c *Comment) LoadAssigneeUserAndTeam() error {
|
func (c *Comment) LoadAssigneeUserAndTeam(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if c.AssigneeID > 0 && c.Assignee == nil {
|
if c.AssigneeID > 0 && c.Assignee == nil {
|
||||||
c.Assignee, err = user_model.GetUserByID(db.DefaultContext, c.AssigneeID)
|
c.Assignee, err = user_model.GetUserByID(ctx, c.AssigneeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !user_model.IsErrUserNotExist(err) {
|
if !user_model.IsErrUserNotExist(err) {
|
||||||
return err
|
return err
|
||||||
@@ -603,20 +603,20 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
|
|||||||
c.Assignee = user_model.NewGhostUser()
|
c.Assignee = user_model.NewGhostUser()
|
||||||
}
|
}
|
||||||
} else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil {
|
} else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil {
|
||||||
if err = c.LoadIssue(db.DefaultContext); err != nil {
|
if err = c.LoadIssue(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.Issue.LoadRepo(db.DefaultContext); err != nil {
|
if err = c.Issue.LoadRepo(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.Issue.Repo.LoadOwner(db.DefaultContext); err != nil {
|
if err = c.Issue.Repo.LoadOwner(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Issue.Repo.Owner.IsOrganization() {
|
if c.Issue.Repo.Owner.IsOrganization() {
|
||||||
c.AssigneeTeam, err = organization.GetTeamByID(db.DefaultContext, c.AssigneeTeamID)
|
c.AssigneeTeam, err = organization.GetTeamByID(ctx, c.AssigneeTeamID)
|
||||||
if err != nil && !organization.IsErrTeamNotExist(err) {
|
if err != nil && !organization.IsErrTeamNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -626,11 +626,11 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadResolveDoer if comment.Type is CommentTypeCode and ResolveDoerID not zero, then load resolveDoer
|
// LoadResolveDoer if comment.Type is CommentTypeCode and ResolveDoerID not zero, then load resolveDoer
|
||||||
func (c *Comment) LoadResolveDoer() (err error) {
|
func (c *Comment) LoadResolveDoer(ctx context.Context) (err error) {
|
||||||
if c.ResolveDoerID == 0 || c.Type != CommentTypeCode {
|
if c.ResolveDoerID == 0 || c.Type != CommentTypeCode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.ResolveDoer, err = user_model.GetUserByID(db.DefaultContext, c.ResolveDoerID)
|
c.ResolveDoer, err = user_model.GetUserByID(ctx, c.ResolveDoerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
if user_model.IsErrUserNotExist(err) {
|
||||||
c.ResolveDoer = user_model.NewGhostUser()
|
c.ResolveDoer = user_model.NewGhostUser()
|
||||||
@@ -646,11 +646,11 @@ func (c *Comment) IsResolved() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadDepIssueDetails loads Dependent Issue Details
|
// LoadDepIssueDetails loads Dependent Issue Details
|
||||||
func (c *Comment) LoadDepIssueDetails() (err error) {
|
func (c *Comment) LoadDepIssueDetails(ctx context.Context) (err error) {
|
||||||
if c.DependentIssueID <= 0 || c.DependentIssue != nil {
|
if c.DependentIssueID <= 0 || c.DependentIssue != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.DependentIssue, err = GetIssueByID(db.DefaultContext, c.DependentIssueID)
|
c.DependentIssue, err = GetIssueByID(ctx, c.DependentIssueID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,8 +683,8 @@ func (c *Comment) loadReactions(ctx context.Context, repo *repo_model.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadReactions loads comment reactions
|
// LoadReactions loads comment reactions
|
||||||
func (c *Comment) LoadReactions(repo *repo_model.Repository) error {
|
func (c *Comment) LoadReactions(ctx context.Context, repo *repo_model.Repository) error {
|
||||||
return c.loadReactions(db.DefaultContext, repo)
|
return c.loadReactions(ctx, repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) loadReview(ctx context.Context) (err error) {
|
func (c *Comment) loadReview(ctx context.Context) (err error) {
|
||||||
@@ -698,8 +698,8 @@ func (c *Comment) loadReview(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadReview loads the associated review
|
// LoadReview loads the associated review
|
||||||
func (c *Comment) LoadReview() error {
|
func (c *Comment) LoadReview(ctx context.Context) error {
|
||||||
return c.loadReview(db.DefaultContext)
|
return c.loadReview(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes.
|
// DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes.
|
||||||
@@ -719,13 +719,13 @@ func (c *Comment) UnsignedLine() uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CodeCommentLink returns the url to a comment in code
|
// CodeCommentLink returns the url to a comment in code
|
||||||
func (c *Comment) CodeCommentLink() string {
|
func (c *Comment) CodeCommentLink(ctx context.Context) string {
|
||||||
err := c.LoadIssue(db.DefaultContext)
|
err := c.LoadIssue(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
err = c.Issue.LoadRepo(ctx)
|
||||||
if err != nil { // Silently dropping errors :unamused:
|
if err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||||
return ""
|
return ""
|
||||||
@@ -1074,8 +1074,8 @@ func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountComments count all comments according options by ignoring pagination
|
// CountComments count all comments according options by ignoring pagination
|
||||||
func CountComments(opts *FindCommentsOptions) (int64, error) {
|
func CountComments(ctx context.Context, opts *FindCommentsOptions) (int64, error) {
|
||||||
sess := db.GetEngine(db.DefaultContext).Where(opts.ToConds())
|
sess := db.GetEngine(ctx).Where(opts.ToConds())
|
||||||
if opts.RepoID > 0 {
|
if opts.RepoID > 0 {
|
||||||
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
|
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
|
||||||
}
|
}
|
||||||
@@ -1089,8 +1089,8 @@ func UpdateCommentInvalidate(ctx context.Context, c *Comment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateComment updates information of comment.
|
// UpdateComment updates information of comment.
|
||||||
func UpdateComment(c *Comment, doer *user_model.User) error {
|
func UpdateComment(ctx context.Context, c *Comment, doer *user_model.User) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1147,8 +1147,8 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
|
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
|
||||||
func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
func UpdateCommentsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("comment").
|
_, err := db.GetEngine(ctx).Table("comment").
|
||||||
Where(builder.In("issue_id",
|
Where(builder.In("issue_id",
|
||||||
builder.Select("issue.id").
|
builder.Select("issue.id").
|
||||||
From("issue").
|
From("issue").
|
||||||
@@ -1250,7 +1250,7 @@ func (c *Comment) HasOriginalAuthor() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertIssueComments inserts many comments of issues.
|
// InsertIssueComments inserts many comments of issues.
|
||||||
func InsertIssueComments(comments []*Comment) error {
|
func InsertIssueComments(ctx context.Context, comments []*Comment) error {
|
||||||
if len(comments) == 0 {
|
if len(comments) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1260,7 +1260,7 @@ func InsertIssueComments(comments []*Comment) error {
|
|||||||
issueIDs.Add(comment.IssueID)
|
issueIDs.Add(comment.IssueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,11 +99,11 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
|
|||||||
comments[n] = comment
|
comments[n] = comment
|
||||||
n++
|
n++
|
||||||
|
|
||||||
if err := comment.LoadResolveDoer(); err != nil {
|
if err := comment.LoadResolveDoer(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := comment.LoadReactions(issue.Repo); err != nil {
|
if err := comment.LoadReactions(ctx, issue.Repo); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommentList defines a list of comments
|
// CommentList defines a list of comments
|
||||||
@@ -422,37 +423,18 @@ func (comments CommentList) loadReviews(ctx context.Context) error {
|
|||||||
|
|
||||||
reviewIDs := comments.getReviewIDs()
|
reviewIDs := comments.getReviewIDs()
|
||||||
reviews := make(map[int64]*Review, len(reviewIDs))
|
reviews := make(map[int64]*Review, len(reviewIDs))
|
||||||
left := len(reviewIDs)
|
if err := db.GetEngine(ctx).In("id", reviewIDs).Find(&reviews); err != nil {
|
||||||
for left > 0 {
|
return err
|
||||||
limit := db.DefaultMaxInSize
|
|
||||||
if left < limit {
|
|
||||||
limit = left
|
|
||||||
}
|
|
||||||
rows, err := db.GetEngine(ctx).
|
|
||||||
In("id", reviewIDs[:limit]).
|
|
||||||
Rows(new(Review))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var review Review
|
|
||||||
err = rows.Scan(&review)
|
|
||||||
if err != nil {
|
|
||||||
_ = rows.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
reviews[review.ID] = &review
|
|
||||||
}
|
|
||||||
_ = rows.Close()
|
|
||||||
|
|
||||||
left -= limit
|
|
||||||
reviewIDs = reviewIDs[limit:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
comment.Review = reviews[comment.ReviewID]
|
comment.Review = reviews[comment.ReviewID]
|
||||||
|
if comment.Review == nil {
|
||||||
|
if comment.ReviewID > 0 {
|
||||||
|
log.Error("comment with review id [%d] but has no review record", comment.ReviewID)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// If the comment dismisses a review, we need to load the reviewer to show whose review has been dismissed.
|
// If the comment dismisses a review, we need to load the reviewer to show whose review has been dismissed.
|
||||||
// Otherwise, the reviewer is the poster of the comment, so we don't need to load it.
|
// Otherwise, the reviewer is the poster of the comment, so we don't need to load it.
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func TestMigrate_InsertIssueComments(t *testing.T) {
|
|||||||
Reactions: []*issues_model.Reaction{reaction},
|
Reactions: []*issues_model.Reaction{reaction},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := issues_model.InsertIssueComments([]*issues_model.Comment{comment})
|
err := issues_model.InsertIssueComments(db.DefaultContext, []*issues_model.Comment{comment})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||||
|
|||||||
@@ -3,12 +3,16 @@
|
|||||||
|
|
||||||
package issues
|
package issues
|
||||||
|
|
||||||
import "code.gitea.io/gitea/models/db"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
)
|
||||||
|
|
||||||
// RecalculateIssueIndexForRepo create issue_index for repo if not exist and
|
// RecalculateIssueIndexForRepo create issue_index for repo if not exist and
|
||||||
// update it based on highest index of existing issues assigned to a repo
|
// update it based on highest index of existing issues assigned to a repo
|
||||||
func RecalculateIssueIndexForRepo(repoID int64) error {
|
func RecalculateIssueIndexForRepo(ctx context.Context, repoID int64) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue.Labels = append(issue.Labels, label)
|
||||||
|
|
||||||
return updateLabelCols(ctx, label, "num_issues", "num_closed_issue")
|
return updateLabelCols(ctx, label, "num_issues", "num_closed_issue")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +124,11 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
|
|||||||
if err = issue.LoadRepo(ctx); err != nil {
|
if err = issue.LoadRepo(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = issue.LoadLabels(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, l := range labels {
|
for _, l := range labels {
|
||||||
// Don't add already present labels and invalid labels
|
// Don't add already present labels and invalid labels
|
||||||
if HasIssueLabel(ctx, issue.ID, l.ID) ||
|
if HasIssueLabel(ctx, issue.ID, l.ID) ||
|
||||||
@@ -129,6 +136,10 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = RemoveDuplicateExclusiveIssueLabels(ctx, issue, l, doer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err = newIssueLabel(ctx, issue, l, doer); err != nil {
|
if err = newIssueLabel(ctx, issue, l, doer); err != nil {
|
||||||
return fmt.Errorf("newIssueLabel: %w", err)
|
return fmt.Errorf("newIssueLabel: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package issues_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewIssueLabelsScope(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 18})
|
||||||
|
label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 7})
|
||||||
|
label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 8})
|
||||||
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.NewIssueLabels(issue, []*issues_model.Label{label1, label2}, doer))
|
||||||
|
|
||||||
|
assert.Len(t, issue.Labels, 1)
|
||||||
|
assert.Equal(t, label2.ID, issue.Labels[0].ID)
|
||||||
|
}
|
||||||
@@ -362,14 +362,21 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64)
|
|||||||
From("team_user").
|
From("team_user").
|
||||||
Where(builder.Eq{"team_user.uid": reviewRequestedID})
|
Where(builder.Eq{"team_user.uid": reviewRequestedID})
|
||||||
|
|
||||||
|
// if the review is approved or rejected, it should not be shown in the review requested list
|
||||||
|
maxReview := builder.Select("MAX(r.id)").
|
||||||
|
From("review as r").
|
||||||
|
Where(builder.In("r.type", []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest})).
|
||||||
|
GroupBy("r.issue_id, r.reviewer_id, r.reviewer_team_id")
|
||||||
|
|
||||||
subQuery := builder.Select("review.issue_id").
|
subQuery := builder.Select("review.issue_id").
|
||||||
From("review").
|
From("review").
|
||||||
Where(builder.And(
|
Where(builder.And(
|
||||||
builder.In("review.type", []ReviewType{ReviewTypeRequest, ReviewTypeReject, ReviewTypeApprove}),
|
builder.Eq{"review.type": ReviewTypeRequest},
|
||||||
builder.Or(
|
builder.Or(
|
||||||
builder.Eq{"review.reviewer_id": reviewRequestedID},
|
builder.Eq{"review.reviewer_id": reviewRequestedID},
|
||||||
builder.In("review.reviewer_team_id", existInTeamQuery),
|
builder.In("review.reviewer_team_id", existInTeamQuery),
|
||||||
),
|
),
|
||||||
|
builder.In("review.id", maxReview),
|
||||||
))
|
))
|
||||||
return sess.Where("issue.poster_id <> ?", reviewRequestedID).
|
return sess.Where("issue.poster_id <> ?", reviewRequestedID).
|
||||||
And(builder.In("issue.id", subQuery))
|
And(builder.In("issue.id", subQuery))
|
||||||
|
|||||||
@@ -80,9 +80,9 @@ func CountIssues(ctx context.Context, opts *IssuesOptions) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueStats returns issue statistic information by given conditions.
|
// GetIssueStats returns issue statistic information by given conditions.
|
||||||
func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) {
|
func GetIssueStats(ctx context.Context, opts *IssuesOptions) (*IssueStats, error) {
|
||||||
if len(opts.IssueIDs) <= MaxQueryParameters {
|
if len(opts.IssueIDs) <= MaxQueryParameters {
|
||||||
return getIssueStatsChunk(opts, opts.IssueIDs)
|
return getIssueStatsChunk(ctx, opts, opts.IssueIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If too long a list of IDs is provided, we get the statistics in
|
// If too long a list of IDs is provided, we get the statistics in
|
||||||
@@ -95,7 +95,7 @@ func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) {
|
|||||||
if chunk > len(opts.IssueIDs) {
|
if chunk > len(opts.IssueIDs) {
|
||||||
chunk = len(opts.IssueIDs)
|
chunk = len(opts.IssueIDs)
|
||||||
}
|
}
|
||||||
stats, err := getIssueStatsChunk(opts, opts.IssueIDs[i:chunk])
|
stats, err := getIssueStatsChunk(ctx, opts, opts.IssueIDs[i:chunk])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -112,10 +112,10 @@ func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) {
|
|||||||
return accum, nil
|
return accum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIssueStatsChunk(opts *IssuesOptions, issueIDs []int64) (*IssueStats, error) {
|
func getIssueStatsChunk(ctx context.Context, opts *IssuesOptions, issueIDs []int64) (*IssueStats, error) {
|
||||||
stats := &IssueStats{}
|
stats := &IssueStats{}
|
||||||
|
|
||||||
sess := db.GetEngine(db.DefaultContext).
|
sess := db.GetEngine(ctx).
|
||||||
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *is
|
|||||||
Title: title,
|
Title: title,
|
||||||
Content: content,
|
Content: content,
|
||||||
}
|
}
|
||||||
err := issues_model.NewIssue(repo, &issue, nil, nil)
|
err := issues_model.NewIssue(db.DefaultContext, repo, &issue, nil, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Get(&newIssue)
|
has, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Get(&newIssue)
|
||||||
@@ -369,7 +369,7 @@ func TestCorrectIssueStats(t *testing.T) {
|
|||||||
|
|
||||||
// Now we will call the GetIssueStats with these IDs and if working,
|
// Now we will call the GetIssueStats with these IDs and if working,
|
||||||
// get the correct stats back.
|
// get the correct stats back.
|
||||||
issueStats, err := issues_model.GetIssueStats(&issues_model.IssuesOptions{
|
issueStats, err := issues_model.GetIssueStats(db.DefaultContext, &issues_model.IssuesOptions{
|
||||||
RepoIDs: []int64{1},
|
RepoIDs: []int64{1},
|
||||||
IssueIDs: ids,
|
IssueIDs: ids,
|
||||||
})
|
})
|
||||||
@@ -403,7 +403,7 @@ func TestCountIssues(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{})
|
count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 19, count)
|
assert.EqualValues(t, 20, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueLoadAttributes(t *testing.T) {
|
func TestIssueLoadAttributes(t *testing.T) {
|
||||||
|
|||||||
@@ -165,8 +165,8 @@ func ChangeIssueTitle(ctx context.Context, issue *Issue, doer *user_model.User,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ChangeIssueRef changes the branch of this issue, as the given user.
|
// ChangeIssueRef changes the branch of this issue, as the given user.
|
||||||
func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err error) {
|
func ChangeIssueRef(ctx context.Context, issue *Issue, doer *user_model.User, oldRef string) (err error) {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -215,8 +215,8 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssueAttachments update attachments by UUIDs for the issue
|
// UpdateIssueAttachments update attachments by UUIDs for the issue
|
||||||
func UpdateIssueAttachments(issueID int64, uuids []string) (err error) {
|
func UpdateIssueAttachments(ctx context.Context, issueID int64, uuids []string) (err error) {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -235,8 +235,8 @@ func UpdateIssueAttachments(issueID int64, uuids []string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ChangeIssueContent changes issue content, as the given user.
|
// ChangeIssueContent changes issue content, as the given user.
|
||||||
func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (err error) {
|
func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User, content string) (err error) {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -381,8 +381,8 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewIssue creates new issue with labels for repository.
|
// NewIssue creates new issue with labels for repository.
|
||||||
func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -432,8 +432,8 @@ func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_mo
|
|||||||
// UpdateIssueByAPI updates all allowed fields of given issue.
|
// UpdateIssueByAPI updates all allowed fields of given issue.
|
||||||
// If the issue status is changed a statusChangeComment is returned
|
// If the issue status is changed a statusChangeComment is returned
|
||||||
// similarly if the title is changed the titleChanged bool is set to true
|
// similarly if the title is changed the titleChanged bool is set to true
|
||||||
func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) {
|
func UpdateIssueByAPI(ctx context.Context, issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@@ -486,12 +486,12 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it.
|
// UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it.
|
||||||
func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) {
|
func UpdateIssueDeadline(ctx context.Context, issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) {
|
||||||
// if the deadline hasn't changed do nothing
|
// if the deadline hasn't changed do nothing
|
||||||
if issue.DeadlineUnix == deadlineUnix {
|
if issue.DeadlineUnix == deadlineUnix {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -669,8 +669,8 @@ func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *u
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssuesMigrationsByType updates all migrated repositories' issues from gitServiceType to replace originalAuthorID to posterID
|
// UpdateIssuesMigrationsByType updates all migrated repositories' issues from gitServiceType to replace originalAuthorID to posterID
|
||||||
func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, posterID int64) error {
|
func UpdateIssuesMigrationsByType(ctx context.Context, gitServiceType api.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("issue").
|
_, err := db.GetEngine(ctx).Table("issue").
|
||||||
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||||
And("original_author_id = ?", originalAuthorID).
|
And("original_author_id = ?", originalAuthorID).
|
||||||
Update(map[string]any{
|
Update(map[string]any{
|
||||||
@@ -682,8 +682,8 @@ func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAut
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID
|
// UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID
|
||||||
func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error {
|
func UpdateReactionsMigrationsByType(ctx context.Context, gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("reaction").
|
_, err := db.GetEngine(ctx).Table("reaction").
|
||||||
Where("original_author_id = ?", originalAuthorID).
|
Where("original_author_id = ?", originalAuthorID).
|
||||||
And(migratedIssueCond(gitServiceType)).
|
And(migratedIssueCond(gitServiceType)).
|
||||||
Update(map[string]any{
|
Update(map[string]any{
|
||||||
@@ -696,85 +696,100 @@ func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, original
|
|||||||
|
|
||||||
// DeleteIssuesByRepoID deletes issues by repositories id
|
// DeleteIssuesByRepoID deletes issues by repositories id
|
||||||
func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []string, err error) {
|
func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []string, err error) {
|
||||||
deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID})
|
// MariaDB has a performance bug: https://jira.mariadb.org/browse/MDEV-16289
|
||||||
|
// so here it uses "DELETE ... WHERE IN" with pre-queried IDs.
|
||||||
sess := db.GetEngine(ctx)
|
sess := db.GetEngine(ctx)
|
||||||
// Delete content histories
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
|
||||||
Delete(&ContentHistory{}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete comments and attachments
|
for {
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
issueIDs := make([]int64, 0, db.DefaultMaxInSize)
|
||||||
Delete(&Comment{}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dependencies for issues in this repository
|
err := sess.Table(&Issue{}).Where("repo_id = ?", repoID).OrderBy("id").Limit(db.DefaultMaxInSize).Cols("id").Find(&issueIDs)
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
if err != nil {
|
||||||
Delete(&IssueDependency{}); err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Delete dependencies for issues in other repositories
|
if len(issueIDs) == 0 {
|
||||||
if _, err = sess.In("dependency_id", deleteCond).
|
break
|
||||||
Delete(&IssueDependency{}); err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
// Delete content histories
|
||||||
Delete(&IssueUser{}); err != nil {
|
_, err = sess.In("issue_id", issueIDs).Delete(&ContentHistory{})
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
// Delete comments and attachments
|
||||||
Delete(&Reaction{}); err != nil {
|
_, err = sess.In("issue_id", issueIDs).Delete(&Comment{})
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
// Dependencies for issues in this repository
|
||||||
Delete(&IssueWatch{}); err != nil {
|
_, err = sess.In("issue_id", issueIDs).Delete(&IssueDependency{})
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
// Delete dependencies for issues in other repositories
|
||||||
Delete(&Stopwatch{}); err != nil {
|
_, err = sess.In("dependency_id", issueIDs).Delete(&IssueDependency{})
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
_, err = sess.In("issue_id", issueIDs).Delete(&IssueUser{})
|
||||||
Delete(&TrackedTime{}); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
_, err = sess.In("issue_id", issueIDs).Delete(&Reaction{})
|
||||||
Delete(&project_model.ProjectIssue{}); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.In("dependent_issue_id", deleteCond).
|
_, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{})
|
||||||
Delete(&Comment{}); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachments []*repo_model.Attachment
|
_, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{})
|
||||||
if err = sess.In("issue_id", deleteCond).
|
if err != nil {
|
||||||
Find(&attachments); err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for j := range attachments {
|
_, err = sess.In("issue_id", issueIDs).Delete(&TrackedTime{})
|
||||||
attachmentPaths = append(attachmentPaths, attachments[j].RelativePath())
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
_, err = sess.In("issue_id", issueIDs).Delete(&project_model.ProjectIssue{})
|
||||||
Delete(&repo_model.Attachment{}); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = db.DeleteByBean(ctx, &Issue{RepoID: repoID}); err != nil {
|
_, err = sess.In("dependent_issue_id", issueIDs).Delete(&Comment{})
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachments []*repo_model.Attachment
|
||||||
|
err = sess.In("issue_id", issueIDs).Find(&attachments)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := range attachments {
|
||||||
|
attachmentPaths = append(attachmentPaths, attachments[j].RelativePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = sess.In("issue_id", issueIDs).Delete(&repo_model.Attachment{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = sess.In("id", issueIDs).Delete(&Issue{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachmentPaths, err
|
return attachmentPaths, err
|
||||||
@@ -809,7 +824,7 @@ func DeleteOrphanedIssues(ctx context.Context) error {
|
|||||||
|
|
||||||
// Remove issue attachment files.
|
// Remove issue attachment files.
|
||||||
for i := range attachmentPaths {
|
for i := range attachmentPaths {
|
||||||
system_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i])
|
system_model.RemoveAllWithNotice(ctx, "Delete issue attachment", attachmentPaths[i])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
type IssueUser struct {
|
type IssueUser struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UID int64 `xorm:"INDEX"` // User ID.
|
UID int64 `xorm:"INDEX"` // User ID.
|
||||||
IssueID int64
|
IssueID int64 `xorm:"INDEX"`
|
||||||
IsRead bool
|
IsRead bool
|
||||||
IsMentioned bool
|
IsMentioned bool
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -252,22 +252,22 @@ func (c *Comment) neuterCrossReferences(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadRefComment loads comment that created this reference from database
|
// LoadRefComment loads comment that created this reference from database
|
||||||
func (c *Comment) LoadRefComment() (err error) {
|
func (c *Comment) LoadRefComment(ctx context.Context) (err error) {
|
||||||
if c.RefComment != nil {
|
if c.RefComment != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.RefComment, err = GetCommentByID(db.DefaultContext, c.RefCommentID)
|
c.RefComment, err = GetCommentByID(ctx, c.RefCommentID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadRefIssue loads comment that created this reference from database
|
// LoadRefIssue loads comment that created this reference from database
|
||||||
func (c *Comment) LoadRefIssue() (err error) {
|
func (c *Comment) LoadRefIssue(ctx context.Context) (err error) {
|
||||||
if c.RefIssue != nil {
|
if c.RefIssue != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.RefIssue, err = GetIssueByID(db.DefaultContext, c.RefIssueID)
|
c.RefIssue, err = GetIssueByID(ctx, c.RefIssueID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = c.RefIssue.LoadRepo(db.DefaultContext)
|
err = c.RefIssue.LoadRepo(ctx)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -278,21 +278,21 @@ func CommentTypeIsRef(t CommentType) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RefCommentLink returns the relative URL for the comment that created this reference
|
// RefCommentLink returns the relative URL for the comment that created this reference
|
||||||
func (c *Comment) RefCommentLink() string {
|
func (c *Comment) RefCommentLink(ctx context.Context) string {
|
||||||
// Edge case for when the reference is inside the title or the description of the referring issue
|
// Edge case for when the reference is inside the title or the description of the referring issue
|
||||||
if c.RefCommentID == 0 {
|
if c.RefCommentID == 0 {
|
||||||
return c.RefIssueLink()
|
return c.RefIssueLink(ctx)
|
||||||
}
|
}
|
||||||
if err := c.LoadRefComment(); err != nil { // Silently dropping errors :unamused:
|
if err := c.LoadRefComment(ctx); err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadRefComment(%d): %v", c.RefCommentID, err)
|
log.Error("LoadRefComment(%d): %v", c.RefCommentID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return c.RefComment.Link()
|
return c.RefComment.Link(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefIssueLink returns the relative URL of the issue where this reference was created
|
// RefIssueLink returns the relative URL of the issue where this reference was created
|
||||||
func (c *Comment) RefIssueLink() string {
|
func (c *Comment) RefIssueLink(ctx context.Context) string {
|
||||||
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
|
if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -300,8 +300,8 @@ func (c *Comment) RefIssueLink() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RefIssueTitle returns the title of the issue where this reference was created
|
// RefIssueTitle returns the title of the issue where this reference was created
|
||||||
func (c *Comment) RefIssueTitle() string {
|
func (c *Comment) RefIssueTitle(ctx context.Context) string {
|
||||||
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
|
if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -309,8 +309,8 @@ func (c *Comment) RefIssueTitle() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RefIssueIdent returns the user friendly identity (e.g. "#1234") of the issue where this reference was created
|
// RefIssueIdent returns the user friendly identity (e.g. "#1234") of the issue where this reference was created
|
||||||
func (c *Comment) RefIssueIdent() string {
|
func (c *Comment) RefIssueIdent(ctx context.Context) string {
|
||||||
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
|
if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused:
|
||||||
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
reviews, err := GetReviewsByIssueID(pr.Issue.ID)
|
reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -71,11 +71,11 @@ type Reaction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadUser load user of reaction
|
// LoadUser load user of reaction
|
||||||
func (r *Reaction) LoadUser() (*user_model.User, error) {
|
func (r *Reaction) LoadUser(ctx context.Context) (*user_model.User, error) {
|
||||||
if r.User != nil {
|
if r.User != nil {
|
||||||
return r.User, nil
|
return r.User, nil
|
||||||
}
|
}
|
||||||
user, err := user_model.GetUserByID(db.DefaultContext, r.UserID)
|
user, err := user_model.GetUserByID(ctx, r.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -141,16 +141,16 @@ func (opts *FindReactionsOptions) toConds() builder.Cond {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindCommentReactions returns a ReactionList of all reactions from an comment
|
// FindCommentReactions returns a ReactionList of all reactions from an comment
|
||||||
func FindCommentReactions(issueID, commentID int64) (ReactionList, int64, error) {
|
func FindCommentReactions(ctx context.Context, issueID, commentID int64) (ReactionList, int64, error) {
|
||||||
return FindReactions(db.DefaultContext, FindReactionsOptions{
|
return FindReactions(ctx, FindReactionsOptions{
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
CommentID: commentID,
|
CommentID: commentID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindIssueReactions returns a ReactionList of all reactions from an issue
|
// FindIssueReactions returns a ReactionList of all reactions from an issue
|
||||||
func FindIssueReactions(issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) {
|
func FindIssueReactions(ctx context.Context, issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) {
|
||||||
return FindReactions(db.DefaultContext, FindReactionsOptions{
|
return FindReactions(ctx, FindReactionsOptions{
|
||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
CommentID: -1,
|
CommentID: -1,
|
||||||
@@ -218,12 +218,12 @@ type ReactionOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateReaction creates reaction for issue or comment.
|
// CreateReaction creates reaction for issue or comment.
|
||||||
func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
|
func CreateReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, error) {
|
||||||
if !setting.UI.ReactionsLookup.Contains(opts.Type) {
|
if !setting.UI.ReactionsLookup.Contains(opts.Type) {
|
||||||
return nil, ErrForbiddenIssueReaction{opts.Type}
|
return nil, ErrForbiddenIssueReaction{opts.Type}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -241,8 +241,8 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateIssueReaction creates a reaction on issue.
|
// CreateIssueReaction creates a reaction on issue.
|
||||||
func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, error) {
|
func CreateIssueReaction(ctx context.Context, doerID, issueID int64, content string) (*Reaction, error) {
|
||||||
return CreateReaction(&ReactionOptions{
|
return CreateReaction(ctx, &ReactionOptions{
|
||||||
Type: content,
|
Type: content,
|
||||||
DoerID: doerID,
|
DoerID: doerID,
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
@@ -250,8 +250,8 @@ func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateCommentReaction creates a reaction on comment.
|
// CreateCommentReaction creates a reaction on comment.
|
||||||
func CreateCommentReaction(doerID, issueID, commentID int64, content string) (*Reaction, error) {
|
func CreateCommentReaction(ctx context.Context, doerID, issueID, commentID int64, content string) (*Reaction, error) {
|
||||||
return CreateReaction(&ReactionOptions{
|
return CreateReaction(ctx, &ReactionOptions{
|
||||||
Type: content,
|
Type: content,
|
||||||
DoerID: doerID,
|
DoerID: doerID,
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
@@ -279,8 +279,8 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueReaction deletes a reaction on issue.
|
// DeleteIssueReaction deletes a reaction on issue.
|
||||||
func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
func DeleteIssueReaction(ctx context.Context, doerID, issueID int64, content string) error {
|
||||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
return DeleteReaction(ctx, &ReactionOptions{
|
||||||
Type: content,
|
Type: content,
|
||||||
DoerID: doerID,
|
DoerID: doerID,
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
@@ -289,8 +289,8 @@ func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCommentReaction deletes a reaction on comment.
|
// DeleteCommentReaction deletes a reaction on comment.
|
||||||
func DeleteCommentReaction(doerID, issueID, commentID int64, content string) error {
|
func DeleteCommentReaction(ctx context.Context, doerID, issueID, commentID int64, content string) error {
|
||||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
return DeleteReaction(ctx, &ReactionOptions{
|
||||||
Type: content,
|
Type: content,
|
||||||
DoerID: doerID,
|
DoerID: doerID,
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ func addReaction(t *testing.T, doerID, issueID, commentID int64, content string)
|
|||||||
var reaction *issues_model.Reaction
|
var reaction *issues_model.Reaction
|
||||||
var err error
|
var err error
|
||||||
if commentID == 0 {
|
if commentID == 0 {
|
||||||
reaction, err = issues_model.CreateIssueReaction(doerID, issueID, content)
|
reaction, err = issues_model.CreateIssueReaction(db.DefaultContext, doerID, issueID, content)
|
||||||
} else {
|
} else {
|
||||||
reaction, err = issues_model.CreateCommentReaction(doerID, issueID, commentID, content)
|
reaction, err = issues_model.CreateCommentReaction(db.DefaultContext, doerID, issueID, commentID, content)
|
||||||
}
|
}
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, reaction)
|
assert.NotNil(t, reaction)
|
||||||
@@ -49,7 +49,7 @@ func TestIssueAddDuplicateReaction(t *testing.T) {
|
|||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
||||||
|
|
||||||
reaction, err := issues_model.CreateReaction(&issues_model.ReactionOptions{
|
reaction, err := issues_model.CreateReaction(db.DefaultContext, &issues_model.ReactionOptions{
|
||||||
DoerID: user1.ID,
|
DoerID: user1.ID,
|
||||||
IssueID: issue1ID,
|
IssueID: issue1ID,
|
||||||
Type: "heart",
|
Type: "heart",
|
||||||
@@ -70,7 +70,7 @@ func TestIssueDeleteReaction(t *testing.T) {
|
|||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
||||||
|
|
||||||
err := issues_model.DeleteIssueReaction(user1.ID, issue1ID, "heart")
|
err := issues_model.DeleteIssueReaction(db.DefaultContext, user1.ID, issue1ID, "heart")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID})
|
unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID})
|
||||||
@@ -168,7 +168,7 @@ func TestIssueCommentReactionCount(t *testing.T) {
|
|||||||
var comment1ID int64 = 1
|
var comment1ID int64 = 1
|
||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, comment1ID, "heart")
|
addReaction(t, user1.ID, issue1ID, comment1ID, "heart")
|
||||||
assert.NoError(t, issues_model.DeleteCommentReaction(user1.ID, issue1ID, comment1ID, "heart"))
|
assert.NoError(t, issues_model.DeleteCommentReaction(db.DefaultContext, user1.ID, issue1ID, comment1ID, "heart"))
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID})
|
unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID})
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-34
@@ -231,7 +231,7 @@ type CreateReviewOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals)
|
// IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals)
|
||||||
func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_model.User) (bool, error) {
|
func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewer *user_model.User) (bool, error) {
|
||||||
pr, err := GetPullRequestByIssueID(ctx, issue.ID)
|
pr, err := GetPullRequestByIssueID(ctx, issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -242,14 +242,21 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if rule == nil {
|
if rule == nil {
|
||||||
return false, nil
|
// if no rule is found, then user with write access can make official reviews
|
||||||
|
err := pr.LoadBaseRepo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
writeAccess, err := access_model.HasAccessUnit(ctx, reviewer, pr.BaseRepo, unit.TypeCode, perm.AccessModeWrite)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return writeAccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, reviewer := range reviewers {
|
official, err := git_model.IsUserOfficialReviewer(ctx, rule, reviewer)
|
||||||
official, err := git_model.IsUserOfficialReviewer(ctx, rule, reviewer)
|
if official || err != nil {
|
||||||
if official || err != nil {
|
return official, err
|
||||||
return official, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
@@ -322,8 +329,8 @@ func GetCurrentReview(ctx context.Context, reviewer *user_model.User, issue *Iss
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReviewExists returns whether a review exists for a particular line of code in the PR
|
// ReviewExists returns whether a review exists for a particular line of code in the PR
|
||||||
func ReviewExists(issue *Issue, treePath string, line int64) (bool, error) {
|
func ReviewExists(ctx context.Context, issue *Issue, treePath string, line int64) (bool, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Cols("id").Exist(&Comment{IssueID: issue.ID, TreePath: treePath, Line: line, Type: CommentTypeCode})
|
return db.GetEngine(ctx).Cols("id").Exist(&Comment{IssueID: issue.ID, TreePath: treePath, Line: line, Type: CommentTypeCode})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContentEmptyErr represents an content empty error
|
// ContentEmptyErr represents an content empty error
|
||||||
@@ -340,8 +347,8 @@ func IsContentEmptyErr(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
||||||
func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
|
func SubmitReview(ctx context.Context, doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -487,15 +494,15 @@ func GetTeamReviewerByIssueIDAndTeamID(ctx context.Context, issueID, teamID int6
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarkReviewsAsStale marks existing reviews as stale
|
// MarkReviewsAsStale marks existing reviews as stale
|
||||||
func MarkReviewsAsStale(issueID int64) (err error) {
|
func MarkReviewsAsStale(ctx context.Context, issueID int64) (err error) {
|
||||||
_, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `review` SET stale=? WHERE issue_id=?", true, issueID)
|
_, err = db.GetEngine(ctx).Exec("UPDATE `review` SET stale=? WHERE issue_id=?", true, issueID)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkReviewsAsNotStale marks existing reviews as not stale for a giving commit SHA
|
// MarkReviewsAsNotStale marks existing reviews as not stale for a giving commit SHA
|
||||||
func MarkReviewsAsNotStale(issueID int64, commitID string) (err error) {
|
func MarkReviewsAsNotStale(ctx context.Context, issueID int64, commitID string) (err error) {
|
||||||
_, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `review` SET stale=? WHERE issue_id=? AND commit_id=?", false, issueID, commitID)
|
_, err = db.GetEngine(ctx).Exec("UPDATE `review` SET stale=? WHERE issue_id=? AND commit_id=?", false, issueID, commitID)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -518,8 +525,8 @@ func DismissReview(ctx context.Context, review *Review, isDismiss bool) (err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertReviews inserts review and review comments
|
// InsertReviews inserts review and review comments
|
||||||
func InsertReviews(reviews []*Review) error {
|
func InsertReviews(ctx context.Context, reviews []*Review) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -578,7 +585,9 @@ func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_mo
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
official, err := IsOfficialReviewer(ctx, issue, reviewer, doer)
|
// if the reviewer is an official reviewer,
|
||||||
|
// remove the official flag in the all previous reviews
|
||||||
|
official, err := IsOfficialReviewer(ctx, issue, reviewer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if official {
|
} else if official {
|
||||||
@@ -794,7 +803,7 @@ func RemoveTeamReviewRequest(ctx context.Context, issue *Issue, reviewer *organi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarkConversation Add or remove Conversation mark for a code comment
|
// MarkConversation Add or remove Conversation mark for a code comment
|
||||||
func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (err error) {
|
func MarkConversation(ctx context.Context, comment *Comment, doer *user_model.User, isResolve bool) (err error) {
|
||||||
if comment.Type != CommentTypeCode {
|
if comment.Type != CommentTypeCode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -804,7 +813,7 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", doer.ID, comment.ID); err != nil {
|
if _, err = db.GetEngine(ctx).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", doer.ID, comment.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -812,7 +821,7 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", 0, comment.ID); err != nil {
|
if _, err = db.GetEngine(ctx).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", 0, comment.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -822,24 +831,24 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (
|
|||||||
|
|
||||||
// CanMarkConversation Add or remove Conversation mark for a code comment permission check
|
// CanMarkConversation Add or remove Conversation mark for a code comment permission check
|
||||||
// the PR writer , offfcial reviewer and poster can do it
|
// the PR writer , offfcial reviewer and poster can do it
|
||||||
func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, err error) {
|
func CanMarkConversation(ctx context.Context, issue *Issue, doer *user_model.User) (permResult bool, err error) {
|
||||||
if doer == nil || issue == nil {
|
if doer == nil || issue == nil {
|
||||||
return false, fmt.Errorf("issue or doer is nil")
|
return false, fmt.Errorf("issue or doer is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if doer.ID != issue.PosterID {
|
if doer.ID != issue.PosterID {
|
||||||
if err = issue.LoadRepo(db.DefaultContext); err != nil {
|
if err = issue.LoadRepo(ctx); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := access_model.GetUserRepoPermission(db.DefaultContext, issue.Repo, doer)
|
p, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
permResult = p.CanAccess(perm.AccessModeWrite, unit.TypePullRequests)
|
permResult = p.CanAccess(perm.AccessModeWrite, unit.TypePullRequests)
|
||||||
if !permResult {
|
if !permResult {
|
||||||
if permResult, err = IsOfficialReviewer(db.DefaultContext, issue, doer); err != nil {
|
if permResult, err = IsOfficialReviewer(ctx, issue, doer); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -853,8 +862,8 @@ func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteReview delete a review and it's code comments
|
// DeleteReview delete a review and it's code comments
|
||||||
func DeleteReview(r *Review) error {
|
func DeleteReview(ctx context.Context, r *Review) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -903,7 +912,7 @@ func DeleteReview(r *Review) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCodeCommentsCount return count of CodeComments a Review has
|
// GetCodeCommentsCount return count of CodeComments a Review has
|
||||||
func (r *Review) GetCodeCommentsCount() int {
|
func (r *Review) GetCodeCommentsCount(ctx context.Context) int {
|
||||||
opts := FindCommentsOptions{
|
opts := FindCommentsOptions{
|
||||||
Type: CommentTypeCode,
|
Type: CommentTypeCode,
|
||||||
IssueID: r.IssueID,
|
IssueID: r.IssueID,
|
||||||
@@ -914,7 +923,7 @@ func (r *Review) GetCodeCommentsCount() int {
|
|||||||
conds = conds.And(builder.Eq{"invalidated": false})
|
conds = conds.And(builder.Eq{"invalidated": false})
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err := db.GetEngine(db.DefaultContext).Where(conds).Count(new(Comment))
|
count, err := db.GetEngine(ctx).Where(conds).Count(new(Comment))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -922,18 +931,18 @@ func (r *Review) GetCodeCommentsCount() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HTMLURL formats a URL-string to the related review issue-comment
|
// HTMLURL formats a URL-string to the related review issue-comment
|
||||||
func (r *Review) HTMLURL() string {
|
func (r *Review) HTMLURL(ctx context.Context) string {
|
||||||
opts := FindCommentsOptions{
|
opts := FindCommentsOptions{
|
||||||
Type: CommentTypeReview,
|
Type: CommentTypeReview,
|
||||||
IssueID: r.IssueID,
|
IssueID: r.IssueID,
|
||||||
ReviewID: r.ID,
|
ReviewID: r.ID,
|
||||||
}
|
}
|
||||||
comment := new(Comment)
|
comment := new(Comment)
|
||||||
has, err := db.GetEngine(db.DefaultContext).Where(opts.ToConds()).Get(comment)
|
has, err := db.GetEngine(ctx).Where(opts.ToConds()).Get(comment)
|
||||||
if err != nil || !has {
|
if err != nil || !has {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return comment.HTMLURL()
|
return comment.HTMLURL(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemapExternalUser ExternalUserRemappable interface
|
// RemapExternalUser ExternalUserRemappable interface
|
||||||
@@ -954,8 +963,8 @@ func (r *Review) GetExternalName() string { return r.OriginalAuthor }
|
|||||||
func (r *Review) GetExternalID() int64 { return r.OriginalAuthorID }
|
func (r *Review) GetExternalID() int64 { return r.OriginalAuthorID }
|
||||||
|
|
||||||
// UpdateReviewsMigrationsByType updates reviews' migrations information via given git service type and original id and poster id
|
// UpdateReviewsMigrationsByType updates reviews' migrations information via given git service type and original id and poster id
|
||||||
func UpdateReviewsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
func UpdateReviewsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("review").
|
_, err := db.GetEngine(ctx).Table("review").
|
||||||
Where("original_author_id = ?", originalAuthorID).
|
Where("original_author_id = ?", originalAuthorID).
|
||||||
And(migratedIssueCond(tp)).
|
And(migratedIssueCond(tp)).
|
||||||
Update(map[string]any{
|
Update(map[string]any{
|
||||||
|
|||||||
@@ -126,16 +126,16 @@ func FindLatestReviews(ctx context.Context, opts FindReviewOptions) (ReviewList,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountReviews returns count of reviews passing FindReviewOptions
|
// CountReviews returns count of reviews passing FindReviewOptions
|
||||||
func CountReviews(opts FindReviewOptions) (int64, error) {
|
func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{})
|
return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
||||||
func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) (ReviewList, error) {
|
func GetReviewersFromOriginalAuthorsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
||||||
reviews := make([]*Review, 0, 10)
|
reviews := make([]*Review, 0, 10)
|
||||||
|
|
||||||
// Get latest review of each reviewer, sorted in order they were made
|
// Get latest review of each reviewer, sorted in order they were made
|
||||||
if err := db.GetEngine(db.DefaultContext).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
|
if err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
|
||||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
||||||
Find(&reviews); err != nil {
|
Find(&reviews); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -145,10 +145,10 @@ func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) (ReviewList, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||||
func GetReviewsByIssueID(issueID int64) (ReviewList, error) {
|
func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
||||||
reviews := make([]*Review, 0, 10)
|
reviews := make([]*Review, 0, 10)
|
||||||
|
|
||||||
sess := db.GetEngine(db.DefaultContext)
|
sess := db.GetEngine(ctx)
|
||||||
|
|
||||||
// Get latest review of each reviewer, sorted in order they were made
|
// Get latest review of each reviewer, sorted in order they were made
|
||||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
|||||||
UpdatedUnix: 946684814,
|
UpdatedUnix: 946684814,
|
||||||
})
|
})
|
||||||
|
|
||||||
allReviews, err := issues_model.GetReviewsByIssueID(issue.ID)
|
allReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
for _, review := range allReviews {
|
for _, review := range allReviews {
|
||||||
assert.NoError(t, review.LoadReviewer(db.DefaultContext))
|
assert.NoError(t, review.LoadReviewer(db.DefaultContext))
|
||||||
@@ -157,7 +157,7 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allReviews, err = issues_model.GetReviewsByIssueID(issue.ID)
|
allReviews, err = issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, allReviews.LoadReviewers(db.DefaultContext))
|
assert.NoError(t, allReviews.LoadReviewers(db.DefaultContext))
|
||||||
if assert.Len(t, allReviews, 3) {
|
if assert.Len(t, allReviews, 3) {
|
||||||
@@ -248,7 +248,7 @@ func TestDeleteReview(t *testing.T) {
|
|||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DeleteReview(review2))
|
assert.NoError(t, issues_model.DeleteReview(db.DefaultContext, review2))
|
||||||
|
|
||||||
_, err = issues_model.GetReviewByID(db.DefaultContext, review2.ID)
|
_, err = issues_model.GetReviewByID(db.DefaultContext, review2.ID)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|||||||
@@ -26,4 +26,3 @@
|
|||||||
id: 5
|
id: 5
|
||||||
issue_id: 2
|
issue_id: 2
|
||||||
label_id: 87
|
label_id: 87
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
-
|
-
|
||||||
id: 3
|
id: 3
|
||||||
repo_id: 0
|
repo_id: 0
|
||||||
org_id: 3
|
org_id: 3
|
||||||
name: orglabel3
|
name: orglabel3
|
||||||
color: '#abcdef'
|
color: '#abcdef'
|
||||||
num_issues: 0
|
num_issues: 0
|
||||||
|
|||||||
@@ -23,4 +23,3 @@
|
|||||||
id: 5
|
id: 5
|
||||||
repo_id: 3
|
repo_id: 3
|
||||||
org_id: 0
|
org_id: 0
|
||||||
|
|
||||||
|
|||||||
-1
@@ -28,4 +28,3 @@
|
|||||||
attestation_type: 'fido-u2f'
|
attestation_type: 'fido-u2f'
|
||||||
sign_count: 1
|
sign_count: 1
|
||||||
clone_warning: false
|
clone_warning: false
|
||||||
|
|
||||||
|
|||||||
@@ -534,6 +534,12 @@ var migrations = []Migration{
|
|||||||
NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun),
|
NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun),
|
||||||
// v276 -> v277
|
// v276 -> v277
|
||||||
NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors),
|
NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors),
|
||||||
|
// v277 -> v278
|
||||||
|
NewMigration("Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID),
|
||||||
|
// v278 -> v279
|
||||||
|
NewMigration("Add Index to comment.dependent_issue_id", v1_21.AddIndexToCommentDependentIssueID),
|
||||||
|
// v279 -> v280
|
||||||
|
NewMigration("Add Index to action.user_id", v1_21.AddIndexToActionUserID),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
package v1_18 //nolint
|
package v1_18 //nolint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
@@ -22,42 +18,6 @@ type SystemSetting struct {
|
|||||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertSettingsIfNotExist(x *xorm.Engine, sysSettings []*SystemSetting) error {
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
if err := sess.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, setting := range sysSettings {
|
|
||||||
exist, err := sess.Table("system_setting").Where("setting_key=?", setting.SettingKey).Exist()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !exist {
|
|
||||||
if _, err := sess.Insert(setting); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateSystemSettingsTable(x *xorm.Engine) error {
|
func CreateSystemSettingsTable(x *xorm.Engine) error {
|
||||||
if err := x.Sync(new(SystemSetting)); err != nil {
|
return x.Sync(new(SystemSetting))
|
||||||
return fmt.Errorf("sync2: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// migrate xx to database
|
|
||||||
sysSettings := []*SystemSetting{
|
|
||||||
{
|
|
||||||
SettingKey: "picture.disable_gravatar",
|
|
||||||
SettingValue: strconv.FormatBool(setting.DisableGravatar),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
SettingKey: "picture.enable_federated_avatar",
|
|
||||||
SettingValue: strconv.FormatBool(setting.EnableFederatedAvatar),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return insertSettingsIfNotExist(x, sysSettings)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_21 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddIndexToIssueUserIssueID(x *xorm.Engine) error {
|
||||||
|
type IssueUser struct {
|
||||||
|
IssueID int64 `xorm:"INDEX"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Sync(new(IssueUser))
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_21 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddIndexToCommentDependentIssueID(x *xorm.Engine) error {
|
||||||
|
type Comment struct {
|
||||||
|
DependentIssueID int64 `xorm:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Sync(new(Comment))
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_21 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddIndexToActionUserID(x *xorm.Engine) error {
|
||||||
|
type Action struct {
|
||||||
|
UserID int64 `xorm:"INDEX"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Sync(new(Action))
|
||||||
|
}
|
||||||
@@ -77,8 +77,8 @@ func (opts *SearchTeamOptions) toCond() builder.Cond {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchTeam search for teams. Caller is responsible to check permissions.
|
// SearchTeam search for teams. Caller is responsible to check permissions.
|
||||||
func SearchTeam(opts *SearchTeamOptions) (TeamList, int64, error) {
|
func SearchTeam(ctx context.Context, opts *SearchTeamOptions) (TeamList, int64, error) {
|
||||||
sess := db.GetEngine(db.DefaultContext)
|
sess := db.GetEngine(ctx)
|
||||||
|
|
||||||
opts.SetDefaultValues()
|
opts.SetDefaultValues()
|
||||||
cond := opts.toCond()
|
cond := opts.toCond()
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func TestGetTeamMembers(t *testing.T) {
|
|||||||
func TestGetUserTeams(t *testing.T) {
|
func TestGetUserTeams(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
test := func(userID int64) {
|
test := func(userID int64) {
|
||||||
teams, _, err := organization.SearchTeam(&organization.SearchTeamOptions{UserID: userID})
|
teams, _, err := organization.SearchTeam(db.DefaultContext, &organization.SearchTeamOptions{UserID: userID})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{TeamID: team.ID, UID: userID})
|
unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{TeamID: team.ID, UID: userID})
|
||||||
|
|||||||
+11
-11
@@ -69,8 +69,8 @@ func (Board) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumIssues return counter of all issues assigned to the board
|
// NumIssues return counter of all issues assigned to the board
|
||||||
func (b *Board) NumIssues() int {
|
func (b *Board) NumIssues(ctx context.Context) int {
|
||||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||||
Where("project_id=?", b.ProjectID).
|
Where("project_id=?", b.ProjectID).
|
||||||
And("project_board_id=?", b.ID).
|
And("project_board_id=?", b.ID).
|
||||||
GroupBy("issue_id").
|
GroupBy("issue_id").
|
||||||
@@ -142,18 +142,18 @@ func createBoardsForProjectsType(ctx context.Context, project *Project) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewBoard adds a new project board to a given project
|
// NewBoard adds a new project board to a given project
|
||||||
func NewBoard(board *Board) error {
|
func NewBoard(ctx context.Context, board *Board) error {
|
||||||
if len(board.Color) != 0 && !BoardColorPattern.MatchString(board.Color) {
|
if len(board.Color) != 0 && !BoardColorPattern.MatchString(board.Color) {
|
||||||
return fmt.Errorf("bad color code: %s", board.Color)
|
return fmt.Errorf("bad color code: %s", board.Color)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := db.GetEngine(db.DefaultContext).Insert(board)
|
_, err := db.GetEngine(ctx).Insert(board)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBoardByID removes all issues references to the project board.
|
// DeleteBoardByID removes all issues references to the project board.
|
||||||
func DeleteBoardByID(boardID int64) error {
|
func DeleteBoardByID(ctx context.Context, boardID int64) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -265,8 +265,8 @@ func (p *Project) getDefaultBoard(ctx context.Context) (*Board, error) {
|
|||||||
|
|
||||||
// SetDefaultBoard represents a board for issues not assigned to one
|
// SetDefaultBoard represents a board for issues not assigned to one
|
||||||
// if boardID is 0 unset default
|
// if boardID is 0 unset default
|
||||||
func SetDefaultBoard(projectID, boardID int64) error {
|
func SetDefaultBoard(ctx context.Context, projectID, boardID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Where(builder.Eq{
|
_, err := db.GetEngine(ctx).Where(builder.Eq{
|
||||||
"project_id": projectID,
|
"project_id": projectID,
|
||||||
"`default`": true,
|
"`default`": true,
|
||||||
}).Cols("`default`").Update(&Board{Default: false})
|
}).Cols("`default`").Update(&Board{Default: false})
|
||||||
@@ -275,7 +275,7 @@ func SetDefaultBoard(projectID, boardID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if boardID > 0 {
|
if boardID > 0 {
|
||||||
_, err = db.GetEngine(db.DefaultContext).ID(boardID).Where(builder.Eq{"project_id": projectID}).
|
_, err = db.GetEngine(ctx).ID(boardID).Where(builder.Eq{"project_id": projectID}).
|
||||||
Cols("`default`").Update(&Board{Default: true})
|
Cols("`default`").Update(&Board{Default: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,9 +283,9 @@ func SetDefaultBoard(projectID, boardID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateBoardSorting update project board sorting
|
// UpdateBoardSorting update project board sorting
|
||||||
func UpdateBoardSorting(bs BoardList) error {
|
func UpdateBoardSorting(ctx context.Context, bs BoardList) error {
|
||||||
for i := range bs {
|
for i := range bs {
|
||||||
_, err := db.GetEngine(db.DefaultContext).ID(bs[i].ID).Cols(
|
_, err := db.GetEngine(ctx).ID(bs[i].ID).Cols(
|
||||||
"sorting",
|
"sorting",
|
||||||
).Update(bs[i])
|
).Update(bs[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ func deleteProjectIssuesByProjectID(ctx context.Context, projectID int64) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumIssues return counter of all issues assigned to a project
|
// NumIssues return counter of all issues assigned to a project
|
||||||
func (p *Project) NumIssues() int {
|
func (p *Project) NumIssues(ctx context.Context) int {
|
||||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||||
Where("project_id=?", p.ID).
|
Where("project_id=?", p.ID).
|
||||||
GroupBy("issue_id").
|
GroupBy("issue_id").
|
||||||
Cols("issue_id").
|
Cols("issue_id").
|
||||||
@@ -48,8 +48,8 @@ func (p *Project) NumIssues() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumClosedIssues return counter of closed issues assigned to a project
|
// NumClosedIssues return counter of closed issues assigned to a project
|
||||||
func (p *Project) NumClosedIssues() int {
|
func (p *Project) NumClosedIssues(ctx context.Context) int {
|
||||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||||
Join("INNER", "issue", "project_issue.issue_id=issue.id").
|
Join("INNER", "issue", "project_issue.issue_id=issue.id").
|
||||||
Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, true).
|
Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, true).
|
||||||
Cols("issue_id").
|
Cols("issue_id").
|
||||||
@@ -62,8 +62,8 @@ func (p *Project) NumClosedIssues() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumOpenIssues return counter of open issues assigned to a project
|
// NumOpenIssues return counter of open issues assigned to a project
|
||||||
func (p *Project) NumOpenIssues() int {
|
func (p *Project) NumOpenIssues(ctx context.Context) int {
|
||||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||||
Join("INNER", "issue", "project_issue.issue_id=issue.id").
|
Join("INNER", "issue", "project_issue.issue_id=issue.id").
|
||||||
Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false).
|
Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false).
|
||||||
Cols("issue_id").
|
Cols("issue_id").
|
||||||
@@ -76,8 +76,8 @@ func (p *Project) NumOpenIssues() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column
|
// MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column
|
||||||
func MoveIssuesOnProjectBoard(board *Board, sortedIssueIDs map[int64]int64) error {
|
func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64) error {
|
||||||
return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
sess := db.GetEngine(ctx)
|
sess := db.GetEngine(ctx)
|
||||||
|
|
||||||
issueIDs := make([]int64, 0, len(sortedIssueIDs))
|
issueIDs := make([]int64, 0, len(sortedIssueIDs))
|
||||||
|
|||||||
@@ -124,9 +124,9 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Link returns the project's relative URL.
|
// Link returns the project's relative URL.
|
||||||
func (p *Project) Link() string {
|
func (p *Project) Link(ctx context.Context) string {
|
||||||
if p.OwnerID > 0 {
|
if p.OwnerID > 0 {
|
||||||
err := p.LoadOwner(db.DefaultContext)
|
err := p.LoadOwner(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LoadOwner: %v", err)
|
log.Error("LoadOwner: %v", err)
|
||||||
return ""
|
return ""
|
||||||
@@ -134,7 +134,7 @@ func (p *Project) Link() string {
|
|||||||
return fmt.Sprintf("%s/-/projects/%d", p.Owner.HomeLink(), p.ID)
|
return fmt.Sprintf("%s/-/projects/%d", p.Owner.HomeLink(), p.ID)
|
||||||
}
|
}
|
||||||
if p.RepoID > 0 {
|
if p.RepoID > 0 {
|
||||||
err := p.LoadRepo(db.DefaultContext)
|
err := p.LoadRepo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LoadRepo: %v", err)
|
log.Error("LoadRepo: %v", err)
|
||||||
return ""
|
return ""
|
||||||
@@ -261,7 +261,7 @@ func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewProject creates a new Project
|
// NewProject creates a new Project
|
||||||
func NewProject(p *Project) error {
|
func NewProject(ctx context.Context, p *Project) error {
|
||||||
if !IsBoardTypeValid(p.BoardType) {
|
if !IsBoardTypeValid(p.BoardType) {
|
||||||
p.BoardType = BoardTypeNone
|
p.BoardType = BoardTypeNone
|
||||||
}
|
}
|
||||||
@@ -274,7 +274,7 @@ func NewProject(p *Project) error {
|
|||||||
return util.NewInvalidArgumentErrorf("project type is not valid")
|
return util.NewInvalidArgumentErrorf("project type is not valid")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -348,8 +348,8 @@ func updateRepositoryProjectCount(ctx context.Context, repoID int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed
|
// ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed
|
||||||
func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) error {
|
func ChangeProjectStatusByRepoIDAndID(ctx context.Context, repoID, projectID int64, isClosed bool) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -372,8 +372,8 @@ func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ChangeProjectStatus toggle a project between opened and closed
|
// ChangeProjectStatus toggle a project between opened and closed
|
||||||
func ChangeProjectStatus(p *Project, isClosed bool) error {
|
func ChangeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func TestProject(t *testing.T) {
|
|||||||
CreatorID: 2,
|
CreatorID: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, NewProject(project))
|
assert.NoError(t, NewProject(db.DefaultContext, project))
|
||||||
|
|
||||||
_, err := GetProjectByID(db.DefaultContext, project.ID)
|
_, err := GetProjectByID(db.DefaultContext, project.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -74,7 +74,7 @@ func TestProject(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, project.Title, projectFromDB.Title)
|
assert.Equal(t, project.Title, projectFromDB.Title)
|
||||||
|
|
||||||
assert.NoError(t, ChangeProjectStatus(project, true))
|
assert.NoError(t, ChangeProjectStatus(db.DefaultContext, project, true))
|
||||||
|
|
||||||
// Retrieve from DB afresh to check if it is truly closed
|
// Retrieve from DB afresh to check if it is truly closed
|
||||||
projectFromDB, err = GetProjectByID(db.DefaultContext, project.ID)
|
projectFromDB, err = GetProjectByID(db.DefaultContext, project.ID)
|
||||||
|
|||||||
+1
-5
@@ -16,7 +16,6 @@ import (
|
|||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
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"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
|
||||||
"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/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
@@ -24,10 +23,7 @@ import (
|
|||||||
|
|
||||||
// Init initialize model
|
// Init initialize model
|
||||||
func Init(ctx context.Context) error {
|
func Init(ctx context.Context) error {
|
||||||
if err := unit.LoadUnitConfig(); err != nil {
|
return unit.LoadUnitConfig()
|
||||||
return err
|
|
||||||
}
|
|
||||||
return system_model.Init(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type repoChecker struct {
|
type repoChecker struct {
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ func GetCollaborators(ctx context.Context, repoID int64, listOptions db.ListOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountCollaborators returns total number of collaborators for a repository
|
// CountCollaborators returns total number of collaborators for a repository
|
||||||
func CountCollaborators(repoID int64) (int64, error) {
|
func CountCollaborators(ctx context.Context, repoID int64) (int64, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repoID).Count(&Collaboration{})
|
return db.GetEngine(ctx).Where("repo_id = ? ", repoID).Count(&Collaboration{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCollaboration get collaboration for a repository id with a user id
|
// GetCollaboration get collaboration for a repository id with a user id
|
||||||
@@ -138,11 +138,11 @@ func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid in
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository
|
// IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository
|
||||||
func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) {
|
func IsOwnerMemberCollaborator(ctx context.Context, repo *Repository, userID int64) (bool, error) {
|
||||||
if repo.OwnerID == userID {
|
if repo.OwnerID == userID {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
teamMember, err := db.GetEngine(db.DefaultContext).Join("INNER", "team_repo", "team_repo.team_id = team_user.team_id").
|
teamMember, err := db.GetEngine(ctx).Join("INNER", "team_repo", "team_repo.team_id = team_user.team_id").
|
||||||
Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id").
|
Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id").
|
||||||
Where("team_repo.repo_id = ?", repo.ID).
|
Where("team_repo.repo_id = ?", repo.ID).
|
||||||
And("team_unit.`type` = ?", unit.TypeCode).
|
And("team_unit.`type` = ?", unit.TypeCode).
|
||||||
@@ -154,5 +154,5 @@ func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.GetEngine(db.DefaultContext).Get(&Collaboration{RepoID: repo.ID, UserID: userID})
|
return db.GetEngine(ctx).Get(&Collaboration{RepoID: repo.ID, UserID: userID})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,17 +89,17 @@ func TestRepository_CountCollaborators(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
count, err := repo_model.CountCollaborators(repo1.ID)
|
count, err := repo_model.CountCollaborators(db.DefaultContext, repo1.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 2, count)
|
assert.EqualValues(t, 2, count)
|
||||||
|
|
||||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
||||||
count, err = repo_model.CountCollaborators(repo2.ID)
|
count, err = repo_model.CountCollaborators(db.DefaultContext, repo2.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 2, count)
|
assert.EqualValues(t, 2, count)
|
||||||
|
|
||||||
// Non-existent repository.
|
// Non-existent repository.
|
||||||
count, err = repo_model.CountCollaborators(unittest.NonexistentID)
|
count, err = repo_model.CountCollaborators(db.DefaultContext, unittest.NonexistentID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, count)
|
assert.EqualValues(t, 0, count)
|
||||||
}
|
}
|
||||||
@@ -110,31 +110,31 @@ func TestRepository_IsOwnerMemberCollaborator(t *testing.T) {
|
|||||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||||
|
|
||||||
// Organisation owner.
|
// Organisation owner.
|
||||||
actual, err := repo_model.IsOwnerMemberCollaborator(repo1, 2)
|
actual, err := repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, actual)
|
assert.True(t, actual)
|
||||||
|
|
||||||
// Team member.
|
// Team member.
|
||||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 4)
|
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 4)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, actual)
|
assert.True(t, actual)
|
||||||
|
|
||||||
// Normal user.
|
// Normal user.
|
||||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 1)
|
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, actual)
|
assert.False(t, actual)
|
||||||
|
|
||||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
|
||||||
// Collaborator.
|
// Collaborator.
|
||||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo2, 4)
|
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo2, 4)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, actual)
|
assert.True(t, actual)
|
||||||
|
|
||||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
|
||||||
|
|
||||||
// Repository owner.
|
// Repository owner.
|
||||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo3, 2)
|
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo3, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, actual)
|
assert.True(t, actual)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ func (m *Mirror) BeforeInsert() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRepository returns the repository.
|
// GetRepository returns the repository.
|
||||||
func (m *Mirror) GetRepository() *Repository {
|
func (m *Mirror) GetRepository(ctx context.Context) *Repository {
|
||||||
if m.Repo != nil {
|
if m.Repo != nil {
|
||||||
return m.Repo
|
return m.Repo
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
m.Repo, err = GetRepositoryByID(db.DefaultContext, m.RepoID)
|
m.Repo, err = GetRepositoryByID(ctx, m.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("getRepositoryByID[%d]: %v", m.ID, err)
|
log.Error("getRepositoryByID[%d]: %v", m.ID, err)
|
||||||
}
|
}
|
||||||
@@ -99,14 +99,14 @@ func TouchMirror(ctx context.Context, m *Mirror) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteMirrorByRepoID deletes a mirror by repoID
|
// DeleteMirrorByRepoID deletes a mirror by repoID
|
||||||
func DeleteMirrorByRepoID(repoID int64) error {
|
func DeleteMirrorByRepoID(ctx context.Context, repoID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID})
|
_, err := db.GetEngine(ctx).Delete(&Mirror{RepoID: repoID})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MirrorsIterate iterates all mirror repositories.
|
// MirrorsIterate iterates all mirror repositories.
|
||||||
func MirrorsIterate(limit int, f func(idx int, bean any) error) error {
|
func MirrorsIterate(ctx context.Context, limit int, f func(idx int, bean any) error) error {
|
||||||
sess := db.GetEngine(db.DefaultContext).
|
sess := db.GetEngine(ctx).
|
||||||
Where("next_update_unix<=?", time.Now().Unix()).
|
Where("next_update_unix<=?", time.Now().Unix()).
|
||||||
And("next_update_unix!=0").
|
And("next_update_unix!=0").
|
||||||
OrderBy("updated_unix ASC")
|
OrderBy("updated_unix ASC")
|
||||||
|
|||||||
+18
-18
@@ -181,9 +181,9 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRelease returns release by given ID.
|
// GetRelease returns release by given ID.
|
||||||
func GetRelease(repoID int64, tagName string) (*Release, error) {
|
func GetRelease(ctx context.Context, repoID int64, tagName string) (*Release, error) {
|
||||||
rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}
|
rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}
|
||||||
has, err := db.GetEngine(db.DefaultContext).Get(rel)
|
has, err := db.GetEngine(ctx).Get(rel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
@@ -284,12 +284,12 @@ func GetTagNamesByRepoID(ctx context.Context, repoID int64) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID.
|
// CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID.
|
||||||
func CountReleasesByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) {
|
func CountReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Where(opts.toConds(repoID)).Count(new(Release))
|
return db.GetEngine(ctx).Where(opts.toConds(repoID)).Count(new(Release))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLatestReleaseByRepoID returns the latest release for a repository
|
// GetLatestReleaseByRepoID returns the latest release for a repository
|
||||||
func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
|
func GetLatestReleaseByRepoID(ctx context.Context, repoID int64) (*Release, error) {
|
||||||
cond := builder.NewCond().
|
cond := builder.NewCond().
|
||||||
And(builder.Eq{"repo_id": repoID}).
|
And(builder.Eq{"repo_id": repoID}).
|
||||||
And(builder.Eq{"is_draft": false}).
|
And(builder.Eq{"is_draft": false}).
|
||||||
@@ -297,7 +297,7 @@ func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
|
|||||||
And(builder.Eq{"is_tag": false})
|
And(builder.Eq{"is_tag": false})
|
||||||
|
|
||||||
rel := new(Release)
|
rel := new(Release)
|
||||||
has, err := db.GetEngine(db.DefaultContext).
|
has, err := db.GetEngine(ctx).
|
||||||
Desc("created_unix", "id").
|
Desc("created_unix", "id").
|
||||||
Where(cond).
|
Where(cond).
|
||||||
Get(rel)
|
Get(rel)
|
||||||
@@ -442,8 +442,8 @@ func DeleteReleaseByID(ctx context.Context, id int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID
|
// UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID
|
||||||
func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
func UpdateReleasesMigrationsByType(ctx context.Context, gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("release").
|
_, err := db.GetEngine(ctx).Table("release").
|
||||||
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||||
And("original_author_id = ?", originalAuthorID).
|
And("original_author_id = ?", originalAuthorID).
|
||||||
Update(map[string]any{
|
Update(map[string]any{
|
||||||
@@ -485,8 +485,8 @@ func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PushUpdateDeleteTag must be called for any push actions to delete tag
|
// PushUpdateDeleteTag must be called for any push actions to delete tag
|
||||||
func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
func PushUpdateDeleteTag(ctx context.Context, repo *Repository, tagName string) error {
|
||||||
rel, err := GetRelease(repo.ID, tagName)
|
rel, err := GetRelease(ctx, repo.ID, tagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrReleaseNotExist(err) {
|
if IsErrReleaseNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
@@ -494,14 +494,14 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
|||||||
return fmt.Errorf("GetRelease: %w", err)
|
return fmt.Errorf("GetRelease: %w", err)
|
||||||
}
|
}
|
||||||
if rel.IsTag {
|
if rel.IsTag {
|
||||||
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).Delete(new(Release)); err != nil {
|
if _, err = db.GetEngine(ctx).ID(rel.ID).Delete(new(Release)); err != nil {
|
||||||
return fmt.Errorf("Delete: %w", err)
|
return fmt.Errorf("Delete: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rel.IsDraft = true
|
rel.IsDraft = true
|
||||||
rel.NumCommits = 0
|
rel.NumCommits = 0
|
||||||
rel.Sha1 = ""
|
rel.Sha1 = ""
|
||||||
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil {
|
if _, err = db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel); err != nil {
|
||||||
return fmt.Errorf("Update: %w", err)
|
return fmt.Errorf("Update: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,15 +510,15 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveOrUpdateTag must be called for any push actions to add tag
|
// SaveOrUpdateTag must be called for any push actions to add tag
|
||||||
func SaveOrUpdateTag(repo *Repository, newRel *Release) error {
|
func SaveOrUpdateTag(ctx context.Context, repo *Repository, newRel *Release) error {
|
||||||
rel, err := GetRelease(repo.ID, newRel.TagName)
|
rel, err := GetRelease(ctx, repo.ID, newRel.TagName)
|
||||||
if err != nil && !IsErrReleaseNotExist(err) {
|
if err != nil && !IsErrReleaseNotExist(err) {
|
||||||
return fmt.Errorf("GetRelease: %w", err)
|
return fmt.Errorf("GetRelease: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rel == nil {
|
if rel == nil {
|
||||||
rel = newRel
|
rel = newRel
|
||||||
if _, err = db.GetEngine(db.DefaultContext).Insert(rel); err != nil {
|
if _, err = db.GetEngine(ctx).Insert(rel); err != nil {
|
||||||
return fmt.Errorf("InsertOne: %w", err)
|
return fmt.Errorf("InsertOne: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -529,7 +529,7 @@ func SaveOrUpdateTag(repo *Repository, newRel *Release) error {
|
|||||||
if rel.IsTag && newRel.PublisherID > 0 {
|
if rel.IsTag && newRel.PublisherID > 0 {
|
||||||
rel.PublisherID = newRel.PublisherID
|
rel.PublisherID = newRel.PublisherID
|
||||||
}
|
}
|
||||||
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil {
|
if _, err = db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel); err != nil {
|
||||||
return fmt.Errorf("Update: %w", err)
|
return fmt.Errorf("Update: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,8 +554,8 @@ func (r *Release) GetExternalName() string { return r.OriginalAuthor }
|
|||||||
func (r *Release) GetExternalID() int64 { return r.OriginalAuthorID }
|
func (r *Release) GetExternalID() int64 { return r.OriginalAuthorID }
|
||||||
|
|
||||||
// InsertReleases migrates release
|
// InsertReleases migrates release
|
||||||
func InsertReleases(rels ...*Release) error {
|
func InsertReleases(ctx context.Context, rels ...*Release) error {
|
||||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -21,6 +22,6 @@ func TestMigrate_InsertReleases(t *testing.T) {
|
|||||||
Attachments: []*Attachment{a},
|
Attachments: []*Attachment{a},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := InsertReleases(r)
|
err := InsertReleases(db.DefaultContext, r)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -94,28 +94,28 @@ func CountNotices() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notices returns notices in given page.
|
// Notices returns notices in given page.
|
||||||
func Notices(page, pageSize int) ([]*Notice, error) {
|
func Notices(ctx context.Context, page, pageSize int) ([]*Notice, error) {
|
||||||
notices := make([]*Notice, 0, pageSize)
|
notices := make([]*Notice, 0, pageSize)
|
||||||
return notices, db.GetEngine(db.DefaultContext).
|
return notices, db.GetEngine(ctx).
|
||||||
Limit(pageSize, (page-1)*pageSize).
|
Limit(pageSize, (page-1)*pageSize).
|
||||||
Desc("created_unix").
|
Desc("created_unix").
|
||||||
Find(¬ices)
|
Find(¬ices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNotice deletes a system notice by given ID.
|
// DeleteNotice deletes a system notice by given ID.
|
||||||
func DeleteNotice(id int64) error {
|
func DeleteNotice(ctx context.Context, id int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).ID(id).Delete(new(Notice))
|
_, err := db.GetEngine(ctx).ID(id).Delete(new(Notice))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNotices deletes all notices with ID from start to end (inclusive).
|
// DeleteNotices deletes all notices with ID from start to end (inclusive).
|
||||||
func DeleteNotices(start, end int64) error {
|
func DeleteNotices(ctx context.Context, start, end int64) error {
|
||||||
if start == 0 && end == 0 {
|
if start == 0 && end == 0 {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Exec("DELETE FROM notice")
|
_, err := db.GetEngine(ctx).Exec("DELETE FROM notice")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := db.GetEngine(db.DefaultContext).Where("id >= ?", start)
|
sess := db.GetEngine(ctx).Where("id >= ?", start)
|
||||||
if end > 0 {
|
if end > 0 {
|
||||||
sess.And("id <= ?", end)
|
sess.And("id <= ?", end)
|
||||||
}
|
}
|
||||||
@@ -124,22 +124,22 @@ func DeleteNotices(start, end int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteNoticesByIDs deletes notices by given IDs.
|
// DeleteNoticesByIDs deletes notices by given IDs.
|
||||||
func DeleteNoticesByIDs(ids []int64) error {
|
func DeleteNoticesByIDs(ctx context.Context, ids []int64) error {
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err := db.GetEngine(db.DefaultContext).
|
_, err := db.GetEngine(ctx).
|
||||||
In("id", ids).
|
In("id", ids).
|
||||||
Delete(new(Notice))
|
Delete(new(Notice))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOldSystemNotices deletes all old system notices from database.
|
// DeleteOldSystemNotices deletes all old system notices from database.
|
||||||
func DeleteOldSystemNotices(olderThan time.Duration) (err error) {
|
func DeleteOldSystemNotices(ctx context.Context, olderThan time.Duration) (err error) {
|
||||||
if olderThan <= 0 {
|
if olderThan <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Notice{})
|
_, err = db.GetEngine(ctx).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Notice{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,14 +55,14 @@ func TestCountNotices(t *testing.T) {
|
|||||||
func TestNotices(t *testing.T) {
|
func TestNotices(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
notices, err := system.Notices(1, 2)
|
notices, err := system.Notices(db.DefaultContext, 1, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, notices, 2) {
|
if assert.Len(t, notices, 2) {
|
||||||
assert.Equal(t, int64(3), notices[0].ID)
|
assert.Equal(t, int64(3), notices[0].ID)
|
||||||
assert.Equal(t, int64(2), notices[1].ID)
|
assert.Equal(t, int64(2), notices[1].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
notices, err = system.Notices(2, 2)
|
notices, err = system.Notices(db.DefaultContext, 2, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, notices, 1) {
|
if assert.Len(t, notices, 1) {
|
||||||
assert.Equal(t, int64(1), notices[0].ID)
|
assert.Equal(t, int64(1), notices[0].ID)
|
||||||
@@ -73,7 +73,7 @@ func TestDeleteNotice(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
assert.NoError(t, system.DeleteNotice(3))
|
assert.NoError(t, system.DeleteNotice(db.DefaultContext, 3))
|
||||||
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ func TestDeleteNotices(t *testing.T) {
|
|||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
assert.NoError(t, system.DeleteNotices(1, 2))
|
assert.NoError(t, system.DeleteNotices(db.DefaultContext, 1, 2))
|
||||||
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
|
||||||
unittest.AssertNotExistsBean(t, &system.Notice{ID: 2})
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 2})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
@@ -97,7 +97,7 @@ func TestDeleteNotices2(t *testing.T) {
|
|||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
assert.NoError(t, system.DeleteNotices(3, 2))
|
assert.NoError(t, system.DeleteNotices(db.DefaultContext, 3, 2))
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
@@ -109,7 +109,7 @@ func TestDeleteNoticesByIDs(t *testing.T) {
|
|||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
assert.NoError(t, system.DeleteNoticesByIDs([]int64{1, 3}))
|
assert.NoError(t, system.DeleteNoticesByIDs(db.DefaultContext, []int64{1, 3}))
|
||||||
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
|
||||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
||||||
|
|||||||
+104
-271
@@ -5,26 +5,21 @@ package system
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"math"
|
||||||
"net/url"
|
"sync"
|
||||||
"strconv"
|
"time"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/log"
|
||||||
setting_module "code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting/config"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"strk.kbt.io/projects/go/libravatar"
|
|
||||||
"xorm.io/builder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Setting is a key value store of user settings
|
|
||||||
type Setting struct {
|
type Setting struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
SettingKey string `xorm:"varchar(255) unique"` // ensure key is always lowercase
|
SettingKey string `xorm:"varchar(255) unique"` // key should be lowercase
|
||||||
SettingValue string `xorm:"text"`
|
SettingValue string `xorm:"text"`
|
||||||
Version int `xorm:"version"` // prevent to override
|
Version int `xorm:"version"`
|
||||||
Created timeutil.TimeStamp `xorm:"created"`
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
}
|
}
|
||||||
@@ -34,281 +29,119 @@ func (s *Setting) TableName() string {
|
|||||||
return "system_setting"
|
return "system_setting"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Setting) GetValueBool() bool {
|
|
||||||
if s == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
b, _ := strconv.ParseBool(s.SettingValue)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
db.RegisterModel(new(Setting))
|
db.RegisterModel(new(Setting))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrSettingIsNotExist represents an error that a setting is not exist with special key
|
const keyRevision = "revision"
|
||||||
type ErrSettingIsNotExist struct {
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements error
|
func GetRevision(ctx context.Context) int {
|
||||||
func (err ErrSettingIsNotExist) Error() string {
|
revision := &Setting{SettingKey: keyRevision}
|
||||||
return fmt.Sprintf("System setting[%s] is not exist", err.Key)
|
if has, err := db.GetByBean(ctx, revision); err != nil {
|
||||||
}
|
return 0
|
||||||
|
} else if !has {
|
||||||
// IsErrSettingIsNotExist return true if err is ErrSettingIsNotExist
|
err = db.Insert(ctx, &Setting{SettingKey: keyRevision, Version: 1})
|
||||||
func IsErrSettingIsNotExist(err error) bool {
|
if err != nil {
|
||||||
_, ok := err.(ErrSettingIsNotExist)
|
return 0
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrDataExpired represents an error that update a record which has been updated by another thread
|
|
||||||
type ErrDataExpired struct {
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements error
|
|
||||||
func (err ErrDataExpired) Error() string {
|
|
||||||
return fmt.Sprintf("System setting[%s] has been updated by another thread", err.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrDataExpired return true if err is ErrDataExpired
|
|
||||||
func IsErrDataExpired(err error) bool {
|
|
||||||
_, ok := err.(ErrDataExpired)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSetting returns specific setting without using the cache
|
|
||||||
func GetSetting(ctx context.Context, key string) (*Setting, error) {
|
|
||||||
v, err := GetSettings(ctx, []string{key})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(v) == 0 {
|
|
||||||
return nil, ErrSettingIsNotExist{key}
|
|
||||||
}
|
|
||||||
return v[strings.ToLower(key)], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextCacheKey = "system_setting"
|
|
||||||
|
|
||||||
// GetSettingWithCache returns the setting value via the key
|
|
||||||
func GetSettingWithCache(ctx context.Context, key, defaultVal string) (string, error) {
|
|
||||||
return cache.GetWithContextCache(ctx, contextCacheKey, key, func() (string, error) {
|
|
||||||
return cache.GetString(genSettingCacheKey(key), func() (string, error) {
|
|
||||||
res, err := GetSetting(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
if IsErrSettingIsNotExist(err) {
|
|
||||||
return defaultVal, nil
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return res.SettingValue, nil
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSettingBool return bool value of setting,
|
|
||||||
// none existing keys and errors are ignored and result in false
|
|
||||||
func GetSettingBool(ctx context.Context, key string, defaultVal bool) (bool, error) {
|
|
||||||
s, err := GetSetting(ctx, key)
|
|
||||||
switch {
|
|
||||||
case err == nil:
|
|
||||||
v, _ := strconv.ParseBool(s.SettingValue)
|
|
||||||
return v, nil
|
|
||||||
case IsErrSettingIsNotExist(err):
|
|
||||||
return defaultVal, nil
|
|
||||||
default:
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSettingWithCacheBool(ctx context.Context, key string, defaultVal bool) bool {
|
|
||||||
s, _ := GetSettingWithCache(ctx, key, strconv.FormatBool(defaultVal))
|
|
||||||
v, _ := strconv.ParseBool(s)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSettings returns specific settings
|
|
||||||
func GetSettings(ctx context.Context, keys []string) (map[string]*Setting, error) {
|
|
||||||
for i := 0; i < len(keys); i++ {
|
|
||||||
keys[i] = strings.ToLower(keys[i])
|
|
||||||
}
|
|
||||||
settings := make([]*Setting, 0, len(keys))
|
|
||||||
if err := db.GetEngine(ctx).
|
|
||||||
Where(builder.In("setting_key", keys)).
|
|
||||||
Find(&settings); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
settingsMap := make(map[string]*Setting)
|
|
||||||
for _, s := range settings {
|
|
||||||
settingsMap[s.SettingKey] = s
|
|
||||||
}
|
|
||||||
return settingsMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type AllSettings map[string]*Setting
|
|
||||||
|
|
||||||
func (settings AllSettings) Get(key string) Setting {
|
|
||||||
if v, ok := settings[strings.ToLower(key)]; ok {
|
|
||||||
return *v
|
|
||||||
}
|
|
||||||
return Setting{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings AllSettings) GetBool(key string) bool {
|
|
||||||
b, _ := strconv.ParseBool(settings.Get(key).SettingValue)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings AllSettings) GetVersion(key string) int {
|
|
||||||
return settings.Get(key).Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllSettings returns all settings from user
|
|
||||||
func GetAllSettings(ctx context.Context) (AllSettings, error) {
|
|
||||||
settings := make([]*Setting, 0, 5)
|
|
||||||
if err := db.GetEngine(ctx).
|
|
||||||
Find(&settings); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
settingsMap := make(map[string]*Setting)
|
|
||||||
for _, s := range settings {
|
|
||||||
settingsMap[s.SettingKey] = s
|
|
||||||
}
|
|
||||||
return settingsMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSetting deletes a specific setting for a user
|
|
||||||
func DeleteSetting(ctx context.Context, setting *Setting) error {
|
|
||||||
cache.RemoveContextData(ctx, contextCacheKey, setting.SettingKey)
|
|
||||||
cache.Remove(genSettingCacheKey(setting.SettingKey))
|
|
||||||
_, err := db.GetEngine(ctx).Delete(setting)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetSettingNoVersion(ctx context.Context, key, value string) error {
|
|
||||||
s, err := GetSetting(ctx, key)
|
|
||||||
if IsErrSettingIsNotExist(err) {
|
|
||||||
return SetSetting(ctx, &Setting{
|
|
||||||
SettingKey: key,
|
|
||||||
SettingValue: value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.SettingValue = value
|
|
||||||
return SetSetting(ctx, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSetting updates a users' setting for a specific key
|
|
||||||
func SetSetting(ctx context.Context, setting *Setting) error {
|
|
||||||
if err := upsertSettingValue(ctx, strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
setting.Version++
|
|
||||||
|
|
||||||
cc := cache.GetCache()
|
|
||||||
if cc != nil {
|
|
||||||
if err := cc.Put(genSettingCacheKey(setting.SettingKey), setting.SettingValue, setting_module.CacheService.TTLSeconds()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
return 1
|
||||||
|
} else if revision.Version <= 0 || revision.Version >= math.MaxInt-1 {
|
||||||
|
_, err = db.Exec(ctx, "UPDATE system_setting SET version=1 WHERE setting_key=?", keyRevision)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
cache.SetContextData(ctx, contextCacheKey, setting.SettingKey, setting.SettingValue)
|
return revision.Version
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func upsertSettingValue(parentCtx context.Context, key, value string, version int) error {
|
func GetAllSettings(ctx context.Context) (revision int, res map[string]string, err error) {
|
||||||
return db.WithTx(parentCtx, func(ctx context.Context) error {
|
_ = GetRevision(ctx) // prepare the "revision" key ahead
|
||||||
|
var settings []*Setting
|
||||||
|
if err := db.GetEngine(ctx).
|
||||||
|
Find(&settings); err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
res = make(map[string]string)
|
||||||
|
for _, s := range settings {
|
||||||
|
if s.SettingKey == keyRevision {
|
||||||
|
revision = s.Version
|
||||||
|
}
|
||||||
|
res[s.SettingKey] = s.SettingValue
|
||||||
|
}
|
||||||
|
return revision, res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSettings(ctx context.Context, settings map[string]string) error {
|
||||||
|
_ = GetRevision(ctx) // prepare the "revision" key ahead
|
||||||
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
_, err := db.Exec(ctx, "UPDATE system_setting SET version=version+1 WHERE setting_key=?", keyRevision)
|
||||||
// here we use a general method to do a safe upsert for different databases (and most transaction levels)
|
|
||||||
// 1. try to UPDATE the record and acquire the transaction write lock
|
|
||||||
// if UPDATE returns non-zero rows are changed, OK, the setting is saved correctly
|
|
||||||
// if UPDATE returns "0 rows changed", two possibilities: (a) record doesn't exist (b) value is not changed
|
|
||||||
// 2. do a SELECT to check if the row exists or not (we already have the transaction lock)
|
|
||||||
// 3. if the row doesn't exist, do an INSERT (we are still protected by the transaction lock, so it's safe)
|
|
||||||
//
|
|
||||||
// to optimize the SELECT in step 2, we can use an extra column like `revision=revision+1`
|
|
||||||
// to make sure the UPDATE always returns a non-zero value for existing (unchanged) records.
|
|
||||||
|
|
||||||
res, err := e.Exec("UPDATE system_setting SET setting_value=?, version = version+1 WHERE setting_key=? AND version=?", value, key, version)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, _ := res.RowsAffected()
|
for k, v := range settings {
|
||||||
if rows > 0 {
|
res, err := e.Exec("UPDATE system_setting SET setting_value=? WHERE setting_key=?", v, k)
|
||||||
// the existing row is updated, so we can return
|
if err != nil {
|
||||||
return nil
|
return err
|
||||||
|
}
|
||||||
|
rows, _ := res.RowsAffected()
|
||||||
|
if rows == 0 { // if no existing row, insert a new row
|
||||||
|
if _, err = e.Insert(&Setting{SettingKey: k, SettingValue: v}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
// in case the value isn't changed, update would return 0 rows changed, so we need this check
|
|
||||||
has, err := e.Exist(&Setting{SettingKey: key})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if has {
|
|
||||||
return ErrDataExpired{Key: key}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no existing row, insert a new row
|
|
||||||
_, err = e.Insert(&Setting{SettingKey: key, SettingValue: value})
|
|
||||||
return err
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
type dbConfigCachedGetter struct {
|
||||||
GravatarSourceURL *url.URL
|
mu sync.RWMutex
|
||||||
LibravatarService *libravatar.Libravatar
|
|
||||||
)
|
|
||||||
|
|
||||||
func Init(ctx context.Context) error {
|
cacheTime time.Time
|
||||||
disableGravatar, err := GetSettingBool(ctx, KeyPictureDisableGravatar, setting_module.GetDefaultDisableGravatar())
|
revision int
|
||||||
if err != nil {
|
settings map[string]string
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
var _ config.DynKeyGetter = (*dbConfigCachedGetter)(nil)
|
||||||
enableFederatedAvatar, err := GetSettingBool(ctx, KeyPictureEnableFederatedAvatar, setting_module.GetDefaultEnableFederatedAvatar(disableGravatar))
|
|
||||||
if err != nil {
|
func (d *dbConfigCachedGetter) GetValue(ctx context.Context, key string) (v string, has bool) {
|
||||||
return err
|
d.mu.RLock()
|
||||||
}
|
defer d.mu.RUnlock()
|
||||||
|
v, has = d.settings[key]
|
||||||
if setting_module.OfflineMode {
|
return v, has
|
||||||
if !disableGravatar {
|
}
|
||||||
if err := SetSettingNoVersion(ctx, KeyPictureDisableGravatar, "true"); err != nil {
|
|
||||||
return fmt.Errorf("failed to set setting %q: %w", KeyPictureDisableGravatar, err)
|
func (d *dbConfigCachedGetter) GetRevision(ctx context.Context) int {
|
||||||
}
|
d.mu.RLock()
|
||||||
}
|
defer d.mu.RUnlock()
|
||||||
disableGravatar = true
|
if time.Since(d.cacheTime) < time.Second {
|
||||||
|
return d.revision
|
||||||
if enableFederatedAvatar {
|
}
|
||||||
if err := SetSettingNoVersion(ctx, KeyPictureEnableFederatedAvatar, "false"); err != nil {
|
if GetRevision(ctx) != d.revision {
|
||||||
return fmt.Errorf("failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err)
|
d.mu.RUnlock()
|
||||||
}
|
d.mu.Lock()
|
||||||
}
|
rev, set, err := GetAllSettings(ctx)
|
||||||
enableFederatedAvatar = false
|
if err != nil {
|
||||||
}
|
log.Error("Unable to get all settings: %v", err)
|
||||||
|
} else {
|
||||||
if enableFederatedAvatar || !disableGravatar {
|
d.cacheTime = time.Now()
|
||||||
var err error
|
d.revision = rev
|
||||||
GravatarSourceURL, err = url.Parse(setting_module.GravatarSource)
|
d.settings = set
|
||||||
if err != nil {
|
}
|
||||||
return fmt.Errorf("failed to parse Gravatar URL(%s): %w", setting_module.GravatarSource, err)
|
d.mu.Unlock()
|
||||||
}
|
d.mu.RLock()
|
||||||
}
|
}
|
||||||
|
return d.revision
|
||||||
if GravatarSourceURL != nil && enableFederatedAvatar {
|
}
|
||||||
LibravatarService = libravatar.New()
|
|
||||||
if GravatarSourceURL.Scheme == "https" {
|
func (d *dbConfigCachedGetter) InvalidateCache() {
|
||||||
LibravatarService.SetUseHTTPS(true)
|
d.mu.Lock()
|
||||||
LibravatarService.SetSecureFallbackHost(GravatarSourceURL.Host)
|
d.cacheTime = time.Time{}
|
||||||
} else {
|
d.mu.Unlock()
|
||||||
LibravatarService.SetUseHTTPS(false)
|
}
|
||||||
LibravatarService.SetFallbackHost(GravatarSourceURL.Host)
|
|
||||||
}
|
func NewDatabaseDynKeyGetter() config.DynKeyGetter {
|
||||||
}
|
return &dbConfigCachedGetter{}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
// enumerate all system setting keys
|
|
||||||
const (
|
|
||||||
KeyPictureDisableGravatar = "picture.disable_gravatar"
|
|
||||||
KeyPictureEnableFederatedAvatar = "picture.enable_federated_avatar"
|
|
||||||
)
|
|
||||||
|
|
||||||
// genSettingCacheKey returns the cache key for some configuration
|
|
||||||
func genSettingCacheKey(key string) string {
|
|
||||||
return "system.setting." + key
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
package system_test
|
package system_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@@ -15,43 +14,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSettings(t *testing.T) {
|
func TestSettings(t *testing.T) {
|
||||||
keyName := "server.LFS_LOCKS_PAGING_NUM"
|
keyName := "test.key"
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
newSetting := &system.Setting{SettingKey: keyName, SettingValue: "50"}
|
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &system.Setting{}))
|
||||||
|
|
||||||
// create setting
|
rev, settings, err := system.GetAllSettings(db.DefaultContext)
|
||||||
err := system.SetSetting(db.DefaultContext, newSetting)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
// test about saving unchanged values
|
|
||||||
err = system.SetSetting(db.DefaultContext, newSetting)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, rev)
|
||||||
|
assert.Len(t, settings, 1) // there is only one "revision" key
|
||||||
|
|
||||||
// get specific setting
|
err = system.SetSettings(db.DefaultContext, map[string]string{keyName: "true"})
|
||||||
settings, err := system.GetSettings(db.DefaultContext, []string{keyName})
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, settings, 1)
|
rev, settings, err = system.GetAllSettings(db.DefaultContext)
|
||||||
assert.EqualValues(t, newSetting.SettingValue, settings[strings.ToLower(keyName)].SettingValue)
|
|
||||||
|
|
||||||
// updated setting
|
|
||||||
updatedSetting := &system.Setting{SettingKey: keyName, SettingValue: "100", Version: settings[strings.ToLower(keyName)].Version}
|
|
||||||
err = system.SetSetting(db.DefaultContext, updatedSetting)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
value, err := system.GetSetting(db.DefaultContext, keyName)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, updatedSetting.SettingValue, value.SettingValue)
|
|
||||||
|
|
||||||
// get all settings
|
|
||||||
settings, err = system.GetAllSettings(db.DefaultContext)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, settings, 3)
|
|
||||||
assert.EqualValues(t, updatedSetting.SettingValue, settings[strings.ToLower(updatedSetting.SettingKey)].SettingValue)
|
|
||||||
|
|
||||||
// delete setting
|
|
||||||
err = system.DeleteSetting(db.DefaultContext, &system.Setting{SettingKey: strings.ToLower(keyName)})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
settings, err = system.GetAllSettings(db.DefaultContext)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 2, rev)
|
||||||
assert.Len(t, settings, 2)
|
assert.Len(t, settings, 2)
|
||||||
|
assert.EqualValues(t, "true", settings[keyName])
|
||||||
|
|
||||||
|
err = system.SetSettings(db.DefaultContext, map[string]string{keyName: "false"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
rev, settings, err = system.GetAllSettings(db.DefaultContext)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 3, rev)
|
||||||
|
assert.Len(t, settings, 2)
|
||||||
|
assert.EqualValues(t, "false", settings[keyName])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
"code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/setting/config"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
@@ -134,13 +135,11 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
|
|||||||
|
|
||||||
setting.IncomingEmail.ReplyToAddress = "incoming+%{token}@localhost"
|
setting.IncomingEmail.ReplyToAddress = "incoming+%{token}@localhost"
|
||||||
|
|
||||||
|
config.SetDynGetter(system.NewDatabaseDynKeyGetter())
|
||||||
|
|
||||||
if err = storage.Init(); err != nil {
|
if err = storage.Init(); err != nil {
|
||||||
fatalTestError("storage.Init: %v\n", err)
|
fatalTestError("storage.Init: %v\n", err)
|
||||||
}
|
}
|
||||||
if err = system_model.Init(db.DefaultContext); err != nil {
|
|
||||||
fatalTestError("models.Init: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = util.RemoveAll(repoRootPath); err != nil {
|
if err = util.RemoveAll(repoRootPath); err != nil {
|
||||||
fatalTestError("util.RemoveAll: %v\n", err)
|
fatalTestError("util.RemoveAll: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/avatars"
|
"code.gitea.io/gitea/models/avatars"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
|
||||||
"code.gitea.io/gitea/modules/avatar"
|
"code.gitea.io/gitea/modules/avatar"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@@ -67,9 +66,7 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
|
|||||||
useLocalAvatar := false
|
useLocalAvatar := false
|
||||||
autoGenerateAvatar := false
|
autoGenerateAvatar := false
|
||||||
|
|
||||||
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar,
|
disableGravatar := setting.Config().Picture.DisableGravatar.Value(ctx)
|
||||||
setting.GetDefaultDisableGravatar(),
|
|
||||||
)
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case u.UseCustomAvatar:
|
case u.UseCustomAvatar:
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LookupUserRedirect look up userID if a user has a redirect name
|
// LookupUserRedirect look up userID if a user has a redirect name
|
||||||
func LookupUserRedirect(userName string) (int64, error) {
|
func LookupUserRedirect(ctx context.Context, userName string) (int64, error) {
|
||||||
userName = strings.ToLower(userName)
|
userName = strings.ToLower(userName)
|
||||||
redirect := &Redirect{LowerName: userName}
|
redirect := &Redirect{LowerName: userName}
|
||||||
if has, err := db.GetEngine(db.DefaultContext).Get(redirect); err != nil {
|
if has, err := db.GetEngine(ctx).Get(redirect); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return 0, ErrUserRedirectNotExist{Name: userName}
|
return 0, ErrUserRedirectNotExist{Name: userName}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package user_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
|
||||||
@@ -15,10 +16,10 @@ import (
|
|||||||
func TestLookupUserRedirect(t *testing.T) {
|
func TestLookupUserRedirect(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
userID, err := user_model.LookupUserRedirect("olduser1")
|
userID, err := user_model.LookupUserRedirect(db.DefaultContext, "olduser1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, userID)
|
assert.EqualValues(t, 1, userID)
|
||||||
|
|
||||||
_, err = user_model.LookupUserRedirect("doesnotexist")
|
_, err = user_model.LookupUserRedirect(db.DefaultContext, "doesnotexist")
|
||||||
assert.True(t, user_model.IsErrUserRedirectNotExist(err))
|
assert.True(t, user_model.IsErrUserRedirectNotExist(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func GetOrganizationByParams(ctx *Context) {
|
|||||||
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
|
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if organization.IsErrOrgNotExist(err) {
|
if organization.IsErrOrgNotExist(err) {
|
||||||
redirectUserID, err := user_model.LookupUserRedirect(orgName)
|
redirectUserID, err := user_model.LookupUserRedirect(ctx, orgName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
RedirectToUser(ctx.Base, orgName, redirectUserID)
|
RedirectToUser(ctx.Base, orgName, redirectUserID)
|
||||||
} else if user_model.IsErrUserRedirectNotExist(err) {
|
} else if user_model.IsErrUserRedirectNotExist(err) {
|
||||||
|
|||||||
+21
-1
@@ -456,7 +456,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectUserID, err := user_model.LookupUserRedirect(userName); err == nil {
|
if redirectUserID, err := user_model.LookupUserRedirect(ctx, userName); err == nil {
|
||||||
RedirectToUser(ctx.Base, userName, redirectUserID)
|
RedirectToUser(ctx.Base, userName, redirectUserID)
|
||||||
} else if user_model.IsErrUserRedirectNotExist(err) {
|
} else if user_model.IsErrUserRedirectNotExist(err) {
|
||||||
ctx.NotFound("GetUserByName", nil)
|
ctx.NotFound("GetUserByName", nil)
|
||||||
@@ -773,6 +773,8 @@ const (
|
|||||||
RepoRefBlob
|
RepoRefBlob
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const headRefName = "HEAD"
|
||||||
|
|
||||||
// RepoRef handles repository reference names when the ref name is not
|
// RepoRef handles repository reference names when the ref name is not
|
||||||
// explicitly given
|
// explicitly given
|
||||||
func RepoRef() func(*Context) context.CancelFunc {
|
func RepoRef() func(*Context) context.CancelFunc {
|
||||||
@@ -833,6 +835,14 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
|
|||||||
case RepoRefBranch:
|
case RepoRefBranch:
|
||||||
ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist)
|
ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist)
|
||||||
if len(ref) == 0 {
|
if len(ref) == 0 {
|
||||||
|
|
||||||
|
// check if ref is HEAD
|
||||||
|
parts := strings.Split(path, "/")
|
||||||
|
if parts[0] == headRefName {
|
||||||
|
repo.TreePath = strings.Join(parts[1:], "/")
|
||||||
|
return repo.Repository.DefaultBranch
|
||||||
|
}
|
||||||
|
|
||||||
// maybe it's a renamed branch
|
// maybe it's a renamed branch
|
||||||
return getRefNameFromPath(ctx, repo, path, func(s string) bool {
|
return getRefNameFromPath(ctx, repo, path, func(s string) bool {
|
||||||
b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s)
|
b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s)
|
||||||
@@ -861,6 +871,16 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
|
|||||||
repo.TreePath = strings.Join(parts[1:], "/")
|
repo.TreePath = strings.Join(parts[1:], "/")
|
||||||
return parts[0]
|
return parts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(parts) > 0 && parts[0] == headRefName {
|
||||||
|
// HEAD ref points to last default branch commit
|
||||||
|
commit, err := repo.GitRepo.GetBranchCommit(repo.Repository.DefaultBranch)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
repo.TreePath = strings.Join(parts[1:], "/")
|
||||||
|
return commit.ID.String()
|
||||||
|
}
|
||||||
case RepoRefBlob:
|
case RepoRefBlob:
|
||||||
_, err := repo.GitRepo.GetBlob(path)
|
_, err := repo.GitRepo.GetBlob(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
|||||||
return fmt.Errorf("Unable to open authorized_keys file. ERROR: %w", err)
|
return fmt.Errorf("Unable to open authorized_keys file. ERROR: %w", err)
|
||||||
}
|
}
|
||||||
logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err)
|
logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err)
|
||||||
if err = asymkey_model.RewriteAllPublicKeys(); err != nil {
|
if err = asymkey_model.RewriteAllPublicKeys(ctx); err != nil {
|
||||||
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
|
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
|
||||||
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
|
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
|||||||
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
|
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
|
||||||
}
|
}
|
||||||
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
|
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
|
||||||
err = asymkey_model.RewriteAllPublicKeys()
|
err = asymkey_model.RewriteAllPublicKeys(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
|
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
|
||||||
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
|
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
|
|||||||
},
|
},
|
||||||
// find releases without existing repository
|
// find releases without existing repository
|
||||||
genericOrphanCheck("Orphaned Releases without existing repository",
|
genericOrphanCheck("Orphaned Releases without existing repository",
|
||||||
"release", "repository", "release.repo_id=repository.id"),
|
"release", "repository", "`release`.repo_id=repository.id"),
|
||||||
// find pulls without existing issues
|
// find pulls without existing issues
|
||||||
genericOrphanCheck("Orphaned PullRequests without existing issue",
|
genericOrphanCheck("Orphaned PullRequests without existing issue",
|
||||||
"pull_request", "issue", "pull_request.issue_id=issue.id"),
|
"pull_request", "issue", "pull_request.issue_id=issue.id"),
|
||||||
@@ -168,9 +168,9 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
|
|||||||
// find protected branches without existing repository
|
// find protected branches without existing repository
|
||||||
genericOrphanCheck("Protected Branches without existing repository",
|
genericOrphanCheck("Protected Branches without existing repository",
|
||||||
"protected_branch", "repository", "protected_branch.repo_id=repository.id"),
|
"protected_branch", "repository", "protected_branch.repo_id=repository.id"),
|
||||||
// find deleted branches without existing repository
|
// find branches without existing repository
|
||||||
genericOrphanCheck("Deleted Branches without existing repository",
|
genericOrphanCheck("Branches without existing repository",
|
||||||
"deleted_branch", "repository", "deleted_branch.repo_id=repository.id"),
|
"branch", "repository", "branch.repo_id=repository.id"),
|
||||||
// find LFS locks without existing repository
|
// find LFS locks without existing repository
|
||||||
genericOrphanCheck("LFS locks without existing repository",
|
genericOrphanCheck("LFS locks without existing repository",
|
||||||
"lfs_lock", "repository", "lfs_lock.repo_id=repository.id"),
|
"lfs_lock", "repository", "lfs_lock.repo_id=repository.id"),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user