mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-03 08:02:36 +09:00
Compare commits
71 Commits
v1.23.5
...
v1.21.0-rc
| 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 |
@@ -44,7 +44,10 @@ steps:
|
||||
image: techknowlogick/xgo:go-1.21.x
|
||||
pull: always
|
||||
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
|
||||
- make release
|
||||
environment:
|
||||
|
||||
@@ -11,7 +11,6 @@ parserOptions:
|
||||
plugins:
|
||||
- "@eslint-community/eslint-plugin-eslint-comments"
|
||||
- eslint-plugin-array-func
|
||||
- eslint-plugin-custom-elements
|
||||
- eslint-plugin-import
|
||||
- eslint-plugin-jquery
|
||||
- eslint-plugin-no-jquery
|
||||
@@ -19,6 +18,7 @@ plugins:
|
||||
- eslint-plugin-regexp
|
||||
- eslint-plugin-sonarjs
|
||||
- eslint-plugin-unicorn
|
||||
- eslint-plugin-vitest-globals
|
||||
- eslint-plugin-wc
|
||||
|
||||
env:
|
||||
@@ -46,6 +46,9 @@ overrides:
|
||||
- files: ["*.config.*"]
|
||||
rules:
|
||||
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/**/*"]
|
||||
rules:
|
||||
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
|
||||
@@ -88,19 +91,6 @@ rules:
|
||||
consistent-this: [0]
|
||||
constructor-super: [2]
|
||||
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: [0]
|
||||
default-param-last: [0]
|
||||
@@ -740,14 +730,27 @@ rules:
|
||||
valid-typeof: [2, {requireStringLiterals: true}]
|
||||
vars-on-top: [0]
|
||||
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/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-constructor-attributes: [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-typos: [2]
|
||||
wc/require-listener-teardown: [2]
|
||||
wc/tag-name-matches-class: [2]
|
||||
wrap-iife: [2, inside]
|
||||
wrap-regex: [0]
|
||||
yield-star-spacing: [2, after]
|
||||
|
||||
@@ -44,5 +44,3 @@ rules:
|
||||
ignore: |
|
||||
.venv
|
||||
node_modules
|
||||
/models/fixtures
|
||||
/models/migrations/fixtures
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -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
|
||||
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
|
||||
|
||||
* SECURITY
|
||||
|
||||
4
Makefile
4
Makefile
@@ -226,6 +226,7 @@ help:
|
||||
@echo " - test-frontend test frontend files"
|
||||
@echo " - test-backend test backend files"
|
||||
@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-py update py dependencies"
|
||||
@echo " - webpack build webpack files"
|
||||
@@ -924,6 +925,9 @@ node_modules: package-lock.json
|
||||
poetry install
|
||||
@touch .venv
|
||||
|
||||
.PHONY: update
|
||||
update: update-js update-py
|
||||
|
||||
.PHONY: update-js
|
||||
update-js: node-check | node_modules
|
||||
npx updates -u -f package.json
|
||||
|
||||
@@ -389,7 +389,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
||||
}
|
||||
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)
|
||||
gitRepo.Close()
|
||||
continue
|
||||
@@ -438,7 +438,7 @@ func runRegenerateKeys(_ *cli.Context) error {
|
||||
if err := initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return asymkey_model.RewriteAllPublicKeys()
|
||||
return asymkey_model.RewriteAllPublicKeys(ctx)
|
||||
}
|
||||
|
||||
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@@ -30,7 +31,7 @@ func TestMigratePackages(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
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{
|
||||
Owner: creator,
|
||||
PackageType: packages.TypeGeneric,
|
||||
|
||||
@@ -2568,6 +2568,12 @@ LEVEL = Info
|
||||
;DEFAULT_ACTIONS_URL = github
|
||||
;; Default artifact retention time in days, default is 90 days
|
||||
;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]`
|
||||
- `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.
|
||||
- `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.
|
||||
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
|
||||
|
||||
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).
|
||||
|
||||
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:
|
||||
|
||||
@@ -45,7 +45,7 @@ Note: All steps below requires that the database engine of your choice is instal
|
||||
|
||||
```sql
|
||||
SET old_passwords=0;
|
||||
CREATE USER 'gitea' IDENTIFIED BY 'gitea';
|
||||
CREATE USER 'gitea'@'%' IDENTIFIED BY 'gitea';
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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" \
|
||||
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
|
||||
```
|
||||
|
||||
在开发构建中,默认启用 Webpack 源映射,在生产构建中禁用。可以通过设置`ENABLE_SOURCEMAP=true`环境变量来启用它们。
|
||||
|
||||
## 测试
|
||||
|
||||
按照上述步骤完成后,工作目录中将会有一个`gitea`二进制文件。可以从该目录进行测试,或将其移动到带有测试数据的目录中。当手动从命令行启动 Gitea 时,可以通过按下`Ctrl + C`来停止程序。
|
||||
@@ -221,3 +219,11 @@ GOARCH=amd64 \
|
||||
TAGS="bindata sqlite sqlite_unlock_notify" \
|
||||
make build
|
||||
```
|
||||
|
||||
## 源映射
|
||||
|
||||
默认情况下,gitea 会为前端文件生成精简的源映射以节省空间。 这可以通过“ENABLE_SOURCEMAP”环境变量进行控制:
|
||||
|
||||
- `ENABLE_SOURCEMAP=true` 生成所有源映射,这是开发版本的默认设置
|
||||
- `ENABLE_SOURCEMAP=reduced` 生成有限的源映射,这是生产版本的默认设置
|
||||
- `ENABLE_SOURCEMAP=false` 不生成源映射
|
||||
|
||||
22
go.mod
22
go.mod
@@ -19,7 +19,7 @@ require (
|
||||
github.com/PuerkitoBio/goquery v1.8.1
|
||||
github.com/alecthomas/chroma/v2 v2.9.1
|
||||
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/buildkite/terminal-to-html/v3 v3.9.1
|
||||
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/cors v1.2.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-git/go-billy/v5 v5.4.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/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.5 // indirect
|
||||
github.com/blevesearch/geo v0.1.17 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.9.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.6 // indirect
|
||||
github.com/blevesearch/geo v0.1.18 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/gtreap v0.1.1 // 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/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||
github.com/blevesearch/vellum v1.0.10 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.9 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.12 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.10 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.13 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230611145640-acc696258285 // indirect
|
||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||
|
||||
44
go.sum
44
go.sum
@@ -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/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.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.9.0 h1:g1YivPG8jOtrN013Fe8OBXubkiTwvm7/vG2vXz03ANU=
|
||||
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/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.3.9 h1:pUMvK0mxAexqasZcVj8lazmWnEW5XiV0tASIqANiNTQ=
|
||||
github.com/blevesearch/bleve/v2 v2.3.9/go.mod h1:1PibElcjlQMQHF9uS9mRv58ODQgj4pCWHA1Wfd+qagU=
|
||||
github.com/blevesearch/bleve/v2 v2.3.10 h1:z8V0wwGoL4rp7nG/O3qVVLYxUqCbEwskMt4iRJsPLgg=
|
||||
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.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw=
|
||||
github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||
github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA=
|
||||
github.com/blevesearch/geo v0.1.17/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
|
||||
github.com/blevesearch/bleve_index_api v1.0.6 h1:gyUUxdsrvmW3jVhhYdCVL6h9dCjNT/geNU7PxGn37p8=
|
||||
github.com/blevesearch/bleve_index_api v1.0.6/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||
github.com/blevesearch/geo v0.1.18 h1:Np8jycHTZ5scFe7VEPLrDoHnnb9C4j636ue/CGrhtDw=
|
||||
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/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||
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/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.1.5 h1:1g713kpCQZ8u4a3stRGBfrwVOuGRnmxOVU5MQkUPrHU=
|
||||
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 h1:CdekX/Ob6YCYmeHzD72cKpwzBjvkOGegHOqhAkXp6yA=
|
||||
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.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||
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/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
||||
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.9/go.mod h1:jcAYnQwlr+LqD2vLjDWjWiZDXDXGFqPbpPDRTd3XmS4=
|
||||
github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk=
|
||||
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.3.9 h1:MXGLlZ03oxXH3DMJTZaBaRj2xb6t4wQVZeZK/wu1M6w=
|
||||
github.com/blevesearch/zapx/v12 v12.3.9/go.mod h1:QXCMwmOkdLnMDgTN1P4CcuX5F851iUOtOwXbw0HMBYs=
|
||||
github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s=
|
||||
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.3.9 h1:+VAz9V0VmllHXlZV4DCvfYj0nqaZHgF3MeEHwOyRBwQ=
|
||||
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 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIqMGahDE8=
|
||||
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.3.9 h1:wuqxATgsTCNHM9xsOFOeFp8H2heZ/gMX/tsl9lRK8U4=
|
||||
github.com/blevesearch/zapx/v14 v14.3.9/go.mod h1:MWZ4v8AzFBRurhDzkLvokFW8ljcq9Evm27mkWe8OGbM=
|
||||
github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU=
|
||||
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.3.12 h1:w/kU9aHyfMDEdwHGZzCiakC3HZ9z5gYlXaALDC4Dct8=
|
||||
github.com/blevesearch/zapx/v15 v15.3.12/go.mod h1:tx53gDJS/7Oa3Je820cmVurqCuJ4dqdAy1kiDMV/IUo=
|
||||
github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ=
|
||||
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 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
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-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-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs=
|
||||
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 h1:jtYXblst2+d9k7ZgEgkv6Q5hKRKPf0qHRjt715BZEX4=
|
||||
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/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
|
||||
@@ -22,7 +22,7 @@ type ActionRunnerToken struct {
|
||||
Owner *user_model.User `xorm:"-"`
|
||||
RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
IsActive bool
|
||||
IsActive bool // true means it can be used
|
||||
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
@@ -57,7 +57,7 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string
|
||||
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) {
|
||||
token, err := util.CryptoRandomString(40)
|
||||
if err != nil {
|
||||
@@ -66,17 +66,27 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo
|
||||
runnerToken := &ActionRunnerToken{
|
||||
OwnerID: ownerID,
|
||||
RepoID: repoID,
|
||||
IsActive: false,
|
||||
IsActive: true,
|
||||
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
|
||||
func GetUnactivatedRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
// GetLastestRunnerToken returns the latest runner token
|
||||
func GetLastestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
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 {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
|
||||
@@ -140,7 +140,7 @@ func (at ActionType) InActions(actions ...string) bool {
|
||||
// used in template render.
|
||||
type Action struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 // Receiver user id.
|
||||
UserID int64 `xorm:"INDEX"` // Receiver user id.
|
||||
OpType ActionType
|
||||
ActUserID int64 // Action user id.
|
||||
ActUser *user_model.User `xorm:"-"`
|
||||
@@ -208,91 +208,91 @@ func (a *Action) loadRepo(ctx context.Context) {
|
||||
}
|
||||
|
||||
// GetActFullName gets the action's user full name.
|
||||
func (a *Action) GetActFullName() string {
|
||||
a.LoadActUser(db.DefaultContext)
|
||||
func (a *Action) GetActFullName(ctx context.Context) string {
|
||||
a.LoadActUser(ctx)
|
||||
return a.ActUser.FullName
|
||||
}
|
||||
|
||||
// GetActUserName gets the action's user name.
|
||||
func (a *Action) GetActUserName() string {
|
||||
a.LoadActUser(db.DefaultContext)
|
||||
func (a *Action) GetActUserName(ctx context.Context) string {
|
||||
a.LoadActUser(ctx)
|
||||
return a.ActUser.Name
|
||||
}
|
||||
|
||||
// ShortActUserName gets the action's user name trimmed to max 20
|
||||
// chars.
|
||||
func (a *Action) ShortActUserName() string {
|
||||
return base.EllipsisString(a.GetActUserName(), 20)
|
||||
func (a *Action) ShortActUserName(ctx context.Context) string {
|
||||
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.
|
||||
func (a *Action) GetDisplayName() string {
|
||||
func (a *Action) GetDisplayName(ctx context.Context) string {
|
||||
if setting.UI.DefaultShowFullName {
|
||||
trimmedFullName := strings.TrimSpace(a.GetActFullName())
|
||||
trimmedFullName := strings.TrimSpace(a.GetActFullName(ctx))
|
||||
if len(trimmedFullName) > 0 {
|
||||
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
|
||||
func (a *Action) GetDisplayNameTitle() string {
|
||||
func (a *Action) GetDisplayNameTitle(ctx context.Context) string {
|
||||
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.
|
||||
func (a *Action) GetRepoUserName() string {
|
||||
a.loadRepo(db.DefaultContext)
|
||||
func (a *Action) GetRepoUserName(ctx context.Context) string {
|
||||
a.loadRepo(ctx)
|
||||
return a.Repo.OwnerName
|
||||
}
|
||||
|
||||
// ShortRepoUserName returns the name of the action repository owner
|
||||
// trimmed to max 20 chars.
|
||||
func (a *Action) ShortRepoUserName() string {
|
||||
return base.EllipsisString(a.GetRepoUserName(), 20)
|
||||
func (a *Action) ShortRepoUserName(ctx context.Context) string {
|
||||
return base.EllipsisString(a.GetRepoUserName(ctx), 20)
|
||||
}
|
||||
|
||||
// GetRepoName returns the name of the action repository.
|
||||
func (a *Action) GetRepoName() string {
|
||||
a.loadRepo(db.DefaultContext)
|
||||
func (a *Action) GetRepoName(ctx context.Context) string {
|
||||
a.loadRepo(ctx)
|
||||
return a.Repo.Name
|
||||
}
|
||||
|
||||
// ShortRepoName returns the name of the action repository
|
||||
// trimmed to max 33 chars.
|
||||
func (a *Action) ShortRepoName() string {
|
||||
return base.EllipsisString(a.GetRepoName(), 33)
|
||||
func (a *Action) ShortRepoName(ctx context.Context) string {
|
||||
return base.EllipsisString(a.GetRepoName(ctx), 33)
|
||||
}
|
||||
|
||||
// GetRepoPath returns the virtual path to the action repository.
|
||||
func (a *Action) GetRepoPath() string {
|
||||
return path.Join(a.GetRepoUserName(), a.GetRepoName())
|
||||
func (a *Action) GetRepoPath(ctx context.Context) string {
|
||||
return path.Join(a.GetRepoUserName(ctx), a.GetRepoName(ctx))
|
||||
}
|
||||
|
||||
// ShortRepoPath returns the virtual path to the action repository
|
||||
// trimmed to max 20 + 1 + 33 chars.
|
||||
func (a *Action) ShortRepoPath() string {
|
||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
|
||||
func (a *Action) ShortRepoPath(ctx context.Context) string {
|
||||
return path.Join(a.ShortRepoUserName(ctx), a.ShortRepoName(ctx))
|
||||
}
|
||||
|
||||
// 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
|
||||
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.
|
||||
func (a *Action) GetRepoAbsoluteLink() string {
|
||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
|
||||
func (a *Action) GetRepoAbsoluteLink(ctx context.Context) string {
|
||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName(ctx)) + "/" + url.PathEscape(a.GetRepoName(ctx))
|
||||
}
|
||||
|
||||
// GetCommentHTMLURL returns link to action comment.
|
||||
func (a *Action) GetCommentHTMLURL() string {
|
||||
return a.getCommentHTMLURL(db.DefaultContext)
|
||||
func (a *Action) GetCommentHTMLURL(ctx context.Context) string {
|
||||
return a.getCommentHTMLURL(ctx)
|
||||
}
|
||||
|
||||
func (a *Action) loadComment(ctx context.Context) (err error) {
|
||||
@@ -309,7 +309,7 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string {
|
||||
}
|
||||
_ = a.loadComment(ctx)
|
||||
if a.Comment != nil {
|
||||
return a.Comment.HTMLURL()
|
||||
return a.Comment.HTMLURL(ctx)
|
||||
}
|
||||
if len(a.GetIssueInfos()) == 0 {
|
||||
return "#"
|
||||
@@ -334,8 +334,8 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string {
|
||||
}
|
||||
|
||||
// GetCommentLink returns link to action comment.
|
||||
func (a *Action) GetCommentLink() string {
|
||||
return a.getCommentLink(db.DefaultContext)
|
||||
func (a *Action) GetCommentLink(ctx context.Context) string {
|
||||
return a.getCommentLink(ctx)
|
||||
}
|
||||
|
||||
func (a *Action) getCommentLink(ctx context.Context) string {
|
||||
@@ -344,7 +344,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
|
||||
}
|
||||
_ = a.loadComment(ctx)
|
||||
if a.Comment != nil {
|
||||
return a.Comment.Link()
|
||||
return a.Comment.Link(ctx)
|
||||
}
|
||||
if len(a.GetIssueInfos()) == 0 {
|
||||
return "#"
|
||||
@@ -374,8 +374,8 @@ func (a *Action) GetBranch() string {
|
||||
}
|
||||
|
||||
// GetRefLink returns the action's ref link.
|
||||
func (a *Action) GetRefLink() string {
|
||||
return git.RefURL(a.GetRepoLink(), a.RefName)
|
||||
func (a *Action) GetRefLink(ctx context.Context) string {
|
||||
return git.RefURL(a.GetRepoLink(ctx), a.RefName)
|
||||
}
|
||||
|
||||
// GetTag returns the action's repository tag.
|
||||
@@ -399,11 +399,10 @@ func (a *Action) GetIssueInfos() []string {
|
||||
return strings.SplitN(a.Content, "|", 3)
|
||||
}
|
||||
|
||||
// GetIssueTitle returns the title of first issue associated
|
||||
// with the action. This function will be invoked in template so keep db.DefaultContext here
|
||||
func (a *Action) GetIssueTitle() string {
|
||||
// GetIssueTitle returns the title of first issue associated with the action.
|
||||
func (a *Action) GetIssueTitle(ctx context.Context) string {
|
||||
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 {
|
||||
log.Error("GetIssueByIndex: %v", err)
|
||||
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")
|
||||
}
|
||||
|
||||
cond, err := activityQueryCondition(opts)
|
||||
cond, err := activityQueryCondition(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@@ -473,11 +472,11 @@ func ActivityReadable(user, doer *user_model.User) bool {
|
||||
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()
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -564,12 +563,12 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -679,8 +678,8 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||
}
|
||||
|
||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||
func NotifyWatchersActions(acts []*Action) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func NotifyWatchersActions(ctx context.Context, acts []*Action) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestAction_GetRepoPath(t *testing.T) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
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) {
|
||||
@@ -35,9 +35,9 @@ func TestAction_GetRepoLink(t *testing.T) {
|
||||
action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID}
|
||||
setting.AppSubURL = "/suburl"
|
||||
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
||||
assert.Equal(t, expected, action.GetRepoLink())
|
||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
|
||||
assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL())
|
||||
assert.Equal(t, expected, action.GetRepoLink(db.DefaultContext))
|
||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink(db.DefaultContext))
|
||||
assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext))
|
||||
}
|
||||
|
||||
func TestGetFeeds(t *testing.T) {
|
||||
|
||||
@@ -175,8 +175,8 @@ func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_mo
|
||||
// CreateOrUpdateIssueNotifications creates an issue notification
|
||||
// for each watcher, or updates it if already exists
|
||||
// receiverID > 0 just send to receiver, else send to all watcher
|
||||
func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -435,21 +435,21 @@ func (n *Notification) loadUser(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// GetRepo returns the repo of the notification
|
||||
func (n *Notification) GetRepo() (*repo_model.Repository, error) {
|
||||
return n.Repository, n.loadRepo(db.DefaultContext)
|
||||
func (n *Notification) GetRepo(ctx context.Context) (*repo_model.Repository, error) {
|
||||
return n.Repository, n.loadRepo(ctx)
|
||||
}
|
||||
|
||||
// GetIssue returns the issue of the notification
|
||||
func (n *Notification) GetIssue() (*issues_model.Issue, error) {
|
||||
return n.Issue, n.loadIssue(db.DefaultContext)
|
||||
func (n *Notification) GetIssue(ctx context.Context) (*issues_model.Issue, error) {
|
||||
return n.Issue, n.loadIssue(ctx)
|
||||
}
|
||||
|
||||
// HTMLURL formats a URL-string to the notification
|
||||
func (n *Notification) HTMLURL() string {
|
||||
func (n *Notification) HTMLURL(ctx context.Context) string {
|
||||
switch n.Source {
|
||||
case NotificationSourceIssue, NotificationSourcePullRequest:
|
||||
if n.Comment != nil {
|
||||
return n.Comment.HTMLURL()
|
||||
return n.Comment.HTMLURL(ctx)
|
||||
}
|
||||
return n.Issue.HTMLURL()
|
||||
case NotificationSourceCommit:
|
||||
@@ -461,11 +461,11 @@ func (n *Notification) HTMLURL() string {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
case NotificationSourceIssue, NotificationSourcePullRequest:
|
||||
if n.Comment != nil {
|
||||
return n.Comment.Link()
|
||||
return n.Comment.Link(ctx)
|
||||
}
|
||||
return n.Issue.Link()
|
||||
case NotificationSourceCommit:
|
||||
@@ -733,12 +733,12 @@ type UserIDCount struct {
|
||||
}
|
||||
|
||||
// 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 ` +
|
||||
`WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
|
||||
`updated_unix < ?) AND status = ? GROUP BY user_id`
|
||||
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.
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
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
|
||||
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) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
||||
repo, err := notf.GetRepo()
|
||||
repo, err := notf.GetRepo(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, repo, notf.Repository)
|
||||
assert.EqualValues(t, notf.RepoID, repo.ID)
|
||||
@@ -59,7 +59,7 @@ func TestNotification_GetRepo(t *testing.T) {
|
||||
func TestNotification_GetIssue(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
|
||||
issue, err := notf.GetIssue()
|
||||
issue, err := notf.GetIssue(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, issue, notf.Issue)
|
||||
assert.EqualValues(t, notf.IssueID, issue.ID)
|
||||
|
||||
@@ -342,7 +342,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
||||
|
||||
// Published releases list
|
||||
sess := releasesForActivityStatement(ctx, repoID, fromTime)
|
||||
sess.OrderBy("release.created_unix DESC")
|
||||
sess.OrderBy("`release`.created_unix DESC")
|
||||
stats.PublishedReleases = make([]*repo_model.Release, 0)
|
||||
if err = sess.Find(&stats.PublishedReleases); err != nil {
|
||||
return err
|
||||
@@ -350,7 +350,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from
|
||||
|
||||
// Published releases authors
|
||||
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
|
||||
}
|
||||
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 {
|
||||
return db.GetEngine(ctx).Where("release.repo_id = ?", repoID).
|
||||
And("release.is_draft = ?", false).
|
||||
And("release.created_unix >= ?", fromTime.Unix())
|
||||
return db.GetEngine(ctx).Where("`release`.repo_id = ?", repoID).
|
||||
And("`release`.is_draft = ?", false).
|
||||
And("`release`.created_unix >= ?", fromTime.Unix())
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
package activities
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@@ -18,16 +20,16 @@ type UserHeatmapData struct {
|
||||
}
|
||||
|
||||
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
|
||||
func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(user, nil, doer)
|
||||
func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(ctx, user, nil, doer)
|
||||
}
|
||||
|
||||
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
|
||||
func GetUserHeatmapDataByUserTeam(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
return getUserHeatmapData(user, team, doer)
|
||||
func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
|
||||
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)
|
||||
|
||||
if !ActivityReadable(user, doer) {
|
||||
@@ -45,7 +47,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
|
||||
groupByName = groupBy
|
||||
}
|
||||
|
||||
cond, err := activityQueryCondition(GetFeedsOptions{
|
||||
cond, err := activityQueryCondition(ctx, GetFeedsOptions{
|
||||
RequestedUser: user,
|
||||
RequestedTeam: team,
|
||||
Actor: doer,
|
||||
@@ -60,7 +62,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hdata, db.GetEngine(db.DefaultContext).
|
||||
return hdata, db.GetEngine(ctx).
|
||||
Select(groupBy+" AS timestamp, count(user_id) as contributions").
|
||||
Table("action").
|
||||
Where(cond).
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get the heatmap and compare
|
||||
heatmap, err := activities_model.GetUserHeatmapDataByUser(user, doer)
|
||||
heatmap, err := activities_model.GetUserHeatmapDataByUser(db.DefaultContext, user, doer)
|
||||
var contributions int
|
||||
for _, hm := range heatmap {
|
||||
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
|
||||
func CountUserGPGKeys(userID int64) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
||||
func CountUserGPGKeys(ctx context.Context, userID int64) (int64, error) {
|
||||
return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
||||
}
|
||||
|
||||
// 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)
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(keyID).Get(key)
|
||||
has, err := db.GetEngine(ctx).ID(keyID).Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@@ -105,9 +105,9 @@ func GetGPGKeyByID(keyID int64) (*GPGKey, error) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
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
|
||||
@@ -224,8 +224,8 @@ func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
||||
}
|
||||
|
||||
// DeleteGPGKey deletes GPG key information in database.
|
||||
func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
||||
key, err := GetGPGKeyByID(id)
|
||||
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
||||
key, err := GetGPGKeyByID(ctx, id)
|
||||
if err != nil {
|
||||
if IsErrGPGKeyNotExist(err) {
|
||||
return nil
|
||||
@@ -238,7 +238,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
|
||||
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -66,13 +66,13 @@ func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
|
||||
if keyID == "" {
|
||||
return nil
|
||||
}
|
||||
keys, err := GetGPGKeysByKeyID(keyID)
|
||||
keys, err := GetGPGKeysByKeyID(ctx, keyID)
|
||||
if err != nil {
|
||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||
return &CommitVerification{
|
||||
@@ -407,7 +407,7 @@ func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
|
||||
for _, key := range keys {
|
||||
var primaryKeys []*GPGKey
|
||||
if key.PrimaryKeyID != "" {
|
||||
primaryKeys, err = GetGPGKeysByKeyID(key.PrimaryKeyID)
|
||||
primaryKeys, err = GetGPGKeysByKeyID(ctx, key.PrimaryKeyID)
|
||||
if err != nil {
|
||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||
return &CommitVerification{
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
@@ -228,7 +229,7 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL
|
||||
=zHo9
|
||||
-----END PGP PUBLIC KEY BLOCK-----`
|
||||
|
||||
keys, err := AddGPGKey(1, testEmailWithUpperCaseLetters, "", "")
|
||||
keys, err := AddGPGKey(db.DefaultContext, 1, testEmailWithUpperCaseLetters, "", "")
|
||||
assert.NoError(t, err)
|
||||
if assert.NotEmpty(t, keys) {
|
||||
key := keys[0]
|
||||
|
||||
@@ -117,7 +117,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
||||
// 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
|
||||
// outside any session scope independently.
|
||||
func RewriteAllPublicKeys() error {
|
||||
func RewriteAllPublicKeys(ctx context.Context) error {
|
||||
// Don't rewrite key if internal server
|
||||
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -5,18 +5,20 @@ package avatars
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"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/cache"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"strk.kbt.io/projects/go/libravatar"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -36,24 +38,54 @@ func init() {
|
||||
db.RegisterModel(new(EmailHash))
|
||||
}
|
||||
|
||||
var (
|
||||
type avatarSettingStruct struct {
|
||||
defaultAvatarLink string
|
||||
once sync.Once
|
||||
)
|
||||
gravatarSource string
|
||||
gravatarSourceURL *url.URL
|
||||
libravatar *libravatar.Libravatar
|
||||
}
|
||||
|
||||
// DefaultAvatarLink the default avatar link
|
||||
func DefaultAvatarLink() string {
|
||||
once.Do(func() {
|
||||
var avatarSettingAtomic atomic.Pointer[avatarSettingStruct]
|
||||
|
||||
func loadAvatarSetting() (*avatarSettingStruct, error) {
|
||||
s := avatarSettingAtomic.Load()
|
||||
if s == nil || s.gravatarSource != setting.GravatarSource {
|
||||
s = &avatarSettingStruct{}
|
||||
u, err := url.Parse(setting.AppSubURL)
|
||||
if err != nil {
|
||||
log.Error("Can not parse AppSubURL: %v", err)
|
||||
return
|
||||
return nil, fmt.Errorf("unable to parse AppSubURL: %w", err)
|
||||
}
|
||||
|
||||
u.Path = path.Join(u.Path, "/assets/img/avatar_default.png")
|
||||
defaultAvatarLink = u.String()
|
||||
})
|
||||
return defaultAvatarLink
|
||||
s.defaultAvatarLink = u.String()
|
||||
|
||||
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/
|
||||
@@ -76,7 +108,11 @@ func GetEmailForHash(md5Sum string) (string, error) {
|
||||
// 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.
|
||||
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 {
|
||||
log.Error("LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||
return nil, err
|
||||
@@ -153,15 +189,13 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
|
||||
return DefaultAvatarLink()
|
||||
}
|
||||
|
||||
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar,
|
||||
setting.GetDefaultDisableGravatar(),
|
||||
)
|
||||
avatarSetting, err := loadAvatarSetting()
|
||||
if err != nil {
|
||||
return DefaultAvatarLink()
|
||||
}
|
||||
|
||||
enableFederatedAvatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureEnableFederatedAvatar,
|
||||
setting.GetDefaultEnableFederatedAvatar(disableGravatar))
|
||||
|
||||
var err error
|
||||
if enableFederatedAvatar && system_model.LibravatarService != nil {
|
||||
enableFederatedAvatar := setting.Config().Picture.EnableFederatedAvatar.Value(ctx)
|
||||
if enableFederatedAvatar {
|
||||
emailHash := saveEmailHash(email)
|
||||
if final {
|
||||
// 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
|
||||
}
|
||||
|
||||
disableGravatar := setting.Config().Picture.DisableGravatar.Value(ctx)
|
||||
if !disableGravatar {
|
||||
// copy GravatarSourceURL, because we will modify its Path.
|
||||
avatarURLCopy := *system_model.GravatarSourceURL
|
||||
avatarURLCopy := *avatarSetting.gravatarSourceURL
|
||||
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))
|
||||
return generateRecognizedAvatarURL(avatarURLCopy, size)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/setting/config"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -17,19 +18,16 @@ import (
|
||||
const gravatarSource = "https://secure.gravatar.com/avatar/"
|
||||
|
||||
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)
|
||||
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)
|
||||
system_model.LibravatarService = nil
|
||||
}
|
||||
|
||||
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)
|
||||
setting.GravatarSource = gravatarSource
|
||||
err = system_model.Init(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHashEmail(t *testing.T) {
|
||||
@@ -47,10 +45,12 @@ func TestSizedAvatarLink(t *testing.T) {
|
||||
setting.AppSubURL = "/testsuburl"
|
||||
|
||||
disableGravatar(t)
|
||||
config.GetDynGetter().InvalidateCache()
|
||||
assert.Equal(t, "/testsuburl/assets/img/avatar_default.png",
|
||||
avatars_model.GenerateEmailAvatarFastLink(db.DefaultContext, "gitea@example.com", 100))
|
||||
|
||||
enableGravatar(t)
|
||||
config.GetDynGetter().InvalidateCache()
|
||||
assert.Equal(t,
|
||||
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=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, " repo_id: %d\n", a.RepoID)
|
||||
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
|
||||
|
||||
@@ -22,12 +22,13 @@ func TestFixtureGeneration(t *testing.T) {
|
||||
if !assert.NoError(t, err) {
|
||||
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) {
|
||||
return
|
||||
}
|
||||
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")
|
||||
|
||||
@@ -135,4 +135,3 @@
|
||||
user_id: 31
|
||||
repo_id: 28
|
||||
mode: 4
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
id: 1
|
||||
uid: 1
|
||||
name: Token A
|
||||
#token: d2c6c1ba3890b309189a8e618c72a162e4efbf36
|
||||
# token: d2c6c1ba3890b309189a8e618c72a162e4efbf36
|
||||
token_hash: 2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f
|
||||
token_salt: QuSiZr1byZ
|
||||
token_last_eight: e4efbf36
|
||||
@@ -13,7 +13,7 @@
|
||||
id: 2
|
||||
uid: 1
|
||||
name: Token B
|
||||
#token: 4c6f36e6cf498e2a448662f915d932c09c5a146c
|
||||
# token: 4c6f36e6cf498e2a448662f915d932c09c5a146c
|
||||
token_hash: 1a0e32a231ebbd582dc626c1543a42d3c63d4fa76c07c72862721467c55e8f81c923d60700f0528b5f5f443f055559d3a279
|
||||
token_salt: Lfwopukrq5
|
||||
token_last_eight: 9c5a146c
|
||||
@@ -24,10 +24,10 @@
|
||||
id: 3
|
||||
uid: 2
|
||||
name: Token A
|
||||
#token: 90a18faa671dc43924b795806ffe4fd169d28c91
|
||||
# token: 90a18faa671dc43924b795806ffe4fd169d28c91
|
||||
token_hash: d6d404048048812d9e911d93aefbe94fc768d4876fdf75e3bef0bdc67828e0af422846d3056f2f25ec35c51dc92075685ec5
|
||||
token_salt: 99ArgXKlQQ
|
||||
token_last_eight: 69d28c91
|
||||
created_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
|
||||
size: 0
|
||||
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
|
||||
repo_id: 1
|
||||
sha: "1234123412341234123412341234123412341234"
|
||||
max_index: 5
|
||||
max_index: 5
|
||||
|
||||
@@ -321,3 +321,20 @@
|
||||
created_unix: 946684830
|
||||
updated_unix: 978307200
|
||||
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
|
||||
created_unix: 1559593109
|
||||
updated_unix: 1565224552
|
||||
login_source_id: 0
|
||||
login_source_id: 0
|
||||
|
||||
@@ -89,3 +89,12 @@
|
||||
base_branch: main
|
||||
merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6
|
||||
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)
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
@@ -7,7 +7,7 @@
|
||||
created_unix: 1573248001
|
||||
|
||||
-
|
||||
id: 2 #issue reaction
|
||||
id: 2 # issue reaction
|
||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
@@ -15,7 +15,7 @@
|
||||
created_unix: 1573248002
|
||||
|
||||
-
|
||||
id: 3 #issue reaction
|
||||
id: 3 # issue reaction
|
||||
type: eyes # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
@@ -23,7 +23,7 @@
|
||||
created_unix: 1573248003
|
||||
|
||||
-
|
||||
id: 4 #comment reaction
|
||||
id: 4 # comment reaction
|
||||
type: laugh # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 2
|
||||
@@ -31,7 +31,7 @@
|
||||
created_unix: 1573248004
|
||||
|
||||
-
|
||||
id: 5 #comment reaction
|
||||
id: 5 # comment reaction
|
||||
type: laugh # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 2
|
||||
|
||||
@@ -136,3 +136,17 @@
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
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_issues: 0
|
||||
num_closed_issues: 0
|
||||
num_pulls: 0
|
||||
num_pulls: 1
|
||||
num_closed_pulls: 0
|
||||
num_milestones: 0
|
||||
num_closed_milestones: 0
|
||||
|
||||
@@ -132,3 +132,41 @@
|
||||
content: "singular review from org6 and final review for this pr"
|
||||
updated_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
|
||||
authorize: 1 # read
|
||||
num_repos: 1
|
||||
num_members: 2
|
||||
num_members: 3
|
||||
includes_all_repositories: false
|
||||
can_create_org_repo: false
|
||||
|
||||
|
||||
@@ -62,4 +62,4 @@
|
||||
id: 11
|
||||
org_id: 17
|
||||
team_id: 9
|
||||
repo_id: 24
|
||||
repo_id: 24
|
||||
|
||||
@@ -123,3 +123,9 @@
|
||||
org_id: 36
|
||||
team_id: 20
|
||||
uid: 5
|
||||
|
||||
-
|
||||
id: 22
|
||||
org_id: 17
|
||||
team_id: 9
|
||||
uid: 15
|
||||
|
||||
@@ -26,4 +26,4 @@
|
||||
id: 5
|
||||
user_id: 11
|
||||
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),
|
||||
repo.GetTrustModel(),
|
||||
func(user *user_model.User) (bool, error) {
|
||||
return repo_model.IsOwnerMemberCollaborator(repo, user.ID)
|
||||
return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID)
|
||||
},
|
||||
),
|
||||
repo,
|
||||
|
||||
@@ -246,7 +246,7 @@ type Comment struct {
|
||||
NewTitle string
|
||||
OldRef string
|
||||
NewRef string
|
||||
DependentIssueID int64
|
||||
DependentIssueID int64 `xorm:"index"` // This is used by issue_service.deleteIssue
|
||||
DependentIssue *Issue `xorm:"-"`
|
||||
|
||||
CommitID int64
|
||||
@@ -371,42 +371,42 @@ func (c *Comment) AfterDelete(ctx context.Context) {
|
||||
}
|
||||
|
||||
// HTMLURL formats a URL-string to the issue-comment
|
||||
func (c *Comment) HTMLURL() string {
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
func (c *Comment) HTMLURL(ctx context.Context) string {
|
||||
err := c.LoadIssue(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
||||
err = c.Issue.LoadRepo(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
}
|
||||
return c.Issue.HTMLURL() + c.hashLink()
|
||||
return c.Issue.HTMLURL() + c.hashLink(ctx)
|
||||
}
|
||||
|
||||
// Link formats a relative URL-string to the issue-comment
|
||||
func (c *Comment) Link() string {
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
func (c *Comment) Link(ctx context.Context) string {
|
||||
err := c.LoadIssue(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
||||
err = c.Issue.LoadRepo(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
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.ReviewID == 0 {
|
||||
return "/files#" + c.HashTag()
|
||||
}
|
||||
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)
|
||||
return "/files#" + c.HashTag()
|
||||
}
|
||||
@@ -419,13 +419,13 @@ func (c *Comment) hashLink() string {
|
||||
}
|
||||
|
||||
// APIURL formats a API-string to the issue-comment
|
||||
func (c *Comment) APIURL() string {
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
func (c *Comment) APIURL(ctx context.Context) string {
|
||||
err := c.LoadIssue(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
||||
err = c.Issue.LoadRepo(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
@@ -435,8 +435,8 @@ func (c *Comment) APIURL() string {
|
||||
}
|
||||
|
||||
// IssueURL formats a URL-string to the issue
|
||||
func (c *Comment) IssueURL() string {
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
func (c *Comment) IssueURL(ctx context.Context) string {
|
||||
err := c.LoadIssue(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
@@ -446,7 +446,7 @@ func (c *Comment) IssueURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
||||
err = c.Issue.LoadRepo(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
@@ -455,14 +455,14 @@ func (c *Comment) IssueURL() string {
|
||||
}
|
||||
|
||||
// PRURL formats a URL-string to the pull-request
|
||||
func (c *Comment) PRURL() string {
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
func (c *Comment) PRURL(ctx context.Context) string {
|
||||
err := c.LoadIssue(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
||||
err = c.Issue.LoadRepo(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
@@ -490,9 +490,9 @@ func (c *Comment) EventTag() string {
|
||||
}
|
||||
|
||||
// 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
|
||||
has, err := db.GetEngine(db.DefaultContext).ID(c.LabelID).Get(&label)
|
||||
has, err := db.GetEngine(ctx).ID(c.LabelID).Get(&label)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
@@ -506,10 +506,10 @@ func (c *Comment) LoadLabel() error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
return err
|
||||
} else if has {
|
||||
@@ -519,7 +519,7 @@ func (c *Comment) LoadProject() error {
|
||||
|
||||
if c.ProjectID > 0 {
|
||||
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 {
|
||||
return err
|
||||
} else if has {
|
||||
@@ -569,8 +569,8 @@ func (c *Comment) LoadAttachments(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// UpdateAttachments update attachments by UUIDs for the comment
|
||||
func (c *Comment) UpdateAttachments(uuids []string) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func (c *Comment) UpdateAttachments(ctx context.Context, uuids []string) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -591,11 +591,11 @@ func (c *Comment) UpdateAttachments(uuids []string) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
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 !user_model.IsErrUserNotExist(err) {
|
||||
return err
|
||||
@@ -603,20 +603,20 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
|
||||
c.Assignee = user_model.NewGhostUser()
|
||||
}
|
||||
} 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
|
||||
}
|
||||
|
||||
if err = c.Issue.LoadRepo(db.DefaultContext); err != nil {
|
||||
if err = c.Issue.LoadRepo(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = c.Issue.Repo.LoadOwner(db.DefaultContext); err != nil {
|
||||
if err = c.Issue.Repo.LoadOwner(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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) {
|
||||
return err
|
||||
}
|
||||
@@ -626,11 +626,11 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 user_model.IsErrUserNotExist(err) {
|
||||
c.ResolveDoer = user_model.NewGhostUser()
|
||||
@@ -646,11 +646,11 @@ func (c *Comment) IsResolved() bool {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil
|
||||
}
|
||||
c.DependentIssue, err = GetIssueByID(db.DefaultContext, c.DependentIssueID)
|
||||
c.DependentIssue, err = GetIssueByID(ctx, c.DependentIssueID)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -683,8 +683,8 @@ func (c *Comment) loadReactions(ctx context.Context, repo *repo_model.Repository
|
||||
}
|
||||
|
||||
// LoadReactions loads comment reactions
|
||||
func (c *Comment) LoadReactions(repo *repo_model.Repository) error {
|
||||
return c.loadReactions(db.DefaultContext, repo)
|
||||
func (c *Comment) LoadReactions(ctx context.Context, repo *repo_model.Repository) error {
|
||||
return c.loadReactions(ctx, repo)
|
||||
}
|
||||
|
||||
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
|
||||
func (c *Comment) LoadReview() error {
|
||||
return c.loadReview(db.DefaultContext)
|
||||
func (c *Comment) LoadReview(ctx context.Context) error {
|
||||
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.
|
||||
@@ -719,13 +719,13 @@ func (c *Comment) UnsignedLine() uint64 {
|
||||
}
|
||||
|
||||
// CodeCommentLink returns the url to a comment in code
|
||||
func (c *Comment) CodeCommentLink() string {
|
||||
err := c.LoadIssue(db.DefaultContext)
|
||||
func (c *Comment) CodeCommentLink(ctx context.Context) string {
|
||||
err := c.LoadIssue(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
err = c.Issue.LoadRepo(db.DefaultContext)
|
||||
err = c.Issue.LoadRepo(ctx)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
@@ -1074,8 +1074,8 @@ func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList,
|
||||
}
|
||||
|
||||
// CountComments count all comments according options by ignoring pagination
|
||||
func CountComments(opts *FindCommentsOptions) (int64, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).Where(opts.ToConds())
|
||||
func CountComments(ctx context.Context, opts *FindCommentsOptions) (int64, error) {
|
||||
sess := db.GetEngine(ctx).Where(opts.ToConds())
|
||||
if opts.RepoID > 0 {
|
||||
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.
|
||||
func UpdateComment(c *Comment, doer *user_model.User) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func UpdateComment(ctx context.Context, c *Comment, doer *user_model.User) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
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
|
||||
func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("comment").
|
||||
func UpdateCommentsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(ctx).Table("comment").
|
||||
Where(builder.In("issue_id",
|
||||
builder.Select("issue.id").
|
||||
From("issue").
|
||||
@@ -1250,7 +1250,7 @@ func (c *Comment) HasOriginalAuthor() bool {
|
||||
}
|
||||
|
||||
// InsertIssueComments inserts many comments of issues.
|
||||
func InsertIssueComments(comments []*Comment) error {
|
||||
func InsertIssueComments(ctx context.Context, comments []*Comment) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -1260,7 +1260,7 @@ func InsertIssueComments(comments []*Comment) error {
|
||||
issueIDs.Add(comment.IssueID)
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -99,11 +99,11 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
|
||||
comments[n] = comment
|
||||
n++
|
||||
|
||||
if err := comment.LoadResolveDoer(); err != nil {
|
||||
if err := comment.LoadResolveDoer(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := comment.LoadReactions(issue.Repo); err != nil {
|
||||
if err := comment.LoadReactions(ctx, issue.Repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// CommentList defines a list of comments
|
||||
@@ -422,37 +423,18 @@ func (comments CommentList) loadReviews(ctx context.Context) error {
|
||||
|
||||
reviewIDs := comments.getReviewIDs()
|
||||
reviews := make(map[int64]*Review, len(reviewIDs))
|
||||
left := len(reviewIDs)
|
||||
for left > 0 {
|
||||
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:]
|
||||
if err := db.GetEngine(ctx).In("id", reviewIDs).Find(&reviews); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, comment := range comments {
|
||||
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.
|
||||
// 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},
|
||||
}
|
||||
|
||||
err := issues_model.InsertIssueComments([]*issues_model.Comment{comment})
|
||||
err := issues_model.InsertIssueComments(db.DefaultContext, []*issues_model.Comment{comment})
|
||||
assert.NoError(t, err)
|
||||
|
||||
issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
|
||||
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
|
||||
// update it based on highest index of existing issues assigned to a repo
|
||||
func RecalculateIssueIndexForRepo(repoID int64) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func RecalculateIssueIndexForRepo(ctx context.Context, repoID int64) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m
|
||||
return err
|
||||
}
|
||||
|
||||
issue.Labels = append(issue.Labels, label)
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadLabels(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, l := range labels {
|
||||
// Don't add already present labels and invalid labels
|
||||
if HasIssueLabel(ctx, issue.ID, l.ID) ||
|
||||
@@ -129,6 +136,10 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
|
||||
continue
|
||||
}
|
||||
|
||||
if err = RemoveDuplicateExclusiveIssueLabels(ctx, issue, l, doer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = newIssueLabel(ctx, issue, l, doer); err != nil {
|
||||
return fmt.Errorf("newIssueLabel: %w", err)
|
||||
}
|
||||
|
||||
28
models/issues/issue_label_test.go
Normal file
28
models/issues/issue_label_test.go
Normal file
@@ -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").
|
||||
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").
|
||||
From("review").
|
||||
Where(builder.And(
|
||||
builder.In("review.type", []ReviewType{ReviewTypeRequest, ReviewTypeReject, ReviewTypeApprove}),
|
||||
builder.Eq{"review.type": ReviewTypeRequest},
|
||||
builder.Or(
|
||||
builder.Eq{"review.reviewer_id": reviewRequestedID},
|
||||
builder.In("review.reviewer_team_id", existInTeamQuery),
|
||||
),
|
||||
builder.In("review.id", maxReview),
|
||||
))
|
||||
return sess.Where("issue.poster_id <> ?", reviewRequestedID).
|
||||
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.
|
||||
func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) {
|
||||
func GetIssueStats(ctx context.Context, opts *IssuesOptions) (*IssueStats, error) {
|
||||
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
|
||||
@@ -95,7 +95,7 @@ func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) {
|
||||
if 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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -112,10 +112,10 @@ func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) {
|
||||
return accum, nil
|
||||
}
|
||||
|
||||
func getIssueStatsChunk(opts *IssuesOptions, issueIDs []int64) (*IssueStats, error) {
|
||||
func getIssueStatsChunk(ctx context.Context, opts *IssuesOptions, issueIDs []int64) (*IssueStats, error) {
|
||||
stats := &IssueStats{}
|
||||
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
sess := db.GetEngine(ctx).
|
||||
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
|
||||
var err error
|
||||
|
||||
@@ -253,7 +253,7 @@ func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *is
|
||||
Title: title,
|
||||
Content: content,
|
||||
}
|
||||
err := issues_model.NewIssue(repo, &issue, nil, nil)
|
||||
err := issues_model.NewIssue(db.DefaultContext, repo, &issue, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
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,
|
||||
// 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},
|
||||
IssueIDs: ids,
|
||||
})
|
||||
@@ -403,7 +403,7 @@ func TestCountIssues(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 19, count)
|
||||
assert.EqualValues(t, 20, count)
|
||||
}
|
||||
|
||||
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.
|
||||
func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err error) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func ChangeIssueRef(ctx context.Context, issue *Issue, doer *user_model.User, oldRef string) (err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -215,8 +215,8 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *
|
||||
}
|
||||
|
||||
// UpdateIssueAttachments update attachments by UUIDs for the issue
|
||||
func UpdateIssueAttachments(issueID int64, uuids []string) (err error) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func UpdateIssueAttachments(ctx context.Context, issueID int64, uuids []string) (err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -235,8 +235,8 @@ func UpdateIssueAttachments(issueID int64, uuids []string) (err error) {
|
||||
}
|
||||
|
||||
// ChangeIssueContent changes issue content, as the given user.
|
||||
func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (err error) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User, content string) (err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
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.
|
||||
func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -432,8 +432,8 @@ func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_mo
|
||||
// UpdateIssueByAPI updates all allowed fields of given issue.
|
||||
// If the issue status is changed a statusChangeComment is returned
|
||||
// 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) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func UpdateIssueByAPI(ctx context.Context, issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
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.
|
||||
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 issue.DeadlineUnix == deadlineUnix {
|
||||
return nil
|
||||
}
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
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
|
||||
func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("issue").
|
||||
func UpdateIssuesMigrationsByType(ctx context.Context, gitServiceType api.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(ctx).Table("issue").
|
||||
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||
And("original_author_id = ?", originalAuthorID).
|
||||
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
|
||||
func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("reaction").
|
||||
func UpdateReactionsMigrationsByType(ctx context.Context, gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error {
|
||||
_, err := db.GetEngine(ctx).Table("reaction").
|
||||
Where("original_author_id = ?", originalAuthorID).
|
||||
And(migratedIssueCond(gitServiceType)).
|
||||
Update(map[string]any{
|
||||
@@ -696,85 +696,100 @@ func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, original
|
||||
|
||||
// DeleteIssuesByRepoID deletes issues by repositories id
|
||||
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)
|
||||
// Delete content histories
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&ContentHistory{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Delete comments and attachments
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&Comment{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
issueIDs := make([]int64, 0, db.DefaultMaxInSize)
|
||||
|
||||
// Dependencies for issues in this repository
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&IssueDependency{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := sess.Table(&Issue{}).Where("repo_id = ?", repoID).OrderBy("id").Limit(db.DefaultMaxInSize).Cols("id").Find(&issueIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Delete dependencies for issues in other repositories
|
||||
if _, err = sess.In("dependency_id", deleteCond).
|
||||
Delete(&IssueDependency{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(issueIDs) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&IssueUser{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Delete content histories
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&ContentHistory{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&Reaction{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Delete comments and attachments
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&Comment{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&IssueWatch{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Dependencies for issues in this repository
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&IssueDependency{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&Stopwatch{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Delete dependencies for issues in other repositories
|
||||
_, err = sess.In("dependency_id", issueIDs).Delete(&IssueDependency{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&TrackedTime{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&IssueUser{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&project_model.ProjectIssue{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&Reaction{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("dependent_issue_id", deleteCond).
|
||||
Delete(&Comment{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var attachments []*repo_model.Attachment
|
||||
if err = sess.In("issue_id", deleteCond).
|
||||
Find(&attachments); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for j := range attachments {
|
||||
attachmentPaths = append(attachmentPaths, attachments[j].RelativePath())
|
||||
}
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&TrackedTime{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&repo_model.Attachment{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = sess.In("issue_id", issueIDs).Delete(&project_model.ProjectIssue{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = db.DeleteByBean(ctx, &Issue{RepoID: repoID}); err != nil {
|
||||
return nil, err
|
||||
_, err = sess.In("dependent_issue_id", issueIDs).Delete(&Comment{})
|
||||
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
|
||||
@@ -809,7 +824,7 @@ func DeleteOrphanedIssues(ctx context.Context) error {
|
||||
|
||||
// Remove issue attachment files.
|
||||
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
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
type IssueUser struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UID int64 `xorm:"INDEX"` // User ID.
|
||||
IssueID int64
|
||||
IssueID int64 `xorm:"INDEX"`
|
||||
IsRead bool
|
||||
IsMentioned bool
|
||||
}
|
||||
|
||||
@@ -252,22 +252,22 @@ func (c *Comment) neuterCrossReferences(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil
|
||||
}
|
||||
c.RefComment, err = GetCommentByID(db.DefaultContext, c.RefCommentID)
|
||||
c.RefComment, err = GetCommentByID(ctx, c.RefCommentID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil
|
||||
}
|
||||
c.RefIssue, err = GetIssueByID(db.DefaultContext, c.RefIssueID)
|
||||
c.RefIssue, err = GetIssueByID(ctx, c.RefIssueID)
|
||||
if err == nil {
|
||||
err = c.RefIssue.LoadRepo(db.DefaultContext)
|
||||
err = c.RefIssue.LoadRepo(ctx)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -278,21 +278,21 @@ func CommentTypeIsRef(t CommentType) bool {
|
||||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
return ""
|
||||
}
|
||||
return c.RefComment.Link()
|
||||
return c.RefComment.Link(ctx)
|
||||
}
|
||||
|
||||
// RefIssueLink returns the relative URL of the issue where this reference was created
|
||||
func (c *Comment) RefIssueLink() string {
|
||||
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
|
||||
func (c *Comment) RefIssueLink(ctx context.Context) string {
|
||||
if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
||||
return ""
|
||||
}
|
||||
@@ -300,8 +300,8 @@ func (c *Comment) RefIssueLink() string {
|
||||
}
|
||||
|
||||
// RefIssueTitle returns the title of the issue where this reference was created
|
||||
func (c *Comment) RefIssueTitle() string {
|
||||
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
|
||||
func (c *Comment) RefIssueTitle(ctx context.Context) string {
|
||||
if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
||||
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
|
||||
func (c *Comment) RefIssueIdent() string {
|
||||
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
|
||||
func (c *Comment) RefIssueIdent(ctx context.Context) string {
|
||||
if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused:
|
||||
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
reviews, err := GetReviewsByIssueID(pr.Issue.ID)
|
||||
reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -71,11 +71,11 @@ type Reaction struct {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return r.User, nil
|
||||
}
|
||||
user, err := user_model.GetUserByID(db.DefaultContext, r.UserID)
|
||||
user, err := user_model.GetUserByID(ctx, r.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -141,16 +141,16 @@ func (opts *FindReactionsOptions) toConds() builder.Cond {
|
||||
}
|
||||
|
||||
// FindCommentReactions returns a ReactionList of all reactions from an comment
|
||||
func FindCommentReactions(issueID, commentID int64) (ReactionList, int64, error) {
|
||||
return FindReactions(db.DefaultContext, FindReactionsOptions{
|
||||
func FindCommentReactions(ctx context.Context, issueID, commentID int64) (ReactionList, int64, error) {
|
||||
return FindReactions(ctx, FindReactionsOptions{
|
||||
IssueID: issueID,
|
||||
CommentID: commentID,
|
||||
})
|
||||
}
|
||||
|
||||
// FindIssueReactions returns a ReactionList of all reactions from an issue
|
||||
func FindIssueReactions(issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) {
|
||||
return FindReactions(db.DefaultContext, FindReactionsOptions{
|
||||
func FindIssueReactions(ctx context.Context, issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) {
|
||||
return FindReactions(ctx, FindReactionsOptions{
|
||||
ListOptions: listOptions,
|
||||
IssueID: issueID,
|
||||
CommentID: -1,
|
||||
@@ -218,12 +218,12 @@ type ReactionOptions struct {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return nil, ErrForbiddenIssueReaction{opts.Type}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -241,8 +241,8 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
|
||||
}
|
||||
|
||||
// CreateIssueReaction creates a reaction on issue.
|
||||
func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, error) {
|
||||
return CreateReaction(&ReactionOptions{
|
||||
func CreateIssueReaction(ctx context.Context, doerID, issueID int64, content string) (*Reaction, error) {
|
||||
return CreateReaction(ctx, &ReactionOptions{
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
@@ -250,8 +250,8 @@ func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, erro
|
||||
}
|
||||
|
||||
// CreateCommentReaction creates a reaction on comment.
|
||||
func CreateCommentReaction(doerID, issueID, commentID int64, content string) (*Reaction, error) {
|
||||
return CreateReaction(&ReactionOptions{
|
||||
func CreateCommentReaction(ctx context.Context, doerID, issueID, commentID int64, content string) (*Reaction, error) {
|
||||
return CreateReaction(ctx, &ReactionOptions{
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
@@ -279,8 +279,8 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error {
|
||||
}
|
||||
|
||||
// DeleteIssueReaction deletes a reaction on issue.
|
||||
func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
||||
func DeleteIssueReaction(ctx context.Context, doerID, issueID int64, content string) error {
|
||||
return DeleteReaction(ctx, &ReactionOptions{
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
@@ -289,8 +289,8 @@ func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
||||
}
|
||||
|
||||
// DeleteCommentReaction deletes a reaction on comment.
|
||||
func DeleteCommentReaction(doerID, issueID, commentID int64, content string) error {
|
||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
||||
func DeleteCommentReaction(ctx context.Context, doerID, issueID, commentID int64, content string) error {
|
||||
return DeleteReaction(ctx, &ReactionOptions{
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
|
||||
@@ -20,9 +20,9 @@ func addReaction(t *testing.T, doerID, issueID, commentID int64, content string)
|
||||
var reaction *issues_model.Reaction
|
||||
var err error
|
||||
if commentID == 0 {
|
||||
reaction, err = issues_model.CreateIssueReaction(doerID, issueID, content)
|
||||
reaction, err = issues_model.CreateIssueReaction(db.DefaultContext, doerID, issueID, content)
|
||||
} 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.NotNil(t, reaction)
|
||||
@@ -49,7 +49,7 @@ func TestIssueAddDuplicateReaction(t *testing.T) {
|
||||
|
||||
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,
|
||||
IssueID: issue1ID,
|
||||
Type: "heart",
|
||||
@@ -70,7 +70,7 @@ func TestIssueDeleteReaction(t *testing.T) {
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
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)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -242,14 +242,21 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo
|
||||
return false, err
|
||||
}
|
||||
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)
|
||||
if official || err != nil {
|
||||
return official, err
|
||||
}
|
||||
official, err := git_model.IsUserOfficialReviewer(ctx, rule, reviewer)
|
||||
if official || err != nil {
|
||||
return official, err
|
||||
}
|
||||
|
||||
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
|
||||
func ReviewExists(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})
|
||||
func ReviewExists(ctx context.Context, issue *Issue, treePath string, line int64) (bool, error) {
|
||||
return db.GetEngine(ctx).Cols("id").Exist(&Comment{IssueID: issue.ID, TreePath: treePath, Line: line, Type: CommentTypeCode})
|
||||
}
|
||||
|
||||
// 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
|
||||
func SubmitReview(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)
|
||||
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(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -487,15 +494,15 @@ func GetTeamReviewerByIssueIDAndTeamID(ctx context.Context, issueID, teamID int6
|
||||
}
|
||||
|
||||
// MarkReviewsAsStale marks existing reviews as stale
|
||||
func MarkReviewsAsStale(issueID int64) (err error) {
|
||||
_, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `review` SET stale=? WHERE issue_id=?", true, issueID)
|
||||
func MarkReviewsAsStale(ctx context.Context, issueID int64) (err error) {
|
||||
_, err = db.GetEngine(ctx).Exec("UPDATE `review` SET stale=? WHERE issue_id=?", true, issueID)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// MarkReviewsAsNotStale marks existing reviews as not stale for a giving commit SHA
|
||||
func MarkReviewsAsNotStale(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)
|
||||
func MarkReviewsAsNotStale(ctx context.Context, issueID int64, commitID string) (err error) {
|
||||
_, err = db.GetEngine(ctx).Exec("UPDATE `review` SET stale=? WHERE issue_id=? AND commit_id=?", false, issueID, commitID)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -518,8 +525,8 @@ func DismissReview(ctx context.Context, review *Review, isDismiss bool) (err err
|
||||
}
|
||||
|
||||
// InsertReviews inserts review and review comments
|
||||
func InsertReviews(reviews []*Review) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func InsertReviews(ctx context.Context, reviews []*Review) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -578,7 +585,9 @@ func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_mo
|
||||
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 {
|
||||
return nil, err
|
||||
} 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
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
@@ -804,7 +813,7 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (
|
||||
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
|
||||
}
|
||||
} else {
|
||||
@@ -812,7 +821,7 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
// 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 {
|
||||
return false, fmt.Errorf("issue or doer is nil")
|
||||
}
|
||||
|
||||
if doer.ID != issue.PosterID {
|
||||
if err = issue.LoadRepo(db.DefaultContext); err != nil {
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
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 {
|
||||
return false, err
|
||||
}
|
||||
|
||||
permResult = p.CanAccess(perm.AccessModeWrite, unit.TypePullRequests)
|
||||
if !permResult {
|
||||
if permResult, err = IsOfficialReviewer(db.DefaultContext, issue, doer); err != nil {
|
||||
if permResult, err = IsOfficialReviewer(ctx, issue, doer); err != nil {
|
||||
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
|
||||
func DeleteReview(r *Review) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func DeleteReview(ctx context.Context, r *Review) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -903,7 +912,7 @@ func DeleteReview(r *Review) error {
|
||||
}
|
||||
|
||||
// GetCodeCommentsCount return count of CodeComments a Review has
|
||||
func (r *Review) GetCodeCommentsCount() int {
|
||||
func (r *Review) GetCodeCommentsCount(ctx context.Context) int {
|
||||
opts := FindCommentsOptions{
|
||||
Type: CommentTypeCode,
|
||||
IssueID: r.IssueID,
|
||||
@@ -914,7 +923,7 @@ func (r *Review) GetCodeCommentsCount() int {
|
||||
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 {
|
||||
return 0
|
||||
}
|
||||
@@ -922,18 +931,18 @@ func (r *Review) GetCodeCommentsCount() int {
|
||||
}
|
||||
|
||||
// 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{
|
||||
Type: CommentTypeReview,
|
||||
IssueID: r.IssueID,
|
||||
ReviewID: r.ID,
|
||||
}
|
||||
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 {
|
||||
return ""
|
||||
}
|
||||
return comment.HTMLURL()
|
||||
return comment.HTMLURL(ctx)
|
||||
}
|
||||
|
||||
// RemapExternalUser ExternalUserRemappable interface
|
||||
@@ -954,8 +963,8 @@ func (r *Review) GetExternalName() string { return r.OriginalAuthor }
|
||||
func (r *Review) GetExternalID() int64 { return r.OriginalAuthorID }
|
||||
|
||||
// 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 {
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("review").
|
||||
func UpdateReviewsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(ctx).Table("review").
|
||||
Where("original_author_id = ?", originalAuthorID).
|
||||
And(migratedIssueCond(tp)).
|
||||
Update(map[string]any{
|
||||
|
||||
@@ -126,16 +126,16 @@ func FindLatestReviews(ctx context.Context, opts FindReviewOptions) (ReviewList,
|
||||
}
|
||||
|
||||
// CountReviews returns count of reviews passing FindReviewOptions
|
||||
func CountReviews(opts FindReviewOptions) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{})
|
||||
func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{})
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
// 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).
|
||||
Find(&reviews); err != nil {
|
||||
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
|
||||
func GetReviewsByIssueID(issueID int64) (ReviewList, error) {
|
||||
func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
||||
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
|
||||
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,
|
||||
})
|
||||
|
||||
allReviews, err := issues_model.GetReviewsByIssueID(issue.ID)
|
||||
allReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
||||
assert.NoError(t, err)
|
||||
for _, review := range allReviews {
|
||||
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, allReviews.LoadReviewers(db.DefaultContext))
|
||||
if assert.Len(t, allReviews, 3) {
|
||||
@@ -248,7 +248,7 @@ func TestDeleteReview(t *testing.T) {
|
||||
})
|
||||
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)
|
||||
assert.Error(t, err)
|
||||
|
||||
@@ -26,4 +26,3 @@
|
||||
id: 5
|
||||
issue_id: 2
|
||||
label_id: 87
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
-
|
||||
id: 3
|
||||
repo_id: 0
|
||||
org_id: 3
|
||||
org_id: 3
|
||||
name: orglabel3
|
||||
color: '#abcdef'
|
||||
num_issues: 0
|
||||
|
||||
@@ -23,4 +23,3 @@
|
||||
id: 5
|
||||
repo_id: 3
|
||||
org_id: 0
|
||||
|
||||
|
||||
@@ -28,4 +28,3 @@
|
||||
attestation_type: 'fido-u2f'
|
||||
sign_count: 1
|
||||
clone_warning: false
|
||||
|
||||
|
||||
@@ -534,6 +534,12 @@ var migrations = []Migration{
|
||||
NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun),
|
||||
// v276 -> v277
|
||||
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
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
package v1_18 //nolint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm"
|
||||
@@ -22,42 +18,6 @@ type SystemSetting struct {
|
||||
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 {
|
||||
if err := x.Sync(new(SystemSetting)); err != nil {
|
||||
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)
|
||||
return x.Sync(new(SystemSetting))
|
||||
}
|
||||
|
||||
16
models/migrations/v1_21/v277.go
Normal file
16
models/migrations/v1_21/v277.go
Normal file
@@ -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))
|
||||
}
|
||||
16
models/migrations/v1_21/v278.go
Normal file
16
models/migrations/v1_21/v278.go
Normal file
@@ -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))
|
||||
}
|
||||
16
models/migrations/v1_21/v279.go
Normal file
16
models/migrations/v1_21/v279.go
Normal file
@@ -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.
|
||||
func SearchTeam(opts *SearchTeamOptions) (TeamList, int64, error) {
|
||||
sess := db.GetEngine(db.DefaultContext)
|
||||
func SearchTeam(ctx context.Context, opts *SearchTeamOptions) (TeamList, int64, error) {
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
opts.SetDefaultValues()
|
||||
cond := opts.toCond()
|
||||
|
||||
@@ -142,7 +142,7 @@ func TestGetTeamMembers(t *testing.T) {
|
||||
func TestGetUserTeams(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
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)
|
||||
for _, team := range teams {
|
||||
unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{TeamID: team.ID, UID: userID})
|
||||
|
||||
@@ -69,8 +69,8 @@ func (Board) TableName() string {
|
||||
}
|
||||
|
||||
// NumIssues return counter of all issues assigned to the board
|
||||
func (b *Board) NumIssues() int {
|
||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
||||
func (b *Board) NumIssues(ctx context.Context) int {
|
||||
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||
Where("project_id=?", b.ProjectID).
|
||||
And("project_board_id=?", b.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
|
||||
func NewBoard(board *Board) error {
|
||||
func NewBoard(ctx context.Context, board *Board) error {
|
||||
if len(board.Color) != 0 && !BoardColorPattern.MatchString(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
|
||||
}
|
||||
|
||||
// DeleteBoardByID removes all issues references to the project board.
|
||||
func DeleteBoardByID(boardID int64) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func DeleteBoardByID(ctx context.Context, boardID int64) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
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
|
||||
// if boardID is 0 unset default
|
||||
func SetDefaultBoard(projectID, boardID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Where(builder.Eq{
|
||||
func SetDefaultBoard(ctx context.Context, projectID, boardID int64) error {
|
||||
_, err := db.GetEngine(ctx).Where(builder.Eq{
|
||||
"project_id": projectID,
|
||||
"`default`": true,
|
||||
}).Cols("`default`").Update(&Board{Default: false})
|
||||
@@ -275,7 +275,7 @@ func SetDefaultBoard(projectID, boardID int64) error {
|
||||
}
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
@@ -283,9 +283,9 @@ func SetDefaultBoard(projectID, boardID int64) error {
|
||||
}
|
||||
|
||||
// UpdateBoardSorting update project board sorting
|
||||
func UpdateBoardSorting(bs BoardList) error {
|
||||
func UpdateBoardSorting(ctx context.Context, bs BoardList) error {
|
||||
for i := range bs {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(bs[i].ID).Cols(
|
||||
_, err := db.GetEngine(ctx).ID(bs[i].ID).Cols(
|
||||
"sorting",
|
||||
).Update(bs[i])
|
||||
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
|
||||
func (p *Project) NumIssues() int {
|
||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
||||
func (p *Project) NumIssues(ctx context.Context) int {
|
||||
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||
Where("project_id=?", p.ID).
|
||||
GroupBy("issue_id").
|
||||
Cols("issue_id").
|
||||
@@ -48,8 +48,8 @@ func (p *Project) NumIssues() int {
|
||||
}
|
||||
|
||||
// NumClosedIssues return counter of closed issues assigned to a project
|
||||
func (p *Project) NumClosedIssues() int {
|
||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
||||
func (p *Project) NumClosedIssues(ctx context.Context) int {
|
||||
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||
Join("INNER", "issue", "project_issue.issue_id=issue.id").
|
||||
Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, true).
|
||||
Cols("issue_id").
|
||||
@@ -62,8 +62,8 @@ func (p *Project) NumClosedIssues() int {
|
||||
}
|
||||
|
||||
// NumOpenIssues return counter of open issues assigned to a project
|
||||
func (p *Project) NumOpenIssues() int {
|
||||
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
|
||||
func (p *Project) NumOpenIssues(ctx context.Context) int {
|
||||
c, err := db.GetEngine(ctx).Table("project_issue").
|
||||
Join("INNER", "issue", "project_issue.issue_id=issue.id").
|
||||
Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false).
|
||||
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
|
||||
func MoveIssuesOnProjectBoard(board *Board, sortedIssueIDs map[int64]int64) error {
|
||||
return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||
func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64) error {
|
||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
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.
|
||||
func (p *Project) Link() string {
|
||||
func (p *Project) Link(ctx context.Context) string {
|
||||
if p.OwnerID > 0 {
|
||||
err := p.LoadOwner(db.DefaultContext)
|
||||
err := p.LoadOwner(ctx)
|
||||
if err != nil {
|
||||
log.Error("LoadOwner: %v", err)
|
||||
return ""
|
||||
@@ -134,7 +134,7 @@ func (p *Project) Link() string {
|
||||
return fmt.Sprintf("%s/-/projects/%d", p.Owner.HomeLink(), p.ID)
|
||||
}
|
||||
if p.RepoID > 0 {
|
||||
err := p.LoadRepo(db.DefaultContext)
|
||||
err := p.LoadRepo(ctx)
|
||||
if err != nil {
|
||||
log.Error("LoadRepo: %v", err)
|
||||
return ""
|
||||
@@ -261,7 +261,7 @@ func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, e
|
||||
}
|
||||
|
||||
// NewProject creates a new Project
|
||||
func NewProject(p *Project) error {
|
||||
func NewProject(ctx context.Context, p *Project) error {
|
||||
if !IsBoardTypeValid(p.BoardType) {
|
||||
p.BoardType = BoardTypeNone
|
||||
}
|
||||
@@ -274,7 +274,7 @@ func NewProject(p *Project) error {
|
||||
return util.NewInvalidArgumentErrorf("project type is not valid")
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -348,8 +348,8 @@ func updateRepositoryProjectCount(ctx context.Context, repoID int64) error {
|
||||
}
|
||||
|
||||
// ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed
|
||||
func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func ChangeProjectStatusByRepoIDAndID(ctx context.Context, repoID, projectID int64, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -372,8 +372,8 @@ func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) er
|
||||
}
|
||||
|
||||
// ChangeProjectStatus toggle a project between opened and closed
|
||||
func ChangeProjectStatus(p *Project, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func ChangeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func TestProject(t *testing.T) {
|
||||
CreatorID: 2,
|
||||
}
|
||||
|
||||
assert.NoError(t, NewProject(project))
|
||||
assert.NoError(t, NewProject(db.DefaultContext, project))
|
||||
|
||||
_, err := GetProjectByID(db.DefaultContext, project.ID)
|
||||
assert.NoError(t, err)
|
||||
@@ -74,7 +74,7 @@ func TestProject(t *testing.T) {
|
||||
|
||||
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
|
||||
projectFromDB, err = GetProjectByID(db.DefaultContext, project.ID)
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@@ -24,10 +23,7 @@ import (
|
||||
|
||||
// Init initialize model
|
||||
func Init(ctx context.Context) error {
|
||||
if err := unit.LoadUnitConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
return system_model.Init(ctx)
|
||||
return unit.LoadUnitConfig()
|
||||
}
|
||||
|
||||
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
|
||||
func CountCollaborators(repoID int64) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repoID).Count(&Collaboration{})
|
||||
func CountCollaborators(ctx context.Context, repoID int64) (int64, error) {
|
||||
return db.GetEngine(ctx).Where("repo_id = ? ", repoID).Count(&Collaboration{})
|
||||
}
|
||||
|
||||
// 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
|
||||
func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) {
|
||||
func IsOwnerMemberCollaborator(ctx context.Context, repo *Repository, userID int64) (bool, error) {
|
||||
if repo.OwnerID == userID {
|
||||
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").
|
||||
Where("team_repo.repo_id = ?", repo.ID).
|
||||
And("team_unit.`type` = ?", unit.TypeCode).
|
||||
@@ -154,5 +154,5 @@ func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) {
|
||||
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())
|
||||
|
||||
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.EqualValues(t, 2, count)
|
||||
|
||||
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.EqualValues(t, 2, count)
|
||||
|
||||
// Non-existent repository.
|
||||
count, err = repo_model.CountCollaborators(unittest.NonexistentID)
|
||||
count, err = repo_model.CountCollaborators(db.DefaultContext, unittest.NonexistentID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, count)
|
||||
}
|
||||
@@ -110,31 +110,31 @@ func TestRepository_IsOwnerMemberCollaborator(t *testing.T) {
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||
|
||||
// Organisation owner.
|
||||
actual, err := repo_model.IsOwnerMemberCollaborator(repo1, 2)
|
||||
actual, err := repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
|
||||
// Team member.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 4)
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
|
||||
// Normal user.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 1)
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, actual)
|
||||
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||
|
||||
// Collaborator.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo2, 4)
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo2, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
|
||||
|
||||
// Repository owner.
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(repo3, 2)
|
||||
actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo3, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, actual)
|
||||
}
|
||||
|
||||
@@ -47,12 +47,12 @@ func (m *Mirror) BeforeInsert() {
|
||||
}
|
||||
|
||||
// GetRepository returns the repository.
|
||||
func (m *Mirror) GetRepository() *Repository {
|
||||
func (m *Mirror) GetRepository(ctx context.Context) *Repository {
|
||||
if m.Repo != nil {
|
||||
return m.Repo
|
||||
}
|
||||
var err error
|
||||
m.Repo, err = GetRepositoryByID(db.DefaultContext, m.RepoID)
|
||||
m.Repo, err = GetRepositoryByID(ctx, m.RepoID)
|
||||
if err != nil {
|
||||
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
|
||||
func DeleteMirrorByRepoID(repoID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID})
|
||||
func DeleteMirrorByRepoID(ctx context.Context, repoID int64) error {
|
||||
_, err := db.GetEngine(ctx).Delete(&Mirror{RepoID: repoID})
|
||||
return err
|
||||
}
|
||||
|
||||
// MirrorsIterate iterates all mirror repositories.
|
||||
func MirrorsIterate(limit int, f func(idx int, bean any) error) error {
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
func MirrorsIterate(ctx context.Context, limit int, f func(idx int, bean any) error) error {
|
||||
sess := db.GetEngine(ctx).
|
||||
Where("next_update_unix<=?", time.Now().Unix()).
|
||||
And("next_update_unix!=0").
|
||||
OrderBy("updated_unix ASC")
|
||||
|
||||
@@ -181,9 +181,9 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs
|
||||
}
|
||||
|
||||
// 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)}
|
||||
has, err := db.GetEngine(db.DefaultContext).Get(rel)
|
||||
has, err := db.GetEngine(ctx).Get(rel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} 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.
|
||||
func CountReleasesByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(opts.toConds(repoID)).Count(new(Release))
|
||||
func CountReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toConds(repoID)).Count(new(Release))
|
||||
}
|
||||
|
||||
// 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().
|
||||
And(builder.Eq{"repo_id": repoID}).
|
||||
And(builder.Eq{"is_draft": false}).
|
||||
@@ -297,7 +297,7 @@ func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
|
||||
And(builder.Eq{"is_tag": false})
|
||||
|
||||
rel := new(Release)
|
||||
has, err := db.GetEngine(db.DefaultContext).
|
||||
has, err := db.GetEngine(ctx).
|
||||
Desc("created_unix", "id").
|
||||
Where(cond).
|
||||
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
|
||||
func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Table("release").
|
||||
func UpdateReleasesMigrationsByType(ctx context.Context, gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||
_, err := db.GetEngine(ctx).Table("release").
|
||||
Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||
And("original_author_id = ?", originalAuthorID).
|
||||
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
|
||||
func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
||||
rel, err := GetRelease(repo.ID, tagName)
|
||||
func PushUpdateDeleteTag(ctx context.Context, repo *Repository, tagName string) error {
|
||||
rel, err := GetRelease(ctx, repo.ID, tagName)
|
||||
if err != nil {
|
||||
if IsErrReleaseNotExist(err) {
|
||||
return nil
|
||||
@@ -494,14 +494,14 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
||||
return fmt.Errorf("GetRelease: %w", err)
|
||||
}
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
rel.IsDraft = true
|
||||
rel.NumCommits = 0
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -510,15 +510,15 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
||||
}
|
||||
|
||||
// SaveOrUpdateTag must be called for any push actions to add tag
|
||||
func SaveOrUpdateTag(repo *Repository, newRel *Release) error {
|
||||
rel, err := GetRelease(repo.ID, newRel.TagName)
|
||||
func SaveOrUpdateTag(ctx context.Context, repo *Repository, newRel *Release) error {
|
||||
rel, err := GetRelease(ctx, repo.ID, newRel.TagName)
|
||||
if err != nil && !IsErrReleaseNotExist(err) {
|
||||
return fmt.Errorf("GetRelease: %w", err)
|
||||
}
|
||||
|
||||
if rel == nil {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
@@ -529,7 +529,7 @@ func SaveOrUpdateTag(repo *Repository, newRel *Release) error {
|
||||
if rel.IsTag && newRel.PublisherID > 0 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -554,8 +554,8 @@ func (r *Release) GetExternalName() string { return r.OriginalAuthor }
|
||||
func (r *Release) GetExternalID() int64 { return r.OriginalAuthorID }
|
||||
|
||||
// InsertReleases migrates release
|
||||
func InsertReleases(rels ...*Release) error {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
func InsertReleases(ctx context.Context, rels ...*Release) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package repo
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -21,6 +22,6 @@ func TestMigrate_InsertReleases(t *testing.T) {
|
||||
Attachments: []*Attachment{a},
|
||||
}
|
||||
|
||||
err := InsertReleases(r)
|
||||
err := InsertReleases(db.DefaultContext, r)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -94,28 +94,28 @@ func CountNotices() int64 {
|
||||
}
|
||||
|
||||
// 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)
|
||||
return notices, db.GetEngine(db.DefaultContext).
|
||||
return notices, db.GetEngine(ctx).
|
||||
Limit(pageSize, (page-1)*pageSize).
|
||||
Desc("created_unix").
|
||||
Find(¬ices)
|
||||
}
|
||||
|
||||
// DeleteNotice deletes a system notice by given ID.
|
||||
func DeleteNotice(id int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(id).Delete(new(Notice))
|
||||
func DeleteNotice(ctx context.Context, id int64) error {
|
||||
_, err := db.GetEngine(ctx).ID(id).Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
_, err := db.GetEngine(db.DefaultContext).Exec("DELETE FROM notice")
|
||||
_, err := db.GetEngine(ctx).Exec("DELETE FROM notice")
|
||||
return err
|
||||
}
|
||||
|
||||
sess := db.GetEngine(db.DefaultContext).Where("id >= ?", start)
|
||||
sess := db.GetEngine(ctx).Where("id >= ?", start)
|
||||
if end > 0 {
|
||||
sess.And("id <= ?", end)
|
||||
}
|
||||
@@ -124,22 +124,22 @@ func DeleteNotices(start, end int64) error {
|
||||
}
|
||||
|
||||
// DeleteNoticesByIDs deletes notices by given IDs.
|
||||
func DeleteNoticesByIDs(ids []int64) error {
|
||||
func DeleteNoticesByIDs(ctx context.Context, ids []int64) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := db.GetEngine(db.DefaultContext).
|
||||
_, err := db.GetEngine(ctx).
|
||||
In("id", ids).
|
||||
Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -55,14 +55,14 @@ func TestCountNotices(t *testing.T) {
|
||||
func TestNotices(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
notices, err := system.Notices(1, 2)
|
||||
notices, err := system.Notices(db.DefaultContext, 1, 2)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, notices, 2) {
|
||||
assert.Equal(t, int64(3), notices[0].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)
|
||||
if assert.Len(t, notices, 1) {
|
||||
assert.Equal(t, int64(1), notices[0].ID)
|
||||
@@ -73,7 +73,7 @@ func TestDeleteNotice(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestDeleteNotices(t *testing.T) {
|
||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||
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: 2})
|
||||
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: 2})
|
||||
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: 2})
|
||||
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: 2})
|
||||
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.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
||||
|
||||
@@ -5,26 +5,21 @@ package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/cache"
|
||||
setting_module "code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting/config"
|
||||
"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 {
|
||||
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"`
|
||||
Version int `xorm:"version"` // prevent to override
|
||||
Version int `xorm:"version"`
|
||||
Created timeutil.TimeStamp `xorm:"created"`
|
||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||
}
|
||||
@@ -34,281 +29,119 @@ func (s *Setting) TableName() string {
|
||||
return "system_setting"
|
||||
}
|
||||
|
||||
func (s *Setting) GetValueBool() bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
b, _ := strconv.ParseBool(s.SettingValue)
|
||||
return b
|
||||
}
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(Setting))
|
||||
}
|
||||
|
||||
// ErrSettingIsNotExist represents an error that a setting is not exist with special key
|
||||
type ErrSettingIsNotExist struct {
|
||||
Key string
|
||||
}
|
||||
const keyRevision = "revision"
|
||||
|
||||
// Error implements error
|
||||
func (err ErrSettingIsNotExist) Error() string {
|
||||
return fmt.Sprintf("System setting[%s] is not exist", err.Key)
|
||||
}
|
||||
|
||||
// IsErrSettingIsNotExist return true if err is ErrSettingIsNotExist
|
||||
func IsErrSettingIsNotExist(err error) bool {
|
||||
_, ok := err.(ErrSettingIsNotExist)
|
||||
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
|
||||
func GetRevision(ctx context.Context) int {
|
||||
revision := &Setting{SettingKey: keyRevision}
|
||||
if has, err := db.GetByBean(ctx, revision); err != nil {
|
||||
return 0
|
||||
} else if !has {
|
||||
err = db.Insert(ctx, &Setting{SettingKey: keyRevision, Version: 1})
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
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 nil
|
||||
return revision.Version
|
||||
}
|
||||
|
||||
func upsertSettingValue(parentCtx context.Context, key, value string, version int) error {
|
||||
return db.WithTx(parentCtx, func(ctx context.Context) error {
|
||||
func GetAllSettings(ctx context.Context) (revision int, res map[string]string, err 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)
|
||||
|
||||
// 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)
|
||||
_, err := db.Exec(ctx, "UPDATE system_setting SET version=version+1 WHERE setting_key=?", keyRevision)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, _ := res.RowsAffected()
|
||||
if rows > 0 {
|
||||
// the existing row is updated, so we can return
|
||||
return nil
|
||||
for k, v := range settings {
|
||||
res, err := e.Exec("UPDATE system_setting SET setting_value=? WHERE setting_key=?", v, k)
|
||||
if err != 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
GravatarSourceURL *url.URL
|
||||
LibravatarService *libravatar.Libravatar
|
||||
)
|
||||
type dbConfigCachedGetter struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
func Init(ctx context.Context) error {
|
||||
disableGravatar, err := GetSettingBool(ctx, KeyPictureDisableGravatar, setting_module.GetDefaultDisableGravatar())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enableFederatedAvatar, err := GetSettingBool(ctx, KeyPictureEnableFederatedAvatar, setting_module.GetDefaultEnableFederatedAvatar(disableGravatar))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if setting_module.OfflineMode {
|
||||
if !disableGravatar {
|
||||
if err := SetSettingNoVersion(ctx, KeyPictureDisableGravatar, "true"); err != nil {
|
||||
return fmt.Errorf("failed to set setting %q: %w", KeyPictureDisableGravatar, err)
|
||||
}
|
||||
}
|
||||
disableGravatar = true
|
||||
|
||||
if enableFederatedAvatar {
|
||||
if err := SetSettingNoVersion(ctx, KeyPictureEnableFederatedAvatar, "false"); err != nil {
|
||||
return fmt.Errorf("failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err)
|
||||
}
|
||||
}
|
||||
enableFederatedAvatar = false
|
||||
}
|
||||
|
||||
if enableFederatedAvatar || !disableGravatar {
|
||||
var err error
|
||||
GravatarSourceURL, err = url.Parse(setting_module.GravatarSource)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse Gravatar URL(%s): %w", setting_module.GravatarSource, err)
|
||||
}
|
||||
}
|
||||
|
||||
if GravatarSourceURL != nil && enableFederatedAvatar {
|
||||
LibravatarService = libravatar.New()
|
||||
if GravatarSourceURL.Scheme == "https" {
|
||||
LibravatarService.SetUseHTTPS(true)
|
||||
LibravatarService.SetSecureFallbackHost(GravatarSourceURL.Host)
|
||||
} else {
|
||||
LibravatarService.SetUseHTTPS(false)
|
||||
LibravatarService.SetFallbackHost(GravatarSourceURL.Host)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
cacheTime time.Time
|
||||
revision int
|
||||
settings map[string]string
|
||||
}
|
||||
|
||||
var _ config.DynKeyGetter = (*dbConfigCachedGetter)(nil)
|
||||
|
||||
func (d *dbConfigCachedGetter) GetValue(ctx context.Context, key string) (v string, has bool) {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
v, has = d.settings[key]
|
||||
return v, has
|
||||
}
|
||||
|
||||
func (d *dbConfigCachedGetter) GetRevision(ctx context.Context) int {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
if time.Since(d.cacheTime) < time.Second {
|
||||
return d.revision
|
||||
}
|
||||
if GetRevision(ctx) != d.revision {
|
||||
d.mu.RUnlock()
|
||||
d.mu.Lock()
|
||||
rev, set, err := GetAllSettings(ctx)
|
||||
if err != nil {
|
||||
log.Error("Unable to get all settings: %v", err)
|
||||
} else {
|
||||
d.cacheTime = time.Now()
|
||||
d.revision = rev
|
||||
d.settings = set
|
||||
}
|
||||
d.mu.Unlock()
|
||||
d.mu.RLock()
|
||||
}
|
||||
return d.revision
|
||||
}
|
||||
|
||||
func (d *dbConfigCachedGetter) InvalidateCache() {
|
||||
d.mu.Lock()
|
||||
d.cacheTime = time.Time{}
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
func NewDatabaseDynKeyGetter() config.DynKeyGetter {
|
||||
return &dbConfigCachedGetter{}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@@ -15,43 +14,29 @@ import (
|
||||
)
|
||||
|
||||
func TestSettings(t *testing.T) {
|
||||
keyName := "server.LFS_LOCKS_PAGING_NUM"
|
||||
keyName := "test.key"
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
newSetting := &system.Setting{SettingKey: keyName, SettingValue: "50"}
|
||||
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &system.Setting{}))
|
||||
|
||||
// create setting
|
||||
err := system.SetSetting(db.DefaultContext, newSetting)
|
||||
assert.NoError(t, err)
|
||||
// test about saving unchanged values
|
||||
err = system.SetSetting(db.DefaultContext, newSetting)
|
||||
rev, settings, err := system.GetAllSettings(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, rev)
|
||||
assert.Len(t, settings, 1) // there is only one "revision" key
|
||||
|
||||
// get specific setting
|
||||
settings, err := system.GetSettings(db.DefaultContext, []string{keyName})
|
||||
err = system.SetSettings(db.DefaultContext, map[string]string{keyName: "true"})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, settings, 1)
|
||||
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)
|
||||
rev, settings, err = system.GetAllSettings(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, rev)
|
||||
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"
|
||||
|
||||
"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/base"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/setting/config"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
@@ -134,13 +135,11 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
|
||||
|
||||
setting.IncomingEmail.ReplyToAddress = "incoming+%{token}@localhost"
|
||||
|
||||
config.SetDynGetter(system.NewDatabaseDynKeyGetter())
|
||||
|
||||
if err = storage.Init(); err != nil {
|
||||
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 {
|
||||
fatalTestError("util.RemoveAll: %v\n", err)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models/avatars"
|
||||
"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/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -67,9 +66,7 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
|
||||
useLocalAvatar := false
|
||||
autoGenerateAvatar := false
|
||||
|
||||
disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar,
|
||||
setting.GetDefaultDisableGravatar(),
|
||||
)
|
||||
disableGravatar := setting.Config().Picture.DisableGravatar.Value(ctx)
|
||||
|
||||
switch {
|
||||
case u.UseCustomAvatar:
|
||||
|
||||
@@ -48,10 +48,10 @@ func init() {
|
||||
}
|
||||
|
||||
// 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)
|
||||
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
|
||||
} else if !has {
|
||||
return 0, ErrUserRedirectNotExist{Name: userName}
|
||||
|
||||
@@ -6,6 +6,7 @@ package user_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
||||
@@ -15,10 +16,10 @@ import (
|
||||
func TestLookupUserRedirect(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
userID, err := user_model.LookupUserRedirect("olduser1")
|
||||
userID, err := user_model.LookupUserRedirect(db.DefaultContext, "olduser1")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, userID)
|
||||
|
||||
_, err = user_model.LookupUserRedirect("doesnotexist")
|
||||
_, err = user_model.LookupUserRedirect(db.DefaultContext, "doesnotexist")
|
||||
assert.True(t, user_model.IsErrUserRedirectNotExist(err))
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func GetOrganizationByParams(ctx *Context) {
|
||||
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
|
||||
if err != nil {
|
||||
if organization.IsErrOrgNotExist(err) {
|
||||
redirectUserID, err := user_model.LookupUserRedirect(orgName)
|
||||
redirectUserID, err := user_model.LookupUserRedirect(ctx, orgName)
|
||||
if err == nil {
|
||||
RedirectToUser(ctx.Base, orgName, redirectUserID)
|
||||
} else if user_model.IsErrUserRedirectNotExist(err) {
|
||||
|
||||
@@ -456,7 +456,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
|
||||
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)
|
||||
} else if user_model.IsErrUserRedirectNotExist(err) {
|
||||
ctx.NotFound("GetUserByName", nil)
|
||||
@@ -773,6 +773,8 @@ const (
|
||||
RepoRefBlob
|
||||
)
|
||||
|
||||
const headRefName = "HEAD"
|
||||
|
||||
// RepoRef handles repository reference names when the ref name is not
|
||||
// explicitly given
|
||||
func RepoRef() func(*Context) context.CancelFunc {
|
||||
@@ -833,6 +835,14 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
|
||||
case RepoRefBranch:
|
||||
ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist)
|
||||
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
|
||||
return getRefNameFromPath(ctx, repo, path, func(s string) bool {
|
||||
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:], "/")
|
||||
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:
|
||||
_, err := repo.GitRepo.GetBlob(path)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
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"`)
|
||||
}
|
||||
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
|
||||
err = asymkey_model.RewriteAllPublicKeys()
|
||||
err = asymkey_model.RewriteAllPublicKeys(ctx)
|
||||
if err != nil {
|
||||
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", 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
|
||||
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
|
||||
genericOrphanCheck("Orphaned PullRequests without existing issue",
|
||||
"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
|
||||
genericOrphanCheck("Protected Branches without existing repository",
|
||||
"protected_branch", "repository", "protected_branch.repo_id=repository.id"),
|
||||
// find deleted branches without existing repository
|
||||
genericOrphanCheck("Deleted Branches without existing repository",
|
||||
"deleted_branch", "repository", "deleted_branch.repo_id=repository.id"),
|
||||
// find branches without existing repository
|
||||
genericOrphanCheck("Branches without existing repository",
|
||||
"branch", "repository", "branch.repo_id=repository.id"),
|
||||
// find LFS locks without existing repository
|
||||
genericOrphanCheck("LFS locks without existing repository",
|
||||
"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