pull/1/head
1379 2 years ago
commit 1bfdc2da5a

@ -0,0 +1,7 @@
如果你遇到的问题不是 Sonic 的 bug比如你不清楚要如何配置请使用[Discussion](https://github.com/go-sonic/discussion/issues)进行讨论。
此 Issue 会被立即关闭。
If you are not sure if your question is truely a bug in Sonic, please discuss it [here](https://github.com/go-sonic/discussion/issues) first.
This issue will be closed immediately.

@ -0,0 +1,87 @@
---
name: V2Ray 程序问题
about: "提交一个 V2Ray 的程序问题报告。"
---
<!--
除非特殊情况,请完整填写所有问题。不按模板发的 issue 将直接被关闭。
如果你遇到的问题不是 V2Ray 的 bug比如你不清楚如何配置请在 https://github.com/v2fly/v2ray-core/discussions 进行讨论。
-->
## 你正在使用哪个版本的 V2Ray
<!-- 如果服务端和客户端使用了不同版本,请注明 -->
## 你的使用场景是什么?
<!-- 比如使用 Chrome 通过 Socks/VMess 代理观看 YouTube 视频 -->
## 你看到的异常现象是什么?
<!-- 请描述具体现象比如访问超时、TLS 证书错误等 -->
## 你期待看到的正常表现是怎样的?
## 请附上你的配置
<!-- 提交 issue 前,请隐去服务器域名或 IP 地址 -->
**服务端配置:**
```javascript
// 在这里附上服务器端配置文件
```
**客户端配置:**
```javascript
// 在这里附上客户端配置
```
## 请附上出错时软件输出的错误日志
<!-- 在 Linux 中,日志通常在 `/var/log/v2ray/error.log` 文件中 -->
**服务器端错误日志:**
```javascript
// 在这里附上服务器端日志
```
**客户端错误日志:**
```javascript
// 在这里附上客户端日志
```
## 请附上访问日志
<!-- 在 Linux 中,访问日志通常在 `/var/log/v2ray/access.log` 文件中 -->
```javascript
// 在这里附上服务器端日志
```
## 其它相关的配置文件(如 Nginx和相关日志
## 如果 V2Ray 无法启动,请附上 `--test` 命令的输出
## 如果 V2Ray 服务运行异常,请附上 journal 日志
<!-- 通常的命令为 `journalctl -u v2ray` -->
<!-- 请预览一下你填写的内容并整理好格式后,再提交 -->

@ -0,0 +1,90 @@
---
name: Bug report
about: "Create a bug report to help us improve"
---
<!--
Please answer all the questions with enough information. All issues not following this template will be closed immediately.
If you are not sure if your question is truely a bug of V2Ray, please discuss it at https://github.com/v2fly/v2ray-core/discussions first.
-->
## What version of V2Ray are you using?
<!-- If you deploy different versions of V2Ray on server and client, please explicitly point out -->
## What's your scenario of using V2Ray?
<!-- E.g., watching YouTube videos in browsers via Socks/VMess proxy -->
## What problems have you encountered?
<!-- Please describe in detail, such as timeout, fake TLS certificate, etc -->
## What's your expectation?
## Please attach your configuration here
<!-- Remember to mask your IP address or hostname -->
**Server configuration:**
```javascript
// Please attach your server configuration here.
```
**Client configuration:**
```javascript
// Please attach your client configuration here.
```
## Please attach error logs here
<!--
only trailing lines if the log file is large in size.
Error log file is usually at `/var/log/v2ray/error.log` on Linux.
-->
**Server error log:**
```javascript
// Please attach your server error log here.
```
**Client error log:**
```javascript
// Please attach your client error log here.
```
## Please attach access log here
<!-- Access log is usually at '/var/log/v2ray/access.log' on Linux. -->
```javascript
// Please attach your server access log here.
```
## Other configurations (such as Nginx) and logs here
## If V2Ray cannot start up, please attach output from `--test` command
## If V2Ray service is abnormal, please attach journal log here
<!-- Usual command is `journalctl -u v2ray` -->
<!-- Please review your issue and check the format before submitting. -->

@ -0,0 +1,12 @@
---
name: Other
about: "其它问题请使用 https://github.com/v2fly/v2ray-core/discussions 进行讨论 / Please discuss other issues at https://github.com/v2fly/v2ray-core/discussions"
---
如果你遇到的问题不是 V2Ray 的 bug比如你不清楚要如何配置请使用[Discussion](https://github.com/v2fly/v2ray-core/discussions)进行讨论。
此 Issue 会被立即关闭。
If you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/v2ray-core/discussions) first.
This issue will be closed immediately.

@ -0,0 +1,17 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

@ -0,0 +1,54 @@
run:
timeout: 5m
skip-files:
- .gen.go
- .pb.go
issues:
new: true
exclude-rules:
- linters:
- staticcheck
text: "SA1019:"
- linters:
- stylecheck
text: "ST1016:"
linters:
enable:
- asciicheck
- bodyclose
- depguard
- gocritic
- gofmt
- gofumpt
- goimports
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- revive
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- varcheck
- whitespace
disable:
- deadcode
- errcheck
- unused
linters-settings:
goimports:
local-prefixes: github.com/go-sonic/sonic
revive:
rules:
- name: blank-imports
severity: warning
disabled: true

@ -0,0 +1,47 @@
name: CodeQL
on:
push:
branches: [master]
pull_request:
branches: [master]
types: [opened, synchronize, reopened]
paths-ignore:
- '**/*.md'
- '**/*.txt'
jobs:
analyze:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: ["go"]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

@ -0,0 +1,35 @@
name: Linter
on:
push:
branches:
- master
- v*
paths:
- "**/*.go"
- ".github/workflows/linter.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- ".github/workflows/linter.yml"
jobs:
lint:
if: github.repository == 'go-sonic/sonic'
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Checkout codebase
uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --config=.github/linters/.golangci.yml
only-new-issues: true

@ -0,0 +1,133 @@
name: Release
on:
release:
types: [prereleased]
push:
branches:
- master
- v*
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
# Include amd64 on all platforms.
goos: [windows, linux, darwin]
goarch: [amd64, 386]
exclude:
- goarch: 386
goos: darwin
include:
# BEGIN Linux ARM 5 6 7
- goos: linux
goarch: arm-7
- goos: linux
goarch: arm-6
- goos: linux
goarch: arm-5
# END Linux ARM 5 6 7
# BEGIN Other architectures
- goos: darwin
goarch: arm64
- goos: linux
goarch: arm64
# BEGIN MIPS
- goos: linux
goarch: mips64
- goos: linux
goarch: mips64le
- goos: linux
goarch: mipsle
- goos: linux
goarch: mips
# END MIPS
fail-fast: false
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Show workflow information
run: |
echo "GOOS: $GOOS, GOARCH: $GOARCH"
- name: Build
uses: crazy-max/ghaction-xgo@v2
with:
xgo_version: latest
go_version: 1.19
dest: build
prefix: sonic
targets: ${{matrix.goos}}/${{matrix.goarch}}
v: true
x: false
race: false
ldflags: -s -w
buildmode: default
trimpath: true
- name: Rename executable file
run: |
cd ./build || exit 1
mv sonic-$GOOS-$GOARCH* sonic
- name: Rename Windows ecutable file
if: matrix.goos == 'windows'
run: |
cd ./build || exit 1
mv sonic sonic.exe
- name: Prepare package
run: |
cp -rv ./conf ./build
cp -rv ./resources ./build
- name: Prepare package for Linux
if: matrix.goos == 'linux'
run: cp -rv ./release/systemd ./build/
- name: Create ZIP archive
run: |
pushd build || exit 1
zip -9vr ../sonic-$GOOS-$GOARCH.zip .
popd || exit 1
FILE=./sonic-$GOOS-$GOARCH.zip
DGST=$FILE.dgst
openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
- name: Upload ZIP file to Artifacts
uses: actions/upload-artifact@v3
with:
name: sonic-${{matrix.goos}}-${{matrix.goarch}}.zip
path: sonic-${{matrix.goos}}-${{matrix.goarch}}.zip
- name: Upload files to GitHub release
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file_glob: true
file: ./sonic-${{matrix.goos}}-${{matrix.goarch}}.zip*
tag: ${{ github.ref }}

@ -0,0 +1,20 @@
name: Semgrep
on: [pull_request]
jobs:
semgrep:
name: Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: returntocorp/semgrep-action@v1
env: # Optional environment variable for inline PR comments (beta)
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config: |
p/golang
p/r2c-ci
p/r2c-security-audit
p/insecure-transport
p/secrets
publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
publishDeployment: 241

@ -0,0 +1,17 @@
name: Mark stale issues and pull requests
on:
schedule:
- cron: "30 1 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days"
stale-pr-message: 'It has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 120
days-before-close: 5

7
.gitignore vendored

@ -0,0 +1,7 @@
/.idea
/logs
.DS_Store
/upload
/.vscode
sonic.db
__debug_bin

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "resources/template/theme/default-theme-anatole"]
path = resources/template/theme/default-theme-anatole
url = git@github.com:go-sonic/default-theme-anatole.git

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 1379Monitor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,73 @@
<p align="center">
<img src="https://raw.githubusercontent.com/go-sonic/resources/master/logo/logo.png" />
</p>
<p align="center"><b>Sonic </b> [ˈsɒnɪk] ,Sonic is a Go Blogging Platform. Simple and Powerful.</p>
<p align="center">
<a href="https://github.com/go-sonic/sonic/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/go-sonic/sonic.svg?style=flat-square&include_prereleases" /></a>
<a href="https://github.com/go-sonic/sonic/releases"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/go-sonic/sonic/total.svg?style=flat-square" /></a>
<a href="https://hub.docker.com/r/go-sonic/sonic"><img alt="Docker pulls" src="https://img.shields.io/docker/pulls/go-sonic/sonic?style=flat-square" /></a>
<a href="https://github.com/go-sonic/sonic/commits"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/go-sonic/sonic.svg?style=flat-square" /></a>
<a href="https://github.com/go-sonic/sonic/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/go-sonic/sonic/Sonic%20CI?style=flat-square" /></a>
<br />
<a href="https://go-sonic.org">Website</a>
<a href="https://t.me/go_sonic">Telegram Channel</a>
</p>
English | [中文](doc/README_ZH.md)
## 📖 Introduction
Sonic means as fast as sound speed. Like its name, sonic is a high-performance blog system developed using golang
Thanks [Halo](https://github.com/halo-dev) project team,this project is inspired by Halo. Front end project fork from Halo
## 🚀 Features:
- Support multiple types of databases: SQLite、MySQL(TODO: PostgreSQL)
- Small: The installation file is only 10mb size
- High-performance: Post details page can withstand 900qps(Enviroment: Intel Xeon Platinum 8260 4C 8G ,SQLite3)
- Support changing theme
- Support Linux、Windows、Mac OS. And Support x86、x64、Arm、Arm64、MIPS
- Object storage(MINIO、Google Cloud、AWS、AliYun)
## 🧰 How to install
### Download the latest installation package
> Please pay attention to the operating system and instruction set
```bash
wget https://github.com/go-sonic/sonic/releases/download/v1.0.0/sonic-linux-64.zip -O sonic.zip
```
### Decompression
```bash
unzip sonic.zip
```
### Launch
```bash
cd sonic
./sonic -config conf/config.yaml
```
### Initialization
**The default port is 8080**
Open http://ip:port/admin#install
Next, you can access sonic through the browser.
The URL of the admin console is http://ip:port/admin
## TODO
- [ ] i18n
- [ ] PostgreSQL
- [ ] Better error handling
- [ ] Plugin(base on Wasm)
- [ ] Use new web framework([Hertz](https://github.com/cloudwego/hertz))
## 📄 License
Source code in `sonic` is available under the [MIT License](/LICENSE.md).

52
cache/cache.go vendored

@ -0,0 +1,52 @@
package cache
import (
"time"
goCache "github.com/patrickmn/go-cache"
)
type Cache interface {
SetDefault(key string, value interface{})
Set(key string, value interface{}, expiration time.Duration)
Get(key string) (interface{}, bool)
Delete(key string)
BatchDelete(keys []string)
}
var _ Cache = &cacheImpl{}
type cacheImpl struct {
goCache *goCache.Cache
}
func NewCache() Cache {
return &cacheImpl{
goCache: goCache.New(time.Hour, time.Hour),
}
}
// SetDefault to cache with defaultExpiration time
func (c *cacheImpl) SetDefault(key string, value interface{}) {
c.goCache.SetDefault(key, value)
}
// Set to cache with expiration in params
func (c *cacheImpl) Set(key string, value interface{}, expiration time.Duration) {
c.goCache.Set(key, value, expiration)
}
// Get key's value
func (c *cacheImpl) Get(key string) (interface{}, bool) {
return c.goCache.Get(key)
}
func (c *cacheImpl) Delete(key string) {
c.goCache.Delete(key)
}
func (c *cacheImpl) BatchDelete(keys []string) {
for _, key := range keys {
c.Delete(key)
}
}

45
cache/key.go vendored

@ -0,0 +1,45 @@
package cache
import (
"context"
"strconv"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/util/xerr"
)
func BuildTokenAccessKey(accessToken string) string {
return consts.TokenAccessCachePrefix + accessToken
}
func BuildTokenRefreshKey(refreshToken string) string {
return consts.TokenRefreshCachePrefix + refreshToken
}
func BuildAccessTokenKey(userID int32) string {
return consts.TokenAccessCachePrefix + strconv.Itoa(int(userID))
}
func BuildRefreshTokenKey(userID int32) string {
return consts.TokenRefreshCachePrefix + strconv.Itoa(int(userID))
}
func BuildCodeCacheKey(userID int32) string {
return consts.CodePrefix + strconv.Itoa(int(userID))
}
func BuildAccessPermissionKey(ctx context.Context) (string, error) {
sessionID := ctx.Value(consts.SessionID)
if sessionID == nil {
return "", xerr.NoType.New("session_id not exist").WithStatus(xerr.StatusInternalServerError)
}
sessionIDStr, ok := sessionID.(string)
if !ok || sessionIDStr == "" {
return "", xerr.NoType.New("session_id not exist").WithStatus(xerr.StatusInternalServerError)
}
return consts.AccessPermissionKeyPrefix + sessionIDStr, nil
}
func BuildCategoryPermissionKey(categoryID int32) string {
return strconv.Itoa(int(categoryID))
}

@ -0,0 +1,67 @@
package main
import (
"go.uber.org/fx"
"gorm.io/gen"
"gorm.io/gorm"
"github.com/go-sonic/sonic/config"
"github.com/go-sonic/sonic/dal"
"github.com/go-sonic/sonic/log"
)
// generate code
func main() {
var DB *gorm.DB
_ = fx.New(
fx.Provide(log.NewLogger),
fx.Provide(dal.NewGormDB),
fx.Provide(log.NewGormLogger),
fx.Provide(config.NewConfig),
fx.Populate(&DB),
)
// specify the output directory (default: "./query")
// ### if you want to query without context constrain, set mode gen.WithoutContext ###
g := gen.NewGenerator(gen.Config{
Mode: gen.WithDefaultQuery,
OutPath: "./dal",
ModelPkgPath: "./model/entity",
/* Mode: gen.WithoutContext,*/
//if you want the nullable field generation property to be pointer type, set FieldNullable true
FieldNullable: true,
FieldWithIndexTag: true,
FieldWithTypeTag: true,
})
// reuse the database connection in Project or create a connection here
// if you want to use GenerateModel/GenerateModelAs, UseDB is necessary, or it will panic
g.UseDB(DB)
// apply basic crud api on structs or table models which is specified by table name with function
// GenerateModel/GenerateModelAs. And generator will generate table models' code when calling Excute.
g.ApplyBasic(g.GenerateModel("attachment", gen.FieldType("type", "consts.AttachmentType")),
g.GenerateModel("category", gen.FieldType("type", "consts.CategoryType")),
g.GenerateModel("comment", gen.FieldType("type", "consts.CommentType"), gen.FieldType("status", "consts.CommentStatus")),
g.GenerateModel("comment_black"),
g.GenerateModel("flyway_schema_history"),
g.GenerateModel("journal", gen.FieldType("type", "consts.JournalType")),
g.GenerateModel("link"),
g.GenerateModel("log", gen.FieldType("type", "consts.LogType")),
g.GenerateModel("menu"),
g.GenerateModelAs("meta", "Meta", gen.FieldType("type", "consts.MetaType")),
g.GenerateModel("option", gen.FieldType("type", "consts.OptionType")),
g.GenerateModel("photo"),
g.GenerateModel("post", gen.FieldType("type", "consts.PostType"), gen.FieldType("status", "consts.PostStatus"), gen.FieldType("editor_type", "consts.EditorType")),
g.GenerateModel("post_category"),
g.GenerateModel("post_tag"),
g.GenerateModel("tag"),
g.GenerateModel("theme_setting"),
g.GenerateModel("user", gen.FieldType("mfa_type", "consts.MFAType")),
)
// apply diy interfaces on structs or table models
// g.ApplyInterface(func(method model.Method) {}, model.User{}, g.GenerateModel("company"))
// execute the action of code generation
g.Execute()
}

@ -0,0 +1,33 @@
server:
host: 127.0.0.1
port: 8080
logging:
filename: sonic.log
level:
app: debug # debug,info,warn,error
gorm: info # info,warn,error,silent
maxsize: 10 # 单位 megabytes
maxage: 30 #单位 天
compress: false # 是否对旧日志使用gzip进行压缩
### 数据库配置, MySQL 和 SQLite3 二选一 .如果同时配置了MySQL 或 SQLite3 ,优先使用 Sqlite3
### The Database configuration,You should choose one between MySQL and SQLite3,if both MySQL and SQLite3 are configured ,use Sqlite3 first
sqlite3:
enable: true
mysql:
host: 127.0.0.1
port: 3306
db: sonicdb
username: "root"
password: "12345678"
sonic:
mode: "development"
work_dir: "./" # 不填默认为当前路径,用来存放日志文件、数据库文件、模板、上传的附件等(The default is the current directory. Used to store log files, database files, templates, upload files)
log_dir: "./logs" # 不填则使用work_dir 路径下的log路径 (If it is empty, use the "log" path under work_dir)

@ -0,0 +1,32 @@
server:
host: 0.0.0.0
port: 8080
logging:
filename: sonic.log
level:
app: info # debug,info,warn,error
gorm: warn # info,warn,error,silent
maxsize: 10 # 单位 megabytes
maxage: 30 #单位 天
compress: false # 是否对旧日志使用gzip进行压缩
### 数据库配置, MySQL 和 SQLite3 二选一 .如果同时配置了MySQL 或 SQLite3 ,优先使用 Sqlite3
### The Database configuration,You should choose one between MySQL and SQLite3,if bothMySQL and SQLite3 are configured ,use Sqlite3 first
sqlite3:
enable: true
mysql:
host: 127.0.0.1
port: 3306
db: sonicdb
username: "root"
password: "12345678"
sonic:
mode: "production"
work_dir: "./" # 不填默认为当前路径,用来存放日志文件、数据库文件、模板、上传的附件等(The default is the current directory. Used to store log files, database files, templates, upload files)
log_dir: "./logs" # 不填则使用work_dir 路径下的log路径 (If it is empty, use the "log" path under work_dir)

@ -0,0 +1,103 @@
package config
import (
"flag"
"fmt"
"os"
"path/filepath"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/util"
)
func NewConfig() *Config {
var configFile string
flag.StringVar(&configFile, "config", "", "")
flag.Parse()
viper.SetConfigType("yaml")
if configFile != "" {
viper.SetConfigFile(configFile)
} else {
viper.AddConfigPath("./conf/")
viper.SetConfigName("config.yaml")
}
conf := &Config{}
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
if err := viper.Unmarshal(conf); err != nil {
panic(err)
}
if conf.Sonic.WorkDir == "" {
pwd, err := os.Getwd()
if err != nil {
panic(errors.Wrap(err, "init config: get current dir"))
}
conf.Sonic.WorkDir, _ = filepath.Abs(pwd)
} else {
workDir, err := filepath.Abs(conf.Sonic.WorkDir)
if err != nil {
panic(err)
}
conf.Sonic.WorkDir = workDir
}
normalizeDir := func(path *string, subDir string) {
if *path == "" {
*path = filepath.Join(conf.Sonic.WorkDir, subDir)
} else {
temp, err := filepath.Abs(*path)
if err != nil {
panic(err)
}
*path = temp
}
}
normalizeDir(&conf.Sonic.LogDir, "log")
normalizeDir(&conf.Sonic.TemplateDir, "resources/template")
normalizeDir(&conf.Sonic.AdminResourcesDir, "resources/admin")
normalizeDir(&conf.Sonic.UploadDir, consts.SonicUploadDir)
normalizeDir(&conf.Sonic.ThemeDir, "resources/template/theme")
if conf.SQLite3 != nil && conf.SQLite3.Enable {
normalizeDir(&conf.SQLite3.File, "sonic.db")
}
if !util.FileIsExisted(conf.Sonic.TemplateDir) {
panic("template dir: " + conf.Sonic.TemplateDir + " not exist")
}
if !util.FileIsExisted(conf.Sonic.AdminResourcesDir) {
panic("AdminResourcesDir: " + conf.Sonic.AdminResourcesDir + "not exist")
}
if !util.FileIsExisted(conf.Sonic.ThemeDir) {
panic("theme dir: " + conf.Sonic.ThemeDir + " not exist")
}
initDirectory(conf)
mode = conf.Sonic.Mode
return conf
}
func initDirectory(conf *Config) {
mkdirFunc := func(dir string, err error) error {
if err == nil {
if _, err = os.Stat(dir); os.IsNotExist(err) {
err = os.MkdirAll(dir, os.ModePerm)
}
}
return err
}
err := mkdirFunc(conf.Sonic.LogDir, nil)
err = mkdirFunc(conf.Sonic.UploadDir, err)
if err != nil {
panic(fmt.Errorf("initDirectory err=%v", err))
}
}
var mode string
func IsDev() bool {
return mode == "development"
}

@ -0,0 +1,14 @@
package config
import (
"os"
"path/filepath"
)
var (
TempDir = os.TempDir()
BackupDir = filepath.Join(TempDir, "sonic-backup") + string(os.PathSeparator)
BackupMarkdownDir = filepath.Join(TempDir, "sonic-backup-markdown") + string(os.PathSeparator)
DataExportDir = filepath.Join(TempDir, "sonic-data-export") + string(os.PathSeparator)
ResourcesDir, _ = filepath.Abs("./resources")
)

@ -0,0 +1,54 @@
package config
type Config struct {
Server Server `mapstructure:"server"`
Log Log `mapstructure:"logging"`
PostgreSQL *PostgreSQL `mapstructure:"postgre"`
MySQL *MySQL `mapstructure:"mysql"`
SQLite3 *SQLite3 `mapstructure:"sqlite3"`
Sonic Sonic `mapstructure:"sonic"`
}
type PostgreSQL struct {
Host string `mapstructure:"host"`
Port string `mapstructure:"port"`
DB string `mapstructure:"db"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}
type MySQL struct {
Host string `mapstructure:"host"`
Port string `mapstructure:"port"`
DB string `mapstructure:"db"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}
type SQLite3 struct {
Enable bool `mapstructure:"enable"`
File string
}
type Server struct {
Host string `mapstructure:"host"`
Port string `mapstructure:"port"`
}
type Log struct {
FileName string `mapstructure:"filename"`
Levels Levels `mapstructure:"level"`
MaxSize int `mapstructure:"maxsize"`
MaxAge int `mapstructure:"maxage"`
Compress bool `mapstructure:"compress"`
}
type Levels struct {
App string `mapstructure:"app"`
Gorm string `mapstructure:"gorm"`
}
type Sonic struct {
Mode string `mapstructure:"mode"`
WorkDir string `mapstructure:"work_dir"`
UploadDir string
LogDir string `mapstructure:"log_dir"`
TemplateDir string `mapstructure:"template_dir"`
ThemeDir string
AdminResourcesDir string
}

@ -0,0 +1,46 @@
package consts
import (
"time"
)
const (
AccessTokenExpiredSeconds = 24 * 3600
RefreshTokenExpiredDays = 30
TokenAccessCachePrefix = "admin_access_token_"
TokenRefreshCachePrefix = "admin_refresh_token_"
AdminTokenHeaderName = "Admin-Authorization"
AuthorizedUser = "authorized_user"
CodePrefix = "code_"
CodeValidDuration = time.Second
OneTimeTokenQueryName = "ott"
SessionID = "session_id"
AccessPermissionKeyPrefix = "access_permission_"
)
const (
SonicVersion = "1.0.0"
SonicBackupPrefix = "sonic-backup-"
SonicDataExportPrefix = "sonic-data-export-"
SonicBackupMarkdownPrefix = "sonic-backup-markdown-"
SonicDefaultTagColor = "#cfd3d7"
SonicUploadDir = "upload"
SonicDefaultThemeDirName = "default-theme-anatole"
)
var (
ThemePropertyFilenames = [2]string{"theme.yaml", "theme.yml"}
ThemeSettingFilenames = [2]string{"settings.yaml", "settings.yml"}
)
const (
DefaultThemeId = "caicai_anatole"
ThemeScreenshotsName = "screenshot"
ThemeCustomSheetPrefix = "sheet_"
ThemeCustomPostPrefix = "post_"
)
// StartTime 系统启动时间
var StartTime time.Time
var DatabaseVersion string

@ -0,0 +1,990 @@
package consts
import (
"database/sql/driver"
"strconv"
"strings"
"github.com/go-sonic/sonic/util/xerr"
)
type DBType string
const (
DBTypeMySQL = "MySQL"
DBTypeSQLite = "SQLite"
)
type AttachmentType int32
const (
AttachmentTypeLocal AttachmentType = iota
// AttachmentTypeUpOSS 又拍云
AttachmentTypeUpOSS
// AttachmentTypeQiNiuOSS 七牛云
AttachmentTypeQiNiuOSS
// AttachmentTypeSMMS sm.ms
AttachmentTypeSMMS
// AttachmentTypeAliOSS 阿里云OSS
AttachmentTypeAliOSS
// AttachmentTypeBaiDuOSS 百度云OSS
AttachmentTypeBaiDuOSS
// AttachmentTypeTencentCOS 腾讯COS
AttachmentTypeTencentCOS
// AttachmentTypeHuaweiOBS 华为OBS
AttachmentTypeHuaweiOBS
// AttachmentTypeMinIO AttachmentTypeMinIO
AttachmentTypeMinIO
)
func (a AttachmentType) String() string {
switch a {
case AttachmentTypeLocal:
return "LOCAL"
case AttachmentTypeUpOSS:
return "UPOSS"
case AttachmentTypeQiNiuOSS:
return "QINIUOSS"
case AttachmentTypeSMMS:
return "AttachmentTypeSMMS"
case AttachmentTypeAliOSS:
return "ALIOSS"
case AttachmentTypeBaiDuOSS:
return "BAIDUOSS"
case AttachmentTypeTencentCOS:
return "TENCENTOSS"
case AttachmentTypeHuaweiOBS:
return "HUAWEIOBS"
case AttachmentTypeMinIO:
return "MINIO"
default:
return "UNKNOWN"
}
}
func (a AttachmentType) MarshalJSON() ([]byte, error) {
switch a {
case AttachmentTypeLocal:
return []byte(`"LOCAL"`), nil
case AttachmentTypeUpOSS:
return []byte(`"UPOSS"`), nil
case AttachmentTypeQiNiuOSS:
return []byte(`"QINIUOSS"`), nil
case AttachmentTypeSMMS:
return []byte(`"AttachmentTypeSMMS"`), nil
case AttachmentTypeAliOSS:
return []byte(`"ALIOSS"`), nil
case AttachmentTypeBaiDuOSS:
return []byte(`"BAIDUOSS"`), nil
case AttachmentTypeTencentCOS:
return []byte(`"TENCENTOSS"`), nil
case AttachmentTypeHuaweiOBS:
return []byte(`"HUAWEIOBS"`), nil
case AttachmentTypeMinIO:
return []byte(`"MINIO"`), nil
default:
return []byte(`"UNKNOWN"`), nil
}
}
func (a *AttachmentType) UnmarshalJSON(data []byte) error {
str := string(data)
switch str {
case `"LOCAL"`:
*a = AttachmentTypeLocal
case `"UPOSS"`:
*a = AttachmentTypeUpOSS
case `"QINIUOSS"`:
*a = AttachmentTypeQiNiuOSS
case `"AttachmentTypeSMMS"`:
*a = AttachmentTypeSMMS
case `"ALIOSS"`:
*a = AttachmentTypeAliOSS
case `"BAIDUBOS"`:
*a = AttachmentTypeBaiDuOSS
case `"TENCENTCOS"`:
*a = AttachmentTypeTencentCOS
case `"HUAWEIOBS"`:
*a = AttachmentTypeHuaweiOBS
case `"MINIO"`:
*a = AttachmentTypeMinIO
default:
return xerr.BadParam.New("").WithMsg("unknown AttachmentType")
}
return nil
}
func (a *AttachmentType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*a = AttachmentType(data)
case int32:
*a = AttachmentType(data)
case int:
*a = AttachmentType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (a AttachmentType) Value() (driver.Value, error) {
return int64(a), nil
}
type LogType int32
const (
LogTypeBlogInitialized LogType = iota
LogTypePostPublished
LogTypePostEdited
LogTypePostDeleted
LogTypeLoggedIn
LogTypeLoggedOut
LogTypeLoginFailed
LogTypePasswordUpdated
LogTypeProfileUpdated
LogTypeSheetPublished
LogTypeSheetEdited
LogTypeSheetDeleted
LogTypeMfaUpdated
LogTypeLoggedPreCheck
)
func (l LogType) MarshalJSON() ([]byte, error) {
switch l {
case LogTypeBlogInitialized:
return []byte(`"BLOG_INITIALIZED"`), nil
case LogTypePostPublished:
return []byte(`"POST_PUBLISHED"`), nil
case LogTypePostEdited:
return []byte(`"POST_EDITED"`), nil
case LogTypePostDeleted:
return []byte(`"POST_DELETED"`), nil
case LogTypeLoggedIn:
return []byte(`"LOGGED_IN"`), nil
case LogTypeLoggedOut:
return []byte(`"LOGGED_OUT"`), nil
case LogTypeLoginFailed:
return []byte(`"LOGIN_FAILED"`), nil
case LogTypePasswordUpdated:
return []byte(`"PASSWORD_UPDATED"`), nil
case LogTypeProfileUpdated:
return []byte(`"PROFILE_UPDATED"`), nil
case LogTypeSheetPublished:
return []byte(`"SHEET_PUBLISHED"`), nil
case LogTypeSheetEdited:
return []byte(`"SHEET_EDITED"`), nil
case LogTypeSheetDeleted:
return []byte(`"SHEET_DELETED"`), nil
case LogTypeMfaUpdated:
return []byte(`"MFA_UPDATED"`), nil
case LogTypeLoggedPreCheck:
return []byte(`"LOGGED_PRE_CHECK"`), nil
}
return nil, nil
}
func (l *LogType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*l = LogType(data)
case int32:
*l = LogType(data)
case int:
*l = LogType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (l LogType) Value() (driver.Value, error) {
return int64(l), nil
}
type MFAType int32
const (
MFANone MFAType = iota
// MFATFATotp Time-based One-time Password (rfc6238).
// see: https://tools.ietf.org/html/rfc6238
MFATFATotp
)
func (m MFAType) MarshalJSON() ([]byte, error) {
if m == MFANone {
return []byte(`"NONE"`), nil
} else if m == MFATFATotp {
return []byte(`"TFA_TOTP"`), nil
}
return nil, nil
}
func (m *MFAType) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"NONE"` {
*m = MFANone
} else if str == `"TFA_TOTP"` {
*m = MFATFATotp
} else {
return xerr.BadParam.New("").WithMsg("unknown MFAType")
}
return nil
}
func (m *MFAType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*m = MFAType(data)
case int32:
*m = MFAType(data)
case int:
*m = MFAType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (m MFAType) Value() (driver.Value, error) {
return int64(m), nil
}
type PostStatus int32
const (
PostStatusPublished PostStatus = iota
PostStatusDraft
PostStatusRecycle
PostStatusIntimate
)
func (c PostStatus) MarshalJSON() ([]byte, error) {
if c == PostStatusPublished {
return []byte(`"PUBLISHED"`), nil
} else if c == PostStatusDraft {
return []byte(`"DRAFT"`), nil
} else if c == PostStatusRecycle {
return []byte(`"RECYCLE"`), nil
} else if c == PostStatusIntimate {
return []byte(`"INTIMATE"`), nil
}
return nil, nil
}
func (c *PostStatus) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"PUBLISHED"` {
*c = PostStatusPublished
} else if str == `"DRAFT"` {
*c = PostStatusDraft
} else if str == `"RECYCLE"` {
*c = PostStatusRecycle
} else if str == `"INTIMATE"` {
*c = PostStatusIntimate
} else if str == "" {
*c = PostStatusDraft
} else {
return xerr.BadParam.New("").WithMsg("unknown PostStatus")
}
return nil
}
func (c *PostStatus) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*c = PostStatus(data)
case int32:
*c = PostStatus(data)
case int:
*c = PostStatus(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (c PostStatus) Value() (driver.Value, error) {
return int64(c), nil
}
func (c PostStatus) Ptr() *PostStatus {
return &c
}
type CommentStatus int32
const (
CommentStatusPublished CommentStatus = iota
CommentStatusAuditing
CommentStatusRecycle
)
func (c CommentStatus) MarshalJSON() ([]byte, error) {
if c == CommentStatusPublished {
return []byte(`"PUBLISHED"`), nil
} else if c == CommentStatusAuditing {
return []byte(`"AUDITING"`), nil
} else if c == CommentStatusRecycle {
return []byte(`"RECYCLE"`), nil
}
return nil, nil
}
func (c *CommentStatus) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"PUBLISHED"` {
*c = CommentStatusPublished
} else if str == `"AUDITING"` {
*c = CommentStatusAuditing
} else if str == `"RECYCLE"` {
*c = CommentStatusRecycle
} else {
return xerr.BadParam.New("").WithMsg("unknown CommentStatus")
}
return nil
}
func (c *CommentStatus) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*c = CommentStatus(data)
case int32:
*c = CommentStatus(data)
case int:
*c = CommentStatus(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func CommentStatusFromString(str string) (CommentStatus, error) {
if str == "PUBLISHED" {
return CommentStatusPublished, nil
} else if str == "AUDITING" {
return CommentStatusAuditing, nil
} else if str == "RECYCLE" {
return CommentStatusRecycle, nil
} else {
return CommentStatusPublished, xerr.BadParam.New("").WithMsg("unknown CommentStatus")
}
}
func (c CommentStatus) Value() (driver.Value, error) {
return int64(c), nil
}
func (c CommentStatus) Ptr() *CommentStatus {
return &c
}
type PostPermalinkType string
const (
PostPermalinkTypeDefault PostPermalinkType = "DEFAULT"
PostPermalinkTypeDate PostPermalinkType = "DATE"
PostPermalinkTypeDay PostPermalinkType = "DAY"
PostPermalinkTypeID PostPermalinkType = "ID"
PostPermalinkTypeYear PostPermalinkType = "YEAR"
PostPermalinkTypeIDSlug PostPermalinkType = "ID_SLUG"
)
type EditorType int32
const (
EditorTypeMarkdown = iota
EditorTypeRichText
)
func (e *EditorType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*e = EditorType(data)
case int32:
*e = EditorType(data)
case int:
*e = EditorType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (e EditorType) Value() (driver.Value, error) {
return int64(e), nil
}
func (e EditorType) MarshalJSON() ([]byte, error) {
if e == EditorTypeMarkdown {
return []byte(`"MARKDOWN"`), nil
} else if e == EditorTypeRichText {
return []byte(`"RICHTEXT"`), nil
}
return nil, nil
}
func (e *EditorType) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"MARKDOWN"` {
*e = EditorTypeMarkdown
} else if str == `"RICHTEXT"` {
*e = EditorTypeRichText
} else if str == "" {
*e = EditorTypeMarkdown
} else {
return xerr.BadParam.New("").WithMsg("unknown editorType")
}
return nil
}
type OptionType int32
const (
OptionTypeInternal = iota
OptionTypeCustom
)
func (o OptionType) MarshalJSON() ([]byte, error) {
if o == OptionTypeInternal {
return []byte(`"INTERNAL"`), nil
} else if o == OptionTypeCustom {
return []byte(`"CUSTOM"`), nil
}
return nil, nil
}
func (o *OptionType) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"INTERNAL"` {
*o = OptionTypeInternal
} else if str == `"CUSTOM"` {
*o = OptionTypeCustom
} else {
return xerr.BadParam.New("").WithMsg("unknown OptionType")
}
return nil
}
func (o *OptionType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*o = OptionType(data)
case int32:
*o = OptionType(data)
case int:
*o = OptionType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (o OptionType) Value() (driver.Value, error) {
return int64(o), nil
}
type PostType int32
const (
PostTypePost PostType = iota
PostTypeSheet
)
func (p *PostType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*p = PostType(data)
case int32:
*p = PostType(data)
case int:
*p = PostType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (p PostType) Value() (driver.Value, error) {
return int64(p), nil
}
type CommentType int32
const (
CommentTypePost CommentType = iota
CommentTypeSheet
CommentTypeJournal
)
func (ct *CommentType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("unknown OptionType")
}
switch data := src.(type) {
case int64:
*ct = CommentType(data)
case int32:
*ct = CommentType(data)
case int:
*ct = CommentType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (ct CommentType) Value() (driver.Value, error) {
return int64(ct), nil
}
type SheetPermaLinkType string
const (
SheetPermaLinkTypeSecondary = "SECONDARY"
SheetPermaLinkTypeRoot = "ROOT"
)
type JournalType int32
const (
JournalTypePublic JournalType = iota
JournalTypeIntimate
)
func (j JournalType) Ptr() *JournalType {
return &j
}
func (j JournalType) MarshalJSON() ([]byte, error) {
if j == JournalTypePublic {
return []byte(`"PUBLIC"`), nil
} else if j == JournalTypeIntimate {
return []byte(`"INTIMATE"`), nil
}
return nil, nil
}
func (j *JournalType) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"PUBLIC"` {
*j = JournalTypePublic
} else if str == `"INTIMATE"` {
*j = JournalTypeIntimate
} else {
return xerr.BadParam.New("").WithMsg("unknown JournalType")
}
return nil
}
func (j *JournalType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*j = JournalType(data)
case int32:
*j = JournalType(data)
case int:
*j = JournalType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (j JournalType) Value() (driver.Value, error) {
return int64(j), nil
}
type MetaType int32
const (
MetaTypePost = iota
MetaTypeSheet = iota
)
func (m *MetaType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*m = MetaType(data)
case int32:
*m = MetaType(data)
case int:
*m = MetaType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (m MetaType) Value() (driver.Value, error) {
return int64(m), nil
}
type ThemeUpdateStrategy int32
const (
ThemeUpdateStrategyBranch = iota
ThemeUpdateStrategyRelease
)
type ThemeConfigInputType int32
const (
// ThemeConfigInputTypeTEXT Text input type
ThemeConfigInputTypeTEXT = iota
// ThemeConfigInputTypeNUMBER Number input type
ThemeConfigInputTypeNUMBER
// ThemeConfigInputTypeRADIO Radio box input type
ThemeConfigInputTypeRADIO
// ThemeConfigInputTypeSELECT Select input type
ThemeConfigInputTypeSELECT
// ThemeConfigInputTypeTEXTAREA Textarea input type
ThemeConfigInputTypeTEXTAREA
// ThemeConfigInputTypeCOLOR Color picker input type
ThemeConfigInputTypeCOLOR
// ThemeConfigInputTypeATTACHMENT Attachment picker input type
ThemeConfigInputTypeATTACHMENT
// ThemeConfigInputTypeSWITCH Switch input type, only true or false
ThemeConfigInputTypeSWITCH
)
func (t ThemeConfigInputType) MarshalJSON() ([]byte, error) {
switch t {
case ThemeConfigInputTypeTEXT:
return []byte(`"TEXT"`), nil
case ThemeConfigInputTypeNUMBER:
return []byte(`"NUMBER"`), nil
case ThemeConfigInputTypeRADIO:
return []byte(`"RADIO"`), nil
case ThemeConfigInputTypeSELECT:
return []byte(`"SELECT"`), nil
case ThemeConfigInputTypeTEXTAREA:
return []byte(`"TEXTAREA"`), nil
case ThemeConfigInputTypeCOLOR:
return []byte(`"COLOR"`), nil
case ThemeConfigInputTypeATTACHMENT:
return []byte(`"ATTACHMENT"`), nil
case ThemeConfigInputTypeSWITCH:
return []byte(`"SWITCH"`), nil
default:
return nil, xerr.BadParam.New("").WithMsg("unknown ThemeConfigInputType")
}
}
func (t *ThemeConfigInputType) UnmarshalJSON(data []byte) error {
str := string(data)
switch str {
case `"TEXT"`:
*t = ThemeConfigInputTypeTEXT
return nil
case `"NUMBER"`:
*t = ThemeConfigInputTypeNUMBER
return nil
case `"RADIO"`:
*t = ThemeConfigInputTypeRADIO
return nil
case `"SELECT"`:
*t = ThemeConfigInputTypeSELECT
return nil
case `"TEXTAREA"`:
*t = ThemeConfigInputTypeTEXTAREA
return nil
case `"COLOR"`:
*t = ThemeConfigInputTypeCOLOR
return nil
case `"SWITCH"`:
*t = ThemeConfigInputTypeSWITCH
return nil
case `"ATTACHMENT"`:
*t = ThemeConfigInputTypeATTACHMENT
return nil
default:
return xerr.BadParam.New("").WithMsg("unknown ThemeConfigInputType")
}
}
func (t *ThemeConfigInputType) UnmarshalYAML(unmarshal func(interface{}) error) error {
strType := ""
err := unmarshal(&strType)
if err != nil {
return xerr.BadParam.New("").WithMsg("ThemeConfigInputType yaml unmarshal err")
}
strType = strings.ToUpper(strType)
switch strType {
case "TEXT":
*t = ThemeConfigInputTypeTEXT
return nil
case "NUMBER":
*t = ThemeConfigInputTypeNUMBER
return nil
case "RADIO":
*t = ThemeConfigInputTypeRADIO
return nil
case "SELECT":
*t = ThemeConfigInputTypeSELECT
return nil
case "TEXTAREA":
*t = ThemeConfigInputTypeTEXTAREA
return nil
case "COLOR":
*t = ThemeConfigInputTypeCOLOR
return nil
case "SWITCH":
*t = ThemeConfigInputTypeSWITCH
return nil
case "ATTACHMENT":
*t = ThemeConfigInputTypeATTACHMENT
return nil
default:
return xerr.BadParam.New("").WithMsg("unknown ThemeConfigInputType")
}
}
type ThemeConfigDataType int32
const (
ThemeConfigDataTypeString ThemeConfigDataType = iota
ThemeConfigDataTypeLong
ThemeConfigDataTypeDouble
ThemeConfigDataTypeBool
)
func (t ThemeConfigDataType) Convert(value string) (interface{}, error) {
switch t {
case ThemeConfigDataTypeString:
return value, nil
case ThemeConfigDataTypeLong:
result, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, xerr.WithErrMsgf(err, "value invalid ThemeConfigDataType")
}
return result, nil
case ThemeConfigDataTypeDouble:
result, err := strconv.ParseFloat(value, 64)
if err != nil {
return nil, xerr.WithErrMsgf(err, "value invalid ThemeConfigDataType")
}
return result, nil
case ThemeConfigDataTypeBool:
result, err := strconv.ParseBool(value)
if err != nil {
return nil, xerr.WithErrMsgf(err, "value invalid ThemeConfigDataType")
}
return result, nil
default:
return nil, xerr.WithErrMsgf(nil, "invalid ThemeConfigDataType")
}
}
func (t ThemeConfigDataType) FormatToStr(value interface{}) (string, error) {
switch t {
case ThemeConfigDataTypeString:
valueStr, ok := value.(string)
if !ok {
return "", xerr.WithErrMsgf(nil, "value invalid ThemeConfigDataType")
}
return valueStr, nil
case ThemeConfigDataTypeLong:
var valueStr string
switch data := value.(type) {
case int:
valueStr = strconv.FormatInt(int64(data), 10)
case int64:
valueStr = strconv.FormatInt(data, 10)
case int32:
valueStr = strconv.FormatInt(int64(data), 10)
default:
return "", xerr.WithErrMsgf(nil, "value invalid ThemeConfigDataType")
}
return valueStr, nil
case ThemeConfigDataTypeDouble:
var valueStr string
switch data := value.(type) {
case float32:
valueStr = strconv.FormatFloat(float64(data), 'f', 5, 32)
case float64:
valueStr = strconv.FormatFloat(float64(data), 'f', 5, 64)
default:
return "", xerr.WithErrMsgf(nil, "value invalid ThemeConfigDataType")
}
return valueStr, nil
case ThemeConfigDataTypeBool:
var valueStr string
switch data := value.(type) {
case bool:
valueStr = strconv.FormatBool(data)
default:
return "", xerr.WithErrMsgf(nil, "value invalid ThemeConfigDataType")
}
return valueStr, nil
default:
return "", xerr.WithErrMsgf(nil, "invalid ThemeConfigDataType")
}
}
func (t ThemeConfigDataType) MarshalJSON() ([]byte, error) {
switch t {
case ThemeConfigDataTypeString:
return []byte(`"STRING"`), nil
case ThemeConfigDataTypeLong:
return []byte(`"LONG"`), nil
case ThemeConfigDataTypeDouble:
return []byte(`"DOUBLE"`), nil
case ThemeConfigDataTypeBool:
return []byte(`"BOOL"`), nil
default:
return nil, xerr.BadParam.New("").WithMsg("unknown ThemeConfigDataType")
}
}
func (t *ThemeConfigDataType) UnmarshalJSON(data []byte) error {
str := string(data)
switch str {
case `"STRING"`:
*t = ThemeConfigDataTypeString
return nil
case `"LONG"`:
*t = ThemeConfigDataTypeLong
return nil
case `"DOUBLE"`:
*t = ThemeConfigDataTypeDouble
return nil
case `"BOOL"`:
*t = ThemeConfigDataTypeBool
return nil
default:
return xerr.BadParam.New("").WithMsg("unknown ThemeConfigInputType")
}
}
func (t *ThemeConfigDataType) UnmarshalYAML(unmarshal func(interface{}) error) error {
strType := ""
err := unmarshal(&strType)
if err != nil {
return xerr.BadParam.New("").WithMsg("ThemeConfigDataType yaml unmarshal err")
}
strType = strings.ToUpper(strType)
switch strType {
case "STRING":
*t = ThemeConfigDataTypeString
return nil
case "LONG":
*t = ThemeConfigDataTypeLong
return nil
case "DOUBLE":
*t = ThemeConfigDataTypeDouble
return nil
case "BOOL":
*t = ThemeConfigDataTypeBool
return nil
default:
return xerr.BadParam.New("").WithMsg("unknown ThemeConfigDataType")
}
}
type EncryptType int32
const (
EncryptTypePost EncryptType = iota
EncryptTypeCategory
)
func (e EncryptType) Name() string {
if e == EncryptTypePost {
return "post"
}
if e == EncryptTypeCategory {
return "category"
}
return ""
}
type CategoryType int32
const (
CategoryTypeNormal CategoryType = iota
CategoryTypeIntimate
)
func (c CategoryType) MarshalJSON() ([]byte, error) {
if c == CategoryTypeNormal {
return []byte(`"NORMAL"`), nil
} else if c == CategoryTypeIntimate {
return []byte(`"INTIMATE"`), nil
}
return nil, nil
}
func (c *CategoryType) UnmarshalJSON(data []byte) error {
str := string(data)
if str == `"NORMAL"` {
*c = CategoryTypeNormal
} else if str == `"INTIMATE"` {
*c = CategoryTypeIntimate
} else {
return xerr.BadParam.New("").WithMsg("unknown PostStatus")
}
return nil
}
func (c *CategoryType) Scan(src interface{}) error {
if src == nil {
return xerr.BadParam.New("").WithMsg("field nil")
}
switch data := src.(type) {
case int64:
*c = CategoryType(data)
case int32:
*c = CategoryType(data)
case int:
*c = CategoryType(data)
default:
return xerr.BadParam.New("").WithMsg("bad type")
}
return nil
}
func (c CategoryType) Value() (driver.Value, error) {
return int64(c), nil
}
func (c CategoryType) Ptr() *CategoryType {
return &c
}

@ -0,0 +1,368 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newAttachment(db *gorm.DB) attachment {
_attachment := attachment{}
_attachment.attachmentDo.UseDB(db)
_attachment.attachmentDo.UseModel(&entity.Attachment{})
tableName := _attachment.attachmentDo.TableName()
_attachment.ALL = field.NewAsterisk(tableName)
_attachment.ID = field.NewInt32(tableName, "id")
_attachment.CreateTime = field.NewTime(tableName, "create_time")
_attachment.UpdateTime = field.NewTime(tableName, "update_time")
_attachment.FileKey = field.NewString(tableName, "file_key")
_attachment.Height = field.NewInt32(tableName, "height")
_attachment.MediaType = field.NewString(tableName, "media_type")
_attachment.Name = field.NewString(tableName, "name")
_attachment.Path = field.NewString(tableName, "path")
_attachment.Size = field.NewInt64(tableName, "size")
_attachment.Suffix = field.NewString(tableName, "suffix")
_attachment.ThumbPath = field.NewString(tableName, "thumb_path")
_attachment.Type = field.NewField(tableName, "type")
_attachment.Width = field.NewInt32(tableName, "width")
_attachment.fillFieldMap()
return _attachment
}
type attachment struct {
attachmentDo attachmentDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
FileKey field.String
Height field.Int32
MediaType field.String
Name field.String
Path field.String
Size field.Int64
Suffix field.String
ThumbPath field.String
Type field.Field
Width field.Int32
fieldMap map[string]field.Expr
}
func (a attachment) Table(newTableName string) *attachment {
a.attachmentDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a attachment) As(alias string) *attachment {
a.attachmentDo.DO = *(a.attachmentDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *attachment) updateTableName(table string) *attachment {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt32(table, "id")
a.CreateTime = field.NewTime(table, "create_time")
a.UpdateTime = field.NewTime(table, "update_time")
a.FileKey = field.NewString(table, "file_key")
a.Height = field.NewInt32(table, "height")
a.MediaType = field.NewString(table, "media_type")
a.Name = field.NewString(table, "name")
a.Path = field.NewString(table, "path")
a.Size = field.NewInt64(table, "size")
a.Suffix = field.NewString(table, "suffix")
a.ThumbPath = field.NewString(table, "thumb_path")
a.Type = field.NewField(table, "type")
a.Width = field.NewInt32(table, "width")
a.fillFieldMap()
return a
}
func (a *attachment) WithContext(ctx context.Context) *attachmentDo {
return a.attachmentDo.WithContext(ctx)
}
func (a attachment) TableName() string { return a.attachmentDo.TableName() }
func (a attachment) Alias() string { return a.attachmentDo.Alias() }
func (a *attachment) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *attachment) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 13)
a.fieldMap["id"] = a.ID
a.fieldMap["create_time"] = a.CreateTime
a.fieldMap["update_time"] = a.UpdateTime
a.fieldMap["file_key"] = a.FileKey
a.fieldMap["height"] = a.Height
a.fieldMap["media_type"] = a.MediaType
a.fieldMap["name"] = a.Name
a.fieldMap["path"] = a.Path
a.fieldMap["size"] = a.Size
a.fieldMap["suffix"] = a.Suffix
a.fieldMap["thumb_path"] = a.ThumbPath
a.fieldMap["type"] = a.Type
a.fieldMap["width"] = a.Width
}
func (a attachment) clone(db *gorm.DB) attachment {
a.attachmentDo.ReplaceDB(db)
return a
}
type attachmentDo struct{ gen.DO }
func (a attachmentDo) Debug() *attachmentDo {
return a.withDO(a.DO.Debug())
}
func (a attachmentDo) WithContext(ctx context.Context) *attachmentDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a attachmentDo) ReadDB() *attachmentDo {
return a.Clauses(dbresolver.Read)
}
func (a attachmentDo) WriteDB() *attachmentDo {
return a.Clauses(dbresolver.Write)
}
func (a attachmentDo) Clauses(conds ...clause.Expression) *attachmentDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a attachmentDo) Returning(value interface{}, columns ...string) *attachmentDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a attachmentDo) Not(conds ...gen.Condition) *attachmentDo {
return a.withDO(a.DO.Not(conds...))
}
func (a attachmentDo) Or(conds ...gen.Condition) *attachmentDo {
return a.withDO(a.DO.Or(conds...))
}
func (a attachmentDo) Select(conds ...field.Expr) *attachmentDo {
return a.withDO(a.DO.Select(conds...))
}
func (a attachmentDo) Where(conds ...gen.Condition) *attachmentDo {
return a.withDO(a.DO.Where(conds...))
}
func (a attachmentDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *attachmentDo {
return a.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (a attachmentDo) Order(conds ...field.Expr) *attachmentDo {
return a.withDO(a.DO.Order(conds...))
}
func (a attachmentDo) Distinct(cols ...field.Expr) *attachmentDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a attachmentDo) Omit(cols ...field.Expr) *attachmentDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a attachmentDo) Join(table schema.Tabler, on ...field.Expr) *attachmentDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a attachmentDo) LeftJoin(table schema.Tabler, on ...field.Expr) *attachmentDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a attachmentDo) RightJoin(table schema.Tabler, on ...field.Expr) *attachmentDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a attachmentDo) Group(cols ...field.Expr) *attachmentDo {
return a.withDO(a.DO.Group(cols...))
}
func (a attachmentDo) Having(conds ...gen.Condition) *attachmentDo {
return a.withDO(a.DO.Having(conds...))
}
func (a attachmentDo) Limit(limit int) *attachmentDo {
return a.withDO(a.DO.Limit(limit))
}
func (a attachmentDo) Offset(offset int) *attachmentDo {
return a.withDO(a.DO.Offset(offset))
}
func (a attachmentDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *attachmentDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a attachmentDo) Unscoped() *attachmentDo {
return a.withDO(a.DO.Unscoped())
}
func (a attachmentDo) Create(values ...*entity.Attachment) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a attachmentDo) CreateInBatches(values []*entity.Attachment, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a attachmentDo) Save(values ...*entity.Attachment) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a attachmentDo) First() (*entity.Attachment, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Attachment), nil
}
}
func (a attachmentDo) Take() (*entity.Attachment, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Attachment), nil
}
}
func (a attachmentDo) Last() (*entity.Attachment, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Attachment), nil
}
}
func (a attachmentDo) Find() ([]*entity.Attachment, error) {
result, err := a.DO.Find()
return result.([]*entity.Attachment), err
}
func (a attachmentDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Attachment, err error) {
buf := make([]*entity.Attachment, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a attachmentDo) FindInBatches(result *[]*entity.Attachment, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a attachmentDo) Attrs(attrs ...field.AssignExpr) *attachmentDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a attachmentDo) Assign(attrs ...field.AssignExpr) *attachmentDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a attachmentDo) Joins(fields ...field.RelationField) *attachmentDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a attachmentDo) Preload(fields ...field.RelationField) *attachmentDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a attachmentDo) FirstOrInit() (*entity.Attachment, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Attachment), nil
}
}
func (a attachmentDo) FirstOrCreate() (*entity.Attachment, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Attachment), nil
}
}
func (a attachmentDo) FindByPage(offset int, limit int) (result []*entity.Attachment, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a attachmentDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a attachmentDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a attachmentDo) Delete(models ...*entity.Attachment) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *attachmentDo) withDO(do gen.Dao) *attachmentDo {
a.DO = *do.(*gen.DO)
return a
}

@ -0,0 +1,358 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newCategory(db *gorm.DB) category {
_category := category{}
_category.categoryDo.UseDB(db)
_category.categoryDo.UseModel(&entity.Category{})
tableName := _category.categoryDo.TableName()
_category.ALL = field.NewAsterisk(tableName)
_category.ID = field.NewInt32(tableName, "id")
_category.CreateTime = field.NewTime(tableName, "create_time")
_category.UpdateTime = field.NewTime(tableName, "update_time")
_category.Description = field.NewString(tableName, "description")
_category.Name = field.NewString(tableName, "name")
_category.ParentID = field.NewInt32(tableName, "parent_id")
_category.Password = field.NewString(tableName, "password")
_category.Slug = field.NewString(tableName, "slug")
_category.Thumbnail = field.NewString(tableName, "thumbnail")
_category.Priority = field.NewInt32(tableName, "priority")
_category.Type = field.NewField(tableName, "type")
_category.fillFieldMap()
return _category
}
type category struct {
categoryDo categoryDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Description field.String
Name field.String
ParentID field.Int32
Password field.String
Slug field.String
Thumbnail field.String
Priority field.Int32
Type field.Field
fieldMap map[string]field.Expr
}
func (c category) Table(newTableName string) *category {
c.categoryDo.UseTable(newTableName)
return c.updateTableName(newTableName)
}
func (c category) As(alias string) *category {
c.categoryDo.DO = *(c.categoryDo.As(alias).(*gen.DO))
return c.updateTableName(alias)
}
func (c *category) updateTableName(table string) *category {
c.ALL = field.NewAsterisk(table)
c.ID = field.NewInt32(table, "id")
c.CreateTime = field.NewTime(table, "create_time")
c.UpdateTime = field.NewTime(table, "update_time")
c.Description = field.NewString(table, "description")
c.Name = field.NewString(table, "name")
c.ParentID = field.NewInt32(table, "parent_id")
c.Password = field.NewString(table, "password")
c.Slug = field.NewString(table, "slug")
c.Thumbnail = field.NewString(table, "thumbnail")
c.Priority = field.NewInt32(table, "priority")
c.Type = field.NewField(table, "type")
c.fillFieldMap()
return c
}
func (c *category) WithContext(ctx context.Context) *categoryDo { return c.categoryDo.WithContext(ctx) }
func (c category) TableName() string { return c.categoryDo.TableName() }
func (c category) Alias() string { return c.categoryDo.Alias() }
func (c *category) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := c.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (c *category) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 11)
c.fieldMap["id"] = c.ID
c.fieldMap["create_time"] = c.CreateTime
c.fieldMap["update_time"] = c.UpdateTime
c.fieldMap["description"] = c.Description
c.fieldMap["name"] = c.Name
c.fieldMap["parent_id"] = c.ParentID
c.fieldMap["password"] = c.Password
c.fieldMap["slug"] = c.Slug
c.fieldMap["thumbnail"] = c.Thumbnail
c.fieldMap["priority"] = c.Priority
c.fieldMap["type"] = c.Type
}
func (c category) clone(db *gorm.DB) category {
c.categoryDo.ReplaceDB(db)
return c
}
type categoryDo struct{ gen.DO }
func (c categoryDo) Debug() *categoryDo {
return c.withDO(c.DO.Debug())
}
func (c categoryDo) WithContext(ctx context.Context) *categoryDo {
return c.withDO(c.DO.WithContext(ctx))
}
func (c categoryDo) ReadDB() *categoryDo {
return c.Clauses(dbresolver.Read)
}
func (c categoryDo) WriteDB() *categoryDo {
return c.Clauses(dbresolver.Write)
}
func (c categoryDo) Clauses(conds ...clause.Expression) *categoryDo {
return c.withDO(c.DO.Clauses(conds...))
}
func (c categoryDo) Returning(value interface{}, columns ...string) *categoryDo {
return c.withDO(c.DO.Returning(value, columns...))
}
func (c categoryDo) Not(conds ...gen.Condition) *categoryDo {
return c.withDO(c.DO.Not(conds...))
}
func (c categoryDo) Or(conds ...gen.Condition) *categoryDo {
return c.withDO(c.DO.Or(conds...))
}
func (c categoryDo) Select(conds ...field.Expr) *categoryDo {
return c.withDO(c.DO.Select(conds...))
}
func (c categoryDo) Where(conds ...gen.Condition) *categoryDo {
return c.withDO(c.DO.Where(conds...))
}
func (c categoryDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *categoryDo {
return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (c categoryDo) Order(conds ...field.Expr) *categoryDo {
return c.withDO(c.DO.Order(conds...))
}
func (c categoryDo) Distinct(cols ...field.Expr) *categoryDo {
return c.withDO(c.DO.Distinct(cols...))
}
func (c categoryDo) Omit(cols ...field.Expr) *categoryDo {
return c.withDO(c.DO.Omit(cols...))
}
func (c categoryDo) Join(table schema.Tabler, on ...field.Expr) *categoryDo {
return c.withDO(c.DO.Join(table, on...))
}
func (c categoryDo) LeftJoin(table schema.Tabler, on ...field.Expr) *categoryDo {
return c.withDO(c.DO.LeftJoin(table, on...))
}
func (c categoryDo) RightJoin(table schema.Tabler, on ...field.Expr) *categoryDo {
return c.withDO(c.DO.RightJoin(table, on...))
}
func (c categoryDo) Group(cols ...field.Expr) *categoryDo {
return c.withDO(c.DO.Group(cols...))
}
func (c categoryDo) Having(conds ...gen.Condition) *categoryDo {
return c.withDO(c.DO.Having(conds...))
}
func (c categoryDo) Limit(limit int) *categoryDo {
return c.withDO(c.DO.Limit(limit))
}
func (c categoryDo) Offset(offset int) *categoryDo {
return c.withDO(c.DO.Offset(offset))
}
func (c categoryDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *categoryDo {
return c.withDO(c.DO.Scopes(funcs...))
}
func (c categoryDo) Unscoped() *categoryDo {
return c.withDO(c.DO.Unscoped())
}
func (c categoryDo) Create(values ...*entity.Category) error {
if len(values) == 0 {
return nil
}
return c.DO.Create(values)
}
func (c categoryDo) CreateInBatches(values []*entity.Category, batchSize int) error {
return c.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (c categoryDo) Save(values ...*entity.Category) error {
if len(values) == 0 {
return nil
}
return c.DO.Save(values)
}
func (c categoryDo) First() (*entity.Category, error) {
if result, err := c.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Category), nil
}
}
func (c categoryDo) Take() (*entity.Category, error) {
if result, err := c.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Category), nil
}
}
func (c categoryDo) Last() (*entity.Category, error) {
if result, err := c.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Category), nil
}
}
func (c categoryDo) Find() ([]*entity.Category, error) {
result, err := c.DO.Find()
return result.([]*entity.Category), err
}
func (c categoryDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Category, err error) {
buf := make([]*entity.Category, 0, batchSize)
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (c categoryDo) FindInBatches(result *[]*entity.Category, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return c.DO.FindInBatches(result, batchSize, fc)
}
func (c categoryDo) Attrs(attrs ...field.AssignExpr) *categoryDo {
return c.withDO(c.DO.Attrs(attrs...))
}
func (c categoryDo) Assign(attrs ...field.AssignExpr) *categoryDo {
return c.withDO(c.DO.Assign(attrs...))
}
func (c categoryDo) Joins(fields ...field.RelationField) *categoryDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Joins(_f))
}
return &c
}
func (c categoryDo) Preload(fields ...field.RelationField) *categoryDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Preload(_f))
}
return &c
}
func (c categoryDo) FirstOrInit() (*entity.Category, error) {
if result, err := c.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Category), nil
}
}
func (c categoryDo) FirstOrCreate() (*entity.Category, error) {
if result, err := c.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Category), nil
}
}
func (c categoryDo) FindByPage(offset int, limit int) (result []*entity.Category, count int64, err error) {
result, err = c.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = c.Offset(-1).Limit(-1).Count()
return
}
func (c categoryDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = c.Count()
if err != nil {
return
}
err = c.Offset(offset).Limit(limit).Scan(result)
return
}
func (c categoryDo) Scan(result interface{}) (err error) {
return c.DO.Scan(result)
}
func (c categoryDo) Delete(models ...*entity.Category) (result gen.ResultInfo, err error) {
return c.DO.Delete(models)
}
func (c *categoryDo) withDO(do gen.Dao) *categoryDo {
c.DO = *do.(*gen.DO)
return c
}

@ -0,0 +1,382 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newComment(db *gorm.DB) comment {
_comment := comment{}
_comment.commentDo.UseDB(db)
_comment.commentDo.UseModel(&entity.Comment{})
tableName := _comment.commentDo.TableName()
_comment.ALL = field.NewAsterisk(tableName)
_comment.ID = field.NewInt64(tableName, "id")
_comment.Type = field.NewField(tableName, "type")
_comment.CreateTime = field.NewTime(tableName, "create_time")
_comment.UpdateTime = field.NewTime(tableName, "update_time")
_comment.AllowNotification = field.NewBool(tableName, "allow_notification")
_comment.Author = field.NewString(tableName, "author")
_comment.AuthorURL = field.NewString(tableName, "author_url")
_comment.Content = field.NewString(tableName, "content")
_comment.Email = field.NewString(tableName, "email")
_comment.GravatarMd5 = field.NewString(tableName, "gravatar_md5")
_comment.IPAddress = field.NewString(tableName, "ip_address")
_comment.IsAdmin = field.NewBool(tableName, "is_admin")
_comment.ParentID = field.NewInt64(tableName, "parent_id")
_comment.PostID = field.NewInt32(tableName, "post_id")
_comment.Status = field.NewField(tableName, "status")
_comment.TopPriority = field.NewInt32(tableName, "top_priority")
_comment.UserAgent = field.NewString(tableName, "user_agent")
_comment.fillFieldMap()
return _comment
}
type comment struct {
commentDo commentDo
ALL field.Asterisk
ID field.Int64
Type field.Field
CreateTime field.Time
UpdateTime field.Time
AllowNotification field.Bool
Author field.String
AuthorURL field.String
Content field.String
Email field.String
GravatarMd5 field.String
IPAddress field.String
IsAdmin field.Bool
ParentID field.Int64
PostID field.Int32
Status field.Field
TopPriority field.Int32
UserAgent field.String
fieldMap map[string]field.Expr
}
func (c comment) Table(newTableName string) *comment {
c.commentDo.UseTable(newTableName)
return c.updateTableName(newTableName)
}
func (c comment) As(alias string) *comment {
c.commentDo.DO = *(c.commentDo.As(alias).(*gen.DO))
return c.updateTableName(alias)
}
func (c *comment) updateTableName(table string) *comment {
c.ALL = field.NewAsterisk(table)
c.ID = field.NewInt64(table, "id")
c.Type = field.NewField(table, "type")
c.CreateTime = field.NewTime(table, "create_time")
c.UpdateTime = field.NewTime(table, "update_time")
c.AllowNotification = field.NewBool(table, "allow_notification")
c.Author = field.NewString(table, "author")
c.AuthorURL = field.NewString(table, "author_url")
c.Content = field.NewString(table, "content")
c.Email = field.NewString(table, "email")
c.GravatarMd5 = field.NewString(table, "gravatar_md5")
c.IPAddress = field.NewString(table, "ip_address")
c.IsAdmin = field.NewBool(table, "is_admin")
c.ParentID = field.NewInt64(table, "parent_id")
c.PostID = field.NewInt32(table, "post_id")
c.Status = field.NewField(table, "status")
c.TopPriority = field.NewInt32(table, "top_priority")
c.UserAgent = field.NewString(table, "user_agent")
c.fillFieldMap()
return c
}
func (c *comment) WithContext(ctx context.Context) *commentDo { return c.commentDo.WithContext(ctx) }
func (c comment) TableName() string { return c.commentDo.TableName() }
func (c comment) Alias() string { return c.commentDo.Alias() }
func (c *comment) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := c.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (c *comment) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 17)
c.fieldMap["id"] = c.ID
c.fieldMap["type"] = c.Type
c.fieldMap["create_time"] = c.CreateTime
c.fieldMap["update_time"] = c.UpdateTime
c.fieldMap["allow_notification"] = c.AllowNotification
c.fieldMap["author"] = c.Author
c.fieldMap["author_url"] = c.AuthorURL
c.fieldMap["content"] = c.Content
c.fieldMap["email"] = c.Email
c.fieldMap["gravatar_md5"] = c.GravatarMd5
c.fieldMap["ip_address"] = c.IPAddress
c.fieldMap["is_admin"] = c.IsAdmin
c.fieldMap["parent_id"] = c.ParentID
c.fieldMap["post_id"] = c.PostID
c.fieldMap["status"] = c.Status
c.fieldMap["top_priority"] = c.TopPriority
c.fieldMap["user_agent"] = c.UserAgent
}
func (c comment) clone(db *gorm.DB) comment {
c.commentDo.ReplaceDB(db)
return c
}
type commentDo struct{ gen.DO }
func (c commentDo) Debug() *commentDo {
return c.withDO(c.DO.Debug())
}
func (c commentDo) WithContext(ctx context.Context) *commentDo {
return c.withDO(c.DO.WithContext(ctx))
}
func (c commentDo) ReadDB() *commentDo {
return c.Clauses(dbresolver.Read)
}
func (c commentDo) WriteDB() *commentDo {
return c.Clauses(dbresolver.Write)
}
func (c commentDo) Clauses(conds ...clause.Expression) *commentDo {
return c.withDO(c.DO.Clauses(conds...))
}
func (c commentDo) Returning(value interface{}, columns ...string) *commentDo {
return c.withDO(c.DO.Returning(value, columns...))
}
func (c commentDo) Not(conds ...gen.Condition) *commentDo {
return c.withDO(c.DO.Not(conds...))
}
func (c commentDo) Or(conds ...gen.Condition) *commentDo {
return c.withDO(c.DO.Or(conds...))
}
func (c commentDo) Select(conds ...field.Expr) *commentDo {
return c.withDO(c.DO.Select(conds...))
}
func (c commentDo) Where(conds ...gen.Condition) *commentDo {
return c.withDO(c.DO.Where(conds...))
}
func (c commentDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *commentDo {
return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (c commentDo) Order(conds ...field.Expr) *commentDo {
return c.withDO(c.DO.Order(conds...))
}
func (c commentDo) Distinct(cols ...field.Expr) *commentDo {
return c.withDO(c.DO.Distinct(cols...))
}
func (c commentDo) Omit(cols ...field.Expr) *commentDo {
return c.withDO(c.DO.Omit(cols...))
}
func (c commentDo) Join(table schema.Tabler, on ...field.Expr) *commentDo {
return c.withDO(c.DO.Join(table, on...))
}
func (c commentDo) LeftJoin(table schema.Tabler, on ...field.Expr) *commentDo {
return c.withDO(c.DO.LeftJoin(table, on...))
}
func (c commentDo) RightJoin(table schema.Tabler, on ...field.Expr) *commentDo {
return c.withDO(c.DO.RightJoin(table, on...))
}
func (c commentDo) Group(cols ...field.Expr) *commentDo {
return c.withDO(c.DO.Group(cols...))
}
func (c commentDo) Having(conds ...gen.Condition) *commentDo {
return c.withDO(c.DO.Having(conds...))
}
func (c commentDo) Limit(limit int) *commentDo {
return c.withDO(c.DO.Limit(limit))
}
func (c commentDo) Offset(offset int) *commentDo {
return c.withDO(c.DO.Offset(offset))
}
func (c commentDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *commentDo {
return c.withDO(c.DO.Scopes(funcs...))
}
func (c commentDo) Unscoped() *commentDo {
return c.withDO(c.DO.Unscoped())
}
func (c commentDo) Create(values ...*entity.Comment) error {
if len(values) == 0 {
return nil
}
return c.DO.Create(values)
}
func (c commentDo) CreateInBatches(values []*entity.Comment, batchSize int) error {
return c.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (c commentDo) Save(values ...*entity.Comment) error {
if len(values) == 0 {
return nil
}
return c.DO.Save(values)
}
func (c commentDo) First() (*entity.Comment, error) {
if result, err := c.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Comment), nil
}
}
func (c commentDo) Take() (*entity.Comment, error) {
if result, err := c.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Comment), nil
}
}
func (c commentDo) Last() (*entity.Comment, error) {
if result, err := c.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Comment), nil
}
}
func (c commentDo) Find() ([]*entity.Comment, error) {
result, err := c.DO.Find()
return result.([]*entity.Comment), err
}
func (c commentDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Comment, err error) {
buf := make([]*entity.Comment, 0, batchSize)
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (c commentDo) FindInBatches(result *[]*entity.Comment, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return c.DO.FindInBatches(result, batchSize, fc)
}
func (c commentDo) Attrs(attrs ...field.AssignExpr) *commentDo {
return c.withDO(c.DO.Attrs(attrs...))
}
func (c commentDo) Assign(attrs ...field.AssignExpr) *commentDo {
return c.withDO(c.DO.Assign(attrs...))
}
func (c commentDo) Joins(fields ...field.RelationField) *commentDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Joins(_f))
}
return &c
}
func (c commentDo) Preload(fields ...field.RelationField) *commentDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Preload(_f))
}
return &c
}
func (c commentDo) FirstOrInit() (*entity.Comment, error) {
if result, err := c.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Comment), nil
}
}
func (c commentDo) FirstOrCreate() (*entity.Comment, error) {
if result, err := c.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Comment), nil
}
}
func (c commentDo) FindByPage(offset int, limit int) (result []*entity.Comment, count int64, err error) {
result, err = c.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = c.Offset(-1).Limit(-1).Count()
return
}
func (c commentDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = c.Count()
if err != nil {
return
}
err = c.Offset(offset).Limit(limit).Scan(result)
return
}
func (c commentDo) Scan(result interface{}) (err error) {
return c.DO.Scan(result)
}
func (c commentDo) Delete(models ...*entity.Comment) (result gen.ResultInfo, err error) {
return c.DO.Delete(models)
}
func (c *commentDo) withDO(do gen.Dao) *commentDo {
c.DO = *do.(*gen.DO)
return c
}

@ -0,0 +1,336 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newCommentBlack(db *gorm.DB) commentBlack {
_commentBlack := commentBlack{}
_commentBlack.commentBlackDo.UseDB(db)
_commentBlack.commentBlackDo.UseModel(&entity.CommentBlack{})
tableName := _commentBlack.commentBlackDo.TableName()
_commentBlack.ALL = field.NewAsterisk(tableName)
_commentBlack.ID = field.NewInt64(tableName, "id")
_commentBlack.CreateTime = field.NewTime(tableName, "create_time")
_commentBlack.UpdateTime = field.NewTime(tableName, "update_time")
_commentBlack.BanTime = field.NewTime(tableName, "ban_time")
_commentBlack.IPAddress = field.NewString(tableName, "ip_address")
_commentBlack.fillFieldMap()
return _commentBlack
}
type commentBlack struct {
commentBlackDo commentBlackDo
ALL field.Asterisk
ID field.Int64
CreateTime field.Time
UpdateTime field.Time
BanTime field.Time
IPAddress field.String
fieldMap map[string]field.Expr
}
func (c commentBlack) Table(newTableName string) *commentBlack {
c.commentBlackDo.UseTable(newTableName)
return c.updateTableName(newTableName)
}
func (c commentBlack) As(alias string) *commentBlack {
c.commentBlackDo.DO = *(c.commentBlackDo.As(alias).(*gen.DO))
return c.updateTableName(alias)
}
func (c *commentBlack) updateTableName(table string) *commentBlack {
c.ALL = field.NewAsterisk(table)
c.ID = field.NewInt64(table, "id")
c.CreateTime = field.NewTime(table, "create_time")
c.UpdateTime = field.NewTime(table, "update_time")
c.BanTime = field.NewTime(table, "ban_time")
c.IPAddress = field.NewString(table, "ip_address")
c.fillFieldMap()
return c
}
func (c *commentBlack) WithContext(ctx context.Context) *commentBlackDo {
return c.commentBlackDo.WithContext(ctx)
}
func (c commentBlack) TableName() string { return c.commentBlackDo.TableName() }
func (c commentBlack) Alias() string { return c.commentBlackDo.Alias() }
func (c *commentBlack) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := c.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (c *commentBlack) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 5)
c.fieldMap["id"] = c.ID
c.fieldMap["create_time"] = c.CreateTime
c.fieldMap["update_time"] = c.UpdateTime
c.fieldMap["ban_time"] = c.BanTime
c.fieldMap["ip_address"] = c.IPAddress
}
func (c commentBlack) clone(db *gorm.DB) commentBlack {
c.commentBlackDo.ReplaceDB(db)
return c
}
type commentBlackDo struct{ gen.DO }
func (c commentBlackDo) Debug() *commentBlackDo {
return c.withDO(c.DO.Debug())
}
func (c commentBlackDo) WithContext(ctx context.Context) *commentBlackDo {
return c.withDO(c.DO.WithContext(ctx))
}
func (c commentBlackDo) ReadDB() *commentBlackDo {
return c.Clauses(dbresolver.Read)
}
func (c commentBlackDo) WriteDB() *commentBlackDo {
return c.Clauses(dbresolver.Write)
}
func (c commentBlackDo) Clauses(conds ...clause.Expression) *commentBlackDo {
return c.withDO(c.DO.Clauses(conds...))
}
func (c commentBlackDo) Returning(value interface{}, columns ...string) *commentBlackDo {
return c.withDO(c.DO.Returning(value, columns...))
}
func (c commentBlackDo) Not(conds ...gen.Condition) *commentBlackDo {
return c.withDO(c.DO.Not(conds...))
}
func (c commentBlackDo) Or(conds ...gen.Condition) *commentBlackDo {
return c.withDO(c.DO.Or(conds...))
}
func (c commentBlackDo) Select(conds ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.Select(conds...))
}
func (c commentBlackDo) Where(conds ...gen.Condition) *commentBlackDo {
return c.withDO(c.DO.Where(conds...))
}
func (c commentBlackDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *commentBlackDo {
return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (c commentBlackDo) Order(conds ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.Order(conds...))
}
func (c commentBlackDo) Distinct(cols ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.Distinct(cols...))
}
func (c commentBlackDo) Omit(cols ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.Omit(cols...))
}
func (c commentBlackDo) Join(table schema.Tabler, on ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.Join(table, on...))
}
func (c commentBlackDo) LeftJoin(table schema.Tabler, on ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.LeftJoin(table, on...))
}
func (c commentBlackDo) RightJoin(table schema.Tabler, on ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.RightJoin(table, on...))
}
func (c commentBlackDo) Group(cols ...field.Expr) *commentBlackDo {
return c.withDO(c.DO.Group(cols...))
}
func (c commentBlackDo) Having(conds ...gen.Condition) *commentBlackDo {
return c.withDO(c.DO.Having(conds...))
}
func (c commentBlackDo) Limit(limit int) *commentBlackDo {
return c.withDO(c.DO.Limit(limit))
}
func (c commentBlackDo) Offset(offset int) *commentBlackDo {
return c.withDO(c.DO.Offset(offset))
}
func (c commentBlackDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *commentBlackDo {
return c.withDO(c.DO.Scopes(funcs...))
}
func (c commentBlackDo) Unscoped() *commentBlackDo {
return c.withDO(c.DO.Unscoped())
}
func (c commentBlackDo) Create(values ...*entity.CommentBlack) error {
if len(values) == 0 {
return nil
}
return c.DO.Create(values)
}
func (c commentBlackDo) CreateInBatches(values []*entity.CommentBlack, batchSize int) error {
return c.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (c commentBlackDo) Save(values ...*entity.CommentBlack) error {
if len(values) == 0 {
return nil
}
return c.DO.Save(values)
}
func (c commentBlackDo) First() (*entity.CommentBlack, error) {
if result, err := c.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.CommentBlack), nil
}
}
func (c commentBlackDo) Take() (*entity.CommentBlack, error) {
if result, err := c.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.CommentBlack), nil
}
}
func (c commentBlackDo) Last() (*entity.CommentBlack, error) {
if result, err := c.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.CommentBlack), nil
}
}
func (c commentBlackDo) Find() ([]*entity.CommentBlack, error) {
result, err := c.DO.Find()
return result.([]*entity.CommentBlack), err
}
func (c commentBlackDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.CommentBlack, err error) {
buf := make([]*entity.CommentBlack, 0, batchSize)
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (c commentBlackDo) FindInBatches(result *[]*entity.CommentBlack, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return c.DO.FindInBatches(result, batchSize, fc)
}
func (c commentBlackDo) Attrs(attrs ...field.AssignExpr) *commentBlackDo {
return c.withDO(c.DO.Attrs(attrs...))
}
func (c commentBlackDo) Assign(attrs ...field.AssignExpr) *commentBlackDo {
return c.withDO(c.DO.Assign(attrs...))
}
func (c commentBlackDo) Joins(fields ...field.RelationField) *commentBlackDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Joins(_f))
}
return &c
}
func (c commentBlackDo) Preload(fields ...field.RelationField) *commentBlackDo {
for _, _f := range fields {
c = *c.withDO(c.DO.Preload(_f))
}
return &c
}
func (c commentBlackDo) FirstOrInit() (*entity.CommentBlack, error) {
if result, err := c.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.CommentBlack), nil
}
}
func (c commentBlackDo) FirstOrCreate() (*entity.CommentBlack, error) {
if result, err := c.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.CommentBlack), nil
}
}
func (c commentBlackDo) FindByPage(offset int, limit int) (result []*entity.CommentBlack, count int64, err error) {
result, err = c.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = c.Offset(-1).Limit(-1).Count()
return
}
func (c commentBlackDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = c.Count()
if err != nil {
return
}
err = c.Offset(offset).Limit(limit).Scan(result)
return
}
func (c commentBlackDo) Scan(result interface{}) (err error) {
return c.DO.Scan(result)
}
func (c commentBlackDo) Delete(models ...*entity.CommentBlack) (result gen.ResultInfo, err error) {
return c.DO.Delete(models)
}
func (c *commentBlackDo) withDO(do gen.Dao) *commentBlackDo {
c.DO = *do.(*gen.DO)
return c
}

@ -0,0 +1,131 @@
package dal
import (
"context"
"fmt"
"time"
"go.uber.org/zap"
"gorm.io/driver/mysql"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"github.com/go-sonic/sonic/config"
"github.com/go-sonic/sonic/consts"
sonicLog "github.com/go-sonic/sonic/log"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/util/xerr"
)
// mysqlDsn example user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
const mysqlDsn = "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=3s&readTimeout=1s&writeTimeout=1s&interpolateParams=true"
var (
DB *gorm.DB
DBType consts.DBType
)
func NewGormDB(conf *config.Config, gormLogger logger.Interface) *gorm.DB {
var err error
if conf.SQLite3 != nil && conf.SQLite3.Enable {
DB, err = initSQLite(conf, gormLogger)
if err != nil {
sonicLog.Fatal("open SQLite3 error", zap.Error(err))
}
DBType = consts.DBTypeSQLite
} else if conf.MySQL != nil {
DB, err = initMySQL(conf, gormLogger)
if err != nil {
sonicLog.Fatal("connect to MySQL error", zap.Error(err))
}
DBType = consts.DBTypeMySQL
} else {
sonicLog.Fatal("No database available")
}
if DB == nil {
sonicLog.Fatal("no available database")
}
sonicLog.Info("connect database success")
sqlDB, err := DB.DB()
if err != nil {
sonicLog.Fatal("get database connection error")
}
sqlDB.SetMaxIdleConns(200)
sqlDB.SetMaxOpenConns(300)
sqlDB.SetConnMaxIdleTime(time.Hour)
dbMigrate()
return DB
}
func initMySQL(conf *config.Config, gormLogger logger.Interface) (*gorm.DB, error) {
mysqlConfig := conf.MySQL
if mysqlConfig == nil {
return nil, xerr.WithMsg(nil, "nil MySQL config")
}
dsn := fmt.Sprintf(mysqlDsn, mysqlConfig.Username, mysqlConfig.Password, mysqlConfig.Host, mysqlConfig.Port, mysqlConfig.DB)
sonicLog.Info("try connect to MySQL", zap.String("dsn", fmt.Sprintf(mysqlDsn, mysqlConfig.Username, "***", mysqlConfig.Host, mysqlConfig.Port, mysqlConfig.DB)))
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: gormLogger,
PrepareStmt: true,
SkipDefaultTransaction: true,
DisableNestedTransaction: true,
})
return db, err
}
func initSQLite(conf *config.Config, gormLogger logger.Interface) (*gorm.DB, error) {
sqliteConfig := conf.SQLite3
if sqliteConfig == nil {
return nil, xerr.WithMsg(nil, "nil SQLite config")
}
sonicLog.Info("try to open SQLite3 db", zap.String("path", sqliteConfig.File))
db, err := gorm.Open(sqlite.Open(sqliteConfig.File), &gorm.Config{
Logger: gormLogger,
PrepareStmt: true,
SkipDefaultTransaction: true,
DisableNestedTransaction: true,
})
return db, err
}
func dbMigrate() {
db := DB.Session(&gorm.Session{
Logger: DB.Logger.LogMode(logger.Warn),
})
err := db.AutoMigrate(&entity.Attachment{}, &entity.Category{}, &entity.Comment{}, &entity.CommentBlack{}, &entity.Journal{},
&entity.Link{}, &entity.Log{}, &entity.Menu{}, &entity.Meta{}, &entity.Option{}, &entity.Photo{}, &entity.Post{},
&entity.PostCategory{}, &entity.PostTag{}, &entity.Tag{}, &entity.ThemeSetting{}, &entity.User{})
if err != nil {
sonicLog.Fatal("failed auto migrate db", zap.Error(err))
}
}
type ctxTransaction struct{}
func GetDBByCtx(ctx context.Context) *gorm.DB {
dbI := ctx.Value(ctxTransaction{})
if dbI != nil {
db, ok := dbI.(*gorm.DB)
if !ok {
panic("unexpected context db value type")
}
if db != nil {
return db
}
}
return DB.WithContext(ctx)
}
func SetCtxDB(ctx context.Context, tx *gorm.DB) context.Context {
return context.WithValue(ctx, ctxTransaction{}, tx)
}
func Transaction(ctx context.Context, fn func(txCtx context.Context) error) error {
db := GetDBByCtx(ctx)
return db.Transaction(func(tx *gorm.DB) error {
txCtx := SetCtxDB(ctx, tx)
return fn(txCtx)
})
}

@ -0,0 +1,356 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newFlywaySchemaHistory(db *gorm.DB) flywaySchemaHistory {
_flywaySchemaHistory := flywaySchemaHistory{}
_flywaySchemaHistory.flywaySchemaHistoryDo.UseDB(db)
_flywaySchemaHistory.flywaySchemaHistoryDo.UseModel(&entity.FlywaySchemaHistory{})
tableName := _flywaySchemaHistory.flywaySchemaHistoryDo.TableName()
_flywaySchemaHistory.ALL = field.NewAsterisk(tableName)
_flywaySchemaHistory.InstalledRank = field.NewInt32(tableName, "installed_rank")
_flywaySchemaHistory.Version = field.NewString(tableName, "version")
_flywaySchemaHistory.Description = field.NewString(tableName, "description")
_flywaySchemaHistory.Type = field.NewString(tableName, "type")
_flywaySchemaHistory.Script = field.NewString(tableName, "script")
_flywaySchemaHistory.Checksum = field.NewInt32(tableName, "checksum")
_flywaySchemaHistory.InstalledBy = field.NewString(tableName, "installed_by")
_flywaySchemaHistory.InstalledOn = field.NewTime(tableName, "installed_on")
_flywaySchemaHistory.ExecutionTime = field.NewInt32(tableName, "execution_time")
_flywaySchemaHistory.Success = field.NewBool(tableName, "success")
_flywaySchemaHistory.fillFieldMap()
return _flywaySchemaHistory
}
type flywaySchemaHistory struct {
flywaySchemaHistoryDo flywaySchemaHistoryDo
ALL field.Asterisk
InstalledRank field.Int32
Version field.String
Description field.String
Type field.String
Script field.String
Checksum field.Int32
InstalledBy field.String
InstalledOn field.Time
ExecutionTime field.Int32
Success field.Bool
fieldMap map[string]field.Expr
}
func (f flywaySchemaHistory) Table(newTableName string) *flywaySchemaHistory {
f.flywaySchemaHistoryDo.UseTable(newTableName)
return f.updateTableName(newTableName)
}
func (f flywaySchemaHistory) As(alias string) *flywaySchemaHistory {
f.flywaySchemaHistoryDo.DO = *(f.flywaySchemaHistoryDo.As(alias).(*gen.DO))
return f.updateTableName(alias)
}
func (f *flywaySchemaHistory) updateTableName(table string) *flywaySchemaHistory {
f.ALL = field.NewAsterisk(table)
f.InstalledRank = field.NewInt32(table, "installed_rank")
f.Version = field.NewString(table, "version")
f.Description = field.NewString(table, "description")
f.Type = field.NewString(table, "type")
f.Script = field.NewString(table, "script")
f.Checksum = field.NewInt32(table, "checksum")
f.InstalledBy = field.NewString(table, "installed_by")
f.InstalledOn = field.NewTime(table, "installed_on")
f.ExecutionTime = field.NewInt32(table, "execution_time")
f.Success = field.NewBool(table, "success")
f.fillFieldMap()
return f
}
func (f *flywaySchemaHistory) WithContext(ctx context.Context) *flywaySchemaHistoryDo {
return f.flywaySchemaHistoryDo.WithContext(ctx)
}
func (f flywaySchemaHistory) TableName() string { return f.flywaySchemaHistoryDo.TableName() }
func (f flywaySchemaHistory) Alias() string { return f.flywaySchemaHistoryDo.Alias() }
func (f *flywaySchemaHistory) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := f.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (f *flywaySchemaHistory) fillFieldMap() {
f.fieldMap = make(map[string]field.Expr, 10)
f.fieldMap["installed_rank"] = f.InstalledRank
f.fieldMap["version"] = f.Version
f.fieldMap["description"] = f.Description
f.fieldMap["type"] = f.Type
f.fieldMap["script"] = f.Script
f.fieldMap["checksum"] = f.Checksum
f.fieldMap["installed_by"] = f.InstalledBy
f.fieldMap["installed_on"] = f.InstalledOn
f.fieldMap["execution_time"] = f.ExecutionTime
f.fieldMap["success"] = f.Success
}
func (f flywaySchemaHistory) clone(db *gorm.DB) flywaySchemaHistory {
f.flywaySchemaHistoryDo.ReplaceDB(db)
return f
}
type flywaySchemaHistoryDo struct{ gen.DO }
func (f flywaySchemaHistoryDo) Debug() *flywaySchemaHistoryDo {
return f.withDO(f.DO.Debug())
}
func (f flywaySchemaHistoryDo) WithContext(ctx context.Context) *flywaySchemaHistoryDo {
return f.withDO(f.DO.WithContext(ctx))
}
func (f flywaySchemaHistoryDo) ReadDB() *flywaySchemaHistoryDo {
return f.Clauses(dbresolver.Read)
}
func (f flywaySchemaHistoryDo) WriteDB() *flywaySchemaHistoryDo {
return f.Clauses(dbresolver.Write)
}
func (f flywaySchemaHistoryDo) Clauses(conds ...clause.Expression) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Clauses(conds...))
}
func (f flywaySchemaHistoryDo) Returning(value interface{}, columns ...string) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Returning(value, columns...))
}
func (f flywaySchemaHistoryDo) Not(conds ...gen.Condition) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Not(conds...))
}
func (f flywaySchemaHistoryDo) Or(conds ...gen.Condition) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Or(conds...))
}
func (f flywaySchemaHistoryDo) Select(conds ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Select(conds...))
}
func (f flywaySchemaHistoryDo) Where(conds ...gen.Condition) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Where(conds...))
}
func (f flywaySchemaHistoryDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *flywaySchemaHistoryDo {
return f.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (f flywaySchemaHistoryDo) Order(conds ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Order(conds...))
}
func (f flywaySchemaHistoryDo) Distinct(cols ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Distinct(cols...))
}
func (f flywaySchemaHistoryDo) Omit(cols ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Omit(cols...))
}
func (f flywaySchemaHistoryDo) Join(table schema.Tabler, on ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Join(table, on...))
}
func (f flywaySchemaHistoryDo) LeftJoin(table schema.Tabler, on ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.LeftJoin(table, on...))
}
func (f flywaySchemaHistoryDo) RightJoin(table schema.Tabler, on ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.RightJoin(table, on...))
}
func (f flywaySchemaHistoryDo) Group(cols ...field.Expr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Group(cols...))
}
func (f flywaySchemaHistoryDo) Having(conds ...gen.Condition) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Having(conds...))
}
func (f flywaySchemaHistoryDo) Limit(limit int) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Limit(limit))
}
func (f flywaySchemaHistoryDo) Offset(offset int) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Offset(offset))
}
func (f flywaySchemaHistoryDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Scopes(funcs...))
}
func (f flywaySchemaHistoryDo) Unscoped() *flywaySchemaHistoryDo {
return f.withDO(f.DO.Unscoped())
}
func (f flywaySchemaHistoryDo) Create(values ...*entity.FlywaySchemaHistory) error {
if len(values) == 0 {
return nil
}
return f.DO.Create(values)
}
func (f flywaySchemaHistoryDo) CreateInBatches(values []*entity.FlywaySchemaHistory, batchSize int) error {
return f.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (f flywaySchemaHistoryDo) Save(values ...*entity.FlywaySchemaHistory) error {
if len(values) == 0 {
return nil
}
return f.DO.Save(values)
}
func (f flywaySchemaHistoryDo) First() (*entity.FlywaySchemaHistory, error) {
if result, err := f.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.FlywaySchemaHistory), nil
}
}
func (f flywaySchemaHistoryDo) Take() (*entity.FlywaySchemaHistory, error) {
if result, err := f.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.FlywaySchemaHistory), nil
}
}
func (f flywaySchemaHistoryDo) Last() (*entity.FlywaySchemaHistory, error) {
if result, err := f.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.FlywaySchemaHistory), nil
}
}
func (f flywaySchemaHistoryDo) Find() ([]*entity.FlywaySchemaHistory, error) {
result, err := f.DO.Find()
return result.([]*entity.FlywaySchemaHistory), err
}
func (f flywaySchemaHistoryDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.FlywaySchemaHistory, err error) {
buf := make([]*entity.FlywaySchemaHistory, 0, batchSize)
err = f.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (f flywaySchemaHistoryDo) FindInBatches(result *[]*entity.FlywaySchemaHistory, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return f.DO.FindInBatches(result, batchSize, fc)
}
func (f flywaySchemaHistoryDo) Attrs(attrs ...field.AssignExpr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Attrs(attrs...))
}
func (f flywaySchemaHistoryDo) Assign(attrs ...field.AssignExpr) *flywaySchemaHistoryDo {
return f.withDO(f.DO.Assign(attrs...))
}
func (f flywaySchemaHistoryDo) Joins(fields ...field.RelationField) *flywaySchemaHistoryDo {
for _, _f := range fields {
f = *f.withDO(f.DO.Joins(_f))
}
return &f
}
func (f flywaySchemaHistoryDo) Preload(fields ...field.RelationField) *flywaySchemaHistoryDo {
for _, _f := range fields {
f = *f.withDO(f.DO.Preload(_f))
}
return &f
}
func (f flywaySchemaHistoryDo) FirstOrInit() (*entity.FlywaySchemaHistory, error) {
if result, err := f.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.FlywaySchemaHistory), nil
}
}
func (f flywaySchemaHistoryDo) FirstOrCreate() (*entity.FlywaySchemaHistory, error) {
if result, err := f.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.FlywaySchemaHistory), nil
}
}
func (f flywaySchemaHistoryDo) FindByPage(offset int, limit int) (result []*entity.FlywaySchemaHistory, count int64, err error) {
result, err = f.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = f.Offset(-1).Limit(-1).Count()
return
}
func (f flywaySchemaHistoryDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = f.Count()
if err != nil {
return
}
err = f.Offset(offset).Limit(limit).Scan(result)
return
}
func (f flywaySchemaHistoryDo) Scan(result interface{}) (err error) {
return f.DO.Scan(result)
}
func (f flywaySchemaHistoryDo) Delete(models ...*entity.FlywaySchemaHistory) (result gen.ResultInfo, err error) {
return f.DO.Delete(models)
}
func (f *flywaySchemaHistoryDo) withDO(do gen.Dao) *flywaySchemaHistoryDo {
f.DO = *do.(*gen.DO)
return f
}

@ -0,0 +1,199 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"database/sql"
"gorm.io/gorm"
)
var (
Q = new(Query)
Attachment *attachment
Category *category
Comment *comment
CommentBlack *commentBlack
FlywaySchemaHistory *flywaySchemaHistory
Journal *journal
Link *link
Log *log
Menu *menu
Meta *meta
Option *option
Photo *photo
Post *post
PostCategory *postCategory
PostTag *postTag
Tag *tag
ThemeSetting *themeSetting
User *user
)
func SetDefault(db *gorm.DB) {
*Q = *Use(db)
Attachment = &Q.Attachment
Category = &Q.Category
Comment = &Q.Comment
CommentBlack = &Q.CommentBlack
FlywaySchemaHistory = &Q.FlywaySchemaHistory
Journal = &Q.Journal
Link = &Q.Link
Log = &Q.Log
Menu = &Q.Menu
Meta = &Q.Meta
Option = &Q.Option
Photo = &Q.Photo
Post = &Q.Post
PostCategory = &Q.PostCategory
PostTag = &Q.PostTag
Tag = &Q.Tag
ThemeSetting = &Q.ThemeSetting
User = &Q.User
}
func Use(db *gorm.DB) *Query {
return &Query{
db: db,
Attachment: newAttachment(db),
Category: newCategory(db),
Comment: newComment(db),
CommentBlack: newCommentBlack(db),
FlywaySchemaHistory: newFlywaySchemaHistory(db),
Journal: newJournal(db),
Link: newLink(db),
Log: newLog(db),
Menu: newMenu(db),
Meta: newMeta(db),
Option: newOption(db),
Photo: newPhoto(db),
Post: newPost(db),
PostCategory: newPostCategory(db),
PostTag: newPostTag(db),
Tag: newTag(db),
ThemeSetting: newThemeSetting(db),
User: newUser(db),
}
}
type Query struct {
db *gorm.DB
Attachment attachment
Category category
Comment comment
CommentBlack commentBlack
FlywaySchemaHistory flywaySchemaHistory
Journal journal
Link link
Log log
Menu menu
Meta meta
Option option
Photo photo
Post post
PostCategory postCategory
PostTag postTag
Tag tag
ThemeSetting themeSetting
User user
}
func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query {
return &Query{
db: db,
Attachment: q.Attachment.clone(db),
Category: q.Category.clone(db),
Comment: q.Comment.clone(db),
CommentBlack: q.CommentBlack.clone(db),
FlywaySchemaHistory: q.FlywaySchemaHistory.clone(db),
Journal: q.Journal.clone(db),
Link: q.Link.clone(db),
Log: q.Log.clone(db),
Menu: q.Menu.clone(db),
Meta: q.Meta.clone(db),
Option: q.Option.clone(db),
Photo: q.Photo.clone(db),
Post: q.Post.clone(db),
PostCategory: q.PostCategory.clone(db),
PostTag: q.PostTag.clone(db),
Tag: q.Tag.clone(db),
ThemeSetting: q.ThemeSetting.clone(db),
User: q.User.clone(db),
}
}
type queryCtx struct {
Attachment *attachmentDo
Category *categoryDo
Comment *commentDo
CommentBlack *commentBlackDo
FlywaySchemaHistory *flywaySchemaHistoryDo
Journal *journalDo
Link *linkDo
Log *logDo
Menu *menuDo
Meta *metaDo
Option *optionDo
Photo *photoDo
Post *postDo
PostCategory *postCategoryDo
PostTag *postTagDo
Tag *tagDo
ThemeSetting *themeSettingDo
User *userDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{
Attachment: q.Attachment.WithContext(ctx),
Category: q.Category.WithContext(ctx),
Comment: q.Comment.WithContext(ctx),
CommentBlack: q.CommentBlack.WithContext(ctx),
FlywaySchemaHistory: q.FlywaySchemaHistory.WithContext(ctx),
Journal: q.Journal.WithContext(ctx),
Link: q.Link.WithContext(ctx),
Log: q.Log.WithContext(ctx),
Menu: q.Menu.WithContext(ctx),
Meta: q.Meta.WithContext(ctx),
Option: q.Option.WithContext(ctx),
Photo: q.Photo.WithContext(ctx),
Post: q.Post.WithContext(ctx),
PostCategory: q.PostCategory.WithContext(ctx),
PostTag: q.PostTag.WithContext(ctx),
Tag: q.Tag.WithContext(ctx),
ThemeSetting: q.ThemeSetting.WithContext(ctx),
User: q.User.WithContext(ctx),
}
}
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
return &QueryTx{q.clone(q.db.Begin(opts...))}
}
type QueryTx struct{ *Query }
func (q *QueryTx) Commit() error {
return q.db.Commit().Error
}
func (q *QueryTx) Rollback() error {
return q.db.Rollback().Error
}
func (q *QueryTx) SavePoint(name string) error {
return q.db.SavePoint(name).Error
}
func (q *QueryTx) RollbackTo(name string) error {
return q.db.RollbackTo(name).Error
}

@ -0,0 +1,342 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newJournal(db *gorm.DB) journal {
_journal := journal{}
_journal.journalDo.UseDB(db)
_journal.journalDo.UseModel(&entity.Journal{})
tableName := _journal.journalDo.TableName()
_journal.ALL = field.NewAsterisk(tableName)
_journal.ID = field.NewInt32(tableName, "id")
_journal.CreateTime = field.NewTime(tableName, "create_time")
_journal.UpdateTime = field.NewTime(tableName, "update_time")
_journal.Content = field.NewString(tableName, "content")
_journal.Likes = field.NewInt64(tableName, "likes")
_journal.SourceContent = field.NewString(tableName, "source_content")
_journal.Type = field.NewField(tableName, "type")
_journal.fillFieldMap()
return _journal
}
type journal struct {
journalDo journalDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Content field.String
Likes field.Int64
SourceContent field.String
Type field.Field
fieldMap map[string]field.Expr
}
func (j journal) Table(newTableName string) *journal {
j.journalDo.UseTable(newTableName)
return j.updateTableName(newTableName)
}
func (j journal) As(alias string) *journal {
j.journalDo.DO = *(j.journalDo.As(alias).(*gen.DO))
return j.updateTableName(alias)
}
func (j *journal) updateTableName(table string) *journal {
j.ALL = field.NewAsterisk(table)
j.ID = field.NewInt32(table, "id")
j.CreateTime = field.NewTime(table, "create_time")
j.UpdateTime = field.NewTime(table, "update_time")
j.Content = field.NewString(table, "content")
j.Likes = field.NewInt64(table, "likes")
j.SourceContent = field.NewString(table, "source_content")
j.Type = field.NewField(table, "type")
j.fillFieldMap()
return j
}
func (j *journal) WithContext(ctx context.Context) *journalDo { return j.journalDo.WithContext(ctx) }
func (j journal) TableName() string { return j.journalDo.TableName() }
func (j journal) Alias() string { return j.journalDo.Alias() }
func (j *journal) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := j.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (j *journal) fillFieldMap() {
j.fieldMap = make(map[string]field.Expr, 7)
j.fieldMap["id"] = j.ID
j.fieldMap["create_time"] = j.CreateTime
j.fieldMap["update_time"] = j.UpdateTime
j.fieldMap["content"] = j.Content
j.fieldMap["likes"] = j.Likes
j.fieldMap["source_content"] = j.SourceContent
j.fieldMap["type"] = j.Type
}
func (j journal) clone(db *gorm.DB) journal {
j.journalDo.ReplaceDB(db)
return j
}
type journalDo struct{ gen.DO }
func (j journalDo) Debug() *journalDo {
return j.withDO(j.DO.Debug())
}
func (j journalDo) WithContext(ctx context.Context) *journalDo {
return j.withDO(j.DO.WithContext(ctx))
}
func (j journalDo) ReadDB() *journalDo {
return j.Clauses(dbresolver.Read)
}
func (j journalDo) WriteDB() *journalDo {
return j.Clauses(dbresolver.Write)
}
func (j journalDo) Clauses(conds ...clause.Expression) *journalDo {
return j.withDO(j.DO.Clauses(conds...))
}
func (j journalDo) Returning(value interface{}, columns ...string) *journalDo {
return j.withDO(j.DO.Returning(value, columns...))
}
func (j journalDo) Not(conds ...gen.Condition) *journalDo {
return j.withDO(j.DO.Not(conds...))
}
func (j journalDo) Or(conds ...gen.Condition) *journalDo {
return j.withDO(j.DO.Or(conds...))
}
func (j journalDo) Select(conds ...field.Expr) *journalDo {
return j.withDO(j.DO.Select(conds...))
}
func (j journalDo) Where(conds ...gen.Condition) *journalDo {
return j.withDO(j.DO.Where(conds...))
}
func (j journalDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *journalDo {
return j.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (j journalDo) Order(conds ...field.Expr) *journalDo {
return j.withDO(j.DO.Order(conds...))
}
func (j journalDo) Distinct(cols ...field.Expr) *journalDo {
return j.withDO(j.DO.Distinct(cols...))
}
func (j journalDo) Omit(cols ...field.Expr) *journalDo {
return j.withDO(j.DO.Omit(cols...))
}
func (j journalDo) Join(table schema.Tabler, on ...field.Expr) *journalDo {
return j.withDO(j.DO.Join(table, on...))
}
func (j journalDo) LeftJoin(table schema.Tabler, on ...field.Expr) *journalDo {
return j.withDO(j.DO.LeftJoin(table, on...))
}
func (j journalDo) RightJoin(table schema.Tabler, on ...field.Expr) *journalDo {
return j.withDO(j.DO.RightJoin(table, on...))
}
func (j journalDo) Group(cols ...field.Expr) *journalDo {
return j.withDO(j.DO.Group(cols...))
}
func (j journalDo) Having(conds ...gen.Condition) *journalDo {
return j.withDO(j.DO.Having(conds...))
}
func (j journalDo) Limit(limit int) *journalDo {
return j.withDO(j.DO.Limit(limit))
}
func (j journalDo) Offset(offset int) *journalDo {
return j.withDO(j.DO.Offset(offset))
}
func (j journalDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *journalDo {
return j.withDO(j.DO.Scopes(funcs...))
}
func (j journalDo) Unscoped() *journalDo {
return j.withDO(j.DO.Unscoped())
}
func (j journalDo) Create(values ...*entity.Journal) error {
if len(values) == 0 {
return nil
}
return j.DO.Create(values)
}
func (j journalDo) CreateInBatches(values []*entity.Journal, batchSize int) error {
return j.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (j journalDo) Save(values ...*entity.Journal) error {
if len(values) == 0 {
return nil
}
return j.DO.Save(values)
}
func (j journalDo) First() (*entity.Journal, error) {
if result, err := j.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Journal), nil
}
}
func (j journalDo) Take() (*entity.Journal, error) {
if result, err := j.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Journal), nil
}
}
func (j journalDo) Last() (*entity.Journal, error) {
if result, err := j.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Journal), nil
}
}
func (j journalDo) Find() ([]*entity.Journal, error) {
result, err := j.DO.Find()
return result.([]*entity.Journal), err
}
func (j journalDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Journal, err error) {
buf := make([]*entity.Journal, 0, batchSize)
err = j.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (j journalDo) FindInBatches(result *[]*entity.Journal, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return j.DO.FindInBatches(result, batchSize, fc)
}
func (j journalDo) Attrs(attrs ...field.AssignExpr) *journalDo {
return j.withDO(j.DO.Attrs(attrs...))
}
func (j journalDo) Assign(attrs ...field.AssignExpr) *journalDo {
return j.withDO(j.DO.Assign(attrs...))
}
func (j journalDo) Joins(fields ...field.RelationField) *journalDo {
for _, _f := range fields {
j = *j.withDO(j.DO.Joins(_f))
}
return &j
}
func (j journalDo) Preload(fields ...field.RelationField) *journalDo {
for _, _f := range fields {
j = *j.withDO(j.DO.Preload(_f))
}
return &j
}
func (j journalDo) FirstOrInit() (*entity.Journal, error) {
if result, err := j.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Journal), nil
}
}
func (j journalDo) FirstOrCreate() (*entity.Journal, error) {
if result, err := j.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Journal), nil
}
}
func (j journalDo) FindByPage(offset int, limit int) (result []*entity.Journal, count int64, err error) {
result, err = j.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = j.Offset(-1).Limit(-1).Count()
return
}
func (j journalDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = j.Count()
if err != nil {
return
}
err = j.Offset(offset).Limit(limit).Scan(result)
return
}
func (j journalDo) Scan(result interface{}) (err error) {
return j.DO.Scan(result)
}
func (j journalDo) Delete(models ...*entity.Journal) (result gen.ResultInfo, err error) {
return j.DO.Delete(models)
}
func (j *journalDo) withDO(do gen.Dao) *journalDo {
j.DO = *do.(*gen.DO)
return j
}

@ -0,0 +1,350 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newLink(db *gorm.DB) link {
_link := link{}
_link.linkDo.UseDB(db)
_link.linkDo.UseModel(&entity.Link{})
tableName := _link.linkDo.TableName()
_link.ALL = field.NewAsterisk(tableName)
_link.ID = field.NewInt32(tableName, "id")
_link.CreateTime = field.NewTime(tableName, "create_time")
_link.UpdateTime = field.NewTime(tableName, "update_time")
_link.Description = field.NewString(tableName, "description")
_link.Logo = field.NewString(tableName, "logo")
_link.Name = field.NewString(tableName, "name")
_link.Priority = field.NewInt32(tableName, "priority")
_link.Team = field.NewString(tableName, "team")
_link.URL = field.NewString(tableName, "url")
_link.fillFieldMap()
return _link
}
type link struct {
linkDo linkDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Description field.String
Logo field.String
Name field.String
Priority field.Int32
Team field.String
URL field.String
fieldMap map[string]field.Expr
}
func (l link) Table(newTableName string) *link {
l.linkDo.UseTable(newTableName)
return l.updateTableName(newTableName)
}
func (l link) As(alias string) *link {
l.linkDo.DO = *(l.linkDo.As(alias).(*gen.DO))
return l.updateTableName(alias)
}
func (l *link) updateTableName(table string) *link {
l.ALL = field.NewAsterisk(table)
l.ID = field.NewInt32(table, "id")
l.CreateTime = field.NewTime(table, "create_time")
l.UpdateTime = field.NewTime(table, "update_time")
l.Description = field.NewString(table, "description")
l.Logo = field.NewString(table, "logo")
l.Name = field.NewString(table, "name")
l.Priority = field.NewInt32(table, "priority")
l.Team = field.NewString(table, "team")
l.URL = field.NewString(table, "url")
l.fillFieldMap()
return l
}
func (l *link) WithContext(ctx context.Context) *linkDo { return l.linkDo.WithContext(ctx) }
func (l link) TableName() string { return l.linkDo.TableName() }
func (l link) Alias() string { return l.linkDo.Alias() }
func (l *link) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := l.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (l *link) fillFieldMap() {
l.fieldMap = make(map[string]field.Expr, 9)
l.fieldMap["id"] = l.ID
l.fieldMap["create_time"] = l.CreateTime
l.fieldMap["update_time"] = l.UpdateTime
l.fieldMap["description"] = l.Description
l.fieldMap["logo"] = l.Logo
l.fieldMap["name"] = l.Name
l.fieldMap["priority"] = l.Priority
l.fieldMap["team"] = l.Team
l.fieldMap["url"] = l.URL
}
func (l link) clone(db *gorm.DB) link {
l.linkDo.ReplaceDB(db)
return l
}
type linkDo struct{ gen.DO }
func (l linkDo) Debug() *linkDo {
return l.withDO(l.DO.Debug())
}
func (l linkDo) WithContext(ctx context.Context) *linkDo {
return l.withDO(l.DO.WithContext(ctx))
}
func (l linkDo) ReadDB() *linkDo {
return l.Clauses(dbresolver.Read)
}
func (l linkDo) WriteDB() *linkDo {
return l.Clauses(dbresolver.Write)
}
func (l linkDo) Clauses(conds ...clause.Expression) *linkDo {
return l.withDO(l.DO.Clauses(conds...))
}
func (l linkDo) Returning(value interface{}, columns ...string) *linkDo {
return l.withDO(l.DO.Returning(value, columns...))
}
func (l linkDo) Not(conds ...gen.Condition) *linkDo {
return l.withDO(l.DO.Not(conds...))
}
func (l linkDo) Or(conds ...gen.Condition) *linkDo {
return l.withDO(l.DO.Or(conds...))
}
func (l linkDo) Select(conds ...field.Expr) *linkDo {
return l.withDO(l.DO.Select(conds...))
}
func (l linkDo) Where(conds ...gen.Condition) *linkDo {
return l.withDO(l.DO.Where(conds...))
}
func (l linkDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *linkDo {
return l.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (l linkDo) Order(conds ...field.Expr) *linkDo {
return l.withDO(l.DO.Order(conds...))
}
func (l linkDo) Distinct(cols ...field.Expr) *linkDo {
return l.withDO(l.DO.Distinct(cols...))
}
func (l linkDo) Omit(cols ...field.Expr) *linkDo {
return l.withDO(l.DO.Omit(cols...))
}
func (l linkDo) Join(table schema.Tabler, on ...field.Expr) *linkDo {
return l.withDO(l.DO.Join(table, on...))
}
func (l linkDo) LeftJoin(table schema.Tabler, on ...field.Expr) *linkDo {
return l.withDO(l.DO.LeftJoin(table, on...))
}
func (l linkDo) RightJoin(table schema.Tabler, on ...field.Expr) *linkDo {
return l.withDO(l.DO.RightJoin(table, on...))
}
func (l linkDo) Group(cols ...field.Expr) *linkDo {
return l.withDO(l.DO.Group(cols...))
}
func (l linkDo) Having(conds ...gen.Condition) *linkDo {
return l.withDO(l.DO.Having(conds...))
}
func (l linkDo) Limit(limit int) *linkDo {
return l.withDO(l.DO.Limit(limit))
}
func (l linkDo) Offset(offset int) *linkDo {
return l.withDO(l.DO.Offset(offset))
}
func (l linkDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *linkDo {
return l.withDO(l.DO.Scopes(funcs...))
}
func (l linkDo) Unscoped() *linkDo {
return l.withDO(l.DO.Unscoped())
}
func (l linkDo) Create(values ...*entity.Link) error {
if len(values) == 0 {
return nil
}
return l.DO.Create(values)
}
func (l linkDo) CreateInBatches(values []*entity.Link, batchSize int) error {
return l.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (l linkDo) Save(values ...*entity.Link) error {
if len(values) == 0 {
return nil
}
return l.DO.Save(values)
}
func (l linkDo) First() (*entity.Link, error) {
if result, err := l.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Link), nil
}
}
func (l linkDo) Take() (*entity.Link, error) {
if result, err := l.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Link), nil
}
}
func (l linkDo) Last() (*entity.Link, error) {
if result, err := l.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Link), nil
}
}
func (l linkDo) Find() ([]*entity.Link, error) {
result, err := l.DO.Find()
return result.([]*entity.Link), err
}
func (l linkDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Link, err error) {
buf := make([]*entity.Link, 0, batchSize)
err = l.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (l linkDo) FindInBatches(result *[]*entity.Link, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return l.DO.FindInBatches(result, batchSize, fc)
}
func (l linkDo) Attrs(attrs ...field.AssignExpr) *linkDo {
return l.withDO(l.DO.Attrs(attrs...))
}
func (l linkDo) Assign(attrs ...field.AssignExpr) *linkDo {
return l.withDO(l.DO.Assign(attrs...))
}
func (l linkDo) Joins(fields ...field.RelationField) *linkDo {
for _, _f := range fields {
l = *l.withDO(l.DO.Joins(_f))
}
return &l
}
func (l linkDo) Preload(fields ...field.RelationField) *linkDo {
for _, _f := range fields {
l = *l.withDO(l.DO.Preload(_f))
}
return &l
}
func (l linkDo) FirstOrInit() (*entity.Link, error) {
if result, err := l.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Link), nil
}
}
func (l linkDo) FirstOrCreate() (*entity.Link, error) {
if result, err := l.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Link), nil
}
}
func (l linkDo) FindByPage(offset int, limit int) (result []*entity.Link, count int64, err error) {
result, err = l.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = l.Offset(-1).Limit(-1).Count()
return
}
func (l linkDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = l.Count()
if err != nil {
return
}
err = l.Offset(offset).Limit(limit).Scan(result)
return
}
func (l linkDo) Scan(result interface{}) (err error) {
return l.DO.Scan(result)
}
func (l linkDo) Delete(models ...*entity.Link) (result gen.ResultInfo, err error) {
return l.DO.Delete(models)
}
func (l *linkDo) withDO(do gen.Dao) *linkDo {
l.DO = *do.(*gen.DO)
return l
}

@ -0,0 +1,342 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newLog(db *gorm.DB) log {
_log := log{}
_log.logDo.UseDB(db)
_log.logDo.UseModel(&entity.Log{})
tableName := _log.logDo.TableName()
_log.ALL = field.NewAsterisk(tableName)
_log.ID = field.NewInt64(tableName, "id")
_log.CreateTime = field.NewTime(tableName, "create_time")
_log.UpdateTime = field.NewTime(tableName, "update_time")
_log.Content = field.NewString(tableName, "content")
_log.IPAddress = field.NewString(tableName, "ip_address")
_log.LogKey = field.NewString(tableName, "log_key")
_log.Type = field.NewField(tableName, "type")
_log.fillFieldMap()
return _log
}
type log struct {
logDo logDo
ALL field.Asterisk
ID field.Int64
CreateTime field.Time
UpdateTime field.Time
Content field.String
IPAddress field.String
LogKey field.String
Type field.Field
fieldMap map[string]field.Expr
}
func (l log) Table(newTableName string) *log {
l.logDo.UseTable(newTableName)
return l.updateTableName(newTableName)
}
func (l log) As(alias string) *log {
l.logDo.DO = *(l.logDo.As(alias).(*gen.DO))
return l.updateTableName(alias)
}
func (l *log) updateTableName(table string) *log {
l.ALL = field.NewAsterisk(table)
l.ID = field.NewInt64(table, "id")
l.CreateTime = field.NewTime(table, "create_time")
l.UpdateTime = field.NewTime(table, "update_time")
l.Content = field.NewString(table, "content")
l.IPAddress = field.NewString(table, "ip_address")
l.LogKey = field.NewString(table, "log_key")
l.Type = field.NewField(table, "type")
l.fillFieldMap()
return l
}
func (l *log) WithContext(ctx context.Context) *logDo { return l.logDo.WithContext(ctx) }
func (l log) TableName() string { return l.logDo.TableName() }
func (l log) Alias() string { return l.logDo.Alias() }
func (l *log) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := l.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (l *log) fillFieldMap() {
l.fieldMap = make(map[string]field.Expr, 7)
l.fieldMap["id"] = l.ID
l.fieldMap["create_time"] = l.CreateTime
l.fieldMap["update_time"] = l.UpdateTime
l.fieldMap["content"] = l.Content
l.fieldMap["ip_address"] = l.IPAddress
l.fieldMap["log_key"] = l.LogKey
l.fieldMap["type"] = l.Type
}
func (l log) clone(db *gorm.DB) log {
l.logDo.ReplaceDB(db)
return l
}
type logDo struct{ gen.DO }
func (l logDo) Debug() *logDo {
return l.withDO(l.DO.Debug())
}
func (l logDo) WithContext(ctx context.Context) *logDo {
return l.withDO(l.DO.WithContext(ctx))
}
func (l logDo) ReadDB() *logDo {
return l.Clauses(dbresolver.Read)
}
func (l logDo) WriteDB() *logDo {
return l.Clauses(dbresolver.Write)
}
func (l logDo) Clauses(conds ...clause.Expression) *logDo {
return l.withDO(l.DO.Clauses(conds...))
}
func (l logDo) Returning(value interface{}, columns ...string) *logDo {
return l.withDO(l.DO.Returning(value, columns...))
}
func (l logDo) Not(conds ...gen.Condition) *logDo {
return l.withDO(l.DO.Not(conds...))
}
func (l logDo) Or(conds ...gen.Condition) *logDo {
return l.withDO(l.DO.Or(conds...))
}
func (l logDo) Select(conds ...field.Expr) *logDo {
return l.withDO(l.DO.Select(conds...))
}
func (l logDo) Where(conds ...gen.Condition) *logDo {
return l.withDO(l.DO.Where(conds...))
}
func (l logDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *logDo {
return l.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (l logDo) Order(conds ...field.Expr) *logDo {
return l.withDO(l.DO.Order(conds...))
}
func (l logDo) Distinct(cols ...field.Expr) *logDo {
return l.withDO(l.DO.Distinct(cols...))
}
func (l logDo) Omit(cols ...field.Expr) *logDo {
return l.withDO(l.DO.Omit(cols...))
}
func (l logDo) Join(table schema.Tabler, on ...field.Expr) *logDo {
return l.withDO(l.DO.Join(table, on...))
}
func (l logDo) LeftJoin(table schema.Tabler, on ...field.Expr) *logDo {
return l.withDO(l.DO.LeftJoin(table, on...))
}
func (l logDo) RightJoin(table schema.Tabler, on ...field.Expr) *logDo {
return l.withDO(l.DO.RightJoin(table, on...))
}
func (l logDo) Group(cols ...field.Expr) *logDo {
return l.withDO(l.DO.Group(cols...))
}
func (l logDo) Having(conds ...gen.Condition) *logDo {
return l.withDO(l.DO.Having(conds...))
}
func (l logDo) Limit(limit int) *logDo {
return l.withDO(l.DO.Limit(limit))
}
func (l logDo) Offset(offset int) *logDo {
return l.withDO(l.DO.Offset(offset))
}
func (l logDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *logDo {
return l.withDO(l.DO.Scopes(funcs...))
}
func (l logDo) Unscoped() *logDo {
return l.withDO(l.DO.Unscoped())
}
func (l logDo) Create(values ...*entity.Log) error {
if len(values) == 0 {
return nil
}
return l.DO.Create(values)
}
func (l logDo) CreateInBatches(values []*entity.Log, batchSize int) error {
return l.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (l logDo) Save(values ...*entity.Log) error {
if len(values) == 0 {
return nil
}
return l.DO.Save(values)
}
func (l logDo) First() (*entity.Log, error) {
if result, err := l.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Log), nil
}
}
func (l logDo) Take() (*entity.Log, error) {
if result, err := l.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Log), nil
}
}
func (l logDo) Last() (*entity.Log, error) {
if result, err := l.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Log), nil
}
}
func (l logDo) Find() ([]*entity.Log, error) {
result, err := l.DO.Find()
return result.([]*entity.Log), err
}
func (l logDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Log, err error) {
buf := make([]*entity.Log, 0, batchSize)
err = l.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (l logDo) FindInBatches(result *[]*entity.Log, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return l.DO.FindInBatches(result, batchSize, fc)
}
func (l logDo) Attrs(attrs ...field.AssignExpr) *logDo {
return l.withDO(l.DO.Attrs(attrs...))
}
func (l logDo) Assign(attrs ...field.AssignExpr) *logDo {
return l.withDO(l.DO.Assign(attrs...))
}
func (l logDo) Joins(fields ...field.RelationField) *logDo {
for _, _f := range fields {
l = *l.withDO(l.DO.Joins(_f))
}
return &l
}
func (l logDo) Preload(fields ...field.RelationField) *logDo {
for _, _f := range fields {
l = *l.withDO(l.DO.Preload(_f))
}
return &l
}
func (l logDo) FirstOrInit() (*entity.Log, error) {
if result, err := l.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Log), nil
}
}
func (l logDo) FirstOrCreate() (*entity.Log, error) {
if result, err := l.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Log), nil
}
}
func (l logDo) FindByPage(offset int, limit int) (result []*entity.Log, count int64, err error) {
result, err = l.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = l.Offset(-1).Limit(-1).Count()
return
}
func (l logDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = l.Count()
if err != nil {
return
}
err = l.Offset(offset).Limit(limit).Scan(result)
return
}
func (l logDo) Scan(result interface{}) (err error) {
return l.DO.Scan(result)
}
func (l logDo) Delete(models ...*entity.Log) (result gen.ResultInfo, err error) {
return l.DO.Delete(models)
}
func (l *logDo) withDO(do gen.Dao) *logDo {
l.DO = *do.(*gen.DO)
return l
}

@ -0,0 +1,354 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newMenu(db *gorm.DB) menu {
_menu := menu{}
_menu.menuDo.UseDB(db)
_menu.menuDo.UseModel(&entity.Menu{})
tableName := _menu.menuDo.TableName()
_menu.ALL = field.NewAsterisk(tableName)
_menu.ID = field.NewInt32(tableName, "id")
_menu.CreateTime = field.NewTime(tableName, "create_time")
_menu.UpdateTime = field.NewTime(tableName, "update_time")
_menu.Icon = field.NewString(tableName, "icon")
_menu.Name = field.NewString(tableName, "name")
_menu.ParentID = field.NewInt32(tableName, "parent_id")
_menu.Priority = field.NewInt32(tableName, "priority")
_menu.Target = field.NewString(tableName, "target")
_menu.Team = field.NewString(tableName, "team")
_menu.URL = field.NewString(tableName, "url")
_menu.fillFieldMap()
return _menu
}
type menu struct {
menuDo menuDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Icon field.String
Name field.String
ParentID field.Int32
Priority field.Int32
Target field.String
Team field.String
URL field.String
fieldMap map[string]field.Expr
}
func (m menu) Table(newTableName string) *menu {
m.menuDo.UseTable(newTableName)
return m.updateTableName(newTableName)
}
func (m menu) As(alias string) *menu {
m.menuDo.DO = *(m.menuDo.As(alias).(*gen.DO))
return m.updateTableName(alias)
}
func (m *menu) updateTableName(table string) *menu {
m.ALL = field.NewAsterisk(table)
m.ID = field.NewInt32(table, "id")
m.CreateTime = field.NewTime(table, "create_time")
m.UpdateTime = field.NewTime(table, "update_time")
m.Icon = field.NewString(table, "icon")
m.Name = field.NewString(table, "name")
m.ParentID = field.NewInt32(table, "parent_id")
m.Priority = field.NewInt32(table, "priority")
m.Target = field.NewString(table, "target")
m.Team = field.NewString(table, "team")
m.URL = field.NewString(table, "url")
m.fillFieldMap()
return m
}
func (m *menu) WithContext(ctx context.Context) *menuDo { return m.menuDo.WithContext(ctx) }
func (m menu) TableName() string { return m.menuDo.TableName() }
func (m menu) Alias() string { return m.menuDo.Alias() }
func (m *menu) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := m.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (m *menu) fillFieldMap() {
m.fieldMap = make(map[string]field.Expr, 10)
m.fieldMap["id"] = m.ID
m.fieldMap["create_time"] = m.CreateTime
m.fieldMap["update_time"] = m.UpdateTime
m.fieldMap["icon"] = m.Icon
m.fieldMap["name"] = m.Name
m.fieldMap["parent_id"] = m.ParentID
m.fieldMap["priority"] = m.Priority
m.fieldMap["target"] = m.Target
m.fieldMap["team"] = m.Team
m.fieldMap["url"] = m.URL
}
func (m menu) clone(db *gorm.DB) menu {
m.menuDo.ReplaceDB(db)
return m
}
type menuDo struct{ gen.DO }
func (m menuDo) Debug() *menuDo {
return m.withDO(m.DO.Debug())
}
func (m menuDo) WithContext(ctx context.Context) *menuDo {
return m.withDO(m.DO.WithContext(ctx))
}
func (m menuDo) ReadDB() *menuDo {
return m.Clauses(dbresolver.Read)
}
func (m menuDo) WriteDB() *menuDo {
return m.Clauses(dbresolver.Write)
}
func (m menuDo) Clauses(conds ...clause.Expression) *menuDo {
return m.withDO(m.DO.Clauses(conds...))
}
func (m menuDo) Returning(value interface{}, columns ...string) *menuDo {
return m.withDO(m.DO.Returning(value, columns...))
}
func (m menuDo) Not(conds ...gen.Condition) *menuDo {
return m.withDO(m.DO.Not(conds...))
}
func (m menuDo) Or(conds ...gen.Condition) *menuDo {
return m.withDO(m.DO.Or(conds...))
}
func (m menuDo) Select(conds ...field.Expr) *menuDo {
return m.withDO(m.DO.Select(conds...))
}
func (m menuDo) Where(conds ...gen.Condition) *menuDo {
return m.withDO(m.DO.Where(conds...))
}
func (m menuDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *menuDo {
return m.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (m menuDo) Order(conds ...field.Expr) *menuDo {
return m.withDO(m.DO.Order(conds...))
}
func (m menuDo) Distinct(cols ...field.Expr) *menuDo {
return m.withDO(m.DO.Distinct(cols...))
}
func (m menuDo) Omit(cols ...field.Expr) *menuDo {
return m.withDO(m.DO.Omit(cols...))
}
func (m menuDo) Join(table schema.Tabler, on ...field.Expr) *menuDo {
return m.withDO(m.DO.Join(table, on...))
}
func (m menuDo) LeftJoin(table schema.Tabler, on ...field.Expr) *menuDo {
return m.withDO(m.DO.LeftJoin(table, on...))
}
func (m menuDo) RightJoin(table schema.Tabler, on ...field.Expr) *menuDo {
return m.withDO(m.DO.RightJoin(table, on...))
}
func (m menuDo) Group(cols ...field.Expr) *menuDo {
return m.withDO(m.DO.Group(cols...))
}
func (m menuDo) Having(conds ...gen.Condition) *menuDo {
return m.withDO(m.DO.Having(conds...))
}
func (m menuDo) Limit(limit int) *menuDo {
return m.withDO(m.DO.Limit(limit))
}
func (m menuDo) Offset(offset int) *menuDo {
return m.withDO(m.DO.Offset(offset))
}
func (m menuDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *menuDo {
return m.withDO(m.DO.Scopes(funcs...))
}
func (m menuDo) Unscoped() *menuDo {
return m.withDO(m.DO.Unscoped())
}
func (m menuDo) Create(values ...*entity.Menu) error {
if len(values) == 0 {
return nil
}
return m.DO.Create(values)
}
func (m menuDo) CreateInBatches(values []*entity.Menu, batchSize int) error {
return m.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (m menuDo) Save(values ...*entity.Menu) error {
if len(values) == 0 {
return nil
}
return m.DO.Save(values)
}
func (m menuDo) First() (*entity.Menu, error) {
if result, err := m.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Menu), nil
}
}
func (m menuDo) Take() (*entity.Menu, error) {
if result, err := m.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Menu), nil
}
}
func (m menuDo) Last() (*entity.Menu, error) {
if result, err := m.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Menu), nil
}
}
func (m menuDo) Find() ([]*entity.Menu, error) {
result, err := m.DO.Find()
return result.([]*entity.Menu), err
}
func (m menuDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Menu, err error) {
buf := make([]*entity.Menu, 0, batchSize)
err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (m menuDo) FindInBatches(result *[]*entity.Menu, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return m.DO.FindInBatches(result, batchSize, fc)
}
func (m menuDo) Attrs(attrs ...field.AssignExpr) *menuDo {
return m.withDO(m.DO.Attrs(attrs...))
}
func (m menuDo) Assign(attrs ...field.AssignExpr) *menuDo {
return m.withDO(m.DO.Assign(attrs...))
}
func (m menuDo) Joins(fields ...field.RelationField) *menuDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Joins(_f))
}
return &m
}
func (m menuDo) Preload(fields ...field.RelationField) *menuDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Preload(_f))
}
return &m
}
func (m menuDo) FirstOrInit() (*entity.Menu, error) {
if result, err := m.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Menu), nil
}
}
func (m menuDo) FirstOrCreate() (*entity.Menu, error) {
if result, err := m.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Menu), nil
}
}
func (m menuDo) FindByPage(offset int, limit int) (result []*entity.Menu, count int64, err error) {
result, err = m.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = m.Offset(-1).Limit(-1).Count()
return
}
func (m menuDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = m.Count()
if err != nil {
return
}
err = m.Offset(offset).Limit(limit).Scan(result)
return
}
func (m menuDo) Scan(result interface{}) (err error) {
return m.DO.Scan(result)
}
func (m menuDo) Delete(models ...*entity.Menu) (result gen.ResultInfo, err error) {
return m.DO.Delete(models)
}
func (m *menuDo) withDO(do gen.Dao) *menuDo {
m.DO = *do.(*gen.DO)
return m
}

@ -0,0 +1,342 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newMeta(db *gorm.DB) meta {
_meta := meta{}
_meta.metaDo.UseDB(db)
_meta.metaDo.UseModel(&entity.Meta{})
tableName := _meta.metaDo.TableName()
_meta.ALL = field.NewAsterisk(tableName)
_meta.ID = field.NewInt64(tableName, "id")
_meta.Type = field.NewField(tableName, "type")
_meta.CreateTime = field.NewTime(tableName, "create_time")
_meta.UpdateTime = field.NewTime(tableName, "update_time")
_meta.MetaKey = field.NewString(tableName, "meta_key")
_meta.PostID = field.NewInt32(tableName, "post_id")
_meta.MetaValue = field.NewString(tableName, "meta_value")
_meta.fillFieldMap()
return _meta
}
type meta struct {
metaDo metaDo
ALL field.Asterisk
ID field.Int64
Type field.Field
CreateTime field.Time
UpdateTime field.Time
MetaKey field.String
PostID field.Int32
MetaValue field.String
fieldMap map[string]field.Expr
}
func (m meta) Table(newTableName string) *meta {
m.metaDo.UseTable(newTableName)
return m.updateTableName(newTableName)
}
func (m meta) As(alias string) *meta {
m.metaDo.DO = *(m.metaDo.As(alias).(*gen.DO))
return m.updateTableName(alias)
}
func (m *meta) updateTableName(table string) *meta {
m.ALL = field.NewAsterisk(table)
m.ID = field.NewInt64(table, "id")
m.Type = field.NewField(table, "type")
m.CreateTime = field.NewTime(table, "create_time")
m.UpdateTime = field.NewTime(table, "update_time")
m.MetaKey = field.NewString(table, "meta_key")
m.PostID = field.NewInt32(table, "post_id")
m.MetaValue = field.NewString(table, "meta_value")
m.fillFieldMap()
return m
}
func (m *meta) WithContext(ctx context.Context) *metaDo { return m.metaDo.WithContext(ctx) }
func (m meta) TableName() string { return m.metaDo.TableName() }
func (m meta) Alias() string { return m.metaDo.Alias() }
func (m *meta) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := m.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (m *meta) fillFieldMap() {
m.fieldMap = make(map[string]field.Expr, 7)
m.fieldMap["id"] = m.ID
m.fieldMap["type"] = m.Type
m.fieldMap["create_time"] = m.CreateTime
m.fieldMap["update_time"] = m.UpdateTime
m.fieldMap["meta_key"] = m.MetaKey
m.fieldMap["post_id"] = m.PostID
m.fieldMap["meta_value"] = m.MetaValue
}
func (m meta) clone(db *gorm.DB) meta {
m.metaDo.ReplaceDB(db)
return m
}
type metaDo struct{ gen.DO }
func (m metaDo) Debug() *metaDo {
return m.withDO(m.DO.Debug())
}
func (m metaDo) WithContext(ctx context.Context) *metaDo {
return m.withDO(m.DO.WithContext(ctx))
}
func (m metaDo) ReadDB() *metaDo {
return m.Clauses(dbresolver.Read)
}
func (m metaDo) WriteDB() *metaDo {
return m.Clauses(dbresolver.Write)
}
func (m metaDo) Clauses(conds ...clause.Expression) *metaDo {
return m.withDO(m.DO.Clauses(conds...))
}
func (m metaDo) Returning(value interface{}, columns ...string) *metaDo {
return m.withDO(m.DO.Returning(value, columns...))
}
func (m metaDo) Not(conds ...gen.Condition) *metaDo {
return m.withDO(m.DO.Not(conds...))
}
func (m metaDo) Or(conds ...gen.Condition) *metaDo {
return m.withDO(m.DO.Or(conds...))
}
func (m metaDo) Select(conds ...field.Expr) *metaDo {
return m.withDO(m.DO.Select(conds...))
}
func (m metaDo) Where(conds ...gen.Condition) *metaDo {
return m.withDO(m.DO.Where(conds...))
}
func (m metaDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *metaDo {
return m.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (m metaDo) Order(conds ...field.Expr) *metaDo {
return m.withDO(m.DO.Order(conds...))
}
func (m metaDo) Distinct(cols ...field.Expr) *metaDo {
return m.withDO(m.DO.Distinct(cols...))
}
func (m metaDo) Omit(cols ...field.Expr) *metaDo {
return m.withDO(m.DO.Omit(cols...))
}
func (m metaDo) Join(table schema.Tabler, on ...field.Expr) *metaDo {
return m.withDO(m.DO.Join(table, on...))
}
func (m metaDo) LeftJoin(table schema.Tabler, on ...field.Expr) *metaDo {
return m.withDO(m.DO.LeftJoin(table, on...))
}
func (m metaDo) RightJoin(table schema.Tabler, on ...field.Expr) *metaDo {
return m.withDO(m.DO.RightJoin(table, on...))
}
func (m metaDo) Group(cols ...field.Expr) *metaDo {
return m.withDO(m.DO.Group(cols...))
}
func (m metaDo) Having(conds ...gen.Condition) *metaDo {
return m.withDO(m.DO.Having(conds...))
}
func (m metaDo) Limit(limit int) *metaDo {
return m.withDO(m.DO.Limit(limit))
}
func (m metaDo) Offset(offset int) *metaDo {
return m.withDO(m.DO.Offset(offset))
}
func (m metaDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *metaDo {
return m.withDO(m.DO.Scopes(funcs...))
}
func (m metaDo) Unscoped() *metaDo {
return m.withDO(m.DO.Unscoped())
}
func (m metaDo) Create(values ...*entity.Meta) error {
if len(values) == 0 {
return nil
}
return m.DO.Create(values)
}
func (m metaDo) CreateInBatches(values []*entity.Meta, batchSize int) error {
return m.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (m metaDo) Save(values ...*entity.Meta) error {
if len(values) == 0 {
return nil
}
return m.DO.Save(values)
}
func (m metaDo) First() (*entity.Meta, error) {
if result, err := m.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Meta), nil
}
}
func (m metaDo) Take() (*entity.Meta, error) {
if result, err := m.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Meta), nil
}
}
func (m metaDo) Last() (*entity.Meta, error) {
if result, err := m.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Meta), nil
}
}
func (m metaDo) Find() ([]*entity.Meta, error) {
result, err := m.DO.Find()
return result.([]*entity.Meta), err
}
func (m metaDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Meta, err error) {
buf := make([]*entity.Meta, 0, batchSize)
err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (m metaDo) FindInBatches(result *[]*entity.Meta, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return m.DO.FindInBatches(result, batchSize, fc)
}
func (m metaDo) Attrs(attrs ...field.AssignExpr) *metaDo {
return m.withDO(m.DO.Attrs(attrs...))
}
func (m metaDo) Assign(attrs ...field.AssignExpr) *metaDo {
return m.withDO(m.DO.Assign(attrs...))
}
func (m metaDo) Joins(fields ...field.RelationField) *metaDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Joins(_f))
}
return &m
}
func (m metaDo) Preload(fields ...field.RelationField) *metaDo {
for _, _f := range fields {
m = *m.withDO(m.DO.Preload(_f))
}
return &m
}
func (m metaDo) FirstOrInit() (*entity.Meta, error) {
if result, err := m.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Meta), nil
}
}
func (m metaDo) FirstOrCreate() (*entity.Meta, error) {
if result, err := m.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Meta), nil
}
}
func (m metaDo) FindByPage(offset int, limit int) (result []*entity.Meta, count int64, err error) {
result, err = m.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = m.Offset(-1).Limit(-1).Count()
return
}
func (m metaDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = m.Count()
if err != nil {
return
}
err = m.Offset(offset).Limit(limit).Scan(result)
return
}
func (m metaDo) Scan(result interface{}) (err error) {
return m.DO.Scan(result)
}
func (m metaDo) Delete(models ...*entity.Meta) (result gen.ResultInfo, err error) {
return m.DO.Delete(models)
}
func (m *metaDo) withDO(do gen.Dao) *metaDo {
m.DO = *do.(*gen.DO)
return m
}

@ -0,0 +1,338 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newOption(db *gorm.DB) option {
_option := option{}
_option.optionDo.UseDB(db)
_option.optionDo.UseModel(&entity.Option{})
tableName := _option.optionDo.TableName()
_option.ALL = field.NewAsterisk(tableName)
_option.ID = field.NewInt32(tableName, "id")
_option.CreateTime = field.NewTime(tableName, "create_time")
_option.UpdateTime = field.NewTime(tableName, "update_time")
_option.OptionKey = field.NewString(tableName, "option_key")
_option.Type = field.NewField(tableName, "type")
_option.OptionValue = field.NewString(tableName, "option_value")
_option.fillFieldMap()
return _option
}
type option struct {
optionDo optionDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
OptionKey field.String
Type field.Field
OptionValue field.String
fieldMap map[string]field.Expr
}
func (o option) Table(newTableName string) *option {
o.optionDo.UseTable(newTableName)
return o.updateTableName(newTableName)
}
func (o option) As(alias string) *option {
o.optionDo.DO = *(o.optionDo.As(alias).(*gen.DO))
return o.updateTableName(alias)
}
func (o *option) updateTableName(table string) *option {
o.ALL = field.NewAsterisk(table)
o.ID = field.NewInt32(table, "id")
o.CreateTime = field.NewTime(table, "create_time")
o.UpdateTime = field.NewTime(table, "update_time")
o.OptionKey = field.NewString(table, "option_key")
o.Type = field.NewField(table, "type")
o.OptionValue = field.NewString(table, "option_value")
o.fillFieldMap()
return o
}
func (o *option) WithContext(ctx context.Context) *optionDo { return o.optionDo.WithContext(ctx) }
func (o option) TableName() string { return o.optionDo.TableName() }
func (o option) Alias() string { return o.optionDo.Alias() }
func (o *option) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := o.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (o *option) fillFieldMap() {
o.fieldMap = make(map[string]field.Expr, 6)
o.fieldMap["id"] = o.ID
o.fieldMap["create_time"] = o.CreateTime
o.fieldMap["update_time"] = o.UpdateTime
o.fieldMap["option_key"] = o.OptionKey
o.fieldMap["type"] = o.Type
o.fieldMap["option_value"] = o.OptionValue
}
func (o option) clone(db *gorm.DB) option {
o.optionDo.ReplaceDB(db)
return o
}
type optionDo struct{ gen.DO }
func (o optionDo) Debug() *optionDo {
return o.withDO(o.DO.Debug())
}
func (o optionDo) WithContext(ctx context.Context) *optionDo {
return o.withDO(o.DO.WithContext(ctx))
}
func (o optionDo) ReadDB() *optionDo {
return o.Clauses(dbresolver.Read)
}
func (o optionDo) WriteDB() *optionDo {
return o.Clauses(dbresolver.Write)
}
func (o optionDo) Clauses(conds ...clause.Expression) *optionDo {
return o.withDO(o.DO.Clauses(conds...))
}
func (o optionDo) Returning(value interface{}, columns ...string) *optionDo {
return o.withDO(o.DO.Returning(value, columns...))
}
func (o optionDo) Not(conds ...gen.Condition) *optionDo {
return o.withDO(o.DO.Not(conds...))
}
func (o optionDo) Or(conds ...gen.Condition) *optionDo {
return o.withDO(o.DO.Or(conds...))
}
func (o optionDo) Select(conds ...field.Expr) *optionDo {
return o.withDO(o.DO.Select(conds...))
}
func (o optionDo) Where(conds ...gen.Condition) *optionDo {
return o.withDO(o.DO.Where(conds...))
}
func (o optionDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *optionDo {
return o.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (o optionDo) Order(conds ...field.Expr) *optionDo {
return o.withDO(o.DO.Order(conds...))
}
func (o optionDo) Distinct(cols ...field.Expr) *optionDo {
return o.withDO(o.DO.Distinct(cols...))
}
func (o optionDo) Omit(cols ...field.Expr) *optionDo {
return o.withDO(o.DO.Omit(cols...))
}
func (o optionDo) Join(table schema.Tabler, on ...field.Expr) *optionDo {
return o.withDO(o.DO.Join(table, on...))
}
func (o optionDo) LeftJoin(table schema.Tabler, on ...field.Expr) *optionDo {
return o.withDO(o.DO.LeftJoin(table, on...))
}
func (o optionDo) RightJoin(table schema.Tabler, on ...field.Expr) *optionDo {
return o.withDO(o.DO.RightJoin(table, on...))
}
func (o optionDo) Group(cols ...field.Expr) *optionDo {
return o.withDO(o.DO.Group(cols...))
}
func (o optionDo) Having(conds ...gen.Condition) *optionDo {
return o.withDO(o.DO.Having(conds...))
}
func (o optionDo) Limit(limit int) *optionDo {
return o.withDO(o.DO.Limit(limit))
}
func (o optionDo) Offset(offset int) *optionDo {
return o.withDO(o.DO.Offset(offset))
}
func (o optionDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *optionDo {
return o.withDO(o.DO.Scopes(funcs...))
}
func (o optionDo) Unscoped() *optionDo {
return o.withDO(o.DO.Unscoped())
}
func (o optionDo) Create(values ...*entity.Option) error {
if len(values) == 0 {
return nil
}
return o.DO.Create(values)
}
func (o optionDo) CreateInBatches(values []*entity.Option, batchSize int) error {
return o.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (o optionDo) Save(values ...*entity.Option) error {
if len(values) == 0 {
return nil
}
return o.DO.Save(values)
}
func (o optionDo) First() (*entity.Option, error) {
if result, err := o.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Option), nil
}
}
func (o optionDo) Take() (*entity.Option, error) {
if result, err := o.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Option), nil
}
}
func (o optionDo) Last() (*entity.Option, error) {
if result, err := o.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Option), nil
}
}
func (o optionDo) Find() ([]*entity.Option, error) {
result, err := o.DO.Find()
return result.([]*entity.Option), err
}
func (o optionDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Option, err error) {
buf := make([]*entity.Option, 0, batchSize)
err = o.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (o optionDo) FindInBatches(result *[]*entity.Option, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return o.DO.FindInBatches(result, batchSize, fc)
}
func (o optionDo) Attrs(attrs ...field.AssignExpr) *optionDo {
return o.withDO(o.DO.Attrs(attrs...))
}
func (o optionDo) Assign(attrs ...field.AssignExpr) *optionDo {
return o.withDO(o.DO.Assign(attrs...))
}
func (o optionDo) Joins(fields ...field.RelationField) *optionDo {
for _, _f := range fields {
o = *o.withDO(o.DO.Joins(_f))
}
return &o
}
func (o optionDo) Preload(fields ...field.RelationField) *optionDo {
for _, _f := range fields {
o = *o.withDO(o.DO.Preload(_f))
}
return &o
}
func (o optionDo) FirstOrInit() (*entity.Option, error) {
if result, err := o.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Option), nil
}
}
func (o optionDo) FirstOrCreate() (*entity.Option, error) {
if result, err := o.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Option), nil
}
}
func (o optionDo) FindByPage(offset int, limit int) (result []*entity.Option, count int64, err error) {
result, err = o.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = o.Offset(-1).Limit(-1).Count()
return
}
func (o optionDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = o.Count()
if err != nil {
return
}
err = o.Offset(offset).Limit(limit).Scan(result)
return
}
func (o optionDo) Scan(result interface{}) (err error) {
return o.DO.Scan(result)
}
func (o optionDo) Delete(models ...*entity.Option) (result gen.ResultInfo, err error) {
return o.DO.Delete(models)
}
func (o *optionDo) withDO(do gen.Dao) *optionDo {
o.DO = *do.(*gen.DO)
return o
}

@ -0,0 +1,358 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newPhoto(db *gorm.DB) photo {
_photo := photo{}
_photo.photoDo.UseDB(db)
_photo.photoDo.UseModel(&entity.Photo{})
tableName := _photo.photoDo.TableName()
_photo.ALL = field.NewAsterisk(tableName)
_photo.ID = field.NewInt32(tableName, "id")
_photo.CreateTime = field.NewTime(tableName, "create_time")
_photo.UpdateTime = field.NewTime(tableName, "update_time")
_photo.Description = field.NewString(tableName, "description")
_photo.Location = field.NewString(tableName, "location")
_photo.Name = field.NewString(tableName, "name")
_photo.TakeTime = field.NewTime(tableName, "take_time")
_photo.Team = field.NewString(tableName, "team")
_photo.Thumbnail = field.NewString(tableName, "thumbnail")
_photo.URL = field.NewString(tableName, "url")
_photo.Likes = field.NewInt64(tableName, "likes")
_photo.fillFieldMap()
return _photo
}
type photo struct {
photoDo photoDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Description field.String
Location field.String
Name field.String
TakeTime field.Time
Team field.String
Thumbnail field.String
URL field.String
Likes field.Int64
fieldMap map[string]field.Expr
}
func (p photo) Table(newTableName string) *photo {
p.photoDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p photo) As(alias string) *photo {
p.photoDo.DO = *(p.photoDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *photo) updateTableName(table string) *photo {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt32(table, "id")
p.CreateTime = field.NewTime(table, "create_time")
p.UpdateTime = field.NewTime(table, "update_time")
p.Description = field.NewString(table, "description")
p.Location = field.NewString(table, "location")
p.Name = field.NewString(table, "name")
p.TakeTime = field.NewTime(table, "take_time")
p.Team = field.NewString(table, "team")
p.Thumbnail = field.NewString(table, "thumbnail")
p.URL = field.NewString(table, "url")
p.Likes = field.NewInt64(table, "likes")
p.fillFieldMap()
return p
}
func (p *photo) WithContext(ctx context.Context) *photoDo { return p.photoDo.WithContext(ctx) }
func (p photo) TableName() string { return p.photoDo.TableName() }
func (p photo) Alias() string { return p.photoDo.Alias() }
func (p *photo) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *photo) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 11)
p.fieldMap["id"] = p.ID
p.fieldMap["create_time"] = p.CreateTime
p.fieldMap["update_time"] = p.UpdateTime
p.fieldMap["description"] = p.Description
p.fieldMap["location"] = p.Location
p.fieldMap["name"] = p.Name
p.fieldMap["take_time"] = p.TakeTime
p.fieldMap["team"] = p.Team
p.fieldMap["thumbnail"] = p.Thumbnail
p.fieldMap["url"] = p.URL
p.fieldMap["likes"] = p.Likes
}
func (p photo) clone(db *gorm.DB) photo {
p.photoDo.ReplaceDB(db)
return p
}
type photoDo struct{ gen.DO }
func (p photoDo) Debug() *photoDo {
return p.withDO(p.DO.Debug())
}
func (p photoDo) WithContext(ctx context.Context) *photoDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p photoDo) ReadDB() *photoDo {
return p.Clauses(dbresolver.Read)
}
func (p photoDo) WriteDB() *photoDo {
return p.Clauses(dbresolver.Write)
}
func (p photoDo) Clauses(conds ...clause.Expression) *photoDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p photoDo) Returning(value interface{}, columns ...string) *photoDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p photoDo) Not(conds ...gen.Condition) *photoDo {
return p.withDO(p.DO.Not(conds...))
}
func (p photoDo) Or(conds ...gen.Condition) *photoDo {
return p.withDO(p.DO.Or(conds...))
}
func (p photoDo) Select(conds ...field.Expr) *photoDo {
return p.withDO(p.DO.Select(conds...))
}
func (p photoDo) Where(conds ...gen.Condition) *photoDo {
return p.withDO(p.DO.Where(conds...))
}
func (p photoDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *photoDo {
return p.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (p photoDo) Order(conds ...field.Expr) *photoDo {
return p.withDO(p.DO.Order(conds...))
}
func (p photoDo) Distinct(cols ...field.Expr) *photoDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p photoDo) Omit(cols ...field.Expr) *photoDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p photoDo) Join(table schema.Tabler, on ...field.Expr) *photoDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p photoDo) LeftJoin(table schema.Tabler, on ...field.Expr) *photoDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p photoDo) RightJoin(table schema.Tabler, on ...field.Expr) *photoDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p photoDo) Group(cols ...field.Expr) *photoDo {
return p.withDO(p.DO.Group(cols...))
}
func (p photoDo) Having(conds ...gen.Condition) *photoDo {
return p.withDO(p.DO.Having(conds...))
}
func (p photoDo) Limit(limit int) *photoDo {
return p.withDO(p.DO.Limit(limit))
}
func (p photoDo) Offset(offset int) *photoDo {
return p.withDO(p.DO.Offset(offset))
}
func (p photoDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *photoDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p photoDo) Unscoped() *photoDo {
return p.withDO(p.DO.Unscoped())
}
func (p photoDo) Create(values ...*entity.Photo) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p photoDo) CreateInBatches(values []*entity.Photo, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p photoDo) Save(values ...*entity.Photo) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p photoDo) First() (*entity.Photo, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Photo), nil
}
}
func (p photoDo) Take() (*entity.Photo, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Photo), nil
}
}
func (p photoDo) Last() (*entity.Photo, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Photo), nil
}
}
func (p photoDo) Find() ([]*entity.Photo, error) {
result, err := p.DO.Find()
return result.([]*entity.Photo), err
}
func (p photoDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Photo, err error) {
buf := make([]*entity.Photo, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p photoDo) FindInBatches(result *[]*entity.Photo, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p photoDo) Attrs(attrs ...field.AssignExpr) *photoDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p photoDo) Assign(attrs ...field.AssignExpr) *photoDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p photoDo) Joins(fields ...field.RelationField) *photoDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p photoDo) Preload(fields ...field.RelationField) *photoDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p photoDo) FirstOrInit() (*entity.Photo, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Photo), nil
}
}
func (p photoDo) FirstOrCreate() (*entity.Photo, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Photo), nil
}
}
func (p photoDo) FindByPage(offset int, limit int) (result []*entity.Photo, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p photoDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p photoDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p photoDo) Delete(models ...*entity.Photo) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *photoDo) withDO(do gen.Dao) *photoDo {
p.DO = *do.(*gen.DO)
return p
}

@ -0,0 +1,406 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newPost(db *gorm.DB) post {
_post := post{}
_post.postDo.UseDB(db)
_post.postDo.UseModel(&entity.Post{})
tableName := _post.postDo.TableName()
_post.ALL = field.NewAsterisk(tableName)
_post.ID = field.NewInt32(tableName, "id")
_post.Type = field.NewField(tableName, "type")
_post.CreateTime = field.NewTime(tableName, "create_time")
_post.UpdateTime = field.NewTime(tableName, "update_time")
_post.DisallowComment = field.NewBool(tableName, "disallow_comment")
_post.EditTime = field.NewTime(tableName, "edit_time")
_post.EditorType = field.NewField(tableName, "editor_type")
_post.Likes = field.NewInt64(tableName, "likes")
_post.MetaDescription = field.NewString(tableName, "meta_description")
_post.MetaKeywords = field.NewString(tableName, "meta_keywords")
_post.Password = field.NewString(tableName, "password")
_post.Slug = field.NewString(tableName, "slug")
_post.Status = field.NewField(tableName, "status")
_post.Summary = field.NewString(tableName, "summary")
_post.Template = field.NewString(tableName, "template")
_post.Thumbnail = field.NewString(tableName, "thumbnail")
_post.Title = field.NewString(tableName, "title")
_post.TopPriority = field.NewInt32(tableName, "top_priority")
_post.Visits = field.NewInt64(tableName, "visits")
_post.WordCount = field.NewInt64(tableName, "word_count")
_post.Version = field.NewInt32(tableName, "version")
_post.FormatContent = field.NewString(tableName, "format_content")
_post.OriginalContent = field.NewString(tableName, "original_content")
_post.fillFieldMap()
return _post
}
type post struct {
postDo postDo
ALL field.Asterisk
ID field.Int32
Type field.Field
CreateTime field.Time
UpdateTime field.Time
DisallowComment field.Bool
EditTime field.Time
EditorType field.Field
Likes field.Int64
MetaDescription field.String
MetaKeywords field.String
Password field.String
Slug field.String
Status field.Field
Summary field.String
Template field.String
Thumbnail field.String
Title field.String
TopPriority field.Int32
Visits field.Int64
WordCount field.Int64
Version field.Int32
FormatContent field.String
OriginalContent field.String
fieldMap map[string]field.Expr
}
func (p post) Table(newTableName string) *post {
p.postDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p post) As(alias string) *post {
p.postDo.DO = *(p.postDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *post) updateTableName(table string) *post {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt32(table, "id")
p.Type = field.NewField(table, "type")
p.CreateTime = field.NewTime(table, "create_time")
p.UpdateTime = field.NewTime(table, "update_time")
p.DisallowComment = field.NewBool(table, "disallow_comment")
p.EditTime = field.NewTime(table, "edit_time")
p.EditorType = field.NewField(table, "editor_type")
p.Likes = field.NewInt64(table, "likes")
p.MetaDescription = field.NewString(table, "meta_description")
p.MetaKeywords = field.NewString(table, "meta_keywords")
p.Password = field.NewString(table, "password")
p.Slug = field.NewString(table, "slug")
p.Status = field.NewField(table, "status")
p.Summary = field.NewString(table, "summary")
p.Template = field.NewString(table, "template")
p.Thumbnail = field.NewString(table, "thumbnail")
p.Title = field.NewString(table, "title")
p.TopPriority = field.NewInt32(table, "top_priority")
p.Visits = field.NewInt64(table, "visits")
p.WordCount = field.NewInt64(table, "word_count")
p.Version = field.NewInt32(table, "version")
p.FormatContent = field.NewString(table, "format_content")
p.OriginalContent = field.NewString(table, "original_content")
p.fillFieldMap()
return p
}
func (p *post) WithContext(ctx context.Context) *postDo { return p.postDo.WithContext(ctx) }
func (p post) TableName() string { return p.postDo.TableName() }
func (p post) Alias() string { return p.postDo.Alias() }
func (p *post) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *post) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 23)
p.fieldMap["id"] = p.ID
p.fieldMap["type"] = p.Type
p.fieldMap["create_time"] = p.CreateTime
p.fieldMap["update_time"] = p.UpdateTime
p.fieldMap["disallow_comment"] = p.DisallowComment
p.fieldMap["edit_time"] = p.EditTime
p.fieldMap["editor_type"] = p.EditorType
p.fieldMap["likes"] = p.Likes
p.fieldMap["meta_description"] = p.MetaDescription
p.fieldMap["meta_keywords"] = p.MetaKeywords
p.fieldMap["password"] = p.Password
p.fieldMap["slug"] = p.Slug
p.fieldMap["status"] = p.Status
p.fieldMap["summary"] = p.Summary
p.fieldMap["template"] = p.Template
p.fieldMap["thumbnail"] = p.Thumbnail
p.fieldMap["title"] = p.Title
p.fieldMap["top_priority"] = p.TopPriority
p.fieldMap["visits"] = p.Visits
p.fieldMap["word_count"] = p.WordCount
p.fieldMap["version"] = p.Version
p.fieldMap["format_content"] = p.FormatContent
p.fieldMap["original_content"] = p.OriginalContent
}
func (p post) clone(db *gorm.DB) post {
p.postDo.ReplaceDB(db)
return p
}
type postDo struct{ gen.DO }
func (p postDo) Debug() *postDo {
return p.withDO(p.DO.Debug())
}
func (p postDo) WithContext(ctx context.Context) *postDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p postDo) ReadDB() *postDo {
return p.Clauses(dbresolver.Read)
}
func (p postDo) WriteDB() *postDo {
return p.Clauses(dbresolver.Write)
}
func (p postDo) Clauses(conds ...clause.Expression) *postDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p postDo) Returning(value interface{}, columns ...string) *postDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p postDo) Not(conds ...gen.Condition) *postDo {
return p.withDO(p.DO.Not(conds...))
}
func (p postDo) Or(conds ...gen.Condition) *postDo {
return p.withDO(p.DO.Or(conds...))
}
func (p postDo) Select(conds ...field.Expr) *postDo {
return p.withDO(p.DO.Select(conds...))
}
func (p postDo) Where(conds ...gen.Condition) *postDo {
return p.withDO(p.DO.Where(conds...))
}
func (p postDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *postDo {
return p.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (p postDo) Order(conds ...field.Expr) *postDo {
return p.withDO(p.DO.Order(conds...))
}
func (p postDo) Distinct(cols ...field.Expr) *postDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p postDo) Omit(cols ...field.Expr) *postDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p postDo) Join(table schema.Tabler, on ...field.Expr) *postDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p postDo) LeftJoin(table schema.Tabler, on ...field.Expr) *postDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p postDo) RightJoin(table schema.Tabler, on ...field.Expr) *postDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p postDo) Group(cols ...field.Expr) *postDo {
return p.withDO(p.DO.Group(cols...))
}
func (p postDo) Having(conds ...gen.Condition) *postDo {
return p.withDO(p.DO.Having(conds...))
}
func (p postDo) Limit(limit int) *postDo {
return p.withDO(p.DO.Limit(limit))
}
func (p postDo) Offset(offset int) *postDo {
return p.withDO(p.DO.Offset(offset))
}
func (p postDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *postDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p postDo) Unscoped() *postDo {
return p.withDO(p.DO.Unscoped())
}
func (p postDo) Create(values ...*entity.Post) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p postDo) CreateInBatches(values []*entity.Post, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p postDo) Save(values ...*entity.Post) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p postDo) First() (*entity.Post, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Post), nil
}
}
func (p postDo) Take() (*entity.Post, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Post), nil
}
}
func (p postDo) Last() (*entity.Post, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Post), nil
}
}
func (p postDo) Find() ([]*entity.Post, error) {
result, err := p.DO.Find()
return result.([]*entity.Post), err
}
func (p postDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Post, err error) {
buf := make([]*entity.Post, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p postDo) FindInBatches(result *[]*entity.Post, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p postDo) Attrs(attrs ...field.AssignExpr) *postDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p postDo) Assign(attrs ...field.AssignExpr) *postDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p postDo) Joins(fields ...field.RelationField) *postDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p postDo) Preload(fields ...field.RelationField) *postDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p postDo) FirstOrInit() (*entity.Post, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Post), nil
}
}
func (p postDo) FirstOrCreate() (*entity.Post, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Post), nil
}
}
func (p postDo) FindByPage(offset int, limit int) (result []*entity.Post, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p postDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p postDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p postDo) Delete(models ...*entity.Post) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *postDo) withDO(do gen.Dao) *postDo {
p.DO = *do.(*gen.DO)
return p
}

@ -0,0 +1,336 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newPostCategory(db *gorm.DB) postCategory {
_postCategory := postCategory{}
_postCategory.postCategoryDo.UseDB(db)
_postCategory.postCategoryDo.UseModel(&entity.PostCategory{})
tableName := _postCategory.postCategoryDo.TableName()
_postCategory.ALL = field.NewAsterisk(tableName)
_postCategory.ID = field.NewInt32(tableName, "id")
_postCategory.CreateTime = field.NewTime(tableName, "create_time")
_postCategory.UpdateTime = field.NewTime(tableName, "update_time")
_postCategory.CategoryID = field.NewInt32(tableName, "category_id")
_postCategory.PostID = field.NewInt32(tableName, "post_id")
_postCategory.fillFieldMap()
return _postCategory
}
type postCategory struct {
postCategoryDo postCategoryDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
CategoryID field.Int32
PostID field.Int32
fieldMap map[string]field.Expr
}
func (p postCategory) Table(newTableName string) *postCategory {
p.postCategoryDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p postCategory) As(alias string) *postCategory {
p.postCategoryDo.DO = *(p.postCategoryDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *postCategory) updateTableName(table string) *postCategory {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt32(table, "id")
p.CreateTime = field.NewTime(table, "create_time")
p.UpdateTime = field.NewTime(table, "update_time")
p.CategoryID = field.NewInt32(table, "category_id")
p.PostID = field.NewInt32(table, "post_id")
p.fillFieldMap()
return p
}
func (p *postCategory) WithContext(ctx context.Context) *postCategoryDo {
return p.postCategoryDo.WithContext(ctx)
}
func (p postCategory) TableName() string { return p.postCategoryDo.TableName() }
func (p postCategory) Alias() string { return p.postCategoryDo.Alias() }
func (p *postCategory) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *postCategory) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 5)
p.fieldMap["id"] = p.ID
p.fieldMap["create_time"] = p.CreateTime
p.fieldMap["update_time"] = p.UpdateTime
p.fieldMap["category_id"] = p.CategoryID
p.fieldMap["post_id"] = p.PostID
}
func (p postCategory) clone(db *gorm.DB) postCategory {
p.postCategoryDo.ReplaceDB(db)
return p
}
type postCategoryDo struct{ gen.DO }
func (p postCategoryDo) Debug() *postCategoryDo {
return p.withDO(p.DO.Debug())
}
func (p postCategoryDo) WithContext(ctx context.Context) *postCategoryDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p postCategoryDo) ReadDB() *postCategoryDo {
return p.Clauses(dbresolver.Read)
}
func (p postCategoryDo) WriteDB() *postCategoryDo {
return p.Clauses(dbresolver.Write)
}
func (p postCategoryDo) Clauses(conds ...clause.Expression) *postCategoryDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p postCategoryDo) Returning(value interface{}, columns ...string) *postCategoryDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p postCategoryDo) Not(conds ...gen.Condition) *postCategoryDo {
return p.withDO(p.DO.Not(conds...))
}
func (p postCategoryDo) Or(conds ...gen.Condition) *postCategoryDo {
return p.withDO(p.DO.Or(conds...))
}
func (p postCategoryDo) Select(conds ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.Select(conds...))
}
func (p postCategoryDo) Where(conds ...gen.Condition) *postCategoryDo {
return p.withDO(p.DO.Where(conds...))
}
func (p postCategoryDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *postCategoryDo {
return p.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (p postCategoryDo) Order(conds ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.Order(conds...))
}
func (p postCategoryDo) Distinct(cols ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p postCategoryDo) Omit(cols ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p postCategoryDo) Join(table schema.Tabler, on ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p postCategoryDo) LeftJoin(table schema.Tabler, on ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p postCategoryDo) RightJoin(table schema.Tabler, on ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p postCategoryDo) Group(cols ...field.Expr) *postCategoryDo {
return p.withDO(p.DO.Group(cols...))
}
func (p postCategoryDo) Having(conds ...gen.Condition) *postCategoryDo {
return p.withDO(p.DO.Having(conds...))
}
func (p postCategoryDo) Limit(limit int) *postCategoryDo {
return p.withDO(p.DO.Limit(limit))
}
func (p postCategoryDo) Offset(offset int) *postCategoryDo {
return p.withDO(p.DO.Offset(offset))
}
func (p postCategoryDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *postCategoryDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p postCategoryDo) Unscoped() *postCategoryDo {
return p.withDO(p.DO.Unscoped())
}
func (p postCategoryDo) Create(values ...*entity.PostCategory) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p postCategoryDo) CreateInBatches(values []*entity.PostCategory, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p postCategoryDo) Save(values ...*entity.PostCategory) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p postCategoryDo) First() (*entity.PostCategory, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.PostCategory), nil
}
}
func (p postCategoryDo) Take() (*entity.PostCategory, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.PostCategory), nil
}
}
func (p postCategoryDo) Last() (*entity.PostCategory, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.PostCategory), nil
}
}
func (p postCategoryDo) Find() ([]*entity.PostCategory, error) {
result, err := p.DO.Find()
return result.([]*entity.PostCategory), err
}
func (p postCategoryDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.PostCategory, err error) {
buf := make([]*entity.PostCategory, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p postCategoryDo) FindInBatches(result *[]*entity.PostCategory, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p postCategoryDo) Attrs(attrs ...field.AssignExpr) *postCategoryDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p postCategoryDo) Assign(attrs ...field.AssignExpr) *postCategoryDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p postCategoryDo) Joins(fields ...field.RelationField) *postCategoryDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p postCategoryDo) Preload(fields ...field.RelationField) *postCategoryDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p postCategoryDo) FirstOrInit() (*entity.PostCategory, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.PostCategory), nil
}
}
func (p postCategoryDo) FirstOrCreate() (*entity.PostCategory, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.PostCategory), nil
}
}
func (p postCategoryDo) FindByPage(offset int, limit int) (result []*entity.PostCategory, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p postCategoryDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p postCategoryDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p postCategoryDo) Delete(models ...*entity.PostCategory) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *postCategoryDo) withDO(do gen.Dao) *postCategoryDo {
p.DO = *do.(*gen.DO)
return p
}

@ -0,0 +1,334 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newPostTag(db *gorm.DB) postTag {
_postTag := postTag{}
_postTag.postTagDo.UseDB(db)
_postTag.postTagDo.UseModel(&entity.PostTag{})
tableName := _postTag.postTagDo.TableName()
_postTag.ALL = field.NewAsterisk(tableName)
_postTag.ID = field.NewInt32(tableName, "id")
_postTag.CreateTime = field.NewTime(tableName, "create_time")
_postTag.UpdateTime = field.NewTime(tableName, "update_time")
_postTag.PostID = field.NewInt32(tableName, "post_id")
_postTag.TagID = field.NewInt32(tableName, "tag_id")
_postTag.fillFieldMap()
return _postTag
}
type postTag struct {
postTagDo postTagDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
PostID field.Int32
TagID field.Int32
fieldMap map[string]field.Expr
}
func (p postTag) Table(newTableName string) *postTag {
p.postTagDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p postTag) As(alias string) *postTag {
p.postTagDo.DO = *(p.postTagDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *postTag) updateTableName(table string) *postTag {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt32(table, "id")
p.CreateTime = field.NewTime(table, "create_time")
p.UpdateTime = field.NewTime(table, "update_time")
p.PostID = field.NewInt32(table, "post_id")
p.TagID = field.NewInt32(table, "tag_id")
p.fillFieldMap()
return p
}
func (p *postTag) WithContext(ctx context.Context) *postTagDo { return p.postTagDo.WithContext(ctx) }
func (p postTag) TableName() string { return p.postTagDo.TableName() }
func (p postTag) Alias() string { return p.postTagDo.Alias() }
func (p *postTag) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *postTag) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 5)
p.fieldMap["id"] = p.ID
p.fieldMap["create_time"] = p.CreateTime
p.fieldMap["update_time"] = p.UpdateTime
p.fieldMap["post_id"] = p.PostID
p.fieldMap["tag_id"] = p.TagID
}
func (p postTag) clone(db *gorm.DB) postTag {
p.postTagDo.ReplaceDB(db)
return p
}
type postTagDo struct{ gen.DO }
func (p postTagDo) Debug() *postTagDo {
return p.withDO(p.DO.Debug())
}
func (p postTagDo) WithContext(ctx context.Context) *postTagDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p postTagDo) ReadDB() *postTagDo {
return p.Clauses(dbresolver.Read)
}
func (p postTagDo) WriteDB() *postTagDo {
return p.Clauses(dbresolver.Write)
}
func (p postTagDo) Clauses(conds ...clause.Expression) *postTagDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p postTagDo) Returning(value interface{}, columns ...string) *postTagDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p postTagDo) Not(conds ...gen.Condition) *postTagDo {
return p.withDO(p.DO.Not(conds...))
}
func (p postTagDo) Or(conds ...gen.Condition) *postTagDo {
return p.withDO(p.DO.Or(conds...))
}
func (p postTagDo) Select(conds ...field.Expr) *postTagDo {
return p.withDO(p.DO.Select(conds...))
}
func (p postTagDo) Where(conds ...gen.Condition) *postTagDo {
return p.withDO(p.DO.Where(conds...))
}
func (p postTagDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *postTagDo {
return p.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (p postTagDo) Order(conds ...field.Expr) *postTagDo {
return p.withDO(p.DO.Order(conds...))
}
func (p postTagDo) Distinct(cols ...field.Expr) *postTagDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p postTagDo) Omit(cols ...field.Expr) *postTagDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p postTagDo) Join(table schema.Tabler, on ...field.Expr) *postTagDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p postTagDo) LeftJoin(table schema.Tabler, on ...field.Expr) *postTagDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p postTagDo) RightJoin(table schema.Tabler, on ...field.Expr) *postTagDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p postTagDo) Group(cols ...field.Expr) *postTagDo {
return p.withDO(p.DO.Group(cols...))
}
func (p postTagDo) Having(conds ...gen.Condition) *postTagDo {
return p.withDO(p.DO.Having(conds...))
}
func (p postTagDo) Limit(limit int) *postTagDo {
return p.withDO(p.DO.Limit(limit))
}
func (p postTagDo) Offset(offset int) *postTagDo {
return p.withDO(p.DO.Offset(offset))
}
func (p postTagDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *postTagDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p postTagDo) Unscoped() *postTagDo {
return p.withDO(p.DO.Unscoped())
}
func (p postTagDo) Create(values ...*entity.PostTag) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p postTagDo) CreateInBatches(values []*entity.PostTag, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p postTagDo) Save(values ...*entity.PostTag) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p postTagDo) First() (*entity.PostTag, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.PostTag), nil
}
}
func (p postTagDo) Take() (*entity.PostTag, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.PostTag), nil
}
}
func (p postTagDo) Last() (*entity.PostTag, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.PostTag), nil
}
}
func (p postTagDo) Find() ([]*entity.PostTag, error) {
result, err := p.DO.Find()
return result.([]*entity.PostTag), err
}
func (p postTagDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.PostTag, err error) {
buf := make([]*entity.PostTag, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p postTagDo) FindInBatches(result *[]*entity.PostTag, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p postTagDo) Attrs(attrs ...field.AssignExpr) *postTagDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p postTagDo) Assign(attrs ...field.AssignExpr) *postTagDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p postTagDo) Joins(fields ...field.RelationField) *postTagDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p postTagDo) Preload(fields ...field.RelationField) *postTagDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p postTagDo) FirstOrInit() (*entity.PostTag, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.PostTag), nil
}
}
func (p postTagDo) FirstOrCreate() (*entity.PostTag, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.PostTag), nil
}
}
func (p postTagDo) FindByPage(offset int, limit int) (result []*entity.PostTag, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p postTagDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p postTagDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p postTagDo) Delete(models ...*entity.PostTag) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *postTagDo) withDO(do gen.Dao) *postTagDo {
p.DO = *do.(*gen.DO)
return p
}

@ -0,0 +1,342 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newTag(db *gorm.DB) tag {
_tag := tag{}
_tag.tagDo.UseDB(db)
_tag.tagDo.UseModel(&entity.Tag{})
tableName := _tag.tagDo.TableName()
_tag.ALL = field.NewAsterisk(tableName)
_tag.ID = field.NewInt32(tableName, "id")
_tag.CreateTime = field.NewTime(tableName, "create_time")
_tag.UpdateTime = field.NewTime(tableName, "update_time")
_tag.Name = field.NewString(tableName, "name")
_tag.Slug = field.NewString(tableName, "slug")
_tag.Thumbnail = field.NewString(tableName, "thumbnail")
_tag.Color = field.NewString(tableName, "color")
_tag.fillFieldMap()
return _tag
}
type tag struct {
tagDo tagDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Name field.String
Slug field.String
Thumbnail field.String
Color field.String
fieldMap map[string]field.Expr
}
func (t tag) Table(newTableName string) *tag {
t.tagDo.UseTable(newTableName)
return t.updateTableName(newTableName)
}
func (t tag) As(alias string) *tag {
t.tagDo.DO = *(t.tagDo.As(alias).(*gen.DO))
return t.updateTableName(alias)
}
func (t *tag) updateTableName(table string) *tag {
t.ALL = field.NewAsterisk(table)
t.ID = field.NewInt32(table, "id")
t.CreateTime = field.NewTime(table, "create_time")
t.UpdateTime = field.NewTime(table, "update_time")
t.Name = field.NewString(table, "name")
t.Slug = field.NewString(table, "slug")
t.Thumbnail = field.NewString(table, "thumbnail")
t.Color = field.NewString(table, "color")
t.fillFieldMap()
return t
}
func (t *tag) WithContext(ctx context.Context) *tagDo { return t.tagDo.WithContext(ctx) }
func (t tag) TableName() string { return t.tagDo.TableName() }
func (t tag) Alias() string { return t.tagDo.Alias() }
func (t *tag) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := t.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (t *tag) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 7)
t.fieldMap["id"] = t.ID
t.fieldMap["create_time"] = t.CreateTime
t.fieldMap["update_time"] = t.UpdateTime
t.fieldMap["name"] = t.Name
t.fieldMap["slug"] = t.Slug
t.fieldMap["thumbnail"] = t.Thumbnail
t.fieldMap["color"] = t.Color
}
func (t tag) clone(db *gorm.DB) tag {
t.tagDo.ReplaceDB(db)
return t
}
type tagDo struct{ gen.DO }
func (t tagDo) Debug() *tagDo {
return t.withDO(t.DO.Debug())
}
func (t tagDo) WithContext(ctx context.Context) *tagDo {
return t.withDO(t.DO.WithContext(ctx))
}
func (t tagDo) ReadDB() *tagDo {
return t.Clauses(dbresolver.Read)
}
func (t tagDo) WriteDB() *tagDo {
return t.Clauses(dbresolver.Write)
}
func (t tagDo) Clauses(conds ...clause.Expression) *tagDo {
return t.withDO(t.DO.Clauses(conds...))
}
func (t tagDo) Returning(value interface{}, columns ...string) *tagDo {
return t.withDO(t.DO.Returning(value, columns...))
}
func (t tagDo) Not(conds ...gen.Condition) *tagDo {
return t.withDO(t.DO.Not(conds...))
}
func (t tagDo) Or(conds ...gen.Condition) *tagDo {
return t.withDO(t.DO.Or(conds...))
}
func (t tagDo) Select(conds ...field.Expr) *tagDo {
return t.withDO(t.DO.Select(conds...))
}
func (t tagDo) Where(conds ...gen.Condition) *tagDo {
return t.withDO(t.DO.Where(conds...))
}
func (t tagDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *tagDo {
return t.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (t tagDo) Order(conds ...field.Expr) *tagDo {
return t.withDO(t.DO.Order(conds...))
}
func (t tagDo) Distinct(cols ...field.Expr) *tagDo {
return t.withDO(t.DO.Distinct(cols...))
}
func (t tagDo) Omit(cols ...field.Expr) *tagDo {
return t.withDO(t.DO.Omit(cols...))
}
func (t tagDo) Join(table schema.Tabler, on ...field.Expr) *tagDo {
return t.withDO(t.DO.Join(table, on...))
}
func (t tagDo) LeftJoin(table schema.Tabler, on ...field.Expr) *tagDo {
return t.withDO(t.DO.LeftJoin(table, on...))
}
func (t tagDo) RightJoin(table schema.Tabler, on ...field.Expr) *tagDo {
return t.withDO(t.DO.RightJoin(table, on...))
}
func (t tagDo) Group(cols ...field.Expr) *tagDo {
return t.withDO(t.DO.Group(cols...))
}
func (t tagDo) Having(conds ...gen.Condition) *tagDo {
return t.withDO(t.DO.Having(conds...))
}
func (t tagDo) Limit(limit int) *tagDo {
return t.withDO(t.DO.Limit(limit))
}
func (t tagDo) Offset(offset int) *tagDo {
return t.withDO(t.DO.Offset(offset))
}
func (t tagDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *tagDo {
return t.withDO(t.DO.Scopes(funcs...))
}
func (t tagDo) Unscoped() *tagDo {
return t.withDO(t.DO.Unscoped())
}
func (t tagDo) Create(values ...*entity.Tag) error {
if len(values) == 0 {
return nil
}
return t.DO.Create(values)
}
func (t tagDo) CreateInBatches(values []*entity.Tag, batchSize int) error {
return t.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (t tagDo) Save(values ...*entity.Tag) error {
if len(values) == 0 {
return nil
}
return t.DO.Save(values)
}
func (t tagDo) First() (*entity.Tag, error) {
if result, err := t.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.Tag), nil
}
}
func (t tagDo) Take() (*entity.Tag, error) {
if result, err := t.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.Tag), nil
}
}
func (t tagDo) Last() (*entity.Tag, error) {
if result, err := t.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.Tag), nil
}
}
func (t tagDo) Find() ([]*entity.Tag, error) {
result, err := t.DO.Find()
return result.([]*entity.Tag), err
}
func (t tagDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Tag, err error) {
buf := make([]*entity.Tag, 0, batchSize)
err = t.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (t tagDo) FindInBatches(result *[]*entity.Tag, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return t.DO.FindInBatches(result, batchSize, fc)
}
func (t tagDo) Attrs(attrs ...field.AssignExpr) *tagDo {
return t.withDO(t.DO.Attrs(attrs...))
}
func (t tagDo) Assign(attrs ...field.AssignExpr) *tagDo {
return t.withDO(t.DO.Assign(attrs...))
}
func (t tagDo) Joins(fields ...field.RelationField) *tagDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Joins(_f))
}
return &t
}
func (t tagDo) Preload(fields ...field.RelationField) *tagDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Preload(_f))
}
return &t
}
func (t tagDo) FirstOrInit() (*entity.Tag, error) {
if result, err := t.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.Tag), nil
}
}
func (t tagDo) FirstOrCreate() (*entity.Tag, error) {
if result, err := t.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.Tag), nil
}
}
func (t tagDo) FindByPage(offset int, limit int) (result []*entity.Tag, count int64, err error) {
result, err = t.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = t.Offset(-1).Limit(-1).Count()
return
}
func (t tagDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = t.Count()
if err != nil {
return
}
err = t.Offset(offset).Limit(limit).Scan(result)
return
}
func (t tagDo) Scan(result interface{}) (err error) {
return t.DO.Scan(result)
}
func (t tagDo) Delete(models ...*entity.Tag) (result gen.ResultInfo, err error) {
return t.DO.Delete(models)
}
func (t *tagDo) withDO(do gen.Dao) *tagDo {
t.DO = *do.(*gen.DO)
return t
}

@ -0,0 +1,340 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newThemeSetting(db *gorm.DB) themeSetting {
_themeSetting := themeSetting{}
_themeSetting.themeSettingDo.UseDB(db)
_themeSetting.themeSettingDo.UseModel(&entity.ThemeSetting{})
tableName := _themeSetting.themeSettingDo.TableName()
_themeSetting.ALL = field.NewAsterisk(tableName)
_themeSetting.ID = field.NewInt32(tableName, "id")
_themeSetting.CreateTime = field.NewTime(tableName, "create_time")
_themeSetting.UpdateTime = field.NewTime(tableName, "update_time")
_themeSetting.SettingKey = field.NewString(tableName, "setting_key")
_themeSetting.ThemeID = field.NewString(tableName, "theme_id")
_themeSetting.SettingValue = field.NewString(tableName, "setting_value")
_themeSetting.fillFieldMap()
return _themeSetting
}
type themeSetting struct {
themeSettingDo themeSettingDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
SettingKey field.String
ThemeID field.String
SettingValue field.String
fieldMap map[string]field.Expr
}
func (t themeSetting) Table(newTableName string) *themeSetting {
t.themeSettingDo.UseTable(newTableName)
return t.updateTableName(newTableName)
}
func (t themeSetting) As(alias string) *themeSetting {
t.themeSettingDo.DO = *(t.themeSettingDo.As(alias).(*gen.DO))
return t.updateTableName(alias)
}
func (t *themeSetting) updateTableName(table string) *themeSetting {
t.ALL = field.NewAsterisk(table)
t.ID = field.NewInt32(table, "id")
t.CreateTime = field.NewTime(table, "create_time")
t.UpdateTime = field.NewTime(table, "update_time")
t.SettingKey = field.NewString(table, "setting_key")
t.ThemeID = field.NewString(table, "theme_id")
t.SettingValue = field.NewString(table, "setting_value")
t.fillFieldMap()
return t
}
func (t *themeSetting) WithContext(ctx context.Context) *themeSettingDo {
return t.themeSettingDo.WithContext(ctx)
}
func (t themeSetting) TableName() string { return t.themeSettingDo.TableName() }
func (t themeSetting) Alias() string { return t.themeSettingDo.Alias() }
func (t *themeSetting) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := t.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (t *themeSetting) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 6)
t.fieldMap["id"] = t.ID
t.fieldMap["create_time"] = t.CreateTime
t.fieldMap["update_time"] = t.UpdateTime
t.fieldMap["setting_key"] = t.SettingKey
t.fieldMap["theme_id"] = t.ThemeID
t.fieldMap["setting_value"] = t.SettingValue
}
func (t themeSetting) clone(db *gorm.DB) themeSetting {
t.themeSettingDo.ReplaceDB(db)
return t
}
type themeSettingDo struct{ gen.DO }
func (t themeSettingDo) Debug() *themeSettingDo {
return t.withDO(t.DO.Debug())
}
func (t themeSettingDo) WithContext(ctx context.Context) *themeSettingDo {
return t.withDO(t.DO.WithContext(ctx))
}
func (t themeSettingDo) ReadDB() *themeSettingDo {
return t.Clauses(dbresolver.Read)
}
func (t themeSettingDo) WriteDB() *themeSettingDo {
return t.Clauses(dbresolver.Write)
}
func (t themeSettingDo) Clauses(conds ...clause.Expression) *themeSettingDo {
return t.withDO(t.DO.Clauses(conds...))
}
func (t themeSettingDo) Returning(value interface{}, columns ...string) *themeSettingDo {
return t.withDO(t.DO.Returning(value, columns...))
}
func (t themeSettingDo) Not(conds ...gen.Condition) *themeSettingDo {
return t.withDO(t.DO.Not(conds...))
}
func (t themeSettingDo) Or(conds ...gen.Condition) *themeSettingDo {
return t.withDO(t.DO.Or(conds...))
}
func (t themeSettingDo) Select(conds ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.Select(conds...))
}
func (t themeSettingDo) Where(conds ...gen.Condition) *themeSettingDo {
return t.withDO(t.DO.Where(conds...))
}
func (t themeSettingDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *themeSettingDo {
return t.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (t themeSettingDo) Order(conds ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.Order(conds...))
}
func (t themeSettingDo) Distinct(cols ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.Distinct(cols...))
}
func (t themeSettingDo) Omit(cols ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.Omit(cols...))
}
func (t themeSettingDo) Join(table schema.Tabler, on ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.Join(table, on...))
}
func (t themeSettingDo) LeftJoin(table schema.Tabler, on ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.LeftJoin(table, on...))
}
func (t themeSettingDo) RightJoin(table schema.Tabler, on ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.RightJoin(table, on...))
}
func (t themeSettingDo) Group(cols ...field.Expr) *themeSettingDo {
return t.withDO(t.DO.Group(cols...))
}
func (t themeSettingDo) Having(conds ...gen.Condition) *themeSettingDo {
return t.withDO(t.DO.Having(conds...))
}
func (t themeSettingDo) Limit(limit int) *themeSettingDo {
return t.withDO(t.DO.Limit(limit))
}
func (t themeSettingDo) Offset(offset int) *themeSettingDo {
return t.withDO(t.DO.Offset(offset))
}
func (t themeSettingDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *themeSettingDo {
return t.withDO(t.DO.Scopes(funcs...))
}
func (t themeSettingDo) Unscoped() *themeSettingDo {
return t.withDO(t.DO.Unscoped())
}
func (t themeSettingDo) Create(values ...*entity.ThemeSetting) error {
if len(values) == 0 {
return nil
}
return t.DO.Create(values)
}
func (t themeSettingDo) CreateInBatches(values []*entity.ThemeSetting, batchSize int) error {
return t.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (t themeSettingDo) Save(values ...*entity.ThemeSetting) error {
if len(values) == 0 {
return nil
}
return t.DO.Save(values)
}
func (t themeSettingDo) First() (*entity.ThemeSetting, error) {
if result, err := t.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.ThemeSetting), nil
}
}
func (t themeSettingDo) Take() (*entity.ThemeSetting, error) {
if result, err := t.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.ThemeSetting), nil
}
}
func (t themeSettingDo) Last() (*entity.ThemeSetting, error) {
if result, err := t.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.ThemeSetting), nil
}
}
func (t themeSettingDo) Find() ([]*entity.ThemeSetting, error) {
result, err := t.DO.Find()
return result.([]*entity.ThemeSetting), err
}
func (t themeSettingDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.ThemeSetting, err error) {
buf := make([]*entity.ThemeSetting, 0, batchSize)
err = t.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (t themeSettingDo) FindInBatches(result *[]*entity.ThemeSetting, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return t.DO.FindInBatches(result, batchSize, fc)
}
func (t themeSettingDo) Attrs(attrs ...field.AssignExpr) *themeSettingDo {
return t.withDO(t.DO.Attrs(attrs...))
}
func (t themeSettingDo) Assign(attrs ...field.AssignExpr) *themeSettingDo {
return t.withDO(t.DO.Assign(attrs...))
}
func (t themeSettingDo) Joins(fields ...field.RelationField) *themeSettingDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Joins(_f))
}
return &t
}
func (t themeSettingDo) Preload(fields ...field.RelationField) *themeSettingDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Preload(_f))
}
return &t
}
func (t themeSettingDo) FirstOrInit() (*entity.ThemeSetting, error) {
if result, err := t.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.ThemeSetting), nil
}
}
func (t themeSettingDo) FirstOrCreate() (*entity.ThemeSetting, error) {
if result, err := t.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.ThemeSetting), nil
}
}
func (t themeSettingDo) FindByPage(offset int, limit int) (result []*entity.ThemeSetting, count int64, err error) {
result, err = t.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = t.Offset(-1).Limit(-1).Count()
return
}
func (t themeSettingDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = t.Count()
if err != nil {
return
}
err = t.Offset(offset).Limit(limit).Scan(result)
return
}
func (t themeSettingDo) Scan(result interface{}) (err error) {
return t.DO.Scan(result)
}
func (t themeSettingDo) Delete(models ...*entity.ThemeSetting) (result gen.ResultInfo, err error) {
return t.DO.Delete(models)
}
func (t *themeSettingDo) withDO(do gen.Dao) *themeSettingDo {
t.DO = *do.(*gen.DO)
return t
}

@ -0,0 +1,362 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package dal
import (
"context"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/plugin/dbresolver"
"github.com/go-sonic/sonic/model/entity"
)
func newUser(db *gorm.DB) user {
_user := user{}
_user.userDo.UseDB(db)
_user.userDo.UseModel(&entity.User{})
tableName := _user.userDo.TableName()
_user.ALL = field.NewAsterisk(tableName)
_user.ID = field.NewInt32(tableName, "id")
_user.CreateTime = field.NewTime(tableName, "create_time")
_user.UpdateTime = field.NewTime(tableName, "update_time")
_user.Avatar = field.NewString(tableName, "avatar")
_user.Description = field.NewString(tableName, "description")
_user.Email = field.NewString(tableName, "email")
_user.ExpireTime = field.NewTime(tableName, "expire_time")
_user.MfaKey = field.NewString(tableName, "mfa_key")
_user.MfaType = field.NewField(tableName, "mfa_type")
_user.Nickname = field.NewString(tableName, "nickname")
_user.Password = field.NewString(tableName, "password")
_user.Username = field.NewString(tableName, "username")
_user.fillFieldMap()
return _user
}
type user struct {
userDo userDo
ALL field.Asterisk
ID field.Int32
CreateTime field.Time
UpdateTime field.Time
Avatar field.String
Description field.String
Email field.String
ExpireTime field.Time
MfaKey field.String
MfaType field.Field
Nickname field.String
Password field.String
Username field.String
fieldMap map[string]field.Expr
}
func (u user) Table(newTableName string) *user {
u.userDo.UseTable(newTableName)
return u.updateTableName(newTableName)
}
func (u user) As(alias string) *user {
u.userDo.DO = *(u.userDo.As(alias).(*gen.DO))
return u.updateTableName(alias)
}
func (u *user) updateTableName(table string) *user {
u.ALL = field.NewAsterisk(table)
u.ID = field.NewInt32(table, "id")
u.CreateTime = field.NewTime(table, "create_time")
u.UpdateTime = field.NewTime(table, "update_time")
u.Avatar = field.NewString(table, "avatar")
u.Description = field.NewString(table, "description")
u.Email = field.NewString(table, "email")
u.ExpireTime = field.NewTime(table, "expire_time")
u.MfaKey = field.NewString(table, "mfa_key")
u.MfaType = field.NewField(table, "mfa_type")
u.Nickname = field.NewString(table, "nickname")
u.Password = field.NewString(table, "password")
u.Username = field.NewString(table, "username")
u.fillFieldMap()
return u
}
func (u *user) WithContext(ctx context.Context) *userDo { return u.userDo.WithContext(ctx) }
func (u user) TableName() string { return u.userDo.TableName() }
func (u user) Alias() string { return u.userDo.Alias() }
func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := u.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (u *user) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 12)
u.fieldMap["id"] = u.ID
u.fieldMap["create_time"] = u.CreateTime
u.fieldMap["update_time"] = u.UpdateTime
u.fieldMap["avatar"] = u.Avatar
u.fieldMap["description"] = u.Description
u.fieldMap["email"] = u.Email
u.fieldMap["expire_time"] = u.ExpireTime
u.fieldMap["mfa_key"] = u.MfaKey
u.fieldMap["mfa_type"] = u.MfaType
u.fieldMap["nickname"] = u.Nickname
u.fieldMap["password"] = u.Password
u.fieldMap["username"] = u.Username
}
func (u user) clone(db *gorm.DB) user {
u.userDo.ReplaceDB(db)
return u
}
type userDo struct{ gen.DO }
func (u userDo) Debug() *userDo {
return u.withDO(u.DO.Debug())
}
func (u userDo) WithContext(ctx context.Context) *userDo {
return u.withDO(u.DO.WithContext(ctx))
}
func (u userDo) ReadDB() *userDo {
return u.Clauses(dbresolver.Read)
}
func (u userDo) WriteDB() *userDo {
return u.Clauses(dbresolver.Write)
}
func (u userDo) Clauses(conds ...clause.Expression) *userDo {
return u.withDO(u.DO.Clauses(conds...))
}
func (u userDo) Returning(value interface{}, columns ...string) *userDo {
return u.withDO(u.DO.Returning(value, columns...))
}
func (u userDo) Not(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Not(conds...))
}
func (u userDo) Or(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Or(conds...))
}
func (u userDo) Select(conds ...field.Expr) *userDo {
return u.withDO(u.DO.Select(conds...))
}
func (u userDo) Where(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Where(conds...))
}
func (u userDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *userDo {
return u.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (u userDo) Order(conds ...field.Expr) *userDo {
return u.withDO(u.DO.Order(conds...))
}
func (u userDo) Distinct(cols ...field.Expr) *userDo {
return u.withDO(u.DO.Distinct(cols...))
}
func (u userDo) Omit(cols ...field.Expr) *userDo {
return u.withDO(u.DO.Omit(cols...))
}
func (u userDo) Join(table schema.Tabler, on ...field.Expr) *userDo {
return u.withDO(u.DO.Join(table, on...))
}
func (u userDo) LeftJoin(table schema.Tabler, on ...field.Expr) *userDo {
return u.withDO(u.DO.LeftJoin(table, on...))
}
func (u userDo) RightJoin(table schema.Tabler, on ...field.Expr) *userDo {
return u.withDO(u.DO.RightJoin(table, on...))
}
func (u userDo) Group(cols ...field.Expr) *userDo {
return u.withDO(u.DO.Group(cols...))
}
func (u userDo) Having(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Having(conds...))
}
func (u userDo) Limit(limit int) *userDo {
return u.withDO(u.DO.Limit(limit))
}
func (u userDo) Offset(offset int) *userDo {
return u.withDO(u.DO.Offset(offset))
}
func (u userDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *userDo {
return u.withDO(u.DO.Scopes(funcs...))
}
func (u userDo) Unscoped() *userDo {
return u.withDO(u.DO.Unscoped())
}
func (u userDo) Create(values ...*entity.User) error {
if len(values) == 0 {
return nil
}
return u.DO.Create(values)
}
func (u userDo) CreateInBatches(values []*entity.User, batchSize int) error {
return u.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (u userDo) Save(values ...*entity.User) error {
if len(values) == 0 {
return nil
}
return u.DO.Save(values)
}
func (u userDo) First() (*entity.User, error) {
if result, err := u.DO.First(); err != nil {
return nil, err
} else {
return result.(*entity.User), nil
}
}
func (u userDo) Take() (*entity.User, error) {
if result, err := u.DO.Take(); err != nil {
return nil, err
} else {
return result.(*entity.User), nil
}
}
func (u userDo) Last() (*entity.User, error) {
if result, err := u.DO.Last(); err != nil {
return nil, err
} else {
return result.(*entity.User), nil
}
}
func (u userDo) Find() ([]*entity.User, error) {
result, err := u.DO.Find()
return result.([]*entity.User), err
}
func (u userDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.User, err error) {
buf := make([]*entity.User, 0, batchSize)
err = u.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (u userDo) FindInBatches(result *[]*entity.User, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return u.DO.FindInBatches(result, batchSize, fc)
}
func (u userDo) Attrs(attrs ...field.AssignExpr) *userDo {
return u.withDO(u.DO.Attrs(attrs...))
}
func (u userDo) Assign(attrs ...field.AssignExpr) *userDo {
return u.withDO(u.DO.Assign(attrs...))
}
func (u userDo) Joins(fields ...field.RelationField) *userDo {
for _, _f := range fields {
u = *u.withDO(u.DO.Joins(_f))
}
return &u
}
func (u userDo) Preload(fields ...field.RelationField) *userDo {
for _, _f := range fields {
u = *u.withDO(u.DO.Preload(_f))
}
return &u
}
func (u userDo) FirstOrInit() (*entity.User, error) {
if result, err := u.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*entity.User), nil
}
}
func (u userDo) FirstOrCreate() (*entity.User, error) {
if result, err := u.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*entity.User), nil
}
}
func (u userDo) FindByPage(offset int, limit int) (result []*entity.User, count int64, err error) {
result, err = u.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = u.Offset(-1).Limit(-1).Count()
return
}
func (u userDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = u.Count()
if err != nil {
return
}
err = u.Offset(offset).Limit(limit).Scan(result)
return
}
func (u userDo) Scan(result interface{}) (err error) {
return u.DO.Scan(result)
}
func (u userDo) Delete(models ...*entity.User) (result gen.ResultInfo, err error) {
return u.DO.Delete(models)
}
func (u *userDo) withDO(do gen.Dao) *userDo {
u.DO = *do.(*gen.DO)
return u
}

@ -0,0 +1,66 @@
<p align="center">
<img src="https://raw.githubusercontent.com/go-sonic/resources/master/logo/logo.png" />
</p>
<p align="center"><b>Sonic </b> [ˈsɒnɪk] ,Sonic 是一个用Golang开发的博客平台高效快速.</p>
<p align="center">
<a href="https://github.com/go-sonic/sonic/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/go-sonic/sonic.svg?style=flat-square&include_prereleases" /></a>
<a href="https://github.com/go-sonic/sonic/releases"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/go-sonic/sonic/total.svg?style=flat-square" /></a>
<a href="https://hub.docker.com/r/go-sonic/sonic"><img alt="Docker pulls" src="https://img.shields.io/docker/pulls/go-sonic/sonic?style=flat-square" /></a>
<a href="https://github.com/go-sonic/sonic/commits"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/go-sonic/sonic.svg?style=flat-square" /></a>
<a href="https://github.com/go-sonic/sonic/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/go-sonic/sonic/Sonic%20CI?style=flat-square" /></a>
<br />
<a href="https://t.me/go_sonic">Telegram 频道</a>
</p>
## 📖 介绍
Sonic 意为声速的、声音的,正如它的名字一样, sonic 致力于成为最快速的开源博客平台。
感谢 [Halo](https://github.com/halo-dev/) 项目组本项目的灵感来自Halo前端项目Fork自[Console](https://github.com/halo-dev)
## 🚀 Features:
- 支持多种类型的数据库SQLite、MySQL(TODO: PostgreSQL)
- 体积小: 安装包仅仅只有10Mb
- 高性能: 文章详情页可以达到1000 QPS(压测环境是: Intel Xeon Platinum 8260 4C 8G ,SQLite3)
- 支持更换主题
- 支持 Linux、Windows、Mac OS等主流操作系统支持x86、x64、Arm、Arm64、MIPS等指令集架构
- 支持对象存储(MINIO、Google Cloud、AWS、AliYun)
## 🧰 安装
### 下载对应平台的安装包
> 根据你的操作系统和指令集下载对应的安装包
```bash
wget https://github.com/go-sonic/sonic/releases/download/v1.0.0/sonic-linux-64.zip -O sonic.zip
```
### 解压
```bash
unzip sonic.zip
```
### 运行
> 可以通过 -config选项来指定配置文件的位置
```bash
cd sonic
./sonic -config conf/config.yaml
```
**然后你就可以通过浏览器访问sonic了默认的端口是8080**
后台管理路径是 http://ip:port/admin
## TODO
- [ ] i18n
- [ ] PostgreSQL
- [ ] 更好的错误处理
- [ ] 插件系统(基于 Wasm)
- [ ] 使用新的web框架([Hertz](https://github.com/cloudwego/hertz))
## 📄 License
Source code in `sonic` is available under the [MIT License](/LICENSE.md).

@ -0,0 +1,70 @@
package event
import (
"context"
"reflect"
"sync"
"go.uber.org/zap"
"github.com/go-sonic/sonic/log"
)
type Listener func(ctx context.Context, event Event) error
type Bus interface {
Publish(ctx context.Context, event Event)
Subscribe(eventType string, listener Listener)
UnSubscribe(eventType string, listener Listener)
}
type syncLocalBus struct {
listeners sync.Map
logger *zap.Logger
}
func NewSyncEventBus(logger *zap.Logger) Bus {
return &syncLocalBus{
logger: logger,
}
}
func (e *syncLocalBus) Publish(ctx context.Context, event Event) {
defer func() {
if err := recover(); err != nil {
log.CtxError(ctx, "event panic", zap.String("event", event.EventType()), zap.Stack("stack"), zap.Any("err", err))
}
}()
if listeners, ok := e.listeners.Load(event.EventType()); ok {
for _, listener := range listeners.([]Listener) {
err := listener(ctx, event)
if err != nil {
e.logger.Error("error in event listener", zap.Any("event", event.EventType()), zap.Error(err))
}
}
}
}
func (e *syncLocalBus) Subscribe(eventType string, listener Listener) {
if listeners, ok := e.listeners.Load(eventType); ok {
listeners = append(listeners.([]Listener), listener)
e.listeners.Store(eventType, listeners)
} else {
listeners := make([]Listener, 0)
listeners = append(listeners, listener)
e.listeners.Store(eventType, listeners)
}
}
func (e *syncLocalBus) UnSubscribe(eventType string, listener Listener) {
if listeners, ok := e.listeners.Load(eventType); ok && len(listeners.([]Listener)) > 0 {
target := reflect.ValueOf(listener).Pointer()
var filtered []Listener
for _, i := range listeners.([]Listener) {
if reflect.ValueOf(i).Pointer() != target {
filtered = append(filtered, i)
}
}
e.listeners.Store(eventType, filtered)
}
}

@ -0,0 +1,96 @@
package event
import (
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/model/entity"
)
type Event interface {
EventType() string
}
const (
LogEventName = "LogEvent"
StartEventName = "StartEvent"
UserUpdateEventName = "UserUpdateEvent"
ThemeUpdateEventName = "ThemeUpdateEvent"
OptionUpdateEventName = "OptionUpdateEvent"
ThemeActivatedEventName = "ThemeActivatedEvent"
ThemeFileUpdatedEventName = "ThemeFileUpdatedEvent"
PostUpdateEventName = "PostUpdateEvent"
CommentNewEventName = "CommentNewEvent"
CommentReplyEventName = "CommentReplayEvent"
)
type LogEvent struct {
LogKey string
LogType consts.LogType
Content string
IpAddress string
}
func (*LogEvent) EventType() string {
return LogEventName
}
type StartEvent struct{}
func (*StartEvent) EventType() string {
return StartEventName
}
type UserUpdateEvent struct {
UserID int32
}
func (*UserUpdateEvent) EventType() string {
return UserUpdateEventName
}
type ThemeUpdateEvent struct{}
func (*ThemeUpdateEvent) EventType() string {
return ThemeUpdateEventName
}
type OptionUpdateEvent struct{}
func (o *OptionUpdateEvent) EventType() string {
return OptionUpdateEventName
}
type ThemeActivatedEvent struct{}
func (t *ThemeActivatedEvent) EventType() string {
return ThemeActivatedEventName
}
type ThemeFileUpdatedEvent struct{}
func (t *ThemeFileUpdatedEvent) EventType() string {
return ThemeFileUpdatedEventName
}
type PostUpdateEvent struct {
PostID int32
}
func (p *PostUpdateEvent) EventType() string {
return PostUpdateEventName
}
type CommentNewEvent struct {
Comment *entity.Comment
}
func (c *CommentNewEvent) EventType() string {
return CommentNewEventName
}
type CommentReplyEvent struct {
Comment *entity.Comment
}
func (c *CommentReplyEvent) EventType() string {
return CommentReplyEventName
}

@ -0,0 +1,257 @@
package listener
import (
"bytes"
"context"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/event"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/template"
"github.com/go-sonic/sonic/util"
)
type CommentListener struct {
OptionService service.OptionService
PostService service.PostService
PostAssembler assembler.PostAssembler
JournalService service.JournalService
SheetService service.SheetService
ThemeService service.ThemeService
EmailService service.EmailService
UserService service.UserService
BaseCommentService service.BaseCommentService
Template *template.Template
}
func NewCommentListener(
optionService service.OptionService,
postService service.PostService,
journalService service.JournalService,
sheetService service.SheetService,
bus event.Bus,
postAssembler assembler.PostAssembler,
themeService service.ThemeService,
emailService service.EmailService,
userService service.UserService,
template *template.Template,
baseCommentService service.BaseCommentService,
) {
c := &CommentListener{
OptionService: optionService,
PostService: postService,
PostAssembler: postAssembler,
JournalService: journalService,
SheetService: sheetService,
ThemeService: themeService,
EmailService: emailService,
UserService: userService,
Template: template,
BaseCommentService: baseCommentService,
}
bus.Subscribe(event.CommentNewEventName, c.HandleCommentNew)
bus.Subscribe(event.CommentReplyEventName, c.HandleCommentReply)
}
func (c *CommentListener) HandleCommentNew(ctx context.Context, ce event.Event) error {
newCommentNotice, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.CommentNewNotice, property.CommentNewNotice.DefaultValue)
if err != nil {
return err
}
if !newCommentNotice.(bool) {
return nil
}
commentEvent, ok := ce.(*event.CommentNewEvent)
if !ok {
return nil
}
enabledAbsolutePath, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.GlobalAbsolutePathEnabled, false)
if err != nil {
return err
}
blogBaseURL, err := c.OptionService.GetBlogBaseURL(ctx)
if err != nil {
return err
}
comment := commentEvent.Comment
data := make(map[string]interface{})
var subject string
if comment.Type == consts.CommentTypePost || comment.Type == consts.CommentTypeSheet {
post, err := c.PostService.GetByPostID(ctx, commentEvent.Comment.PostID)
if err != nil {
return nil
}
postDTO, err := c.PostAssembler.ConvertToMinimalDTO(ctx, post)
if err != nil {
return nil
}
data["pageFullPath"] = util.IfElse(enabledAbsolutePath.(bool), postDTO.FullPath, blogBaseURL+postDTO.FullPath).(string)
data["pageTitle"] = postDTO.Title
data["author"] = comment.Author
data["content"] = comment.Content
data["email"] = comment.Email
data["status"] = comment.Status
data["createTime"] = comment.CreateTime
data["authorUrl"] = comment.AuthorURL
if comment.Type == consts.CommentTypePost {
subject = "Your blog post 《" + postDTO.Title + "》 has a new comment"
} else {
subject = "Your blog page 《" + postDTO.Title + "》 has a new comment"
}
} else if comment.Type == consts.CommentTypeJournal {
journalPrefix, err := c.OptionService.GetJournalPrefix(ctx)
if err != nil {
return err
}
journals, err := c.JournalService.GetByJournalIDs(ctx, []int32{comment.PostID})
if err != nil {
return err
}
if len(journals) == 0 {
return nil
}
journal := journals[comment.PostID]
data["pageFullPath"] = blogBaseURL + "/" + journalPrefix
data["pageTitle"] = journal.CreateTime.Format("2006-01-02 03:04")
data["author"] = comment.Author
data["content"] = comment.Content
data["email"] = comment.Email
data["status"] = comment.Status
data["createTime"] = comment.CreateTime
data["authorUrl"] = comment.AuthorURL
subject = "Your blog journal has a new comment"
}
template := "common/mail_template/mail_notice"
if exist, err := c.ThemeService.TemplateExist(ctx, "mail_template/mail_notice.tmpl"); err != nil && exist {
t, err := c.ThemeService.Render(ctx, "mail_template/mail_notice")
if err == nil {
template = t
}
}
content := bytes.Buffer{}
err = c.Template.ExecuteTemplate(&content, template, data)
if err != nil {
return err
}
users, err := c.UserService.GetAllUser(ctx)
if err != nil {
return err
}
return c.EmailService.SendTemplateEmail(ctx, users[0].Email, subject, content.String())
}
func (c *CommentListener) HandleCommentReply(ctx context.Context, ce event.Event) error {
commentReplyNotice, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.CommentReplyNotice, property.CommentNewNotice.DefaultValue)
if err != nil {
return err
}
if !commentReplyNotice.(bool) {
return nil
}
commentEvent, ok := ce.(*event.CommentReplyEvent)
if !ok {
return nil
}
comment := commentEvent.Comment
if comment.Status != consts.CommentStatusPublished {
return nil
}
parentComment, err := c.BaseCommentService.GetByID(ctx, comment.ParentID)
if err != nil {
return err
}
if !parentComment.AllowNotification || parentComment.Status != consts.CommentStatusPublished {
return nil
}
blogTitle, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.BlogTitle, "")
if err != nil {
return err
}
enabledAbsolutePath, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.GlobalAbsolutePathEnabled, false)
if err != nil {
return err
}
blogBaseURL, err := c.OptionService.GetBlogBaseURL(ctx)
if err != nil {
return err
}
data := make(map[string]interface{})
var subject string
if comment.Type == consts.CommentTypePost || comment.Type == consts.CommentTypeSheet {
post, err := c.PostService.GetByPostID(ctx, commentEvent.Comment.PostID)
if err != nil {
return nil
}
postDTO, err := c.PostAssembler.ConvertToMinimalDTO(ctx, post)
if err != nil {
return nil
}
data["pageFullPath"] = util.IfElse(enabledAbsolutePath.(bool), postDTO.FullPath, blogBaseURL+postDTO.FullPath).(string)
data["pageTitle"] = postDTO.Title
data["baseAuthor"] = parentComment.Author
data["baseContent"] = parentComment.Content
data["replyAuthor"] = comment.Author
data["replyContent"] = comment.Content
data["baseAuthorEmail"] = parentComment.Email
data["replyAuthorEmail"] = comment.Email
data["status"] = comment.Status
data["createTime"] = comment.CreateTime
data["authorUrl"] = comment.AuthorURL
if comment.Type == consts.CommentTypePost {
subject = "You have a new reply in the 《" + post.Title + "》 article you comment on " + blogTitle.(string)
} else {
subject = "You have a new reply in the 《" + post.Title + "》 page you comment on " + blogTitle.(string)
}
} else if comment.Type == consts.CommentTypeJournal {
blogBaseURL, err := c.OptionService.GetBlogBaseURL(ctx)
if err != nil {
return err
}
journalPrefix, err := c.OptionService.GetJournalPrefix(ctx)
if err != nil {
return err
}
journals, err := c.JournalService.GetByJournalIDs(ctx, []int32{comment.PostID})
if err != nil {
return err
}
if len(journals) == 0 {
return nil
}
journal := journals[comment.PostID]
data["pageFullPath"] = blogBaseURL + "/" + journalPrefix
data["pageTitle"] = journal.CreateTime.Format("2006-01-02 03:04")
data["baseAuthor"] = parentComment.Author
data["baseContent"] = parentComment.Content
data["replyAuthor"] = comment.Author
data["replyContent"] = comment.Content
data["baseAuthorEmail"] = parentComment.Email
data["replyAuthorEmail"] = comment.Email
data["status"] = comment.Status
data["createTime"] = comment.CreateTime
data["authorUrl"] = comment.AuthorURL
subject = "You have a new reply in the journal page you comment on " + blogTitle.(string)
}
template := "common/mail_template/mail_reply"
if exist, err := c.ThemeService.TemplateExist(ctx, "mail_template/mail_reply.tmpl"); err != nil && exist {
t, err := c.ThemeService.Render(ctx, "mail_template/mail_reply")
if err == nil {
template = t
}
}
content := bytes.Buffer{}
err = c.Template.ExecuteTemplate(&content, template, data)
if err != nil {
return err
}
users, err := c.UserService.GetAllUser(ctx)
if err != nil {
return err
}
return c.EmailService.SendTemplateEmail(ctx, users[0].Email, subject, content.String())
}

@ -0,0 +1,37 @@
package listener
import (
"context"
"gorm.io/gorm"
"github.com/go-sonic/sonic/dal"
"github.com/go-sonic/sonic/event"
"github.com/go-sonic/sonic/model/entity"
)
type LogEventListener struct {
db *gorm.DB
}
func NewLogEventListener(db *gorm.DB, bus event.Bus) {
l := &LogEventListener{
db: db,
}
bus.Subscribe(event.LogEventName, l.HandleEvent)
}
func (l *LogEventListener) HandleEvent(ctx context.Context, logEvent event.Event) error {
log, ok := logEvent.(*event.LogEvent)
if !ok {
return nil
}
logDAL := dal.Use(dal.GetDBByCtx(ctx)).Log
logEntity := &entity.Log{
Content: log.Content,
IPAddress: log.IpAddress,
LogKey: log.LogKey,
Type: log.LogType,
}
return logDAL.WithContext(ctx).Create(logEntity)
}

@ -0,0 +1,61 @@
package listener
import (
"context"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/event"
"github.com/go-sonic/sonic/service"
)
type PostUpdateListener struct {
CategoryService service.CategoryService
PostCategoryService service.PostCategoryService
PostService service.PostService
}
func NewPostUpdateListener(bus event.Bus,
categoryService service.CategoryService,
postCategoryService service.PostCategoryService,
postService service.PostService,
) {
p := &PostUpdateListener{
PostCategoryService: postCategoryService,
PostService: postService,
CategoryService: categoryService,
}
bus.Subscribe(event.PostUpdateEventName, p.HandlePostUpdateEvent)
}
func (p *PostUpdateListener) HandlePostUpdateEvent(ctx context.Context, postUpdateEvent event.Event) error {
postID := postUpdateEvent.(*event.PostUpdateEvent).PostID
categories, err := p.PostCategoryService.ListCategoryByPostID(ctx, postID)
if err != nil {
return err
}
postStatus := consts.PostStatusPublished
for _, category := range categories {
if category.Type == consts.CategoryTypeIntimate {
postStatus = consts.PostStatusIntimate
}
}
post, err := p.PostService.GetByPostID(ctx, postID)
if err != nil {
return err
}
if post.Status == consts.PostStatusRecycle || post.Status == consts.PostStatusDraft {
return nil
}
if post.Password != "" {
postStatus = consts.PostStatusIntimate
}
if post.Status == postStatus {
return nil
}
_, err = p.PostService.UpdateStatus(ctx, postID, postStatus)
return err
}

@ -0,0 +1,91 @@
package listener
import (
"context"
"time"
"go.uber.org/zap"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/dal"
"github.com/go-sonic/sonic/event"
"github.com/go-sonic/sonic/log"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
)
type StartListener struct {
db *gorm.DB
optionService service.OptionService
bus event.Bus
}
func NewStartListener(db *gorm.DB, optionService service.OptionService, bus event.Bus) {
s := StartListener{
db: db,
optionService: optionService,
bus: bus,
}
bus.Subscribe(event.StartEventName, s.HandleEvent)
}
func (s *StartListener) HandleEvent(ctx context.Context, startEvent event.Event) error {
if _, ok := startEvent.(*event.StartEvent); !ok {
return nil
}
consts.StartTime = time.Now()
err := s.createOptions()
if err != nil {
log.Error("create options err", zap.Error(err))
}
if dal.DBType == consts.DBTypeMySQL {
err = dal.DB.Session(&gorm.Session{Context: ctx}).Raw("SELECT VERSION()").Scan(&consts.DatabaseVersion).Error
} else if dal.DBType == consts.DBTypeSQLite {
err = dal.DB.Session(&gorm.Session{Context: ctx}).Raw("SELECT SQLITE_VERSION()").Scan(&consts.DatabaseVersion).Error
}
if err != nil {
return err
}
_ = s.printStartInfo(ctx)
return nil
}
func (s *StartListener) createOptions() error {
ctx := context.Background()
ctx = dal.SetCtxDB(ctx, dal.GetDBByCtx(ctx).Session(&gorm.Session{
Logger: dal.DB.Logger.LogMode(logger.Warn),
}))
optionDAL := dal.Use(dal.GetDBByCtx(ctx)).Option
options, err := optionDAL.WithContext(ctx).Find()
if err != nil {
return err
}
toCreate := make([]*entity.Option, 0)
out:
for _, p := range property.AllProperty {
for _, o := range options {
if p.KeyValue == o.OptionKey {
continue out
}
}
toCreate = append(toCreate, p.ConvertToOption())
}
return optionDAL.WithContext(ctx).Create(toCreate...)
}
func (s *StartListener) printStartInfo(ctx context.Context) error {
blogURL, err := s.optionService.GetBlogBaseURL(ctx)
if err != nil {
return err
}
site := logger.BlueBold + "Sonic started at " + blogURL + logger.Reset
log.Info(site)
adminSite := logger.BlueBold + "Sonic admin started at " + blogURL + "/admin" + logger.Reset
log.Info(adminSite)
return nil
}

@ -0,0 +1,207 @@
package listener
import (
"context"
"path/filepath"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"github.com/go-sonic/sonic/config"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/dal"
"github.com/go-sonic/sonic/event"
"github.com/go-sonic/sonic/handler"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/template"
)
type TemplateConfigListener struct {
Template *template.Template
ThemeService service.ThemeService
OptionService service.ClientOptionService
UserService service.UserService
Logger *zap.Logger
Config *config.Config
Router *gin.Engine
}
func NewTemplateConfigListener(bus event.Bus,
template *template.Template,
themeService service.ThemeService,
optionService service.ClientOptionService,
logger *zap.Logger,
userService service.UserService,
config *config.Config, server *handler.Server,
) {
t := &TemplateConfigListener{
Template: template,
ThemeService: themeService,
OptionService: optionService,
Logger: logger,
UserService: userService,
Config: config,
Router: server.Router,
}
bus.Subscribe(event.ThemeUpdateEventName, t.HandleThemeUpdateEvent)
bus.Subscribe(event.UserUpdateEventName, t.HandleUserUpdateEvent)
bus.Subscribe(event.OptionUpdateEventName, t.HandleOptionUpdateEvent)
bus.Subscribe(event.StartEventName, t.HandleStartEvent)
bus.Subscribe(event.ThemeActivatedEventName, t.HandleThemeUpdateEvent)
}
func (t *TemplateConfigListener) HandleThemeUpdateEvent(ctx context.Context, themeUpdateEvent event.Event) error {
return t.loadThemeConfig(ctx)
}
func (t *TemplateConfigListener) HandleUserUpdateEvent(ctx context.Context, userUpdateEvent event.Event) error {
return t.loadUser(ctx)
}
func (t *TemplateConfigListener) HandleOptionUpdateEvent(ctx context.Context, optionUpdateEvent event.Event) error {
return t.loadOption(ctx)
}
func (t *TemplateConfigListener) HandleStartEvent(ctx context.Context, startEvent event.Event) error {
ctx = dal.SetCtxDB(ctx, dal.GetDBByCtx(ctx).Session(&gorm.Session{
Logger: dal.DB.Logger.LogMode(logger.Warn),
}))
err := t.loadThemeConfig(ctx)
if err != nil {
return err
}
err = t.loadUser(ctx)
if err != nil {
return err
}
err = t.loadOption(ctx)
if err != nil {
return err
}
err = t.loadThemeTemplate(ctx)
if err != nil {
return err
}
err = t.registerTemplateStaticFileRoute(ctx)
return err
}
func (t *TemplateConfigListener) HandleThemeFileUpdateEvent(ctx context.Context, themeFileUpdateEvent event.Event) error {
return t.loadThemeTemplate(ctx)
}
func (t *TemplateConfigListener) loadThemeTemplate(ctx context.Context) error {
theme, err := t.ThemeService.GetActivateTheme(ctx)
if err != nil {
return err
}
err = t.Template.Load([]string{filepath.Join(t.Config.Sonic.TemplateDir, "common"), theme.ThemePath})
return err
}
func (t *TemplateConfigListener) loadThemeConfig(ctx context.Context) error {
theme, err := t.ThemeService.GetActivateTheme(ctx)
if err != nil {
return nil
}
isEnabledAbsolutePath, err := t.OptionService.IsEnabledAbsolutePath(ctx)
if err != nil {
return err
}
blogBaseURL, err := t.OptionService.GetBlogBaseURL(ctx)
if err != nil {
return err
}
themeBasePath := ""
if isEnabledAbsolutePath {
themeBasePath = blogBaseURL + "/themes/" + theme.FolderName
} else {
themeBasePath = "/themes/" + theme.FolderName
}
themeSetting, err := t.ThemeService.GetThemeSettingMap(ctx, theme.ID)
if err != nil {
return err
}
t.Template.SetSharedVariable("theme_base", themeBasePath)
t.Template.SetSharedVariable("theme", theme)
t.Template.SetSharedVariable("settings", themeSetting)
t.Logger.Debug("load theme success", zap.String("theme", theme.Name))
return nil
}
func (t *TemplateConfigListener) loadUser(ctx context.Context) error {
users, err := t.UserService.GetAllUser(ctx)
if err != nil {
return err
}
if len(users) == 0 {
return nil
}
user := users[0]
user.Password = ""
user.MfaKey = ""
user.MfaType = consts.MFANone
t.Template.SetSharedVariable("user", user)
t.Logger.Debug("load user success", zap.Any("user", user))
return nil
}
func (t *TemplateConfigListener) loadOption(ctx context.Context) error {
options, err := t.OptionService.ListAllOption(ctx)
if err != nil {
return err
}
optionMap := make(map[string]interface{})
for _, option := range options {
optionMap[option.Key] = option.Value
}
blogBaseURL := t.OptionService.GetOrByDefault(ctx, property.BlogUrl)
blogTitle := t.OptionService.GetOrByDefault(ctx, property.BlogTitle)
blogLogo := t.OptionService.GetOrByDefault(ctx, property.BlogLogo)
globalAbsolutePathEnabled := t.OptionService.GetOrByDefault(ctx, property.GlobalAbsolutePathEnabled)
seoKeywords := t.OptionService.GetOrByDefault(ctx, property.SeoKeywords)
seoDescription := t.OptionService.GetOrByDefault(ctx, property.SeoDescription)
journalPrefix := t.OptionService.GetOrByDefault(ctx, property.JournalsPrefix)
archivePrefix := t.OptionService.GetOrByDefault(ctx, property.ArchivesPrefix)
categoryPrefix := t.OptionService.GetOrByDefault(ctx, property.CategoriesPrefix)
tagPrefix := t.OptionService.GetOrByDefault(ctx, property.TagsPrefix)
linkPrefix := t.OptionService.GetOrByDefault(ctx, property.LinksPrefix)
photoPrefix := t.OptionService.GetOrByDefault(ctx, property.PhotosPrefix)
urlContext := "/"
if globalAbsolutePathEnabled.(bool) {
urlContext = blogBaseURL.(string) + "/"
}
t.Template.SetSharedVariable("version", consts.SonicVersion)
t.Template.SetSharedVariable("options", optionMap)
t.Template.SetSharedVariable("context", urlContext)
t.Template.SetSharedVariable("globalAbsolutePathEnabled", globalAbsolutePathEnabled.(bool))
t.Template.SetSharedVariable("blog_title", blogTitle)
t.Template.SetSharedVariable("blog_logo", blogLogo)
t.Template.SetSharedVariable("blog_url", blogBaseURL)
t.Template.SetSharedVariable("seo_keywords", seoKeywords)
t.Template.SetSharedVariable("seo_description", seoDescription)
t.Template.SetSharedVariable("rss_url", blogBaseURL.(string)+"/rss.xml")
t.Template.SetSharedVariable("atom_url", blogBaseURL.(string)+"/atom.xml")
t.Template.SetSharedVariable("sitemap_xml_url", blogBaseURL.(string)+"/sitemap.xml")
t.Template.SetSharedVariable("sitemap_html_url", blogBaseURL.(string)+"/sitemap.html")
t.Template.SetSharedVariable("links_url", urlContext+linkPrefix.(string))
t.Template.SetSharedVariable("photos_url", urlContext+photoPrefix.(string))
t.Template.SetSharedVariable("journals_url", urlContext+journalPrefix.(string))
t.Template.SetSharedVariable("archives_url", urlContext+archivePrefix.(string))
t.Template.SetSharedVariable("categories_url", urlContext+categoryPrefix.(string))
t.Template.SetSharedVariable("tags_url", urlContext+tagPrefix.(string))
return nil
}
func (t *TemplateConfigListener) registerTemplateStaticFileRoute(ctx context.Context) error {
theme, err := t.ThemeService.GetActivateTheme(ctx)
if err != nil {
return nil
}
t.Router.StaticFS("/themes/"+theme.FolderName, gin.Dir(theme.ThemePath, false))
return nil
}

@ -0,0 +1,7 @@
GENERATE_DIR="./cmd/generate"
cd $GENERATE_DIR || exit
echo "Start Generating"
go run .

@ -0,0 +1,93 @@
module github.com/go-sonic/sonic
go 1.19
require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible
github.com/disintegration/imaging v1.6.2
github.com/fsnotify/fsnotify v1.6.0
github.com/gin-contrib/cors v1.4.0
github.com/gin-gonic/gin v1.8.1
github.com/go-playground/locales v0.14.0
github.com/go-playground/universal-translator v0.18.0
github.com/go-playground/validator/v10 v10.11.1
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.3.0
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
github.com/minio/minio-go/v7 v7.0.42
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.3.0
github.com/spf13/viper v1.13.0
github.com/yeqown/go-qrcode v1.5.10
go.uber.org/dig v1.15.0
go.uber.org/fx v1.18.2
go.uber.org/zap v1.23.0
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b
gopkg.in/yaml.v2 v2.4.0
gorm.io/driver/mysql v1.4.3
gorm.io/driver/sqlite v1.4.3
gorm.io/gen v0.3.17
gorm.io/gorm v1.24.0
gorm.io/plugin/dbresolver v1.3.0
)
require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/goccy/go-json v0.9.7 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.1 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.15 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.1.12 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/datatypes v1.0.7 // indirect
gorm.io/hints v1.1.0 // indirect
)

817
go.sum

@ -0,0 +1,817 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible h1:QoRMR0TCctLDqBCMyOu1eXdZyMw3F7uGA9qPn2J4+R8=
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU=
github.com/denisenkom/go-mssqldb v0.12.2 h1:1OcPn5GBIobjWNd+8yjfHNIaFX14B1pWI3F9HZy5KXw=
github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw=
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12/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/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.42 h1:fP56plNR/Tkw/+Xczw9NL5TGxe5gJDvgd8LidNR3BEI=
github.com/minio/minio-go/v7 v7.0.42/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
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.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/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=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/yeqown/go-qrcode v1.5.10 h1:87GCtypY9oOadB7yGRW4qlgAoDOop8G4JEdqOQwu1WI=
github.com/yeqown/go-qrcode v1.5.10/go.mod h1:0FVyJ3MV9fF5lfAgTr0INcy+3rupmJhjp0mL3Z9eYXk=
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/dig v1.15.0 h1:vq3YWr8zRj1eFGC7Gvf907hE0eRjPTZ1d3xHadD6liE=
go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM=
go.uber.org/fx v1.18.2 h1:bUNI6oShr+OVFQeU8cDNbnN7VFsu+SsjHzUF51V/GAU=
go.uber.org/fx v1.18.2/go.mod h1:g0V1KMQ66zIRk8bLu3Ea5Jt2w/cHlOIp4wdRsgh0JaY=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
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-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
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=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
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=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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.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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM=
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/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=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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/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=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
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/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=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.0.7 h1:8NhJN4+annFjwV1WufDhFiPjdUvV1lSGUdg1UCjQIWY=
gorm.io/datatypes v1.0.7/go.mod h1:l9qkCuy0CdzDEop9HKUdcnC9gHC2sRlaFtHkTzsZRqg=
gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
gorm.io/driver/mysql v1.4.0/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/postgres v1.3.4/go.mod h1:y0vEuInFKJtijuSGu9e5bs5hzzSzPK+LancpKpvbRBw=
gorm.io/driver/postgres v1.4.1 h1:DutsKq2LK2Ag65q/+VygWth0/L4GAVOp+sCtg6WzZjs=
gorm.io/driver/postgres v1.4.1/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw=
gorm.io/driver/sqlite v1.1.6/go.mod h1:W8LmC/6UvVbHKah0+QOC7Ja66EaZXHwUTjgXY8YNWX8=
gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg=
gorm.io/driver/sqlite v1.4.1/go.mod h1:AKZZCAoFfOWHF7Nd685Iq8Uywc0i9sWJlzpoE/INzsw=
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
gorm.io/driver/sqlserver v1.3.1/go.mod h1:w25Vrx2BG+CJNUu/xKbFhaKlGxT/nzRkhWCCoptX8tQ=
gorm.io/driver/sqlserver v1.4.0 h1:3fjbsNkr/YqocSBW5CP16Lq6+APjRrWMzu7NbkXr9QU=
gorm.io/driver/sqlserver v1.4.0/go.mod h1:P8BSbBwkdzXURYx3pWUSEAABRQU0vxbd6xk5+53pg7g=
gorm.io/gen v0.3.17 h1:vIgdvpBnXd3c1HOc7chuWlj0cM6w6ZimGZUDada6nwI=
gorm.io/gen v0.3.17/go.mod h1:uQsfditHYOjbibLcsXkFqSIfBmRFWwucMEa2WrcqX8k=
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74=
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw=
gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y=
gorm.io/plugin/dbresolver v1.3.0 h1:uFDX3bIuH9Lhj5LY2oyqR/bU6pqWuDgas35NAPF4X3M=
gorm.io/plugin/dbresolver v1.3.0/go.mod h1:Pr7p5+JFlgDaiM6sOrli5olekJD16YRunMyA2S7ZfKk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

@ -0,0 +1,100 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type AdminHandler struct {
OptionService service.OptionService
AdminService service.AdminService
TwoFactorMFAService service.TwoFactorTOTPMFAService
}
func NewAdminHandler(optionService service.OptionService, adminService service.AdminService, twoFactorMFA service.TwoFactorTOTPMFAService) *AdminHandler {
return &AdminHandler{
OptionService: optionService,
AdminService: adminService,
TwoFactorMFAService: twoFactorMFA,
}
}
func (a *AdminHandler) IsInstalled(ctx *gin.Context) (interface{}, error) {
return a.OptionService.GetOrByDefaultWithErr(ctx, property.IsInstalled, false)
}
func (a *AdminHandler) AuthPreCheck(ctx *gin.Context) (interface{}, error) {
var loginParam param.LoginParam
err := ctx.ShouldBindJSON(&loginParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.BadParam.Wrapf(err, "")
}
user, err := a.AdminService.Authenticate(ctx, loginParam)
if err != nil {
return nil, err
}
return &dto.LoginPreCheckDTO{NeedMFACode: a.TwoFactorMFAService.UseMFA(user.MfaType)}, nil
}
func (a *AdminHandler) Auth(ctx *gin.Context) (interface{}, error) {
var loginParam param.LoginParam
err := ctx.ShouldBindJSON(&loginParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.BadParam.Wrapf(err, "").WithStatus(xerr.StatusBadRequest)
}
return a.AdminService.Auth(ctx, loginParam)
}
func (a *AdminHandler) LogOut(ctx *gin.Context) (interface{}, error) {
err := a.AdminService.ClearToken(ctx)
return nil, err
}
func (a *AdminHandler) SendResetCode(ctx *gin.Context) (interface{}, error) {
var resetPasswordParam param.ResetPasswordParam
err := ctx.ShouldBindJSON(&resetPasswordParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.BadParam.Wrapf(err, "").WithStatus(xerr.StatusBadRequest)
}
return nil, a.AdminService.SendResetPasswordCode(ctx, resetPasswordParam)
}
func (a *AdminHandler) RefreshToken(ctx *gin.Context) (interface{}, error) {
refreshToken := ctx.Param("refreshToken")
if refreshToken == "" {
return nil, xerr.BadParam.New("refreshToken参数为空").WithStatus(xerr.StatusBadRequest).
WithMsg("refreshToken 参数不能为空")
}
return a.AdminService.RefreshToken(ctx, refreshToken)
}
func (a *AdminHandler) GetEnvironments(ctx *gin.Context) (interface{}, error) {
return a.AdminService.GetEnvironments(ctx), nil
}
func (a *AdminHandler) GetLogFiles(ctx *gin.Context) (interface{}, error) {
lines, err := util.MustGetQueryInt64(ctx, "lines")
if err != nil {
return nil, err
}
return a.AdminService.GetLogFiles(ctx, lines)
}

@ -0,0 +1,118 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type AttachmentHandler struct {
AttachmentService service.AttachmentService
}
func NewAttachmentHandler(attachmentService service.AttachmentService) *AttachmentHandler {
return &AttachmentHandler{
AttachmentService: attachmentService,
}
}
func (a *AttachmentHandler) QueryAttachment(ctx *gin.Context) (interface{}, error) {
queryParam := &param.AttachmentQuery{}
err := ctx.ShouldBindWith(queryParam, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("param error ")
}
attachments, totalCount, err := a.AttachmentService.Page(ctx, queryParam)
if err != nil {
return nil, err
}
attachmentDTOs, err := a.AttachmentService.ConvertToDTOs(ctx, attachments)
if err != nil {
return nil, err
}
return dto.NewPage(attachmentDTOs, totalCount, queryParam.Page), nil
}
func (a *AttachmentHandler) GetAttachmentByID(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
if id < 0 {
return nil, xerr.BadParam.New("id < 0").WithStatus(xerr.StatusBadRequest).WithMsg("param error")
}
return a.AttachmentService.GetAttachment(ctx, id)
}
func (a *AttachmentHandler) UploadAttachment(ctx *gin.Context) (interface{}, error) {
fileHeader, err := ctx.FormFile("file")
if err != nil {
return nil, xerr.WithMsg(err, "上传文件错误").WithStatus(xerr.StatusBadRequest)
}
return a.AttachmentService.Upload(ctx, fileHeader)
}
func (a *AttachmentHandler) UploadAttachments(ctx *gin.Context) (interface{}, error) {
form, _ := ctx.MultipartForm()
if len(form.File) == 0 {
return nil, xerr.BadParam.New("empty files").WithStatus(xerr.StatusBadRequest).WithMsg("empty files")
}
files := form.File["files"]
attachmentDTOs := make([]*dto.AttachmentDTO, 0)
for _, file := range files {
attachment, err := a.AttachmentService.Upload(ctx, file)
if err != nil {
return nil, err
}
attachmentDTOs = append(attachmentDTOs, attachment)
}
return attachmentDTOs, nil
}
func (a *AttachmentHandler) UpdateAttachment(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
updateParam := &param.AttachmentUpdate{}
err = ctx.ShouldBind(updateParam)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("param error ")
}
return a.AttachmentService.Update(ctx, id, updateParam)
}
func (a *AttachmentHandler) DeleteAttachment(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
return a.AttachmentService.Delete(ctx, id)
}
func (a *AttachmentHandler) DeleteAttachmentInBatch(ctx *gin.Context) (interface{}, error) {
ids := make([]int32, 0)
err := ctx.ShouldBind(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
return a.AttachmentService.DeleteBatch(ctx, ids)
}
func (a *AttachmentHandler) GetAllMediaType(ctx *gin.Context) (interface{}, error) {
return a.AttachmentService.GetAllMediaTypes(ctx)
}
func (a *AttachmentHandler) GetAllTypes(ctx *gin.Context) (interface{}, error) {
attachmentTypes, err := a.AttachmentService.GetAllTypes(ctx)
if err != nil {
return nil, err
}
return attachmentTypes, nil
}

@ -0,0 +1,215 @@
package admin
import (
"net/http"
"path/filepath"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/config"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/log"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type BackupHandler struct {
BackupService service.BackupService
}
func NewBackupHandler(backupService service.BackupService) *BackupHandler {
return &BackupHandler{
BackupService: backupService,
}
}
func (b *BackupHandler) GetWorkDirBackup(ctx *gin.Context) (interface{}, error) {
filename, err := util.ParamString(ctx, "filename")
if err != nil {
return nil, err
}
return b.BackupService.GetBackup(ctx, filepath.Join(config.BackupDir, filename), service.WholeSite)
}
func (b *BackupHandler) GetDataBackup(ctx *gin.Context) (interface{}, error) {
filename, err := util.ParamString(ctx, "filename")
if err != nil {
return nil, err
}
return b.BackupService.GetBackup(ctx, filepath.Join(config.DataExportDir, filename), service.JsonData)
}
func (b *BackupHandler) GetMarkDownBackup(ctx *gin.Context) (interface{}, error) {
filename, err := util.ParamString(ctx, "filename")
if err != nil {
return nil, err
}
return b.BackupService.GetBackup(ctx, filepath.Join(config.BackupMarkdownDir, filename), service.Markdown)
}
func (b *BackupHandler) BackupWholeSite(ctx *gin.Context) (interface{}, error) {
return b.BackupService.BackupWholeSite(ctx)
}
func (b *BackupHandler) ListBackups(ctx *gin.Context) (interface{}, error) {
return b.BackupService.ListFiles(ctx, config.BackupDir, service.WholeSite)
}
func (b *BackupHandler) HandleWorkDir(ctx *gin.Context) {
path := ctx.Request.URL.Path
if path == "/api/admin/backups/work-dir/fetch" {
wrapHandler(b.GetWorkDirBackup)(ctx)
return
}
if path == "/api/admin/backups/work-dir" || path == "/api/admin/backups/work-dir/" {
wrapHandler(b.ListBackups)(ctx)
return
}
b.DownloadBackups(ctx)
}
func (b *BackupHandler) DownloadBackups(ctx *gin.Context) {
filename := ctx.Param("path")
if filename == "" {
ctx.AbortWithStatusJSON(http.StatusBadRequest, &dto.BaseDTO{
Status: http.StatusBadRequest,
Message: "Filename parameter does not exist",
})
return
}
filePath, err := b.BackupService.GetBackupFilePath(ctx, config.BackupDir, filename)
if err != nil {
log.CtxErrorf(ctx, "err=%+v", err)
status := xerr.GetHttpStatus(err)
ctx.JSON(status, &dto.BaseDTO{Status: status, Message: xerr.GetMessage(err)})
}
ctx.File(filePath)
}
func (b *BackupHandler) DeleteBackups(ctx *gin.Context) (interface{}, error) {
filename, err := util.ParamString(ctx, "filename")
if err != nil {
return nil, err
}
return nil, b.BackupService.DeleteFile(ctx, config.BackupDir, filename)
}
func (b *BackupHandler) ImportMarkdown(ctx *gin.Context) (interface{}, error) {
fileHeader, err := ctx.FormFile("file")
if err != nil {
return nil, xerr.WithMsg(err, "上传文件错误").WithStatus(xerr.StatusBadRequest)
}
return nil, b.BackupService.ImportMarkdown(ctx, fileHeader)
}
func (b *BackupHandler) ExportData(ctx *gin.Context) (interface{}, error) {
return b.BackupService.ExportData(ctx)
}
func (b *BackupHandler) HandleData(ctx *gin.Context) {
path := ctx.Request.URL.Path
if path == "/api/admin/backups/data/fetch" {
wrapHandler(b.GetDataBackup)(ctx)
return
}
if path == "/api/admin/backups/data" || path == "/api/admin/backups/data/" {
wrapHandler(b.ListExportData)(ctx)
return
}
b.DownloadData(ctx)
}
func (b *BackupHandler) ListExportData(ctx *gin.Context) (interface{}, error) {
return b.BackupService.ListFiles(ctx, config.DataExportDir, service.JsonData)
}
func (b *BackupHandler) DownloadData(ctx *gin.Context) {
filename := ctx.Param("path")
if filename == "" {
ctx.AbortWithStatusJSON(http.StatusBadRequest, &dto.BaseDTO{
Status: http.StatusBadRequest,
Message: "Filename parameter does not exist",
})
}
filePath, err := b.BackupService.GetBackupFilePath(ctx, config.DataExportDir, filename)
if err != nil {
log.CtxErrorf(ctx, "err=%+v", err)
status := xerr.GetHttpStatus(err)
ctx.JSON(status, &dto.BaseDTO{Status: status, Message: xerr.GetMessage(err)})
}
ctx.File(filePath)
}
func (b *BackupHandler) DeleteDataFile(ctx *gin.Context) (interface{}, error) {
filename, ok := ctx.GetQuery("filename")
if !ok || filename == "" {
return nil, xerr.BadParam.New("no filename param").WithStatus(xerr.StatusBadRequest).WithMsg("no filename param")
}
return nil, b.BackupService.DeleteFile(ctx, config.DataExportDir, filename)
}
func (b *BackupHandler) ExportMarkdown(ctx *gin.Context) (interface{}, error) {
var exportMarkdownParam param.ExportMarkdown
err := ctx.ShouldBindJSON(&exportMarkdownParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
return b.BackupService.ExportMarkdown(ctx, exportMarkdownParam.NeedFrontMatter)
}
func (b *BackupHandler) ListMarkdowns(ctx *gin.Context) (interface{}, error) {
return b.BackupService.ListFiles(ctx, config.BackupMarkdownDir, service.Markdown)
}
func (b *BackupHandler) DeleteMarkdowns(ctx *gin.Context) (interface{}, error) {
filename, err := util.ParamString(ctx, "filename")
if err != nil {
return nil, err
}
return nil, b.BackupService.DeleteFile(ctx, config.BackupMarkdownDir, filename)
}
func (b *BackupHandler) DownloadMarkdown(ctx *gin.Context) {
filename := ctx.Param("filename")
if filename == "" {
ctx.AbortWithStatusJSON(http.StatusBadRequest, &dto.BaseDTO{
Status: http.StatusBadRequest,
Message: "Filename parameter does not exist",
})
return
}
filePath, err := b.BackupService.GetBackupFilePath(ctx, config.BackupMarkdownDir, filename)
if err != nil {
log.CtxErrorf(ctx, "err=%+v", err)
status := xerr.GetHttpStatus(err)
ctx.JSON(status, &dto.BaseDTO{Status: status, Message: xerr.GetMessage(err)})
}
ctx.File(filePath)
}
type wrapperHandler func(ctx *gin.Context) (interface{}, error)
func wrapHandler(handler wrapperHandler) gin.HandlerFunc {
return func(ctx *gin.Context) {
data, err := handler(ctx)
if err != nil {
log.CtxErrorf(ctx, "err=%+v", err)
status := xerr.GetHttpStatus(err)
ctx.JSON(status, &dto.BaseDTO{Status: status, Message: xerr.GetMessage(err)})
return
}
ctx.JSON(http.StatusOK, &dto.BaseDTO{
Status: http.StatusOK,
Data: data,
Message: "OK",
})
}
}

@ -0,0 +1,130 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type CategoryHandler struct {
CategoryService service.CategoryService
}
func NewCategoryHandler(categoryService service.CategoryService) *CategoryHandler {
return &CategoryHandler{
CategoryService: categoryService,
}
}
func (c *CategoryHandler) GetCategoryByID(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "categoryID")
if err != nil {
return nil, err
}
category, err := c.CategoryService.GetByID(ctx, int32(id))
if err != nil {
return nil, err
}
return c.CategoryService.ConvertToCategoryDTO(ctx, category)
}
func (c *CategoryHandler) ListAllCategory(ctx *gin.Context) (interface{}, error) {
categoryQuery := struct {
*param.Sort
More *bool `json:"more" form:"more"`
}{}
err := ctx.ShouldBindQuery(&categoryQuery)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if categoryQuery.Sort == nil || len(categoryQuery.Sort.Fields) == 0 {
categoryQuery.Sort = &param.Sort{Fields: []string{"priority,asc"}}
}
if categoryQuery.More != nil && *categoryQuery.More {
return c.CategoryService.ListCategoryWithPostCountDTO(ctx, categoryQuery.Sort)
}
categories, err := c.CategoryService.ListAll(ctx, categoryQuery.Sort)
if err != nil {
return nil, err
}
return c.CategoryService.ConvertToCategoryDTOs(ctx, categories)
}
func (c *CategoryHandler) ListAsTree(ctx *gin.Context) (interface{}, error) {
var sort param.Sort
err := ctx.ShouldBindQuery(&sort)
if err != nil {
return nil, err
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "priority,asc")
}
return c.CategoryService.ListAsTree(ctx, &sort, false)
}
func (c *CategoryHandler) CreateCategory(ctx *gin.Context) (interface{}, error) {
var categoryParam param.Category
err := ctx.ShouldBindJSON(&categoryParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
category, err := c.CategoryService.Create(ctx, &categoryParam)
if err != nil {
return nil, err
}
return c.CategoryService.ConvertToCategoryDTO(ctx, category)
}
func (c *CategoryHandler) UpdateCategory(ctx *gin.Context) (interface{}, error) {
var categoryParam param.Category
err := ctx.ShouldBindJSON(&categoryParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
categoryID, err := util.ParamInt32(ctx, "categoryID")
if err != nil {
return nil, err
}
categoryParam.ID = categoryID
category, err := c.CategoryService.Update(ctx, &categoryParam)
if err != nil {
return nil, err
}
return c.CategoryService.ConvertToCategoryDTO(ctx, category)
}
func (c *CategoryHandler) UpdateCategoryBatch(ctx *gin.Context) (interface{}, error) {
categoryParams := make([]*param.Category, 0)
err := ctx.ShouldBindJSON(&categoryParams)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
categories, err := c.CategoryService.UpdateBatch(ctx, categoryParams)
if err != nil {
return nil, err
}
return c.CategoryService.ConvertToCategoryDTOs(ctx, categories)
}
func (c *CategoryHandler) DeleteCategory(ctx *gin.Context) (interface{}, error) {
categoryID, err := util.ParamInt32(ctx, "categoryID")
if err != nil {
return nil, err
}
return nil, c.CategoryService.Delete(ctx, categoryID)
}

@ -0,0 +1,229 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type JournalCommentHandler struct {
JournalCommentService service.JournalCommentService
OptionService service.OptionService
JournalService service.JournalService
JournalCommentAssembler assembler.JournalCommentAssembler
}
func NewJournalCommentHandler(journalCommentService service.JournalCommentService, optionService service.OptionService, journalService service.JournalService, journalCommentAssembler assembler.JournalCommentAssembler) *JournalCommentHandler {
return &JournalCommentHandler{
JournalCommentService: journalCommentService,
OptionService: optionService,
JournalService: journalService,
JournalCommentAssembler: journalCommentAssembler,
}
}
func (j *JournalCommentHandler) ListJournalComment(ctx *gin.Context) (interface{}, error) {
var commentQuery param.CommentQuery
err := ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
comments, totalCount, err := j.JournalCommentService.Page(ctx, commentQuery, consts.CommentTypeJournal)
if err != nil {
return nil, err
}
commentDTOs, err := j.JournalCommentAssembler.ConvertToWithJournal(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commentDTOs, totalCount, commentQuery.Page), nil
}
func (j *JournalCommentHandler) ListJournalCommentLatest(ctx *gin.Context) (interface{}, error) {
top, err := util.MustGetQueryInt32(ctx, "top")
if err != nil {
return nil, err
}
commentQuery := param.CommentQuery{
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Page: param.Page{PageNum: 0, PageSize: int(top)},
}
comments, _, err := j.JournalCommentService.Page(ctx, commentQuery, consts.CommentTypeSheet)
if err != nil {
return nil, err
}
return j.JournalCommentAssembler.ConvertToWithJournal(ctx, comments)
}
func (j *JournalCommentHandler) ListJournalCommentAsTree(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
pageNum, err := util.MustGetQueryInt32(ctx, "page")
if err != nil {
return nil, err
}
pageSize, err := j.OptionService.GetOrByDefaultWithErr(ctx, property.CommentPageSize, property.CommentPageSize.DefaultValue)
if err != nil {
return nil, err
}
page := param.Page{PageSize: pageSize.(int), PageNum: int(pageNum)}
allComments, err := j.JournalCommentService.GetByContentID(ctx, journalID, &param.Sort{Fields: []string{"createTime,desc"}})
if err != nil {
return nil, err
}
commentVOs, totalCount, err := j.JournalCommentAssembler.PageConvertToVOs(ctx, allComments, page)
if err != nil {
return nil, err
}
return dto.NewPage(commentVOs, totalCount, page), nil
}
func (j *JournalCommentHandler) ListJournalCommentWithParent(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
pageNum, err := util.MustGetQueryInt32(ctx, "page")
if err != nil {
return nil, err
}
pageSize, err := j.OptionService.GetOrByDefaultWithErr(ctx, property.CommentPageSize, property.CommentPageSize.DefaultValue)
if err != nil {
return nil, err
}
page := param.Page{PageSize: pageSize.(int), PageNum: int(pageNum)}
comments, totalCount, err := j.JournalCommentService.Page(ctx, param.CommentQuery{
ContentID: &journalID,
Page: page,
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
}, consts.CommentTypePost)
if err != nil {
return nil, err
}
commentsWithParent, err := j.JournalCommentAssembler.ConvertToWithParentVO(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commentsWithParent, totalCount, page), nil
}
func (j *JournalCommentHandler) CreateJournalComment(ctx *gin.Context) (interface{}, error) {
var commentParam *param.Comment
err := ctx.ShouldBindJSON(&commentParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if commentParam.AuthorURL != "" {
err = util.Validate.Var(commentParam.AuthorURL, "url")
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("url is not available")
}
}
commentParam.CommentType = consts.CommentTypeJournal
comment, err := j.JournalCommentService.CreateBy(ctx, commentParam)
if err != nil {
return nil, err
}
return j.JournalCommentAssembler.ConvertToDTO(ctx, comment)
}
func (j *JournalCommentHandler) UpdateJournalCommentStatus(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt64(ctx, "commentID")
if err != nil {
return nil, err
}
strStatus, err := util.ParamString(ctx, "status")
if err != nil {
return nil, err
}
status, err := consts.CommentStatusFromString(strStatus)
if err != nil {
return nil, err
}
return j.JournalCommentService.UpdateStatus(ctx, commentID, status)
}
func (j *JournalCommentHandler) UpdateJournalComment(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt64(ctx, "commentID")
if err != nil {
return nil, err
}
var commentParam *param.Comment
err = ctx.ShouldBindJSON(&commentParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if commentParam.AuthorURL != "" {
err = util.Validate.Var(commentParam.AuthorURL, "url")
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("url is not available")
}
}
comment, err := j.JournalCommentService.UpdateBy(ctx, commentID, commentParam)
if err != nil {
return nil, err
}
return j.JournalCommentAssembler.ConvertToDTO(ctx, comment)
}
func (j *JournalCommentHandler) UpdateJournalStatusBatch(ctx *gin.Context) (interface{}, error) {
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, err
}
ids := make([]int64, 0)
err = ctx.ShouldBindJSON(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
comments, err := j.JournalCommentService.UpdateStatusBatch(ctx, ids, consts.CommentStatus(status))
if err != nil {
return nil, err
}
return j.JournalCommentAssembler.ConvertToDTOList(ctx, comments)
}
func (j *JournalCommentHandler) DeleteJournalComment(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt64(ctx, "commentID")
if err != nil {
return nil, err
}
return nil, j.JournalCommentService.Delete(ctx, commentID)
}
func (j *JournalCommentHandler) DeleteJournalCommentBatch(ctx *gin.Context) (interface{}, error) {
ids := make([]int64, 0)
err := ctx.ShouldBindJSON(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
return nil, j.JournalCommentService.DeleteBatch(ctx, ids)
}

@ -0,0 +1,236 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type PostCommentHandler struct {
PostCommentService service.PostCommentService
OptionService service.OptionService
PostService service.PostService
PostAssembler assembler.PostAssembler
PostCommentAssembler assembler.PostCommentAssembler
}
func NewPostCommentHandler(
postCommentHandler service.PostCommentService,
optionService service.OptionService,
postService service.PostService,
postAssembler assembler.PostAssembler,
postCommentAssembler assembler.PostCommentAssembler,
) *PostCommentHandler {
return &PostCommentHandler{
PostCommentService: postCommentHandler,
OptionService: optionService,
PostService: postService,
PostAssembler: postAssembler,
PostCommentAssembler: postCommentAssembler,
}
}
func (p *PostCommentHandler) ListPostComment(ctx *gin.Context) (interface{}, error) {
var commentQuery param.CommentQuery
err := ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
comments, totalCount, err := p.PostCommentService.Page(ctx, commentQuery, consts.CommentTypePost)
if err != nil {
return nil, err
}
commentDTOs, err := p.PostCommentAssembler.ConvertToWithPost(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commentDTOs, totalCount, commentQuery.Page), nil
}
func (p *PostCommentHandler) ListPostCommentLatest(ctx *gin.Context) (interface{}, error) {
top, err := util.MustGetQueryInt32(ctx, "top")
if err != nil {
return nil, err
}
commentQuery := param.CommentQuery{
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Page: param.Page{PageNum: 0, PageSize: int(top)},
}
comments, _, err := p.PostCommentService.Page(ctx, commentQuery, consts.CommentTypePost)
if err != nil {
return nil, err
}
return p.PostCommentAssembler.ConvertToWithPost(ctx, comments)
}
func (p *PostCommentHandler) ListPostCommentAsTree(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
pageNum, err := util.MustGetQueryInt32(ctx, "page")
if err != nil {
return nil, err
}
pageSize, err := p.OptionService.GetOrByDefaultWithErr(ctx, property.CommentPageSize, property.CommentPageSize.DefaultValue)
if err != nil {
return nil, err
}
page := param.Page{PageSize: pageSize.(int), PageNum: int(pageNum)}
allComments, err := p.PostCommentService.GetByContentID(ctx, postID, &param.Sort{Fields: []string{"createTime,desc"}})
if err != nil {
return nil, err
}
commentVOs, totalCount, err := p.PostCommentAssembler.PageConvertToVOs(ctx, allComments, page)
if err != nil {
return nil, err
}
return dto.NewPage(commentVOs, totalCount, page), nil
}
func (p *PostCommentHandler) ListPostCommentWithParent(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
pageNum, err := util.MustGetQueryInt32(ctx, "page")
if err != nil {
return nil, err
}
pageSize, err := p.OptionService.GetOrByDefaultWithErr(ctx, property.CommentPageSize, property.CommentPageSize.DefaultValue)
if err != nil {
return nil, err
}
page := param.Page{PageNum: int(pageNum), PageSize: pageSize.(int)}
comments, totalCount, err := p.PostCommentService.Page(ctx, param.CommentQuery{
ContentID: &postID,
Page: page,
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
}, consts.CommentTypePost)
if err != nil {
return nil, err
}
commentsWithParent, err := p.PostCommentAssembler.ConvertToWithParentVO(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commentsWithParent, totalCount, page), nil
}
func (p *PostCommentHandler) CreatePostComment(ctx *gin.Context) (interface{}, error) {
var commentParam *param.Comment
err := ctx.ShouldBindJSON(&commentParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if commentParam.AuthorURL != "" {
err = util.Validate.Var(commentParam.AuthorURL, "url")
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("url is not available")
}
}
commentParam.CommentType = consts.CommentTypeSheet
comment, err := p.PostCommentService.CreateBy(ctx, commentParam)
if err != nil {
return nil, err
}
return p.PostCommentAssembler.ConvertToDTO(ctx, comment)
}
func (p *PostCommentHandler) UpdatePostComment(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt64(ctx, "commentID")
if err != nil {
return nil, err
}
var commentParam *param.Comment
err = ctx.ShouldBindJSON(&commentParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if commentParam.AuthorURL != "" {
err = util.Validate.Var(commentParam.AuthorURL, "url")
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("url is not available")
}
}
comment, err := p.PostCommentService.UpdateBy(ctx, commentID, commentParam)
if err != nil {
return nil, err
}
return p.PostCommentAssembler.ConvertToDTO(ctx, comment)
}
func (p *PostCommentHandler) UpdatePostCommentStatus(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt32(ctx, "commentID")
if err != nil {
return nil, err
}
strStatus, err := util.ParamString(ctx, "status")
if err != nil {
return nil, err
}
status, err := consts.CommentStatusFromString(strStatus)
if err != nil {
return nil, err
}
return p.PostCommentService.UpdateStatus(ctx, int64(commentID), status)
}
func (p *PostCommentHandler) UpdatePostCommentStatusBatch(ctx *gin.Context) (interface{}, error) {
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, err
}
ids := make([]int64, 0)
err = ctx.ShouldBindJSON(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
comments, err := p.PostCommentService.UpdateStatusBatch(ctx, ids, consts.CommentStatus(status))
if err != nil {
return nil, err
}
return p.PostCommentAssembler.ConvertToDTOList(ctx, comments)
}
func (p *PostCommentHandler) DeletePostComment(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt64(ctx, "commentID")
if err != nil {
return nil, err
}
return nil, p.PostCommentService.Delete(ctx, commentID)
}
func (p *PostCommentHandler) DeletePostCommentBatch(ctx *gin.Context) (interface{}, error) {
ids := make([]int64, 0)
err := ctx.ShouldBindJSON(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
return nil, p.PostCommentService.DeleteBatch(ctx, ids)
}

@ -0,0 +1,246 @@
package admin
import (
"context"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/model/vo"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type SheetCommentHandler struct {
SheetCommentService service.SheetCommentService
BaseCommentService service.BaseCommentService
OptionService service.OptionService
SheetService service.SheetService
SheetAssembler assembler.SheetAssembler
SheetCommentAssembler assembler.SheetCommentAssembler
}
func NewSheetCommentHandler(
sheetCommentService service.SheetCommentService,
baseCommentService service.BaseCommentService,
optionService service.OptionService,
sheetService service.SheetService,
sheetAssembler assembler.SheetAssembler,
sheetCommentAssembler assembler.SheetCommentAssembler,
) *SheetCommentHandler {
return &SheetCommentHandler{
SheetCommentService: sheetCommentService,
BaseCommentService: baseCommentService,
OptionService: optionService,
SheetService: sheetService,
SheetAssembler: sheetAssembler,
SheetCommentAssembler: sheetCommentAssembler,
}
}
func (s *SheetCommentHandler) ListSheetComment(ctx *gin.Context) (interface{}, error) {
var commentQuery param.CommentQuery
err := ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
comments, totalCount, err := s.SheetCommentService.Page(ctx, commentQuery, consts.CommentTypeSheet)
if err != nil {
return nil, err
}
commentDTOs, err := s.ConvertToWithSheet(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commentDTOs, totalCount, commentQuery.Page), nil
}
func (s *SheetCommentHandler) ListSheetCommentLatest(ctx *gin.Context) (interface{}, error) {
top, err := util.MustGetQueryInt32(ctx, "top")
if err != nil {
return nil, err
}
commentQuery := param.CommentQuery{
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Page: param.Page{PageNum: 0, PageSize: int(top)},
}
comments, _, err := s.SheetCommentService.Page(ctx, commentQuery, consts.CommentTypeSheet)
if err != nil {
return nil, err
}
return s.ConvertToWithSheet(ctx, comments)
}
func (s *SheetCommentHandler) ListSheetCommentAsTree(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
pageNum, err := util.MustGetQueryInt32(ctx, "page")
if err != nil {
return nil, err
}
pageSize, err := s.OptionService.GetOrByDefaultWithErr(ctx, property.CommentPageSize, property.CommentPageSize.DefaultValue)
if err != nil {
return nil, err
}
page := param.Page{PageSize: pageSize.(int), PageNum: int(pageNum)}
allComments, err := s.SheetCommentService.GetByContentID(ctx, postID, &param.Sort{Fields: []string{"createTime,desc"}})
if err != nil {
return nil, err
}
commentVOs, totalCount, err := s.SheetCommentAssembler.PageConvertToVOs(ctx, allComments, page)
if err != nil {
return nil, err
}
return dto.NewPage(commentVOs, totalCount, page), nil
}
func (s *SheetCommentHandler) ListSheetCommentWithParent(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
pageNum, err := util.MustGetQueryInt32(ctx, "page")
if err != nil {
return nil, err
}
pageSize, err := s.OptionService.GetOrByDefaultWithErr(ctx, property.CommentPageSize, property.CommentPageSize.DefaultValue)
if err != nil {
return nil, err
}
page := param.Page{PageSize: pageSize.(int), PageNum: int(pageNum)}
comments, totalCount, err := s.SheetCommentService.Page(ctx, param.CommentQuery{
ContentID: &postID,
Page: page,
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
}, consts.CommentTypePost)
if err != nil {
return nil, err
}
commentsWithParent, err := s.SheetCommentAssembler.ConvertToWithParentVO(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commentsWithParent, totalCount, page), nil
}
func (s *SheetCommentHandler) CreateSheetComment(ctx *gin.Context) (interface{}, error) {
var commentParam *param.Comment
err := ctx.ShouldBindJSON(&commentParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if commentParam.AuthorURL != "" {
err = util.Validate.Var(commentParam.AuthorURL, "url")
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("url is not available")
}
}
commentParam.CommentType = consts.CommentTypeSheet
comment, err := s.BaseCommentService.CreateBy(ctx, commentParam)
if err != nil {
return nil, err
}
return s.SheetCommentAssembler.ConvertToDTO(ctx, comment)
}
func (s *SheetCommentHandler) UpdateSheetCommentStatus(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt32(ctx, "commentID")
if err != nil {
return nil, err
}
strStatus, err := util.ParamString(ctx, "status")
if err != nil {
return nil, err
}
status, err := consts.CommentStatusFromString(strStatus)
if err != nil {
return nil, err
}
return s.SheetCommentService.UpdateStatus(ctx, int64(commentID), status)
}
func (s *SheetCommentHandler) UpdateSheetCommentStatusBatch(ctx *gin.Context) (interface{}, error) {
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, err
}
ids := make([]int64, 0)
err = ctx.ShouldBindJSON(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
comments, err := s.SheetCommentService.UpdateStatusBatch(ctx, ids, consts.CommentStatus(status))
if err != nil {
return nil, err
}
return s.SheetCommentAssembler.ConvertToDTOList(ctx, comments)
}
func (s *SheetCommentHandler) DeleteSheetComment(ctx *gin.Context) (interface{}, error) {
commentID, err := util.ParamInt32(ctx, "commentID")
if err != nil {
return nil, err
}
return nil, s.SheetCommentService.Delete(ctx, int64(commentID))
}
func (s *SheetCommentHandler) DeleteSheetCommentBatch(ctx *gin.Context) (interface{}, error) {
ids := make([]int64, 0)
err := ctx.ShouldBindJSON(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
return nil, s.SheetCommentService.DeleteBatch(ctx, ids)
}
func (s *SheetCommentHandler) ConvertToWithSheet(ctx context.Context, comments []*entity.Comment) ([]*vo.SheetCommentWithSheet, error) {
postIDs := make([]int32, 0, len(comments))
for _, comment := range comments {
postIDs = append(postIDs, comment.PostID)
}
posts, err := s.SheetService.GetByPostIDs(ctx, postIDs)
if err != nil {
return nil, err
}
result := make([]*vo.SheetCommentWithSheet, 0, len(comments))
for _, comment := range comments {
commentDTO, err := s.SheetCommentAssembler.ConvertToDTO(ctx, comment)
if err != nil {
return nil, err
}
commentWithSheet := &vo.SheetCommentWithSheet{
Comment: *commentDTO,
}
result = append(result, commentWithSheet)
post, ok := posts[comment.PostID]
if ok {
commentWithSheet.PostMinimal, err = s.SheetAssembler.ConvertToMinimalDTO(ctx, post)
if err != nil {
return nil, err
}
}
}
return result, nil
}

@ -0,0 +1,26 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util/xerr"
)
type EmailHandler struct {
EmailService service.EmailService
}
func NewEmailHandler(emailService service.EmailService) *EmailHandler {
return &EmailHandler{
EmailService: emailService,
}
}
func (e *EmailHandler) Test(ctx *gin.Context) (interface{}, error) {
p := &param.TestEmail{}
if err := ctx.ShouldBindJSON(p); err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("param error ")
}
return nil, e.EmailService.SendTextEmail(ctx, p.To, p.Subject, p.Content)
}

@ -0,0 +1,29 @@
package admin
import "github.com/go-sonic/sonic/injection"
func init() {
injection.Provide(
NewAdminHandler,
NewAttachmentHandler,
NewCategoryHandler,
NewBackupHandler,
NewInstallHandler,
NewJournalHandler,
NewJournalCommentHandler,
NewLinkHandler,
NewLogHandler,
NewMenuHandler,
NewOptionHandler,
NewPhotoHandler,
NewPostHandler,
NewPostCommentHandler,
NewSheetHandler,
NewSheetCommentHandler,
NewStatisticHandler,
NewTagHandler,
NewThemeHandler,
NewUserHandler,
NewEmailHandler,
)
}

@ -0,0 +1,37 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util/xerr"
)
type InstallHandler struct {
InstallService service.InstallService
}
func NewInstallHandler(installService service.InstallService) *InstallHandler {
return &InstallHandler{
InstallService: installService,
}
}
func (i *InstallHandler) InstallBlog(ctx *gin.Context) (interface{}, error) {
var installParam param.Install
err := ctx.ShouldBindJSON(&installParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
err = i.InstallService.InstallBlog(ctx, installParam)
if err != nil {
return nil, err
}
return "安装完成", nil
}

@ -0,0 +1,101 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type JournalHandler struct {
JournalService service.JournalService
}
func NewJournalHandler(journalService service.JournalService) *JournalHandler {
return &JournalHandler{
JournalService: journalService,
}
}
func (j *JournalHandler) ListJournal(ctx *gin.Context) (interface{}, error) {
var journalQuery param.JournalQuery
err := ctx.ShouldBindWith(&journalQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
journalQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
journals, totalCount, err := j.JournalService.ListJournal(ctx, journalQuery)
if err != nil {
return nil, err
}
journalDTOs, err := j.JournalService.ConvertToWithCommentDTOList(ctx, journals)
if err != nil {
return nil, err
}
return dto.NewPage(journalDTOs, totalCount, journalQuery.Page), nil
}
func (j *JournalHandler) ListLatestJournal(ctx *gin.Context) (interface{}, error) {
top, err := util.MustGetQueryInt(ctx, "top")
if err != nil {
top = 10
}
journalQuery := param.JournalQuery{
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Page: param.Page{PageNum: 0, PageSize: top},
}
journals, _, err := j.JournalService.ListJournal(ctx, journalQuery)
if err != nil {
return nil, err
}
return j.JournalService.ConvertToWithCommentDTOList(ctx, journals)
}
func (j *JournalHandler) CreateJournal(ctx *gin.Context) (interface{}, error) {
var journalParam param.Journal
err := ctx.ShouldBindJSON(&journalParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
journal, err := j.JournalService.Create(ctx, &journalParam)
if err != nil {
return nil, err
}
return j.JournalService.ConvertToDTO(journal), nil
}
func (j *JournalHandler) UpdateJournal(ctx *gin.Context) (interface{}, error) {
var journalParam param.Journal
err := ctx.ShouldBindJSON(&journalParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
return j.JournalService.Update(ctx, journalID, &journalParam)
}
func (j *JournalHandler) DeleteJournal(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
return nil, j.JournalService.Delete(ctx, int32(journalID))
}

@ -0,0 +1,102 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type LinkHandler struct {
LinkService service.LinkService
}
func NewLinkHandler(linkService service.LinkService) *LinkHandler {
return &LinkHandler{
LinkService: linkService,
}
}
func (l *LinkHandler) ListLinks(ctx *gin.Context) (interface{}, error) {
sort := param.Sort{}
err := ctx.ShouldBindWith(&sort, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithMsg(err, "sort parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "team,desc", "priority,asc")
} else {
sort.Fields = append(sort.Fields, "priority,asc")
}
links, err := l.LinkService.List(ctx, &sort)
if err != nil {
return nil, err
}
return l.LinkService.ConvertToDTOs(ctx, links), nil
}
func (l *LinkHandler) GetLinkByID(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
link, err := l.LinkService.GetByID(ctx, id)
if err != nil {
return nil, err
}
return l.LinkService.ConvertToDTO(ctx, link), nil
}
func (l *LinkHandler) CreateLink(ctx *gin.Context) (interface{}, error) {
linkParam := &param.Link{}
err := ctx.ShouldBindJSON(linkParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
link, err := l.LinkService.Create(ctx, linkParam)
if err != nil {
return nil, err
}
return l.LinkService.ConvertToDTO(ctx, link), nil
}
func (l *LinkHandler) UpdateLink(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
linkParam := &param.Link{}
err = ctx.ShouldBindJSON(linkParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
link, err := l.LinkService.Update(ctx, id, linkParam)
if err != nil {
return nil, err
}
return l.LinkService.ConvertToDTO(ctx, link), nil
}
func (l *LinkHandler) DeleteLink(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
return nil, l.LinkService.Delete(ctx, id)
}
func (l *LinkHandler) ListLinkTeams(ctx *gin.Context) (interface{}, error) {
return l.LinkService.ListTeams(ctx)
}

@ -0,0 +1,67 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type LogHandler struct {
LogService service.LogService
}
func NewLogHandler(logService service.LogService) *LogHandler {
return &LogHandler{
LogService: logService,
}
}
func (l *LogHandler) PageLatestLog(ctx *gin.Context) (interface{}, error) {
top, err := util.MustGetQueryInt32(ctx, "top")
if err != nil {
top = 10
}
logs, _, err := l.LogService.PageLog(ctx, param.Page{PageSize: int(top)}, &param.Sort{Fields: []string{"createTime,desc"}})
if err != nil {
return nil, err
}
logDTOs := make([]*dto.Log, 0, len(logs))
for _, log := range logs {
logDTOs = append(logDTOs, l.LogService.ConvertToDTO(log))
}
return logDTOs, nil
}
func (l *LogHandler) PageLog(ctx *gin.Context) (interface{}, error) {
type LogParam struct {
param.Page
*param.Sort
}
var logParam LogParam
err := ctx.ShouldBindQuery(&logParam)
if err != nil {
return nil, xerr.WithMsg(err, "parameter error").WithStatus(xerr.StatusBadRequest)
}
if logParam.Sort == nil {
logParam.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
logs, totalCount, err := l.LogService.PageLog(ctx, logParam.Page, logParam.Sort)
if err != nil {
return nil, err
}
logDTOs := make([]*dto.Log, 0, len(logs))
for _, log := range logs {
logDTOs = append(logDTOs, l.LogService.ConvertToDTO(log))
}
return dto.NewPage(logDTOs, totalCount, logParam.Page), nil
}
func (l *LogHandler) ClearLog(ctx *gin.Context) (interface{}, error) {
return nil, l.LogService.Clear(ctx)
}

@ -0,0 +1,176 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type MenuHandler struct {
MenuService service.MenuService
}
func NewMenuHandler(menuService service.MenuService) *MenuHandler {
return &MenuHandler{
MenuService: menuService,
}
}
func (m *MenuHandler) ListMenus(ctx *gin.Context) (interface{}, error) {
sort := param.Sort{}
err := ctx.ShouldBindQuery(&sort)
if err != nil {
return nil, xerr.WithMsg(err, "sort parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "team,desc", "priority,asc")
} else {
sort.Fields = append(sort.Fields, "priority,asc")
}
menus, err := m.MenuService.List(ctx, &sort)
if err != nil {
return nil, err
}
return m.MenuService.ConvertToDTOs(ctx, menus), nil
}
func (m *MenuHandler) ListMenusAsTree(ctx *gin.Context) (interface{}, error) {
sort := param.Sort{}
err := ctx.ShouldBindQuery(&sort)
if err != nil {
return nil, xerr.WithMsg(err, "sort parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "team,desc", "priority,asc")
} else {
sort.Fields = append(sort.Fields, "priority,asc")
}
menus, err := m.MenuService.ListAsTree(ctx, &sort)
if err != nil {
return nil, err
}
return menus, nil
}
func (m *MenuHandler) ListMenusAsTreeByTeam(ctx *gin.Context) (interface{}, error) {
sort := param.Sort{}
err := ctx.ShouldBindQuery(&sort)
if err != nil {
return nil, xerr.WithMsg(err, "sort parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "priority,asc")
}
menus, err := m.MenuService.ListAsTree(ctx, &sort)
if err != nil {
return nil, err
}
return menus, nil
}
func (m *MenuHandler) GetMenuByID(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
menu, err := m.MenuService.GetByID(ctx, id)
if err != nil {
return nil, err
}
return m.MenuService.ConvertToDTO(ctx, menu), nil
}
func (m *MenuHandler) CreateMenu(ctx *gin.Context) (interface{}, error) {
menuParam := &param.Menu{}
err := ctx.ShouldBindJSON(menuParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
menu, err := m.MenuService.Create(ctx, menuParam)
if err != nil {
return nil, err
}
return m.MenuService.ConvertToDTO(ctx, menu), nil
}
func (m *MenuHandler) CreateMenuBatch(ctx *gin.Context) (interface{}, error) {
menuParams := make([]*param.Menu, 0)
err := ctx.ShouldBindJSON(&menuParams)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
menus, err := m.MenuService.CreateBatch(ctx, menuParams)
if err != nil {
return nil, err
}
return m.MenuService.ConvertToDTOs(ctx, menus), nil
}
func (m *MenuHandler) UpdateMenu(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
menuParam := &param.Menu{}
err = ctx.ShouldBindJSON(menuParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
menu, err := m.MenuService.Update(ctx, id, menuParam)
if err != nil {
return nil, err
}
return m.MenuService.ConvertToDTO(ctx, menu), nil
}
func (m *MenuHandler) UpdateMenuBatch(ctx *gin.Context) (interface{}, error) {
menuParams := make([]*param.Menu, 0)
err := ctx.ShouldBindJSON(&menuParams)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
menus, err := m.MenuService.UpdateBatch(ctx, menuParams)
if err != nil {
return nil, err
}
return m.MenuService.ConvertToDTOs(ctx, menus), nil
}
func (m *MenuHandler) DeleteMenu(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
return nil, m.MenuService.Delete(ctx, id)
}
func (m *MenuHandler) DeleteMenuBatch(ctx *gin.Context) (interface{}, error) {
menuIDs := make([]int32, 0)
err := ctx.ShouldBind(&menuIDs)
if err != nil {
return nil, xerr.WithMsg(err, "menuIDs error").WithStatus(xerr.StatusBadRequest)
}
return nil, m.MenuService.DeleteBatch(ctx, menuIDs)
}
func (m *MenuHandler) ListMenuTeams(ctx *gin.Context) (interface{}, error) {
return m.MenuService.ListTeams(ctx)
}

@ -0,0 +1,105 @@
package admin
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util/xerr"
)
type OptionHandler struct {
OptionService service.OptionService
}
func NewOptionHandler(optionService service.OptionService) *OptionHandler {
return &OptionHandler{
OptionService: optionService,
}
}
func (o *OptionHandler) ListAllOptions(ctx *gin.Context) (interface{}, error) {
return o.OptionService.ListAllOption(ctx)
}
func (o *OptionHandler) SaveOption(ctx *gin.Context) (interface{}, error) {
optionParams := make([]*param.Option, 0)
err := ctx.ShouldBindJSON(&optionParams)
if err != nil {
return nil, xerr.WithMsg(err, "param error").WithStatus(xerr.StatusBadRequest)
}
optionMap := make(map[string]string, 0)
for _, option := range optionParams {
optionMap[option.Key] = option.Value
}
return nil, o.OptionService.Save(ctx, optionMap)
}
func (o *OptionHandler) ListAllOptionsAsMap(ctx *gin.Context) (interface{}, error) {
options, err := o.OptionService.ListAllOption(ctx)
if err != nil {
return nil, err
}
result := make(map[string]interface{})
for _, option := range options {
result[option.Key] = option.Value
}
return result, nil
}
func (o *OptionHandler) ListAllOptionsAsMapWithKey(ctx *gin.Context) (interface{}, error) {
keys := make([]string, 0)
err := ctx.ShouldBindJSON(&keys)
if err != nil {
return nil, xerr.WithMsg(err, "option key error").WithStatus(xerr.StatusBadRequest)
}
options, err := o.OptionService.ListAllOption(ctx)
if err != nil {
return nil, err
}
keyMap := make(map[string]struct{})
for _, key := range keys {
keyMap[key] = struct{}{}
}
result := make(map[string]interface{})
for _, option := range options {
if _, ok := keyMap[option.Key]; ok {
result[option.Key] = option.Value
}
}
return result, nil
}
func (o *OptionHandler) SaveOptionWithMap(ctx *gin.Context) (interface{}, error) {
optionMap := make(map[string]interface{}, 0)
err := ctx.ShouldBind(&optionMap)
if err != nil {
return nil, xerr.WithMsg(err, "parameter error").WithStatus(xerr.StatusBadRequest)
}
temp := make(map[string]string)
for key, value := range optionMap {
var v string
switch value := value.(type) {
case int32:
v = strconv.Itoa(int(value))
case int64:
v = strconv.FormatInt(value, 10)
case int:
v = strconv.Itoa(value)
case string:
v = value
case bool:
v = strconv.FormatBool(value)
case float64:
v = strconv.FormatFloat(value, 'f', -1, 64)
case float32:
v = strconv.FormatFloat(float64(value), 'f', -1, 32)
default:
return nil, xerr.BadParam.New("key=%v,value=%v", key, value).WithStatus(xerr.StatusBadRequest).WithMsg("Parameter type is incorrect")
}
temp[key] = v
}
return nil, o.OptionService.Save(ctx, temp)
}

@ -0,0 +1,128 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type PhotoHandler struct {
PhotoService service.PhotoService
}
func NewPhotoHandler(photoService service.PhotoService) *PhotoHandler {
return &PhotoHandler{
PhotoService: photoService,
}
}
func (p *PhotoHandler) ListPhoto(ctx *gin.Context) (interface{}, error) {
sort := param.Sort{}
err := ctx.ShouldBindQuery(&sort)
if err != nil {
return nil, xerr.WithMsg(err, "sort parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "createTime,desc")
}
photos, err := p.PhotoService.List(ctx, &sort)
if err != nil {
return nil, err
}
return p.PhotoService.ConvertToDTOs(ctx, photos), nil
}
func (p *PhotoHandler) PagePhotos(ctx *gin.Context) (interface{}, error) {
type Param struct {
param.Page
param.Sort
}
param := Param{}
err := ctx.ShouldBindQuery(&param)
if err != nil {
return nil, xerr.WithMsg(err, "parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(param.Fields) == 0 {
param.Fields = append(param.Fields, "createTime,desc")
}
photos, totalCount, err := p.PhotoService.Page(ctx, param.Page, &param.Sort)
if err != nil {
return nil, err
}
return dto.NewPage(p.PhotoService.ConvertToDTOs(ctx, photos), totalCount, param.Page), nil
}
func (p *PhotoHandler) GetPhotoByID(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
photo, err := p.PhotoService.GetByID(ctx, id)
if err != nil {
return nil, err
}
return p.PhotoService.ConvertToDTO(ctx, photo), nil
}
func (p *PhotoHandler) CreatePhoto(ctx *gin.Context) (interface{}, error) {
photoParam := &param.Photo{}
err := ctx.ShouldBindJSON(photoParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
photo, err := p.PhotoService.Create(ctx, photoParam)
if err != nil {
return nil, err
}
return p.PhotoService.ConvertToDTO(ctx, photo), nil
}
func (p *PhotoHandler) UpdatePhoto(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
photoParam := &param.Photo{}
err = ctx.ShouldBindJSON(photoParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
photo, err := p.PhotoService.Update(ctx, id, photoParam)
if err != nil {
return nil, err
}
return p.PhotoService.ConvertToDTO(ctx, photo), nil
}
func (p *PhotoHandler) DeletePhoto(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
return nil, p.PhotoService.Delete(ctx, id)
}
func (p *PhotoHandler) ListPhotoTeams(ctx *gin.Context) (interface{}, error) {
return p.PhotoService.ListTeams(ctx)
}
func (p *PhotoHandler) IncreasePhotoLike(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
return nil, p.PhotoService.IncreaseLike(ctx, id)
}

@ -0,0 +1,277 @@
package admin
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type PostHandler struct {
PostService service.PostService
PostAssembler assembler.PostAssembler
}
func NewPostHandler(postService service.PostService, postAssembler assembler.PostAssembler) *PostHandler {
return &PostHandler{
PostService: postService,
PostAssembler: postAssembler,
}
}
func (p *PostHandler) ListPosts(ctx *gin.Context) (interface{}, error) {
postQuery := param.PostQuery{}
err := ctx.ShouldBindWith(&postQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if postQuery.Sort == nil {
postQuery.Sort = &param.Sort{Fields: []string{"topPriority,desc", "createTime,desc"}}
}
posts, totalCount, err := p.PostService.Page(ctx, postQuery)
if err != nil {
return nil, err
}
if postQuery.More == nil || *postQuery.More {
postVOs, err := p.PostAssembler.ConvertToListVO(ctx, posts)
return dto.NewPage(postVOs, totalCount, postQuery.Page), err
}
postDTOs := make([]*dto.Post, 0)
for _, post := range posts {
postDTO, err := p.PostAssembler.ConvertToSimpleDTO(ctx, post)
if err != nil {
return nil, err
}
postDTOs = append(postDTOs, postDTO)
}
return dto.NewPage(postDTOs, totalCount, postQuery.Page), nil
}
func (p *PostHandler) ListLatestPosts(ctx *gin.Context) (interface{}, error) {
top, err := util.MustGetQueryInt32(ctx, "top")
if err != nil {
top = 10
}
postQuery := param.PostQuery{
Page: param.Page{
PageSize: int(top),
PageNum: 0,
},
Sort: &param.Sort{
Fields: []string{"createTime,desc"},
},
Keyword: nil,
CategoryID: nil,
More: util.BoolPtr(false),
}
posts, _, err := p.PostService.Page(ctx, postQuery)
if err != nil {
return nil, err
}
postMinimals := make([]*dto.PostMinimal, 0, len(posts))
for _, post := range posts {
postMinimal, err := p.PostAssembler.ConvertToMinimalDTO(ctx, post)
if err != nil {
return nil, err
}
postMinimals = append(postMinimals, postMinimal)
}
return postMinimals, nil
}
func (p *PostHandler) ListPostsByStatus(ctx *gin.Context) (interface{}, error) {
var postQuery param.PostQuery
err := ctx.ShouldBindWith(&postQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if postQuery.Sort == nil {
postQuery.Sort = &param.Sort{Fields: []string{"createTime,desc"}}
}
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, err
}
postQuery.Statuses = make([]*consts.PostStatus, 0)
statusType := consts.PostStatus(status)
postQuery.Statuses = append(postQuery.Statuses, &statusType)
posts, totalCount, err := p.PostService.Page(ctx, postQuery)
if err != nil {
return nil, err
}
if postQuery.More == nil {
*postQuery.More = false
}
if postQuery.More == nil {
postVOs, err := p.PostAssembler.ConvertToListVO(ctx, posts)
return dto.NewPage(postVOs, totalCount, postQuery.Page), err
}
postDTOs := make([]*dto.Post, 0)
for _, post := range posts {
postDTO, err := p.PostAssembler.ConvertToSimpleDTO(ctx, post)
if err != nil {
return nil, err
}
postDTOs = append(postDTOs, postDTO)
}
return dto.NewPage(postDTOs, totalCount, postQuery.Page), nil
}
func (p *PostHandler) GetByPostID(ctx *gin.Context) (interface{}, error) {
postIDStr := ctx.Param("postID")
postID, err := strconv.ParseInt(postIDStr, 10, 32)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
post, err := p.PostService.GetByPostID(ctx, int32(postID))
if err != nil {
return nil, err
}
postDetailVO, err := p.PostAssembler.ConvertToDetailVO(ctx, post)
if err != nil {
return nil, err
}
return postDetailVO, nil
}
func (p *PostHandler) LikePost(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
return nil, p.PostService.IncreaseLike(ctx, int32(postID))
}
func (p *PostHandler) CreatePost(ctx *gin.Context) (interface{}, error) {
var postParam param.Post
err := ctx.ShouldBindJSON(&postParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
post, err := p.PostService.Create(ctx, &postParam)
if err != nil {
return nil, err
}
return p.PostAssembler.ConvertToDetailVO(ctx, post)
}
func (p *PostHandler) UpdatePost(ctx *gin.Context) (interface{}, error) {
var postParam param.Post
err := ctx.ShouldBindJSON(&postParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
postIDStr := ctx.Param("postID")
postID, err := strconv.ParseInt(postIDStr, 10, 32)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
postDetailVO, err := p.PostService.Update(ctx, int32(postID), &postParam)
if err != nil {
return nil, err
}
return postDetailVO, nil
}
func (p *PostHandler) UpdatePostStatus(ctx *gin.Context) (interface{}, error) {
postIDStr := ctx.Param("postID")
postID, err := strconv.ParseInt(postIDStr, 10, 32)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if status < int32(consts.PostStatusPublished) || status > int32(consts.PostStatusIntimate) {
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("status error")
}
post, err := p.PostService.UpdateStatus(ctx, int32(postID), consts.PostStatus(status))
if err != nil {
return nil, err
}
return p.PostAssembler.ConvertToMinimalDTO(ctx, post)
}
func (p *PostHandler) UpdatePostStatusBatch(ctx *gin.Context) (interface{}, error) {
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, err
}
if status < int32(consts.PostStatusPublished) || status > int32(consts.PostStatusIntimate) {
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("status error")
}
ids := make([]int32, 0)
err = ctx.ShouldBind(&ids)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("post ids error")
}
return p.PostService.UpdateStatusBatch(ctx, consts.PostStatus(status), ids)
}
func (p *PostHandler) UpdatePostDraft(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
var postContentParam param.PostContent
err = ctx.ShouldBindJSON(&postContentParam)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("content param error")
}
post, err := p.PostService.UpdateDraftContent(ctx, int32(postID), postContentParam.Content)
if err != nil {
return nil, err
}
return p.PostAssembler.ConvertToDetailDTO(ctx, post)
}
func (p *PostHandler) DeletePost(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
return nil, p.PostService.Delete(ctx, postID)
}
func (p *PostHandler) DeletePostBatch(ctx *gin.Context) (interface{}, error) {
postIDs := make([]int32, 0)
err := ctx.ShouldBind(&postIDs)
if err != nil {
return nil, xerr.WithMsg(err, "postIDs error").WithStatus(xerr.StatusBadRequest)
}
return nil, p.PostService.DeleteBatch(ctx, postIDs)
}
func (p *PostHandler) PreviewPost(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
return p.PostService.Preview(ctx, int32(postID))
}

@ -0,0 +1,155 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type SheetHandler struct {
SheetService service.SheetService
PostService service.PostService
SheetAssembler assembler.SheetAssembler
}
func NewSheetHandler(sheetService service.SheetService, postService service.PostService, sheetAssembler assembler.SheetAssembler) *SheetHandler {
return &SheetHandler{
SheetService: sheetService,
PostService: postService,
SheetAssembler: sheetAssembler,
}
}
func (s *SheetHandler) GetSheetByID(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
sheet, err := s.SheetService.GetByPostID(ctx, sheetID)
if err != nil {
return nil, err
}
return s.SheetAssembler.ConvertToDetailVO(ctx, sheet)
}
func (s *SheetHandler) ListSheet(ctx *gin.Context) (interface{}, error) {
type SheetParam struct {
param.Page
Sort string `json:"sort"`
}
var sheetParam SheetParam
err := ctx.ShouldBind(&sheetParam)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
sheets, totalCount, err := s.SheetService.Page(ctx, sheetParam.Page, &param.Sort{Fields: []string{"createTime,desc"}})
if err != nil {
return nil, err
}
sheetVOs, err := s.SheetAssembler.ConvertToListVO(ctx, sheets)
if err != nil {
return nil, err
}
return dto.NewPage(sheetVOs, totalCount, sheetParam.Page), nil
}
func (s *SheetHandler) IndependentSheets(ctx *gin.Context) (interface{}, error) {
return s.SheetService.ListIndependentSheets(ctx)
}
func (s *SheetHandler) CreateSheet(ctx *gin.Context) (interface{}, error) {
var sheetParam param.Sheet
err := ctx.ShouldBindJSON(&sheetParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
sheet, err := s.SheetService.Create(ctx, &sheetParam)
if err != nil {
return nil, err
}
sheetDetailVO, err := s.SheetAssembler.ConvertToDetailVO(ctx, sheet)
if err != nil {
return nil, err
}
return sheetDetailVO, nil
}
func (s *SheetHandler) UpdateSheet(ctx *gin.Context) (interface{}, error) {
var sheetParam param.Sheet
err := ctx.ShouldBindJSON(&sheetParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
postDetailVO, err := s.SheetService.Update(ctx, sheetID, &sheetParam)
if err != nil {
return nil, err
}
return postDetailVO, nil
}
func (s *SheetHandler) UpdateSheetStatus(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.MustGetQueryInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
status, err := util.ParamInt32(ctx, "status")
if err != nil {
return nil, err
}
if status < int32(consts.PostStatusPublished) || status > int32(consts.PostStatusIntimate) {
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest).WithMsg("status error")
}
return s.SheetService.UpdateStatus(ctx, sheetID, consts.PostStatus(status))
}
func (s *SheetHandler) UpdateSheetDraft(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.MustGetQueryInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
var postContentParam param.PostContent
err = ctx.ShouldBindJSON(&postContentParam)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("content param error")
}
post, err := s.SheetService.UpdateDraftContent(ctx, int32(sheetID), postContentParam.Content)
if err != nil {
return nil, err
}
return s.SheetAssembler.ConvertToDetailDTO(ctx, post)
}
func (s *SheetHandler) DeleteSheet(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.MustGetQueryInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
return nil, s.SheetService.Delete(ctx, int32(sheetID))
}
func (s *SheetHandler) PreviewSheet(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
return s.PostService.Preview(ctx, int32(sheetID))
}

@ -0,0 +1,25 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/service"
)
type StatisticHandler struct {
StatisticService service.StatisticService
}
func NewStatisticHandler(l service.StatisticService) *StatisticHandler {
return &StatisticHandler{
StatisticService: l,
}
}
func (s *StatisticHandler) Statistics(ctx *gin.Context) (interface{}, error) {
return s.StatisticService.Statistic(ctx)
}
func (s *StatisticHandler) StatisticsWithUser(ctx *gin.Context) (interface{}, error) {
return s.StatisticService.StatisticWithUser(ctx)
}

@ -0,0 +1,101 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type TagHandler struct {
PostTagService service.PostTagService
TagService service.TagService
}
func NewTagHandler(postTagService service.PostTagService, tagService service.TagService) *TagHandler {
return &TagHandler{
PostTagService: postTagService,
TagService: tagService,
}
}
func (t *TagHandler) ListTags(ctx *gin.Context) (interface{}, error) {
sort := param.Sort{}
err := ctx.ShouldBindQuery(&sort)
if err != nil {
return nil, xerr.WithMsg(err, "sort parameter error").WithStatus(xerr.StatusBadRequest)
}
if len(sort.Fields) == 0 {
sort.Fields = append(sort.Fields, "createTime,desc")
}
more, _ := util.MustGetQueryBool(ctx, "more")
if more {
return t.PostTagService.ListAllTagWithPostCount(ctx, &sort)
}
tags, err := t.TagService.ListAll(ctx, &sort)
if err != nil {
return nil, err
}
return t.TagService.ConvertToDTOs(ctx, tags)
}
func (t *TagHandler) GetTagByID(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
tag, err := t.TagService.GetByID(ctx, id)
if err != nil {
return nil, err
}
return t.TagService.ConvertToDTO(ctx, tag)
}
func (t *TagHandler) CreateTag(ctx *gin.Context) (interface{}, error) {
tagParam := &param.Tag{}
err := ctx.ShouldBindJSON(tagParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
tag, err := t.TagService.Create(ctx, tagParam)
if err != nil {
return nil, err
}
return t.TagService.ConvertToDTO(ctx, tag)
}
func (t *TagHandler) UpdateTag(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
tagParam := &param.Tag{}
err = ctx.ShouldBindJSON(tagParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
tag, err := t.TagService.Update(ctx, id, tagParam)
if err != nil {
return nil, err
}
return t.TagService.ConvertToDTO(ctx, tag)
}
func (t *TagHandler) DeleteTag(ctx *gin.Context) (interface{}, error) {
id, err := util.ParamInt32(ctx, "id")
if err != nil {
return nil, err
}
return nil, t.TagService.Delete(ctx, id)
}

@ -0,0 +1,305 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type ThemeHandler struct {
ThemeService service.ThemeService
OptionService service.OptionService
}
func NewThemeHandler(l service.ThemeService, o service.OptionService) *ThemeHandler {
return &ThemeHandler{
ThemeService: l,
OptionService: o,
}
}
func (t *ThemeHandler) GetThemeByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeByID(ctx, themeID)
}
func (t *ThemeHandler) ListAllThemes(ctx *gin.Context) (interface{}, error) {
return t.ThemeService.ListAllTheme(ctx)
}
func (t *ThemeHandler) ListActivatedThemeFile(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.ListThemeFiles(ctx, activatedThemeID)
}
func (t *ThemeHandler) ListThemeFileByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
return t.ThemeService.ListThemeFiles(ctx, themeID)
}
func (t *ThemeHandler) GetThemeFileContent(ctx *gin.Context) (interface{}, error) {
path, err := util.MustGetQueryString(ctx, "path")
if err != nil {
return nil, err
}
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeFileContent(ctx, activatedThemeID, path)
}
func (t *ThemeHandler) GetThemeFileContentByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
path, err := util.MustGetQueryString(ctx, "path")
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeFileContent(ctx, themeID, path)
}
func (t *ThemeHandler) UpdateThemeFile(ctx *gin.Context) (interface{}, error) {
themeParam := &param.ThemeContent{}
err := ctx.ShouldBindJSON(themeParam)
if err != nil {
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
}
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return nil, t.ThemeService.UpdateThemeFile(ctx, activatedThemeID, themeParam.Path, themeParam.Content)
}
func (t *ThemeHandler) UpdateThemeFileByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
themeParam := &param.ThemeContent{}
err = ctx.ShouldBindJSON(themeParam)
if err != nil {
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
}
return nil, t.ThemeService.UpdateThemeFile(ctx, themeID, themeParam.Path, themeParam.Content)
}
func (t *ThemeHandler) ListCustomSheetTemplate(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.ListCustomTemplates(ctx, activatedThemeID, consts.ThemeCustomSheetPrefix)
}
func (t *ThemeHandler) ListCustomPostTemplate(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.ListCustomTemplates(ctx, activatedThemeID, consts.ThemeCustomPostPrefix)
}
func (t *ThemeHandler) ActivateTheme(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
return t.ThemeService.ActivateTheme(ctx, themeID)
}
func (t *ThemeHandler) GetActivatedTheme(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeByID(ctx, activatedThemeID)
}
func (t *ThemeHandler) GetActivatedThemeConfig(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeConfig(ctx, activatedThemeID)
}
func (t *ThemeHandler) GetThemeConfigByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeConfig(ctx, themeID)
}
func (t *ThemeHandler) GetThemeConfigByGroup(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
group, err := util.ParamString(ctx, "group")
if err != nil {
return nil, err
}
themeSettings, err := t.ThemeService.GetThemeConfig(ctx, themeID)
if err != nil {
return nil, err
}
for _, setting := range themeSettings {
if setting.Name == group {
return setting.Items, nil
}
}
return nil, nil
}
func (t *ThemeHandler) GetThemeConfigGroupNames(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
themeSettings, err := t.ThemeService.GetThemeConfig(ctx, themeID)
if err != nil {
return nil, err
}
groupNames := make([]string, len(themeSettings))
for index, setting := range themeSettings {
groupNames[index] = setting.Name
}
return groupNames, nil
}
func (t *ThemeHandler) GetActivatedThemeSettingMap(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeSettingMap(ctx, activatedThemeID)
}
func (t *ThemeHandler) GetThemeSettingMapByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeSettingMap(ctx, themeID)
}
func (t *ThemeHandler) GetThemeSettingMapByGroupAndThemeID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
group, err := util.ParamString(ctx, "group")
if err != nil {
return nil, err
}
return t.ThemeService.GetThemeGroupSettingMap(ctx, themeID, group)
}
func (t *ThemeHandler) SaveActivatedThemeSetting(ctx *gin.Context) (interface{}, error) {
activatedThemeID, err := t.OptionService.GetActivatedThemeId(ctx)
if err != nil {
return nil, err
}
settings := make(map[string]interface{})
err = ctx.ShouldBindJSON(&settings)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
return nil, t.ThemeService.SaveThemeSettings(ctx, activatedThemeID, settings)
}
func (t *ThemeHandler) SaveThemeSettingByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
settings := make(map[string]interface{})
err = ctx.ShouldBindJSON(&settings)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest)
}
return nil, t.ThemeService.SaveThemeSettings(ctx, themeID, settings)
}
func (t *ThemeHandler) DeleteThemeByID(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
isDeleteSetting, err := util.GetQueryBool(ctx, "deleteSettings", false)
if err != nil {
return nil, err
}
return nil, t.ThemeService.DeleteTheme(ctx, themeID, isDeleteSetting)
}
func (t *ThemeHandler) UploadTheme(ctx *gin.Context) (interface{}, error) {
fileHeader, err := ctx.FormFile("file")
if err != nil {
return nil, xerr.WithMsg(err, "upload theme error").WithStatus(xerr.StatusBadRequest)
}
return t.ThemeService.UploadTheme(ctx, fileHeader)
}
func (t *ThemeHandler) UpdateThemeByUpload(ctx *gin.Context) (interface{}, error) {
themeID, err := util.ParamString(ctx, "themeID")
if err != nil {
return nil, err
}
fileHeader, err := ctx.FormFile("file")
if err != nil {
return nil, xerr.WithMsg(err, "upload theme error").WithStatus(xerr.StatusBadRequest)
}
return t.ThemeService.UpdateThemeByUpload(ctx, themeID, fileHeader)
}
func (t *ThemeHandler) FetchTheme(ctx *gin.Context) (interface{}, error) {
return nil, xerr.WithMsg(nil, "not support").WithStatus(xerr.StatusInternalServerError)
}
func (t *ThemeHandler) UpdateThemeByFetching(ctx *gin.Context) (interface{}, error) {
return nil, xerr.WithMsg(nil, "not support").WithStatus(xerr.StatusInternalServerError)
}
func (t *ThemeHandler) ReloadTheme(ctx *gin.Context) (interface{}, error) {
return nil, t.ThemeService.ReloadTheme(ctx)
}
func (t *ThemeHandler) TemplateExist(ctx *gin.Context) (interface{}, error) {
template, err := util.MustGetQueryString(ctx, "template")
if err != nil {
return nil, err
}
return t.ThemeService.TemplateExist(ctx, template)
}

@ -0,0 +1,126 @@
package admin
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/trans"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/vo"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/impl"
"github.com/go-sonic/sonic/util/xerr"
)
type UserHandler struct {
UserService service.UserService
TwoFactorMFAService service.TwoFactorTOTPMFAService
}
func NewUserHandler(userService service.UserService, twoFactorMFAService service.TwoFactorTOTPMFAService) *UserHandler {
return &UserHandler{
UserService: userService,
TwoFactorMFAService: twoFactorMFAService,
}
}
func (u *UserHandler) GetCurrentUserProfile(ctx *gin.Context) (interface{}, error) {
user, ok := impl.GetAuthorizedUser(ctx)
if !ok {
return nil, xerr.Forbidden.New("authorized user nil").WithStatus(xerr.StatusForbidden)
}
return u.UserService.ConvertToDTO(ctx, user), nil
}
func (u *UserHandler) UpdateUserProfile(ctx *gin.Context) (interface{}, error) {
userParam := &param.User{}
err := ctx.ShouldBindJSON(userParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
user, err := u.UserService.Update(ctx, userParam)
if err != nil {
return nil, err
}
return u.UserService.ConvertToDTO(ctx, user), nil
}
func (u *UserHandler) UpdatePassword(ctx *gin.Context) (interface{}, error) {
type Password struct {
OldPassword string `json:"oldPassword" form:"oldPassword" binding:"gte=1,lte=100"`
NewPassword string `json:"newPassword" form:"newPassword" binding:"gte=1,lte=100"`
}
passwordParam := &Password{}
err := ctx.ShouldBindJSON(passwordParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
return nil, u.UserService.UpdatePassword(ctx, passwordParam.OldPassword, passwordParam.NewPassword)
}
func (u *UserHandler) GenerateMFAQRCode(ctx *gin.Context) (interface{}, error) {
type Param struct {
MFAType *consts.MFAType `json:"mfaType"`
}
param := &Param{}
err := ctx.ShouldBindJSON(param)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if param.MFAType == nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
user, ok := impl.GetAuthorizedUser(ctx)
if !ok || user == nil {
return nil, xerr.Forbidden.New("").WithMsg("unauthorized").WithStatus(xerr.StatusForbidden)
}
mfaFactorAuthDTO := &vo.MFAFactorAuth{}
if *param.MFAType == consts.MFATFATotp {
key, url, err := u.TwoFactorMFAService.GenerateOTPKey(ctx, user.Nickname)
if err != nil {
return nil, err
}
mfaFactorAuthDTO.MFAType = consts.MFATFATotp
mfaFactorAuthDTO.OptAuthUrl = url
mfaFactorAuthDTO.MFAKey = key
qrCode, err := u.TwoFactorMFAService.GenerateMFAQRCode(ctx, url)
if err != nil {
return nil, err
}
mfaFactorAuthDTO.QRImage = qrCode
return mfaFactorAuthDTO, nil
} else {
return nil, xerr.WithMsg(nil, "Not supported authentication").WithStatus(xerr.StatusBadRequest)
}
}
func (u *UserHandler) UpdateMFA(ctx *gin.Context) (interface{}, error) {
type Param struct {
MFAType *consts.MFAType `json:"mfaType" form:"mfaType"`
MFAKey string `json:"mfaKey" form:"mfaKey"`
AuthCode string `json:"authcode" form:"authcode" binding:"gte=6,lte=6"`
}
mfaParam := &Param{}
err := ctx.ShouldBindJSON(mfaParam)
if err != nil {
if e, ok := err.(validator.ValidationErrors); ok {
return nil, xerr.WithStatus(e, xerr.StatusBadRequest).WithMsg(trans.Translate(e))
}
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
if mfaParam.MFAType == nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("parameter error")
}
return u.UserService.UpdateMFA(ctx, mfaParam.MFAKey, *mfaParam.MFAType, mfaParam.AuthCode), nil
}

@ -0,0 +1,59 @@
package binding
import (
"net/http"
"github.com/gin-gonic/gin/binding"
)
const defaultMemory = 32 << 20
// CustomFormBinding If the type implements the UnmarshalJSON interface, use JSON to bind
// For the purpose of support enum string to turn the enum type binding
var CustomFormBinding = customFormBinding{}
var CustomFormPostBinding = customFormPostBinding{}
type (
customFormBinding struct{}
customFormPostBinding struct{}
)
func (customFormBinding) Name() string {
return "form"
}
func (customFormBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseForm(); err != nil {
return err
}
if err := req.ParseMultipartForm(defaultMemory); err != nil {
if err != http.ErrNotMultipart {
return err
}
}
if err := mapForm(obj, req.Form); err != nil {
return err
}
return validate(obj)
}
func (customFormPostBinding) Name() string {
return "form-urlencoded"
}
func (customFormPostBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseForm(); err != nil {
return err
}
if err := mapForm(obj, req.PostForm); err != nil {
return err
}
return validate(obj)
}
func validate(obj interface{}) error {
if binding.Validator == nil {
return nil
}
return binding.Validator.ValidateStruct(obj)
}

@ -0,0 +1,417 @@
package binding
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/go-sonic/sonic/util"
)
var errUnknownType = errors.New("unknown type")
func mapForm(ptr interface{}, form map[string][]string) error {
return mapFormByTag(ptr, form, "form")
}
var emptyField = reflect.StructField{}
func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
// Check if ptr is a map
ptrVal := reflect.ValueOf(ptr)
var pointed interface{}
if ptrVal.Kind() == reflect.Ptr {
ptrVal = ptrVal.Elem()
pointed = ptrVal.Interface()
}
if ptrVal.Kind() == reflect.Map &&
ptrVal.Type().Key().Kind() == reflect.String {
if pointed != nil {
ptr = pointed
}
return setFormMap(ptr, form)
}
return mappingByPtr(ptr, formSource(form), tag)
}
// setter tries to set value on a walking by fields of a struct
type setter interface {
TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
}
type formSource map[string][]string
var _ setter = formSource(nil)
// TrySet tries to set a value by request's form source (like map[string][]string)
func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
return setByForm(value, field, form, tagValue, opt)
}
func mappingByPtr(ptr interface{}, setter setter, tag string) error {
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
return err
}
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
if field.Tag.Get(tag) == "-" { // just ignoring this field
return false, nil
}
vKind := value.Kind()
if vKind == reflect.Ptr {
var isNew, isSetted bool
vPtr := value
if value.IsNil() {
isNew = true
vPtr = reflect.New(value.Type().Elem())
}
if value.NumMethod() > 0 && value.CanInterface() {
if _, ok := value.Interface().(json.Unmarshaler); ok {
ok, err := tryToSetValue(vPtr, field, setter, tag)
if err != nil {
return false, err
}
if ok {
isSetted = true
}
if isNew && isSetted {
value.Set(vPtr)
}
return isSetted, nil
}
}
isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
if err != nil {
return false, err
}
if isNew && isSetted {
value.Set(vPtr)
}
return isSetted, nil
}
if vKind != reflect.Struct || !field.Anonymous {
ok, err := tryToSetValue(value, field, setter, tag)
if err != nil {
return false, err
}
if ok {
return true, nil
}
}
if vKind == reflect.Struct {
tValue := value.Type()
var isSetted bool
for i := 0; i < value.NumField(); i++ {
sf := tValue.Field(i)
if sf.PkgPath != "" && !sf.Anonymous { // unexported
continue
}
ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
if err != nil {
return false, err
}
isSetted = isSetted || ok
}
return isSetted, nil
}
return false, nil
}
type setOptions struct {
isDefaultExists bool
defaultValue string
}
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
var tagValue string
var setOpt setOptions
tagValue = field.Tag.Get(tag)
tagValue, opts := head(tagValue, ",")
if tagValue == "" { // default value is FieldName
tagValue = field.Name
}
if tagValue == "" { // when field is "emptyField" variable
return false, nil
}
var opt string
for len(opts) > 0 {
opt, opts = head(opts, ",")
if k, v := head(opt, "="); k == "default" {
setOpt.isDefaultExists = true
setOpt.defaultValue = v
}
}
return setter.TrySet(value, field, tagValue, setOpt)
}
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) {
vs, ok := form[tagValue]
if !ok && !opt.isDefaultExists {
return false, nil
}
switch value.Kind() {
case reflect.Slice:
if !ok {
vs = []string{opt.defaultValue}
}
return true, setSlice(vs, value, field)
case reflect.Array:
if !ok {
vs = []string{opt.defaultValue}
}
if len(vs) != value.Len() {
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
}
return true, setArray(vs, value, field)
default:
var val string
if !ok {
val = opt.defaultValue
}
if len(vs) > 0 {
val = vs[0]
}
return true, setWithProperType(val, value, field)
}
}
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
if value.NumMethod() > 0 && value.CanInterface() {
if u, ok := value.Interface().(json.Unmarshaler); ok {
err := u.UnmarshalJSON([]byte("\"" + val + "\""))
if err != nil {
return err
}
return nil
}
}
switch value.Kind() {
case reflect.Int:
return setIntField(val, 0, value)
case reflect.Int8:
return setIntField(val, 8, value)
case reflect.Int16:
return setIntField(val, 16, value)
case reflect.Int32:
return setIntField(val, 32, value)
case reflect.Int64:
switch value.Interface().(type) {
case time.Duration:
return setTimeDuration(val, value)
}
return setIntField(val, 64, value)
case reflect.Uint:
return setUintField(val, 0, value)
case reflect.Uint8:
return setUintField(val, 8, value)
case reflect.Uint16:
return setUintField(val, 16, value)
case reflect.Uint32:
return setUintField(val, 32, value)
case reflect.Uint64:
return setUintField(val, 64, value)
case reflect.Bool:
return setBoolField(val, value)
case reflect.Float32:
return setFloatField(val, 32, value)
case reflect.Float64:
return setFloatField(val, 64, value)
case reflect.String:
value.SetString(val)
case reflect.Struct:
switch value.Interface().(type) {
case time.Time:
return setTimeField(val, field, value)
}
return json.Unmarshal(util.StringToBytes(val), value.Addr().Interface())
case reflect.Map:
return json.Unmarshal(util.StringToBytes(val), value.Addr().Interface())
default:
return errUnknownType
}
return nil
}
func setIntField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0"
}
intVal, err := strconv.ParseInt(val, 10, bitSize)
if err == nil {
field.SetInt(intVal)
}
return err
}
func setUintField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0"
}
uintVal, err := strconv.ParseUint(val, 10, bitSize)
if err == nil {
field.SetUint(uintVal)
}
return err
}
func setBoolField(val string, field reflect.Value) error {
if val == "" {
val = "false"
}
boolVal, err := strconv.ParseBool(val)
if err == nil {
field.SetBool(boolVal)
}
return err
}
func setFloatField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0.0"
}
floatVal, err := strconv.ParseFloat(val, bitSize)
if err == nil {
field.SetFloat(floatVal)
}
return err
}
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
timeFormat := structField.Tag.Get("time_format")
if timeFormat == "" {
timeFormat = time.RFC3339
}
switch tf := strings.ToLower(timeFormat); tf {
case "unix", "unixnano":
tv, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return err
}
d := time.Duration(1)
if tf == "unixnano" {
d = time.Second
}
t := time.Unix(tv/int64(d), tv%int64(d))
value.Set(reflect.ValueOf(t))
return nil
}
if val == "" {
value.Set(reflect.ValueOf(time.Time{}))
return nil
}
l := time.Local
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
l = time.UTC
}
if locTag := structField.Tag.Get("time_location"); locTag != "" {
loc, err := time.LoadLocation(locTag)
if err != nil {
return err
}
l = loc
}
t, err := time.ParseInLocation(timeFormat, val, l)
if err != nil {
return err
}
value.Set(reflect.ValueOf(t))
return nil
}
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
for i, s := range vals {
iv := value.Index(i)
switch iv.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
if iv.IsNil() {
if iv.Type().Kind() == reflect.Pointer {
zeroV := reflect.New(iv.Type().Elem())
iv.Set(zeroV)
}
}
}
err := setWithProperType(s, iv, field)
if err != nil {
return err
}
}
return nil
}
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
err := setArray(vals, slice, field)
if err != nil {
return err
}
value.Set(slice)
return nil
}
func setTimeDuration(val string, value reflect.Value) error {
d, err := time.ParseDuration(val)
if err != nil {
return err
}
value.Set(reflect.ValueOf(d))
return nil
}
func head(str, sep string) (head string, tail string) {
idx := strings.Index(str, sep)
if idx < 0 {
return str, ""
}
return str[:idx], str[idx+len(sep):]
}
func setFormMap(ptr interface{}, form map[string][]string) error {
el := reflect.TypeOf(ptr).Elem()
if el.Kind() == reflect.Slice {
ptrMap, ok := ptr.(map[string][]string)
if !ok {
return errors.New("cannot convert to map slices of strings")
}
for k, v := range form {
ptrMap[k] = v
}
return nil
}
ptrMap, ok := ptr.(map[string]string)
if !ok {
return errors.New("cannot convert to map of strings")
}
for k, v := range form {
ptrMap[k] = v[len(v)-1] // pick last
}
return nil
}

@ -0,0 +1,37 @@
package api
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
)
type ArchiveHandler struct {
PostService service.PostService
PostAssembler assembler.PostAssembler
}
func NewArchiveHandler(postService service.PostService, postAssemeber assembler.PostAssembler) *ArchiveHandler {
return &ArchiveHandler{
PostService: postService,
PostAssembler: postAssemeber,
}
}
func (a *ArchiveHandler) ListYearArchives(ctx *gin.Context) (interface{}, error) {
posts, err := a.PostService.GetByStatus(ctx, []consts.PostStatus{consts.PostStatusPublished}, consts.PostTypePost, nil)
if err != nil {
return nil, err
}
return a.PostAssembler.ConvertToArchiveYearVOs(ctx, posts)
}
func (a *ArchiveHandler) ListMonthArchives(ctx *gin.Context) (interface{}, error) {
posts, err := a.PostService.GetByStatus(ctx, []consts.PostStatus{consts.PostStatusPublished}, consts.PostTypePost, nil)
if err != nil {
return nil, err
}
return a.PostAssembler.ConvertTOArchiveMonthVOs(ctx, posts)
}

@ -0,0 +1,93 @@
package api
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/handler/content/authentication"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type CategoryHandler struct {
PostService service.PostService
CategoryService service.CategoryService
CategoryAuthentication authentication.CategoryAuthentication
PostAssembler assembler.PostAssembler
}
func NewCategoryHandler(postService service.PostService, categoryService service.CategoryService, categoryAuthentication *authentication.CategoryAuthentication, postAssembler assembler.PostAssembler) *CategoryHandler {
return &CategoryHandler{
PostService: postService,
CategoryService: categoryService,
CategoryAuthentication: *categoryAuthentication,
PostAssembler: postAssembler,
}
}
func (c *CategoryHandler) ListCategories(ctx *gin.Context) (interface{}, error) {
categoryQuery := struct {
*param.Sort
More *bool `json:"more" form:"more"`
}{}
err := ctx.ShouldBindQuery(&categoryQuery)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if categoryQuery.Sort == nil || len(categoryQuery.Sort.Fields) == 0 {
categoryQuery.Sort = &param.Sort{Fields: []string{"updateTime,desc"}}
}
if categoryQuery.More != nil && *categoryQuery.More {
return c.CategoryService.ListCategoryWithPostCountDTO(ctx, categoryQuery.Sort)
}
categories, err := c.CategoryService.ListAll(ctx, categoryQuery.Sort)
if err != nil {
return nil, err
}
return c.CategoryService.ConvertToCategoryDTOs(ctx, categories)
}
func (c *CategoryHandler) ListPosts(ctx *gin.Context) (interface{}, error) {
slug, err := util.ParamString(ctx, "slug")
if err != nil {
return nil, err
}
category, err := c.CategoryService.GetBySlug(ctx, slug)
if err != nil {
return nil, err
}
postQuery := param.PostQuery{}
err = ctx.ShouldBindWith(&postQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if postQuery.Sort == nil {
postQuery.Sort = &param.Sort{Fields: []string{"topPriority,desc", "updateTime,desc"}}
}
password, _ := util.MustGetQueryString(ctx, "password")
if category.Type == consts.CategoryTypeIntimate {
token, _ := ctx.Cookie("authentication")
if authenticated, _ := c.CategoryAuthentication.IsAuthenticated(ctx, token, category.ID); !authenticated {
token, err := c.CategoryAuthentication.Authenticate(ctx, token, category.ID, password)
if err != nil {
return nil, err
}
ctx.SetCookie("authentication", token, 1800, "/", "", false, true)
}
}
postQuery.WithPassword = util.BoolPtr(false)
postQuery.Statuses = []*consts.PostStatus{consts.PostStatusPublished.Ptr(), consts.PostStatusIntimate.Ptr()}
posts, totalCount, err := c.PostService.Page(ctx, postQuery)
if err != nil {
return nil, err
}
postVOs, err := c.PostAssembler.ConvertToListVO(ctx, posts)
return dto.NewPage(postVOs, totalCount, postQuery.Page), err
}

@ -0,0 +1,15 @@
package api
import "github.com/go-sonic/sonic/injection"
func init() {
injection.Provide(
NewArchiveHandler,
NewCategoryHandler,
NewJournalHandler,
NewLinkHandler,
NewPostHandler,
NewSheetHandler,
NewOptionHandler,
)
}

@ -0,0 +1,232 @@
package api
import (
"html/template"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type JournalHandler struct {
JournalService service.JournalService
JournalCommentService service.JournalCommentService
OptionService service.ClientOptionService
JournalCommentAssembler assembler.JournalCommentAssembler
}
func NewJournalHandler(
journalService service.JournalService,
journalCommentService service.JournalCommentService,
optionService service.ClientOptionService,
journalCommentAssembler assembler.JournalCommentAssembler,
) *JournalHandler {
return &JournalHandler{
JournalService: journalService,
JournalCommentService: journalCommentService,
OptionService: optionService,
JournalCommentAssembler: journalCommentAssembler,
}
}
func (j *JournalHandler) ListJournal(ctx *gin.Context) (interface{}, error) {
var journalQuery param.JournalQuery
err := ctx.ShouldBindWith(&journalQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
journalQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
journalQuery.JournalType = consts.JournalTypePublic.Ptr()
journals, totalCount, err := j.JournalService.ListJournal(ctx, journalQuery)
if err != nil {
return nil, err
}
journalDTOs, err := j.JournalService.ConvertToWithCommentDTOList(ctx, journals)
if err != nil {
return nil, err
}
return dto.NewPage(journalDTOs, totalCount, journalQuery.Page), nil
}
func (j *JournalHandler) GetJournal(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
journals, err := j.JournalService.GetByJournalIDs(ctx, []int32{journalID})
if err != nil {
return nil, err
}
if len(journals) == 0 {
return nil, xerr.WithStatus(nil, xerr.StatusBadRequest)
}
journalDTOs, err := j.JournalService.ConvertToWithCommentDTOList(ctx, []*entity.Journal{journals[journalID]})
if err != nil {
return nil, err
}
return journalDTOs[0], nil
}
func (j *JournalHandler) ListTopComment(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
pageSize := j.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &journalID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
comments, totalCount, err := j.JournalCommentService.Page(ctx, commentQuery, consts.CommentTypeJournal)
if err != nil {
return nil, err
}
_ = j.JournalCommentAssembler.ClearSensitiveField(ctx, comments)
commenVOs, err := j.JournalCommentAssembler.ConvertToWithHasChildren(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commenVOs, totalCount, commentQuery.Page), nil
}
func (j *JournalHandler) ListChildren(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
parentID, err := util.ParamInt64(ctx, "parentID")
if err != nil {
return nil, err
}
children, err := j.JournalCommentService.GetChildren(ctx, parentID, journalID)
if err != nil {
return nil, err
}
_ = j.JournalCommentAssembler.ClearSensitiveField(ctx, children)
return j.JournalCommentAssembler.ConvertToDTOList(ctx, children)
}
func (j *JournalHandler) ListCommentTree(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
pageSize := j.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &journalID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
allComments, err := j.JournalCommentService.GetByContentID(ctx, journalID, commentQuery.Sort)
if err != nil {
return nil, err
}
_ = j.JournalCommentAssembler.ClearSensitiveField(ctx, allComments)
commentVOs, total, err := j.JournalCommentAssembler.PageConvertToVOs(ctx, allComments, commentQuery.Page)
if err != nil {
return nil, err
}
return dto.NewPage(commentVOs, total, commentQuery.Page), nil
}
func (j *JournalHandler) ListComment(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
pageSize := j.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &journalID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
comments, total, err := j.JournalCommentService.Page(ctx, commentQuery, consts.CommentTypeJournal)
if err != nil {
return nil, err
}
_ = j.JournalCommentAssembler.ClearSensitiveField(ctx, comments)
result, err := j.JournalCommentAssembler.ConvertToWithParentVO(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(result, total, commentQuery.Page), nil
}
func (j *JournalHandler) CreateComment(ctx *gin.Context) (interface{}, error) {
p := param.Comment{}
err := ctx.ShouldBindJSON(&p)
if err != nil {
return nil, err
}
p.Author = template.HTMLEscapeString(p.Author)
p.AuthorURL = template.HTMLEscapeString(p.AuthorURL)
p.Content = template.HTMLEscapeString(p.Content)
p.Email = template.HTMLEscapeString(p.Email)
p.CommentType = consts.CommentTypeJournal
result, err := j.JournalCommentService.CreateBy(ctx, &p)
if err != nil {
return nil, err
}
return j.JournalCommentAssembler.ConvertToDTO(ctx, result)
}
func (j *JournalHandler) Like(ctx *gin.Context) (interface{}, error) {
journalID, err := util.ParamInt32(ctx, "journalID")
if err != nil {
return nil, err
}
err = j.JournalService.IncreaseLike(ctx, journalID)
if err != nil {
return nil, err
}
return nil, err
}

@ -0,0 +1,58 @@
package api
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/service"
)
type LinkHandler struct {
LinkService service.LinkService
}
func NewLinkHandler(linkService service.LinkService) *LinkHandler {
return &LinkHandler{
LinkService: linkService,
}
}
type linkParam struct {
*param.Sort
}
func (l *LinkHandler) ListLinks(ctx *gin.Context) (interface{}, error) {
p := linkParam{}
if err := ctx.ShouldBindQuery(&p); err != nil {
return nil, err
}
if p.Sort == nil || len(p.Sort.Fields) == 0 {
p.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
links, err := l.LinkService.List(ctx, p.Sort)
if err != nil {
return nil, err
}
return l.LinkService.ConvertToDTOs(ctx, links), nil
}
func (l *LinkHandler) LinkTeamVO(ctx *gin.Context) (interface{}, error) {
p := linkParam{}
if err := ctx.ShouldBindQuery(&p); err != nil {
return nil, err
}
if p.Sort == nil || len(p.Sort.Fields) == 0 {
p.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
links, err := l.LinkService.List(ctx, p.Sort)
if err != nil {
return nil, err
}
return l.LinkService.ConvertToLinkTeamVO(ctx, links), nil
}

@ -0,0 +1,29 @@
package api
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
)
type OptionHandler struct {
OptionService service.OptionService
}
func NewOptionHandler(
optionService service.OptionService,
) *OptionHandler {
return &OptionHandler{
OptionService: optionService,
}
}
func (o *OptionHandler) Comment(ctx *gin.Context) (interface{}, error) {
result := make(map[string]interface{})
result[property.CommentGravatarSource.KeyValue] = o.OptionService.GetOrByDefault(ctx, property.CommentGravatarSource)
result[property.CommentGravatarDefault.KeyValue] = o.OptionService.GetOrByDefault(ctx, property.CommentGravatarDefault)
result[property.CommentContentPlaceholder.KeyValue] = o.OptionService.GetOrByDefault(ctx, property.CommentContentPlaceholder)
return result, nil
}

@ -0,0 +1,190 @@
package api
import (
"html/template"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type PostHandler struct {
OptionService service.OptionService
PostService service.PostService
PostCommentService service.PostCommentService
PostCommentAssembler assembler.PostCommentAssembler
}
func NewPostHandler(
optionService service.OptionService,
postService service.PostService,
postCommentService service.PostCommentService,
postCommentAssembler assembler.PostCommentAssembler,
) *PostHandler {
return &PostHandler{
OptionService: optionService,
PostService: postService,
PostCommentService: postCommentService,
PostCommentAssembler: postCommentAssembler,
}
}
func (p *PostHandler) ListTopComment(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
pageSize := p.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &postID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
comments, totalCount, err := p.PostCommentService.Page(ctx, commentQuery, consts.CommentTypePost)
if err != nil {
return nil, err
}
_ = p.PostCommentAssembler.ClearSensitiveField(ctx, comments)
commenVOs, err := p.PostCommentAssembler.ConvertToWithHasChildren(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commenVOs, totalCount, commentQuery.Page), nil
}
func (p *PostHandler) ListChildren(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
parentID, err := util.ParamInt64(ctx, "parentID")
if err != nil {
return nil, err
}
children, err := p.PostCommentService.GetChildren(ctx, parentID, postID)
if err != nil {
return nil, err
}
_ = p.PostCommentAssembler.ClearSensitiveField(ctx, children)
return p.PostCommentAssembler.ConvertToDTOList(ctx, children)
}
func (p *PostHandler) ListCommentTree(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
pageSize := p.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &postID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
allComments, err := p.PostCommentService.GetByContentID(ctx, postID, commentQuery.Sort)
if err != nil {
return nil, err
}
_ = p.PostCommentAssembler.ClearSensitiveField(ctx, allComments)
commentVOs, total, err := p.PostCommentAssembler.PageConvertToVOs(ctx, allComments, commentQuery.Page)
if err != nil {
return nil, err
}
return dto.NewPage(commentVOs, total, commentQuery.Page), nil
}
func (p *PostHandler) ListComment(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
pageSize := p.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &postID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
comments, total, err := p.PostCommentService.Page(ctx, commentQuery, consts.CommentTypePost)
if err != nil {
return nil, err
}
_ = p.PostCommentAssembler.ClearSensitiveField(ctx, comments)
result, err := p.PostCommentAssembler.ConvertToWithParentVO(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(result, total, commentQuery.Page), nil
}
func (p *PostHandler) CreateComment(ctx *gin.Context) (interface{}, error) {
comment := param.Comment{}
err := ctx.ShouldBindJSON(&comment)
if err != nil {
return nil, err
}
comment.Author = template.HTMLEscapeString(comment.Author)
comment.AuthorURL = template.HTMLEscapeString(comment.AuthorURL)
comment.Content = template.HTMLEscapeString(comment.Content)
comment.Email = template.HTMLEscapeString(comment.Email)
comment.CommentType = consts.CommentTypePost
result, err := p.PostCommentService.CreateBy(ctx, &comment)
if err != nil {
return nil, err
}
return p.PostCommentAssembler.ConvertToDTO(ctx, result)
}
func (p *PostHandler) Like(ctx *gin.Context) (interface{}, error) {
postID, err := util.ParamInt32(ctx, "postID")
if err != nil {
return nil, err
}
err = p.PostService.IncreaseLike(ctx, postID)
if err != nil {
return nil, err
}
return nil, err
}

@ -0,0 +1,178 @@
package api
import (
"html/template"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/binding"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type SheetHandler struct {
OptionService service.OptionService
SheetService service.SheetService
SheetCommentService service.SheetCommentService
SheetCommentAssembler assembler.SheetCommentAssembler
}
func NewSheetHandler(
optionService service.OptionService,
sheetService service.SheetService,
sheetCommentService service.SheetCommentService,
sheetCommentAssembler assembler.SheetCommentAssembler,
) *SheetHandler {
return &SheetHandler{
OptionService: optionService,
SheetService: sheetService,
SheetCommentService: sheetCommentService,
SheetCommentAssembler: sheetCommentAssembler,
}
}
func (j *SheetHandler) ListTopComment(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
pageSize := j.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &sheetID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
comments, totalCount, err := j.SheetCommentService.Page(ctx, commentQuery, consts.CommentTypeSheet)
if err != nil {
return nil, err
}
_ = j.SheetCommentAssembler.ClearSensitiveField(ctx, comments)
commenVOs, err := j.SheetCommentAssembler.ConvertToWithHasChildren(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(commenVOs, totalCount, commentQuery.Page), nil
}
func (j *SheetHandler) ListChildren(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
parentID, err := util.ParamInt64(ctx, "parentID")
if err != nil {
return nil, err
}
children, err := j.SheetCommentService.GetChildren(ctx, parentID, sheetID)
if err != nil {
return nil, err
}
_ = j.SheetCommentAssembler.ClearSensitiveField(ctx, children)
return j.SheetCommentAssembler.ConvertToDTOList(ctx, children)
}
func (p *SheetHandler) ListCommentTree(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
pageSize := p.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &sheetID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
allComments, err := p.SheetCommentService.GetByContentID(ctx, sheetID, commentQuery.Sort)
if err != nil {
return nil, err
}
_ = p.SheetCommentAssembler.ClearSensitiveField(ctx, allComments)
commentVOs, total, err := p.SheetCommentAssembler.PageConvertToVOs(ctx, allComments, commentQuery.Page)
if err != nil {
return nil, err
}
return dto.NewPage(commentVOs, total, commentQuery.Page), nil
}
func (p *SheetHandler) ListComment(ctx *gin.Context) (interface{}, error) {
sheetID, err := util.ParamInt32(ctx, "sheetID")
if err != nil {
return nil, err
}
pageSize := p.OptionService.GetOrByDefault(ctx, property.CommentPageSize).(int)
commentQuery := param.CommentQuery{}
err = ctx.ShouldBindWith(&commentQuery, binding.CustomFormBinding)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusBadRequest).WithMsg("Parameter error")
}
if commentQuery.Sort != nil && len(commentQuery.Fields) > 0 {
commentQuery.Sort = &param.Sort{
Fields: []string{"createTime,desc"},
}
}
commentQuery.ContentID = &sheetID
commentQuery.Keyword = nil
commentQuery.CommentStatus = consts.CommentStatusPublished.Ptr()
commentQuery.PageSize = pageSize
commentQuery.ParentID = util.Int32Ptr(0)
comments, total, err := p.SheetCommentService.Page(ctx, commentQuery, consts.CommentTypeSheet)
if err != nil {
return nil, err
}
_ = p.SheetCommentAssembler.ClearSensitiveField(ctx, comments)
result, err := p.SheetCommentAssembler.ConvertToWithParentVO(ctx, comments)
if err != nil {
return nil, err
}
return dto.NewPage(result, total, commentQuery.Page), nil
}
func (p *SheetHandler) CreateComment(ctx *gin.Context) (interface{}, error) {
comment := param.Comment{}
err := ctx.ShouldBindJSON(&p)
if err != nil {
return nil, err
}
comment.Author = template.HTMLEscapeString(comment.Author)
comment.AuthorURL = template.HTMLEscapeString(comment.AuthorURL)
comment.Content = template.HTMLEscapeString(comment.Content)
comment.Email = template.HTMLEscapeString(comment.Email)
comment.CommentType = consts.CommentTypeSheet
result, err := p.SheetCommentService.CreateBy(ctx, &comment)
if err != nil {
return nil, err
}
return p.SheetCommentAssembler.ConvertToDTO(ctx, result)
}

@ -0,0 +1,83 @@
package content
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/content/model"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/template"
"github.com/go-sonic/sonic/util"
)
type ArchiveHandler struct {
OptionService service.OptionService
PostService service.PostService
PostCategoryService service.PostCategoryService
CategoryService service.CategoryService
PostAssembler assembler.PostAssembler
PostModel *model.PostModel
}
func NewArchiveHandler(
optionService service.OptionService,
postService service.PostService,
categoryService service.CategoryService,
postCategoryService service.PostCategoryService,
postAssembler assembler.PostAssembler,
postModel *model.PostModel,
) *ArchiveHandler {
return &ArchiveHandler{
OptionService: optionService,
PostService: postService,
PostCategoryService: postCategoryService,
CategoryService: categoryService,
PostAssembler: postAssembler,
PostModel: postModel,
}
}
func (a *ArchiveHandler) Archives(ctx *gin.Context, model template.Model) (string, error) {
return a.PostModel.Archives(ctx, 0, model)
}
func (a *ArchiveHandler) ArchivesPage(ctx *gin.Context, model template.Model) (string, error) {
page, err := util.ParamInt32(ctx, "page")
if err != nil {
return "", err
}
return a.PostModel.Archives(ctx, int(page-1), model)
}
func (a *ArchiveHandler) ArchivesBySlug(ctx *gin.Context, model template.Model) (string, error) {
slug, err := util.ParamString(ctx, "slug")
if err != nil {
return "", err
}
postPermalinkType, err := a.OptionService.GetPostPermalinkType(ctx)
if err != nil {
return "", err
}
var post *entity.Post
if postPermalinkType == consts.PostPermalinkTypeDefault {
post, err = a.PostService.GetBySlug(ctx, slug)
if err != nil {
return "", err
}
} else if postPermalinkType == consts.PostPermalinkTypeID {
postID, err := strconv.ParseInt(slug, 10, 32)
if err != nil {
return "", err
}
post, err = a.PostService.GetByPostID(ctx, int32(postID))
if err != nil {
return "", err
}
}
token, _ := ctx.Cookie("authentication")
return a.PostModel.Content(ctx, post, token, model)
}

@ -0,0 +1,146 @@
package authentication
import (
"context"
"fmt"
"net/http"
"time"
"github.com/golang-jwt/jwt"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util/xerr"
)
type CategoryAuthentication struct {
OptionService service.OptionService
CategoryService service.CategoryService
}
func NewCategoryAuthentication(
optionService service.OptionService,
categoryService service.CategoryService,
) *CategoryAuthentication {
return &CategoryAuthentication{
OptionService: optionService,
CategoryService: categoryService,
}
}
// Authenticate implements ContentAuthentication
func (c *CategoryAuthentication) Authenticate(ctx context.Context, token string, id int32, password string) (string, error) {
category, err := c.CategoryService.GetByID(ctx, id)
if err != nil {
return "", err
}
if category.Password == "" && category.ParentID == 0 {
return "", nil
}
if category.Password == "" {
categories, err := c.CategoryService.ListAll(ctx, nil)
if err != nil {
return "", err
}
categoryMap := make(map[int32]*entity.Category)
for _, category := range categories {
categoryMap[category.ID] = category
}
parentID := category.ParentID
parentIDs := make([]int32, 0)
for {
parentCategory, ok := categoryMap[parentID]
if !ok || parentCategory == nil {
return "", nil
}
if parentCategory.Password == "" {
parentID = parentCategory.ParentID
parentIDs = append(parentIDs, parentID)
} else if parentCategory.Password == password {
return c.doAuthenticate(ctx, token, parentIDs...)
} else {
return "", xerr.WithMsg(nil, "密码不正确").WithStatus(http.StatusUnauthorized)
}
}
} else if category.Password == password {
return c.doAuthenticate(ctx, token, id)
} else {
return "", xerr.WithMsg(nil, "密码不正确").WithStatus(http.StatusUnauthorized)
}
}
func (c *CategoryAuthentication) IsAuthenticated(ctx context.Context, tokenStr string, id int32) (bool, error) {
if tokenStr == "" {
return false, nil
}
secret, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.JWTSecret, "")
if err != nil {
return false, err
}
if secret.(string) == "" {
return false, xerr.WithMsg(nil, "jwt secret is nil").WithStatus(xerr.StatusInternalServerError)
}
token, err := jwt.ParseWithClaims(tokenStr, &customClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret.(string)), nil
})
if err != nil {
return false, err
}
claims, ok := token.Claims.(*customClaims)
if !ok || !token.Valid || claims == nil {
return false, nil
}
for _, categoryID := range claims.CategoryIDs {
if categoryID == id {
return true, nil
}
}
return false, nil
}
func (c *CategoryAuthentication) doAuthenticate(ctx context.Context, tokenStr string, id ...int32) (string, error) {
secret, err := c.OptionService.GetOrByDefaultWithErr(ctx, property.JWTSecret, "")
if err != nil {
return "", err
}
if secret.(string) == "" {
return "", xerr.WithMsg(nil, "jwt secret is nil").WithStatus(xerr.StatusInternalServerError)
}
var claims *customClaims
if tokenStr != "" {
token, err := jwt.ParseWithClaims(tokenStr, &customClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret.(string)), nil
})
if err == nil {
if c, ok := token.Claims.(*customClaims); ok && token.Valid {
claims = c
}
}
}
if claims == nil {
claims = &customClaims{
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
IssuedAt: time.Now().Unix(),
},
}
}
claims.CategoryIDs = append(claims.CategoryIDs, id...)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString([]byte(secret.(string)))
if err != nil {
return "", xerr.WithStatus(err, xerr.StatusInternalServerError)
}
return ss, nil
}

@ -0,0 +1,18 @@
package authentication
import (
"context"
"github.com/golang-jwt/jwt"
)
type ContentAuthentication interface {
Authenticate(ctx context.Context, token string, id int32, password string) (string, error)
IsAuthenticated(ctx context.Context, token string, id int32) (bool, error)
}
type customClaims struct {
CategoryIDs []int32 `json:"category_ids"`
PostIDs []int32 `json:"post_ids"`
jwt.StandardClaims
}

@ -0,0 +1,10 @@
package authentication
import "github.com/go-sonic/sonic/injection"
func init() {
injection.Provide(
NewCategoryAuthentication,
NewPostAuthentication,
)
}

@ -0,0 +1,190 @@
package authentication
import (
"context"
"fmt"
"net/http"
"time"
"github.com/golang-jwt/jwt"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util/xerr"
)
type PostAuthentication struct {
OptionService service.OptionService
PostService service.PostService
PostCategoryService service.PostCategoryService
CategoryService service.CategoryService
}
func NewPostAuthentication(
optionService service.OptionService,
postService service.PostService,
categoryService service.CategoryService,
postCategoryService service.PostCategoryService,
) *PostAuthentication {
return &PostAuthentication{
CategoryService: categoryService,
OptionService: optionService,
PostService: postService,
PostCategoryService: postCategoryService,
}
}
func (p *PostAuthentication) Authenticate(ctx context.Context, token string, id int32, password string) (string, error) {
post, err := p.PostService.GetByPostID(ctx, id)
if err != nil {
return "", err
}
if post.Password != "" {
if post.Password == password {
return p.doAuthenticate(ctx, token, id)
} else {
return "", xerr.WithMsg(nil, "密码不正确").WithStatus(http.StatusUnauthorized)
}
}
postCategories, err := p.PostCategoryService.ListCategoryByPostID(ctx, id)
if err != nil {
return "", err
}
for _, category := range postCategories {
if category.Password == password {
return p.doAuthenticate(ctx, token, id)
}
}
allCategories, err := p.CategoryService.ListAll(ctx, nil)
if err != nil {
return "", err
}
categoryMap := make(map[int32]*entity.Category)
for _, category := range allCategories {
categoryMap[category.ID] = category
}
for _, postCategory := range postCategories {
parentID := postCategory.ParentID
for {
parentCategory, ok := categoryMap[parentID]
if !ok || parentCategory == nil {
break
}
if parentCategory.Password == "" {
parentID = parentCategory.ParentID
} else if parentCategory.Password == password {
return p.doAuthenticate(ctx, token, id)
} else {
break
}
}
}
return "", xerr.WithMsg(nil, "密码不正确").WithStatus(http.StatusUnauthorized)
}
func (p *PostAuthentication) IsAuthenticated(ctx context.Context, tokenStr string, id int32) (bool, error) {
if tokenStr == "" {
return false, nil
}
secret, err := p.OptionService.GetOrByDefaultWithErr(ctx, property.JWTSecret, "")
if err != nil {
return false, err
}
if secret.(string) == "" {
return false, xerr.WithMsg(nil, "jwt secret is nil").WithStatus(xerr.StatusInternalServerError)
}
post, err := p.PostService.GetByPostID(ctx, id)
if err != nil {
return false, err
}
token, err := jwt.ParseWithClaims(tokenStr, &customClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret.(string)), nil
})
if err != nil {
return false, err
}
claims, ok := token.Claims.(*customClaims)
if !ok || !token.Valid || claims == nil {
return false, nil
}
for _, postID := range claims.PostIDs {
if postID == id {
return true, nil
}
}
if post.Password != "" {
return false, nil
}
categories, err := p.PostCategoryService.ListCategoryByPostID(ctx, id)
if err != nil {
return false, err
}
if err != nil {
return false, err
}
for _, categoryID := range claims.CategoryIDs {
for _, category := range categories {
if category.Type == consts.CategoryTypeNormal {
continue
}
if category.ID == categoryID {
return true, nil
}
}
}
return false, nil
}
func (p *PostAuthentication) doAuthenticate(ctx context.Context, tokenStr string, id int32) (string, error) {
secret, err := p.OptionService.GetOrByDefaultWithErr(ctx, property.JWTSecret, "")
if err != nil {
return "", err
}
if secret.(string) == "" {
return "", xerr.WithMsg(nil, "jwt secret is nil").WithStatus(xerr.StatusInternalServerError)
}
var claims *customClaims
if tokenStr != "" {
token, err := jwt.ParseWithClaims(tokenStr, &customClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret.(string)), nil
})
if err == nil {
if c, ok := token.Claims.(*customClaims); ok && token.Valid {
claims = c
}
}
}
if claims == nil {
claims = &customClaims{
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
IssuedAt: time.Now().Unix(),
},
}
}
claims.PostIDs = append(claims.PostIDs, id)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString([]byte(secret.(string)))
if err != nil {
return "", xerr.WithStatus(err, xerr.StatusInternalServerError)
}
return ss, nil
}

@ -0,0 +1,67 @@
package content
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/handler/content/model"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/template"
"github.com/go-sonic/sonic/util"
)
type CategoryHandler struct {
OptionService service.OptionService
PostService service.PostService
PostCategoryService service.PostCategoryService
CategoryService service.CategoryService
PostAssembler assembler.PostAssembler
PostModel *model.PostModel
CategoryModel *model.CategoryModel
}
func NewCategoryHandler(
optionService service.OptionService,
postService service.PostService,
categoryService service.CategoryService,
postCategoryService service.PostCategoryService,
postAssembler assembler.PostAssembler,
postModel *model.PostModel,
categoryModel *model.CategoryModel,
) *CategoryHandler {
return &CategoryHandler{
OptionService: optionService,
PostService: postService,
PostCategoryService: postCategoryService,
CategoryService: categoryService,
PostAssembler: postAssembler,
PostModel: postModel,
CategoryModel: categoryModel,
}
}
func (c *CategoryHandler) Categories(ctx *gin.Context, model template.Model) (string, error) {
return c.CategoryModel.ListCategories(ctx, model)
}
func (c *CategoryHandler) CategoryDetail(ctx *gin.Context, model template.Model) (string, error) {
slug, err := util.ParamString(ctx, "slug")
if err != nil {
return "", err
}
token, _ := ctx.Cookie("authentication")
return c.CategoryModel.CategoryDetail(ctx, model, slug, 0, token)
}
func (c *CategoryHandler) CategoryDetailPage(ctx *gin.Context, model template.Model) (string, error) {
slug, err := util.ParamString(ctx, "slug")
if err != nil {
return "", err
}
page, err := util.ParamInt32(ctx, "page")
if err != nil {
return "", err
}
token, _ := ctx.Cookie("authentication")
return c.CategoryModel.CategoryDetail(ctx, model, slug, int(page-1), token)
}

@ -0,0 +1,187 @@
package content
import (
"context"
"net/http"
"regexp"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/model/vo"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/template"
"github.com/go-sonic/sonic/util"
)
type FeedHandler struct {
OptionService service.OptionService
PostService service.PostService
PostCategoryService service.PostCategoryService
CategoryService service.CategoryService
PostAssembler assembler.PostAssembler
}
func NewFeedHandler(optionService service.OptionService, postService service.PostService, categoryService service.CategoryService, postCategoryService service.PostCategoryService, postAssembler assembler.PostAssembler) *FeedHandler {
return &FeedHandler{
OptionService: optionService,
PostService: postService,
CategoryService: categoryService,
PostCategoryService: postCategoryService,
PostAssembler: postAssembler,
}
}
func (f *FeedHandler) Feed(ctx *gin.Context, model template.Model) (string, error) {
_, err := f.Atom(ctx, model)
if err != nil {
return "", err
}
ctx.Header("Content-Type", "application/xml; charset=utf-8")
return "common/web/rss", nil
}
func (f *FeedHandler) CategoryFeed(ctx *gin.Context, model template.Model) (string, error) {
_, err := f.CategoryAtom(ctx, model)
if err != nil {
return "", err
}
ctx.Header("Content-Type", "application/xml; charset=utf-8")
return "common/web/rss", nil
}
func (f *FeedHandler) Atom(ctx *gin.Context, model template.Model) (string, error) {
rssPageSize := f.OptionService.GetOrByDefault(ctx, property.RssPageSize).(int)
postQuery := param.PostQuery{
Page: param.Page{PageNum: 0, PageSize: rssPageSize},
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
}
posts, _, err := f.PostService.Page(ctx, postQuery)
if err != nil {
return "", err
}
postDetailVOs, err := f.buildPost(ctx, posts)
if err != nil {
return "", err
}
lastModified := f.getLastModifiedTime(posts)
ctx.Header("Last-Modified", lastModified.Format(http.TimeFormat))
ctx.Header("Content-Type", "application/xml; charset=utf-8")
model["lastModified"] = lastModified
model["posts"] = postDetailVOs
return "common/web/atom", nil
}
func (f *FeedHandler) CategoryAtom(ctx *gin.Context, model template.Model) (string, error) {
slug, err := util.ParamString(ctx, "slug")
if err != nil {
return "", err
}
slug = strings.TrimSuffix(slug, ".xml")
category, err := f.CategoryService.GetBySlug(ctx, slug)
if err != nil {
return "", err
}
categoryDTO, err := f.CategoryService.ConvertToCategoryDTO(ctx, category)
if err != nil {
return "", err
}
posts, err := f.PostCategoryService.ListByCategoryID(ctx, category.ID, consts.PostStatusPublished)
if err != nil {
return "", err
}
postDetailVOs, err := f.buildPost(ctx, posts)
if err != nil {
return "", err
}
lastModified := f.getLastModifiedTime(posts)
model["category"] = categoryDTO
model["posts"] = postDetailVOs
model["lastModified"] = lastModified
ctx.Header("Content-Type", "application/xml; charset=utf-8")
return "common/web/atom", nil
}
func (f *FeedHandler) Robots(ctx *gin.Context, model template.Model) (string, error) {
ctx.Header("Content-Type", "text/plain;charset=utf-8")
return "common/web/robots", nil
}
func (f *FeedHandler) SitemapXML(ctx *gin.Context, model template.Model) (string, error) {
posts, _, err := f.PostService.Page(ctx, param.PostQuery{
Page: param.Page{PageNum: 0, PageSize: int(^uint(0) >> 1)},
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
})
if err != nil {
return "", err
}
postDetailVOs, err := f.buildPost(ctx, posts)
if err != nil {
return "", err
}
model["posts"] = postDetailVOs
ctx.Header("Content-Type", "application/xml; charset=utf-8")
return "common/web/sitemap_xml", nil
}
func (f *FeedHandler) SitemapHTML(ctx *gin.Context, model template.Model) (string, error) {
posts, _, err := f.PostService.Page(ctx, param.PostQuery{
Page: param.Page{PageNum: 0, PageSize: int(^uint(0) >> 1)},
Sort: &param.Sort{Fields: []string{"createTime,desc"}},
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
})
if err != nil {
return "", err
}
postDetailVOs, err := f.buildPost(ctx, posts)
if err != nil {
return "", err
}
model["posts"] = postDetailVOs
return "common/web/sitemap_html", nil
}
func (f *FeedHandler) getLastModifiedTime(posts []*entity.Post) time.Time {
lastModifiedTime := time.Time{}
for _, post := range posts {
if post.EditTime != nil {
if post.EditTime.After(lastModifiedTime) {
lastModifiedTime = *post.EditTime
}
} else {
if post.CreateTime.After(lastModifiedTime) {
lastModifiedTime = post.CreateTime
}
}
}
if lastModifiedTime == (time.Time{}) {
lastModifiedTime = time.Now()
}
return lastModifiedTime
}
var xmlInValidChar = regexp.MustCompile("[\x00-\x1F\x7F]")
func (f *FeedHandler) buildPost(ctx context.Context, posts []*entity.Post) ([]*vo.PostDetailVO, error) {
postDetailVOs, err := f.PostAssembler.ConvertToDetailVOs(ctx, posts)
if err != nil {
return nil, err
}
for _, postDetailVO := range postDetailVOs {
postDetailVO.Content = xmlInValidChar.ReplaceAllString(postDetailVO.Content, "")
postDetailVO.Summary = xmlInValidChar.ReplaceAllString(postDetailVO.Summary, "")
}
return postDetailVOs, nil
}

@ -0,0 +1,31 @@
package content
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/handler/content/model"
"github.com/go-sonic/sonic/template"
"github.com/go-sonic/sonic/util"
)
type IndexHandler struct {
PostModel *model.PostModel
}
func NewIndexHandler(postModel *model.PostModel) *IndexHandler {
return &IndexHandler{
PostModel: postModel,
}
}
func (h *IndexHandler) Index(ctx *gin.Context, model template.Model) (string, error) {
return h.PostModel.List(ctx, 0, model)
}
func (h *IndexHandler) IndexPage(ctx *gin.Context, model template.Model) (string, error) {
page, err := util.ParamInt32(ctx, "page")
if err != nil {
return "", err
}
return h.PostModel.List(ctx, int(page)-1, model)
}

@ -0,0 +1,18 @@
package content
import "github.com/go-sonic/sonic/injection"
func init() {
injection.Provide(
NewIndexHandler,
NewFeedHandler,
NewArchiveHandler,
NewViewHandler,
NewCategoryHandler,
NewSheetHandler,
NewTagHandler,
NewLinkHandler,
NewPhotoHandler,
NewJournalHandler,
)
}

@ -0,0 +1,41 @@
package content
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/handler/content/model"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/template"
"github.com/go-sonic/sonic/util"
)
type JournalHandler struct {
OptionService service.OptionService
JournalService service.JournalService
JournalModel *model.JournalModel
}
func NewJournalHandler(
optionService service.OptionService,
journalService service.JournalService,
journalModel *model.JournalModel,
) *JournalHandler {
return &JournalHandler{
OptionService: optionService,
JournalService: journalService,
JournalModel: journalModel,
}
}
func (p *JournalHandler) JournalsPage(ctx *gin.Context, model template.Model) (string, error) {
page, err := util.ParamInt32(ctx, "page")
if err != nil {
return "", err
}
return p.JournalModel.Journals(ctx, model, int(page-1))
}
func (p *JournalHandler) Journals(ctx *gin.Context, model template.Model) (string, error) {
return p.JournalModel.Journals(ctx, model, 0)
}

@ -0,0 +1,24 @@
package content
import (
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/handler/content/model"
"github.com/go-sonic/sonic/template"
)
type LinkHandler struct {
LinkModel *model.LinkModel
}
func NewLinkHandler(
linkModel *model.LinkModel,
) *LinkHandler {
return &LinkHandler{
LinkModel: linkModel,
}
}
func (t *LinkHandler) Link(ctx *gin.Context, model template.Model) (string, error) {
return t.LinkModel.Links(ctx, model)
}

@ -0,0 +1,122 @@
package model
import (
"context"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/handler/content/authentication"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/service/assembler"
"github.com/go-sonic/sonic/template"
)
func NewCategoryModel(optionService service.OptionService,
postService service.PostService,
themeService service.ThemeService,
postCategoryService service.PostCategoryService,
categoryService service.CategoryService,
postTagService service.PostTagService,
tagService service.TagService,
postAssembler assembler.PostAssembler,
metaService service.MetaService,
categoryAuthentication *authentication.CategoryAuthentication,
) *CategoryModel {
return &CategoryModel{
OptionService: optionService,
PostService: postService,
PostAssembler: postAssembler,
ThemeService: themeService,
PostCategoryService: postCategoryService,
CategoryService: categoryService,
PostTagService: postTagService,
TagService: tagService,
MetaService: metaService,
CategoryAuthentication: categoryAuthentication,
}
}
type CategoryModel struct {
OptionService service.OptionService
PostService service.PostService
ThemeService service.ThemeService
PostCategoryService service.PostCategoryService
CategoryService service.CategoryService
PostTagService service.PostTagService
TagService service.TagService
MetaService service.MetaService
PostAssembler assembler.PostAssembler
CategoryAuthentication *authentication.CategoryAuthentication
}
func (c *CategoryModel) ListCategories(ctx context.Context, model template.Model) (string, error) {
seoKeyWords := c.OptionService.GetOrByDefault(ctx, property.SeoKeywords)
seoDescription := c.OptionService.GetOrByDefault(ctx, property.SeoDescription)
model["is_categories"] = true
model["meta_keywords"] = seoKeyWords
model["meta_description"] = seoDescription
return c.ThemeService.Render(ctx, "categories")
}
func (c *CategoryModel) CategoryDetail(ctx context.Context, model template.Model, slug string, page int, token string) (string, error) {
category, err := c.CategoryService.GetBySlug(ctx, slug)
if err != nil {
return "", err
}
if category.Type == consts.CategoryTypeIntimate {
if isAuthenticated, err := c.CategoryAuthentication.IsAuthenticated(ctx, token, category.ID); err != nil || !isAuthenticated {
model["slug"] = category.Slug
model["type"] = consts.EncryptTypeCategory.Name()
if exist, err := c.ThemeService.TemplateExist(ctx, "post_password.tmpl"); err == nil && exist {
return c.ThemeService.Render(ctx, "post_password")
}
return "common/template/post_password", nil
}
}
pageSize := c.OptionService.GetOrByDefault(ctx, property.ArchivePageSize).(int)
sort := c.OptionService.GetPostSort(ctx)
postQuery := param.PostQuery{
Page: param.Page{
PageNum: page,
PageSize: pageSize,
},
Sort: &sort,
Statuses: []*consts.PostStatus{consts.PostStatusPublished.Ptr()},
CategoryID: &category.ID,
}
if category.Password != "" {
postQuery.Statuses = append(postQuery.Statuses, consts.PostStatusIntimate.Ptr())
}
posts, totalPage, err := c.PostService.Page(ctx, postQuery)
if err != nil {
return "", err
}
postVOs, err := c.PostAssembler.ConvertToListVO(ctx, posts)
if err != nil {
return "", err
}
postPage := dto.NewPage(postVOs, totalPage, param.Page{
PageNum: page,
PageSize: pageSize,
})
categoryDTO, err := c.CategoryService.ConvertToCategoryDTO(ctx, category)
if err != nil {
return "", err
}
if categoryDTO.Description != "" {
model["meta_description"] = categoryDTO.Description
} else {
model["meta_description"] = c.OptionService.GetOrByDefault(ctx, property.SeoDescription)
}
model["is_category"] = true
model["posts"] = postPage
model["category"] = categoryDTO
model["meta_keywords"] = c.OptionService.GetOrByDefault(ctx, property.SeoKeywords)
return c.ThemeService.Render(ctx, "category")
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save