mirror of https://gitee.com/answerdev/answer.git
Merge branch 'main' of git.backyard.segmentfault.com:opensource/answer
This commit is contained in:
commit
e4ca2bb925
|
@ -1,4 +1,8 @@
|
|||
# Contributing to answer
|
||||
## Coding and documentation Style
|
||||
|
||||
To be developed.
|
||||
|
||||
## Submitting Modifications
|
||||
|
||||
To be developed.
|
||||
|
|
54
INSTALL.md
54
INSTALL.md
|
@ -6,9 +6,9 @@ Before installing Answer, you need to install the base environment first.
|
|||
|
||||
You can then install Answer in several ways:
|
||||
|
||||
- Deploy with Docker
|
||||
- binary installation
|
||||
- Source installation
|
||||
- [Deploy with Docker](#Docker-compose-for-Answer)
|
||||
- [Binary installation](#Install-Answer-using-binary)
|
||||
- [Source installation](#Compile-the-image)
|
||||
|
||||
## Docker-compose for Answer
|
||||
```bash
|
||||
|
@ -17,15 +17,15 @@ $ wget https://raw.githubusercontent.com/answerdev/answer/main/docker-compose.ya
|
|||
$ docker-compose up
|
||||
```
|
||||
|
||||
browser open URL [http://127.0.0.1:9080/](http://127.0.0.1:9080/).
|
||||
In browser, open URL [http://127.0.0.1:9080/](http://127.0.0.1:9080/).
|
||||
|
||||
You can log in with the default administrator username( **`admin@admin.com`** ) and password( **`admin`** ).
|
||||
You can log in with the default administrator username (**`admin@admin.com`**) and password (**`admin`**).
|
||||
|
||||
## Docker for Answer
|
||||
Visit Docker Hub or GitHub Container registry to see all available images and tags.
|
||||
Visit [Docker Hub](https://hub.docker.com/r/answerdev/answer) or GitHub Container registry to see all available images and tags.
|
||||
|
||||
### Usage
|
||||
To keep your data out of Docker container, we do a volume (/var/data -> /data) here, and you can change it based on your situation.
|
||||
To persist data beyond the life of a Docker container, use a volume (/var/data -> /data). You can modify this based on your situation.
|
||||
|
||||
```
|
||||
# Pull image from Docker Hub.
|
||||
|
@ -35,9 +35,9 @@ $ docker pull answerdev/answer:latest
|
|||
$ mkdir -p /var/data
|
||||
|
||||
# Run the image first
|
||||
$ docker run --name=answer -p 9080:80 -v /var/data:/data answer/answer
|
||||
$ docker run --name=answer -p 9080:80 -v /var/data:/data answerdev/answer
|
||||
|
||||
# After the first startup, a configuration file will be generated in the /var/data directory
|
||||
# After successful first startup, a configuration file will be generated in the /var/data directory
|
||||
# /var/data/conf/config.yaml
|
||||
# Need to modify the Mysql database address in the configuration file
|
||||
vim /var/data/conf/config.yaml
|
||||
|
@ -46,34 +46,32 @@ vim /var/data/conf/config.yaml
|
|||
# connection: [username]:[password]@tcp([host]:[port])/[DbName]
|
||||
...
|
||||
|
||||
# After configuring the configuration file, you can start the mirror again to start the service
|
||||
# After configuring the configuration file, you can start the container again to start the service
|
||||
$ docker start answer
|
||||
```
|
||||
|
||||
## Binary for Answer
|
||||
## Install Answer using binary
|
||||
|
||||
1. Unzip the compressed package
|
||||
2. Use the command cd to enter the directory you just created
|
||||
3. Execute the command ./answer init
|
||||
4. Answer will generate a ./data directory in the current directory
|
||||
5. Enter the data directory and modify the config.yaml file
|
||||
6. Modify the database connection address to your database connection address
|
||||
|
||||
connection: [username]:[password]@tcp([host]:[port])/[DbName]
|
||||
7. Exit the data directory and execute ./answer run -c ./data/conf/config.yaml
|
||||
2. Use the command `cd` to enter the directory you just created
|
||||
3. Execute the command `./answer init`
|
||||
4. Answer will generate a `./data` directory in the current directory
|
||||
5. Enter the `data` directory and modify the `config.yaml` file
|
||||
6. Modify the database connection identify your database connection information
|
||||
`connection: [username]:[password]@tcp([host]:[port])/[DbName]`
|
||||
7. Use `cd ..` to return the directory from step 2, and execute `./answer run -c ./data/conf/config.yaml`
|
||||
|
||||
## Available Commands
|
||||
Usage: answer [command]
|
||||
Usage: `answer [command]`
|
||||
|
||||
- help: Help about any command
|
||||
- init: Init answer application
|
||||
- run: Run answer application
|
||||
- check: Check answer required environment
|
||||
- dump: Backup answer data
|
||||
- `help`: Help about any command
|
||||
- `init`: Init answer application
|
||||
- `run`: Run answer application
|
||||
- `check`: Check answer required environment
|
||||
- `dump`: Backup answer data
|
||||
|
||||
## config.yaml Description
|
||||
|
||||
Here is a sample/default config.yaml file, as would be created from `answer init`.
|
||||
```
|
||||
server:
|
||||
http:
|
||||
|
@ -97,9 +95,9 @@ service_config:
|
|||
```
|
||||
|
||||
## Compile the image
|
||||
If you have modified the source files and want to repackage the image, you can use the following statement to repackage the image
|
||||
If you have modified the source files and want to repackage the image, you can use the following to repackage the image
|
||||
```
|
||||
docker build -t answer:v1.0.0 .
|
||||
```
|
||||
## common problem
|
||||
1. The project cannot be started, answer the main program startup depends on the configuration file config.yaml, the internationalization translation directory/i18n, the upload file storage directory/upfiles, you need to ensure that the configuration file is loaded when the project starts, answer run -c config.yaml and the correct config.yaml The configuration items that specify the i18n and upfiles directories
|
||||
1. The project cannot be started: the main program startup depends on proper configuraiton of the configuration file, `config.yaml`, as well as the internationalization translation directory (`i18n`), and the upload file storage directory (`upfiles`). Ensure that the configuration file is loaded when the project starts, such as when using `answer run -c config.yaml` and that the `config.yaml` correctly specifies the i18n and upfiles directories.
|
||||
|
|
|
@ -35,7 +35,7 @@ $ docker pull answerdev/answer:latest
|
|||
$ mkdir -p /var/data
|
||||
|
||||
# 先运行一遍镜像
|
||||
$ docker run --name=answer -p 9080:80 -v /var/data:/data answer/answer
|
||||
$ docker run --name=answer -p 9080:80 -v /var/data:/data answerdev/answer
|
||||
|
||||
# 第一次启动后会在/var/data 目录下生成配置文件
|
||||
# /var/data/conf/config.yaml
|
||||
|
|
13
README.md
13
README.md
|
@ -4,13 +4,14 @@
|
|||
|
||||
# Answer - Build Q&A community
|
||||
|
||||
An open-source knowledge based community software. You can use it to quickly build your Q&A community for product technical support, customer support, user communication, and more.
|
||||
An open-source knowledge-based community software. You can use it to quickly build your Q&A community for product technical support, customer support, user communication, and more.
|
||||
|
||||
To learn more about the project, visit [answer.dev](https://answer.dev).
|
||||
|
||||
[![LICENSE](https://img.shields.io/badge/License-Apache-green)](https://github.com/answerdev/answer/blob/main/LICENSE)
|
||||
[![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/)
|
||||
[![Language](https://img.shields.io/badge/Language-React-blue.svg)](https://reactjs.org/)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/answerdev/answer)](https://goreportcard.com/report/github.com/answerdev/answer)
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
@ -18,15 +19,13 @@ To learn more about the project, visit [answer.dev](https://answer.dev).
|
|||
|
||||
## Quick start
|
||||
|
||||
### Running with docker-compose
|
||||
### Running with docker
|
||||
|
||||
```bash
|
||||
mkdir answer && cd answer
|
||||
wget https://raw.githubusercontent.com/answerdev/answer/main/docker-compose.yaml
|
||||
docker-compose up
|
||||
docker run -d -p 9080:80 -v $PWD/answer-data/data:/data --name answer answerdev/answer:latest
|
||||
```
|
||||
|
||||
For more information you can see [INSTALL.md](./INSTALL.md)
|
||||
For more information, see [INSTALL.md](./INSTALL.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -36,4 +35,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for ways to get started.
|
|||
|
||||
## License
|
||||
|
||||
[Apache](https://github.com/answerdev/answer/blob/main/LICENSE)
|
||||
[Apache License 2.0](https://github.com/answerdev/answer/blob/main/LICENSE)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[![LICENSE](https://img.shields.io/badge/License-Apache-green)](https://github.com/answerdev/answer/blob/main/LICENSE)
|
||||
[![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/)
|
||||
[![Language](https://img.shields.io/badge/Language-React-blue.svg)](https://reactjs.org/)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/answerdev/answer)](https://goreportcard.com/report/github.com/answerdev/answer)
|
||||
|
||||
## 截图
|
||||
|
||||
|
@ -18,12 +19,10 @@
|
|||
|
||||
## 快速开始
|
||||
|
||||
### 使用 docker-compose 快速搭建
|
||||
### 使用 docker 快速搭建
|
||||
|
||||
```bash
|
||||
mkdir answer && cd answer
|
||||
wget https://raw.githubusercontent.com/answerdev/answer/main/docker-compose.yaml
|
||||
docker-compose up
|
||||
docker run -d -p 9080:80 -v $PWD/answer-data/data:/data --name answer answerdev/answer:latest
|
||||
```
|
||||
|
||||
其他安装配置细节请参考 [INSTALL.md](./INSTALL.md)
|
||||
|
@ -36,4 +35,4 @@ docker-compose up
|
|||
|
||||
## License
|
||||
|
||||
[Apache](https://github.com/answerdev/answer/blob/main/LICENSE)
|
||||
[Apache License 2.0](https://github.com/answerdev/answer/blob/main/LICENSE)
|
||||
|
|
|
@ -48,7 +48,7 @@ To run answer, use:
|
|||
Use: "run",
|
||||
Short: "Run the application",
|
||||
Long: `Run the application`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
runApp()
|
||||
},
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ To run answer, use:
|
|||
Use: "init",
|
||||
Short: "init answer application",
|
||||
Long: `init answer application`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
cli.InstallAllInitialEnvironment(dataDirPath)
|
||||
c, err := readConfig()
|
||||
if err != nil {
|
||||
|
@ -79,7 +79,7 @@ To run answer, use:
|
|||
Use: "upgrade",
|
||||
Short: "upgrade Answer version",
|
||||
Long: `upgrade Answer version`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
c, err := readConfig()
|
||||
if err != nil {
|
||||
fmt.Println("read config failed: ", err.Error())
|
||||
|
@ -98,7 +98,7 @@ To run answer, use:
|
|||
Use: "dump",
|
||||
Short: "back up data",
|
||||
Long: `back up data`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
fmt.Println("Answer is backing up data")
|
||||
c, err := readConfig()
|
||||
if err != nil {
|
||||
|
@ -119,7 +119,7 @@ To run answer, use:
|
|||
Use: "check",
|
||||
Short: "checking the required environment",
|
||||
Long: `Check if the current environment meets the startup requirements`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
fmt.Println("Start checking the required environment...")
|
||||
if cli.CheckConfigFile(configFilePath) {
|
||||
fmt.Println("config file exists [✔]")
|
||||
|
|
|
@ -67,7 +67,7 @@ import (
|
|||
// Injectors from wire.go:
|
||||
|
||||
// initApplication init application.
|
||||
func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, cacheConf *data.CacheConf, i18nConf *translator.I18n, swaggerConf *router.SwaggerConfig, serviceConf *service_config.ServiceConfig, logConf log.Logger) (*pacman.Application, func(), error) {
|
||||
func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, cacheConf *data.CacheConf, i18nConf *translator.I18n, swaggerConf *router.SwaggerConfig, serviceConf *service_config.ServiceConfig, _ log.Logger) (*pacman.Application, func(), error) {
|
||||
staticRouter := router.NewStaticRouter(serviceConf)
|
||||
i18nTranslator, err := translator.NewTranslator(i18nConf)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,8 +3,8 @@ server:
|
|||
addr: 0.0.0.0:80
|
||||
data:
|
||||
database:
|
||||
driver: "mysql"
|
||||
connection: root:root@tcp(db:3306)/answer
|
||||
driver: "sqlite3"
|
||||
connection: "/data/sqlite3/answer.db"
|
||||
cache:
|
||||
file_path: "/data/cache/cache.db"
|
||||
i18n:
|
||||
|
|
23
docs/docs.go
23
docs/docs.go
|
@ -56,6 +56,12 @@ const docTemplate = `{
|
|||
"description": "user status",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "answer id or question title",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
@ -173,6 +179,12 @@ const docTemplate = `{
|
|||
"description": "user status",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "question id or title",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
@ -709,19 +721,12 @@ const docTemplate = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "username",
|
||||
"name": "username",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "email",
|
||||
"name": "e_mail",
|
||||
"description": "search query: email, username or id:[id]",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"normal",
|
||||
"suspended",
|
||||
"deleted",
|
||||
"inactive"
|
||||
|
|
|
@ -44,6 +44,12 @@
|
|||
"description": "user status",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "answer id or question title",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
@ -161,6 +167,12 @@
|
|||
"description": "user status",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "question id or title",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
@ -697,19 +709,12 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "username",
|
||||
"name": "username",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "email",
|
||||
"name": "e_mail",
|
||||
"description": "search query: email, username or id:[id]",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"normal",
|
||||
"suspended",
|
||||
"deleted",
|
||||
"inactive"
|
||||
|
|
|
@ -1390,6 +1390,10 @@ paths:
|
|||
in: query
|
||||
name: status
|
||||
type: string
|
||||
- description: answer id or question title
|
||||
in: query
|
||||
name: query
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -1463,6 +1467,10 @@ paths:
|
|||
in: query
|
||||
name: status
|
||||
type: string
|
||||
- description: question id or title
|
||||
in: query
|
||||
name: query
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -1788,17 +1796,12 @@ paths:
|
|||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: username
|
||||
- description: 'search query: email, username or id:[id]'
|
||||
in: query
|
||||
name: username
|
||||
type: string
|
||||
- description: email
|
||||
in: query
|
||||
name: e_mail
|
||||
name: query
|
||||
type: string
|
||||
- description: user status
|
||||
enum:
|
||||
- normal
|
||||
- suspended
|
||||
- deleted
|
||||
- inactive
|
||||
|
|
38
go.mod
38
go.mod
|
@ -17,22 +17,22 @@ require (
|
|||
github.com/google/wire v0.5.0
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/jinzhu/now v1.1.5
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/mattn/go-sqlite3 v1.14.15
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/mojocn/base64Captcha v1.3.5
|
||||
github.com/segmentfault/pacman v1.0.1
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220929065758-260b3093a347
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20221018072427-a15dd1434e05
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20221018072427-a15dd1434e05
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20221018072427-a15dd1434e05
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20221018072427-a15dd1434e05
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20221018072427-a15dd1434e05
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a
|
||||
github.com/swaggo/gin-swagger v1.5.3
|
||||
github.com/swaggo/swag v1.8.6
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||
github.com/swaggo/swag v1.8.7
|
||||
golang.org/x/crypto v0.1.0
|
||||
golang.org/x/net v0.1.0
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
xorm.io/builder v0.3.12
|
||||
xorm.io/core v0.7.3
|
||||
|
@ -41,9 +41,9 @@ require (
|
|||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
|
@ -52,7 +52,7 @@ require (
|
|||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
|
@ -81,10 +81,10 @@ require (
|
|||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/image v0.1.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/tools v0.2.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
|
48
go.sum
48
go.sum
|
@ -64,6 +64,8 @@ github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267 h1:vDHsaEcs/Q0dw
|
|||
github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267/go.mod h1:Yj3yPP/vi87JjwylUTCMyd6FrOfGqP1AHk0305hDm2o=
|
||||
github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
|
@ -131,6 +133,8 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3
|
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
||||
|
@ -298,6 +302,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
|||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
|
@ -397,6 +403,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
|
@ -426,6 +434,8 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO
|
|||
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
|
@ -539,14 +549,24 @@ github.com/segmentfault/pacman v1.0.1 h1:GFdvPtNxvVVjnDM4ty02D/+4unHwG9PmjcOZSc2
|
|||
github.com/segmentfault/pacman v1.0.1/go.mod h1:5lNp5REd8QMThmBUvR3Fi9Y3AsOB4GRq7soCB4QLqOs=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220929065758-260b3093a347 h1:0xWBBXHHuemzMY61KYJXh7F5FW/4K8g98RYKNXodTCc=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220929065758-260b3093a347/go.mod h1:rmf1TCwz67dyM+AmTwSd1BxTo2AOYHj262lP93bOZbs=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20221018072427-a15dd1434e05 h1:rXsXgC/HR7m4V425l9pDBW/qxJv6zCh6pEvvO1ZCNsI=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20221018072427-a15dd1434e05/go.mod h1:rmf1TCwz67dyM+AmTwSd1BxTo2AOYHj262lP93bOZbs=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220929065758-260b3093a347 h1:WpnEbmZFE8FYIgvseX+NJtDgGJlM1KSaKJhoxJywUgo=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220929065758-260b3093a347/go.mod h1:prPjFam7MyZ5b3S9dcDOt2tMPz6kf7C9c243s9zSwPY=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20221018072427-a15dd1434e05 h1:BlqTgc3/MYKG6vMI2MI+6o+7P4Gy5PXlawu185wPXAk=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20221018072427-a15dd1434e05/go.mod h1:prPjFam7MyZ5b3S9dcDOt2tMPz6kf7C9c243s9zSwPY=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220929065758-260b3093a347 h1:Q29Ky9ZUGhdLIygfX6jwPYeEa7Wqn8o3f1NJWb8LvvE=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220929065758-260b3093a347/go.mod h1:5Afm+OQdau/HQqSOp/ALlSUp0vZsMMMbv//kJhxuoi8=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20221018072427-a15dd1434e05 h1:gFCY9KUxhYg+/MXNcDYl4ILK+R1SG78FtaSR3JqZNYY=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20221018072427-a15dd1434e05/go.mod h1:5Afm+OQdau/HQqSOp/ALlSUp0vZsMMMbv//kJhxuoi8=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220929065758-260b3093a347 h1:7Adjc296AKv32dg88S0T8t9K3+N+PFYLSCctpPnCUr0=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220929065758-260b3093a347/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20221018072427-a15dd1434e05 h1:jcGZU2juv0L3eFEkuZYV14ESLUlWfGMWnP0mjOfrSZc=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20221018072427-a15dd1434e05/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220929065758-260b3093a347 h1:CfuRhTPK2CBQIZruq5ceuTVthspe8U1FDjWXXI2RWdo=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220929065758-260b3093a347/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20221018072427-a15dd1434e05 h1:91is1nKNbfTOl8CvMYiFgg4c5Vmol+5mVmMV/jDXD+A=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20221018072427-a15dd1434e05/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
|
@ -565,6 +585,8 @@ github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155
|
|||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
|
@ -579,6 +601,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
@ -588,6 +611,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a h1:kAe4YSu0O0UFn1DowNo2MY5p6xzqtJ/wQ7LZynSvGaY=
|
||||
|
@ -597,10 +622,13 @@ github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89
|
|||
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
|
||||
github.com/swaggo/swag v1.8.6 h1:2rgOaLbonWu1PLP6G+/rYjSvPg0jQE0HtrEKuE380eg=
|
||||
github.com/swaggo/swag v1.8.6/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg=
|
||||
github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU=
|
||||
github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
|
@ -614,6 +642,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
|
@ -663,10 +692,13 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
|
|||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -683,6 +715,8 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
|
|||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
|
||||
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -706,6 +740,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -749,8 +784,11 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1
|
|||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -771,6 +809,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -830,9 +869,14 @@ golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -845,6 +889,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -909,6 +955,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
base:
|
||||
success:
|
||||
other: "Successo"
|
||||
unknown:
|
||||
other: "Errore sconosciuto"
|
||||
request_format_error:
|
||||
other: "Il formato della richiesta non è valido"
|
||||
unauthorized_error:
|
||||
other: "Non autorizzato"
|
||||
database_error:
|
||||
other: "Errore server dati"
|
||||
|
||||
email:
|
||||
other: "email"
|
||||
password:
|
||||
other: "password"
|
||||
|
||||
email_or_password_wrong_error: &email_or_password_wrong
|
||||
other: "Email o password errati"
|
||||
|
||||
error:
|
||||
admin:
|
||||
email_or_password_wrong: *email_or_password_wrong
|
||||
answer:
|
||||
not_found:
|
||||
other: "Risposta non trovata"
|
||||
comment:
|
||||
edit_without_permission:
|
||||
other: "Non si hanno di privilegi sufficienti per modificare il commento"
|
||||
not_found:
|
||||
other: "Commento non trovato"
|
||||
email:
|
||||
duplicate:
|
||||
other: "email già esistente"
|
||||
need_to_be_verified:
|
||||
other: "email deve essere verificata"
|
||||
verify_url_expired:
|
||||
other: "l'url di verifica email è scaduto, si prega di reinviare la email"
|
||||
lang:
|
||||
not_found:
|
||||
other: "lingua non trovata"
|
||||
object:
|
||||
captcha_verification_failed:
|
||||
other: "captcha errato"
|
||||
disallow_follow:
|
||||
other: "Non sei autorizzato a seguire"
|
||||
disallow_vote:
|
||||
other: "non sei autorizzato a votare"
|
||||
disallow_vote_your_self:
|
||||
other: "Non puoi votare un tuo post!"
|
||||
not_found:
|
||||
other: "oggetto non trovato"
|
||||
verification_failed:
|
||||
other: "verifica fallita"
|
||||
email_or_password_incorrect:
|
||||
other: "email o password incorretti"
|
||||
old_password_verification_failed:
|
||||
other: "la verifica della vecchia password è fallita"
|
||||
new_password_same_as_previous_setting:
|
||||
other: "La nuova password è identica alla precedente"
|
||||
question:
|
||||
not_found:
|
||||
other: "domanda non trovata"
|
||||
rank:
|
||||
fail_to_meet_the_condition:
|
||||
other: "Condizioni non valide per il grado"
|
||||
report:
|
||||
handle_failed:
|
||||
other: "Gestione del report fallita"
|
||||
not_found:
|
||||
other: "Report non trovato"
|
||||
tag:
|
||||
not_found:
|
||||
other: "Etichetta non trovata"
|
||||
theme:
|
||||
not_found:
|
||||
other: "tema non trovato"
|
||||
user:
|
||||
email_or_password_wrong:
|
||||
other: *email_or_password_wrong
|
||||
not_found:
|
||||
other: "utente non trovato"
|
||||
suspended:
|
||||
other: "utente sospeso"
|
||||
username_invalid:
|
||||
other: "utente non valido"
|
||||
username_duplicate:
|
||||
other: "utente già in uso"
|
||||
|
||||
report:
|
||||
spam:
|
||||
name:
|
||||
other: "spam"
|
||||
description:
|
||||
other: "Questo articolo è una pubblicità o vandalismo. Non è utile o rilevante all'argomento corrente"
|
||||
rude:
|
||||
name:
|
||||
other: "scortese o violento"
|
||||
description:
|
||||
other: "Una persona ragionevole trova questo contenuto inappropriato a un discorso rispettoso"
|
||||
duplicate:
|
||||
name:
|
||||
other: "duplicato"
|
||||
description:
|
||||
other: "Questa domanda è già stata posta e ha già una risposta."
|
||||
not_answer:
|
||||
name:
|
||||
other: "non è una risposta"
|
||||
description:
|
||||
other: "Questo è stato postato come una risposta, ma non sta cercando di rispondere alla domanda. Dovrebbe essere una modifica, un commento, un'altra domanda o cancellato del tutto."
|
||||
not_need:
|
||||
name:
|
||||
other: "non più necessario"
|
||||
description:
|
||||
other: "Questo commento è datato, conversazionale o non rilevante a questo articolo."
|
||||
other:
|
||||
name:
|
||||
other: "altro"
|
||||
description:
|
||||
other: "Questo articolo richiede una supervisione dello staff per altre ragioni non listate sopra."
|
||||
|
||||
question:
|
||||
close:
|
||||
duplicate:
|
||||
name:
|
||||
other: "spam"
|
||||
description:
|
||||
other: "Questa domanda è già stata chiesta o ha già una risposta."
|
||||
guideline:
|
||||
name:
|
||||
other: "motivo legato alla community"
|
||||
description:
|
||||
other: "Questa domanda non soddisfa le linee guida della comunità."
|
||||
multiple:
|
||||
name:
|
||||
other: "richiede maggiori dettagli o chiarezza"
|
||||
description:
|
||||
other: "Questa domanda attualmente contiene più domande. Deve concentrarsi solamente su un unico problema."
|
||||
other:
|
||||
name:
|
||||
other: "altro"
|
||||
description:
|
||||
other: "Questo articolo richiede un'altro motivo non listato sopra."
|
||||
|
||||
notification:
|
||||
action:
|
||||
update_question:
|
||||
other: "domanda aggiornata"
|
||||
answer_the_question:
|
||||
other: "domanda risposta"
|
||||
update_answer:
|
||||
other: "risposta aggiornata"
|
||||
adopt_answer:
|
||||
other: "risposta accettata"
|
||||
comment_question:
|
||||
other: "domanda commentata"
|
||||
comment_answer:
|
||||
other: "risposta commentata"
|
||||
reply_to_you:
|
||||
other: "hai ricevuto risposta"
|
||||
mention_you:
|
||||
other: "sei stato menzionato"
|
||||
your_question_is_closed:
|
||||
other: "la tua domanda è stata chiusa"
|
||||
your_question_was_deleted:
|
||||
other: "la tua domanda è stata rimossa"
|
||||
your_answer_was_deleted:
|
||||
other: "la tua risposta è stata rimossa"
|
||||
your_comment_was_deleted:
|
||||
other: "il tuo commento è stato rimosso"
|
|
@ -3,7 +3,7 @@ package constant
|
|||
import "time"
|
||||
|
||||
const (
|
||||
Default_PageSize = 20 //Default number of pages
|
||||
DefaultPageSize = 20 // Default number of pages
|
||||
UserStatusChangedCacheKey = "answer:user:status:"
|
||||
UserStatusChangedCacheTime = 7 * 24 * time.Hour
|
||||
UserTokenCacheKey = "answer:user:token:"
|
||||
|
|
|
@ -13,7 +13,7 @@ const (
|
|||
ReportNotAnswerDescription = "report.not_answer.description"
|
||||
ReportNotNeedName = "report.not_need.name"
|
||||
ReportNotNeedDescription = "report.not_need.description"
|
||||
//question close
|
||||
// question close
|
||||
QuestionCloseDuplicateName = "question.close.duplicate.name"
|
||||
QuestionCloseDuplicateDescription = "question.close.duplicate.description"
|
||||
QuestionCloseGuidelineName = "question.close.guideline.name"
|
||||
|
@ -27,8 +27,8 @@ const (
|
|||
const (
|
||||
// TODO put this in database
|
||||
// TODO need reason controller to resolve
|
||||
QuestionCloseJson = `[{"name":"question.close.duplicate.name","description":"question.close.duplicate.description","source":"question","type":1,"have_content":false,"content_type":""},{"name":"question.close.guideline.name","description":"question.close.guideline.description","source":"question","type":2,"have_content":false,"content_type":""},{"name":"question.close.multiple.name","description":"question.close.multiple.description","source":"question","type":3,"have_content":true,"content_type":"text"},{"name":"question.close.other.name","description":"question.close.other.description","source":"question","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
QuestionReportJson = `[{"name":"report.spam.name","description":"report.spam.description","source":"question","type":1,"have_content":false,"content_type":""},{"name":"report.rude.name","description":"report.rude.description","source":"question","type":2,"have_content":false,"content_type":""},{"name":"report.duplicate.name","description":"report.duplicate.description","source":"question","type":3,"have_content":true,"content_type":"text"},{"name":"report.other.name","description":"report.other.description","source":"question","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
AnswerReportJson = `[{"name":"report.spam.name","description":"report.spam.description","source":"answer","type":1,"have_content":false,"content_type":""},{"name":"report.rude.name","description":"report.rude.description","source":"answer","type":2,"have_content":false,"content_type":""},{"name":"report.not_answer.name","description":"report.not_answer.description","source":"answer","type":3,"have_content":false,"content_type":""},{"name":"report.other.name","description":"report.other.description","source":"answer","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
CommentReportJson = `[{"name":"report.spam.name","description":"report.spam.description","source":"comment","type":1,"have_content":false,"content_type":""},{"name":"report.rude.name","description":"report.rude.description","source":"comment","type":2,"have_content":false,"content_type":""},{"name":"report.not_need.name","description":"report.not_need.description","source":"comment","type":3,"have_content":true,"content_type":"text"},{"name":"report.other.name","description":"report.other.description","source":"comment","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
QuestionCloseJSON = `[{"name":"question.close.duplicate.name","description":"question.close.duplicate.description","source":"question","type":1,"have_content":false,"content_type":""},{"name":"question.close.guideline.name","description":"question.close.guideline.description","source":"question","type":2,"have_content":false,"content_type":""},{"name":"question.close.multiple.name","description":"question.close.multiple.description","source":"question","type":3,"have_content":true,"content_type":"text"},{"name":"question.close.other.name","description":"question.close.other.description","source":"question","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
QuestionReportJSON = `[{"name":"report.spam.name","description":"report.spam.description","source":"question","type":1,"have_content":false,"content_type":""},{"name":"report.rude.name","description":"report.rude.description","source":"question","type":2,"have_content":false,"content_type":""},{"name":"report.duplicate.name","description":"report.duplicate.description","source":"question","type":3,"have_content":true,"content_type":"text"},{"name":"report.other.name","description":"report.other.description","source":"question","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
AnswerReportJSON = `[{"name":"report.spam.name","description":"report.spam.description","source":"answer","type":1,"have_content":false,"content_type":""},{"name":"report.rude.name","description":"report.rude.description","source":"answer","type":2,"have_content":false,"content_type":""},{"name":"report.not_answer.name","description":"report.not_answer.description","source":"answer","type":3,"have_content":false,"content_type":""},{"name":"report.other.name","description":"report.other.description","source":"answer","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
CommentReportJSON = `[{"name":"report.spam.name","description":"report.spam.description","source":"comment","type":1,"have_content":false,"content_type":""},{"name":"report.rude.name","description":"report.rude.description","source":"comment","type":2,"have_content":false,"content_type":""},{"name":"report.not_need.name","description":"report.not_need.description","source":"comment","type":3,"have_content":true,"content_type":"text"},{"name":"report.other.name","description":"report.other.description","source":"comment","type":4,"have_content":true,"content_type":"textarea"}]`
|
||||
)
|
||||
|
|
|
@ -37,6 +37,13 @@ func NewDB(debug bool, dataConf *Database) (*xorm.Engine, error) {
|
|||
if dataConf.Driver == "" {
|
||||
dataConf.Driver = string(schemas.MYSQL)
|
||||
}
|
||||
if dataConf.Driver == string(schemas.SQLITE) {
|
||||
dbFileDir := filepath.Dir(dataConf.Connection)
|
||||
log.Debugf("try to create database directory %s", dbFileDir)
|
||||
if err := dir.CreateDirIfNotExist(dbFileDir); err != nil {
|
||||
log.Errorf("create database dir failed: %s", err)
|
||||
}
|
||||
}
|
||||
engine, err := xorm.NewEngine(dataConf.Driver, dataConf.Connection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -40,7 +40,6 @@ func HandleResponse(ctx *gin.Context, err error, data interface{}) {
|
|||
respBody.Data = data
|
||||
}
|
||||
ctx.JSON(myErr.Code, respBody)
|
||||
return
|
||||
}
|
||||
|
||||
// BindAndCheck bind request and check
|
||||
|
|
|
@ -14,9 +14,7 @@ import (
|
|||
"github.com/segmentfault/pacman/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ctxUuidKey = "ctxUuidKey"
|
||||
)
|
||||
var ctxUUIDKey = "ctxUuidKey"
|
||||
|
||||
// AuthUserMiddleware auth user middleware
|
||||
type AuthUserMiddleware struct {
|
||||
|
@ -44,7 +42,7 @@ func (am *AuthUserMiddleware) Auth() gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
if userInfo != nil {
|
||||
ctx.Set(ctxUuidKey, userInfo)
|
||||
ctx.Set(ctxUUIDKey, userInfo)
|
||||
}
|
||||
ctx.Next()
|
||||
}
|
||||
|
@ -82,7 +80,7 @@ func (am *AuthUserMiddleware) MustAuth() gin.HandlerFunc {
|
|||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
ctx.Set(ctxUuidKey, userInfo)
|
||||
ctx.Set(ctxUUIDKey, userInfo)
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +105,7 @@ func (am *AuthUserMiddleware) CmsAuth() gin.HandlerFunc {
|
|||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
ctx.Set(ctxUuidKey, userInfo)
|
||||
ctx.Set(ctxUUIDKey, userInfo)
|
||||
}
|
||||
ctx.Next()
|
||||
}
|
||||
|
@ -115,7 +113,7 @@ func (am *AuthUserMiddleware) CmsAuth() gin.HandlerFunc {
|
|||
|
||||
// GetLoginUserIDFromContext get user id from context
|
||||
func GetLoginUserIDFromContext(ctx *gin.Context) (userID string) {
|
||||
userInfo, exist := ctx.Get(ctxUuidKey)
|
||||
userInfo, exist := ctx.Get(ctxUUIDKey)
|
||||
if !exist {
|
||||
return ""
|
||||
}
|
||||
|
@ -128,7 +126,7 @@ func GetLoginUserIDFromContext(ctx *gin.Context) (userID string) {
|
|||
|
||||
// GetUserInfoFromContext get user info from context
|
||||
func GetUserInfoFromContext(ctx *gin.Context) (u *entity.UserCacheInfo) {
|
||||
userInfo, exist := ctx.Get(ctxUuidKey)
|
||||
userInfo, exist := ctx.Get(ctxUUIDKey)
|
||||
if !exist {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ const (
|
|||
UsernameDuplicate = "error.user.username_duplicate"
|
||||
UserSetAvatar = "error.user.set_avatar"
|
||||
EmailDuplicate = "error.email.duplicate"
|
||||
EmailVerifyUrlExpired = "error.email.verify_url_expired"
|
||||
EmailVerifyURLExpired = "error.email.verify_url_expired"
|
||||
EmailNeedToBeVerified = "error.email.need_to_be_verified"
|
||||
UserSuspended = "error.user.suspended"
|
||||
ObjectNotFound = "error.object.not_found"
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/go-playground/locales"
|
||||
english "github.com/go-playground/locales/en"
|
||||
zhongwen "github.com/go-playground/locales/zh"
|
||||
"github.com/go-playground/universal-translator"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/go-playground/validator/v10/translations/en"
|
||||
"github.com/go-playground/validator/v10/translations/zh"
|
||||
|
@ -31,10 +31,8 @@ type ErrorField struct {
|
|||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
var (
|
||||
// GlobalValidatorMapping is a mapping from validator to translator used
|
||||
GlobalValidatorMapping = make(map[string]*MyValidator, 0)
|
||||
)
|
||||
// GlobalValidatorMapping is a mapping from validator to translator used
|
||||
var GlobalValidatorMapping = make(map[string]*MyValidator, 0)
|
||||
|
||||
func init() {
|
||||
zhTran, zhVal := getTran(zhongwen.New(), i18n.LanguageChinese.Abbr()), createDefaultValidator(i18n.LanguageChinese)
|
||||
|
|
|
@ -31,7 +31,6 @@ func InstallAllInitialEnvironment(dataDirPath string) {
|
|||
installUploadDir()
|
||||
installI18nBundle()
|
||||
fmt.Println("install all initial environment done")
|
||||
return
|
||||
}
|
||||
|
||||
func installConfigFile() {
|
||||
|
@ -96,7 +95,7 @@ func installI18nBundle() {
|
|||
}
|
||||
|
||||
func writerFile(filePath, content string) error {
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0o666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -62,9 +62,9 @@ func (ac *AnswerController) RemoveAnswer(ctx *gin.Context) {
|
|||
// @Success 200 {string} string ""
|
||||
func (ac *AnswerController) Get(ctx *gin.Context) {
|
||||
id := ctx.Query("id")
|
||||
userId := middleware.GetLoginUserIDFromContext(ctx)
|
||||
userID := middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
info, questionInfo, has, err := ac.answerService.Get(ctx, id, userId)
|
||||
info, questionInfo, has, err := ac.answerService.Get(ctx, id, userID)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, gin.H{})
|
||||
return
|
||||
|
@ -101,18 +101,18 @@ func (ac *AnswerController) Add(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
answerId, err := ac.answerService.Insert(ctx, req)
|
||||
answerID, err := ac.answerService.Insert(ctx, req)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
info, questionInfo, has, err := ac.answerService.Get(ctx, answerId, req.UserID)
|
||||
info, questionInfo, has, err := ac.answerService.Get(ctx, answerID, req.UserID)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !has {
|
||||
//todo !has
|
||||
// todo !has
|
||||
handler.HandleResponse(ctx, nil, nil)
|
||||
return
|
||||
}
|
||||
|
@ -120,7 +120,6 @@ func (ac *AnswerController) Add(ctx *gin.Context) {
|
|||
"info": info,
|
||||
"question": questionInfo,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Update godoc
|
||||
|
@ -156,7 +155,7 @@ func (ac *AnswerController) Update(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
if !has {
|
||||
//todo !has
|
||||
// todo !has
|
||||
handler.HandleResponse(ctx, nil, nil)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ func (qc *QuestionController) CloseQuestion(ctx *gin.Context) {
|
|||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.UserId = middleware.GetLoginUserIDFromContext(ctx)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
err := qc.questionService.CloseQuestion(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
@ -114,7 +114,6 @@ func (qc *QuestionController) SimilarQuestion(ctx *gin.Context) {
|
|||
"list": list,
|
||||
"count": count,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Index godoc
|
||||
|
@ -365,6 +364,7 @@ func (qc *QuestionController) UserCollectionList(ctx *gin.Context) {
|
|||
// @Param page query int false "page size"
|
||||
// @Param page_size query int false "page size"
|
||||
// @Param status query string false "user status" Enums(available, closed, deleted)
|
||||
// @Param query query string false "question id or title"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/admin/api/question/page [get]
|
||||
func (qc *QuestionController) CmsSearchList(ctx *gin.Context) {
|
||||
|
@ -390,6 +390,7 @@ func (qc *QuestionController) CmsSearchList(ctx *gin.Context) {
|
|||
// @Param page query int false "page size"
|
||||
// @Param page_size query int false "page size"
|
||||
// @Param status query string false "user status" Enums(available,deleted)
|
||||
// @Param query query string false "answer id or question title"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/admin/api/answer/page [get]
|
||||
func (qc *QuestionController) CmsSearchAnswerList(ctx *gin.Context) {
|
||||
|
|
|
@ -35,7 +35,8 @@ func NewUserController(
|
|||
userService *service.UserService,
|
||||
actionService *action.CaptchaService,
|
||||
emailService *export.EmailService,
|
||||
uploaderService *uploader.UploaderService) *UserController {
|
||||
uploaderService *uploader.UploaderService,
|
||||
) *UserController {
|
||||
return &UserController{
|
||||
authService: authService,
|
||||
userService: userService,
|
||||
|
@ -119,7 +120,7 @@ func (uc *UserController) UserEmailLogin(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecord_Type_Login, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeLogin, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||
if !captchaPass {
|
||||
resp := schema.UserVerifyEmailErrorResponse{
|
||||
Key: "captcha_code",
|
||||
|
@ -132,7 +133,7 @@ func (uc *UserController) UserEmailLogin(ctx *gin.Context) {
|
|||
|
||||
resp, err := uc.userService.EmailLogin(ctx, req)
|
||||
if err != nil {
|
||||
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecord_Type_Login, ctx.ClientIP())
|
||||
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecordTypeLogin, ctx.ClientIP())
|
||||
resp := schema.UserVerifyEmailErrorResponse{
|
||||
Key: "e_mail",
|
||||
Value: "error.object.email_or_password_incorrect",
|
||||
|
@ -141,7 +142,7 @@ func (uc *UserController) UserEmailLogin(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, errors.BadRequest(reason.CaptchaVerificationFailed), resp)
|
||||
return
|
||||
}
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecord_Type_Login, ctx.ClientIP())
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecordTypeLogin, ctx.ClientIP())
|
||||
handler.HandleResponse(ctx, nil, resp)
|
||||
}
|
||||
|
||||
|
@ -159,7 +160,7 @@ func (uc *UserController) RetrievePassWord(ctx *gin.Context) {
|
|||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecord_Type_Find_Pass, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeFindPass, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||
if !captchaPass {
|
||||
resp := schema.UserVerifyEmailErrorResponse{
|
||||
Key: "captcha_code",
|
||||
|
@ -169,7 +170,7 @@ func (uc *UserController) RetrievePassWord(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, errors.BadRequest(reason.CaptchaVerificationFailed), resp)
|
||||
return
|
||||
}
|
||||
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecord_Type_Find_Pass, ctx.ClientIP())
|
||||
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecordTypeFindPass, ctx.ClientIP())
|
||||
code, err := uc.userService.RetrievePassWord(ctx, req)
|
||||
handler.HandleResponse(ctx, err, code)
|
||||
}
|
||||
|
@ -191,13 +192,13 @@ func (uc *UserController) UseRePassWord(ctx *gin.Context) {
|
|||
|
||||
req.Content = uc.emailService.VerifyUrlExpired(ctx, req.Code)
|
||||
if len(req.Content) == 0 {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.EmailVerifyUrlExpired),
|
||||
&schema.ForbiddenResp{Type: schema.ForbiddenReasonTypeUrlExpired})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.EmailVerifyURLExpired),
|
||||
&schema.ForbiddenResp{Type: schema.ForbiddenReasonTypeURLExpired})
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := uc.userService.UseRePassWord(ctx, req)
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecord_Type_Find_Pass, ctx.ClientIP())
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecordTypeFindPass, ctx.ClientIP())
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
|
@ -252,8 +253,8 @@ func (uc *UserController) UserVerifyEmail(ctx *gin.Context) {
|
|||
|
||||
req.Content = uc.emailService.VerifyUrlExpired(ctx, req.Code)
|
||||
if len(req.Content) == 0 {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.EmailVerifyUrlExpired),
|
||||
&schema.ForbiddenResp{Type: schema.ForbiddenReasonTypeUrlExpired})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.EmailVerifyURLExpired),
|
||||
&schema.ForbiddenResp{Type: schema.ForbiddenReasonTypeURLExpired})
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -263,7 +264,7 @@ func (uc *UserController) UserVerifyEmail(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecord_Type_Email, ctx.ClientIP())
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP())
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
|
@ -289,7 +290,7 @@ func (uc *UserController) UserVerifyEmailSend(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecord_Type_Email, ctx.ClientIP(),
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP(),
|
||||
req.CaptchaID, req.CaptchaCode)
|
||||
if !captchaPass {
|
||||
resp := schema.UserVerifyEmailErrorResponse{
|
||||
|
@ -301,7 +302,7 @@ func (uc *UserController) UserVerifyEmailSend(ctx *gin.Context) {
|
|||
|
||||
return
|
||||
}
|
||||
uc.actionService.ActionRecordAdd(ctx, schema.ActionRecord_Type_Email, ctx.ClientIP())
|
||||
uc.actionService.ActionRecordAdd(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP())
|
||||
err := uc.userService.UserVerifyEmailSend(ctx, userInfo.UserID)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
@ -321,7 +322,7 @@ func (uc *UserController) UserModifyPassWord(ctx *gin.Context) {
|
|||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.UserId = middleware.GetLoginUserIDFromContext(ctx)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
oldPassVerification, err := uc.userService.UserModifyPassWordVerification(ctx, req)
|
||||
if err != nil {
|
||||
|
@ -367,7 +368,7 @@ func (uc *UserController) UserUpdateInfo(ctx *gin.Context) {
|
|||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.UserId = middleware.GetLoginUserIDFromContext(ctx)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
err := uc.userService.UpdateInfo(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
@ -445,7 +446,7 @@ func (uc *UserController) ActionRecord(ctx *gin.Context) {
|
|||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.Ip = ctx.ClientIP()
|
||||
req.IP = ctx.ClientIP()
|
||||
|
||||
resp, err := uc.actionService.ActionRecord(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
|
@ -467,8 +468,8 @@ func (uc *UserController) UserNoticeSet(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
req.UserId = middleware.GetLoginUserIDFromContext(ctx)
|
||||
resp, err := uc.userService.UserNoticeSet(ctx, req.UserId, req.NoticeSwitch)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
resp, err := uc.userService.UserNoticeSet(ctx, req.UserID, req.NoticeSwitch)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
|
@ -490,7 +491,7 @@ func (uc *UserController) UserChangeEmailSendCode(ctx *gin.Context) {
|
|||
// If the user is not logged in, the api cannot be used.
|
||||
// If the user email is not verified, that also can use this api to modify the email.
|
||||
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecord_Type_Email, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||
if !captchaPass {
|
||||
resp := schema.UserVerifyEmailErrorResponse{
|
||||
Key: "captcha_code",
|
||||
|
@ -505,7 +506,7 @@ func (uc *UserController) UserChangeEmailSendCode(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, errors.Unauthorized(reason.UnauthorizedError), nil)
|
||||
return
|
||||
}
|
||||
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecord_Type_Email, ctx.ClientIP())
|
||||
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP())
|
||||
err := uc.userService.UserChangeEmailSendCode(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
@ -527,12 +528,12 @@ func (uc *UserController) UserChangeEmailVerify(ctx *gin.Context) {
|
|||
}
|
||||
req.Content = uc.emailService.VerifyUrlExpired(ctx, req.Code)
|
||||
if len(req.Content) == 0 {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.EmailVerifyUrlExpired),
|
||||
&schema.ForbiddenResp{Type: schema.ForbiddenReasonTypeUrlExpired})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.EmailVerifyURLExpired),
|
||||
&schema.ForbiddenResp{Type: schema.ForbiddenReasonTypeURLExpired})
|
||||
return
|
||||
}
|
||||
|
||||
err := uc.userService.UserChangeEmailVerify(ctx, req.Content)
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecord_Type_Email, ctx.ClientIP())
|
||||
uc.actionService.ActionRecordDel(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP())
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
|
|
@ -45,9 +45,8 @@ func (uc *UserBackyardController) UpdateUserStatus(ctx *gin.Context) {
|
|||
// @Produce json
|
||||
// @Param page query int false "page size"
|
||||
// @Param page_size query int false "page size"
|
||||
// @Param username query string false "username"
|
||||
// @Param e_mail query string false "email"
|
||||
// @Param status query string false "user status" Enums(normal, suspended, deleted, inactive)
|
||||
// @Param query query string false "search query: email, username or id:[id]"
|
||||
// @Param status query string false "user status" Enums(suspended, deleted, inactive)
|
||||
// @Success 200 {object} handler.RespBody{data=pager.PageModel{records=[]schema.GetUserPageResp}}
|
||||
// @Router /answer/admin/api/users/page [get]
|
||||
func (uc *UserBackyardController) GetUserPage(ctx *gin.Context) {
|
||||
|
|
|
@ -3,9 +3,9 @@ package entity
|
|||
import "time"
|
||||
|
||||
const (
|
||||
Answer_Search_OrderBy_Default = "default"
|
||||
Answer_Search_OrderBy_Time = "updated"
|
||||
Answer_Search_OrderBy_Vote = "vote"
|
||||
AnswerSearchOrderByDefault = "default"
|
||||
AnswerSearchOrderByTime = "updated"
|
||||
AnswerSearchOrderByVote = "vote"
|
||||
|
||||
AnswerStatusAvailable = 1
|
||||
AnswerStatusDeleted = 10
|
||||
|
@ -35,15 +35,16 @@ type Answer struct {
|
|||
type AnswerSearch struct {
|
||||
Answer
|
||||
Order string `json:"order_by" ` // default or updated
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Page int `json:"page" form:"page"` // Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` // Search page size
|
||||
}
|
||||
|
||||
type CmsAnswerSearch struct {
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Page int `json:"page" form:"page"` // Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` // Search page size
|
||||
Status int `json:"-" form:"-"`
|
||||
StatusStr string `json:"status" form:"status"` //Status 1 Available 2 closed 10 Deleted
|
||||
StatusStr string `json:"status" form:"status"` // Status 1 Available 2 closed 10 Deleted
|
||||
Query string `validate:"omitempty,gt=0,lte=100" json:"query" form:"query" ` //Query string
|
||||
}
|
||||
|
||||
type AdminSetAnswerStatusRequest struct {
|
||||
|
|
|
@ -40,7 +40,7 @@ type User struct {
|
|||
Avatar string `xorm:"not null default '' VARCHAR(255) avatar"`
|
||||
Mobile string `xorm:"not null VARCHAR(20) mobile"`
|
||||
Bio string `xorm:"not null TEXT bio"`
|
||||
BioHtml string `xorm:"not null TEXT bio_html"`
|
||||
BioHTML string `xorm:"not null TEXT bio_html"`
|
||||
Website string `xorm:"not null default '' VARCHAR(255) website"`
|
||||
Location string `xorm:"not null default '' VARCHAR(100) location"`
|
||||
IPInfo string `xorm:"not null default '' VARCHAR(255) ip_info"`
|
||||
|
@ -54,6 +54,6 @@ func (User) TableName() string {
|
|||
|
||||
type UserSearch struct {
|
||||
User
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Page int `json:"page" form:"page"` // Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` // Search page size
|
||||
}
|
||||
|
|
|
@ -8,27 +8,25 @@ import (
|
|||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
var (
|
||||
tables = []interface{}{
|
||||
&entity.Activity{},
|
||||
&entity.Answer{},
|
||||
&entity.Collection{},
|
||||
&entity.CollectionGroup{},
|
||||
&entity.Comment{},
|
||||
&entity.Config{},
|
||||
&entity.Meta{},
|
||||
&entity.Notification{},
|
||||
&entity.Question{},
|
||||
&entity.Report{},
|
||||
&entity.Revision{},
|
||||
&entity.SiteInfo{},
|
||||
&entity.Tag{},
|
||||
&entity.TagRel{},
|
||||
&entity.Uniqid{},
|
||||
&entity.User{},
|
||||
&entity.Version{},
|
||||
}
|
||||
)
|
||||
var tables = []interface{}{
|
||||
&entity.Activity{},
|
||||
&entity.Answer{},
|
||||
&entity.Collection{},
|
||||
&entity.CollectionGroup{},
|
||||
&entity.Comment{},
|
||||
&entity.Config{},
|
||||
&entity.Meta{},
|
||||
&entity.Notification{},
|
||||
&entity.Question{},
|
||||
&entity.Report{},
|
||||
&entity.Revision{},
|
||||
&entity.SiteInfo{},
|
||||
&entity.Tag{},
|
||||
&entity.TagRel{},
|
||||
&entity.Uniqid{},
|
||||
&entity.User{},
|
||||
&entity.Version{},
|
||||
}
|
||||
|
||||
// InitDB init db
|
||||
func InitDB(dataConf *data.Database) (err error) {
|
||||
|
@ -95,91 +93,91 @@ func initSiteInfo(engine *xorm.Engine) error {
|
|||
|
||||
func initConfigTable(engine *xorm.Engine) error {
|
||||
defaultConfigTable := []*entity.Config{
|
||||
{1, "answer.accepted", `15`},
|
||||
{2, "answer.voted_up", `10`},
|
||||
{3, "question.voted_up", `10`},
|
||||
{4, "tag.edit_accepted", `2`},
|
||||
{5, "answer.accept", `2`},
|
||||
{6, "answer.voted_down_cancel", `2`},
|
||||
{7, "question.voted_down_cancel", `2`},
|
||||
{8, "answer.vote_down_cancel", `1`},
|
||||
{9, "question.vote_down_cancel", `1`},
|
||||
{10, "user.activated", `1`},
|
||||
{11, "edit.accepted", `2`},
|
||||
{12, "answer.vote_down", `-1`},
|
||||
{13, "question.voted_down", `-2`},
|
||||
{14, "answer.voted_down", `-2`},
|
||||
{15, "answer.accept_cancel", `-2`},
|
||||
{16, "answer.deleted", `-5`},
|
||||
{17, "question.voted_up_cancel", `-10`},
|
||||
{18, "answer.voted_up_cancel", `-10`},
|
||||
{19, "answer.accepted_cancel", `-15`},
|
||||
{20, "object.reported", `-100`},
|
||||
{21, "edit.rejected", `-2`},
|
||||
{22, "daily_rank_limit", `200`},
|
||||
{23, "daily_rank_limit.exclude", `["answer.accepted"]`},
|
||||
{24, "user.follow", `0`},
|
||||
{25, "comment.vote_up", `0`},
|
||||
{26, "comment.vote_up_cancel", `0`},
|
||||
{27, "question.vote_down", `0`},
|
||||
{28, "question.vote_up", `0`},
|
||||
{29, "question.vote_up_cancel", `0`},
|
||||
{30, "answer.vote_up", `0`},
|
||||
{31, "answer.vote_up_cancel", `0`},
|
||||
{32, "question.follow", `0`},
|
||||
{33, "email.config", `{"from_name":"answer","from_email":"answer@answer.com","smtp_host":"smtp.answer.org","smtp_port":465,"smtp_password":"answer","smtp_username":"answer@answer.com","smtp_authentication":true,"encryption":"","register_title":"[{{.SiteName}}] Confirm your new account","register_body":"Welcome to {{.SiteName}}<br><br>\n\nClick the following link to confirm and activate your new account:<br>\n<a href='{{.RegisterUrl}}' target='_blank'>{{.RegisterUrl}}</a><br><br>\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n","pass_reset_title":"[{{.SiteName }}] Password reset","pass_reset_body":"Somebody asked to reset your password on [{{.SiteName}}].<br><br>\n\nIf it was not you, you can safely ignore this email.<br><br>\n\nClick the following link to choose a new password:<br>\n<a href='{{.PassResetUrl}}' target='_blank'>{{.PassResetUrl}}</a>\n","change_title":"[{{.SiteName}}] Confirm your new email address","change_body":"Confirm your new email address for {{.SiteName}} by clicking on the following link:<br><br>\n\n<a href='{{.ChangeEmailUrl}}' target='_blank'>{{.ChangeEmailUrl}}</a><br><br>\n\nIf you did not request this change, please ignore this email.\n","test_title":"[{{.SiteName}}] Test Email","test_body":"This is a test email."}`},
|
||||
{35, "tag.follow", `0`},
|
||||
{36, "rank.question.add", `0`},
|
||||
{37, "rank.question.edit", `0`},
|
||||
{38, "rank.question.delete", `0`},
|
||||
{39, "rank.question.vote_up", `0`},
|
||||
{40, "rank.question.vote_down", `0`},
|
||||
{41, "rank.answer.add", `0`},
|
||||
{42, "rank.answer.edit", `0`},
|
||||
{43, "rank.answer.delete", `0`},
|
||||
{44, "rank.answer.accept", `0`},
|
||||
{45, "rank.answer.vote_up", `0`},
|
||||
{46, "rank.answer.vote_down", `0`},
|
||||
{47, "rank.comment.add", `0`},
|
||||
{48, "rank.comment.edit", `0`},
|
||||
{49, "rank.comment.delete", `0`},
|
||||
{50, "rank.report.add", `0`},
|
||||
{51, "rank.tag.add", `0`},
|
||||
{52, "rank.tag.edit", `0`},
|
||||
{53, "rank.tag.delete", `0`},
|
||||
{54, "rank.tag.synonym", `0`},
|
||||
{55, "rank.link.url_limit", `0`},
|
||||
{56, "rank.vote.detail", `0`},
|
||||
{57, "reason.spam", `{"name":"spam","description":"This post is an advertisement, or vandalism. It is not useful or relevant to the current topic."}`},
|
||||
{58, "reason.rude_or_abusive", `{"name":"rude or abusive","description":"A reasonable person would find this content inappropriate for respectful discourse."}`},
|
||||
{59, "reason.something", `{"name":"something else","description":"This post requires staff attention for another reason not listed above.","content_type":"textarea"}`},
|
||||
{60, "reason.a_duplicate", `{"name":"a duplicate","description":"This question has been asked before and already has an answer.","content_type":"text"}`},
|
||||
{61, "reason.not_a_answer", `{"name":"not a answer","description":"This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question, or deleted altogether.","content_type":""}`},
|
||||
{62, "reason.no_longer_needed", `{"name":"no longer needed","description":"This comment is outdated, conversational or not relevant to this post."}`},
|
||||
{63, "reason.community_specific", `{"name":"a community-specific reason","description":"This question doesn’t meet a community guideline."}`},
|
||||
{64, "reason.not_clarity", `{"name":"needs details or clarity","description":"This question currently includes multiple questions in one. It should focus on one problem only.","content_type":"text"}`},
|
||||
{65, "reason.normal", `{"name":"normal","description":"A normal post available to everyone."}`},
|
||||
{66, "reason.normal.user", `{"name":"normal","description":"A normal user can ask and answer questions."}`},
|
||||
{67, "reason.closed", `{"name":"closed","description":"A closed question can’t answer, but still can edit, vote and comment."}`},
|
||||
{68, "reason.deleted", `{"name":"deleted","description":"All reputation gained and lost will be restored."}`},
|
||||
{69, "reason.deleted.user", `{"name":"deleted","description":"Delete profile, authentication associations."}`},
|
||||
{70, "reason.suspended", `{"name":"suspended","description":"A suspended user can’t log in."}`},
|
||||
{71, "reason.inactive", `{"name":"inactive","description":"An inactive user must re-validate their email."}`},
|
||||
{72, "reason.looks_ok", `{"name":"looks ok","description":"This post is good as-is and not low quality."}`},
|
||||
{73, "reason.needs_edit", `{"name":"needs edit, and I did it","description":"Improve and correct problems with this post yourself."}`},
|
||||
{74, "reason.needs_close", `{"name":"needs close","description":"A closed question can’t answer, but still can edit, vote and comment."}`},
|
||||
{75, "reason.needs_delete", `{"name":"needs delete","description":"All reputation gained and lost will be restored."}`},
|
||||
{76, "question.flag.reasons", `["reason.spam","reason.rude_or_abusive","reason.something","reason.a_duplicate"]`},
|
||||
{77, "answer.flag.reasons", `["reason.spam","reason.rude_or_abusive","reason.something","reason.not_a_answer"]`},
|
||||
{78, "comment.flag.reasons", `["reason.spam","reason.rude_or_abusive","reason.something","reason.no_longer_needed"]`},
|
||||
{79, "question.close.reasons", `["reason.a_duplicate","reason.community_specific","reason.not_clarity","reason.something"]`},
|
||||
{80, "question.status.reasons", `["reason.normal","reason.closed","reason.deleted"]`},
|
||||
{81, "answer.status.reasons", `["reason.normal","reason.deleted"]`},
|
||||
{82, "comment.status.reasons", `["reason.normal","reason.deleted"]`},
|
||||
{83, "user.status.reasons", `["reason.normal.user","reason.suspended","reason.deleted.user","reason.inactive"]`},
|
||||
{84, "question.review.reasons", `["reason.looks_ok","reason.needs_edit","reason.needs_close","reason.needs_delete"]`},
|
||||
{85, "answer.review.reasons", `["reason.looks_ok","reason.needs_edit","reason.needs_delete"]`},
|
||||
{86, "comment.review.reasons", `["reason.looks_ok","reason.needs_edit","reason.needs_delete"]`},
|
||||
{ID: 1, Key: "answer.accepted", Value: `15`},
|
||||
{ID: 2, Key: "answer.voted_up", Value: `10`},
|
||||
{ID: 3, Key: "question.voted_up", Value: `10`},
|
||||
{ID: 4, Key: "tag.edit_accepted", Value: `2`},
|
||||
{ID: 5, Key: "answer.accept", Value: `2`},
|
||||
{ID: 6, Key: "answer.voted_down_cancel", Value: `2`},
|
||||
{ID: 7, Key: "question.voted_down_cancel", Value: `2`},
|
||||
{ID: 8, Key: "answer.vote_down_cancel", Value: `1`},
|
||||
{ID: 9, Key: "question.vote_down_cancel", Value: `1`},
|
||||
{ID: 10, Key: "user.activated", Value: `1`},
|
||||
{ID: 11, Key: "edit.accepted", Value: `2`},
|
||||
{ID: 12, Key: "answer.vote_down", Value: `-1`},
|
||||
{ID: 13, Key: "question.voted_down", Value: `-2`},
|
||||
{ID: 14, Key: "answer.voted_down", Value: `-2`},
|
||||
{ID: 15, Key: "answer.accept_cancel", Value: `-2`},
|
||||
{ID: 16, Key: "answer.deleted", Value: `-5`},
|
||||
{ID: 17, Key: "question.voted_up_cancel", Value: `-10`},
|
||||
{ID: 18, Key: "answer.voted_up_cancel", Value: `-10`},
|
||||
{ID: 19, Key: "answer.accepted_cancel", Value: `-15`},
|
||||
{ID: 20, Key: "object.reported", Value: `-100`},
|
||||
{ID: 21, Key: "edit.rejected", Value: `-2`},
|
||||
{ID: 22, Key: "daily_rank_limit", Value: `200`},
|
||||
{ID: 23, Key: "daily_rank_limit.exclude", Value: `["answer.accepted"]`},
|
||||
{ID: 24, Key: "user.follow", Value: `0`},
|
||||
{ID: 25, Key: "comment.vote_up", Value: `0`},
|
||||
{ID: 26, Key: "comment.vote_up_cancel", Value: `0`},
|
||||
{ID: 27, Key: "question.vote_down", Value: `0`},
|
||||
{ID: 28, Key: "question.vote_up", Value: `0`},
|
||||
{ID: 29, Key: "question.vote_up_cancel", Value: `0`},
|
||||
{ID: 30, Key: "answer.vote_up", Value: `0`},
|
||||
{ID: 31, Key: "answer.vote_up_cancel", Value: `0`},
|
||||
{ID: 32, Key: "question.follow", Value: `0`},
|
||||
{ID: 33, Key: "email.config", Value: `{"from_name":"answer","from_email":"answer@answer.com","smtp_host":"smtp.answer.org","smtp_port":465,"smtp_password":"answer","smtp_username":"answer@answer.com","smtp_authentication":true,"encryption":"","register_title":"[{{.SiteName}}] Confirm your new account","register_body":"Welcome to {{.SiteName}}<br><br>\n\nClick the following link to confirm and activate your new account:<br>\n<a href='{{.RegisterUrl}}' target='_blank'>{{.RegisterUrl}}</a><br><br>\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n","pass_reset_title":"[{{.SiteName }}] Password reset","pass_reset_body":"Somebody asked to reset your password on [{{.SiteName}}].<br><br>\n\nIf it was not you, you can safely ignore this email.<br><br>\n\nClick the following link to choose a new password:<br>\n<a href='{{.PassResetUrl}}' target='_blank'>{{.PassResetUrl}}</a>\n","change_title":"[{{.SiteName}}] Confirm your new email address","change_body":"Confirm your new email address for {{.SiteName}} by clicking on the following link:<br><br>\n\n<a href='{{.ChangeEmailUrl}}' target='_blank'>{{.ChangeEmailUrl}}</a><br><br>\n\nIf you did not request this change, please ignore this email.\n","test_title":"[{{.SiteName}}] Test Email","test_body":"This is a test email."}`},
|
||||
{ID: 35, Key: "tag.follow", Value: `0`},
|
||||
{ID: 36, Key: "rank.question.add", Value: `0`},
|
||||
{ID: 37, Key: "rank.question.edit", Value: `0`},
|
||||
{ID: 38, Key: "rank.question.delete", Value: `0`},
|
||||
{ID: 39, Key: "rank.question.vote_up", Value: `0`},
|
||||
{ID: 40, Key: "rank.question.vote_down", Value: `0`},
|
||||
{ID: 41, Key: "rank.answer.add", Value: `0`},
|
||||
{ID: 42, Key: "rank.answer.edit", Value: `0`},
|
||||
{ID: 43, Key: "rank.answer.delete", Value: `0`},
|
||||
{ID: 44, Key: "rank.answer.accept", Value: `0`},
|
||||
{ID: 45, Key: "rank.answer.vote_up", Value: `0`},
|
||||
{ID: 46, Key: "rank.answer.vote_down", Value: `0`},
|
||||
{ID: 47, Key: "rank.comment.add", Value: `0`},
|
||||
{ID: 48, Key: "rank.comment.edit", Value: `0`},
|
||||
{ID: 49, Key: "rank.comment.delete", Value: `0`},
|
||||
{ID: 50, Key: "rank.report.add", Value: `0`},
|
||||
{ID: 51, Key: "rank.tag.add", Value: `0`},
|
||||
{ID: 52, Key: "rank.tag.edit", Value: `0`},
|
||||
{ID: 53, Key: "rank.tag.delete", Value: `0`},
|
||||
{ID: 54, Key: "rank.tag.synonym", Value: `0`},
|
||||
{ID: 55, Key: "rank.link.url_limit", Value: `0`},
|
||||
{ID: 56, Key: "rank.vote.detail", Value: `0`},
|
||||
{ID: 57, Key: "reason.spam", Value: `{"name":"spam","description":"This post is an advertisement, or vandalism. It is not useful or relevant to the current topic."}`},
|
||||
{ID: 58, Key: "reason.rude_or_abusive", Value: `{"name":"rude or abusive","description":"A reasonable person would find this content inappropriate for respectful discourse."}`},
|
||||
{ID: 59, Key: "reason.something", Value: `{"name":"something else","description":"This post requires staff attention for another reason not listed above.","content_type":"textarea"}`},
|
||||
{ID: 60, Key: "reason.a_duplicate", Value: `{"name":"a duplicate","description":"This question has been asked before and already has an answer.","content_type":"text"}`},
|
||||
{ID: 61, Key: "reason.not_a_answer", Value: `{"name":"not a answer","description":"This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question, or deleted altogether.","content_type":""}`},
|
||||
{ID: 62, Key: "reason.no_longer_needed", Value: `{"name":"no longer needed","description":"This comment is outdated, conversational or not relevant to this post."}`},
|
||||
{ID: 63, Key: "reason.community_specific", Value: `{"name":"a community-specific reason","description":"This question doesn’t meet a community guideline."}`},
|
||||
{ID: 64, Key: "reason.not_clarity", Value: `{"name":"needs details or clarity","description":"This question currently includes multiple questions in one. It should focus on one problem only.","content_type":"text"}`},
|
||||
{ID: 65, Key: "reason.normal", Value: `{"name":"normal","description":"A normal post available to everyone."}`},
|
||||
{ID: 66, Key: "reason.normal.user", Value: `{"name":"normal","description":"A normal user can ask and answer questions."}`},
|
||||
{ID: 67, Key: "reason.closed", Value: `{"name":"closed","description":"A closed question can’t answer, but still can edit, vote and comment."}`},
|
||||
{ID: 68, Key: "reason.deleted", Value: `{"name":"deleted","description":"All reputation gained and lost will be restored."}`},
|
||||
{ID: 69, Key: "reason.deleted.user", Value: `{"name":"deleted","description":"Delete profile, authentication associations."}`},
|
||||
{ID: 70, Key: "reason.suspended", Value: `{"name":"suspended","description":"A suspended user can’t log in."}`},
|
||||
{ID: 71, Key: "reason.inactive", Value: `{"name":"inactive","description":"An inactive user must re-validate their email."}`},
|
||||
{ID: 72, Key: "reason.looks_ok", Value: `{"name":"looks ok","description":"This post is good as-is and not low quality."}`},
|
||||
{ID: 73, Key: "reason.needs_edit", Value: `{"name":"needs edit, and I did it","description":"Improve and correct problems with this post yourself."}`},
|
||||
{ID: 74, Key: "reason.needs_close", Value: `{"name":"needs close","description":"A closed question can’t answer, but still can edit, vote and comment."}`},
|
||||
{ID: 75, Key: "reason.needs_delete", Value: `{"name":"needs delete","description":"All reputation gained and lost will be restored."}`},
|
||||
{ID: 76, Key: "question.flag.reasons", Value: `["reason.spam","reason.rude_or_abusive","reason.something","reason.a_duplicate"]`},
|
||||
{ID: 77, Key: "answer.flag.reasons", Value: `["reason.spam","reason.rude_or_abusive","reason.something","reason.not_a_answer"]`},
|
||||
{ID: 78, Key: "comment.flag.reasons", Value: `["reason.spam","reason.rude_or_abusive","reason.something","reason.no_longer_needed"]`},
|
||||
{ID: 79, Key: "question.close.reasons", Value: `["reason.a_duplicate","reason.community_specific","reason.not_clarity","reason.something"]`},
|
||||
{ID: 80, Key: "question.status.reasons", Value: `["reason.normal","reason.closed","reason.deleted"]`},
|
||||
{ID: 81, Key: "answer.status.reasons", Value: `["reason.normal","reason.deleted"]`},
|
||||
{ID: 82, Key: "comment.status.reasons", Value: `["reason.normal","reason.deleted"]`},
|
||||
{ID: 83, Key: "user.status.reasons", Value: `["reason.normal.user","reason.suspended","reason.deleted.user","reason.inactive"]`},
|
||||
{ID: 84, Key: "question.review.reasons", Value: `["reason.looks_ok","reason.needs_edit","reason.needs_close","reason.needs_delete"]`},
|
||||
{ID: 85, Key: "answer.review.reasons", Value: `["reason.looks_ok","reason.needs_edit","reason.needs_delete"]`},
|
||||
{ID: 86, Key: "comment.review.reasons", Value: `["reason.looks_ok","reason.needs_edit","reason.needs_delete"]`},
|
||||
}
|
||||
_, err := engine.Insert(defaultConfigTable)
|
||||
return err
|
||||
|
|
|
@ -44,7 +44,6 @@ func NewAnswerActivityRepo(
|
|||
userRankRepo rank.UserRankRepo,
|
||||
) activity.AnswerActivityRepo {
|
||||
return &AnswerActivityRepo{
|
||||
|
||||
data: data,
|
||||
activityRepo: activityRepo,
|
||||
userRankRepo: userRankRepo,
|
||||
|
@ -125,7 +124,8 @@ func (ar *AnswerActivityRepo) DeleteQuestion(ctx context.Context, questionID str
|
|||
|
||||
// AcceptAnswer accept other answer
|
||||
func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
||||
answerObjID, questionUserID, answerUserID string, isSelf bool) (err error) {
|
||||
answerObjID, questionUserID, answerUserID string, isSelf bool,
|
||||
) (err error) {
|
||||
addActivityList := make([]*entity.Activity, 0)
|
||||
for _, action := range acceptActionList {
|
||||
// get accept answer need add rank amount
|
||||
|
@ -173,7 +173,7 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
|||
}
|
||||
|
||||
if exists {
|
||||
if _, e := session.Where("id = ?", existsActivity.ID).Cols("`cancelled`").
|
||||
if _, e = session.Where("id = ?", existsActivity.ID).Cols("`cancelled`").
|
||||
Update(&entity.Activity{Cancelled: entity.ActivityAvailable}); e != nil {
|
||||
return nil, errors.InternalServer(reason.DatabaseError).WithError(e).WithStack()
|
||||
}
|
||||
|
@ -222,7 +222,8 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
|||
|
||||
// CancelAcceptAnswer accept other answer
|
||||
func (ar *AnswerActivityRepo) CancelAcceptAnswer(ctx context.Context,
|
||||
answerObjID, questionUserID, answerUserID string) (err error) {
|
||||
answerObjID, questionUserID, answerUserID string,
|
||||
) (err error) {
|
||||
addActivityList := make([]*entity.Activity, 0)
|
||||
for _, action := range acceptActionList {
|
||||
// get accept answer need add rank amount
|
||||
|
|
|
@ -37,8 +37,8 @@ func NewFollowRepo(
|
|||
}
|
||||
}
|
||||
|
||||
func (ar *FollowRepo) Follow(ctx context.Context, objectId, userId string) error {
|
||||
activityType, _, _, err := ar.activityRepo.GetActivityTypeByObjID(ctx, objectId, "follow")
|
||||
func (ar *FollowRepo) Follow(ctx context.Context, objectID, userID string) error {
|
||||
activityType, _, _, err := ar.activityRepo.GetActivityTypeByObjID(ctx, objectID, "follow")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ func (ar *FollowRepo) Follow(ctx context.Context, objectId, userId string) error
|
|||
result = nil
|
||||
|
||||
has, err = session.Where(builder.Eq{"activity_type": activityType}).
|
||||
And(builder.Eq{"user_id": userId}).
|
||||
And(builder.Eq{"object_id": objectId}).
|
||||
And(builder.Eq{"user_id": userID}).
|
||||
And(builder.Eq{"object_id": objectID}).
|
||||
Get(&existsActivity)
|
||||
|
||||
if err != nil {
|
||||
|
@ -72,8 +72,8 @@ func (ar *FollowRepo) Follow(ctx context.Context, objectId, userId string) error
|
|||
} else {
|
||||
// update existing activity with new user id and u object id
|
||||
_, err = session.Insert(&entity.Activity{
|
||||
UserID: userId,
|
||||
ObjectID: objectId,
|
||||
UserID: userID,
|
||||
ObjectID: objectID,
|
||||
ActivityType: activityType,
|
||||
Cancelled: 0,
|
||||
Rank: 0,
|
||||
|
@ -87,7 +87,7 @@ func (ar *FollowRepo) Follow(ctx context.Context, objectId, userId string) error
|
|||
}
|
||||
|
||||
// start update followers when everything is fine
|
||||
err = ar.updateFollows(ctx, session, objectId, 1)
|
||||
err = ar.updateFollows(ctx, session, objectID, 1)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
@ -98,8 +98,8 @@ func (ar *FollowRepo) Follow(ctx context.Context, objectId, userId string) error
|
|||
return err
|
||||
}
|
||||
|
||||
func (ar *FollowRepo) FollowCancel(ctx context.Context, objectId, userId string) error {
|
||||
activityType, _, _, err := ar.activityRepo.GetActivityTypeByObjID(ctx, objectId, "follow")
|
||||
func (ar *FollowRepo) FollowCancel(ctx context.Context, objectID, userID string) error {
|
||||
activityType, _, _, err := ar.activityRepo.GetActivityTypeByObjID(ctx, objectID, "follow")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -112,8 +112,8 @@ func (ar *FollowRepo) FollowCancel(ctx context.Context, objectId, userId string)
|
|||
result = nil
|
||||
|
||||
has, err = session.Where(builder.Eq{"activity_type": activityType}).
|
||||
And(builder.Eq{"user_id": userId}).
|
||||
And(builder.Eq{"object_id": objectId}).
|
||||
And(builder.Eq{"user_id": userID}).
|
||||
And(builder.Eq{"object_id": objectID}).
|
||||
Get(&existsActivity)
|
||||
|
||||
if err != nil || !has {
|
||||
|
@ -130,24 +130,24 @@ func (ar *FollowRepo) FollowCancel(ctx context.Context, objectId, userId string)
|
|||
}); err != nil {
|
||||
return
|
||||
}
|
||||
err = ar.updateFollows(ctx, session, objectId, -1)
|
||||
err = ar.updateFollows(ctx, session, objectID, -1)
|
||||
return
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (ar *FollowRepo) updateFollows(ctx context.Context, session *xorm.Session, objectId string, follows int) error {
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectId)
|
||||
func (ar *FollowRepo) updateFollows(ctx context.Context, session *xorm.Session, objectID string, follows int) error {
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch objectType {
|
||||
case "question":
|
||||
_, err = session.Where("id = ?", objectId).Incr("follow_count", follows).Update(&entity.Question{})
|
||||
_, err = session.Where("id = ?", objectID).Incr("follow_count", follows).Update(&entity.Question{})
|
||||
case "user":
|
||||
_, err = session.Where("id = ?", objectId).Incr("follow_count", follows).Update(&entity.User{})
|
||||
_, err = session.Where("id = ?", objectID).Incr("follow_count", follows).Update(&entity.User{})
|
||||
case "tag":
|
||||
_, err = session.Where("id = ?", objectId).Incr("follow_count", follows).Update(&entity.Tag{})
|
||||
_, err = session.Where("id = ?", objectID).Incr("follow_count", follows).Update(&entity.Tag{})
|
||||
default:
|
||||
err = errors.InternalServer(reason.DisallowFollow).WithMsg("this object can't be followed")
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@ package activity
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
"strings"
|
||||
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/pager"
|
||||
"github.com/answerdev/answer/internal/service/config"
|
||||
"github.com/answerdev/answer/internal/service/notice_queue"
|
||||
|
@ -42,7 +43,8 @@ func NewVoteRepo(
|
|||
configRepo config.ConfigRepo,
|
||||
activityRepo activity_common.ActivityRepo,
|
||||
userRankRepo rank.UserRankRepo,
|
||||
voteCommon activity_common.VoteRepo) service.VoteRepo {
|
||||
voteCommon activity_common.VoteRepo,
|
||||
) service.VoteRepo {
|
||||
return &VoteRepo{
|
||||
data: data,
|
||||
uniqueIDRepo: uniqueIDRepo,
|
||||
|
@ -65,7 +67,7 @@ var LimitDownActions = map[string][]string{
|
|||
"comment": {"vote_down"},
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUserId string, actions []string) (resp *schema.VoteResp, err error) {
|
||||
func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUserID string, actions []string) (resp *schema.VoteResp, err error) {
|
||||
resp = &schema.VoteResp{}
|
||||
_, err = vr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
|
||||
result = nil
|
||||
|
@ -75,24 +77,24 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
insertActivity entity.Activity
|
||||
has bool
|
||||
triggerUserID,
|
||||
activityUserId string
|
||||
activityUserID string
|
||||
activityType, deltaRank, hasRank int
|
||||
)
|
||||
|
||||
activityUserId, activityType, deltaRank, hasRank, err = vr.CheckRank(ctx, objectID, objectUserId, userID, action)
|
||||
activityUserID, activityType, deltaRank, hasRank, err = vr.CheckRank(ctx, objectID, objectUserID, userID, action)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
triggerUserID = userID
|
||||
if userID == activityUserId {
|
||||
if userID == activityUserID {
|
||||
triggerUserID = "0"
|
||||
}
|
||||
|
||||
// check is voted up
|
||||
has, _ = session.
|
||||
Where(builder.Eq{"object_id": objectID}).
|
||||
And(builder.Eq{"user_id": activityUserId}).
|
||||
And(builder.Eq{"user_id": activityUserID}).
|
||||
And(builder.Eq{"trigger_user_id": triggerUserID}).
|
||||
And(builder.Eq{"activity_type": activityType}).
|
||||
Get(&existsActivity)
|
||||
|
@ -104,7 +106,7 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
|
||||
insertActivity = entity.Activity{
|
||||
ObjectID: objectID,
|
||||
UserID: activityUserId,
|
||||
UserID: activityUserID,
|
||||
TriggerUserID: converter.StringToInt64(triggerUserID),
|
||||
ActivityType: activityType,
|
||||
Rank: deltaRank,
|
||||
|
@ -114,7 +116,8 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
|
||||
// trigger user rank and send notification
|
||||
if hasRank != 0 {
|
||||
isReachStandard, err := vr.userRankRepo.TriggerUserRank(ctx, session, activityUserId, deltaRank, activityType)
|
||||
var isReachStandard bool
|
||||
isReachStandard, err = vr.userRankRepo.TriggerUserRank(ctx, session, activityUserID, deltaRank, activityType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -122,7 +125,7 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
insertActivity.Rank = 0
|
||||
}
|
||||
|
||||
vr.sendNotification(ctx, activityUserId, objectUserId, objectID)
|
||||
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
||||
}
|
||||
|
||||
if has {
|
||||
|
@ -163,7 +166,7 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
return
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) voteCancel(ctx context.Context, objectID string, userID, objectUserId string, actions []string) (resp *schema.VoteResp, err error) {
|
||||
func (vr *VoteRepo) voteCancel(ctx context.Context, objectID string, userID, objectUserID string, actions []string) (resp *schema.VoteResp, err error) {
|
||||
resp = &schema.VoteResp{}
|
||||
_, err = vr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
|
||||
for _, action := range actions {
|
||||
|
@ -171,24 +174,24 @@ func (vr *VoteRepo) voteCancel(ctx context.Context, objectID string, userID, obj
|
|||
existsActivity entity.Activity
|
||||
has bool
|
||||
triggerUserID,
|
||||
activityUserId string
|
||||
activityUserID string
|
||||
activityType,
|
||||
deltaRank, hasRank int
|
||||
)
|
||||
result = nil
|
||||
|
||||
activityUserId, activityType, deltaRank, hasRank, err = vr.CheckRank(ctx, objectID, objectUserId, userID, action)
|
||||
activityUserID, activityType, deltaRank, hasRank, err = vr.CheckRank(ctx, objectID, objectUserID, userID, action)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
triggerUserID = userID
|
||||
if userID == activityUserId {
|
||||
if userID == activityUserID {
|
||||
triggerUserID = "0"
|
||||
}
|
||||
|
||||
has, err = session.
|
||||
Where(builder.Eq{"user_id": activityUserId}).
|
||||
Where(builder.Eq{"user_id": activityUserID}).
|
||||
And(builder.Eq{"trigger_user_id": triggerUserID}).
|
||||
And(builder.Eq{"activity_type": activityType}).
|
||||
And(builder.Eq{"object_id": objectID}).
|
||||
|
@ -211,12 +214,12 @@ func (vr *VoteRepo) voteCancel(ctx context.Context, objectID string, userID, obj
|
|||
|
||||
// trigger user rank and send notification
|
||||
if hasRank != 0 {
|
||||
_, err = vr.userRankRepo.TriggerUserRank(ctx, session, activityUserId, -deltaRank, activityType)
|
||||
_, err = vr.userRankRepo.TriggerUserRank(ctx, session, activityUserID, -deltaRank, activityType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
vr.sendNotification(ctx, activityUserId, objectUserId, objectID)
|
||||
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
||||
}
|
||||
|
||||
// update votes
|
||||
|
@ -242,7 +245,7 @@ func (vr *VoteRepo) voteCancel(ctx context.Context, objectID string, userID, obj
|
|||
return
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) VoteUp(ctx context.Context, objectID string, userID, objectUserId string) (resp *schema.VoteResp, err error) {
|
||||
func (vr *VoteRepo) VoteUp(ctx context.Context, objectID string, userID, objectUserID string) (resp *schema.VoteResp, err error) {
|
||||
resp = &schema.VoteResp{}
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectID)
|
||||
if err != nil {
|
||||
|
@ -256,11 +259,11 @@ func (vr *VoteRepo) VoteUp(ctx context.Context, objectID string, userID, objectU
|
|||
return
|
||||
}
|
||||
|
||||
_, _ = vr.VoteDownCancel(ctx, objectID, userID, objectUserId)
|
||||
return vr.vote(ctx, objectID, userID, objectUserId, actions)
|
||||
_, _ = vr.VoteDownCancel(ctx, objectID, userID, objectUserID)
|
||||
return vr.vote(ctx, objectID, userID, objectUserID, actions)
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) VoteDown(ctx context.Context, objectID string, userID, objectUserId string) (resp *schema.VoteResp, err error) {
|
||||
func (vr *VoteRepo) VoteDown(ctx context.Context, objectID string, userID, objectUserID string) (resp *schema.VoteResp, err error) {
|
||||
resp = &schema.VoteResp{}
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectID)
|
||||
if err != nil {
|
||||
|
@ -273,14 +276,12 @@ func (vr *VoteRepo) VoteDown(ctx context.Context, objectID string, userID, objec
|
|||
return
|
||||
}
|
||||
|
||||
_, _ = vr.VoteUpCancel(ctx, objectID, userID, objectUserId)
|
||||
return vr.vote(ctx, objectID, userID, objectUserId, actions)
|
||||
_, _ = vr.VoteUpCancel(ctx, objectID, userID, objectUserID)
|
||||
return vr.vote(ctx, objectID, userID, objectUserID, actions)
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) VoteUpCancel(ctx context.Context, objectID string, userID, objectUserId string) (resp *schema.VoteResp, err error) {
|
||||
var (
|
||||
objectType string
|
||||
)
|
||||
func (vr *VoteRepo) VoteUpCancel(ctx context.Context, objectID string, userID, objectUserID string) (resp *schema.VoteResp, err error) {
|
||||
var objectType string
|
||||
resp = &schema.VoteResp{}
|
||||
|
||||
objectType, err = obj.GetObjectTypeStrByObjectID(objectID)
|
||||
|
@ -294,13 +295,11 @@ func (vr *VoteRepo) VoteUpCancel(ctx context.Context, objectID string, userID, o
|
|||
return
|
||||
}
|
||||
|
||||
return vr.voteCancel(ctx, objectID, userID, objectUserId, actions)
|
||||
return vr.voteCancel(ctx, objectID, userID, objectUserID, actions)
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) VoteDownCancel(ctx context.Context, objectID string, userID, objectUserId string) (resp *schema.VoteResp, err error) {
|
||||
var (
|
||||
objectType string
|
||||
)
|
||||
func (vr *VoteRepo) VoteDownCancel(ctx context.Context, objectID string, userID, objectUserID string) (resp *schema.VoteResp, err error) {
|
||||
var objectType string
|
||||
resp = &schema.VoteResp{}
|
||||
|
||||
objectType, err = obj.GetObjectTypeStrByObjectID(objectID)
|
||||
|
@ -314,22 +313,22 @@ func (vr *VoteRepo) VoteDownCancel(ctx context.Context, objectID string, userID,
|
|||
return
|
||||
}
|
||||
|
||||
return vr.voteCancel(ctx, objectID, userID, objectUserId, actions)
|
||||
return vr.voteCancel(ctx, objectID, userID, objectUserID, actions)
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) CheckRank(ctx context.Context, objectID, objectUserId, userID string, action string) (activityUserId string, activityType, rank, hasRank int, err error) {
|
||||
func (vr *VoteRepo) CheckRank(ctx context.Context, objectID, objectUserID, userID string, action string) (activityUserID string, activityType, rank, hasRank int, err error) {
|
||||
activityType, rank, hasRank, err = vr.activityRepo.GetActivityTypeByObjID(ctx, objectID, action)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
activityUserId = userID
|
||||
activityUserID = userID
|
||||
if strings.Contains(action, "voted") {
|
||||
activityUserId = objectUserId
|
||||
activityUserID = objectUserID
|
||||
}
|
||||
|
||||
return activityUserId, activityType, rank, hasRank, nil
|
||||
return activityUserID, activityType, rank, hasRank, nil
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) GetVoteResultByObjectId(ctx context.Context, objectID string) (resp *schema.VoteResp, err error) {
|
||||
|
@ -341,7 +340,7 @@ func (vr *VoteRepo) GetVoteResultByObjectId(ctx context.Context, objectID string
|
|||
activityType int
|
||||
)
|
||||
|
||||
activityType, _, _, err = vr.activityRepo.GetActivityTypeByObjID(ctx, objectID, action)
|
||||
activityType, _, _, _ = vr.activityRepo.GetActivityTypeByObjID(ctx, objectID, action)
|
||||
|
||||
votes, err = vr.data.DB.Where(builder.Eq{"object_id": objectID}).
|
||||
And(builder.Eq{"activity_type": activityType}).
|
||||
|
@ -417,15 +416,15 @@ func (vr *VoteRepo) updateVotes(ctx context.Context, session *xorm.Session, obje
|
|||
}
|
||||
|
||||
// sendNotification send rank triggered notification
|
||||
func (vr *VoteRepo) sendNotification(ctx context.Context, activityUserId, objectUserId, objectID string) {
|
||||
func (vr *VoteRepo) sendNotification(ctx context.Context, activityUserID, objectUserID, objectID string) {
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: activityUserId,
|
||||
TriggerUserID: objectUserId,
|
||||
ReceiverUserID: activityUserID,
|
||||
TriggerUserID: objectUserID,
|
||||
Type: schema.NotificationTypeAchievement,
|
||||
ObjectID: objectID,
|
||||
ObjectType: objectType,
|
||||
|
|
|
@ -33,27 +33,27 @@ func NewFollowRepo(
|
|||
}
|
||||
|
||||
// GetFollowAmount get object id's follows
|
||||
func (ar *FollowRepo) GetFollowAmount(ctx context.Context, objectId string) (follows int, err error) {
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectId)
|
||||
func (ar *FollowRepo) GetFollowAmount(ctx context.Context, objectID string) (follows int, err error) {
|
||||
objectType, err := obj.GetObjectTypeStrByObjectID(objectID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch objectType {
|
||||
case "question":
|
||||
model := &entity.Question{}
|
||||
_, err = ar.data.DB.Where("id = ?", objectId).Cols("`follow_count`").Get(model)
|
||||
_, err = ar.data.DB.Where("id = ?", objectID).Cols("`follow_count`").Get(model)
|
||||
if err == nil {
|
||||
follows = int(model.FollowCount)
|
||||
}
|
||||
case "user":
|
||||
model := &entity.User{}
|
||||
_, err = ar.data.DB.Where("id = ?", objectId).Cols("`follow_count`").Get(model)
|
||||
_, err = ar.data.DB.Where("id = ?", objectID).Cols("`follow_count`").Get(model)
|
||||
if err == nil {
|
||||
follows = int(model.FollowCount)
|
||||
}
|
||||
case "tag":
|
||||
model := &entity.Tag{}
|
||||
_, err = ar.data.DB.Where("id = ?", objectId).Cols("`follow_count`").Get(model)
|
||||
_, err = ar.data.DB.Where("id = ?", objectID).Cols("`follow_count`").Get(model)
|
||||
if err == nil {
|
||||
follows = int(model.FollowCount)
|
||||
}
|
||||
|
@ -95,6 +95,9 @@ func (ar *FollowRepo) GetFollowUserIDs(ctx context.Context, objectID string) (us
|
|||
func (ar *FollowRepo) GetFollowIDs(ctx context.Context, userID, objectKey string) (followIDs []string, err error) {
|
||||
followIDs = make([]string, 0)
|
||||
activityType, err := ar.activityRepo.GetActivityTypeByObjKey(ctx, objectKey, "follow")
|
||||
if err != nil {
|
||||
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
session := ar.data.DB.Select("object_id")
|
||||
session.Table(entity.Activity{}.TableName())
|
||||
session.Where("user_id = ? AND activity_type = ?", userID, activityType)
|
||||
|
@ -107,14 +110,14 @@ func (ar *FollowRepo) GetFollowIDs(ctx context.Context, userID, objectKey string
|
|||
}
|
||||
|
||||
// IsFollowed check user if follow object or not
|
||||
func (ar *FollowRepo) IsFollowed(userId, objectId string) (bool, error) {
|
||||
activityType, _, _, err := ar.activityRepo.GetActivityTypeByObjID(nil, objectId, "follow")
|
||||
func (ar *FollowRepo) IsFollowed(userID, objectID string) (bool, error) {
|
||||
activityType, _, _, err := ar.activityRepo.GetActivityTypeByObjID(context.TODO(), objectID, "follow")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
at := &entity.Activity{}
|
||||
has, err := ar.data.DB.Where("user_id = ? AND object_id = ? AND activity_type = ?", userId, objectId, activityType).Get(at)
|
||||
has, err := ar.data.DB.Where("user_id = ? AND object_id = ? AND activity_type = ?", userID, objectID, activityType).Get(at)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -6,13 +6,11 @@ import (
|
|||
"github.com/answerdev/answer/internal/base/data"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/service/activity_common"
|
||||
"github.com/answerdev/answer/internal/service/unique"
|
||||
)
|
||||
|
||||
// VoteRepo activity repository
|
||||
type VoteRepo struct {
|
||||
data *data.Data
|
||||
uniqueIDRepo unique.UniqueIDRepo
|
||||
activityRepo activity_common.ActivityRepo
|
||||
}
|
||||
|
||||
|
@ -24,11 +22,14 @@ func NewVoteRepo(data *data.Data, activityRepo activity_common.ActivityRepo) act
|
|||
}
|
||||
}
|
||||
|
||||
func (vr *VoteRepo) GetVoteStatus(ctx context.Context, objectId, userId string) (status string) {
|
||||
func (vr *VoteRepo) GetVoteStatus(ctx context.Context, objectID, userID string) (status string) {
|
||||
for _, action := range []string{"vote_up", "vote_down"} {
|
||||
at := &entity.Activity{}
|
||||
activityType, _, _, err := vr.activityRepo.GetActivityTypeByObjID(ctx, objectId, action)
|
||||
has, err := vr.data.DB.Where("object_id =? AND cancelled=0 AND activity_type=? AND user_id=?", objectId, activityType, userId).Get(at)
|
||||
activityType, _, _, err := vr.activityRepo.GetActivityTypeByObjID(ctx, objectID, action)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
has, err := vr.data.DB.Where("object_id =? AND cancelled=0 AND activity_type=? AND user_id=?", objectID, activityType, userID).Get(at)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -37,14 +37,14 @@ func NewActivityRepo(
|
|||
}
|
||||
}
|
||||
|
||||
func (ar *ActivityRepo) GetActivityTypeByObjID(ctx context.Context, objectId string, action string) (activityType, rank, hasRank int, err error) {
|
||||
objectKey, err := obj.GetObjectTypeStrByObjectID(objectId)
|
||||
func (ar *ActivityRepo) GetActivityTypeByObjID(ctx context.Context, objectID string, action string) (activityType, rank, hasRank int, err error) {
|
||||
objectKey, err := obj.GetObjectTypeStrByObjectID(objectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
confKey := fmt.Sprintf("%s.%s", objectKey, action)
|
||||
activityType, err = ar.configRepo.GetConfigType(confKey)
|
||||
activityType, _ = ar.configRepo.GetConfigType(confKey)
|
||||
|
||||
rank, err = ar.configRepo.GetInt(confKey)
|
||||
hasRank = 0
|
||||
|
@ -64,7 +64,8 @@ func (ar *ActivityRepo) GetActivityTypeByObjKey(ctx context.Context, objectKey,
|
|||
}
|
||||
|
||||
func (ar *ActivityRepo) GetActivity(ctx context.Context, session *xorm.Session,
|
||||
objectID, userID string, activityType int) (existsActivity *entity.Activity, exist bool, err error) {
|
||||
objectID, userID string, activityType int,
|
||||
) (existsActivity *entity.Activity, exist bool, err error) {
|
||||
existsActivity = &entity.Activity{}
|
||||
exist, err = session.
|
||||
Where(builder.Eq{"object_id": objectID}).
|
||||
|
|
|
@ -2,7 +2,10 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"xorm.io/builder"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/data"
|
||||
|
@ -89,7 +92,8 @@ func (ar *answerRepo) UpdateAnswerStatus(ctx context.Context, answer *entity.Ans
|
|||
|
||||
// GetAnswer get answer one
|
||||
func (ar *answerRepo) GetAnswer(ctx context.Context, id string) (
|
||||
answer *entity.Answer, exist bool, err error) {
|
||||
answer *entity.Answer, exist bool, err error,
|
||||
) {
|
||||
answer = &entity.Answer{}
|
||||
exist, err = ar.data.DB.ID(id).Get(answer)
|
||||
if err != nil {
|
||||
|
@ -120,20 +124,20 @@ func (ar *answerRepo) GetAnswerPage(ctx context.Context, page, pageSize int, ans
|
|||
|
||||
// UpdateAdopted
|
||||
// If no answer is selected, the answer id can be 0
|
||||
func (ar *answerRepo) UpdateAdopted(ctx context.Context, id string, questionId string) error {
|
||||
if questionId == "" {
|
||||
func (ar *answerRepo) UpdateAdopted(ctx context.Context, id string, questionID string) error {
|
||||
if questionID == "" {
|
||||
return nil
|
||||
}
|
||||
var data entity.Answer
|
||||
data.ID = id
|
||||
|
||||
data.Adopted = schema.Answer_Adopted_Failed
|
||||
_, err := ar.data.DB.Where("question_id =?", questionId).Cols("adopted").Update(&data)
|
||||
data.Adopted = schema.AnswerAdoptedFailed
|
||||
_, err := ar.data.DB.Where("question_id =?", questionID).Cols("adopted").Update(&data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if id != "0" {
|
||||
data.Adopted = schema.Answer_Adopted_Enable
|
||||
data.Adopted = schema.AnswerAdoptedEnable
|
||||
_, err = ar.data.DB.Where("id = ?", id).Cols("adopted").Update(&data)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
@ -152,9 +156,9 @@ func (ar *answerRepo) GetByID(ctx context.Context, id string) (*entity.Answer, b
|
|||
return &resp, has, nil
|
||||
}
|
||||
|
||||
func (ar *answerRepo) GetByUserIdQuestionId(ctx context.Context, userId string, questionId string) (*entity.Answer, bool, error) {
|
||||
func (ar *answerRepo) GetByUserIDQuestionID(ctx context.Context, userID string, questionID string) (*entity.Answer, bool, error) {
|
||||
var resp entity.Answer
|
||||
has, err := ar.data.DB.Where("question_id =? and user_id = ?", questionId, userId).Get(&resp)
|
||||
has, err := ar.data.DB.Where("question_id =? and user_id = ?", questionID, userID).Get(&resp)
|
||||
if err != nil {
|
||||
return &resp, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -172,7 +176,7 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc
|
|||
search.Page = 0
|
||||
}
|
||||
if search.PageSize == 0 {
|
||||
search.PageSize = constant.Default_PageSize
|
||||
search.PageSize = constant.DefaultPageSize
|
||||
}
|
||||
offset := search.Page * search.PageSize
|
||||
session := ar.data.DB.Where("")
|
||||
|
@ -183,14 +187,14 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc
|
|||
if len(search.UserID) > 0 {
|
||||
session = session.And("user_id = ?", search.UserID)
|
||||
}
|
||||
if search.Order == entity.Answer_Search_OrderBy_Time {
|
||||
switch search.Order {
|
||||
case entity.AnswerSearchOrderByTime:
|
||||
session = session.OrderBy("created_at desc")
|
||||
} else if search.Order == entity.Answer_Search_OrderBy_Vote {
|
||||
case entity.AnswerSearchOrderByVote:
|
||||
session = session.OrderBy("vote_count desc")
|
||||
} else {
|
||||
default:
|
||||
session = session.OrderBy("adopted desc,vote_count desc")
|
||||
}
|
||||
|
||||
session = session.And("status = ?", entity.AnswerStatusAvailable)
|
||||
|
||||
session = session.Limit(search.PageSize, offset)
|
||||
|
@ -202,11 +206,16 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc
|
|||
}
|
||||
|
||||
func (ar *answerRepo) CmsSearchList(ctx context.Context, search *entity.CmsAnswerSearch) ([]*entity.Answer, int64, error) {
|
||||
var count int64
|
||||
var err error
|
||||
if search.Status == 0 {
|
||||
search.Status = 1
|
||||
}
|
||||
var (
|
||||
count int64
|
||||
err error
|
||||
session = ar.data.DB.Table([]string{entity.Answer{}.TableName(), "a"}).Select("a.*")
|
||||
)
|
||||
|
||||
session.Where(builder.Eq{
|
||||
"a.status": search.Status,
|
||||
})
|
||||
|
||||
rows := make([]*entity.Answer, 0)
|
||||
if search.Page > 0 {
|
||||
search.Page = search.Page - 1
|
||||
|
@ -214,13 +223,44 @@ func (ar *answerRepo) CmsSearchList(ctx context.Context, search *entity.CmsAnswe
|
|||
search.Page = 0
|
||||
}
|
||||
if search.PageSize == 0 {
|
||||
search.PageSize = constant.Default_PageSize
|
||||
search.PageSize = constant.DefaultPageSize
|
||||
}
|
||||
|
||||
// search by question title like or answer id
|
||||
if len(search.Query) > 0 {
|
||||
// check id search
|
||||
var (
|
||||
idSearch = false
|
||||
id = ""
|
||||
)
|
||||
|
||||
if strings.Contains(search.Query, "id:") {
|
||||
idSearch = true
|
||||
id = strings.TrimSpace(strings.TrimPrefix(search.Query, "id:"))
|
||||
for _, r := range id {
|
||||
if !unicode.IsDigit(r) {
|
||||
idSearch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if idSearch {
|
||||
session.And(builder.Eq{
|
||||
"id": id,
|
||||
})
|
||||
} else {
|
||||
session.Join("LEFT", []string{entity.Question{}.TableName(), "q"}, "q.id = a.question_id")
|
||||
session.And(builder.Like{
|
||||
"q.title", search.Query,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
offset := search.Page * search.PageSize
|
||||
session := ar.data.DB.Where("")
|
||||
session = session.And("status =?", search.Status)
|
||||
session = session.OrderBy("updated_at desc")
|
||||
session = session.Limit(search.PageSize, offset)
|
||||
session.
|
||||
OrderBy("a.updated_at desc").
|
||||
Limit(search.PageSize, offset)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
return rows, count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
|
|
@ -37,7 +37,7 @@ func (cr *collectionGroupRepo) AddCollectionGroup(ctx context.Context, collectio
|
|||
func (cr *collectionGroupRepo) AddCollectionDefaultGroup(ctx context.Context, userID string) (collectionGroup *entity.CollectionGroup, err error) {
|
||||
defaultGroup := &entity.CollectionGroup{
|
||||
Name: "default",
|
||||
DefaultGroup: schema.CG_DEFAULT,
|
||||
DefaultGroup: schema.CGDefault,
|
||||
UserID: userID,
|
||||
}
|
||||
_, err = cr.data.DB.Insert(defaultGroup)
|
||||
|
@ -60,7 +60,8 @@ func (cr *collectionGroupRepo) UpdateCollectionGroup(ctx context.Context, collec
|
|||
|
||||
// GetCollectionGroup get collection group one
|
||||
func (cr *collectionGroupRepo) GetCollectionGroup(ctx context.Context, id string) (
|
||||
collectionGroup *entity.CollectionGroup, exist bool, err error) {
|
||||
collectionGroup *entity.CollectionGroup, exist bool, err error,
|
||||
) {
|
||||
collectionGroup = &entity.CollectionGroup{}
|
||||
exist, err = cr.data.DB.ID(id).Get(collectionGroup)
|
||||
if err != nil {
|
||||
|
@ -84,9 +85,9 @@ func (cr *collectionGroupRepo) GetCollectionGroupPage(ctx context.Context, page,
|
|||
return
|
||||
}
|
||||
|
||||
func (cr *collectionGroupRepo) GetDefaultID(ctx context.Context, userId string) (collectionGroup *entity.CollectionGroup, has bool, err error) {
|
||||
func (cr *collectionGroupRepo) GetDefaultID(ctx context.Context, userID string) (collectionGroup *entity.CollectionGroup, has bool, err error) {
|
||||
collectionGroup = &entity.CollectionGroup{}
|
||||
has, err = cr.data.DB.Where("user_id =? and default_group = ?", userId, schema.CG_DEFAULT).Get(collectionGroup)
|
||||
has, err = cr.data.DB.Where("user_id =? and default_group = ?", userID, schema.CGDefault).Get(collectionGroup)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
return
|
||||
|
|
|
@ -74,9 +74,9 @@ func (cr *collectionRepo) GetCollectionList(ctx context.Context, collection *ent
|
|||
}
|
||||
|
||||
// GetOneByObjectIDAndUser get one by object TagID and user
|
||||
func (cr *collectionRepo) GetOneByObjectIDAndUser(ctx context.Context, userId string, objectId string) (collection *entity.Collection, exist bool, err error) {
|
||||
func (cr *collectionRepo) GetOneByObjectIDAndUser(ctx context.Context, userID string, objectID string) (collection *entity.Collection, exist bool, err error) {
|
||||
collection = &entity.Collection{}
|
||||
exist, err = cr.data.DB.Where("user_id = ? and object_id = ?", userId, objectId).Get(collection)
|
||||
exist, err = cr.data.DB.Where("user_id = ? and object_id = ?", userID, objectID).Get(collection)
|
||||
if err != nil {
|
||||
return nil, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -84,9 +84,9 @@ func (cr *collectionRepo) GetOneByObjectIDAndUser(ctx context.Context, userId st
|
|||
}
|
||||
|
||||
// SearchByObjectIDsAndUser search by object IDs and user
|
||||
func (cr *collectionRepo) SearchByObjectIDsAndUser(ctx context.Context, userId string, objectIds []string) ([]*entity.Collection, error) {
|
||||
func (cr *collectionRepo) SearchByObjectIDsAndUser(ctx context.Context, userID string, objectIDs []string) ([]*entity.Collection, error) {
|
||||
collectionList := make([]*entity.Collection, 0)
|
||||
err := cr.data.DB.Where("user_id = ?", userId).In("object_id", objectIds).Find(&collectionList)
|
||||
err := cr.data.DB.Where("user_id = ?", userID).In("object_id", objectIDs).Find(&collectionList)
|
||||
if err != nil {
|
||||
return collectionList, err
|
||||
}
|
||||
|
@ -94,9 +94,9 @@ func (cr *collectionRepo) SearchByObjectIDsAndUser(ctx context.Context, userId s
|
|||
}
|
||||
|
||||
// CountByObjectID count by object TagID
|
||||
func (cr *collectionRepo) CountByObjectID(ctx context.Context, objectId string) (total int64, err error) {
|
||||
func (cr *collectionRepo) CountByObjectID(ctx context.Context, objectID string) (total int64, err error) {
|
||||
collection := &entity.Collection{}
|
||||
total, err = cr.data.DB.Where("object_id = ?", objectId).Count(collection)
|
||||
total, err = cr.data.DB.Where("object_id = ?", objectID).Count(collection)
|
||||
if err != nil {
|
||||
return 0, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -105,7 +105,6 @@ func (cr *collectionRepo) CountByObjectID(ctx context.Context, objectId string)
|
|||
|
||||
// GetCollectionPage get collection page
|
||||
func (cr *collectionRepo) GetCollectionPage(ctx context.Context, page, pageSize int, collection *entity.Collection) (collectionList []*entity.Collection, total int64, err error) {
|
||||
|
||||
collectionList = make([]*entity.Collection, 0)
|
||||
|
||||
session := cr.data.DB.NewSession()
|
||||
|
@ -124,9 +123,9 @@ func (cr *collectionRepo) GetCollectionPage(ctx context.Context, page, pageSize
|
|||
}
|
||||
|
||||
// SearchObjectCollected check object is collected or not
|
||||
func (cr *collectionRepo) SearchObjectCollected(ctx context.Context, userId string, objectIds []string) (map[string]bool, error) {
|
||||
func (cr *collectionRepo) SearchObjectCollected(ctx context.Context, userID string, objectIds []string) (map[string]bool, error) {
|
||||
collectedMap := make(map[string]bool)
|
||||
list, err := cr.SearchByObjectIDsAndUser(ctx, userId, objectIds)
|
||||
list, err := cr.SearchByObjectIDsAndUser(ctx, userID, objectIds)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
return collectedMap, err
|
||||
|
@ -148,7 +147,7 @@ func (cr *collectionRepo) SearchList(ctx context.Context, search *entity.Collect
|
|||
search.Page = 0
|
||||
}
|
||||
if search.PageSize == 0 {
|
||||
search.PageSize = constant.Default_PageSize
|
||||
search.PageSize = constant.DefaultPageSize
|
||||
}
|
||||
offset := search.Page * search.PageSize
|
||||
session := cr.data.DB.Where("")
|
||||
|
|
|
@ -69,7 +69,8 @@ func (cr *commentRepo) UpdateComment(ctx context.Context, comment *entity.Commen
|
|||
|
||||
// GetComment get comment one
|
||||
func (cr *commentRepo) GetComment(ctx context.Context, commentID string) (
|
||||
comment *entity.Comment, exist bool, err error) {
|
||||
comment *entity.Comment, exist bool, err error,
|
||||
) {
|
||||
comment = &entity.Comment{}
|
||||
exist, err = cr.data.DB.ID(commentID).Get(comment)
|
||||
if err != nil {
|
||||
|
@ -80,7 +81,8 @@ func (cr *commentRepo) GetComment(ctx context.Context, commentID string) (
|
|||
|
||||
// GetCommentPage get comment page
|
||||
func (cr *commentRepo) GetCommentPage(ctx context.Context, commentQuery *comment.CommentQuery) (
|
||||
commentList []*entity.Comment, total int64, err error) {
|
||||
commentList []*entity.Comment, total int64, err error,
|
||||
) {
|
||||
commentList = make([]*entity.Comment, 0)
|
||||
|
||||
session := cr.data.DB.NewSession()
|
||||
|
|
|
@ -37,15 +37,13 @@ func (cr *CommonRepo) GetRootObjectID(objectID string) (rootObjectID string, err
|
|||
exist, err = cr.data.DB.ID(objectID).Get(&answer)
|
||||
if !exist {
|
||||
err = errors.BadRequest(reason.ObjectNotFound)
|
||||
} else {
|
||||
objectID = answer.QuestionID
|
||||
}
|
||||
case "comment":
|
||||
exist, err = cr.data.DB.ID(objectID).Get(&comment)
|
||||
exist, _ = cr.data.DB.ID(objectID).Get(&comment)
|
||||
if !exist {
|
||||
err = errors.BadRequest(reason.ObjectNotFound)
|
||||
} else {
|
||||
objectID, err = cr.GetRootObjectID(comment.ObjectID)
|
||||
_, err = cr.GetRootObjectID(comment.ObjectID)
|
||||
}
|
||||
default:
|
||||
rootObjectID = objectID
|
||||
|
@ -72,7 +70,7 @@ func (cr *CommonRepo) GetObjectIDMap(objectID string) (objectIDMap map[string]st
|
|||
}
|
||||
switch objectType {
|
||||
case "answer":
|
||||
exist, err = cr.data.DB.ID(objectID).Get(&answer)
|
||||
exist, _ = cr.data.DB.ID(objectID).Get(&answer)
|
||||
if !exist {
|
||||
err = errors.BadRequest(reason.ObjectNotFound)
|
||||
} else {
|
||||
|
@ -80,7 +78,7 @@ func (cr *CommonRepo) GetObjectIDMap(objectID string) (objectIDMap map[string]st
|
|||
ID = answer.ID
|
||||
}
|
||||
case "comment":
|
||||
exist, err = cr.data.DB.ID(objectID).Get(&comment)
|
||||
exist, _ = cr.data.DB.ID(objectID).Get(&comment)
|
||||
if !exist {
|
||||
err = errors.BadRequest(reason.ObjectNotFound)
|
||||
} else {
|
||||
|
|
|
@ -102,7 +102,7 @@ func (nr *notificationRepo) SearchList(ctx context.Context, search *schema.Notif
|
|||
search.Page = 0
|
||||
}
|
||||
if search.PageSize == 0 {
|
||||
search.PageSize = constant.Default_PageSize
|
||||
search.PageSize = constant.DefaultPageSize
|
||||
}
|
||||
offset := search.Page * search.PageSize
|
||||
session := nr.data.DB.Where("")
|
||||
|
|
|
@ -2,7 +2,10 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"xorm.io/builder"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/data"
|
||||
|
@ -64,27 +67,27 @@ func (qr *questionRepo) UpdateQuestion(ctx context.Context, question *entity.Que
|
|||
return
|
||||
}
|
||||
|
||||
func (qr *questionRepo) UpdatePvCount(ctx context.Context, questionId string) (err error) {
|
||||
func (qr *questionRepo) UpdatePvCount(ctx context.Context, questionID string) (err error) {
|
||||
question := &entity.Question{}
|
||||
_, err = qr.data.DB.Where("id =?", questionId).Incr("view_count", 1).Update(question)
|
||||
_, err = qr.data.DB.Where("id =?", questionID).Incr("view_count", 1).Update(question)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qr *questionRepo) UpdateAnswerCount(ctx context.Context, questionId string, num int) (err error) {
|
||||
func (qr *questionRepo) UpdateAnswerCount(ctx context.Context, questionID string, num int) (err error) {
|
||||
question := &entity.Question{}
|
||||
_, err = qr.data.DB.Where("id =?", questionId).Incr("answer_count", num).Update(question)
|
||||
_, err = qr.data.DB.Where("id =?", questionID).Incr("answer_count", num).Update(question)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qr *questionRepo) UpdateCollectionCount(ctx context.Context, questionId string, num int) (err error) {
|
||||
func (qr *questionRepo) UpdateCollectionCount(ctx context.Context, questionID string, num int) (err error) {
|
||||
question := &entity.Question{}
|
||||
_, err = qr.data.DB.Where("id =?", questionId).Incr("collection_count", num).Update(question)
|
||||
_, err = qr.data.DB.Where("id =?", questionID).Incr("collection_count", num).Update(question)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -119,7 +122,8 @@ func (qr *questionRepo) UpdateLastAnswer(ctx context.Context, question *entity.Q
|
|||
|
||||
// GetQuestion get question one
|
||||
func (qr *questionRepo) GetQuestion(ctx context.Context, id string) (
|
||||
question *entity.Question, exist bool, err error) {
|
||||
question *entity.Question, exist bool, err error,
|
||||
) {
|
||||
question = &entity.Question{}
|
||||
question.ID = id
|
||||
exist, err = qr.data.DB.Where("id = ?", id).Get(question)
|
||||
|
@ -179,7 +183,7 @@ func (qr *questionRepo) SearchList(ctx context.Context, search *schema.QuestionS
|
|||
search.Page = 0
|
||||
}
|
||||
if search.PageSize == 0 {
|
||||
search.PageSize = constant.Default_PageSize
|
||||
search.PageSize = constant.DefaultPageSize
|
||||
}
|
||||
offset := search.Page * search.PageSize
|
||||
session := qr.data.DB.Table("question")
|
||||
|
@ -187,7 +191,7 @@ func (qr *questionRepo) SearchList(ctx context.Context, search *schema.QuestionS
|
|||
if len(search.TagIDs) > 0 {
|
||||
session = session.Join("LEFT", "tag_rel", "question.id = tag_rel.object_id")
|
||||
session = session.And("tag_rel.tag_id =?", search.TagIDs[0])
|
||||
//session = session.In("tag_rel.tag_id ", search.TagIDs)
|
||||
// session = session.In("tag_rel.tag_id ", search.TagIDs)
|
||||
session = session.And("tag_rel.status =?", entity.TagRelStatusAvailable)
|
||||
}
|
||||
|
||||
|
@ -199,8 +203,8 @@ func (qr *questionRepo) SearchList(ctx context.Context, search *schema.QuestionS
|
|||
// if search.Status > 0 {
|
||||
// session = session.And("question.status = ?", search.Status)
|
||||
// }
|
||||
//switch
|
||||
//newest, active,frequent,score,unanswered
|
||||
// switch
|
||||
// newest, active,frequent,score,unanswered
|
||||
switch search.Order {
|
||||
case "newest":
|
||||
session = session.OrderBy("question.created_at desc")
|
||||
|
@ -225,8 +229,16 @@ func (qr *questionRepo) SearchList(ctx context.Context, search *schema.QuestionS
|
|||
}
|
||||
|
||||
func (qr *questionRepo) CmsSearchList(ctx context.Context, search *schema.CmsQuestionSearch) ([]*entity.Question, int64, error) {
|
||||
var count int64
|
||||
var err error
|
||||
var (
|
||||
count int64
|
||||
err error
|
||||
session = qr.data.DB.Table("question")
|
||||
)
|
||||
|
||||
session.Where(builder.Eq{
|
||||
"status": search.Status,
|
||||
})
|
||||
|
||||
rows := make([]*entity.Question, 0)
|
||||
if search.Page > 0 {
|
||||
search.Page = search.Page - 1
|
||||
|
@ -234,13 +246,42 @@ func (qr *questionRepo) CmsSearchList(ctx context.Context, search *schema.CmsQue
|
|||
search.Page = 0
|
||||
}
|
||||
if search.PageSize == 0 {
|
||||
search.PageSize = constant.Default_PageSize
|
||||
search.PageSize = constant.DefaultPageSize
|
||||
}
|
||||
|
||||
// search by question title like or question id
|
||||
if len(search.Query) > 0 {
|
||||
// check id search
|
||||
var (
|
||||
idSearch = false
|
||||
id = ""
|
||||
)
|
||||
if strings.Contains(search.Query, "id:") {
|
||||
idSearch = true
|
||||
id = strings.TrimSpace(strings.TrimPrefix(search.Query, "id:"))
|
||||
for _, r := range id {
|
||||
if !unicode.IsDigit(r) {
|
||||
idSearch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if idSearch {
|
||||
session.And(builder.Eq{
|
||||
"id": id,
|
||||
})
|
||||
} else {
|
||||
session.And(builder.Like{
|
||||
"title", search.Query,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
offset := search.Page * search.PageSize
|
||||
session := qr.data.DB.Table("question")
|
||||
session = session.And("status =?", search.Status)
|
||||
session = session.OrderBy("updated_at desc")
|
||||
session = session.Limit(search.PageSize, offset)
|
||||
|
||||
session.OrderBy("updated_at desc").
|
||||
Limit(search.PageSize, offset)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
|
|
@ -34,26 +34,28 @@ func NewUserRankRepo(data *data.Data, configRepo config.ConfigRepo) rank.UserRan
|
|||
// session is need provider, it means this action must be success or failure
|
||||
// if outer action is failed then this action is need rollback
|
||||
func (ur *UserRankRepo) TriggerUserRank(ctx context.Context,
|
||||
session *xorm.Session, userId string, deltaRank int, activityType int) (isReachStandard bool, err error) {
|
||||
session *xorm.Session, userID string, deltaRank int, activityType int,
|
||||
) (isReachStandard bool, err error) {
|
||||
if deltaRank == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if deltaRank < 0 {
|
||||
// if user rank is lower than 1 after this action, then user rank will be set to 1 only.
|
||||
isReachMin, err := ur.checkUserMinRank(ctx, session, userId, activityType)
|
||||
var isReachMin bool
|
||||
isReachMin, err = ur.checkUserMinRank(ctx, session, userID, activityType)
|
||||
if err != nil {
|
||||
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
if isReachMin {
|
||||
_, err = session.Where(builder.Eq{"id": userId}).Update(&entity.User{Rank: 1})
|
||||
_, err = session.Where(builder.Eq{"id": userID}).Update(&entity.User{Rank: 1})
|
||||
if err != nil {
|
||||
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
isReachStandard, err = ur.checkUserTodayRank(ctx, session, userId, activityType)
|
||||
isReachStandard, err = ur.checkUserTodayRank(ctx, session, userID, activityType)
|
||||
if err != nil {
|
||||
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -61,7 +63,7 @@ func (ur *UserRankRepo) TriggerUserRank(ctx context.Context,
|
|||
return isReachStandard, nil
|
||||
}
|
||||
}
|
||||
_, err = session.Where(builder.Eq{"id": userId}).Incr("`rank`", deltaRank).Update(&entity.User{})
|
||||
_, err = session.Where(builder.Eq{"id": userID}).Incr("`rank`", deltaRank).Update(&entity.User{})
|
||||
if err != nil {
|
||||
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -69,7 +71,8 @@ func (ur *UserRankRepo) TriggerUserRank(ctx context.Context,
|
|||
}
|
||||
|
||||
func (ur *UserRankRepo) checkUserMinRank(ctx context.Context, session *xorm.Session, userID string, deltaRank int) (
|
||||
isReachStandard bool, err error) {
|
||||
isReachStandard bool, err error,
|
||||
) {
|
||||
bean := &entity.User{ID: userID}
|
||||
_, err = session.Select("rank").Get(bean)
|
||||
if err != nil {
|
||||
|
@ -83,11 +86,13 @@ func (ur *UserRankRepo) checkUserMinRank(ctx context.Context, session *xorm.Sess
|
|||
}
|
||||
|
||||
func (ur *UserRankRepo) checkUserTodayRank(ctx context.Context,
|
||||
session *xorm.Session, userID string, activityType int) (isReachStandard bool, err error) {
|
||||
session *xorm.Session, userID string, activityType int,
|
||||
) (isReachStandard bool, err error) {
|
||||
// exclude daily rank
|
||||
exclude, err := ur.configRepo.GetArrayString("daily_rank_limit.exclude")
|
||||
exclude, _ := ur.configRepo.GetArrayString("daily_rank_limit.exclude")
|
||||
for _, item := range exclude {
|
||||
excludeActivityType, err := ur.configRepo.GetInt(item)
|
||||
var excludeActivityType int
|
||||
excludeActivityType, err = ur.configRepo.GetInt(item)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -123,14 +128,15 @@ func (ur *UserRankRepo) checkUserTodayRank(ctx context.Context,
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (ur *UserRankRepo) UserRankPage(ctx context.Context, userId string, page, pageSize int) (
|
||||
rankPage []*entity.Activity, total int64, err error) {
|
||||
func (ur *UserRankRepo) UserRankPage(ctx context.Context, userID string, page, pageSize int) (
|
||||
rankPage []*entity.Activity, total int64, err error,
|
||||
) {
|
||||
rankPage = make([]*entity.Activity, 0)
|
||||
|
||||
session := ur.data.DB.Where(builder.Eq{"has_rank": 1}.And(builder.Eq{"cancelled": 0}))
|
||||
session.Desc("created_at")
|
||||
|
||||
cond := &entity.Activity{UserID: userId}
|
||||
cond := &entity.Activity{UserID: userID}
|
||||
total, err = pager.Help(page, pageSize, &rankPage, cond, session)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
|
|
@ -86,7 +86,8 @@ func (ar *reportRepo) GetByID(ctx context.Context, id string) (report entity.Rep
|
|||
func (ar *reportRepo) UpdateByID(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
handleData entity.Report) (err error) {
|
||||
handleData entity.Report,
|
||||
) (err error) {
|
||||
_, err = ar.data.DB.ID(id).Update(&handleData)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
|
|
@ -81,7 +81,8 @@ func (rr *revisionRepo) UpdateObjectRevisionId(ctx context.Context, revision *en
|
|||
|
||||
// GetRevision get revision one
|
||||
func (rr *revisionRepo) GetRevision(ctx context.Context, id string) (
|
||||
revision *entity.Revision, exist bool, err error) {
|
||||
revision *entity.Revision, exist bool, err error,
|
||||
) {
|
||||
revision = &entity.Revision{}
|
||||
exist, err = rr.data.DB.ID(id).Get(revision)
|
||||
if err != nil {
|
||||
|
@ -92,7 +93,8 @@ func (rr *revisionRepo) GetRevision(ctx context.Context, id string) (
|
|||
|
||||
// GetLastRevisionByObjectID get object's last revision by object TagID
|
||||
func (rr *revisionRepo) GetLastRevisionByObjectID(ctx context.Context, objectID string) (
|
||||
revision *entity.Revision, exist bool, err error) {
|
||||
revision *entity.Revision, exist bool, err error,
|
||||
) {
|
||||
revision = &entity.Revision{}
|
||||
exist, err = rr.data.DB.Where("object_id = ?", objectID).OrderBy("create_time DESC").Get(revision)
|
||||
if err != nil {
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
q_fields = []string{
|
||||
qFields = []string{
|
||||
"`question`.`id`",
|
||||
"`question`.`id` as `question_id`",
|
||||
"`title`",
|
||||
|
@ -34,7 +34,7 @@ var (
|
|||
"`question`.`status` as `status`",
|
||||
"`post_update_time`",
|
||||
}
|
||||
a_fields = []string{
|
||||
aFields = []string{
|
||||
"`answer`.`id` as `id`",
|
||||
"`question_id`",
|
||||
"`question`.`title` as `title`",
|
||||
|
@ -70,8 +70,8 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagID,
|
|||
var (
|
||||
b *builder.Builder
|
||||
ub *builder.Builder
|
||||
qfs = q_fields
|
||||
afs = a_fields
|
||||
qfs = qFields
|
||||
afs = aFields
|
||||
argsQ = []interface{}{}
|
||||
argsA = []interface{}{}
|
||||
)
|
||||
|
@ -141,11 +141,11 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagID,
|
|||
|
||||
b = b.Union("all", ub)
|
||||
|
||||
querySql, _, err := builder.MySQL().Select("*").From(b, "t").OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
|
||||
querySQL, _, err := builder.MySQL().Select("*").From(b, "t").OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
countSql, _, err := builder.MySQL().Select("count(*) total").From(b, "c").ToSQL()
|
||||
countSQL, _, err := builder.MySQL().Select("count(*) total").From(b, "c").ToSQL()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -153,11 +153,11 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagID,
|
|||
queryArgs := []interface{}{}
|
||||
countArgs := []interface{}{}
|
||||
|
||||
queryArgs = append(queryArgs, querySql)
|
||||
queryArgs = append(queryArgs, querySQL)
|
||||
queryArgs = append(queryArgs, argsQ...)
|
||||
queryArgs = append(queryArgs, argsA...)
|
||||
|
||||
countArgs = append(countArgs, countSql)
|
||||
countArgs = append(countArgs, countSQL)
|
||||
countArgs = append(countArgs, argsQ...)
|
||||
countArgs = append(countArgs, argsA...)
|
||||
|
||||
|
@ -182,7 +182,7 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagID,
|
|||
// SearchQuestions search question data
|
||||
func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, limitNoAccepted bool, answers, page, size int, order string) (resp []schema.SearchResp, total int64, err error) {
|
||||
var (
|
||||
qfs = q_fields
|
||||
qfs = qFields
|
||||
args = []interface{}{}
|
||||
)
|
||||
if order == "relevance" {
|
||||
|
@ -223,18 +223,18 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, limit
|
|||
queryArgs := []interface{}{}
|
||||
countArgs := []interface{}{}
|
||||
|
||||
querySql, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
|
||||
querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
countSql, _, err := builder.MySQL().Select("count(*) total").From(b, "c").ToSQL()
|
||||
countSQL, _, err := builder.MySQL().Select("count(*) total").From(b, "c").ToSQL()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
queryArgs = append(queryArgs, querySql)
|
||||
queryArgs = append(queryArgs, querySQL)
|
||||
queryArgs = append(queryArgs, args...)
|
||||
|
||||
countArgs = append(countArgs, countSql)
|
||||
countArgs = append(countArgs, countSQL)
|
||||
countArgs = append(countArgs, args...)
|
||||
|
||||
res, err := sr.data.DB.Query(queryArgs...)
|
||||
|
@ -250,10 +250,6 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, limit
|
|||
if len(tr) != 0 {
|
||||
total = converter.StringToInt64(string(tr[0]["total"]))
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
return
|
||||
}
|
||||
resp, err = sr.parseResult(ctx, res)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
@ -264,7 +260,7 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, limit
|
|||
// SearchAnswers search answer data
|
||||
func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, limitAccepted bool, questionID string, page, size int, order string) (resp []schema.SearchResp, total int64, err error) {
|
||||
var (
|
||||
afs = a_fields
|
||||
afs = aFields
|
||||
args = []interface{}{}
|
||||
)
|
||||
if order == "relevance" {
|
||||
|
@ -289,8 +285,8 @@ func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, limitAc
|
|||
}
|
||||
|
||||
if limitAccepted {
|
||||
b.Where(builder.Eq{"adopted": schema.Answer_Adopted_Enable})
|
||||
args = append(args, schema.Answer_Adopted_Enable)
|
||||
b.Where(builder.Eq{"adopted": schema.AnswerAdoptedEnable})
|
||||
args = append(args, schema.AnswerAdoptedEnable)
|
||||
}
|
||||
|
||||
if questionID != "" {
|
||||
|
@ -301,18 +297,18 @@ func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, limitAc
|
|||
queryArgs := []interface{}{}
|
||||
countArgs := []interface{}{}
|
||||
|
||||
querySql, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
|
||||
querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
countSql, _, err := builder.MySQL().Select("count(*) total").From(b, "c").ToSQL()
|
||||
countSQL, _, err := builder.MySQL().Select("count(*) total").From(b, "c").ToSQL()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
queryArgs = append(queryArgs, querySql)
|
||||
queryArgs = append(queryArgs, querySQL)
|
||||
queryArgs = append(queryArgs, args...)
|
||||
|
||||
countArgs = append(countArgs, countSql)
|
||||
countArgs = append(countArgs, countSQL)
|
||||
countArgs = append(countArgs, args...)
|
||||
|
||||
res, err := sr.data.DB.Query(queryArgs...)
|
||||
|
@ -326,10 +322,6 @@ func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, limitAc
|
|||
}
|
||||
|
||||
total = converter.StringToInt64(string(tr[0]["total"]))
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
return
|
||||
}
|
||||
resp, err = sr.parseResult(ctx, res)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
@ -438,7 +430,7 @@ func (sr *searchRepo) userBasicInfoFormat(ctx context.Context, dbinfo *entity.Us
|
|||
Avatar: dbinfo.Avatar,
|
||||
Website: dbinfo.Website,
|
||||
Location: dbinfo.Location,
|
||||
IpInfo: dbinfo.IPInfo,
|
||||
IPInfo: dbinfo.IPInfo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,24 +443,24 @@ func cutOutParsedText(parsedText string) string {
|
|||
return parsedText
|
||||
}
|
||||
|
||||
func addRelevanceField(search_fields, words, fields []string) (res []string, args []interface{}) {
|
||||
var relevanceRes = []string{}
|
||||
func addRelevanceField(searchFields, words, fields []string) (res []string, args []interface{}) {
|
||||
relevanceRes := []string{}
|
||||
args = []interface{}{}
|
||||
|
||||
for _, search_field := range search_fields {
|
||||
for _, searchField := range searchFields {
|
||||
var (
|
||||
relevance = "(LENGTH(" + search_field + ") - LENGTH(%s))"
|
||||
replacement = "REPLACE(%s, ?, '')"
|
||||
replace_field = search_field
|
||||
replaced string
|
||||
argsField = []interface{}{}
|
||||
relevance = "(LENGTH(" + searchField + ") - LENGTH(%s))"
|
||||
replacement = "REPLACE(%s, ?, '')"
|
||||
replaceField = searchField
|
||||
replaced string
|
||||
argsField = []interface{}{}
|
||||
)
|
||||
|
||||
res = fields
|
||||
for i, word := range words {
|
||||
if i == 0 {
|
||||
argsField = append(argsField, word)
|
||||
replaced = fmt.Sprintf(replacement, replace_field)
|
||||
replaced = fmt.Sprintf(replacement, replaceField)
|
||||
} else {
|
||||
argsField = append(argsField, word)
|
||||
replaced = fmt.Sprintf(replacement, replaced)
|
||||
|
|
|
@ -27,7 +27,7 @@ func (sr *siteInfoRepo) SaveByType(ctx context.Context, siteType string, data *e
|
|||
old = &entity.SiteInfo{}
|
||||
exist bool
|
||||
)
|
||||
exist, err = sr.data.DB.Where(builder.Eq{"type": siteType}).Get(old)
|
||||
exist, _ = sr.data.DB.Where(builder.Eq{"type": siteType}).Get(old)
|
||||
if exist {
|
||||
_, err = sr.data.DB.ID(old.ID).Update(data)
|
||||
if err != nil {
|
||||
|
|
|
@ -32,8 +32,8 @@ func (tr *tagListRepo) AddTagRelList(ctx context.Context, tagList []*entity.TagR
|
|||
}
|
||||
|
||||
// RemoveTagRelListByObjectID delete tag list
|
||||
func (tr *tagListRepo) RemoveTagRelListByObjectID(ctx context.Context, objectId string) (err error) {
|
||||
_, err = tr.data.DB.Where("object_id = ?", objectId).Update(&entity.TagRel{Status: entity.TagRelStatusDeleted})
|
||||
func (tr *tagListRepo) RemoveTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
|
||||
_, err = tr.data.DB.Where("object_id = ?", objectID).Update(&entity.TagRel{Status: entity.TagRelStatusDeleted})
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -50,10 +50,11 @@ func (tr *tagListRepo) RemoveTagRelListByIDs(ctx context.Context, ids []int64) (
|
|||
}
|
||||
|
||||
// GetObjectTagRelWithoutStatus get object tag relation no matter status
|
||||
func (tr *tagListRepo) GetObjectTagRelWithoutStatus(ctx context.Context, objectId, tagID string) (
|
||||
tagRel *entity.TagRel, exist bool, err error) {
|
||||
func (tr *tagListRepo) GetObjectTagRelWithoutStatus(ctx context.Context, objectID, tagID string) (
|
||||
tagRel *entity.TagRel, exist bool, err error,
|
||||
) {
|
||||
tagRel = &entity.TagRel{}
|
||||
session := tr.data.DB.Where("object_id = ?", objectId).And("tag_id = ?", tagID)
|
||||
session := tr.data.DB.Where("object_id = ?", objectID).And("tag_id = ?", tagID)
|
||||
exist, err = session.Get(tagRel)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
@ -71,9 +72,9 @@ func (tr *tagListRepo) EnableTagRelByIDs(ctx context.Context, ids []int64) (err
|
|||
}
|
||||
|
||||
// GetObjectTagRelList get object tag relation list all
|
||||
func (tr *tagListRepo) GetObjectTagRelList(ctx context.Context, objectId string) (tagListList []*entity.TagRel, err error) {
|
||||
func (tr *tagListRepo) GetObjectTagRelList(ctx context.Context, objectID string) (tagListList []*entity.TagRel, err error) {
|
||||
tagListList = make([]*entity.TagRel, 0)
|
||||
session := tr.data.DB.Where("object_id = ?", objectId)
|
||||
session := tr.data.DB.Where("object_id = ?", objectID)
|
||||
session.Where("status = ?", entity.TagRelStatusAvailable)
|
||||
err = session.Find(&tagListList)
|
||||
if err != nil {
|
||||
|
|
|
@ -34,7 +34,8 @@ func NewTagRepo(
|
|||
// AddTagList add tag
|
||||
func (tr *tagRepo) AddTagList(ctx context.Context, tagList []*entity.Tag) (err error) {
|
||||
for _, item := range tagList {
|
||||
ID, err := tr.uniqueIDRepo.GenUniqueID(ctx, item.TableName())
|
||||
var ID int64
|
||||
ID, err = tr.uniqueIDRepo.GenUniqueID(ctx, item.TableName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -128,7 +129,8 @@ func (tr *tagRepo) UpdateTagQuestionCount(ctx context.Context, tagID string, que
|
|||
|
||||
// UpdateTagSynonym update synonym tag
|
||||
func (tr *tagRepo) UpdateTagSynonym(ctx context.Context, tagSlugNameList []string, mainTagID int64,
|
||||
mainTagSlugName string) (err error) {
|
||||
mainTagSlugName string,
|
||||
) (err error) {
|
||||
bean := &entity.Tag{MainTagID: mainTagID, MainTagSlugName: mainTagSlugName}
|
||||
session := tr.data.DB.In("slug_name", tagSlugNameList).MustCols("main_tag_id", "main_tag_slug_name")
|
||||
_, err = session.Update(bean)
|
||||
|
@ -140,7 +142,8 @@ func (tr *tagRepo) UpdateTagSynonym(ctx context.Context, tagSlugNameList []strin
|
|||
|
||||
// GetTagByID get tag one
|
||||
func (tr *tagRepo) GetTagByID(ctx context.Context, tagID string) (
|
||||
tag *entity.Tag, exist bool, err error) {
|
||||
tag *entity.Tag, exist bool, err error,
|
||||
) {
|
||||
tag = &entity.Tag{}
|
||||
session := tr.data.DB.Where(builder.Eq{"id": tagID})
|
||||
session.Where(builder.Eq{"status": entity.TagStatusAvailable})
|
||||
|
@ -164,7 +167,8 @@ func (tr *tagRepo) GetTagList(ctx context.Context, tag *entity.Tag) (tagList []*
|
|||
|
||||
// GetTagPage get tag page
|
||||
func (tr *tagRepo) GetTagPage(ctx context.Context, page, pageSize int, tag *entity.Tag, queryCond string) (
|
||||
tagList []*entity.Tag, total int64, err error) {
|
||||
tagList []*entity.Tag, total int64, err error,
|
||||
) {
|
||||
tagList = make([]*entity.Tag, 0)
|
||||
session := tr.data.DB.NewSession()
|
||||
|
||||
|
|
|
@ -3,7 +3,11 @@ package user
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"xorm.io/builder"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/data"
|
||||
|
@ -29,7 +33,8 @@ func NewUserBackyardRepo(data *data.Data) user_backyard.UserBackyardRepo {
|
|||
|
||||
// UpdateUserStatus update user status
|
||||
func (ur *userBackyardRepo) UpdateUserStatus(ctx context.Context, userID string, userStatus, mailStatus int,
|
||||
email string) (err error) {
|
||||
email string,
|
||||
) (err error) {
|
||||
cond := &entity.User{Status: userStatus, MailStatus: mailStatus, EMail: email}
|
||||
switch userStatus {
|
||||
case entity.UserStatusSuspended:
|
||||
|
@ -68,16 +73,51 @@ func (ur *userBackyardRepo) GetUserInfo(ctx context.Context, userID string) (use
|
|||
}
|
||||
|
||||
// GetUserPage get user page
|
||||
func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int, user *entity.User) (users []*entity.User, total int64, err error) {
|
||||
func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int, user *entity.User, query string) (users []*entity.User, total int64, err error) {
|
||||
users = make([]*entity.User, 0)
|
||||
session := ur.data.DB.NewSession()
|
||||
if user.Status == entity.UserStatusDeleted {
|
||||
switch user.Status {
|
||||
case entity.UserStatusDeleted:
|
||||
session.Desc("deleted_at")
|
||||
} else if user.Status == entity.UserStatusSuspended {
|
||||
case entity.UserStatusSuspended:
|
||||
session.Desc("suspended_at")
|
||||
} else {
|
||||
default:
|
||||
session.Desc("created_at")
|
||||
}
|
||||
|
||||
if len(query) > 0 {
|
||||
if email, e := mail.ParseAddress(query); e == nil {
|
||||
session.And(builder.Eq{"e_mail": email.Address})
|
||||
} else {
|
||||
var (
|
||||
idSearch = false
|
||||
id = ""
|
||||
)
|
||||
|
||||
if strings.Contains(query, "id:") {
|
||||
idSearch = true
|
||||
id = strings.TrimSpace(strings.TrimPrefix(query, "id:"))
|
||||
for _, r := range id {
|
||||
if !unicode.IsDigit(r) {
|
||||
idSearch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if idSearch {
|
||||
session.And(builder.Eq{
|
||||
"id": id,
|
||||
})
|
||||
} else {
|
||||
session.And(builder.Or(
|
||||
builder.Like{"username", query},
|
||||
builder.Like{"display_name", query},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total, err = pager.Help(page, pageSize, &users, user, session)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
|
|
@ -9,44 +9,44 @@ type RemoveAnswerReq struct {
|
|||
}
|
||||
|
||||
const (
|
||||
Answer_Adopted_Failed = 1
|
||||
Answer_Adopted_Enable = 2
|
||||
AnswerAdoptedFailed = 1
|
||||
AnswerAdoptedEnable = 2
|
||||
)
|
||||
|
||||
type AnswerAddReq struct {
|
||||
QuestionId string `json:"question_id" ` // question_id
|
||||
QuestionID string `json:"question_id" ` // question_id
|
||||
Content string `json:"content" ` // content
|
||||
Html string `json:"html" ` // html
|
||||
HTML string `json:"html" ` // html
|
||||
UserID string `json:"-" ` // user_id
|
||||
}
|
||||
|
||||
type AnswerUpdateReq struct {
|
||||
ID string `json:"id"` // id
|
||||
QuestionId string `json:"question_id" ` // question_id
|
||||
QuestionID string `json:"question_id" ` // question_id
|
||||
UserID string `json:"-" ` // user_id
|
||||
Title string `json:"title" ` // title
|
||||
Content string `json:"content"` // content
|
||||
Html string `json:"html" ` // html
|
||||
EditSummary string `validate:"omitempty" json:"edit_summary"` //edit_summary
|
||||
HTML string `json:"html" ` // html
|
||||
EditSummary string `validate:"omitempty" json:"edit_summary"` // edit_summary
|
||||
}
|
||||
|
||||
type AnswerList struct {
|
||||
QuestionId string `json:"question_id" form:"question_id"` // question_id
|
||||
QuestionID string `json:"question_id" form:"question_id"` // question_id
|
||||
Order string `json:"order" form:"order"` // 1 Default 2 time
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Page int `json:"page" form:"page"` // Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` // Search page size
|
||||
LoginUserID string `json:"-" `
|
||||
}
|
||||
|
||||
type AnswerInfo struct {
|
||||
ID string `json:"id" xorm:"id"` // id
|
||||
QuestionId string `json:"question_id" xorm:"question_id"` // question_id
|
||||
QuestionID string `json:"question_id" xorm:"question_id"` // question_id
|
||||
Content string `json:"content" xorm:"content"` // content
|
||||
Html string `json:"html" xorm:"html"` // html
|
||||
HTML string `json:"html" xorm:"html"` // html
|
||||
CreateTime int64 `json:"create_time" xorm:"created"` // create_time
|
||||
UpdateTime int64 `json:"update_time" xorm:"updated"` // update_time
|
||||
Adopted int `json:"adopted"` // 1 Failed 2 Adopted
|
||||
UserId string `json:"-" `
|
||||
UserID string `json:"-" `
|
||||
UserInfo *UserBasicInfo `json:"user_info,omitempty"`
|
||||
UpdateUserInfo *UserBasicInfo `json:"update_user_info,omitempty"`
|
||||
Collected bool `json:"collected"`
|
||||
|
@ -60,12 +60,12 @@ type AnswerInfo struct {
|
|||
|
||||
type AdminAnswerInfo struct {
|
||||
ID string `json:"id"`
|
||||
QuestionId string `json:"question_id"`
|
||||
QuestionID string `json:"question_id"`
|
||||
Description string `json:"description"`
|
||||
CreateTime int64 `json:"create_time"`
|
||||
UpdateTime int64 `json:"update_time"`
|
||||
Adopted int `json:"adopted"`
|
||||
UserId string `json:"-" `
|
||||
UserID string `json:"-" `
|
||||
UserInfo *UserBasicInfo `json:"user_info"`
|
||||
VoteCount int `json:"vote_count"`
|
||||
QuestionInfo struct {
|
||||
|
|
|
@ -26,10 +26,8 @@ type GetUserPageReq struct {
|
|||
Page int `validate:"omitempty,min=1" form:"page"`
|
||||
// page size
|
||||
PageSize int `validate:"omitempty,min=1" form:"page_size"`
|
||||
// username
|
||||
Username string `validate:"omitempty,gt=0,lte=50" form:"username"`
|
||||
// email
|
||||
EMail string `validate:"omitempty,gt=0,lte=100" form:"e_mail"`
|
||||
Query string `validate:"omitempty,gt=0,lte=100" form:"query"`
|
||||
// user status
|
||||
Status string `validate:"omitempty,oneof=suspended deleted inactive" form:"status"`
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package schema
|
|||
import "time"
|
||||
|
||||
const (
|
||||
CG_DEFAULT = 1
|
||||
CG_DIY = 2
|
||||
CGDefault = 1
|
||||
CGDIY = 2
|
||||
)
|
||||
|
||||
// CollectionSwitchReq switch collection request
|
||||
|
|
|
@ -2,7 +2,7 @@ package schema
|
|||
|
||||
const (
|
||||
ForbiddenReasonTypeInactive = "inactive"
|
||||
ForbiddenReasonTypeUrlExpired = "url_expired"
|
||||
ForbiddenReasonTypeURLExpired = "url_expired"
|
||||
ForbiddenReasonTypeUserSuspended = "suspended"
|
||||
)
|
||||
|
||||
|
|
|
@ -5,12 +5,11 @@ type RemoveQuestionReq struct {
|
|||
// question id
|
||||
ID string `validate:"required" comment:"question id" json:"id"`
|
||||
UserID string `json:"-" ` // user_id
|
||||
|
||||
}
|
||||
|
||||
type CloseQuestionReq struct {
|
||||
ID string `validate:"required" comment:"question id" json:"id"`
|
||||
UserId string `json:"-" ` // user_id
|
||||
UserID string `json:"-" ` // user_id
|
||||
CloseType int `json:"close_type" ` // close_type
|
||||
CloseMsg string `json:"close_msg" ` // close_type
|
||||
}
|
||||
|
@ -26,7 +25,7 @@ type QuestionAdd struct {
|
|||
// content
|
||||
Content string `validate:"required,gte=6,lte=65535" json:"content"`
|
||||
// html
|
||||
Html string `validate:"required,gte=6,lte=65535" json:"html"`
|
||||
HTML string `validate:"required,gte=6,lte=65535" json:"html"`
|
||||
// tags
|
||||
Tags []*TagItem `validate:"required,dive" json:"tags"`
|
||||
// user id
|
||||
|
@ -41,7 +40,7 @@ type QuestionUpdate struct {
|
|||
// content
|
||||
Content string `validate:"required,gte=6,lte=65535" json:"content"`
|
||||
// html
|
||||
Html string `validate:"required,gte=6,lte=65535" json:"html"`
|
||||
HTML string `validate:"required,gte=6,lte=65535" json:"html"`
|
||||
// tags
|
||||
Tags []*TagItem `validate:"required,dive" json:"tags"`
|
||||
// edit summary
|
||||
|
@ -65,7 +64,7 @@ type QuestionInfo struct {
|
|||
ID string `json:"id" `
|
||||
Title string `json:"title" xorm:"title"` // title
|
||||
Content string `json:"content" xorm:"content"` // content
|
||||
Html string `json:"html" xorm:"html"` // html
|
||||
HTML string `json:"html" xorm:"html"` // html
|
||||
Tags []*TagResp `json:"tags" ` // tags
|
||||
ViewCount int `json:"view_count" xorm:"view_count"` // view_count
|
||||
UniqueViewCount int `json:"unique_view_count" xorm:"unique_view_count"` // unique_view_count
|
||||
|
@ -73,15 +72,15 @@ type QuestionInfo struct {
|
|||
AnswerCount int `json:"answer_count" xorm:"answer_count"` // answer count
|
||||
CollectionCount int `json:"collection_count" xorm:"collection_count"` // collection count
|
||||
FollowCount int `json:"follow_count" xorm:"follow_count"` // follow count
|
||||
AcceptedAnswerId string `json:"accepted_answer_id" ` // accepted_answer_id
|
||||
LastAnswerId string `json:"last_answer_id" ` // last_answer_id
|
||||
AcceptedAnswerID string `json:"accepted_answer_id" ` // accepted_answer_id
|
||||
LastAnswerID string `json:"last_answer_id" ` // last_answer_id
|
||||
CreateTime int64 `json:"create_time" ` // create_time
|
||||
UpdateTime int64 `json:"-"` // update_time
|
||||
PostUpdateTime int64 `json:"update_time"`
|
||||
QuestionUpdateTime int64 `json:"edit_time"`
|
||||
Status int `json:"status"`
|
||||
Operation *Operation `json:"operation,omitempty"`
|
||||
UserId string `json:"-" `
|
||||
UserID string `json:"-" `
|
||||
UserInfo *UserBasicInfo `json:"user_info"`
|
||||
UpdateUserInfo *UserBasicInfo `json:"update_user_info,omitempty"`
|
||||
LastAnsweredUserInfo *UserBasicInfo `json:"last_answered_user_info,omitempty"`
|
||||
|
@ -108,10 +107,10 @@ type AdminQuestionInfo struct {
|
|||
}
|
||||
|
||||
type Operation struct {
|
||||
Operation_Type string `json:"operation_type"`
|
||||
Operation_Description string `json:"operation_description"`
|
||||
Operation_Msg string `json:"operation_msg"`
|
||||
Operation_Time int64 `json:"operation_time"`
|
||||
OperationType string `json:"operation_type"`
|
||||
OperationDescription string `json:"operation_description"`
|
||||
OperationMsg string `json:"operation_msg"`
|
||||
OperationTime int64 `json:"operation_time"`
|
||||
}
|
||||
|
||||
type GetCloseTypeResp struct {
|
||||
|
@ -151,26 +150,27 @@ type UserQuestionInfo struct {
|
|||
AnswerCount int `json:"answer_count"`
|
||||
CollectionCount int `json:"collection_count"`
|
||||
CreateTime int `json:"create_time"`
|
||||
AcceptedAnswerId string `json:"accepted_answer_id"`
|
||||
AcceptedAnswerID string `json:"accepted_answer_id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type QuestionSearch struct {
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Order string `json:"order" form:"order"` //Search order by
|
||||
//Tags []string `json:"tags" form:"tags"` //Search tag
|
||||
Page int `json:"page" form:"page"` // Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` // Search page size
|
||||
Order string `json:"order" form:"order"` // Search order by
|
||||
// Tags []string `json:"tags" form:"tags"` // Search tag
|
||||
Tag string `json:"tag" form:"tag"` //Search tag
|
||||
TagIDs []string `json:"-" form:"-"` //Search tag
|
||||
UserName string `json:"username" form:"username"` //Search username
|
||||
TagIDs []string `json:"-" form:"-"` // Search tag
|
||||
UserName string `json:"username" form:"username"` // Search username
|
||||
UserID string `json:"-" form:"-"`
|
||||
}
|
||||
|
||||
type CmsQuestionSearch struct {
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Page int `json:"page" form:"page"` // Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` // Search page size
|
||||
Status int `json:"-" form:"-"`
|
||||
StatusStr string `json:"status" form:"status"` //Status 1 Available 2 closed 10 UserDeleted
|
||||
StatusStr string `json:"status" form:"status"` // Status 1 Available 2 closed 10 UserDeleted
|
||||
Query string `validate:"omitempty,gt=0,lte=100" json:"query" form:"query" ` //Query string
|
||||
}
|
||||
|
||||
type AdminSetQuestionStatusRequest struct {
|
||||
|
|
|
@ -107,7 +107,7 @@ func (tr *GetTagPageResp) GetExcerpt() {
|
|||
}
|
||||
|
||||
type TagChange struct {
|
||||
ObjectId string `json:"object_id"` // object_id
|
||||
ObjectID string `json:"object_id"` // object_id
|
||||
Tags []*TagItem `json:"tags"` // tags name
|
||||
// user id
|
||||
UserID string `json:"-"`
|
||||
|
|
|
@ -56,7 +56,7 @@ type GetUserResp struct {
|
|||
// bio markdown
|
||||
Bio string `json:"bio"`
|
||||
// bio html
|
||||
BioHtml string `json:"bio_html"`
|
||||
BioHTML string `json:"bio_html"`
|
||||
// website
|
||||
Website string `json:"website"`
|
||||
// location
|
||||
|
@ -73,7 +73,7 @@ type GetUserResp struct {
|
|||
|
||||
func (r *GetUserResp) GetFromUserEntity(userInfo *entity.User) {
|
||||
_ = copier.Copy(r, userInfo)
|
||||
r.Avatar = r.AvatarInfo(userInfo.Avatar)
|
||||
r.Avatar = FormatAvatarInfo(userInfo.Avatar)
|
||||
r.CreatedAt = userInfo.CreatedAt.Unix()
|
||||
r.LastLoginDate = userInfo.LastLoginDate.Unix()
|
||||
statusShow, ok := UserStatusShow[userInfo.Status]
|
||||
|
@ -103,7 +103,7 @@ func (r *GetUserToSetShowResp) GetFromUserEntity(userInfo *entity.User) {
|
|||
r.Avatar = avatarInfo
|
||||
}
|
||||
|
||||
func (us *GetUserResp) AvatarInfo(avatarJson string) string {
|
||||
func FormatAvatarInfo(avatarJson string) string {
|
||||
if avatarJson == "" {
|
||||
return ""
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ type GetOtherUserInfoByUsernameResp struct {
|
|||
// bio markdown
|
||||
Bio string `json:"bio"`
|
||||
// bio html
|
||||
BioHtml string `json:"bio_html"`
|
||||
BioHTML string `json:"bio_html"`
|
||||
// website
|
||||
Website string `json:"website"`
|
||||
// location
|
||||
|
@ -172,6 +172,9 @@ type GetOtherUserInfoByUsernameResp struct {
|
|||
|
||||
func (r *GetOtherUserInfoByUsernameResp) GetFromUserEntity(userInfo *entity.User) {
|
||||
_ = copier.Copy(r, userInfo)
|
||||
Avatar := FormatAvatarInfo(userInfo.Avatar)
|
||||
r.Avatar = Avatar
|
||||
|
||||
r.CreatedAt = userInfo.CreatedAt.Unix()
|
||||
r.LastLoginDate = userInfo.LastLoginDate.Unix()
|
||||
statusShow, ok := UserStatusShow[userInfo.Status]
|
||||
|
@ -189,20 +192,19 @@ func (r *GetOtherUserInfoByUsernameResp) GetFromUserEntity(userInfo *entity.User
|
|||
r.StatusMsg = statusMsgShow
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const (
|
||||
Mail_State_Pass = 1
|
||||
Mail_State_Verifi = 2
|
||||
MailStatePass = 1
|
||||
MailStateVerifi = 2
|
||||
|
||||
Notice_Status_On = 1
|
||||
Notice_Status_Off = 2
|
||||
NoticeStatusOn = 1
|
||||
NoticeStatusOff = 2
|
||||
|
||||
//ActionRecord ReportType
|
||||
ActionRecord_Type_Login = "login"
|
||||
ActionRecord_Type_Email = "e_mail"
|
||||
ActionRecord_Type_Find_Pass = "find_pass"
|
||||
// ActionRecord ReportType
|
||||
ActionRecordTypeLogin = "login"
|
||||
ActionRecordTypeEmail = "e_mail"
|
||||
ActionRecordTypeFindPass = "find_pass"
|
||||
)
|
||||
|
||||
var UserStatusShow = map[int]string{
|
||||
|
@ -210,6 +212,7 @@ var UserStatusShow = map[int]string{
|
|||
9: "forbidden",
|
||||
10: "deleted",
|
||||
}
|
||||
|
||||
var UserStatusShowMsg = map[int]string{
|
||||
1: "",
|
||||
9: "<strong>This user was suspended forever.</strong> This user doesn’t meet a community guideline.",
|
||||
|
@ -250,7 +253,7 @@ func (u *UserRegisterReq) Check() (errField *validator.ErrorField, err error) {
|
|||
|
||||
// UserModifyPassWordRequest
|
||||
type UserModifyPassWordRequest struct {
|
||||
UserId string `json:"-" ` // user_id
|
||||
UserID string `json:"-" ` // user_id
|
||||
OldPass string `json:"old_pass" ` // old password
|
||||
Pass string `json:"pass" ` // password
|
||||
}
|
||||
|
@ -277,13 +280,13 @@ type UpdateInfoRequest struct {
|
|||
// bio
|
||||
Bio string `validate:"omitempty,gt=0,lte=4096" json:"bio"`
|
||||
// bio
|
||||
BioHtml string `validate:"omitempty,gt=0,lte=4096" json:"bio_html"`
|
||||
BioHTML string `validate:"omitempty,gt=0,lte=4096" json:"bio_html"`
|
||||
// website
|
||||
Website string `validate:"omitempty,gt=0,lte=500" json:"website"`
|
||||
// location
|
||||
Location string `validate:"omitempty,gt=0,lte=100" json:"location"`
|
||||
// user id
|
||||
UserId string `json:"-" `
|
||||
UserID string `json:"-" `
|
||||
}
|
||||
|
||||
type AvatarInfo struct {
|
||||
|
@ -332,7 +335,7 @@ func (u *UserRePassWordRequest) Check() (errField *validator.ErrorField, err err
|
|||
}
|
||||
|
||||
type UserNoticeSetRequest struct {
|
||||
UserId string `json:"-" ` // user_id
|
||||
UserID string `json:"-" ` // user_id
|
||||
NoticeSwitch bool `json:"notice_switch" `
|
||||
}
|
||||
|
||||
|
@ -343,7 +346,7 @@ type UserNoticeSetResp struct {
|
|||
type ActionRecordReq struct {
|
||||
// action
|
||||
Action string `validate:"required,oneof=login e_mail find_pass" form:"action"`
|
||||
Ip string `json:"-"`
|
||||
IP string `json:"-"`
|
||||
}
|
||||
|
||||
type ActionRecordResp struct {
|
||||
|
@ -360,7 +363,7 @@ type UserBasicInfo struct {
|
|||
Avatar string `json:"avatar" ` // avatar
|
||||
Website string `json:"website" ` // website
|
||||
Location string `json:"location" ` // location
|
||||
IpInfo string `json:"ip_info"` // ip info
|
||||
IPInfo string `json:"ip_info"` // ip info
|
||||
Status string `json:"status"` // status
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ func NewCaptchaService(captchaRepo CaptchaRepo) *CaptchaService {
|
|||
// ActionRecord action record
|
||||
func (cs *CaptchaService) ActionRecord(ctx context.Context, req *schema.ActionRecordReq) (resp *schema.ActionRecordResp, err error) {
|
||||
resp = &schema.ActionRecordResp{}
|
||||
num, err := cs.captchaRepo.GetActionType(ctx, req.Ip, req.Action)
|
||||
num, err := cs.captchaRepo.GetActionType(ctx, req.IP, req.Action)
|
||||
if err != nil {
|
||||
num = 0
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ func (cs *CaptchaService) ActionRecord(ctx context.Context, req *schema.ActionRe
|
|||
// ActionRecordVerifyCaptcha
|
||||
// Verify that you need to enter a CAPTCHA, and that the CAPTCHA is correct
|
||||
func (cs *CaptchaService) ActionRecordVerifyCaptcha(
|
||||
ctx context.Context, actionType string, ip string, id string, VerifyValue string) bool {
|
||||
ctx context.Context, actionType string, ip string, id string, VerifyValue string,
|
||||
) bool {
|
||||
num, cahceErr := cs.captchaRepo.GetActionType(ctx, ip, actionType)
|
||||
if cahceErr != nil {
|
||||
return true
|
||||
|
|
|
@ -14,9 +14,9 @@ type AnswerRepo interface {
|
|||
GetAnswer(ctx context.Context, id string) (answer *entity.Answer, exist bool, err error)
|
||||
GetAnswerList(ctx context.Context, answer *entity.Answer) (answerList []*entity.Answer, err error)
|
||||
GetAnswerPage(ctx context.Context, page, pageSize int, answer *entity.Answer) (answerList []*entity.Answer, total int64, err error)
|
||||
UpdateAdopted(ctx context.Context, id string, questionId string) error
|
||||
UpdateAdopted(ctx context.Context, id string, questionID string) error
|
||||
GetByID(ctx context.Context, id string) (*entity.Answer, bool, error)
|
||||
GetByUserIdQuestionId(ctx context.Context, userId string, questionId string) (*entity.Answer, bool, error)
|
||||
GetByUserIDQuestionID(ctx context.Context, userID string, questionID string) (*entity.Answer, bool, error)
|
||||
SearchList(ctx context.Context, search *entity.AnswerSearch) ([]*entity.Answer, int64, error)
|
||||
CmsSearchList(ctx context.Context, search *entity.CmsAnswerSearch) ([]*entity.Answer, int64, error)
|
||||
UpdateAnswerStatus(ctx context.Context, answer *entity.Answer) (err error)
|
||||
|
@ -33,8 +33,8 @@ func NewAnswerCommon(answerRepo AnswerRepo) *AnswerCommon {
|
|||
}
|
||||
}
|
||||
|
||||
func (as *AnswerCommon) SearchAnswered(ctx context.Context, userId, questionId string) (bool, error) {
|
||||
_, has, err := as.answerRepo.GetByUserIdQuestionId(ctx, userId, questionId)
|
||||
func (as *AnswerCommon) SearchAnswered(ctx context.Context, userID, questionID string) (bool, error) {
|
||||
_, has, err := as.answerRepo.GetByUserIDQuestionID(ctx, userID, questionID)
|
||||
if err != nil {
|
||||
return has, err
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ func (as *AnswerCommon) SearchAnswered(ctx context.Context, userId, questionId s
|
|||
}
|
||||
|
||||
func (as *AnswerCommon) CmsSearchList(ctx context.Context, search *entity.CmsAnswerSearch) ([]*entity.Answer, int64, error) {
|
||||
if search.Status == 0 {
|
||||
search.Status = 1
|
||||
}
|
||||
return as.answerRepo.CmsSearchList(ctx, search)
|
||||
}
|
||||
|
||||
|
@ -56,26 +59,26 @@ func (as *AnswerCommon) Search(ctx context.Context, search *entity.AnswerSearch)
|
|||
func (as *AnswerCommon) ShowFormat(ctx context.Context, data *entity.Answer) *schema.AnswerInfo {
|
||||
info := schema.AnswerInfo{}
|
||||
info.ID = data.ID
|
||||
info.QuestionId = data.QuestionID
|
||||
info.QuestionID = data.QuestionID
|
||||
info.Content = data.OriginalText
|
||||
info.Html = data.ParsedText
|
||||
info.HTML = data.ParsedText
|
||||
info.Adopted = data.Adopted
|
||||
info.VoteCount = data.VoteCount
|
||||
info.CreateTime = data.CreatedAt.Unix()
|
||||
info.UpdateTime = data.UpdatedAt.Unix()
|
||||
info.UserId = data.UserID
|
||||
info.UserID = data.UserID
|
||||
return &info
|
||||
}
|
||||
|
||||
func (as *AnswerCommon) AdminShowFormat(ctx context.Context, data *entity.Answer) *schema.AdminAnswerInfo {
|
||||
info := schema.AdminAnswerInfo{}
|
||||
info.ID = data.ID
|
||||
info.QuestionId = data.QuestionID
|
||||
info.QuestionID = data.QuestionID
|
||||
info.Description = data.ParsedText
|
||||
info.Adopted = data.Adopted
|
||||
info.VoteCount = data.VoteCount
|
||||
info.CreateTime = data.CreatedAt.Unix()
|
||||
info.UpdateTime = data.UpdatedAt.Unix()
|
||||
info.UserId = data.UserID
|
||||
info.UserID = data.UserID
|
||||
return &info
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, id string) (err error
|
|||
return nil
|
||||
}
|
||||
|
||||
//user add question count
|
||||
// user add question count
|
||||
err = as.questionCommon.UpdateAnswerCount(ctx, answerInfo.QuestionID, -1)
|
||||
if err != nil {
|
||||
log.Error("IncreaseAnswerCount error", err.Error())
|
||||
|
@ -97,7 +97,7 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, id string) (err error
|
|||
}
|
||||
|
||||
func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) (string, error) {
|
||||
questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, req.QuestionId)
|
||||
questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -108,24 +108,24 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) (
|
|||
insertData := new(entity.Answer)
|
||||
insertData.UserID = req.UserID
|
||||
insertData.OriginalText = req.Content
|
||||
insertData.ParsedText = req.Html
|
||||
insertData.Adopted = schema.Answer_Adopted_Failed
|
||||
insertData.QuestionID = req.QuestionId
|
||||
insertData.ParsedText = req.HTML
|
||||
insertData.Adopted = schema.AnswerAdoptedFailed
|
||||
insertData.QuestionID = req.QuestionID
|
||||
insertData.RevisionID = "0"
|
||||
insertData.Status = entity.AnswerStatusAvailable
|
||||
insertData.UpdatedAt = now
|
||||
if err := as.answerRepo.AddAnswer(ctx, insertData); err != nil {
|
||||
if err = as.answerRepo.AddAnswer(ctx, insertData); err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = as.questionCommon.UpdateAnswerCount(ctx, req.QuestionId, 1)
|
||||
err = as.questionCommon.UpdateAnswerCount(ctx, req.QuestionID, 1)
|
||||
if err != nil {
|
||||
log.Error("IncreaseAnswerCount error", err.Error())
|
||||
}
|
||||
err = as.questionCommon.UpdateLastAnswer(ctx, req.QuestionId, insertData.ID)
|
||||
err = as.questionCommon.UpdateLastAnswer(ctx, req.QuestionID, insertData.ID)
|
||||
if err != nil {
|
||||
log.Error("UpdateLastAnswer error", err.Error())
|
||||
}
|
||||
err = as.questionCommon.UpdataPostTime(ctx, req.QuestionId)
|
||||
err = as.questionCommon.UpdataPostTime(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return insertData.ID, err
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) (
|
|||
ObjectID: insertData.ID,
|
||||
Title: "",
|
||||
}
|
||||
InfoJson, _ := json.Marshal(insertData)
|
||||
revisionDTO.Content = string(InfoJson)
|
||||
infoJSON, _ := json.Marshal(insertData)
|
||||
revisionDTO.Content = string(infoJSON)
|
||||
err = as.revisionService.AddRevision(ctx, revisionDTO, true)
|
||||
if err != nil {
|
||||
return insertData.ID, err
|
||||
|
@ -151,7 +151,7 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) (
|
|||
}
|
||||
|
||||
func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq) (string, error) {
|
||||
questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, req.QuestionId)
|
||||
questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -161,15 +161,15 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq
|
|||
now := time.Now()
|
||||
insertData := new(entity.Answer)
|
||||
insertData.ID = req.ID
|
||||
insertData.QuestionID = req.QuestionId
|
||||
insertData.QuestionID = req.QuestionID
|
||||
insertData.UserID = req.UserID
|
||||
insertData.OriginalText = req.Content
|
||||
insertData.ParsedText = req.Html
|
||||
insertData.ParsedText = req.HTML
|
||||
insertData.UpdatedAt = now
|
||||
if err := as.answerRepo.UpdateAnswer(ctx, insertData, []string{"original_text", "parsed_text", "update_time"}); err != nil {
|
||||
if err = as.answerRepo.UpdateAnswer(ctx, insertData, []string{"original_text", "parsed_text", "update_time"}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = as.questionCommon.UpdataPostTime(ctx, req.QuestionId)
|
||||
err = as.questionCommon.UpdataPostTime(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return insertData.ID, err
|
||||
}
|
||||
|
@ -179,8 +179,8 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq
|
|||
Title: "",
|
||||
Log: req.EditSummary,
|
||||
}
|
||||
InfoJson, _ := json.Marshal(insertData)
|
||||
revisionDTO.Content = string(InfoJson)
|
||||
infoJSON, _ := json.Marshal(insertData)
|
||||
revisionDTO.Content = string(infoJSON)
|
||||
err = as.revisionService.AddRevision(ctx, revisionDTO, true)
|
||||
if err != nil {
|
||||
return insertData.ID, err
|
||||
|
@ -228,7 +228,7 @@ func (as *AnswerService) UpdateAdopted(ctx context.Context, req *schema.AnswerAd
|
|||
|
||||
var oldAnswerInfo *entity.Answer
|
||||
if len(questionInfo.AcceptedAnswerID) > 0 && questionInfo.AcceptedAnswerID != "0" {
|
||||
oldAnswerInfo, exist, err = as.answerRepo.GetByID(ctx, questionInfo.AcceptedAnswerID)
|
||||
oldAnswerInfo, _, err = as.answerRepo.GetByID(ctx, questionInfo.AcceptedAnswerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -249,8 +249,8 @@ func (as *AnswerService) UpdateAdopted(ctx context.Context, req *schema.AnswerAd
|
|||
}
|
||||
|
||||
func (as *AnswerService) updateAnswerRank(ctx context.Context, userID string,
|
||||
questionInfo *entity.Question, newAnswerInfo *entity.Answer, oldAnswerInfo *entity.Answer) {
|
||||
|
||||
questionInfo *entity.Question, newAnswerInfo *entity.Answer, oldAnswerInfo *entity.Answer,
|
||||
) {
|
||||
// if this question is already been answered, should cancel old answer rank
|
||||
if oldAnswerInfo != nil {
|
||||
err := as.answerActivityService.CancelAcceptAnswer(
|
||||
|
@ -266,21 +266,20 @@ func (as *AnswerService) updateAnswerRank(ctx context.Context, userID string,
|
|||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (as *AnswerService) Get(ctx context.Context, answerID, loginUserId string) (*schema.AnswerInfo, *schema.QuestionInfo, bool, error) {
|
||||
func (as *AnswerService) Get(ctx context.Context, answerID, loginUserID string) (*schema.AnswerInfo, *schema.QuestionInfo, bool, error) {
|
||||
answerInfo, has, err := as.answerRepo.GetByID(ctx, answerID)
|
||||
if err != nil {
|
||||
return nil, nil, has, err
|
||||
}
|
||||
info := as.ShowFormat(ctx, answerInfo)
|
||||
//todo questionFunc
|
||||
questionInfo, err := as.questionCommon.Info(ctx, answerInfo.QuestionID, loginUserId)
|
||||
// todo questionFunc
|
||||
questionInfo, err := as.questionCommon.Info(ctx, answerInfo.QuestionID, loginUserID)
|
||||
if err != nil {
|
||||
return nil, nil, has, err
|
||||
}
|
||||
//todo UserFunc
|
||||
// todo UserFunc
|
||||
userinfo, has, err := as.userCommon.GetUserBasicInfoByID(ctx, answerInfo.UserID)
|
||||
if err != nil {
|
||||
return nil, nil, has, err
|
||||
|
@ -290,13 +289,13 @@ func (as *AnswerService) Get(ctx context.Context, answerID, loginUserId string)
|
|||
info.UpdateUserInfo = userinfo
|
||||
}
|
||||
|
||||
if loginUserId == "" {
|
||||
if loginUserID == "" {
|
||||
return info, questionInfo, has, nil
|
||||
}
|
||||
|
||||
info.VoteStatus = as.voteRepo.GetVoteStatus(ctx, answerID, loginUserId)
|
||||
info.VoteStatus = as.voteRepo.GetVoteStatus(ctx, answerID, loginUserID)
|
||||
|
||||
CollectedMap, err := as.collectionCommon.SearchObjectCollected(ctx, loginUserId, []string{answerInfo.ID})
|
||||
CollectedMap, err := as.collectionCommon.SearchObjectCollected(ctx, loginUserID, []string{answerInfo.ID})
|
||||
if err != nil {
|
||||
log.Error("CollectionFunc.SearchObjectCollected error", err)
|
||||
}
|
||||
|
@ -348,7 +347,7 @@ func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, answerID stri
|
|||
func (as *AnswerService) SearchList(ctx context.Context, search *schema.AnswerList) ([]*schema.AnswerInfo, int64, error) {
|
||||
list := make([]*schema.AnswerInfo, 0)
|
||||
dbSearch := entity.AnswerSearch{}
|
||||
dbSearch.QuestionID = search.QuestionId
|
||||
dbSearch.QuestionID = search.QuestionID
|
||||
dbSearch.Page = search.Page
|
||||
dbSearch.PageSize = search.PageSize
|
||||
dbSearch.Order = search.Order
|
||||
|
@ -363,7 +362,7 @@ func (as *AnswerService) SearchList(ctx context.Context, search *schema.AnswerLi
|
|||
return AnswerList, count, nil
|
||||
}
|
||||
|
||||
func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.Answer, loginUserId string) ([]*schema.AnswerInfo, error) {
|
||||
func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.Answer, loginUserID string) ([]*schema.AnswerInfo, error) {
|
||||
list := make([]*schema.AnswerInfo, 0)
|
||||
objectIds := make([]string, 0)
|
||||
userIds := make([]string, 0)
|
||||
|
@ -372,9 +371,9 @@ func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.
|
|||
list = append(list, item)
|
||||
objectIds = append(objectIds, dbitem.ID)
|
||||
userIds = append(userIds, dbitem.UserID)
|
||||
if loginUserId != "" {
|
||||
//item.VoteStatus = as.activityFunc.GetVoteStatus(ctx, item.TagID, loginUserId)
|
||||
item.VoteStatus = as.voteRepo.GetVoteStatus(ctx, item.ID, loginUserId)
|
||||
if loginUserID != "" {
|
||||
// item.VoteStatus = as.activityFunc.GetVoteStatus(ctx, item.TagID, loginUserId)
|
||||
item.VoteStatus = as.voteRepo.GetVoteStatus(ctx, item.ID, loginUserID)
|
||||
}
|
||||
}
|
||||
userInfoMap, err := as.userCommon.BatchUserBasicInfoByID(ctx, userIds)
|
||||
|
@ -382,18 +381,18 @@ func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.
|
|||
return list, err
|
||||
}
|
||||
for _, item := range list {
|
||||
_, ok := userInfoMap[item.UserId]
|
||||
_, ok := userInfoMap[item.UserID]
|
||||
if ok {
|
||||
item.UserInfo = userInfoMap[item.UserId]
|
||||
item.UpdateUserInfo = userInfoMap[item.UserId]
|
||||
item.UserInfo = userInfoMap[item.UserID]
|
||||
item.UpdateUserInfo = userInfoMap[item.UserID]
|
||||
}
|
||||
}
|
||||
|
||||
if loginUserId == "" {
|
||||
if loginUserID == "" {
|
||||
return list, nil
|
||||
}
|
||||
|
||||
CollectedMap, err := as.collectionCommon.SearchObjectCollected(ctx, loginUserId, objectIds)
|
||||
CollectedMap, err := as.collectionCommon.SearchObjectCollected(ctx, loginUserID, objectIds)
|
||||
if err != nil {
|
||||
log.Error("CollectionFunc.SearchObjectCollected error", err)
|
||||
}
|
||||
|
@ -406,7 +405,7 @@ func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.
|
|||
}
|
||||
|
||||
for _, item := range list {
|
||||
item.MemberActions = permission.GetAnswerPermission(loginUserId, item.UserId)
|
||||
item.MemberActions = permission.GetAnswerPermission(loginUserID, item.UserID)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
|
|
|
@ -17,7 +17,7 @@ type CollectionGroupRepo interface {
|
|||
UpdateCollectionGroup(ctx context.Context, collectionGroup *entity.CollectionGroup, cols []string) (err error)
|
||||
GetCollectionGroup(ctx context.Context, id string) (collectionGroup *entity.CollectionGroup, exist bool, err error)
|
||||
GetCollectionGroupPage(ctx context.Context, page, pageSize int, collectionGroup *entity.CollectionGroup) (collectionGroupList []*entity.CollectionGroup, total int64, err error)
|
||||
GetDefaultID(ctx context.Context, userId string) (collectionGroup *entity.CollectionGroup, has bool, err error)
|
||||
GetDefaultID(ctx context.Context, userID string) (collectionGroup *entity.CollectionGroup, has bool, err error)
|
||||
}
|
||||
|
||||
// CollectionGroupService user service
|
||||
|
|
|
@ -23,7 +23,6 @@ func NewCollectionService(
|
|||
collectionRepo collectioncommon.CollectionRepo,
|
||||
collectionGroupRepo CollectionGroupRepo,
|
||||
questionCommon *questioncommon.QuestionCommon,
|
||||
|
||||
) *CollectionService {
|
||||
return &CollectionService{
|
||||
collectionRepo: collectionRepo,
|
||||
|
@ -31,6 +30,7 @@ func NewCollectionService(
|
|||
questionCommon: questionCommon,
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *CollectionService) CollectionSwitch(ctx context.Context, dto *schema.CollectionSwitchDTO) (resp *schema.CollectionSwitchResp, err error) {
|
||||
resp = &schema.CollectionSwitchResp{}
|
||||
dbData, has, err := cs.collectionRepo.GetOneByObjectIDAndUser(ctx, dto.UserID, dto.ObjectID)
|
||||
|
@ -46,7 +46,8 @@ func (cs *CollectionService) CollectionSwitch(ctx context.Context, dto *schema.C
|
|||
if err != nil {
|
||||
log.Error("UpdateCollectionCount", err.Error())
|
||||
}
|
||||
count, err := cs.objectCollectionCount(ctx, dto.ObjectID)
|
||||
var count int64
|
||||
count, err = cs.objectCollectionCount(ctx, dto.ObjectID)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
@ -56,12 +57,17 @@ func (cs *CollectionService) CollectionSwitch(ctx context.Context, dto *schema.C
|
|||
}
|
||||
|
||||
if dto.GroupID == "" || dto.GroupID == "0" {
|
||||
defaultGroup, has, err := cs.collectionGroupRepo.GetDefaultID(ctx, dto.UserID)
|
||||
var (
|
||||
defaultGroup *entity.CollectionGroup
|
||||
has bool
|
||||
)
|
||||
defaultGroup, has, err = cs.collectionGroupRepo.GetDefaultID(ctx, dto.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
dbdefaultGroup, err := cs.collectionGroupRepo.AddCollectionDefaultGroup(ctx, dto.UserID)
|
||||
var dbdefaultGroup *entity.CollectionGroup
|
||||
dbdefaultGroup, err = cs.collectionGroupRepo.AddCollectionDefaultGroup(ctx, dto.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -93,8 +99,8 @@ func (cs *CollectionService) CollectionSwitch(ctx context.Context, dto *schema.C
|
|||
return
|
||||
}
|
||||
|
||||
func (cs *CollectionService) objectCollectionCount(ctx context.Context, objectId string) (int64, error) {
|
||||
count, err := cs.collectionRepo.CountByObjectID(ctx, objectId)
|
||||
func (cs *CollectionService) objectCollectionCount(ctx context.Context, objectID string) (int64, error) {
|
||||
count, err := cs.collectionRepo.CountByObjectID(ctx, objectID)
|
||||
return count, err
|
||||
}
|
||||
|
||||
|
@ -108,12 +114,16 @@ func (cs *CollectionService) add(ctx context.Context, collection *entity.Collect
|
|||
}
|
||||
|
||||
if collection.UserCollectionGroupID == "" || collection.UserCollectionGroupID == "0" {
|
||||
defaultGroup, has, err := cs.collectionGroupRepo.GetDefaultID(ctx, collection.UserID)
|
||||
var (
|
||||
defaultGroup *entity.CollectionGroup
|
||||
has bool
|
||||
)
|
||||
defaultGroup, has, err = cs.collectionGroupRepo.GetDefaultID(ctx, collection.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has {
|
||||
defaultGroup, err := cs.collectionGroupRepo.AddCollectionDefaultGroup(ctx, collection.UserID)
|
||||
defaultGroup, err = cs.collectionGroupRepo.AddCollectionDefaultGroup(ctx, collection.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ type QuestionRepo interface {
|
|||
SearchList(ctx context.Context, search *schema.QuestionSearch) ([]*entity.QuestionTag, int64, error)
|
||||
UpdateQuestionStatus(ctx context.Context, question *entity.Question) (err error)
|
||||
SearchByTitleLike(ctx context.Context, title string) (questionList []*entity.Question, err error)
|
||||
UpdatePvCount(ctx context.Context, questionId string) (err error)
|
||||
UpdateAnswerCount(ctx context.Context, questionId string, num int) (err error)
|
||||
UpdateCollectionCount(ctx context.Context, questionId string, num int) (err error)
|
||||
UpdatePvCount(ctx context.Context, questionID string) (err error)
|
||||
UpdateAnswerCount(ctx context.Context, questionID string, num int) (err error)
|
||||
UpdateCollectionCount(ctx context.Context, questionID string, num int) (err error)
|
||||
UpdateAccepted(ctx context.Context, question *entity.Question) (err error)
|
||||
UpdateLastAnswer(ctx context.Context, question *entity.Question) (err error)
|
||||
FindByID(ctx context.Context, id []string) (questionList []*entity.Question, err error)
|
||||
|
@ -64,7 +64,6 @@ func NewQuestionCommon(questionRepo QuestionRepo,
|
|||
answerCommon *answercommon.AnswerCommon,
|
||||
metaService *meta.MetaService,
|
||||
configRepo config.ConfigRepo,
|
||||
|
||||
) *QuestionCommon {
|
||||
return &QuestionCommon{
|
||||
questionRepo: questionRepo,
|
||||
|
@ -80,42 +79,44 @@ func NewQuestionCommon(questionRepo QuestionRepo,
|
|||
}
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) UpdataPv(ctx context.Context, questionId string) error {
|
||||
return qs.questionRepo.UpdatePvCount(ctx, questionId)
|
||||
}
|
||||
func (qs *QuestionCommon) UpdateAnswerCount(ctx context.Context, questionId string, num int) error {
|
||||
return qs.questionRepo.UpdateAnswerCount(ctx, questionId, num)
|
||||
}
|
||||
func (qs *QuestionCommon) UpdateCollectionCount(ctx context.Context, questionId string, num int) error {
|
||||
return qs.questionRepo.UpdateCollectionCount(ctx, questionId, num)
|
||||
func (qs *QuestionCommon) UpdataPv(ctx context.Context, questionID string) error {
|
||||
return qs.questionRepo.UpdatePvCount(ctx, questionID)
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) UpdateAccepted(ctx context.Context, questionId, AnswerId string) error {
|
||||
func (qs *QuestionCommon) UpdateAnswerCount(ctx context.Context, questionID string, num int) error {
|
||||
return qs.questionRepo.UpdateAnswerCount(ctx, questionID, num)
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) UpdateCollectionCount(ctx context.Context, questionID string, num int) error {
|
||||
return qs.questionRepo.UpdateCollectionCount(ctx, questionID, num)
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) UpdateAccepted(ctx context.Context, questionID, AnswerID string) error {
|
||||
question := &entity.Question{}
|
||||
question.ID = questionId
|
||||
question.AcceptedAnswerID = AnswerId
|
||||
question.ID = questionID
|
||||
question.AcceptedAnswerID = AnswerID
|
||||
return qs.questionRepo.UpdateAccepted(ctx, question)
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) UpdateLastAnswer(ctx context.Context, questionId, AnswerId string) error {
|
||||
func (qs *QuestionCommon) UpdateLastAnswer(ctx context.Context, questionID, AnswerID string) error {
|
||||
question := &entity.Question{}
|
||||
question.ID = questionId
|
||||
question.LastAnswerID = AnswerId
|
||||
question.ID = questionID
|
||||
question.LastAnswerID = AnswerID
|
||||
return qs.questionRepo.UpdateLastAnswer(ctx, question)
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) UpdataPostTime(ctx context.Context, questionId string) error {
|
||||
func (qs *QuestionCommon) UpdataPostTime(ctx context.Context, questionID string) error {
|
||||
questioninfo := &entity.Question{}
|
||||
now := time.Now()
|
||||
questioninfo.ID = questionId
|
||||
questioninfo.ID = questionID
|
||||
questioninfo.PostUpdateTime = now
|
||||
return qs.questionRepo.UpdateQuestion(ctx, questioninfo, []string{"post_update_time"})
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) FindInfoByID(ctx context.Context, questionIds []string, loginUserID string) (map[string]*schema.QuestionInfo, error) {
|
||||
func (qs *QuestionCommon) FindInfoByID(ctx context.Context, questionIDs []string, loginUserID string) (map[string]*schema.QuestionInfo, error) {
|
||||
list := make(map[string]*schema.QuestionInfo)
|
||||
listAddTag := make([]*entity.QuestionTag, 0)
|
||||
questionList, err := qs.questionRepo.FindByID(ctx, questionIds)
|
||||
questionList, err := qs.questionRepo.FindByID(ctx, questionIDs)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
@ -134,8 +135,8 @@ func (qs *QuestionCommon) FindInfoByID(ctx context.Context, questionIds []string
|
|||
return list, nil
|
||||
}
|
||||
|
||||
func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUserID string) (showinfo *schema.QuestionInfo, err error) {
|
||||
dbinfo, has, err := qs.questionRepo.GetQuestion(ctx, questionId)
|
||||
func (qs *QuestionCommon) Info(ctx context.Context, questionID string, loginUserID string) (showinfo *schema.QuestionInfo, err error) {
|
||||
dbinfo, has, err := qs.questionRepo.GetQuestion(ctx, questionID)
|
||||
if err != nil {
|
||||
return showinfo, err
|
||||
}
|
||||
|
@ -145,13 +146,14 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUser
|
|||
showinfo = qs.ShowFormat(ctx, dbinfo)
|
||||
|
||||
if showinfo.Status == 2 {
|
||||
metainfo, err := qs.metaService.GetMetaByObjectIdAndKey(ctx, dbinfo.ID, entity.QuestionCloseReasonKey)
|
||||
var metainfo *entity.Meta
|
||||
metainfo, err = qs.metaService.GetMetaByObjectIdAndKey(ctx, dbinfo.ID, entity.QuestionCloseReasonKey)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
} else {
|
||||
//metainfo.Value
|
||||
// metainfo.Value
|
||||
closemsg := &schema.CloseQuestionMeta{}
|
||||
err := json.Unmarshal([]byte(metainfo.Value), closemsg)
|
||||
err = json.Unmarshal([]byte(metainfo.Value), closemsg)
|
||||
if err != nil {
|
||||
log.Error("json.Unmarshal CloseQuestionMeta error", err.Error())
|
||||
} else {
|
||||
|
@ -161,10 +163,10 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUser
|
|||
log.Error("json.Unmarshal QuestionCloseJson error", err.Error())
|
||||
} else {
|
||||
operation := &schema.Operation{}
|
||||
operation.Operation_Type = closeinfo.Name
|
||||
operation.Operation_Description = closeinfo.Description
|
||||
operation.Operation_Msg = closemsg.CloseMsg
|
||||
operation.Operation_Time = metainfo.CreatedAt.Unix()
|
||||
operation.OperationType = closeinfo.Name
|
||||
operation.OperationDescription = closeinfo.Description
|
||||
operation.OperationMsg = closemsg.CloseMsg
|
||||
operation.OperationTime = metainfo.CreatedAt.Unix()
|
||||
showinfo.Operation = operation
|
||||
}
|
||||
|
||||
|
@ -173,7 +175,7 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUser
|
|||
}
|
||||
}
|
||||
|
||||
tagmap, err := qs.tagCommon.GetObjectTag(ctx, questionId)
|
||||
tagmap, err := qs.tagCommon.GetObjectTag(ctx, questionID)
|
||||
if err != nil {
|
||||
return showinfo, err
|
||||
}
|
||||
|
@ -193,10 +195,10 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUser
|
|||
return showinfo, nil
|
||||
}
|
||||
|
||||
showinfo.VoteStatus = qs.voteRepo.GetVoteStatus(ctx, questionId, loginUserID)
|
||||
showinfo.VoteStatus = qs.voteRepo.GetVoteStatus(ctx, questionID, loginUserID)
|
||||
|
||||
// // check is followed
|
||||
isFollowed, _ := qs.followCommon.IsFollowed(loginUserID, questionId)
|
||||
isFollowed, _ := qs.followCommon.IsFollowed(loginUserID, questionID)
|
||||
showinfo.IsFollowed = isFollowed
|
||||
|
||||
has, err = qs.AnswerCommon.SearchAnswered(ctx, loginUserID, dbinfo.ID)
|
||||
|
@ -205,7 +207,7 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUser
|
|||
}
|
||||
showinfo.Answered = has
|
||||
|
||||
//login user Collected information
|
||||
// login user Collected information
|
||||
|
||||
CollectedMap, err := qs.collectionCommon.SearchObjectCollected(ctx, loginUserID, []string{dbinfo.ID})
|
||||
if err != nil {
|
||||
|
@ -245,11 +247,11 @@ func (qs *QuestionCommon) ListFormat(ctx context.Context, questionList []*entity
|
|||
if ok {
|
||||
item.Tags = tagsMap[item.ID]
|
||||
}
|
||||
_, ok = userInfoMap[item.UserId]
|
||||
_, ok = userInfoMap[item.UserID]
|
||||
if ok {
|
||||
item.UserInfo = userInfoMap[item.UserId]
|
||||
item.UpdateUserInfo = userInfoMap[item.UserId]
|
||||
item.LastAnsweredUserInfo = userInfoMap[item.UserId]
|
||||
item.UserInfo = userInfoMap[item.UserID]
|
||||
item.UpdateUserInfo = userInfoMap[item.UserID]
|
||||
item.LastAnsweredUserInfo = userInfoMap[item.UserID]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +288,7 @@ func (qs *QuestionCommon) RemoveQuestion(ctx context.Context, req *schema.Remove
|
|||
return err
|
||||
}
|
||||
|
||||
//user add question count
|
||||
// user add question count
|
||||
err = qs.userCommon.UpdateQuestionCount(ctx, questionInfo.UserID, -1)
|
||||
if err != nil {
|
||||
log.Error("user UpdateQuestionCount error", err.Error())
|
||||
|
@ -332,7 +334,7 @@ func (as *QuestionCommon) RemoveAnswer(ctx context.Context, id string) (err erro
|
|||
return nil
|
||||
}
|
||||
|
||||
//user add question count
|
||||
// user add question count
|
||||
|
||||
err = as.UpdateAnswerCount(ctx, answerinfo.QuestionID, -1)
|
||||
if err != nil {
|
||||
|
@ -356,21 +358,21 @@ func (qs *QuestionCommon) ShowFormat(ctx context.Context, data *entity.Question)
|
|||
info.ID = data.ID
|
||||
info.Title = data.Title
|
||||
info.Content = data.OriginalText
|
||||
info.Html = data.ParsedText
|
||||
info.HTML = data.ParsedText
|
||||
info.ViewCount = data.ViewCount
|
||||
info.UniqueViewCount = data.UniqueViewCount
|
||||
info.VoteCount = data.VoteCount
|
||||
info.AnswerCount = data.AnswerCount
|
||||
info.CollectionCount = data.CollectionCount
|
||||
info.FollowCount = data.FollowCount
|
||||
info.AcceptedAnswerId = data.AcceptedAnswerID
|
||||
info.LastAnswerId = data.LastAnswerID
|
||||
info.AcceptedAnswerID = data.AcceptedAnswerID
|
||||
info.LastAnswerID = data.LastAnswerID
|
||||
info.CreateTime = data.CreatedAt.Unix()
|
||||
info.UpdateTime = data.UpdatedAt.Unix()
|
||||
info.PostUpdateTime = data.PostUpdateTime.Unix()
|
||||
info.QuestionUpdateTime = data.UpdatedAt.Unix()
|
||||
info.Status = data.Status
|
||||
info.UserId = data.UserID
|
||||
info.UserID = data.UserID
|
||||
info.Tags = make([]*schema.TagResp, 0)
|
||||
return &info
|
||||
}
|
||||
|
|
|
@ -89,9 +89,10 @@ func (qs *QuestionService) CloseQuestion(ctx context.Context, req *schema.CloseQ
|
|||
|
||||
// CloseMsgList list close question condition
|
||||
func (qs *QuestionService) CloseMsgList(ctx context.Context, lang i18n.Language) (
|
||||
resp []*schema.GetCloseTypeResp, err error) {
|
||||
resp []*schema.GetCloseTypeResp, err error,
|
||||
) {
|
||||
resp = make([]*schema.GetCloseTypeResp, 0)
|
||||
err = json.Unmarshal([]byte(constant.QuestionCloseJson), &resp)
|
||||
err = json.Unmarshal([]byte(constant.QuestionCloseJSON), &resp)
|
||||
if err != nil {
|
||||
return nil, errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
|
|||
question.UserID = req.UserID
|
||||
question.Title = req.Title
|
||||
question.OriginalText = req.Content
|
||||
question.ParsedText = req.Html
|
||||
question.ParsedText = req.HTML
|
||||
question.AcceptedAnswerID = "0"
|
||||
question.LastAnswerID = "0"
|
||||
question.PostUpdateTime = now
|
||||
|
@ -123,7 +124,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
|
|||
return
|
||||
}
|
||||
objectTagData := schema.TagChange{}
|
||||
objectTagData.ObjectId = question.ID
|
||||
objectTagData.ObjectID = question.ID
|
||||
objectTagData.Tags = req.Tags
|
||||
objectTagData.UserID = req.UserID
|
||||
err = qs.ChangeTag(ctx, &objectTagData)
|
||||
|
@ -136,14 +137,14 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
|
|||
ObjectID: question.ID,
|
||||
Title: "",
|
||||
}
|
||||
InfoJson, _ := json.Marshal(question)
|
||||
revisionDTO.Content = string(InfoJson)
|
||||
infoJSON, _ := json.Marshal(question)
|
||||
revisionDTO.Content = string(infoJSON)
|
||||
err = qs.revisionService.AddRevision(ctx, revisionDTO, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//user add question count
|
||||
// user add question count
|
||||
err = qs.userCommon.UpdateQuestionCount(ctx, question.UserID, 1)
|
||||
if err != nil {
|
||||
log.Error("user IncreaseQuestionCount error", err.Error())
|
||||
|
@ -168,7 +169,7 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov
|
|||
return err
|
||||
}
|
||||
|
||||
//user add question count
|
||||
// user add question count
|
||||
err = qs.userCommon.UpdateQuestionCount(ctx, questionInfo.UserID, -1)
|
||||
if err != nil {
|
||||
log.Error("user IncreaseQuestionCount error", err.Error())
|
||||
|
@ -190,7 +191,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest
|
|||
question.UserID = req.UserID
|
||||
question.Title = req.Title
|
||||
question.OriginalText = req.Content
|
||||
question.ParsedText = req.Html
|
||||
question.ParsedText = req.HTML
|
||||
question.ID = req.ID
|
||||
question.UpdatedAt = now
|
||||
dbinfo, has, err := qs.questionRepo.GetQuestion(ctx, question.ID)
|
||||
|
@ -208,7 +209,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest
|
|||
return
|
||||
}
|
||||
objectTagData := schema.TagChange{}
|
||||
objectTagData.ObjectId = question.ID
|
||||
objectTagData.ObjectID = question.ID
|
||||
objectTagData.Tags = req.Tags
|
||||
objectTagData.UserID = req.UserID
|
||||
err = qs.ChangeTag(ctx, &objectTagData)
|
||||
|
@ -222,8 +223,8 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest
|
|||
Title: "",
|
||||
Log: req.EditSummary,
|
||||
}
|
||||
InfoJson, _ := json.Marshal(question)
|
||||
revisionDTO.Content = string(InfoJson)
|
||||
infoJSON, _ := json.Marshal(question)
|
||||
revisionDTO.Content = string(infoJSON)
|
||||
err = qs.revisionService.AddRevision(ctx, revisionDTO, true)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -246,7 +247,7 @@ func (qs *QuestionService) GetQuestion(ctx context.Context, id, loginUserID stri
|
|||
}
|
||||
}
|
||||
|
||||
question.MemberActions = permission.GetQuestionPermission(loginUserID, question.UserId)
|
||||
question.MemberActions = permission.GetQuestionPermission(loginUserID, question.UserID)
|
||||
return question, nil
|
||||
}
|
||||
|
||||
|
@ -300,9 +301,9 @@ func (qs *QuestionService) SearchUserAnswerList(ctx context.Context, userName, o
|
|||
answersearch.PageSize = pageSize
|
||||
answersearch.Page = page
|
||||
if order == "newest" {
|
||||
answersearch.Order = entity.Answer_Search_OrderBy_Time
|
||||
answersearch.Order = entity.AnswerSearchOrderByTime
|
||||
} else {
|
||||
answersearch.Order = entity.Answer_Search_OrderBy_Default
|
||||
answersearch.Order = entity.AnswerSearchOrderByDefault
|
||||
}
|
||||
questionIDs := make([]string, 0)
|
||||
answerList, count, err := qs.questioncommon.AnswerCommon.Search(ctx, answersearch)
|
||||
|
@ -319,16 +320,16 @@ func (qs *QuestionService) SearchUserAnswerList(ctx context.Context, userName, o
|
|||
return userAnswerlist, count, err
|
||||
}
|
||||
for _, item := range answerlist {
|
||||
_, ok := questionMaps[item.QuestionId]
|
||||
_, ok := questionMaps[item.QuestionID]
|
||||
if ok {
|
||||
item.QuestionInfo = questionMaps[item.QuestionId]
|
||||
item.QuestionInfo = questionMaps[item.QuestionID]
|
||||
}
|
||||
}
|
||||
for _, item := range answerlist {
|
||||
info := &schema.UserAnswerInfo{}
|
||||
_ = copier.Copy(info, item)
|
||||
info.AnswerID = item.ID
|
||||
info.QuestionID = item.QuestionId
|
||||
info.QuestionID = item.QuestionID
|
||||
userAnswerlist = append(userAnswerlist, info)
|
||||
}
|
||||
return userAnswerlist, count, nil
|
||||
|
@ -366,7 +367,7 @@ func (qs *QuestionService) SearchUserCollectionList(ctx context.Context, page, p
|
|||
questionMaps[id].LastAnsweredUserInfo = nil
|
||||
questionMaps[id].UpdateUserInfo = nil
|
||||
questionMaps[id].Content = ""
|
||||
questionMaps[id].Html = ""
|
||||
questionMaps[id].HTML = ""
|
||||
list = append(list, questionMaps[id])
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +400,7 @@ func (qs *QuestionService) SearchUserTopList(ctx context.Context, userName strin
|
|||
answersearch := &entity.AnswerSearch{}
|
||||
answersearch.UserID = userinfo.ID
|
||||
answersearch.PageSize = 5
|
||||
answersearch.Order = entity.Answer_Search_OrderBy_Vote
|
||||
answersearch.Order = entity.AnswerSearchOrderByVote
|
||||
questionIDs := make([]string, 0)
|
||||
answerList, _, err := qs.questioncommon.AnswerCommon.Search(ctx, answersearch)
|
||||
if err != nil {
|
||||
|
@ -415,9 +416,9 @@ func (qs *QuestionService) SearchUserTopList(ctx context.Context, userName strin
|
|||
return userQuestionlist, userAnswerlist, err
|
||||
}
|
||||
for _, item := range answerlist {
|
||||
_, ok := questionMaps[item.QuestionId]
|
||||
_, ok := questionMaps[item.QuestionID]
|
||||
if ok {
|
||||
item.QuestionInfo = questionMaps[item.QuestionId]
|
||||
item.QuestionInfo = questionMaps[item.QuestionID]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +432,7 @@ func (qs *QuestionService) SearchUserTopList(ctx context.Context, userName strin
|
|||
info := &schema.UserAnswerInfo{}
|
||||
_ = copier.Copy(info, item)
|
||||
info.AnswerID = item.ID
|
||||
info.QuestionID = item.QuestionId
|
||||
info.QuestionID = item.QuestionID
|
||||
userAnswerlist = append(userAnswerlist, info)
|
||||
}
|
||||
|
||||
|
@ -629,13 +630,13 @@ func (qs *QuestionService) CmsSearchAnswerList(ctx context.Context, search *enti
|
|||
return answerlist, count, err
|
||||
}
|
||||
for _, item := range answerlist {
|
||||
_, ok := questionMaps[item.QuestionId]
|
||||
_, ok := questionMaps[item.QuestionID]
|
||||
if ok {
|
||||
item.QuestionInfo.Title = questionMaps[item.QuestionId].Title
|
||||
item.QuestionInfo.Title = questionMaps[item.QuestionID].Title
|
||||
}
|
||||
_, ok = userInfoMap[item.UserId]
|
||||
_, ok = userInfoMap[item.UserID]
|
||||
if ok {
|
||||
item.UserInfo = userInfoMap[item.UserId]
|
||||
item.UserInfo = userInfoMap[item.UserID]
|
||||
}
|
||||
}
|
||||
return answerlist, count, nil
|
||||
|
|
|
@ -24,7 +24,8 @@ type ReportService struct {
|
|||
|
||||
// NewReportService new report service
|
||||
func NewReportService(reportRepo report_common.ReportRepo,
|
||||
objectInfoService *object_info.ObjService) *ReportService {
|
||||
objectInfoService *object_info.ObjService,
|
||||
) *ReportService {
|
||||
return &ReportService{
|
||||
reportRepo: reportRepo,
|
||||
objectInfoService: objectInfoService,
|
||||
|
@ -58,15 +59,16 @@ func (rs *ReportService) AddReport(ctx context.Context, req *schema.AddReportReq
|
|||
|
||||
// GetReportTypeList get report list all
|
||||
func (rs *ReportService) GetReportTypeList(ctx context.Context, lang i18n.Language, req *schema.GetReportListReq) (
|
||||
resp []*schema.GetReportTypeResp, err error) {
|
||||
resp []*schema.GetReportTypeResp, err error,
|
||||
) {
|
||||
resp = make([]*schema.GetReportTypeResp, 0)
|
||||
switch req.Source {
|
||||
case constant.QuestionObjectType:
|
||||
err = json.Unmarshal([]byte(constant.QuestionReportJson), &resp)
|
||||
err = json.Unmarshal([]byte(constant.QuestionReportJSON), &resp)
|
||||
case constant.AnswerObjectType:
|
||||
err = json.Unmarshal([]byte(constant.AnswerReportJson), &resp)
|
||||
err = json.Unmarshal([]byte(constant.AnswerReportJSON), &resp)
|
||||
case constant.CommentObjectType:
|
||||
err = json.Unmarshal([]byte(constant.CommentReportJson), &resp)
|
||||
err = json.Unmarshal([]byte(constant.CommentReportJSON), &resp)
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.BadRequest(reason.UnknownError)
|
||||
|
|
|
@ -64,7 +64,7 @@ func (s *SiteInfoService) SaveSiteGeneral(ctx context.Context, req schema.SiteGe
|
|||
siteType = "general"
|
||||
content []byte
|
||||
)
|
||||
content, err = json.Marshal(req)
|
||||
content, _ = json.Marshal(req)
|
||||
|
||||
data := entity.SiteInfo{
|
||||
Type: siteType,
|
||||
|
@ -107,7 +107,7 @@ func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.Site
|
|||
return
|
||||
}
|
||||
|
||||
content, err = json.Marshal(req)
|
||||
content, _ = json.Marshal(req)
|
||||
|
||||
data := entity.SiteInfo{
|
||||
Type: siteType,
|
||||
|
@ -120,7 +120,8 @@ func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.Site
|
|||
|
||||
// GetSMTPConfig get smtp config
|
||||
func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) (
|
||||
resp *schema.GetSMTPConfigResp, err error) {
|
||||
resp *schema.GetSMTPConfigResp, err error,
|
||||
) {
|
||||
emailConfig, err := s.emailService.GetEmailConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -47,7 +47,8 @@ type TagCommonService struct {
|
|||
|
||||
// NewTagCommonService new tag service
|
||||
func NewTagCommonService(tagRepo TagRepo, tagRelRepo TagRelRepo,
|
||||
revisionService *revision_common.RevisionService) *TagCommonService {
|
||||
revisionService *revision_common.RevisionService,
|
||||
) *TagCommonService {
|
||||
return &TagCommonService{
|
||||
tagRepo: tagRepo,
|
||||
tagRelRepo: tagRelRepo,
|
||||
|
@ -97,20 +98,20 @@ func (ts *TagCommonService) GetObjectTag(ctx context.Context, objectId string) (
|
|||
|
||||
// BatchGetObjectTag batch get object tag
|
||||
func (ts *TagCommonService) BatchGetObjectTag(ctx context.Context, objectIds []string) (map[string][]*schema.TagResp, error) {
|
||||
objectIdTagMap := make(map[string][]*schema.TagResp)
|
||||
objectIDTagMap := make(map[string][]*schema.TagResp)
|
||||
tagIDList := make([]string, 0)
|
||||
tagsInfoMap := make(map[string]*entity.Tag)
|
||||
|
||||
tagList, err := ts.tagRelRepo.BatchGetObjectTagRelList(ctx, objectIds)
|
||||
if err != nil {
|
||||
return objectIdTagMap, err
|
||||
return objectIDTagMap, err
|
||||
}
|
||||
for _, tag := range tagList {
|
||||
tagIDList = append(tagIDList, tag.TagID)
|
||||
}
|
||||
tagsInfoList, err := ts.tagRepo.GetTagListByIDs(ctx, tagIDList)
|
||||
if err != nil {
|
||||
return objectIdTagMap, err
|
||||
return objectIDTagMap, err
|
||||
}
|
||||
for _, item := range tagsInfoList {
|
||||
tagsInfoMap[item.ID] = item
|
||||
|
@ -124,10 +125,10 @@ func (ts *TagCommonService) BatchGetObjectTag(ctx context.Context, objectIds []s
|
|||
DisplayName: tagInfo.DisplayName,
|
||||
MainTagSlugName: tagInfo.MainTagSlugName,
|
||||
}
|
||||
objectIdTagMap[item.ObjectID] = append(objectIdTagMap[item.ObjectID], t)
|
||||
objectIDTagMap[item.ObjectID] = append(objectIDTagMap[item.ObjectID], t)
|
||||
}
|
||||
}
|
||||
return objectIdTagMap, nil
|
||||
return objectIDTagMap, nil
|
||||
}
|
||||
|
||||
// ObjectChangeTag change object tag list
|
||||
|
@ -191,7 +192,7 @@ func (ts *TagCommonService) ObjectChangeTag(ctx context.Context, objectTagData *
|
|||
}
|
||||
}
|
||||
|
||||
err = ts.CreateOrUpdateTagRelList(ctx, objectTagData.ObjectId, thisObjTagIDList)
|
||||
err = ts.CreateOrUpdateTagRelList(ctx, objectTagData.ObjectID, thisObjTagIDList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
type UserBackyardRepo interface {
|
||||
UpdateUserStatus(ctx context.Context, userID string, userStatus, mailStatus int, email string) (err error)
|
||||
GetUserInfo(ctx context.Context, userID string) (user *entity.User, exist bool, err error)
|
||||
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User) (users []*entity.User, total int64, err error)
|
||||
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User, query string) (users []*entity.User, total int64, err error)
|
||||
}
|
||||
|
||||
// UserBackyardService user service
|
||||
|
@ -91,13 +91,14 @@ func (us *UserBackyardService) GetUserPage(ctx context.Context, req *schema.GetU
|
|||
user.Status = entity.UserStatusDeleted
|
||||
}
|
||||
|
||||
users, total, err := us.userRepo.GetUserPage(ctx, req.Page, req.PageSize, user)
|
||||
users, total, err := us.userRepo.GetUserPage(ctx, req.Page, req.PageSize, user, req.Query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp := make([]*schema.GetUserPageResp, 0)
|
||||
for _, u := range users {
|
||||
avatar := schema.FormatAvatarInfo(u.Avatar)
|
||||
t := &schema.GetUserPageResp{
|
||||
UserID: u.ID,
|
||||
CreatedAt: u.CreatedAt.Unix(),
|
||||
|
@ -105,7 +106,7 @@ func (us *UserBackyardService) GetUserPage(ctx context.Context, req *schema.GetU
|
|||
EMail: u.EMail,
|
||||
Rank: u.Rank,
|
||||
DisplayName: u.DisplayName,
|
||||
Avatar: u.Avatar,
|
||||
Avatar: avatar,
|
||||
}
|
||||
if u.Status == entity.UserStatusDeleted {
|
||||
t.Status = schema.UserDeleted
|
||||
|
|
|
@ -76,16 +76,15 @@ func (us *UserCommon) BatchUserBasicInfoByID(ctx context.Context, IDs []string)
|
|||
// UserBasicInfoFormat
|
||||
func (us *UserCommon) UserBasicInfoFormat(ctx context.Context, userInfo *entity.User) *schema.UserBasicInfo {
|
||||
userBasicInfo := &schema.UserBasicInfo{}
|
||||
uinfo := &schema.GetUserResp{}
|
||||
uinfo.AvatarInfo(userInfo.Avatar)
|
||||
Avatar := schema.FormatAvatarInfo(userInfo.Avatar)
|
||||
userBasicInfo.ID = userInfo.ID
|
||||
userBasicInfo.Username = userInfo.Username
|
||||
userBasicInfo.Rank = userInfo.Rank
|
||||
userBasicInfo.DisplayName = userInfo.DisplayName
|
||||
userBasicInfo.Avatar = uinfo.Avatar
|
||||
userBasicInfo.Avatar = Avatar
|
||||
userBasicInfo.Website = userInfo.Website
|
||||
userBasicInfo.Location = userInfo.Location
|
||||
userBasicInfo.IpInfo = userInfo.IPInfo
|
||||
userBasicInfo.IPInfo = userInfo.IPInfo
|
||||
userBasicInfo.Status = schema.UserStatusShow[userInfo.Status]
|
||||
if userBasicInfo.Status == schema.UserDeleted {
|
||||
userBasicInfo.Avatar = ""
|
||||
|
|
|
@ -40,7 +40,8 @@ func NewUserService(userRepo usercommon.UserRepo,
|
|||
userActivity activity.UserActiveActivityRepo,
|
||||
emailService *export.EmailService,
|
||||
authService *auth.AuthService,
|
||||
serviceConfig *service_config.ServiceConfig) *UserService {
|
||||
serviceConfig *service_config.ServiceConfig,
|
||||
) *UserService {
|
||||
return &UserService{
|
||||
userRepo: userRepo,
|
||||
userActivity: userActivity,
|
||||
|
@ -95,7 +96,8 @@ func (us *UserService) GetUserStatus(ctx context.Context, userID, token string)
|
|||
}
|
||||
|
||||
func (us *UserService) GetOtherUserInfoByUsername(ctx context.Context, username string) (
|
||||
resp *schema.GetOtherUserInfoResp, err error) {
|
||||
resp *schema.GetOtherUserInfoResp, err error,
|
||||
) {
|
||||
userInfo, exist, err := us.userRepo.GetByUsername(ctx, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -166,8 +168,8 @@ func (us *UserService) RetrievePassWord(ctx context.Context, req *schema.UserRet
|
|||
UserID: userInfo.ID,
|
||||
}
|
||||
code := uuid.NewString()
|
||||
verifyEmailUrl := fmt.Sprintf("%s/users/password-reset?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.PassResetTemplate(ctx, verifyEmailUrl)
|
||||
verifyEmailURL := fmt.Sprintf("%s/users/password-reset?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.PassResetTemplate(ctx, verifyEmailURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -180,7 +182,7 @@ func (us *UserService) UseRePassWord(ctx context.Context, req *schema.UserRePass
|
|||
data := &schema.EmailCodeContent{}
|
||||
err = data.FromJSONString(req.Content)
|
||||
if err != nil {
|
||||
return nil, errors.BadRequest(reason.EmailVerifyUrlExpired)
|
||||
return nil, errors.BadRequest(reason.EmailVerifyURLExpired)
|
||||
}
|
||||
|
||||
userInfo, exist, err := us.userRepo.GetByEmail(ctx, data.Email)
|
||||
|
@ -204,8 +206,7 @@ func (us *UserService) UseRePassWord(ctx context.Context, req *schema.UserRePass
|
|||
}
|
||||
|
||||
func (us *UserService) UserModifyPassWordVerification(ctx context.Context, request *schema.UserModifyPassWordRequest) (bool, error) {
|
||||
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, request.UserId)
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, request.UserID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -226,7 +227,7 @@ func (us *UserService) UserModifyPassWord(ctx context.Context, request *schema.U
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, request.UserId)
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, request.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -252,21 +253,21 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist && userInfo.ID != req.UserId {
|
||||
if exist && userInfo.ID != req.UserID {
|
||||
return errors.BadRequest(reason.UsernameDuplicate)
|
||||
}
|
||||
}
|
||||
Avatar, err := json.Marshal(req.Avatar)
|
||||
avatar, err := json.Marshal(req.Avatar)
|
||||
if err != nil {
|
||||
err = errors.BadRequest(reason.UserSetAvatar).WithError(err).WithStack()
|
||||
return err
|
||||
}
|
||||
userInfo := entity.User{}
|
||||
userInfo.ID = req.UserId
|
||||
userInfo.Avatar = string(Avatar)
|
||||
userInfo.ID = req.UserID
|
||||
userInfo.Avatar = string(avatar)
|
||||
userInfo.DisplayName = req.DisplayName
|
||||
userInfo.Bio = req.Bio
|
||||
userInfo.BioHtml = req.BioHtml
|
||||
userInfo.BioHTML = req.BioHTML
|
||||
userInfo.Location = req.Location
|
||||
userInfo.Website = req.Website
|
||||
userInfo.Username = req.Username
|
||||
|
@ -286,7 +287,8 @@ func (us *UserService) UserEmailHas(ctx context.Context, email string) (bool, er
|
|||
|
||||
// UserRegisterByEmail user register
|
||||
func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo *schema.UserRegisterReq) (
|
||||
resp *schema.GetUserResp, err error) {
|
||||
resp *schema.GetUserResp, err error,
|
||||
) {
|
||||
_, has, err := us.userRepo.GetByEmail(ctx, registerUserInfo.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -320,8 +322,8 @@ func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo
|
|||
UserID: userInfo.ID,
|
||||
}
|
||||
code := uuid.NewString()
|
||||
verifyEmailUrl := fmt.Sprintf("%s/users/account-activation?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailUrl)
|
||||
verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -363,8 +365,8 @@ func (us *UserService) UserVerifyEmailSend(ctx context.Context, userID string) e
|
|||
UserID: userInfo.ID,
|
||||
}
|
||||
code := uuid.NewString()
|
||||
verifyEmailUrl := fmt.Sprintf("%s/users/account-activation?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailUrl)
|
||||
verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -372,9 +374,10 @@ func (us *UserService) UserVerifyEmailSend(ctx context.Context, userID string) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (us *UserService) UserNoticeSet(ctx context.Context, userId string, noticeSwitch bool) (
|
||||
resp *schema.UserNoticeSetResp, err error) {
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, userId)
|
||||
func (us *UserService) UserNoticeSet(ctx context.Context, userID string, noticeSwitch bool) (
|
||||
resp *schema.UserNoticeSetResp, err error,
|
||||
) {
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -382,9 +385,9 @@ func (us *UserService) UserNoticeSet(ctx context.Context, userId string, noticeS
|
|||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
if noticeSwitch {
|
||||
userInfo.NoticeStatus = schema.Notice_Status_On
|
||||
userInfo.NoticeStatus = schema.NoticeStatusOn
|
||||
} else {
|
||||
userInfo.NoticeStatus = schema.Notice_Status_Off
|
||||
userInfo.NoticeStatus = schema.NoticeStatusOff
|
||||
}
|
||||
err = us.userRepo.UpdateNoticeStatus(ctx, userInfo.ID, userInfo.NoticeStatus)
|
||||
return &schema.UserNoticeSetResp{NoticeSwitch: noticeSwitch}, err
|
||||
|
@ -394,7 +397,7 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri
|
|||
data := &schema.EmailCodeContent{}
|
||||
err = data.FromJSONString(req.Content)
|
||||
if err != nil {
|
||||
return nil, errors.BadRequest(reason.EmailVerifyUrlExpired)
|
||||
return nil, errors.BadRequest(reason.EmailVerifyURLExpired)
|
||||
}
|
||||
|
||||
userInfo, has, err := us.userRepo.GetByEmail(ctx, data.Email)
|
||||
|
@ -476,23 +479,20 @@ func (us *UserService) makeUsername(ctx context.Context, displayName string) (us
|
|||
// Compare whether the password is correct
|
||||
func (us *UserService) verifyPassword(ctx context.Context, LoginPass, UserPass string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(UserPass), []byte(LoginPass))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// encryptPassword
|
||||
// The password does irreversible encryption.
|
||||
func (us *UserService) encryptPassword(ctx context.Context, Pass string) (string, error) {
|
||||
hashPwd, err := bcrypt.GenerateFromPassword([]byte(Pass), bcrypt.DefaultCost)
|
||||
//This encrypted string can be saved to the database and can be used as password matching verification
|
||||
// This encrypted string can be saved to the database and can be used as password matching verification
|
||||
return string(hashPwd), err
|
||||
}
|
||||
|
||||
// UserChangeEmailSendCode user change email verification
|
||||
func (us *UserService) UserChangeEmailSendCode(ctx context.Context, req *schema.UserChangeEmailSendCodeReq) error {
|
||||
_, exist, err := us.userRepo.GetByUserID(ctx, req.UserID)
|
||||
userInfo, exist, err := us.userRepo.GetByUserID(ctx, req.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -513,12 +513,17 @@ func (us *UserService) UserChangeEmailSendCode(ctx context.Context, req *schema.
|
|||
UserID: req.UserID,
|
||||
}
|
||||
code := uuid.NewString()
|
||||
verifyEmailUrl := fmt.Sprintf("%s/users/confirm-new-email?code=%s", us.serviceConfig.WebHost, code)
|
||||
title, body, err := us.emailService.ChangeEmailTemplate(ctx, verifyEmailUrl)
|
||||
var title, body string
|
||||
verifyEmailURL := fmt.Sprintf("%s/users/confirm-new-email?code=%s", us.serviceConfig.WebHost, code)
|
||||
if userInfo.MailStatus == entity.EmailStatusToBeVerified {
|
||||
title, body, err = us.emailService.RegisterTemplate(ctx, verifyEmailURL)
|
||||
} else {
|
||||
title, body, err = us.emailService.ChangeEmailTemplate(ctx, verifyEmailURL)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("send email confirmation %s", verifyEmailUrl)
|
||||
log.Infof("send email confirmation %s", verifyEmailURL)
|
||||
|
||||
go us.emailService.Send(context.Background(), req.Email, title, body, code, data.ToJSONString())
|
||||
return nil
|
||||
|
@ -529,7 +534,7 @@ func (us *UserService) UserChangeEmailVerify(ctx context.Context, content string
|
|||
data := &schema.EmailCodeContent{}
|
||||
err = data.FromJSONString(content)
|
||||
if err != nil {
|
||||
return errors.BadRequest(reason.EmailVerifyUrlExpired)
|
||||
return errors.BadRequest(reason.EmailVerifyURLExpired)
|
||||
}
|
||||
|
||||
_, exist, err := us.userRepo.GetByEmail(ctx, data.Email)
|
||||
|
|
|
@ -67,7 +67,7 @@ func (as *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteRes
|
|||
|
||||
var objectUserID string
|
||||
|
||||
objectUserID, err = as.GetObjectUserId(ctx, dto.ObjectID)
|
||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteR
|
|||
|
||||
var objectUserID string
|
||||
|
||||
objectUserID, err = as.GetObjectUserId(ctx, dto.ObjectID)
|
||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteR
|
|||
}
|
||||
}
|
||||
|
||||
func (vs *VoteService) GetObjectUserId(ctx context.Context, objectID string) (userID string, err error) {
|
||||
func (vs *VoteService) GetObjectUserID(ctx context.Context, objectID string) (userID string, err error) {
|
||||
var objectKey string
|
||||
objectKey, err = obj.GetObjectTypeStrByObjectID(objectID)
|
||||
|
||||
|
@ -162,7 +162,8 @@ func (vs *VoteService) ListUserVotes(ctx context.Context, req schema.GetVoteWith
|
|||
)
|
||||
|
||||
for _, typeKey := range typeKeys {
|
||||
t, err := vs.configRepo.GetConfigType(typeKey)
|
||||
var t int
|
||||
t, err = vs.configRepo.GetConfigType(typeKey)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@ -175,7 +176,8 @@ func (vs *VoteService) ListUserVotes(ctx context.Context, req schema.GetVoteWith
|
|||
}
|
||||
|
||||
for _, voteInfo := range voteList {
|
||||
objInfo, err := vs.objectService.GetInfo(ctx, voteInfo.ObjectID)
|
||||
var objInfo *schema.SimpleObjectInfo
|
||||
objInfo, err = vs.objectService.GetInfo(ctx, voteInfo.ObjectID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
|
|
@ -3,12 +3,10 @@ package checker
|
|||
import "unicode"
|
||||
|
||||
func IsChinese(str string) bool {
|
||||
var count int
|
||||
for _, v := range str {
|
||||
if unicode.Is(unicode.Han, v) {
|
||||
count++
|
||||
break
|
||||
return true
|
||||
}
|
||||
}
|
||||
return count > 0
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func CheckPassword(minLength, maxLength, minLevel int, pwd string) error {
|
|||
// The password strength level is initialized to D.
|
||||
// The regular is used to verify the password strength.
|
||||
// If the matching is successful, the password strength increases by 1
|
||||
var level int = levelD
|
||||
level := levelD
|
||||
patternList := []string{`[0-9]+`, `[a-z]+`, `[A-Z]+`, `[~!@#$%^&*?_-]+`}
|
||||
for _, pattern := range patternList {
|
||||
match, _ := regexp.MatchString(pattern, pwd)
|
||||
|
@ -41,7 +41,7 @@ func CheckPassword(minLength, maxLength, minLevel int, pwd string) error {
|
|||
|
||||
// If the final password strength falls below the required minimum strength, return with an error
|
||||
if level < minLevel {
|
||||
return fmt.Errorf("The password does not satisfy the current policy requirements. ")
|
||||
return fmt.Errorf("the password does not satisfy the current policy requirements")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ type SnowFlakeID struct {
|
|||
var snowFlakeIDGenerator *SnowFlakeID
|
||||
|
||||
func init() {
|
||||
//todo
|
||||
// todo
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
node, err := snowflake.NewNode(int64(rand.Intn(1000)) + 1)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"jsxBracketSameLine": true,
|
||||
"printWidth": 80
|
||||
}
|
||||
"printWidth": 80,
|
||||
"endOfLine": "auto"
|
||||
}
|
|
@ -25,8 +25,7 @@ module.exports = {
|
|||
const config = configFunction(proxy, allowedHost);
|
||||
config.proxy = {
|
||||
'/answer': {
|
||||
target: "http://10.0.20.84:8080",
|
||||
// target: 'http://10.0.10.98:2060',
|
||||
target: 'http://10.0.10.98:2060',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
"katex": "^0.16.2",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "^4.0.19",
|
||||
"md5": "^2.3.0",
|
||||
"mermaid": "^9.1.7",
|
||||
"next-share": "^0.18.1",
|
||||
"qs": "^6.11.0",
|
||||
|
|
|
@ -57,6 +57,7 @@ specifiers:
|
|||
lint-staged: ^13.0.3
|
||||
lodash: ^4.17.21
|
||||
marked: ^4.0.19
|
||||
md5: ^2.3.0
|
||||
mermaid: ^9.1.7
|
||||
next-share: ^0.18.1
|
||||
postcss: ^8.0.0
|
||||
|
@ -96,6 +97,7 @@ dependencies:
|
|||
katex: 0.16.2
|
||||
lodash: 4.17.21
|
||||
marked: 4.1.0
|
||||
md5: 2.3.0
|
||||
mermaid: 9.1.7
|
||||
next-share: 0.18.1_lbqamd2wfmenkveygahn4wdfcq
|
||||
qs: 6.11.0
|
||||
|
@ -152,7 +154,7 @@ devDependencies:
|
|||
prettier: 2.7.1
|
||||
purgecss-webpack-plugin: 4.1.3
|
||||
react-app-rewired: 2.2.1_react-scripts@5.0.1
|
||||
react-scripts: 5.0.1_r727nmttzgvwuocpb6eyxi2m5i
|
||||
react-scripts: 5.0.1_vcopaw66ubzwqe5wj7m4edgwnq
|
||||
sass: 1.54.9
|
||||
tsconfig-paths-webpack-plugin: 4.0.0
|
||||
typescript: 4.8.3
|
||||
|
@ -3660,6 +3662,10 @@ packages:
|
|||
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
|
||||
dev: true
|
||||
|
||||
/charenc/0.0.2:
|
||||
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
|
||||
dev: false
|
||||
|
||||
/check-types/11.1.2:
|
||||
resolution: {integrity: sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==}
|
||||
|
||||
|
@ -4060,8 +4066,8 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-text-path: 1.0.1
|
||||
JSONStream: 1.3.5
|
||||
is-text-path: 1.0.1
|
||||
lodash: 4.17.21
|
||||
meow: 8.1.2
|
||||
split2: 3.2.2
|
||||
|
@ -4157,6 +4163,10 @@ packages:
|
|||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
/crypt/0.0.2:
|
||||
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
|
||||
dev: false
|
||||
|
||||
/crypto-random-string/2.0.0:
|
||||
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -6807,6 +6817,10 @@ packages:
|
|||
call-bind: 1.0.2
|
||||
has-tostringtag: 1.0.0
|
||||
|
||||
/is-buffer/1.1.6:
|
||||
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
|
||||
dev: false
|
||||
|
||||
/is-callable/1.2.6:
|
||||
resolution: {integrity: sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -7966,6 +7980,14 @@ packages:
|
|||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/md5/2.3.0:
|
||||
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
|
||||
dependencies:
|
||||
charenc: 0.0.2
|
||||
crypt: 0.0.2
|
||||
is-buffer: 1.1.6
|
||||
dev: false
|
||||
|
||||
/mdn-data/2.0.14:
|
||||
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
|
||||
|
||||
|
@ -8167,7 +8189,7 @@ packages:
|
|||
jsonp: 0.2.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-scripts: 5.0.1_r727nmttzgvwuocpb6eyxi2m5i
|
||||
react-scripts: 5.0.1_vcopaw66ubzwqe5wj7m4edgwnq
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
@ -9497,7 +9519,7 @@ packages:
|
|||
peerDependencies:
|
||||
react-scripts: '>=2.1.3'
|
||||
dependencies:
|
||||
react-scripts: 5.0.1_r727nmttzgvwuocpb6eyxi2m5i
|
||||
react-scripts: 5.0.1_vcopaw66ubzwqe5wj7m4edgwnq
|
||||
semver: 5.7.1
|
||||
dev: true
|
||||
|
||||
|
@ -9531,6 +9553,12 @@ packages:
|
|||
/react-dev-utils/12.0.1_npfwkgbcmgrbevrxnqgustqabe:
|
||||
resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
typescript: '>=2.7'
|
||||
webpack: '>=4'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.18.6
|
||||
address: 1.2.1
|
||||
|
@ -9561,9 +9589,7 @@ packages:
|
|||
transitivePeerDependencies:
|
||||
- eslint
|
||||
- supports-color
|
||||
- typescript
|
||||
- vue-template-compiler
|
||||
- webpack
|
||||
|
||||
/react-dom/18.2.0_react@18.2.0:
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
|
@ -9655,11 +9681,12 @@ packages:
|
|||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-scripts/5.0.1_r727nmttzgvwuocpb6eyxi2m5i:
|
||||
/react-scripts/5.0.1_vcopaw66ubzwqe5wj7m4edgwnq:
|
||||
resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
eslint: '*'
|
||||
react: '>= 16'
|
||||
typescript: ^3.2.1 || ^4
|
||||
peerDependenciesMeta:
|
||||
|
@ -9708,7 +9735,7 @@ packages:
|
|||
semver: 7.3.7
|
||||
source-map-loader: 3.0.1_webpack@5.74.0
|
||||
style-loader: 3.3.1_webpack@5.74.0
|
||||
tailwindcss: 3.1.8
|
||||
tailwindcss: 3.1.8_postcss@8.4.16
|
||||
terser-webpack-plugin: 5.3.6_webpack@5.74.0
|
||||
typescript: 4.8.3
|
||||
webpack: 5.74.0
|
||||
|
@ -10686,10 +10713,12 @@ packages:
|
|||
/symbol-tree/3.2.4:
|
||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||
|
||||
/tailwindcss/3.1.8:
|
||||
/tailwindcss/3.1.8_postcss@8.4.16:
|
||||
resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==}
|
||||
engines: {node: '>=12.13.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
postcss: ^8.0.9
|
||||
dependencies:
|
||||
arg: 5.0.2
|
||||
chokidar: 3.5.3
|
||||
|
|
|
@ -2,6 +2,7 @@ export interface FormValue<T = any> {
|
|||
value: T;
|
||||
isInvalid: boolean;
|
||||
errorMsg: string;
|
||||
[prop: string]: any;
|
||||
}
|
||||
|
||||
export interface FormDataType {
|
||||
|
@ -89,7 +90,7 @@ export interface ModifyPasswordReq {
|
|||
export interface ModifyUserReq {
|
||||
display_name: string;
|
||||
username?: string;
|
||||
avatar: string;
|
||||
avatar: any;
|
||||
bio: string;
|
||||
bio_html?: string;
|
||||
location: string;
|
||||
|
@ -97,7 +98,7 @@ export interface ModifyUserReq {
|
|||
}
|
||||
|
||||
export interface UserInfoBase {
|
||||
avatar: string;
|
||||
avatar: any;
|
||||
username: string;
|
||||
display_name: string;
|
||||
rank: number;
|
||||
|
|
|
@ -6,15 +6,28 @@ import DefaultAvatar from '@/assets/images/default-avatar.svg';
|
|||
|
||||
interface IProps {
|
||||
/** avatar url */
|
||||
avatar: string;
|
||||
avatar: string | { type: string; gravatar: string; custom: string };
|
||||
/** size 48 96 128 256 */
|
||||
size: string;
|
||||
searchStr?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Index: FC<IProps> = ({ avatar, size, className }) => {
|
||||
const Index: FC<IProps> = ({ avatar, size, className, searchStr = '' }) => {
|
||||
let url = '';
|
||||
if (typeof avatar === 'string') {
|
||||
if (avatar.length > 1) {
|
||||
url = `${avatar}?${searchStr}`;
|
||||
}
|
||||
} else if (avatar?.type === 'gravatar') {
|
||||
url = `${avatar.gravatar}?${searchStr}&d=identicon`;
|
||||
} else if (avatar?.type === 'custom') {
|
||||
url = `${avatar.custom}?${searchStr}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
src={avatar || DefaultAvatar}
|
||||
src={url || DefaultAvatar}
|
||||
width={size}
|
||||
height={size}
|
||||
className={classNames('rounded', className)}
|
||||
|
|
|
@ -9,6 +9,7 @@ interface Props {
|
|||
data: any;
|
||||
showAvatar?: boolean;
|
||||
avatarSize?: string;
|
||||
avatarSearchStr?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
|
@ -17,20 +18,31 @@ const Index: FC<Props> = ({
|
|||
showAvatar = true,
|
||||
avatarSize = '20px',
|
||||
className = 'fs-14',
|
||||
avatarSearchStr = 's=48',
|
||||
}) => {
|
||||
return (
|
||||
<div className={`text-secondary ${className}`}>
|
||||
{data?.status !== 'deleted' ? (
|
||||
<Link to={`/users/${data?.username}`}>
|
||||
{showAvatar && (
|
||||
<Avatar avatar={data?.avatar} size={avatarSize} className="me-1" />
|
||||
<Avatar
|
||||
avatar={data?.avatar}
|
||||
size={avatarSize}
|
||||
className="me-1"
|
||||
searchStr={avatarSearchStr}
|
||||
/>
|
||||
)}
|
||||
<span className="me-1 text-break">{data?.display_name}</span>
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
{showAvatar && (
|
||||
<Avatar avatar={data?.avatar} size={avatarSize} className="me-1" />
|
||||
<Avatar
|
||||
avatar={data?.avatar}
|
||||
size={avatarSize}
|
||||
className="me-1"
|
||||
searchStr={avatarSearchStr}
|
||||
/>
|
||||
)}
|
||||
<span className="me-1 text-break">{data?.display_name}</span>
|
||||
</>
|
||||
|
|
|
@ -19,7 +19,9 @@ const Form = ({ userName, onSendReply, onCancel, mode }) => {
|
|||
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="fs-14 mb-2">Reply to {userName}</div>
|
||||
<div className="fs-14 mb-2">
|
||||
{t('reply_to')} {userName}
|
||||
</div>
|
||||
<div className="d-flex mb-1 align-items-start flex-column flex-md-row">
|
||||
<div>
|
||||
<Mentions
|
||||
|
|
|
@ -43,7 +43,7 @@ const Index: FC<Props> = ({ redDot, userInfo, logOut }) => {
|
|||
id="dropdown-basic"
|
||||
as="a"
|
||||
className="no-toggle pointer">
|
||||
<Avatar size="36px" avatar={userInfo?.avatar} />
|
||||
<Avatar size="36px" avatar={userInfo?.avatar} searchStr="s=96" />
|
||||
</Dropdown.Toggle>
|
||||
|
||||
<Dropdown.Menu>
|
||||
|
|
|
@ -41,7 +41,7 @@ const QuestionLastUpdate = ({ q }) => {
|
|||
•
|
||||
<FormatTime
|
||||
time={q.update_time}
|
||||
className="text-secondary mx-1"
|
||||
className="text-secondary ms-1"
|
||||
preFix={t('answered')}
|
||||
/>
|
||||
</div>
|
||||
|
@ -60,7 +60,7 @@ const QuestionLastUpdate = ({ q }) => {
|
|||
•
|
||||
<FormatTime
|
||||
time={q.edit_time}
|
||||
className="text-secondary mx-1"
|
||||
className="text-secondary ms-1"
|
||||
preFix={t('modified')}
|
||||
/>
|
||||
</div>
|
||||
|
@ -75,7 +75,7 @@ const QuestionLastUpdate = ({ q }) => {
|
|||
<FormatTime
|
||||
time={q.create_time}
|
||||
preFix={t('asked')}
|
||||
className="text-secondary mx-1"
|
||||
className="text-secondary ms-1"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -136,7 +136,7 @@ const QuestionList: FC<Props> = ({ source }) => {
|
|||
<div className="ms-0 ms-md-3 mt-2 mt-md-0">
|
||||
<span>
|
||||
<Icon name="hand-thumbs-up-fill" />
|
||||
<em className="fst-normal mx-1">{li.vote_count}</em>
|
||||
<em className="fst-normal ms-1">{li.vote_count}</em>
|
||||
</span>
|
||||
<span
|
||||
className={`ms-3 ${
|
||||
|
@ -149,11 +149,11 @@ const QuestionList: FC<Props> = ({ source }) => {
|
|||
: 'chat-square-text-fill'
|
||||
}
|
||||
/>
|
||||
<em className="fst-normal mx-1">{li.answer_count}</em>
|
||||
<em className="fst-normal ms-1">{li.answer_count}</em>
|
||||
</span>
|
||||
<span className="summary-stat ms-3">
|
||||
<Icon name="eye-fill" />
|
||||
<em className="fst-normal mx-1">{li.view_count}</em>
|
||||
<em className="fst-normal ms-1">{li.view_count}</em>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Col } from 'react-bootstrap';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { resendEmail, checkImgCode } from '@answer/api';
|
||||
import { PicAuthCodeModal } from '@answer/components/Modal';
|
||||
|
@ -120,6 +121,9 @@ const Index: React.FC<IProps> = ({ visible = false }) => {
|
|||
<Button variant="link" onClick={onSentEmail}>
|
||||
{t('btn_name')}
|
||||
</Button>
|
||||
<Link to="/users/change-email" replace className="btn btn-link ms-2">
|
||||
{t('change_btn_name')}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
|
@ -23,16 +23,23 @@ const Index: FC<Props> = ({ data, time, preFix, className = '' }) => {
|
|||
avatar={data?.avatar}
|
||||
size="40px"
|
||||
className="me-2 d-none d-md-block"
|
||||
searchStr="s=96"
|
||||
/>
|
||||
|
||||
<Avatar
|
||||
avatar={data?.avatar}
|
||||
size="24px"
|
||||
className="me-2 d-block d-md-none"
|
||||
searchStr="s=48"
|
||||
/>
|
||||
</Link>
|
||||
) : (
|
||||
<Avatar avatar={data?.avatar} size="40px" className="me-2" />
|
||||
<Avatar
|
||||
avatar={data?.avatar}
|
||||
size="40px"
|
||||
className="me-2"
|
||||
searchStr="s=96"
|
||||
/>
|
||||
)}
|
||||
<div className="fs-14 text-secondary d-flex flex-row flex-md-column align-items-center align-items-md-start">
|
||||
<div className="me-1 me-md-0">
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
"account_activation": "Account Activation",
|
||||
"confirm_email": "Confirm Email",
|
||||
"account_suspended": "Account Suspended",
|
||||
"admin": "Admin"
|
||||
"admin": "Admin",
|
||||
"change_email": "Modify Email"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
|
@ -250,7 +251,7 @@
|
|||
"synonyms_text": "The following tags will be remapped to",
|
||||
"delete": {
|
||||
"title": "Delete this tag",
|
||||
"content": "<p>We do not allowed deleting tag with posts.</p><p>Please remove the python tag from the posts first.</p>",
|
||||
"content": "<p>We do not allowed deleting tag with posts.</p><p>Please remove this tag from the posts first.</p>",
|
||||
"content2": "Are you sure you wish to delete?",
|
||||
"close": "Close"
|
||||
}
|
||||
|
@ -403,7 +404,7 @@
|
|||
}
|
||||
},
|
||||
"footer": {
|
||||
"build_on": "Build on <1> Answer </1>- the open-source software that power Q&A communities.<br />Made with love. © 2022 Answer."
|
||||
"build_on": "Built on <1> Answer </1>- the open-source software that power Q&A communities<br />Made with love © 2022 Answer"
|
||||
},
|
||||
"upload_img": {
|
||||
"name": "Change",
|
||||
|
@ -421,6 +422,7 @@
|
|||
"info": "If it doesn't arrive, check your spam folder.",
|
||||
"another": "We sent another activation email to you at <bold>{{mail}}</bold>. It might take a few minutes for it to arrive; be sure to check your spam folder.",
|
||||
"btn_name": "Resend activation email",
|
||||
"change_btn_name": "Change email",
|
||||
"msg": {
|
||||
"empty": "Cannot be empty."
|
||||
}
|
||||
|
@ -462,6 +464,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"change_email": {
|
||||
"page_title": "Welcome to Answer",
|
||||
"btn_cancel": "Cancel",
|
||||
"btn_update": "Update email address",
|
||||
"send_success": "If an account matches <strong>{{mail}}</strong>, you should receive an email with instructions on how to reset your password shortly.",
|
||||
"email": {
|
||||
"label": "New Email",
|
||||
"msg": {
|
||||
"empty": "Email cannot be empty."
|
||||
}
|
||||
}
|
||||
},
|
||||
"password_reset": {
|
||||
"page_title": "Password Reset",
|
||||
"btn_name": "Reset my password",
|
||||
|
@ -504,7 +518,12 @@
|
|||
},
|
||||
"avatar": {
|
||||
"label": "Profile Image",
|
||||
"text": "You can upload your image or <1>reset</1> it to"
|
||||
"gravatar": "Gravatar",
|
||||
"gravatar_text": "You can change image on <1>gravatar.com</1>",
|
||||
"custom": "Custom",
|
||||
"btn_refresh": "Refresh",
|
||||
"custom_text": "You can upload your image.",
|
||||
"default": "Default"
|
||||
},
|
||||
"bio": {
|
||||
"label": "About Me (optional)"
|
||||
|
@ -572,6 +591,8 @@
|
|||
"update": "Modified",
|
||||
"edit": "edited",
|
||||
"Views": "Viewed",
|
||||
"Follow": "Follow",
|
||||
"Following": "Following",
|
||||
"answered": "answered",
|
||||
"closed_in": "Closed in",
|
||||
"show_exist": "Show existing question.",
|
||||
|
|
|
@ -1,45 +1,440 @@
|
|||
{
|
||||
"how_to_format": {
|
||||
"title": "如何设定文本格式",
|
||||
"description": "<ul class=\"mb-0\"><li><p class=\"mb-2\">添加链接:</p><pre class=\"mb-2\"><code><https://url.com><br/><br/>[标题](https://url.com)</code></pre></li><li><p class=\"mb-2\">段落之间使用空行分隔</p></li><li><p class=\"mb-2\"><em>_斜体_</em> 或者 **<strong>粗体</strong>**</p></li><li><p class=\"mb-2\">使用 4 个空格缩进代码</p></li><li><p class=\"mb-2\">在行首添加<code>></code>表示引用</p></li><li><p class=\"mb-2\">反引号进行转义 <code>`像 _这样_`</code></p></li><li><p class=\"mb-2\">使用<code>```</code>创建代码块</p><pre class=\"mb-0\"><code>```<br/>// 这是代码<br/>```</code></pre></li></ul>"
|
||||
},
|
||||
"pagination": {
|
||||
"prev": "上一页",
|
||||
"next": "下一页"
|
||||
},
|
||||
"page_title": {
|
||||
"question": "问题",
|
||||
"questions": "问题",
|
||||
"tag": "标签",
|
||||
"tags": "标签",
|
||||
"tag_wiki": "标签 wiki",
|
||||
"edit_tag": "编辑标签",
|
||||
"ask_a_question": "提问题",
|
||||
"edit_question": "编辑问题",
|
||||
"edit_answer": "编辑回答",
|
||||
"search": "搜索",
|
||||
"posts_containing": "包含",
|
||||
"settings": "设定",
|
||||
"notifications": "通知",
|
||||
"login": "登录",
|
||||
"sign_up": "注册",
|
||||
"account_recovery": "账号恢复",
|
||||
"account_activation": "账号激活",
|
||||
"confirm_email": "确认电子邮件",
|
||||
"account_suspended": "账号已封禁",
|
||||
"admin": "后台管理"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "通知",
|
||||
"inbox": "收件箱",
|
||||
"achievement": "成就",
|
||||
"all_read": "全部标记为已读",
|
||||
"show_more": "显示更多"
|
||||
},
|
||||
"suspended": {
|
||||
"title": "账号已封禁",
|
||||
"until_time": "你的账号被封禁至{{ time }}。",
|
||||
"forever": "你的账号已被永久封禁。",
|
||||
"end": "违反了我们的社区准则。"
|
||||
},
|
||||
"editor": {
|
||||
"blockquote": {
|
||||
"text": "引用"
|
||||
},
|
||||
"bold": {
|
||||
"text": "粗体"
|
||||
},
|
||||
"chart": {
|
||||
"text": "图表",
|
||||
"flow_chart": "流程图",
|
||||
"sequence_diagram": "时序图",
|
||||
"class_diagram": "类图",
|
||||
"state_diagram": "状态图",
|
||||
"entity_relationship_diagram": "ER 图",
|
||||
"user_defined_diagram": "User defined diagram",
|
||||
"gantt_chart": "甘特图",
|
||||
"pie_chart": "饼图"
|
||||
},
|
||||
"code": {
|
||||
"text": "代码块",
|
||||
"add_code": "添加代码块",
|
||||
"form": {
|
||||
"fields": {
|
||||
"code": {
|
||||
"label": "代码块",
|
||||
"msg": {
|
||||
"empty": "代码块不能为空"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"label": "语言 (可选)",
|
||||
"placeholder": "自动识别"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_cancel": "取消",
|
||||
"btn_confirm": "添加"
|
||||
},
|
||||
"formula": {
|
||||
"text": "公式",
|
||||
"options": {
|
||||
"inline": "行内公式",
|
||||
"block": "公式块"
|
||||
}
|
||||
},
|
||||
"heading": {
|
||||
"text": "标题",
|
||||
"options": {
|
||||
"h1": "标题 1",
|
||||
"h2": "标题 2",
|
||||
"h3": "标题 3",
|
||||
"h4": "标题 4",
|
||||
"h5": "标题 5",
|
||||
"h6": "标题 6"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"text": "帮助"
|
||||
},
|
||||
"hr": {
|
||||
"text": "水平分割线"
|
||||
},
|
||||
"image": {
|
||||
"text": "图片",
|
||||
"add_image": "添加图片",
|
||||
"tab_image": "上传图片",
|
||||
"form_image": {
|
||||
"fields": {
|
||||
"file": {
|
||||
"label": "图片文件",
|
||||
"btn": "选择图片",
|
||||
"msg": {
|
||||
"empty": "请选择图片文件。",
|
||||
"only_image": "只能上传图片文件。",
|
||||
"max_size": "图片文件大小不能超过 4 MB。"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"label": "图片描述(可选)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tab_url": "网络图片",
|
||||
"form_url": {
|
||||
"fields": {
|
||||
"url": {
|
||||
"label": "图片地址",
|
||||
"msg": {
|
||||
"empty": "图片地址不能为空"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"label": "图片描述(可选)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_cancel": "取消",
|
||||
"btn_confirm": "添加",
|
||||
"uploading": "上传中..."
|
||||
},
|
||||
"indent": {
|
||||
"text": "添加缩进"
|
||||
},
|
||||
"outdent": {
|
||||
"text": "减少缩进"
|
||||
},
|
||||
"italic": {
|
||||
"text": "斜体"
|
||||
},
|
||||
"link": {
|
||||
"text": "超链接",
|
||||
"add_link": "添加超链接",
|
||||
"form": {
|
||||
"fields": {
|
||||
"url": {
|
||||
"label": "链接",
|
||||
"msg": {
|
||||
"empty": "链接不能为空。"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"label": "链接描述(可选)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_cancel": "取消",
|
||||
"btn_confirm": "添加"
|
||||
},
|
||||
"ordered_list": {
|
||||
"text": "有编号列表"
|
||||
},
|
||||
"unordered_list": {
|
||||
"text": "无编号列表"
|
||||
},
|
||||
"table": {
|
||||
"text": "表格",
|
||||
"heading": "表头",
|
||||
"cell": "单元格"
|
||||
}
|
||||
},
|
||||
"close_modal": {
|
||||
"title": "关闭原因是...",
|
||||
"btn_cancel": "取消",
|
||||
"btn_submit": "提交",
|
||||
"remark": {
|
||||
"empty": "不能为空。"
|
||||
},
|
||||
"msg": {
|
||||
"empty": "请选择一个原因。"
|
||||
}
|
||||
},
|
||||
"report_modal": {
|
||||
"flag_title": "举报原因是...",
|
||||
"close_title": "关闭原因是...",
|
||||
"review_question_title": "审查问题",
|
||||
"review_answer_title": "审查回答",
|
||||
"review_comment_title": "审查评论",
|
||||
"btn_cancel": "取消",
|
||||
"btn_submit": "提交",
|
||||
"remark": {
|
||||
"empty": "不能为空"
|
||||
},
|
||||
"msg": {
|
||||
"empty": "请选择一个原因。"
|
||||
}
|
||||
},
|
||||
"tag_modal": {
|
||||
"title": "创建新标签",
|
||||
"form": {
|
||||
"fields": {
|
||||
"display_name": {
|
||||
"label": "显示名称(别名)",
|
||||
"msg": {
|
||||
"empty": "不能为空",
|
||||
"range": "不能超过 35 个字符"
|
||||
}
|
||||
},
|
||||
"slug_name": {
|
||||
"label": "URL 固定链接",
|
||||
"description": "必须由 \"a-z\", \"0-9\", \"+ # - .\" 组成",
|
||||
"msg": {
|
||||
"empty": "不能为空",
|
||||
"range": "不能超过 35 个字符",
|
||||
"character": "包含非法字符"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"label": "标签描述(可选)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_cancel": "取消",
|
||||
"btn_submit": "提交"
|
||||
},
|
||||
"tag_info": {
|
||||
"created_at": "创建于",
|
||||
"edited_at": "编辑于",
|
||||
"synonyms": {
|
||||
"title": "同义词",
|
||||
"text": "以下标签等同于",
|
||||
"empty": "此标签目前没有同义词。",
|
||||
"btn_add": "添加同义词",
|
||||
"btn_edit": "编辑",
|
||||
"btn_save": "保存"
|
||||
},
|
||||
"synonyms_text": "以下标签等同于",
|
||||
"delete": {
|
||||
"title": "删除标签",
|
||||
"content": "<p>不允许删除有关联问题的标签。</p><p>请先从关联的问题中删除此标签的引用。</p>",
|
||||
"content2": "确定要删除吗?",
|
||||
"close": "关闭"
|
||||
}
|
||||
},
|
||||
"edit_tag": {
|
||||
"title": "编辑标签",
|
||||
"default_reason": "编辑标签",
|
||||
"form": {
|
||||
"fields": {
|
||||
"revision": {
|
||||
"label": "编辑历史"
|
||||
},
|
||||
"display_name": {
|
||||
"label": "名称"
|
||||
},
|
||||
"slug_name": {
|
||||
"label": "URL 固定链接",
|
||||
"info": "必须由 \"a-z\", \"0-9\", \"+ # - .\" 组成"
|
||||
},
|
||||
"description": {
|
||||
"label": "描述"
|
||||
},
|
||||
"edit_summary": {
|
||||
"label": "编辑概要",
|
||||
"placeholder": "简单描述更改原因 (错别字、文字表达、格式等等)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_save_edits": "保存更改",
|
||||
"btn_cancel": "取消"
|
||||
},
|
||||
"dates": {
|
||||
"long_date": "YYYY年MM月",
|
||||
"long_date_with_year": "YYYY年MM月DD日",
|
||||
"long_date_with_time": "YYYY年MM月DD日 HH:mm",
|
||||
"now": "刚刚",
|
||||
"x_seconds_ago": "{{count}} 秒前",
|
||||
"x_minutes_ago": "{{count}} 分钟前",
|
||||
"x_hours_ago": "{{count}} 小时前"
|
||||
},
|
||||
"comment": {
|
||||
"btn_add_comment": "添加评论",
|
||||
"reply_to": "回复",
|
||||
"btn_reply": "回复",
|
||||
"btn_edit": "编辑",
|
||||
"btn_delete": "删除",
|
||||
"btn_flag": "举报",
|
||||
"btn_save_edits": "保存",
|
||||
"btn_cancel": "取消",
|
||||
"show_more": "显示更多评论",
|
||||
"tip_question": "使用评论提问更多信息或者提出改进意见。尽量避免使用评论功能回答问题。",
|
||||
"tip_answer": "使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。"
|
||||
},
|
||||
"edit_answer": {
|
||||
"title": "编辑回答",
|
||||
"default_reason": "编辑回答",
|
||||
"form": {
|
||||
"fields": {
|
||||
"revision": {
|
||||
"label": "编辑历史"
|
||||
},
|
||||
"answer": {
|
||||
"label": "回答内容"
|
||||
},
|
||||
"edit_summary": {
|
||||
"label": "编辑概要",
|
||||
"placeholder": "简单描述更改原因 (错别字、文字表达、格式等等)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_save_edits": "保存更改",
|
||||
"btn_cancel": "取消"
|
||||
},
|
||||
"tags": {
|
||||
"title": "标签",
|
||||
"sort_buttons": {
|
||||
"popular": "热门",
|
||||
"name": "名称",
|
||||
"newest": "最新"
|
||||
},
|
||||
"button_follow": "关注",
|
||||
"button_following": "已关注",
|
||||
"tag_label": "个问题",
|
||||
"search_placeholder": "通过标签名过滤",
|
||||
"no_description": "此标签无描述。",
|
||||
"more": "更多"
|
||||
},
|
||||
"ask": {
|
||||
"title": "提交新的问题",
|
||||
"edit_title": "编辑问题",
|
||||
"default_reason": "编辑问题",
|
||||
"similar_questions": "相似的问题",
|
||||
"form": {
|
||||
"fields": {
|
||||
"revision": {
|
||||
"label": "编辑历史"
|
||||
},
|
||||
"title": {
|
||||
"label": "标题",
|
||||
"placeholder": "请详细描述你的问题",
|
||||
"msg": {
|
||||
"empty": "标题不能为空",
|
||||
"range": "标题最多 150 个字符"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"label": "内容",
|
||||
"msg": {
|
||||
"empty": "内容不能为空"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"label": "标签",
|
||||
"msg": {
|
||||
"empty": "必须选择一个标签"
|
||||
}
|
||||
},
|
||||
"answer": {
|
||||
"label": "回答内容",
|
||||
"msg": {
|
||||
"empty": "回答内容不能为空"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"btn_post_question": "提交问题",
|
||||
"btn_save_edits": "保存更改",
|
||||
"answer_question": "直接发表回答",
|
||||
"post_question&answer": "提交问题和回答"
|
||||
},
|
||||
"tag_selector": {
|
||||
"add_btn": "添加标签",
|
||||
"create_btn": "创建新标签",
|
||||
"search_tag": "搜索标签",
|
||||
"hint": "选择至少一个与问题相关的标签。",
|
||||
"no_result": "没有匹配的标签"
|
||||
},
|
||||
"header": {
|
||||
"nav": {
|
||||
"question": "问题",
|
||||
"tag": "标签",
|
||||
"user": "用户",
|
||||
"profile": "个人主页",
|
||||
"setting": "个人设置",
|
||||
"logout": "退出登录"
|
||||
"profile": "用户主页",
|
||||
"setting": "账号设置",
|
||||
"logout": "退出登录",
|
||||
"admin": "后台管理"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "搜索"
|
||||
},
|
||||
"add_question": "提问题"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"build_on": "Built on <1> Answer </1>- the open-source software that power Q&A communities<br />Made with love © 2022 Answer"
|
||||
},
|
||||
"upload_img": {
|
||||
"name": "更改图片",
|
||||
"loading": "加载中..."
|
||||
},
|
||||
"pic_auth_code": {
|
||||
"btn_name": "验证",
|
||||
"title": "验证码",
|
||||
"placeholder": "输入上面的文字",
|
||||
"placeholder": "输入图片中的文字",
|
||||
"msg": {
|
||||
"empty": "不能为空"
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"first": "你几乎已经完成!我们发送了一封激活邮件到 <strong>{{mail}}</strong>. 请按照邮件中的说明激活您的帐户。",
|
||||
"first": "马上就好了!我们发送了一封激活邮件到 <bold>{{mail}}</bold>。请按照邮件中的说明激活您的帐户。",
|
||||
"info": "如果没有收到,请检查您的垃圾邮件文件夹。",
|
||||
"another": "我们向您发送了另一封激活电子邮件,地址为 <strong>{{mail}}</strong>. 它可能需要几分钟才能到达;请务必检查您的垃圾邮件文件夹。",
|
||||
"btn_name": "重新发送激活电邮",
|
||||
"another": "我们向您发送了另一封激活电子邮件,地址为 <bold>{{mail}}</bold>。它可能需要几分钟才能到达;请务必检查您的垃圾邮件文件夹。",
|
||||
"btn_name": "重新发送激活邮件",
|
||||
"msg": {
|
||||
"empty": "不能为空"
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"page_title": "欢迎来到 Answer",
|
||||
"btn_name": "登录",
|
||||
"info_sign": "没有帐户?<1>注册</1>",
|
||||
"info_login": "已经有一个帐户?<1>登录</1>",
|
||||
"forgot_pass": "忘记密码?",
|
||||
"name": {
|
||||
"label": "昵称",
|
||||
"msg": {
|
||||
"empty": "昵称不能为空"
|
||||
"empty": "昵称不能为空",
|
||||
"range": "昵称最多 30 个字符"
|
||||
}
|
||||
},
|
||||
"email": {
|
||||
|
@ -56,7 +451,464 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"build_on": "由 <1> Answer </1>构建- 为知识社区提供动力的开源软件.<br />Made with love. © 2022 Answer ."
|
||||
"account_forgot": {
|
||||
"page_title": "忘记密码",
|
||||
"btn_name": "发送恢复邮件",
|
||||
"send_success": "如无意外,你的邮箱 <strong>{{mail}}</strong> 将会收到一封重置密码的邮件,请根据指引重置你的密码。",
|
||||
"email": {
|
||||
"label": "邮箱",
|
||||
"msg": {
|
||||
"empty": "邮箱不能为空"
|
||||
}
|
||||
}
|
||||
},
|
||||
"password_reset": {
|
||||
"page_title": "密码重置",
|
||||
"btn_name": "重置我的密码",
|
||||
"reset_success": "你已经成功更改密码,将返回登录页面",
|
||||
"link_invalid": "抱歉,此密码重置链接已失效。也许是你已经重置过密码了?",
|
||||
"to_login": "前往登录页面",
|
||||
"password": {
|
||||
"label": "密码",
|
||||
"msg": {
|
||||
"empty": "密码不能为空",
|
||||
"length": "密码长度在8-32个字符之间",
|
||||
"different": "两次输入密码不一致"
|
||||
}
|
||||
},
|
||||
"password_confirm": {
|
||||
"label": "确认新密码"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"page_title": "设置",
|
||||
"nav": {
|
||||
"profile": "我的资料",
|
||||
"notification": "通知",
|
||||
"account": "账号",
|
||||
"interface": "界面"
|
||||
},
|
||||
"profile": {
|
||||
"btn_name": "保存更改",
|
||||
"display_name": {
|
||||
"label": "昵称",
|
||||
"msg": "昵称不能为空",
|
||||
"msg_range": "昵称不能超过 30 个字符"
|
||||
},
|
||||
"username": {
|
||||
"label": "用户名",
|
||||
"caption": "用户之间可以通过 \"@用户名\" 进行交互。",
|
||||
"msg": "用户名不能为空",
|
||||
"msg_range": "用户名不能超过 30 个字符",
|
||||
"character": "用户名只能由 \"a-z\", \"0-9\", \" - . _\" 组成"
|
||||
},
|
||||
"avatar": {
|
||||
"label": "头像",
|
||||
"text": "您可以上传图片作为头像,也可以 <1>重置</1> 为"
|
||||
},
|
||||
"bio": {
|
||||
"label": "关于我 (可选)"
|
||||
},
|
||||
"website": {
|
||||
"label": "网站 (可选)",
|
||||
"placeholder": "https://example.com",
|
||||
"msg": "格式不正确"
|
||||
},
|
||||
"location": {
|
||||
"label": "位置 (可选)",
|
||||
"placeholder": "城市, 国家"
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"email": {
|
||||
"label": "邮件通知",
|
||||
"radio": "你的提问有新的回答,评论,和其他"
|
||||
}
|
||||
},
|
||||
"account": {
|
||||
"change_email_btn": "更改邮箱",
|
||||
"change_pass_btn": "更改密码",
|
||||
"change_email_info": "邮件已发送。请根据指引完成验证。",
|
||||
"email": {
|
||||
"label": "邮箱",
|
||||
"msg": "邮箱不能为空"
|
||||
},
|
||||
"password_title": "密码",
|
||||
"current_pass": {
|
||||
"label": "当前密码",
|
||||
"msg": {
|
||||
"empty": "当前密码不能为空",
|
||||
"length": "密码长度必须在 8 至 32 之间",
|
||||
"different": "两次输入的密码不匹配"
|
||||
}
|
||||
},
|
||||
"new_pass": {
|
||||
"label": "新密码"
|
||||
},
|
||||
"pass_confirm": {
|
||||
"label": "确认新密码"
|
||||
}
|
||||
},
|
||||
"interface": {
|
||||
"lang": {
|
||||
"label": "界面语言",
|
||||
"text": "设置用户界面语言,在刷新页面后生效。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"toast": {
|
||||
"update": "更新成功",
|
||||
"update_password": "更改密码成功。",
|
||||
"flag_success": "感谢您的标记,我们会尽快处理。"
|
||||
},
|
||||
"related_question": {
|
||||
"title": "相关问题",
|
||||
"btn": "我要提问",
|
||||
"answers": "个回答"
|
||||
},
|
||||
"question_detail": {
|
||||
"Asked": "提问于",
|
||||
"asked": "提问于",
|
||||
"update": "修改于",
|
||||
"edit": "最后编辑于",
|
||||
"Views": "阅读次数",
|
||||
"Follow": "关注此问题",
|
||||
"Following": "已关注",
|
||||
"answered": "回答于",
|
||||
"closed_in": "关闭于",
|
||||
"show_exist": "查看相关问题。",
|
||||
"answers": {
|
||||
"title": "个回答",
|
||||
"score": "评分",
|
||||
"newest": "最新",
|
||||
"btn_accept": "采纳",
|
||||
"btn_accepted": "已被采纳"
|
||||
},
|
||||
"write_answer": {
|
||||
"title": "你的回答",
|
||||
"btn_name": "提交你的回答",
|
||||
"confirm_title": "继续回答",
|
||||
"continue": "继续",
|
||||
"confirm_info": "<p>您确定要提交一个新的回答吗?</p><p>您可以直接编辑和改善您之前的回答的。</p>",
|
||||
"empty": "回答内容不能为空。"
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"title": "删除",
|
||||
"question": "我们不建议<strong>删除有回答的帖子</strong>。因为这样做会使得后来的读者无法从该问题中获得帮助。</p><p>如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗?",
|
||||
"answer_accepted": "<p>我们不建议<strong>删除被采纳的回答</strong>。因为这样做会使得后来的读者无法从该回答中获得帮助。</p>如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗?",
|
||||
"other": "你确定要删除?",
|
||||
"tip_question_deleted": "此问题已被删除",
|
||||
"tip_answer_deleted": "此回答已被删除"
|
||||
},
|
||||
"btns": {
|
||||
"confirm": "确认",
|
||||
"cancel": "取消",
|
||||
"save": "保存",
|
||||
"delete": "删除",
|
||||
"login": "登录",
|
||||
"signup": "注册",
|
||||
"logout": "退出登录",
|
||||
"verify": "验证",
|
||||
"add_question": "我要提问"
|
||||
},
|
||||
"search": {
|
||||
"title": "搜索结果",
|
||||
"keywords": "关键词",
|
||||
"options": "选项",
|
||||
"follow": "关注",
|
||||
"following": "已关注",
|
||||
"counts": "{{count}} 个结果",
|
||||
"more": "更多",
|
||||
"sort_btns": {
|
||||
"relevance": "相关性",
|
||||
"newest": "最新的",
|
||||
"active": "活跃的",
|
||||
"score": "评分"
|
||||
},
|
||||
"tips": {
|
||||
"title": "高级搜索提示",
|
||||
"tag": "<1>[tag]</1> 在指定标签中搜索",
|
||||
"user": "<1>user:username</1> 根据作者搜索",
|
||||
"answer": "<1>answers:0</1> 搜索未回答的问题",
|
||||
"score": "<1>score:3</1> 评分 3 分或以上",
|
||||
"question": "<1>is:question</1> 只搜索问题",
|
||||
"is_answer": "<1>is:answer</1> 只搜索回答"
|
||||
},
|
||||
"empty": "找不到任何相关的内容。<br /> 请尝试其他关键字,或者减少查找内容的长度。"
|
||||
},
|
||||
"share": {
|
||||
"name": "分享",
|
||||
"copy": "复制链接",
|
||||
"via": "分享在...",
|
||||
"copied": "已复制",
|
||||
"facebook": "分享到 Facebook",
|
||||
"twitter": "分享到 Twitter"
|
||||
},
|
||||
"cannot_vote_for_self": "不能给自己投票",
|
||||
"modal_confirm": {
|
||||
"title": "发生错误..."
|
||||
},
|
||||
"account_result": {
|
||||
"page_title": "欢迎来到 Answer",
|
||||
"success": "你的账号已通过验证,即将返回首页。",
|
||||
"link": "返回首页",
|
||||
"invalid": "抱歉,此验证链接已失效。也许是你的账号已经通过验证了?",
|
||||
"confirm_new_email": "你的电子邮箱已更新",
|
||||
"confirm_new_email_invalid": "抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了?"
|
||||
},
|
||||
"question": {
|
||||
"following_tags": "已关注的标签",
|
||||
"edit": "编辑",
|
||||
"save": "保存",
|
||||
"follow_tag_tip": "按照标签整理您的问题列表。",
|
||||
"hot_questions": "热点问题",
|
||||
"all_questions": "全部问题",
|
||||
"x_questions": "{{ count }} 个问题",
|
||||
"x_answers": "{{ count }} 个回答",
|
||||
"questions": "个问题",
|
||||
"answers": "回答",
|
||||
"newest": "最新",
|
||||
"active": "活跃",
|
||||
"frequent": "浏览量",
|
||||
"score": "评分",
|
||||
"unanswered": "未回答",
|
||||
"modified": "修改于",
|
||||
"answered": "回答于",
|
||||
"asked": "提问于",
|
||||
"closed": "已关闭",
|
||||
"follow_a_tag": "关注一个标签",
|
||||
"more": "更多"
|
||||
},
|
||||
"personal": {
|
||||
"overview": "概览",
|
||||
"answers": "回答",
|
||||
"answer": "回答",
|
||||
"questions": "问题",
|
||||
"question": "问题",
|
||||
"bookmarks": "收藏",
|
||||
"reputation": "声望",
|
||||
"comments": "评论",
|
||||
"votes": "得票",
|
||||
"newest": "最新",
|
||||
"score": "评分",
|
||||
"edit_profile": "编辑我的资料",
|
||||
"visited_x_days": "Visited {{ count }} days",
|
||||
"viewed": "Viewed",
|
||||
"joined": "加入于",
|
||||
"last_login": "上次登录",
|
||||
"about_me": "关于我",
|
||||
"about_me_empty": "// Hello, World !",
|
||||
"top_answers": "热门回答",
|
||||
"top_questions": "热门问题",
|
||||
"stats": "状态",
|
||||
"list_empty": "没有找到相关的内容。<br />试试看其他标签?",
|
||||
"accepted": "已采纳",
|
||||
"answered": "回答于",
|
||||
"asked": "提问于",
|
||||
"upvote": "赞同",
|
||||
"downvote": "反对",
|
||||
"mod_short": "管理员",
|
||||
"mod_long": "管理员",
|
||||
"x_reputation": "声望",
|
||||
"x_votes": "得票",
|
||||
"x_answers": "个回答",
|
||||
"x_questions": "个问题"
|
||||
},
|
||||
"page_404": {
|
||||
"description": "页面不存在",
|
||||
"back_home": "回到主页"
|
||||
},
|
||||
"page_50X": {
|
||||
"description": "服务器遇到了一个错误,无法完成你的请求。",
|
||||
"back_home": "回到主页"
|
||||
},
|
||||
"admin": {
|
||||
"admin_header": {
|
||||
"title": "后台管理"
|
||||
},
|
||||
"nav_menus": {
|
||||
"dashboard": "后台管理",
|
||||
"contents": "内容管理",
|
||||
"questions": "问题",
|
||||
"answers": "回答",
|
||||
"users": "用户管理",
|
||||
"flags": "举报管理",
|
||||
"settings": "站点设置",
|
||||
"general": "一般",
|
||||
"interface": "界面",
|
||||
"smtp": "SMTP"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "后台管理",
|
||||
"welcome": "欢迎来到 Answer 后台管理!",
|
||||
"version": "版本"
|
||||
},
|
||||
"flags": {
|
||||
"title": "举报",
|
||||
"pending": "等待处理",
|
||||
"completed": "已完成",
|
||||
"flagged": "被举报内容",
|
||||
"created": "创建于",
|
||||
"action": "操作",
|
||||
"review": "审查"
|
||||
},
|
||||
"change_modal": {
|
||||
"title": "更改用户状态为...",
|
||||
"btn_cancel": "取消",
|
||||
"btn_submit": "提交",
|
||||
"normal_name": "正常",
|
||||
"normal_description": "正常状态的用户可以提问和回答。",
|
||||
"suspended_name": "封禁",
|
||||
"suspended_description": "被封禁的用户将无法登录。",
|
||||
"deleted_name": "删除",
|
||||
"deleted_description": "删除用户的个人信息,认证等等。",
|
||||
"inactive_name": "不活跃",
|
||||
"inactive_description": "不活跃的用户必须重新验证邮箱。",
|
||||
"confirm_title": "删除此用户",
|
||||
"confirm_content": "确定要删除此用户?此操作无法撤销!",
|
||||
"confirm_btn": "删除",
|
||||
"msg": {
|
||||
"empty": "请选择一个原因"
|
||||
}
|
||||
},
|
||||
"status_modal": {
|
||||
"title": "更改 {{ type }} 状态为...",
|
||||
"normal_name": "正常",
|
||||
"normal_description": "所有用户都可以访问",
|
||||
"closed_name": "关闭",
|
||||
"closed_description": "不能回答,但仍然可以编辑、投票和评论。",
|
||||
"deleted_name": "删除",
|
||||
"deleted_description": "所有获得/损失的声望将会恢复。",
|
||||
"btn_cancel": "取消",
|
||||
"btn_submit": "提交",
|
||||
"btn_next": "下一步"
|
||||
},
|
||||
"users": {
|
||||
"title": "用户",
|
||||
"name": "名称",
|
||||
"email": "邮箱",
|
||||
"reputation": "声望",
|
||||
"created_at": "创建时间",
|
||||
"delete_at": "删除时间",
|
||||
"suspend_at": "封禁时间",
|
||||
"status": "状态",
|
||||
"action": "操作",
|
||||
"change": "更改",
|
||||
"all": "全部",
|
||||
"inactive": "不活跃",
|
||||
"suspended": "已封禁",
|
||||
"deleted": "已删除",
|
||||
"normal": "正常"
|
||||
},
|
||||
"questions": {
|
||||
"page_title": "问题",
|
||||
"normal": "正常",
|
||||
"closed": "已关闭",
|
||||
"deleted": "已删除",
|
||||
"post": "标题",
|
||||
"votes": "得票数",
|
||||
"answers": "回答数",
|
||||
"created": "创建于",
|
||||
"status": "状态",
|
||||
"action": "操作",
|
||||
"change": "更改"
|
||||
},
|
||||
"answers": {
|
||||
"page_title": "回答",
|
||||
"normal": "正常",
|
||||
"deleted": "已删除",
|
||||
"post": "标题",
|
||||
"votes": "得票数",
|
||||
"created": "创建于",
|
||||
"status": "状态",
|
||||
"action": "操作",
|
||||
"change": "更改"
|
||||
},
|
||||
"general": {
|
||||
"page_title": "一般",
|
||||
"name": {
|
||||
"label": "站点名称",
|
||||
"msg": "不能为空",
|
||||
"text": "站点的名称,作为站点的标题(HTML 的 title 标签)。"
|
||||
},
|
||||
"short_description": {
|
||||
"label": "简短的站点标语 (可选)",
|
||||
"msg": "不能为空",
|
||||
"text": "简短的标语,作为网站主页的标题(HTML 的 title 标签)。"
|
||||
},
|
||||
"description": {
|
||||
"label": "网站描述 (可选)",
|
||||
"msg": "不能为空",
|
||||
"text": "使用一句话描述本站,作为网站的描述(HTML 的 meta 标签)。"
|
||||
}
|
||||
},
|
||||
"interface": {
|
||||
"page_title": "界面",
|
||||
"logo": {
|
||||
"label": "Logo (可选)",
|
||||
"msg": "不能为空",
|
||||
"text": "可以上传图片,或者<1>重置</1>为站点标题。"
|
||||
},
|
||||
"theme": {
|
||||
"label": "主题",
|
||||
"msg": "不能为空",
|
||||
"text": "选择一个主题"
|
||||
},
|
||||
"language": {
|
||||
"label": "界面语言",
|
||||
"msg": "不能为空",
|
||||
"text": "设置用户界面语言,在刷新页面后生效。"
|
||||
}
|
||||
},
|
||||
"smtp": {
|
||||
"page_title": "SMTP",
|
||||
"from_email": {
|
||||
"label": "发件人地址",
|
||||
"msg": "不能为空",
|
||||
"text": "用于发送邮件的地址。"
|
||||
},
|
||||
"from_name": {
|
||||
"label": "发件人名称",
|
||||
"msg": "不能为空",
|
||||
"text": "发件人的名称"
|
||||
},
|
||||
"smtp_host": {
|
||||
"label": "SMTP 主机",
|
||||
"msg": "不能为空",
|
||||
"text": "邮件服务器"
|
||||
},
|
||||
"encryption": {
|
||||
"label": "加密",
|
||||
"msg": "不能为空",
|
||||
"text": "对于大多数服务器而言,SSL 是推荐开启的。",
|
||||
"ssl": "SSL",
|
||||
"none": "无加密"
|
||||
},
|
||||
"smtp_port": {
|
||||
"label": "SMTP 端口",
|
||||
"msg": "SMTP 端口必须在 1 ~ 65535 之间。",
|
||||
"text": "邮件服务器的端口号。"
|
||||
},
|
||||
"smtp_username": {
|
||||
"label": "SMTP 用户名",
|
||||
"msg": "不能为空"
|
||||
},
|
||||
"smtp_password": {
|
||||
"label": "SMTP 密码",
|
||||
"msg": "不能为空"
|
||||
},
|
||||
"test_email_recipient": {
|
||||
"label": "测试邮件收件人",
|
||||
"text": "提供用于接收测试邮件的邮箱地址。",
|
||||
"msg": "地址无效"
|
||||
},
|
||||
"smtp_authentication": {
|
||||
"label": "SMTP 认证",
|
||||
"msg": "不能为空",
|
||||
"yes": "是",
|
||||
"no": "否"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ a {
|
|||
height: 18px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
left: 15px;
|
||||
top: 0;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ const Users: FC = () => {
|
|||
data={user}
|
||||
className="fs-6"
|
||||
avatarSize="24px"
|
||||
avatarSearchStr="s=48"
|
||||
/>
|
||||
</td>
|
||||
<td>{user.rank}</td>
|
||||
|
|
|
@ -88,7 +88,7 @@ const Index: FC<Props> = ({ data, initPage, hasAnswer }) => {
|
|||
size="sm"
|
||||
className="p-0 btn-no-border"
|
||||
onClick={(e) => handleFollow(e)}>
|
||||
{followed ? 'Following' : 'Follow'}
|
||||
{t(followed ? 'Following' : 'Follow')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="m-n1">
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
import { FC, memo, useEffect, useState } from 'react';
|
||||
import { Form, Button } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { changeEmail, checkImgCode } from '@answer/api';
|
||||
import type {
|
||||
ImgCodeRes,
|
||||
PasswordResetReq,
|
||||
FormDataType,
|
||||
} from '@answer/common/interface';
|
||||
import { userInfoStore } from '@answer/stores';
|
||||
|
||||
import { PicAuthCodeModal } from '@/components/Modal';
|
||||
|
||||
const Index: FC = () => {
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'change_email' });
|
||||
const [formData, setFormData] = useState<FormDataType>({
|
||||
e_mail: {
|
||||
value: '',
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
captcha_code: {
|
||||
value: '',
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
});
|
||||
const [imgCode, setImgCode] = useState<ImgCodeRes>({
|
||||
captcha_id: '',
|
||||
captcha_img: '',
|
||||
verify: false,
|
||||
});
|
||||
const [showModal, setModalState] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const { user: userInfo, update: updateUser } = userInfoStore();
|
||||
|
||||
const getImgCode = () => {
|
||||
checkImgCode({
|
||||
action: 'e_mail',
|
||||
}).then((res) => {
|
||||
setImgCode(res);
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = (params: FormDataType) => {
|
||||
setFormData({ ...formData, ...params });
|
||||
};
|
||||
|
||||
const checkValidated = (): boolean => {
|
||||
let bol = true;
|
||||
|
||||
if (!formData.e_mail.value) {
|
||||
bol = false;
|
||||
formData.e_mail = {
|
||||
value: '',
|
||||
isInvalid: true,
|
||||
errorMsg: t('email.msg.empty'),
|
||||
};
|
||||
}
|
||||
setFormData({
|
||||
...formData,
|
||||
});
|
||||
return bol;
|
||||
};
|
||||
|
||||
const sendEmail = (e?: any) => {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
const params: PasswordResetReq = {
|
||||
e_mail: formData.e_mail.value,
|
||||
};
|
||||
if (imgCode.verify) {
|
||||
params.captcha_code = formData.captcha_code.value;
|
||||
params.captcha_id = imgCode.captcha_id;
|
||||
}
|
||||
|
||||
changeEmail(params)
|
||||
.then(() => {
|
||||
userInfo.e_mail = formData.e_mail.value;
|
||||
updateUser(userInfo);
|
||||
navigate('/users/login', { replace: true });
|
||||
setModalState(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.isError && err.key) {
|
||||
formData[err.key].isInvalid = true;
|
||||
formData[err.key].errorMsg = err.value;
|
||||
if (err.key.indexOf('captcha') < 0) {
|
||||
setModalState(false);
|
||||
}
|
||||
}
|
||||
setFormData({ ...formData });
|
||||
})
|
||||
.finally(() => {
|
||||
getImgCode();
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = async (event: any) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!checkValidated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (imgCode.verify) {
|
||||
setModalState(true);
|
||||
return;
|
||||
}
|
||||
|
||||
sendEmail();
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
navigate('/users/login?status=inactive', { replace: true });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getImgCode();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form noValidate onSubmit={handleSubmit} autoComplete="off">
|
||||
<Form.Group controlId="email" className="mb-3">
|
||||
<Form.Label>{t('email.label')}</Form.Label>
|
||||
<Form.Control
|
||||
required
|
||||
type="email"
|
||||
value={formData.e_mail.value}
|
||||
isInvalid={formData.e_mail.isInvalid}
|
||||
onChange={(e) => {
|
||||
handleChange({
|
||||
e_mail: {
|
||||
value: e.target.value,
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Form.Control.Feedback type="invalid">
|
||||
{formData.e_mail.errorMsg}
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
|
||||
<div className="d-grid mb-3">
|
||||
<Button variant="primary" type="submit">
|
||||
{t('btn_update')}
|
||||
</Button>
|
||||
<Button variant="link" className="mt-2 d-block" onClick={goBack}>
|
||||
{t('btn_cancel')}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<PicAuthCodeModal
|
||||
visible={showModal}
|
||||
data={{
|
||||
captcha: formData.captcha_code,
|
||||
imgCode,
|
||||
}}
|
||||
handleCaptcha={handleChange}
|
||||
clickSubmit={sendEmail}
|
||||
refreshImgCode={getImgCode}
|
||||
onClose={() => setModalState(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
|
@ -0,0 +1,25 @@
|
|||
import { FC, memo } from 'react';
|
||||
import { Container, Col } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import SendEmail from './components/sendEmail';
|
||||
|
||||
import { PageTitle } from '@/components';
|
||||
|
||||
const Index: FC = () => {
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'change_email' });
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={t('change_email', { keyPrefix: 'page_title' })} />
|
||||
<Container style={{ paddingTop: '4rem', paddingBottom: '6rem' }}>
|
||||
<h3 className="text-center mb-5">{t('page_title')}</h3>
|
||||
<Col className="mx-auto" md={3}>
|
||||
<SendEmail />
|
||||
</Col>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
|
@ -3,7 +3,8 @@ import { Container, Row, Col } from 'react-bootstrap';
|
|||
import { Link, useSearchParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { changeEmailVerify } from '@answer/api';
|
||||
import { changeEmailVerify, getUserInfo } from '@answer/api';
|
||||
import { userInfoStore } from '@answer/stores';
|
||||
|
||||
import { PageTitle } from '@/components';
|
||||
|
||||
|
@ -12,6 +13,8 @@ const Index: FC = () => {
|
|||
const [searchParams] = useSearchParams();
|
||||
const [step, setStep] = useState('loading');
|
||||
|
||||
const updateUser = userInfoStore((state) => state.update);
|
||||
|
||||
useEffect(() => {
|
||||
const code = searchParams.get('code');
|
||||
if (code) {
|
||||
|
@ -19,6 +22,10 @@ const Index: FC = () => {
|
|||
changeEmailVerify({ code })
|
||||
.then(() => {
|
||||
setStep('success');
|
||||
getUserInfo().then((res) => {
|
||||
// update user info
|
||||
updateUser(res);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
setStep('invalid');
|
||||
|
|
|
@ -19,10 +19,10 @@ const Index: FC<Props> = ({ data }) => {
|
|||
<div className="d-flex mb-4">
|
||||
{data?.status !== 'deleted' ? (
|
||||
<Link to={`/users/${data.username}`} reloadDocument>
|
||||
<Avatar avatar={data.avatar} size="160px" />
|
||||
<Avatar avatar={data.avatar} size="160px" searchStr="s=256" />
|
||||
</Link>
|
||||
) : (
|
||||
<Avatar avatar={data.avatar} size="160px" />
|
||||
<Avatar avatar={data.avatar} size="160px" searchStr="s=256" />
|
||||
)}
|
||||
|
||||
<div className="ms-4">
|
||||
|
|
|
@ -116,7 +116,7 @@ const Personal: FC = () => {
|
|||
)}
|
||||
</Col>
|
||||
<Col xxl={3} lg={4} sm={12} className="mt-5 mt-lg-0">
|
||||
<h5 className="mb-3">Stats</h5>
|
||||
<h5 className="mb-3">{t('stats')}</h5>
|
||||
{userInfo?.info && (
|
||||
<>
|
||||
<div className="text-secondary">
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Form, Button } from 'react-bootstrap';
|
|||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { marked } from 'marked';
|
||||
import MD5 from 'md5';
|
||||
|
||||
import { modifyUserInfo, uploadAvatar, getUserInfo } from '@answer/api';
|
||||
import type { FormDataType } from '@answer/common/interface';
|
||||
|
@ -16,6 +17,9 @@ const Index: React.FC = () => {
|
|||
});
|
||||
const toast = useToast();
|
||||
const { user, update } = userInfoStore();
|
||||
const [mailHash, setMailHash] = useState('');
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
const [formData, setFormData] = useState<FormDataType>({
|
||||
display_name: {
|
||||
value: '',
|
||||
|
@ -28,6 +32,9 @@ const Index: React.FC = () => {
|
|||
errorMsg: '',
|
||||
},
|
||||
avatar: {
|
||||
type: 'default',
|
||||
gravatar: '',
|
||||
custom: '',
|
||||
value: '',
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
|
@ -59,7 +66,9 @@ const Index: React.FC = () => {
|
|||
setFormData({
|
||||
...formData,
|
||||
avatar: {
|
||||
value: res,
|
||||
...formData.avatar,
|
||||
type: 'custom',
|
||||
custom: res,
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
|
@ -136,7 +145,11 @@ const Index: React.FC = () => {
|
|||
const params = {
|
||||
display_name: formData.display_name.value,
|
||||
username: formData.username.value,
|
||||
avatar: formData.avatar.value,
|
||||
avatar: {
|
||||
type: formData.avatar.type,
|
||||
gravatar: formData.avatar.gravatar,
|
||||
custom: formData.avatar.custom,
|
||||
},
|
||||
bio: formData.bio.value,
|
||||
website: formData.website.value,
|
||||
location: formData.location.value,
|
||||
|
@ -168,13 +181,25 @@ const Index: React.FC = () => {
|
|||
formData.display_name.value = res.display_name;
|
||||
formData.username.value = res.username;
|
||||
formData.bio.value = res.bio;
|
||||
formData.avatar.value = res.avatar;
|
||||
formData.avatar.type = res.avatar.type || 'default';
|
||||
formData.avatar.gravatar = res.avatar.gravatar;
|
||||
formData.avatar.custom = res.avatar.custom;
|
||||
formData.location.value = res.location;
|
||||
formData.website.value = res.website;
|
||||
setFormData({ ...formData });
|
||||
if (res.e_mail) {
|
||||
const str = res.e_mail.toLowerCase().trim();
|
||||
const hash = MD5(str);
|
||||
console.log(str, hash, mailHash);
|
||||
setMailHash(hash);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const refreshGravatar = () => {
|
||||
setCount((pre) => pre + 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getProfile();
|
||||
}, []);
|
||||
|
@ -227,39 +252,121 @@ const Index: React.FC = () => {
|
|||
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>{t('avatar.label')}</Form.Label>
|
||||
<div className="d-flex align-items-center">
|
||||
<Avatar
|
||||
size="128px"
|
||||
avatar={formData.avatar.value}
|
||||
className="me-3 rounded"
|
||||
<div className="mb-2">
|
||||
<Form.Check
|
||||
inline
|
||||
type="radio"
|
||||
id="gravatar"
|
||||
label={t('avatar.gravatar')}
|
||||
className="mb-0"
|
||||
checked={formData.avatar.type === 'gravatar'}
|
||||
onChange={() =>
|
||||
handleChange({
|
||||
avatar: {
|
||||
...formData.avatar,
|
||||
type: 'gravatar',
|
||||
gravatar: `https://www.gravatar.com/avatar/${mailHash}`,
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Form.Check
|
||||
inline
|
||||
type="radio"
|
||||
label={t('avatar.custom')}
|
||||
id="custom"
|
||||
className="mb-0"
|
||||
checked={formData.avatar.type === 'custom'}
|
||||
onChange={() =>
|
||||
handleChange({
|
||||
avatar: {
|
||||
...formData.avatar,
|
||||
type: 'custom',
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Form.Check
|
||||
inline
|
||||
type="radio"
|
||||
id="default"
|
||||
label={t('avatar.default')}
|
||||
className="mb-0"
|
||||
checked={formData.avatar.type === 'default'}
|
||||
onChange={() =>
|
||||
handleChange({
|
||||
avatar: {
|
||||
...formData.avatar,
|
||||
type: 'default',
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="d-flex align-items-center">
|
||||
{formData.avatar.type === 'gravatar' && (
|
||||
<>
|
||||
<Avatar
|
||||
size="128px"
|
||||
avatar={formData.avatar.gravatar}
|
||||
searchStr={`s=256&d=identicon${
|
||||
count > 0 ? `&t=${new Date().valueOf()}` : ''
|
||||
}`}
|
||||
className="me-3 rounded"
|
||||
/>
|
||||
<div>
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
className="mb-2"
|
||||
onClick={refreshGravatar}>
|
||||
{t('avatar.btn_refresh')}
|
||||
</Button>
|
||||
<div>
|
||||
<Form.Text className="text-muted mt-0">
|
||||
<Trans i18nKey="settings.profile.gravatar_text">
|
||||
You can change your image on{' '}
|
||||
<a
|
||||
href="https://gravatar.com"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
gravatar.com
|
||||
</a>
|
||||
</Trans>
|
||||
</Form.Text>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<UploadImg type="avatar" upload={avatarUpload} />
|
||||
<div>
|
||||
<Form.Text className="text-muted mt-0">
|
||||
<Trans i18nKey="settings.profile.avatar.text">
|
||||
You can upload your image or
|
||||
<a
|
||||
href="@/pages/Users/Settings/Profile/index##"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleChange({
|
||||
avatar: {
|
||||
value: '',
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
},
|
||||
});
|
||||
}}>
|
||||
reset
|
||||
</a>
|
||||
it to
|
||||
</Trans>
|
||||
<a href="https://gravatar.com"> gravatar.com</a>
|
||||
</Form.Text>
|
||||
</div>
|
||||
</div>
|
||||
{formData.avatar.type === 'custom' && (
|
||||
<>
|
||||
<Avatar
|
||||
size="128px"
|
||||
searchStr="s=256"
|
||||
avatar={formData.avatar.custom}
|
||||
className="me-3 rounded"
|
||||
/>
|
||||
<div>
|
||||
<UploadImg type="avatar" upload={avatarUpload} />
|
||||
<div>
|
||||
<Form.Text className="text-muted mt-0">
|
||||
<Trans i18nKey="settings.profile.avatar.text">
|
||||
You can upload your image.
|
||||
</Trans>
|
||||
</Form.Text>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{formData.avatar.type === 'default' && (
|
||||
<Avatar size="128px" avatar="" className="me-3 rounded" />
|
||||
)}
|
||||
</div>
|
||||
</Form.Group>
|
||||
|
||||
|
|
|
@ -114,6 +114,10 @@ const routeConfig: RouteNode[] = [
|
|||
path: 'users/account-recovery',
|
||||
page: 'pages/Users/AccountForgot',
|
||||
},
|
||||
{
|
||||
path: 'users/change-email',
|
||||
page: 'pages/Users/ChangeEmail',
|
||||
},
|
||||
{
|
||||
path: 'users/password-reset',
|
||||
page: 'pages/Users/PasswordReset',
|
||||
|
|
|
@ -120,7 +120,7 @@ export const getUserInfo = () => {
|
|||
};
|
||||
|
||||
export const modifyPassword = (params: Type.ModifyPasswordReq) => {
|
||||
return request.post('/answer/api/v1/user/password/modify', params);
|
||||
return request.put('/answer/api/v1/user/password', params);
|
||||
};
|
||||
|
||||
export const modifyUserInfo = (params: Type.ModifyUserReq) => {
|
||||
|
|
Loading…
Reference in New Issue