mirror of https://gitee.com/answerdev/answer.git
Merge branch 'ui' of git.backyard.segmentfault.com:opensource/answer into ui
This commit is contained in:
commit
bf85f586d8
|
@ -10,7 +10,7 @@
|
|||
/.vscode/*.log
|
||||
/cmd/answer/*.sh
|
||||
/cmd/logs
|
||||
/configs/*
|
||||
/configs/config-dev.yaml
|
||||
/go.work*
|
||||
/logs
|
||||
/ui/build
|
||||
|
|
|
@ -27,11 +27,8 @@ stages:
|
|||
"compile the golang project":
|
||||
image: golang:1.18
|
||||
stage: compile-golang
|
||||
before_script:
|
||||
- export GOPROXY="https://goproxy.cn"
|
||||
- export GOPRIVATE=git.backyard.segmentfault.com
|
||||
- sh ./script/prebuild.sh
|
||||
script:
|
||||
- make generate
|
||||
- make build
|
||||
artifacts:
|
||||
paths:
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Contributing to answer
|
||||
## Coding and documentation Style
|
||||
|
||||
## Submitting Modifications
|
22
Dockerfile
22
Dockerfile
|
@ -4,12 +4,7 @@ LABEL maintainer="mingcheng<mc@sf.com>"
|
|||
|
||||
COPY . /answer
|
||||
WORKDIR /answer
|
||||
|
||||
RUN make install-ui-packages ui
|
||||
RUN mv ui/build /tmp
|
||||
CMD ls -al /tmp
|
||||
RUN du -sh /tmp/build
|
||||
|
||||
RUN make install-ui-packages ui && mv ui/build /tmp
|
||||
|
||||
FROM golang:1.18 AS golang-builder
|
||||
LABEL maintainer="aichy"
|
||||
|
@ -23,16 +18,15 @@ ENV GOPRIVATE git.backyard.segmentfault.com
|
|||
# Build
|
||||
COPY . ${BUILD_DIR}
|
||||
WORKDIR ${BUILD_DIR}
|
||||
COPY --from=node-builder /tmp/build ${BUILD_DIR}/web/html
|
||||
CMD ls -al ${BUILD_DIR}/web/html
|
||||
COPY --from=node-builder /tmp/build ${BUILD_DIR}/ui/build
|
||||
RUN make clean build && \
|
||||
cp answer /usr/bin/answer && \
|
||||
cp configs/config.yaml /etc/config.yaml && \
|
||||
mkdir -p /tmp/cache && chmod 777 /tmp/cache && \
|
||||
mkdir -p /data/upfiles && chmod 777 /data/upfiles && cp -r i18n /data
|
||||
mkdir /data && chmod 777 /data && cp configs/config.yaml /data/config.yaml && \
|
||||
mkdir -p /data/upfiles && chmod 777 /data/upfiles && \
|
||||
mkdir -p /data/i18n && chmod 777 /data/i18n && cp -r i18n/*.yaml /data/i18n
|
||||
|
||||
FROM debian:bullseye
|
||||
|
||||
ENV TZ "Asia/Shanghai"
|
||||
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list \
|
||||
&& sed -i 's/security.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list \
|
||||
|
@ -45,9 +39,9 @@ RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.li
|
|||
COPY --from=golang-builder /data /data
|
||||
VOLUME /data
|
||||
|
||||
COPY --from=golang-builder /etc/config.yaml /etc/answer.yaml
|
||||
COPY --from=golang-builder /usr/bin/answer /usr/bin/answer
|
||||
COPY /script/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod 755 /entrypoint.sh
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["dumb-init", "/usr/bin/answer", "-c", "/etc/answer.yaml"]
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
|
5
Makefile
5
Makefile
|
@ -12,6 +12,11 @@ GO=$(GO_ENV) $(shell which go)
|
|||
build:
|
||||
@$(GO_ENV) $(GO) build $(GO_FLAGS) -o $(BIN) $(DIR_SRC)
|
||||
|
||||
generate:
|
||||
go get github.com/google/wire/cmd/wire@latest
|
||||
go generate ./...
|
||||
go mod tidy
|
||||
|
||||
test:
|
||||
@$(GO) test ./...
|
||||
|
||||
|
|
59
README.md
59
README.md
|
@ -1,35 +1,38 @@
|
|||
# answer
|
||||
![logo](docs/img/logo.png)
|
||||
|
||||
问答社区主项目代码
|
||||
# Answer - Simple Q&A Community
|
||||
|
||||
# Dependence
|
||||
github.com/segmentfault/pacman
|
||||
* config-file `viper` https://github.com/spf13/viper
|
||||
* web `gin` https://gin-gonic.com/zh-cn/
|
||||
* log `zap` https://github.com/uber-go/zap
|
||||
* orm `xorm` https://xorm.io/zh/
|
||||
* redis `go-redis` https://github.com/go-redis/redis
|
||||
[![LICENSE](https://img.shields.io/badge/License-MIT-green)](https://github.com/segmentfault/answer/blob/master/LICENSE)
|
||||
[![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/)
|
||||
[![Language](https://img.shields.io/badge/Language-React-blue.svg)](https://reactjs.org/)
|
||||
|
||||
# module
|
||||
- email github.com/jordan-wright/email
|
||||
- session github.com/gin-contrib/sessions
|
||||
- Captcha github.com/mojocn/base64Captcha
|
||||
## What is Answer?
|
||||
This is a minimalist open source Q&A community. Users can post questions and others can answer them.
|
||||
![abstract](docs/img/abstract.png)
|
||||
|
||||
# Run
|
||||
```
|
||||
cd cmd
|
||||
export GOPRIVATE=git.backyard.segmentfault.com
|
||||
go mod tidy
|
||||
./dev.sh
|
||||
## Why?
|
||||
- Help companies build knowledge and Q&A communities better and faster.
|
||||
|
||||
## Features
|
||||
- Produce knowledge by asking and answering questions.
|
||||
- Maintain knowledge by voting and working together.
|
||||
|
||||
## Quick start
|
||||
### Running with docker-compose
|
||||
```bash
|
||||
mkdir answer && cd answer
|
||||
wget https://github.com/segmentfault/answer/releases/latest/download/docker-compose.yaml
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
# pprof
|
||||
For more information you can see [INSTALL.md](./INSTALL.md)
|
||||
|
||||
```
|
||||
# Installation dependency
|
||||
go get -u github.com/google/pprof
|
||||
brew install graphviz
|
||||
```
|
||||
```
|
||||
pprof -http :8082 http://XXX/debug/pprof/profile\?seconds\=10
|
||||
```
|
||||
## Contributing
|
||||
|
||||
Contributions are always welcome!
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for ways to get started.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/segmentfault/answer/blob/master/LICENSE)
|
||||
|
|
39
README_CN.md
39
README_CN.md
|
@ -1,9 +1,38 @@
|
|||
# Answer 问答社区
|
||||
![logo](docs/img/logo.png)
|
||||
|
||||
## 功能说明
|
||||
# Answer - 极简问答社区
|
||||
|
||||
## 安装
|
||||
[![LICENSE](https://img.shields.io/badge/License-MIT-green)](https://github.com/segmentfault/answer/blob/master/LICENSE)
|
||||
[![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/)
|
||||
[![Language](https://img.shields.io/badge/Language-React-blue.svg)](https://reactjs.org/)
|
||||
|
||||
## 配置
|
||||
## 什么是 Answer?
|
||||
这是一个极简的开源问答社区。用户可以发布问题,其他人可以回答。
|
||||
![abstract](docs/img/abstract.png)
|
||||
|
||||
## 常见问题
|
||||
## 目标
|
||||
- 帮助企业更好更快构建知识问答社区
|
||||
|
||||
## 产品功能
|
||||
- 通过提问、回答方式生产知识
|
||||
- 通过投票、共同协作方式维护知识
|
||||
|
||||
## 快速开始
|
||||
### 使用 docker-compose 快速搭建
|
||||
```bash
|
||||
mkdir answer && cd answer
|
||||
wget https://github.com/segmentfault/answer/releases/latest/download/docker-compose.yaml
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
其他安装配置细节请参考 [INSTALL.md](./INSTALL.md)
|
||||
|
||||
## 贡献
|
||||
|
||||
我们随时欢迎你的贡献!
|
||||
|
||||
参考 [CONTRIBUTING.md](CONTRIBUTING.md) 其中的贡献指南
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/segmentfault/answer/blob/master/LICENSE)
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `activity`
|
||||
--
|
||||
|
||||
CREATE TABLE `activity` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'Activity ID autoincrement',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`user_id` bigint(20) NOT NULL COMMENT 'the user ID that generated the activity or affected by the activity',
|
||||
`trigger_user_id` bigint(20) NOT NULL DEFAULT '0',
|
||||
`object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'the object ID that affected by the activity',
|
||||
`activity_type` int(11) NOT NULL COMMENT 'activity type, correspond to config id',
|
||||
`cancelled` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'mark this activity if cancelled or not,default 0(not cancelled)',
|
||||
`rank` int(11) NOT NULL DEFAULT '0' COMMENT 'rank of current operating user affected',
|
||||
`has_rank` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'this activity has rank or not'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='activity';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `answer`
|
||||
--
|
||||
|
||||
CREATE TABLE `answer` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'answer id',
|
||||
`question_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'question id',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'answer user id',
|
||||
`original_text` mediumtext NOT NULL COMMENT 'original text',
|
||||
`parsed_text` mediumtext NOT NULL COMMENT 'parsed text',
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT ' answer status(available: 1; deleted: 10)',
|
||||
`adopted` int(11) NOT NULL DEFAULT '1' COMMENT 'adopted (1 failed 2 adopted)',
|
||||
`comment_count` int(11) NOT NULL DEFAULT '0' COMMENT 'comment count',
|
||||
`vote_count` int(11) NOT NULL DEFAULT '0' COMMENT 'vote count',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`revision_id` bigint(20) NOT NULL DEFAULT '0'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='answer';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `collection`
|
||||
--
|
||||
|
||||
CREATE TABLE `collection` (
|
||||
`id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'collection id',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user id',
|
||||
`object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'object id',
|
||||
`user_collection_group_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user collection group id',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='collection';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `collection_group`
|
||||
--
|
||||
|
||||
CREATE TABLE `collection_group` (
|
||||
`id` bigint(20) NOT NULL,
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0',
|
||||
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'the collection group name',
|
||||
`default_group` int(11) NOT NULL DEFAULT '1' COMMENT 'mark this group is default, default 1',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='collection group';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `comment`
|
||||
--
|
||||
|
||||
CREATE TABLE `comment` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'comment id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user id',
|
||||
`reply_user_id` bigint(20) DEFAULT NULL COMMENT 'reply user id',
|
||||
`reply_comment_id` bigint(20) DEFAULT NULL COMMENT 'reply comment id',
|
||||
`object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'object id',
|
||||
`question_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'question id',
|
||||
`vote_count` int(11) NOT NULL DEFAULT '0' COMMENT 'user vote amount',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'comment status(available: 0; deleted: 10)',
|
||||
`original_text` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'original comment content',
|
||||
`parsed_text` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'parsed comment content'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='comment';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `config`
|
||||
--
|
||||
|
||||
CREATE TABLE `config` (
|
||||
`id` int(11) NOT NULL COMMENT 'config id',
|
||||
`key` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'the config key',
|
||||
`value` text COLLATE utf8mb4_unicode_ci COMMENT 'the config value, custom data structures and types'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='config';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `meta`
|
||||
--
|
||||
|
||||
CREATE TABLE `meta` (
|
||||
`id` int(10) UNSIGNED NOT NULL COMMENT 'id',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'created time',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'updated time',
|
||||
`object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'object id',
|
||||
`key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'key',
|
||||
`value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'value'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='meta';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `notification`
|
||||
--
|
||||
|
||||
CREATE TABLE `notification` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'notification id',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user_id',
|
||||
`object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'object id',
|
||||
`content` text NOT NULL COMMENT 'notification content',
|
||||
`type` int(11) NOT NULL DEFAULT '0' COMMENT '1 inbox 2 achievements',
|
||||
`is_read` int(11) NOT NULL DEFAULT '1' COMMENT 'read status(unread: 1; read 2)',
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT 'notification status(normal: 1; delete 2)',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='notification';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `notification_read`
|
||||
--
|
||||
|
||||
CREATE TABLE `notification_read` (
|
||||
`id` int(11) NOT NULL COMMENT 'id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user id',
|
||||
`message_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'message id',
|
||||
`is_read` int(11) NOT NULL DEFAULT '1' COMMENT 'read status(unread: 1; read 2)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='notification read record';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `question`
|
||||
--
|
||||
|
||||
CREATE TABLE `question` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'question id',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user id',
|
||||
`title` varchar(255) NOT NULL DEFAULT '' COMMENT 'question title',
|
||||
`original_text` mediumtext NOT NULL COMMENT 'original text',
|
||||
`parsed_text` mediumtext NOT NULL COMMENT 'parsed text',
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT ' question status(available: 1; deleted: 10)',
|
||||
`view_count` int(11) NOT NULL DEFAULT '0' COMMENT 'view count',
|
||||
`unique_view_count` int(11) NOT NULL DEFAULT '0' COMMENT 'unique view count',
|
||||
`vote_count` int(11) NOT NULL DEFAULT '0' COMMENT 'vote count',
|
||||
`answer_count` int(11) NOT NULL DEFAULT '0' COMMENT 'answer count',
|
||||
`collection_count` int(11) NOT NULL DEFAULT '0' COMMENT 'collection count',
|
||||
`follow_count` int(11) NOT NULL DEFAULT '0' COMMENT 'follow count',
|
||||
`accepted_answer_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'accepted answer id',
|
||||
`last_answer_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'last answer id',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'update time',
|
||||
`post_update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'answer the last update time',
|
||||
`revision_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'revision id'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='question';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `report`
|
||||
--
|
||||
|
||||
CREATE TABLE `report` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`user_id` bigint(20) NOT NULL COMMENT 'reporter user id',
|
||||
`object_id` bigint(20) NOT NULL COMMENT 'object id',
|
||||
`reported_user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'reported user id',
|
||||
`object_type` int(11) NOT NULL DEFAULT '0' COMMENT 'revision type',
|
||||
`report_type` int(11) NOT NULL DEFAULT '0' COMMENT 'report type',
|
||||
`content` text NOT NULL COMMENT 'report content',
|
||||
`flaged_type` int(11) NOT NULL DEFAULT '0',
|
||||
`flaged_content` text,
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT 'status(normal: 1; pending:2; delete: 10)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='report';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `revision`
|
||||
--
|
||||
|
||||
CREATE TABLE `revision` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'user id',
|
||||
`object_type` int(11) NOT NULL DEFAULT '0' COMMENT 'revision type(question: 1; answer 2)',
|
||||
`object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'object id',
|
||||
`title` varchar(255) NOT NULL DEFAULT '' COMMENT 'title',
|
||||
`content` text NOT NULL COMMENT 'content',
|
||||
`log` varchar(255) DEFAULT NULL,
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT 'revision status(normal: 1; delete 2)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='revision';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `site_info`
|
||||
--
|
||||
|
||||
CREATE TABLE `site_info` (
|
||||
`id` int(10) UNSIGNED NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'update time',
|
||||
`type` varchar(64) DEFAULT NULL,
|
||||
`content` mediumtext,
|
||||
`status` int(11) NOT NULL DEFAULT '1'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `tag`
|
||||
--
|
||||
|
||||
CREATE TABLE `tag` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'tag_id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`main_tag_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'main tag id',
|
||||
`main_tag_slug_name` varchar(50) NOT NULL DEFAULT '' COMMENT 'main tag slug name',
|
||||
`slug_name` varchar(50) NOT NULL DEFAULT '' COMMENT 'slug name',
|
||||
`display_name` varchar(50) NOT NULL DEFAULT '' COMMENT 'display name',
|
||||
`original_text` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'original comment content',
|
||||
`parsed_text` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'parsed comment content',
|
||||
`follow_count` int(11) NOT NULL DEFAULT '0' COMMENT 'follow count',
|
||||
`question_count` int(11) NOT NULL COMMENT 'question count',
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT 'tag status(available: 1; deleted: 10)',
|
||||
`revision_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'revision id'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='tag';
|
||||
|
||||
--
|
||||
-- 转存表中的数据 `tag`
|
||||
--
|
||||
|
||||
INSERT INTO `tag` (`id`, `created_at`, `updated_at`, `main_tag_id`, `main_tag_slug_name`, `slug_name`, `display_name`, `original_text`, `parsed_text`, `follow_count`, `question_count`, `status`, `revision_id`) VALUES
|
||||
(10030000000000007, '2022-09-07 02:07:16', '2022-09-28 06:56:32', 10030000000000364, 'javascript', 'js', 'Js', 'js', 'Js', 7, 21, 1, 90),
|
||||
(10030000000000008, '2022-09-07 02:07:16', '2022-09-19 08:40:36', 0, '', 'php', 'PHP', '2122121对外只有3001一个端口,群集内有负载策略会分发给不同实例2121211212121212121', '<p>2122121对外只有3001一个端口,群集内有负载策略会分发给不同实例2121211212121212121</p>\n', 2, 3, 10, 101),
|
||||
(10030000000000009, '2022-09-07 02:07:16', '2022-09-28 08:00:48', 0, '', 'go', 'Go', 'abcbcsasasasasa', '<p>abcbcsasasasasa</p>\n', 7, 17, 1, 259),
|
||||
(10030000000000010, '2022-09-07 02:07:16', '2022-09-28 05:16:00', 0, '', 'apple', 'Apple', '对外只有3001一个端口,群集内有负载策略会分发给不同实例', '<p>对外只有3001一个端口,群集内有负载策略会分发给不同实例</p>', 5, 3, 1, 0),
|
||||
(10030000000000113, '2022-09-07 02:07:16', '2022-09-26 08:44:04', 0, '', 'lua', 'lua', '对外只有3001一个端口,群集内有负载策略会分发给不同实例', '<p>对外只有3001一个端口,群集内有负载策略会分发给不同实例</p>', 4, 4, 1, 0),
|
||||
(10030000000000114, '2022-09-07 02:07:16', '2022-09-27 09:57:35', 0, '', 'dell', 'dell', '对外只有3001一个端口,群集内有负载策略会分发给不同实例', '<p>对外只有3001一个端口,群集内有负载策略会分发给不同实例</p>', 3, 0, 1, 0),
|
||||
(10030000000000118, '2022-09-07 02:07:16', '2022-09-28 08:20:13', 0, '', 'dells', 'dells', '对外只有3001一个端口,群集内有负载策略会分发给不同实例', '<p>对外只有3001一个端口,群集内有负载策略会分发给不同实例</p>', 2, 2, 1, 0),
|
||||
(10030000000000183, '2022-09-07 02:07:16', '2022-09-27 08:41:31', 0, '', 'string', 'string', '对外只有3001一个端口,群集内有负载策略会分发给不同实例\n\n好不错', '<p>对外只有3001一个端口,群集内有负载策略会分发给不同实例</p>\n<p>好不错</p>\n', 2, 22, 1, 186),
|
||||
(10030000000000311, '2022-09-07 02:07:16', '2022-09-28 07:59:36', 10030000000000009, 'go', 'golang', 'golang', '', '', 4, 6, 1, 0),
|
||||
(10030000000000312, '2022-09-07 02:12:06', '2022-09-15 08:56:04', 0, '', '算法', '算法', '', '', 1, 0, 1, 0),
|
||||
(10030000000000314, '2022-09-07 02:14:08', '2022-09-26 06:54:36', 0, '', 'java', 'java', '', '', 1, 6, 1, 0),
|
||||
(10030000000000316, '2022-09-07 02:14:28', '2022-09-28 08:20:13', 10030000000000009, 'go', 'golang2', 'golang2', 'golang2', 'golang2', 1, 2, 1, 28),
|
||||
(10030000000000324, '2022-09-07 07:14:19', '2022-09-20 03:27:14', 0, '', 'python', 'python', '', '', 0, 2, 1, 41),
|
||||
(10030000000000325, '2022-09-07 07:17:52', '2022-09-27 08:41:31', 0, '', 'spring boot', 'spring boot', '', '', 2, 2, 1, 43),
|
||||
(10030000000000364, '2022-09-08 01:45:26', '2022-09-27 08:41:31', 0, '', 'javascript', 'javascript', 'JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat.\n\nJavaScript is a prototype-based, multi-paradigm, single-threaded, dynamic language, supporting object-oriented, imperative, and declarative (e.g. functional programming) styles. Read more about JavaScript. This section is dedicated to the JavaScript language itself, and not the parts that are specific to Web pages or other host environments. For information about APIs that are specific to Web pages, please see Web APIs and DOM.', '<p>JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat.</p>\n<p>JavaScript is a prototype-based, multi-paradigm, single-threaded, dynamic language, supporting object-oriented, imperative, and declarative (e.g. functional programming) styles. Read more about JavaScript. This section is dedicated to the JavaScript language itself, and not the parts that are specific to Web pages or other host environments. For information about APIs that are specific to Web pages, please see Web APIs and DOM.</p>\n', 3, 3, 1, 292),
|
||||
(10030000000000401, '2022-09-08 07:26:38', '2022-09-28 08:20:13', 0, '', 'test', 'test', '111111\ngjsdghjfghjgjfhgasjdhgfhjasg[hello](https://www.baidu.com)\n\n22222222222\n\n3333333\n\n', '<p>111111\ngjsdghjfghjgjfhgasjdhgfhjasg<a href=\"https://www.baidu.com\">hello</a></p>\n<p>22222222222</p>\n<p>3333333</p>\n', 1, 3, 1, 303),
|
||||
(10030000000000408, '2022-09-08 08:38:03', '2022-09-08 08:38:03', 0, '', 'code ', 'code ', 'code is code', '<p>code is code</p>\n', 0, 0, 1, 70),
|
||||
(10030000000000428, '2022-09-08 11:44:10', '2022-09-26 06:54:31', 0, '', 'abc', 'abc', 'JavaScript 是一门弱类型的动态脚本语言,支持多种编程范式,包括面向对象和函数式编程,被广泛用于 Web 开发。\n\n一般来说,完整的JavaScript包括以下几个部分:\n- ECMAScript,描述了该语言的语法和基本对象\n- 文档对象模型(DOM),描述处理网页内容的方法和接口\n- 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口\n\n它的基本特点如下:\n- 是一种解释性脚本语言(代码不进行预编译)。\n- 主要用来向HTML页面添加交互行为。\n- 可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。\n\nJavaScript常用来完成以下任务:\n- 嵌入动态文本于HTML页面\n- 对浏览器事件作出响应\n- 读写HTML元素\n- 在数据被提交到服务器之前验证数据\n- 检测访客的浏览器信息\n\n![《 Javascript 优点在整个语言中占多大比例?][1]\n\n [1]: http://segmentfault.com/img/bVFXU', '<p>JavaScript 是一门弱类型的动态脚本语言,支持多种编程范式,包括面向对象和函数式编程,被广泛用于 Web 开发。</p>\n<p>一般来说,完整的JavaScript包括以下几个部分:</p>\n<ul>\n<li>ECMAScript,描述了该语言的语法和基本对象</li>\n<li>文档对象模型(DOM),描述处理网页内容的方法和接口</li>\n<li>浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口</li>\n</ul>\n<p>它的基本特点如下:</p>\n<ul>\n<li>是一种解释性脚本语言(代码不进行预编译)。</li>\n<li>主要用来向HTML页面添加交互行为。</li>\n<li>可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。</li>\n</ul>\n<p>JavaScript常用来完成以下任务:</p>\n<ul>\n<li>嵌入动态文本于HTML页面</li>\n<li>对浏览器事件作出响应</li>\n<li>读写HTML元素</li>\n<li>在数据被提交到服务器之前验证数据</li>\n<li>检测访客的浏览器信息</li>\n</ul>\n<p><img src=\"http://segmentfault.com/img/bVFXU\" alt=\"《 Javascript 优点在整个语言中占多大比例?\"></p>\n', 0, 0, 1, 113),
|
||||
(10030000000000507, '2022-09-16 06:32:36', '2022-09-16 08:14:27', 0, '', 'dddddd', 'dddddd', 'ddddddddddddddddd', 'ddddddddddddddddddd', 0, 1, 1, 144),
|
||||
(10030000000000510, '2022-09-16 07:04:34', '2022-09-16 07:30:43', 0, '', 'vim', 'vim', 'vim', '<p>vim</p>\n', 0, 0, 1, 147),
|
||||
(10030000000000592, '2022-09-20 10:23:28', '2022-09-27 08:41:31', 0, '', 'android-studio', 'Android-Studio', '', '', 3, 2, 1, 170),
|
||||
(10030000000000644, '2022-09-23 09:25:39', '2022-09-27 08:41:31', 0, '', 'great', 'great', 'great', '<p>great</p>\n', 2, 1, 1, 272),
|
||||
(10030000000000687, '2022-09-26 10:48:07', '2022-09-28 01:39:19', 0, '', 'qwer', 'qwerDis', 'qwert', '<p>qwert</p>\n', 0, 0, 1, 316),
|
||||
(10030000000000688, '2022-09-26 10:49:39', '2022-09-28 08:20:13', 0, '', 'qwers', 'qwerDiss', 'qwerts', 'qwerts', 0, 1, 1, 300),
|
||||
(10030000000000689, '2022-09-26 10:50:34', '2022-09-28 08:20:13', 10030000000000364, 'javascript', 'jss', '', '', '', 0, 0, 1, 302),
|
||||
(10030000000000708, '2022-09-27 02:12:03', '2022-09-28 05:00:51', 0, '', 'flutter', 'Flutter', '', '<p>212121212121</p>\n', 3, 1, 1, 305),
|
||||
(10030000000000712, '2022-09-27 02:32:53', '2022-09-27 10:09:37', 0, '', 'nextjs', 'Nextjs', '', '<p>2121212121</p>\n', 1, 1, 1, 307),
|
||||
(10030000000000713, '2022-09-27 02:36:29', '2022-09-27 08:41:31', 0, '', 'umijs', 'Umijs', '212121212112121211', '<p>212121212112121211</p>\n', 1, 1, 1, 309),
|
||||
(10030000000000739, '2022-09-28 01:45:09', '2022-09-28 01:45:18', 0, '', '', '', '', '', 0, 0, 1, 320);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `tag_rel`
|
||||
--
|
||||
|
||||
CREATE TABLE `tag_rel` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'tag_list_id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`object_id` bigint(20) NOT NULL COMMENT 'object_id',
|
||||
`tag_id` bigint(20) NOT NULL COMMENT 'tag_id',
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT 'tag_list_status(available: 1; deleted: 10)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='tag relation';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `uniqid`
|
||||
--
|
||||
|
||||
CREATE TABLE `uniqid` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'uniqid_id',
|
||||
`uniqid_type` int(11) NOT NULL DEFAULT '0' COMMENT 'uniqid_type'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='uniqid';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `user`
|
||||
--
|
||||
|
||||
CREATE TABLE `user` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'user id',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT 'create time',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'update time',
|
||||
`suspended_at` timestamp NULL DEFAULT NULL COMMENT 'suspended time',
|
||||
`deleted_at` timestamp NULL DEFAULT NULL COMMENT 'delete time',
|
||||
`last_login_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'last login date',
|
||||
`username` varchar(50) NOT NULL DEFAULT '' COMMENT 'username',
|
||||
`pass` varchar(255) NOT NULL DEFAULT '' COMMENT 'password',
|
||||
`e_mail` varchar(100) NOT NULL COMMENT 'email',
|
||||
`mail_status` tinyint(4) NOT NULL DEFAULT '2' COMMENT 'mail status(1 pass 2 to be verified)',
|
||||
`notice_status` int(11) NOT NULL DEFAULT '2' COMMENT 'notice status(1 on 2off)',
|
||||
`follow_count` int(11) NOT NULL DEFAULT '0' COMMENT 'follow count',
|
||||
`answer_count` int(11) NOT NULL DEFAULT '0' COMMENT 'answer_count',
|
||||
`question_count` int(11) NOT NULL DEFAULT '0' COMMENT 'question_count',
|
||||
`rank` int(11) NOT NULL DEFAULT '0' COMMENT 'rank',
|
||||
`status` int(11) NOT NULL DEFAULT '1' COMMENT 'user status(available: 0; deleted: 10)',
|
||||
`authority_group` int(11) NOT NULL DEFAULT '1' COMMENT 'authority group',
|
||||
`display_name` varchar(50) NOT NULL DEFAULT '' COMMENT 'display name',
|
||||
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT 'avatar',
|
||||
`mobile` varchar(20) NOT NULL COMMENT 'mobile',
|
||||
`bio` text NOT NULL COMMENT 'bio markdown',
|
||||
`bio_html` text NOT NULL COMMENT 'bio html',
|
||||
`website` varchar(255) NOT NULL DEFAULT '' COMMENT 'website',
|
||||
`location` varchar(100) NOT NULL DEFAULT '' COMMENT 'location',
|
||||
`ip_info` varchar(255) NOT NULL DEFAULT '' COMMENT 'ip info',
|
||||
`is_admin` int(11) NOT NULL COMMENT 'admin flag'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='user';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `user_group`
|
||||
--
|
||||
|
||||
CREATE TABLE `user_group` (
|
||||
`id` bigint(20) UNSIGNED NOT NULL COMMENT 'user group id'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='user group';
|
||||
|
||||
--
|
||||
-- 转储表的索引
|
||||
--
|
||||
|
||||
--
|
||||
-- 表的索引 `activity`
|
||||
--
|
||||
ALTER TABLE `activity`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD KEY `post_id` (`object_id`),
|
||||
ADD KEY `user_id` (`user_id`),
|
||||
ADD KEY `trigger_user_id` (`trigger_user_id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `answer`
|
||||
--
|
||||
ALTER TABLE `answer`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `collection`
|
||||
--
|
||||
ALTER TABLE `collection`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `collection_group`
|
||||
--
|
||||
ALTER TABLE `collection_group`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `comment`
|
||||
--
|
||||
ALTER TABLE `comment`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE;
|
||||
|
||||
--
|
||||
-- 表的索引 `config`
|
||||
--
|
||||
ALTER TABLE `config`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `key` (`key`);
|
||||
|
||||
--
|
||||
-- 表的索引 `meta`
|
||||
--
|
||||
ALTER TABLE `meta`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `notification`
|
||||
--
|
||||
ALTER TABLE `notification`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD KEY `idx_objectid` (`object_id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `notification_read`
|
||||
--
|
||||
ALTER TABLE `notification_read`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE;
|
||||
|
||||
--
|
||||
-- 表的索引 `question`
|
||||
--
|
||||
ALTER TABLE `question`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `report`
|
||||
--
|
||||
ALTER TABLE `report`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE;
|
||||
|
||||
--
|
||||
-- 表的索引 `revision`
|
||||
--
|
||||
ALTER TABLE `revision`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE;
|
||||
|
||||
--
|
||||
-- 表的索引 `site_info`
|
||||
--
|
||||
ALTER TABLE `site_info`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `tag`
|
||||
--
|
||||
ALTER TABLE `tag`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD UNIQUE KEY `slug_name` (`slug_name`);
|
||||
|
||||
--
|
||||
-- 表的索引 `tag_rel`
|
||||
--
|
||||
ALTER TABLE `tag_rel`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD UNIQUE KEY `idx_obj_tag_id` (`object_id`,`tag_id`) USING BTREE,
|
||||
ADD KEY `idx_questionid` (`object_id`),
|
||||
ADD KEY `idx_tagid` (`tag_id`) USING BTREE;
|
||||
|
||||
--
|
||||
-- 表的索引 `uniqid`
|
||||
--
|
||||
ALTER TABLE `uniqid`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `user`
|
||||
--
|
||||
ALTER TABLE `user`
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD UNIQUE KEY `username` (`username`);
|
||||
|
||||
--
|
||||
-- 表的索引 `user_group`
|
||||
--
|
||||
ALTER TABLE `user_group`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `id` (`id`);
|
||||
|
||||
--
|
||||
-- 在导出的表使用AUTO_INCREMENT
|
||||
--
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `activity`
|
||||
--
|
||||
ALTER TABLE `activity`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Activity ID autoincrement';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `answer`
|
||||
--
|
||||
ALTER TABLE `answer`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'answer id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `collection_group`
|
||||
--
|
||||
ALTER TABLE `collection_group`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `comment`
|
||||
--
|
||||
ALTER TABLE `comment`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'comment id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `config`
|
||||
--
|
||||
ALTER TABLE `config`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'config id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `meta`
|
||||
--
|
||||
ALTER TABLE `meta`
|
||||
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `notification`
|
||||
--
|
||||
ALTER TABLE `notification`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'notification id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `notification_read`
|
||||
--
|
||||
ALTER TABLE `notification_read`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `report`
|
||||
--
|
||||
ALTER TABLE `report`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `revision`
|
||||
--
|
||||
ALTER TABLE `revision`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `site_info`
|
||||
--
|
||||
ALTER TABLE `site_info`
|
||||
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `tag_rel`
|
||||
--
|
||||
ALTER TABLE `tag_rel`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'tag_list_id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `uniqid`
|
||||
--
|
||||
ALTER TABLE `uniqid`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'uniqid_id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `user`
|
||||
--
|
||||
ALTER TABLE `user`
|
||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'user id';
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `user_group`
|
||||
--
|
||||
ALTER TABLE `user_group`
|
||||
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'user group id';
|
||||
COMMIT;
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package assets
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed answer.sql
|
||||
var AnswerSql []byte
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/internal/base/conf"
|
||||
"github.com/segmentfault/answer/internal/cli"
|
||||
"github.com/segmentfault/pacman"
|
||||
"github.com/segmentfault/pacman/contrib/conf/viper"
|
||||
"github.com/segmentfault/pacman/contrib/log/zap"
|
||||
|
@ -37,6 +38,24 @@ func init() {
|
|||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
cli.Usage()
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "init" {
|
||||
cli.InitConfig()
|
||||
return
|
||||
}
|
||||
if len(args) >= 3 {
|
||||
if args[0] == "run" && args[1] == "-c" {
|
||||
confFlag = args[2]
|
||||
}
|
||||
}
|
||||
|
||||
log.SetLogger(zap.NewLogger(
|
||||
log.ParseLevel(logLevel), zap.WithName(Name), zap.WithPath(logPath), zap.WithCallerFullPath()))
|
||||
|
||||
|
@ -55,13 +74,18 @@ func main() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = cli.CommandCli.InitDB()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer cleanup()
|
||||
if err := app.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newApplication(serverConf *conf.Server, server *gin.Engine) *pacman.Application {
|
||||
func newApplication(serverConf *conf.Server, server *gin.Engine, cli *cli.Cli) *pacman.Application {
|
||||
return pacman.NewApp(
|
||||
pacman.WithName(Name),
|
||||
pacman.WithVersion(Version),
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/segmentfault/answer/internal/base/middleware"
|
||||
"github.com/segmentfault/answer/internal/base/server"
|
||||
"github.com/segmentfault/answer/internal/base/translator"
|
||||
"github.com/segmentfault/answer/internal/cli"
|
||||
"github.com/segmentfault/answer/internal/controller"
|
||||
"github.com/segmentfault/answer/internal/controller_backyard"
|
||||
"github.com/segmentfault/answer/internal/repo"
|
||||
|
@ -33,6 +34,7 @@ func initApplication(
|
|||
serviceConf *service_config.ServiceConfig,
|
||||
logConf log.Logger) (*pacman.Application, func(), error) {
|
||||
panic(wire.Build(
|
||||
cli.ProviderSetCli,
|
||||
server.ProviderSetServer,
|
||||
router.ProviderSetRouter,
|
||||
controller.ProviderSetController,
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/segmentfault/answer/internal/base/middleware"
|
||||
"github.com/segmentfault/answer/internal/base/server"
|
||||
"github.com/segmentfault/answer/internal/base/translator"
|
||||
"github.com/segmentfault/answer/internal/cli"
|
||||
"github.com/segmentfault/answer/internal/controller"
|
||||
"github.com/segmentfault/answer/internal/controller_backyard"
|
||||
"github.com/segmentfault/answer/internal/repo"
|
||||
|
@ -101,13 +102,14 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
userController := controller.NewUserController(authService, userService, captchaService, emailService, uploaderService)
|
||||
commentRepo := comment.NewCommentRepo(dataData, uniqueIDRepo)
|
||||
commentCommonRepo := comment.NewCommentCommonRepo(dataData, uniqueIDRepo)
|
||||
userCommon := usercommon.NewUserCommon(userRepo)
|
||||
answerRepo := repo.NewAnswerRepo(dataData, uniqueIDRepo, userRankRepo, activityRepo)
|
||||
questionRepo := repo.NewQuestionRepo(dataData, uniqueIDRepo)
|
||||
tagRepo := tag.NewTagRepo(dataData, uniqueIDRepo)
|
||||
objService := object_info.NewObjService(answerRepo, questionRepo, commentCommonRepo, tagRepo)
|
||||
voteRepo := activity_common.NewVoteRepo(dataData, activityRepo)
|
||||
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userRepo, objService, voteRepo)
|
||||
rankService := rank2.NewRankService(userRepo, userRankRepo, objService, configRepo)
|
||||
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo)
|
||||
rankService := rank2.NewRankService(userCommon, userRankRepo, objService, configRepo)
|
||||
commentController := controller.NewCommentController(commentService, rankService)
|
||||
reportRepo := report.NewReportRepo(dataData, uniqueIDRepo)
|
||||
reportService := report2.NewReportService(reportRepo, objService)
|
||||
|
@ -127,7 +129,6 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
collectionGroupRepo := collection.NewCollectionGroupRepo(dataData)
|
||||
tagRelRepo := tag.NewTagListRepo(dataData)
|
||||
tagCommonService := tagcommon.NewTagCommonService(tagRepo, tagRelRepo, revisionService)
|
||||
userCommon := usercommon.NewUserCommon(userRepo)
|
||||
collectionCommon := collectioncommon.NewCollectionCommon(collectionRepo)
|
||||
answerCommon := answercommon.NewAnswerCommon(answerRepo)
|
||||
metaRepo := meta.NewMetaRepo(dataData)
|
||||
|
@ -142,10 +143,10 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
questionController := controller.NewQuestionController(questionService, rankService)
|
||||
answerService := service.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo)
|
||||
answerController := controller.NewAnswerController(answerService, rankService)
|
||||
searchRepo := repo.NewSearchRepo(dataData, uniqueIDRepo, userRepo)
|
||||
searchService := service.NewSearchService(searchRepo, tagRepo, userRepo, followRepo)
|
||||
searchRepo := repo.NewSearchRepo(dataData, uniqueIDRepo, userCommon)
|
||||
searchService := service.NewSearchService(searchRepo, tagRepo, userCommon, followRepo)
|
||||
searchController := controller.NewSearchController(searchService)
|
||||
serviceRevisionService := service.NewRevisionService(revisionRepo, userRepo, questionCommon, answerService)
|
||||
serviceRevisionService := service.NewRevisionService(revisionRepo, userCommon, questionCommon, answerService)
|
||||
revisionController := controller.NewRevisionController(serviceRevisionService)
|
||||
rankController := controller.NewRankController(rankService)
|
||||
commonRepo := common.NewCommonRepo(dataData, uniqueIDRepo)
|
||||
|
@ -169,10 +170,11 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
notificationController := controller.NewNotificationController(notificationService)
|
||||
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_backyardReportController, userBackyardController, reasonController, themeController, siteInfoController, siteinfoController, notificationController)
|
||||
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
|
||||
viewRouter := router.NewViewRouter()
|
||||
uiRouter := router.NewUIRouter()
|
||||
authUserMiddleware := middleware.NewAuthUserMiddleware(authService)
|
||||
ginEngine := server.NewHTTPServer(debug, staticRouter, answerAPIRouter, swaggerRouter, viewRouter, authUserMiddleware)
|
||||
application := newApplication(serverConf, ginEngine)
|
||||
ginEngine := server.NewHTTPServer(debug, staticRouter, answerAPIRouter, swaggerRouter, uiRouter, authUserMiddleware)
|
||||
cliCli := cli.NewCli(dataData)
|
||||
application := newApplication(serverConf, ginEngine, cliCli)
|
||||
return application, func() {
|
||||
cleanup2()
|
||||
cleanup()
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package configs
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed config.yaml
|
||||
var Config []byte
|
|
@ -0,0 +1,19 @@
|
|||
server:
|
||||
http:
|
||||
addr: 0.0.0.0:80
|
||||
data:
|
||||
database:
|
||||
connection: root:root@tcp(127.0.0.1:3306)/answer
|
||||
cache:
|
||||
file_path: "/tmp/cache/cache.db"
|
||||
i18n:
|
||||
bundle_dir: "/data/i18n"
|
||||
swaggerui:
|
||||
show: true
|
||||
protocol: http
|
||||
host: 127.0.0.1
|
||||
address: ':80'
|
||||
service_config:
|
||||
secret_key: "answer"
|
||||
web_host: "http://127.0.0.1"
|
||||
upload_path: "./upfiles"
|
|
@ -4,4 +4,6 @@ services:
|
|||
build:
|
||||
context: .
|
||||
image: github.com/segmentfault/answer
|
||||
volumes:
|
||||
- ./data:/data
|
||||
restart: on-failure
|
||||
|
|
52
docs/docs.go
52
docs/docs.go
|
@ -884,7 +884,7 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"/answer/api/v1/answer/list": {
|
||||
"post": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
|
@ -3614,6 +3614,46 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "get user status info",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "get user status info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/schema.GetUserResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/vote/down": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -4206,6 +4246,10 @@ const docTemplate = `{
|
|||
"description": "reply user id",
|
||||
"type": "string"
|
||||
},
|
||||
"reply_user_status": {
|
||||
"description": "reply user status",
|
||||
"type": "string"
|
||||
},
|
||||
"reply_username": {
|
||||
"description": "reply user username",
|
||||
"type": "string"
|
||||
|
@ -4222,6 +4266,10 @@ const docTemplate = `{
|
|||
"description": "user id",
|
||||
"type": "string"
|
||||
},
|
||||
"user_status": {
|
||||
"description": "user status",
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "username",
|
||||
"type": "string"
|
||||
|
@ -5464,7 +5512,7 @@ const docTemplate = `{
|
|||
},
|
||||
"status": {
|
||||
"description": "status",
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "name",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
|
@ -872,7 +872,7 @@
|
|||
}
|
||||
},
|
||||
"/answer/api/v1/answer/list": {
|
||||
"post": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
|
@ -3602,6 +3602,46 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "get user status info",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "get user status info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/schema.GetUserResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/vote/down": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -4194,6 +4234,10 @@
|
|||
"description": "reply user id",
|
||||
"type": "string"
|
||||
},
|
||||
"reply_user_status": {
|
||||
"description": "reply user status",
|
||||
"type": "string"
|
||||
},
|
||||
"reply_username": {
|
||||
"description": "reply user username",
|
||||
"type": "string"
|
||||
|
@ -4210,6 +4254,10 @@
|
|||
"description": "user id",
|
||||
"type": "string"
|
||||
},
|
||||
"user_status": {
|
||||
"description": "user status",
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "username",
|
||||
"type": "string"
|
||||
|
@ -5452,7 +5500,7 @@
|
|||
},
|
||||
"status": {
|
||||
"description": "status",
|
||||
"type": "integer"
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "name",
|
||||
|
|
|
@ -299,6 +299,9 @@ definitions:
|
|||
reply_user_id:
|
||||
description: reply user id
|
||||
type: string
|
||||
reply_user_status:
|
||||
description: reply user status
|
||||
type: string
|
||||
reply_username:
|
||||
description: reply user username
|
||||
type: string
|
||||
|
@ -311,6 +314,9 @@ definitions:
|
|||
user_id:
|
||||
description: user id
|
||||
type: string
|
||||
user_status:
|
||||
description: user status
|
||||
type: string
|
||||
username:
|
||||
description: username
|
||||
type: string
|
||||
|
@ -1209,7 +1215,7 @@ definitions:
|
|||
type: integer
|
||||
status:
|
||||
description: status
|
||||
type: integer
|
||||
type: string
|
||||
username:
|
||||
description: name
|
||||
type: string
|
||||
|
@ -1877,7 +1883,7 @@ paths:
|
|||
tags:
|
||||
- api-answer
|
||||
/answer/api/v1/answer/list:
|
||||
post:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: AnswerList <br> <b>order</b> (default or updated)
|
||||
|
@ -3529,6 +3535,28 @@ paths:
|
|||
summary: UserRegisterByEmail
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/user/status:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: get user status info
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/handler.RespBody'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/schema.GetUserResp'
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: get user status info
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/vote/down:
|
||||
post:
|
||||
consumes:
|
||||
|
|
14
go.mod
14
go.mod
|
@ -19,17 +19,17 @@ require (
|
|||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||
github.com/mojocn/base64Captcha v1.3.5
|
||||
github.com/segmentfault/pacman v1.0.1
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220926035018-18f894415e5b
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220926035018-18f894415e5b
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220926035018-18f894415e5b
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220926035018-18f894415e5b
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220926035018-18f894415e5b
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220929065758-260b3093a347
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220929065758-260b3093a347
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a
|
||||
github.com/swaggo/gin-swagger v1.5.3
|
||||
github.com/swaggo/swag v1.8.6
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||
golang.org/x/net v0.0.0-20220926192436-02166a98028e
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||
xorm.io/builder v0.3.12
|
||||
xorm.io/core v0.7.3
|
||||
xorm.io/xorm v1.3.2
|
||||
|
@ -76,7 +76,7 @@ require (
|
|||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect
|
||||
golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
|
|
21
go.sum
21
go.sum
|
@ -525,14 +525,24 @@ github.com/segmentfault/pacman v1.0.1 h1:GFdvPtNxvVVjnDM4ty02D/+4unHwG9PmjcOZSc2
|
|||
github.com/segmentfault/pacman v1.0.1/go.mod h1:5lNp5REd8QMThmBUvR3Fi9Y3AsOB4GRq7soCB4QLqOs=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220926035018-18f894415e5b h1:jSnRy3z3KVtVuGM2YTZihXwc4zEhW+TvyyJbBm8rjh4=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220926035018-18f894415e5b/go.mod h1:rmf1TCwz67dyM+AmTwSd1BxTo2AOYHj262lP93bOZbs=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220929065758-260b3093a347 h1:0xWBBXHHuemzMY61KYJXh7F5FW/4K8g98RYKNXodTCc=
|
||||
github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20220929065758-260b3093a347/go.mod h1:rmf1TCwz67dyM+AmTwSd1BxTo2AOYHj262lP93bOZbs=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220926035018-18f894415e5b h1:Gx3Brm+VMAyBJn4aBsxgKl+EIhFHc/YH5cLGeFHAW4g=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220926035018-18f894415e5b/go.mod h1:prPjFam7MyZ5b3S9dcDOt2tMPz6kf7C9c243s9zSwPY=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220929065758-260b3093a347 h1:WpnEbmZFE8FYIgvseX+NJtDgGJlM1KSaKJhoxJywUgo=
|
||||
github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20220929065758-260b3093a347/go.mod h1:prPjFam7MyZ5b3S9dcDOt2tMPz6kf7C9c243s9zSwPY=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220926035018-18f894415e5b h1:uQmSgcV2w4OVXU6l3bQb9O+cSAVuzDQ9adJArQyFBa4=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220926035018-18f894415e5b/go.mod h1:5Afm+OQdau/HQqSOp/ALlSUp0vZsMMMbv//kJhxuoi8=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220929065758-260b3093a347 h1:Q29Ky9ZUGhdLIygfX6jwPYeEa7Wqn8o3f1NJWb8LvvE=
|
||||
github.com/segmentfault/pacman/contrib/i18n v0.0.0-20220929065758-260b3093a347/go.mod h1:5Afm+OQdau/HQqSOp/ALlSUp0vZsMMMbv//kJhxuoi8=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220926035018-18f894415e5b h1:TaOBmAglooq+qKdnNTK2sy11t26ud7psHFB7/AV7l5U=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220926035018-18f894415e5b/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220929065758-260b3093a347 h1:7Adjc296AKv32dg88S0T8t9K3+N+PFYLSCctpPnCUr0=
|
||||
github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20220929065758-260b3093a347/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220926035018-18f894415e5b h1:n5n5VPeYGuZCmVppKPgWR/CaINHnL+ipEp9iE1XkcQc=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220926035018-18f894415e5b/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220929065758-260b3093a347 h1:CfuRhTPK2CBQIZruq5ceuTVthspe8U1FDjWXXI2RWdo=
|
||||
github.com/segmentfault/pacman/contrib/server/http v0.0.0-20220929065758-260b3093a347/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
|
@ -584,7 +594,6 @@ github.com/swaggo/swag v1.8.6/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBn
|
|||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
|
@ -648,8 +657,6 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/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-20220924013350-4ba4fb4dd9e7 h1:WJywXQVIb56P2kAvXeMGTIgQ1ZHQxR60+F9dLsodECc=
|
||||
golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -733,10 +740,10 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1
|
|||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI=
|
||||
golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220926192436-02166a98028e h1:I51lVG9ykW5AQeTE50sJ0+gJCAF0J78Hf1+1VUCGxDI=
|
||||
golang.org/x/net v0.0.0-20220926192436-02166a98028e/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/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=
|
||||
|
@ -817,10 +824,10 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 h1:nwzwVf0l2Y/lkov/+IYgMMbFyI+QypZDds9RxlSmsFQ=
|
||||
golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/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=
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package i18n
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *.yaml
|
||||
var I18n embed.FS
|
|
@ -13,6 +13,7 @@ const (
|
|||
UserTokenCacheTime = 7 * 24 * time.Hour
|
||||
AdminTokenCacheKey = "answer:admin:token:"
|
||||
AdminTokenCacheTime = 7 * 24 * time.Hour
|
||||
AcceptLanguageFlag = "Accept-Language"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/internal/base/constant"
|
||||
"github.com/segmentfault/answer/internal/base/reason"
|
||||
"github.com/segmentfault/answer/internal/base/validator"
|
||||
myErrors "github.com/segmentfault/pacman/errors"
|
||||
|
@ -44,13 +45,15 @@ func HandleResponse(ctx *gin.Context, err error, data interface{}) {
|
|||
|
||||
// BindAndCheck bind request and check
|
||||
func BindAndCheck(ctx *gin.Context, data interface{}) bool {
|
||||
lang := GetLang(ctx)
|
||||
ctx.Set(constant.AcceptLanguageFlag, lang)
|
||||
if err := ctx.ShouldBind(data); err != nil {
|
||||
log.Errorf("http_handle BindAndCheck fail, %s", err.Error())
|
||||
HandleResponse(ctx, myErrors.New(http.StatusBadRequest, reason.RequestFormatError), nil)
|
||||
return true
|
||||
}
|
||||
|
||||
errField, err := validator.GetValidatorByLang(GetLang(ctx).Abbr()).Check(data)
|
||||
errField, err := validator.GetValidatorByLang(lang.Abbr()).Check(data)
|
||||
if err != nil {
|
||||
HandleResponse(ctx, myErrors.New(http.StatusBadRequest, reason.RequestFormatError).WithMsg(err.Error()), errField)
|
||||
return true
|
||||
|
|
|
@ -2,12 +2,13 @@ package handler
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/internal/base/constant"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
)
|
||||
|
||||
// GetLang get language from header
|
||||
func GetLang(ctx *gin.Context) i18n.Language {
|
||||
acceptLanguage := ctx.GetHeader("Accept-Language")
|
||||
acceptLanguage := ctx.GetHeader(constant.AcceptLanguageFlag)
|
||||
switch i18n.Language(acceptLanguage) {
|
||||
case i18n.LanguageChinese:
|
||||
return i18n.LanguageChinese
|
||||
|
|
|
@ -17,7 +17,7 @@ type PageCond struct {
|
|||
}
|
||||
|
||||
// NewPageModel new page model
|
||||
func NewPageModel(page, pageSize int, totalRecords int64, records interface{}) *PageModel {
|
||||
func NewPageModel(totalRecords int64, records interface{}) *PageModel {
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(records))
|
||||
if sliceValue.Kind() != reflect.Slice {
|
||||
panic("not a slice")
|
||||
|
|
|
@ -11,7 +11,7 @@ func NewHTTPServer(debug bool,
|
|||
staticRouter *router.StaticRouter,
|
||||
answerRouter *router.AnswerAPIRouter,
|
||||
swaggerRouter *router.SwaggerRouter,
|
||||
viewRouter *router.ViewRouter,
|
||||
viewRouter *router.UIRouter,
|
||||
authUserMiddleware *middleware.AuthUserMiddleware) *gin.Engine {
|
||||
|
||||
if debug {
|
||||
|
@ -22,7 +22,7 @@ func NewHTTPServer(debug bool,
|
|||
r := gin.New()
|
||||
r.GET("/healthz", func(ctx *gin.Context) { ctx.String(200, "OK") })
|
||||
|
||||
viewRouter.RegisterViewRouter(r)
|
||||
viewRouter.Register(r)
|
||||
|
||||
rootGroup := r.Group("")
|
||||
swaggerRouter.Register(rootGroup)
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/segmentfault/answer/configs"
|
||||
"github.com/segmentfault/answer/i18n"
|
||||
"github.com/segmentfault/answer/pkg/dir"
|
||||
)
|
||||
|
||||
var SuccessMsg = `
|
||||
answer initialized successfully
|
||||
`
|
||||
|
||||
var HasBeenInitializedMsg = `
|
||||
Has been initialized.
|
||||
`
|
||||
|
||||
func InitConfig() {
|
||||
exist, err := PathExists("data/config.yaml")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
if exist {
|
||||
fmt.Println(HasBeenInitializedMsg)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
_, err = dir.CreatePathIsNotExist("data")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
WriterFile("data/config.yaml", string(configs.Config))
|
||||
_, err = dir.CreatePathIsNotExist("data/i18n")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
_, err = dir.CreatePathIsNotExist("data/upfiles")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
i18nList, err := i18n.I18n.ReadDir(".")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
for _, item := range i18nList {
|
||||
path := fmt.Sprintf("data/i18n/%s", item.Name())
|
||||
content, err := i18n.I18n.ReadFile(item.Name())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
WriterFile(path, string(content))
|
||||
}
|
||||
fmt.Println(SuccessMsg)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func InitDB() {
|
||||
|
||||
}
|
||||
|
||||
func WriterFile(filePath, content string) error {
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
write := bufio.NewWriter(file)
|
||||
write.WriteString(content)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func PathExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/segmentfault/answer/assets"
|
||||
"github.com/segmentfault/answer/internal/base/data"
|
||||
"github.com/segmentfault/answer/internal/entity"
|
||||
)
|
||||
|
||||
// ProviderSetCli is providers.
|
||||
var ProviderSetCli = wire.NewSet(NewCli)
|
||||
|
||||
type Cli struct {
|
||||
DataSource *data.Data
|
||||
}
|
||||
|
||||
var CommandCli *Cli
|
||||
|
||||
func NewCli(dataSource *data.Data) *Cli {
|
||||
CommandCli = &Cli{DataSource: dataSource}
|
||||
return CommandCli
|
||||
}
|
||||
|
||||
// InitDB init db
|
||||
func (c *Cli) InitDB() (err error) {
|
||||
// check db connection
|
||||
err = c.DataSource.DB.Ping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exist, err := c.DataSource.DB.IsTableExist(&entity.User{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist {
|
||||
return nil
|
||||
}
|
||||
|
||||
// create table if not exist
|
||||
s := &bytes.Buffer{}
|
||||
s.Write(assets.AnswerSql)
|
||||
_, err = c.DataSource.DB.Import(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cli
|
||||
|
||||
import "fmt"
|
||||
|
||||
var usageDoc = `
|
||||
answer
|
||||
|
||||
USAGE
|
||||
answer command
|
||||
|
||||
COMMANDS
|
||||
init init answer config, eg:answer init
|
||||
run config path, eg:answer run -c data/config.yaml
|
||||
`
|
||||
|
||||
func Usage() {
|
||||
fmt.Println(usageDoc)
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -176,23 +175,19 @@ func (ac *AnswerController) Update(ctx *gin.Context) {
|
|||
// @Produce json
|
||||
// @Param data body schema.AnswerList true "AnswerList"
|
||||
// @Success 200 {string} string ""
|
||||
// @Router /answer/api/v1/answer/list [post]
|
||||
func (ac *AnswerController) AnswerList(c *gin.Context) {
|
||||
input := new(schema.AnswerList)
|
||||
err := c.BindJSON(input)
|
||||
if err != nil {
|
||||
handler.HandleResponse(c, err, nil)
|
||||
// @Router /answer/api/v1/answer/list [get]
|
||||
func (ac *AnswerController) AnswerList(ctx *gin.Context) {
|
||||
req := &schema.AnswerList{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
ctx := context.Background()
|
||||
userId := middleware.GetLoginUserIDFromContext(c)
|
||||
input.LoginUserID = userId
|
||||
list, count, err := ac.answerService.SearchList(ctx, input)
|
||||
req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
list, count, err := ac.answerService.SearchList(ctx, req)
|
||||
if err != nil {
|
||||
handler.HandleResponse(c, err, nil)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
handler.HandleResponse(c, nil, gin.H{
|
||||
handler.HandleResponse(ctx, nil, gin.H{
|
||||
"list": list,
|
||||
"count": count,
|
||||
})
|
||||
|
|
|
@ -93,16 +93,16 @@ func (nc *NotificationController) ClearIDUnRead(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, gin.H{})
|
||||
}
|
||||
|
||||
// GetList
|
||||
// @Summary GetRedDot
|
||||
// @Description GetRedDot
|
||||
// GetList get notification list
|
||||
// @Summary get notification list
|
||||
// @Description get notification list
|
||||
// @Tags Notification
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param page query int false "page size"
|
||||
// @Param page_size query int false "page size"
|
||||
// @Param type query string false "type" Enums(inbox,achievement)
|
||||
// @Param type query string true "type" Enums(inbox,achievement)
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/api/v1/notification/page [get]
|
||||
func (nc *NotificationController) GetList(ctx *gin.Context) {
|
||||
|
@ -111,9 +111,6 @@ func (nc *NotificationController) GetList(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
list, count, err := nc.notificationService.GetList(ctx, req)
|
||||
handler.HandleResponse(ctx, err, gin.H{
|
||||
"list": list,
|
||||
"count": count,
|
||||
})
|
||||
resp, err := nc.notificationService.GetList(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
|
|
@ -80,6 +80,21 @@ func (uc *UserController) GetOtherUserInfoByUsername(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// GetUserStatus get user status info
|
||||
// @Summary get user status info
|
||||
// @Description get user status info
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} handler.RespBody{data=schema.GetUserResp}
|
||||
// @Router /answer/api/v1/user/status [get]
|
||||
func (uc *UserController) GetUserStatus(ctx *gin.Context) {
|
||||
userID := middleware.GetLoginUserIDFromContext(ctx)
|
||||
resp, err := uc.userService.GetUserStatus(ctx, userID)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// UserEmailLogin godoc
|
||||
// @Summary UserEmailLogin
|
||||
// @Description UserEmailLogin
|
||||
|
|
|
@ -20,7 +20,7 @@ var CmsAnswerSearchStatus = map[string]int{
|
|||
type Answer struct {
|
||||
ID string `xorm:"not null pk autoincr comment('answer id') BIGINT(20) id"`
|
||||
CreatedAt time.Time `xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"`
|
||||
UpdatedAt time.Time `xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"`
|
||||
UpdatedAt time.Time `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"`
|
||||
QuestionID string `xorm:"not null default 0 comment('question id') BIGINT(20) question_id"`
|
||||
UserID string `xorm:"not null default 0 comment('answer user id') BIGINT(20) user_id"`
|
||||
OriginalText string `xorm:"not null comment('original content') MEDIUMTEXT original_text"`
|
||||
|
|
|
@ -24,6 +24,8 @@ type QuestionTag struct {
|
|||
// Question question
|
||||
type Question struct {
|
||||
ID string `xorm:"not null pk comment('question id') BIGINT(20) id"`
|
||||
CreatedAt time.Time `xorm:"not null default CURRENT_TIMESTAMP comment('create time') TIMESTAMP created_at"`
|
||||
UpdatedAt time.Time `xorm:"not null default CURRENT_TIMESTAMP comment('update time') TIMESTAMP updated_at"`
|
||||
UserID string `xorm:"not null default 0 comment('user id') BIGINT(20) user_id"`
|
||||
Title string `xorm:"not null default '' comment('question title') VARCHAR(255) title"`
|
||||
OriginalText string `xorm:"not null comment('original content') MEDIUMTEXT original_text"`
|
||||
|
@ -37,8 +39,6 @@ type Question struct {
|
|||
FollowCount int `xorm:"not null default 0 comment('follow count') INT(11) follow_count"`
|
||||
AcceptedAnswerID string `xorm:"not null default 0 comment('accepted answer id') BIGINT(20) accepted_answer_id"`
|
||||
LastAnswerID string `xorm:"not null default 0 comment('last answer id') BIGINT(20) last_answer_id"`
|
||||
CreatedAt time.Time `xorm:"not null default CURRENT_TIMESTAMP comment('create time') TIMESTAMP created_at"`
|
||||
UpdatedAt time.Time `xorm:"not null default CURRENT_TIMESTAMP comment('update time') TIMESTAMP updated_at"`
|
||||
PostUpdateTime time.Time `xorm:"default CURRENT_TIMESTAMP comment('answer the last update time') TIMESTAMP post_update_time"`
|
||||
RevisionID string `xorm:"not null default 0 BIGINT(20) revision_id"`
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/segmentfault/answer/internal/base/constant"
|
||||
"github.com/segmentfault/answer/internal/base/data"
|
||||
|
@ -77,7 +78,9 @@ func (ar *answerRepo) UpdateAnswer(ctx context.Context, answer *entity.Answer, C
|
|||
}
|
||||
|
||||
func (ar *answerRepo) UpdateAnswerStatus(ctx context.Context, answer *entity.Answer) (err error) {
|
||||
_, err = ar.data.DB.Where("id =?", answer.ID).Cols("status").Update(answer)
|
||||
now := time.Now()
|
||||
answer.UpdatedAt = now
|
||||
_, err = ar.data.DB.Where("id =?", answer.ID).Cols("status", "updated_at").Update(answer)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -129,7 +132,7 @@ func (ar *answerRepo) UpdateAdopted(ctx context.Context, id string, questionId s
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if id != "" {
|
||||
if id != "0" {
|
||||
data.Adopted = schema.Answer_Adopted_Enable
|
||||
_, err = ar.data.DB.Where("id = ?", id).Cols("adopted").Update(&data)
|
||||
if err != nil {
|
||||
|
@ -181,7 +184,7 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc
|
|||
session = session.And("user_id = ?", search.UserID)
|
||||
}
|
||||
if search.Order == entity.Answer_Search_OrderBy_Time {
|
||||
session = session.OrderBy("updated_at desc")
|
||||
session = session.OrderBy("created_at desc")
|
||||
} else if search.Order == entity.Answer_Search_OrderBy_Vote {
|
||||
session = session.OrderBy("vote_count desc")
|
||||
} else {
|
||||
|
@ -191,7 +194,7 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc
|
|||
session = session.And("status = ?", entity.AnswerStatusAvailable)
|
||||
|
||||
session = session.Limit(search.PageSize, offset)
|
||||
count, err = session.OrderBy("updated_at desc").FindAndCount(&rows)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
return rows, count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -216,7 +219,7 @@ func (ar *answerRepo) CmsSearchList(ctx context.Context, search *entity.CmsAnswe
|
|||
offset := search.Page * search.PageSize
|
||||
session := ar.data.DB.Where("")
|
||||
session = session.And("status =?", search.Status)
|
||||
session = session.OrderBy("created_at desc")
|
||||
session = session.OrderBy("updated_at desc")
|
||||
session = session.Limit(search.PageSize, offset)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/segmentfault/answer/internal/base/constant"
|
||||
"github.com/segmentfault/answer/internal/base/data"
|
||||
|
@ -92,7 +93,9 @@ func (qr *questionRepo) UpdateCollectionCount(ctx context.Context, questionId st
|
|||
}
|
||||
|
||||
func (qr *questionRepo) UpdateQuestionStatus(ctx context.Context, question *entity.Question) (err error) {
|
||||
_, err = qr.data.DB.Where("id =?", question.ID).Cols("status").Update(question)
|
||||
now := time.Now()
|
||||
question.UpdatedAt = now
|
||||
_, err = qr.data.DB.Where("id =?", question.ID).Cols("status", "updated_at").Update(question)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
@ -238,7 +241,7 @@ func (qr *questionRepo) CmsSearchList(ctx context.Context, search *schema.CmsQue
|
|||
offset := search.Page * search.PageSize
|
||||
session := qr.data.DB.Table("question")
|
||||
session = session.And("status =?", search.Status)
|
||||
session = session.OrderBy("created_at desc")
|
||||
session = session.OrderBy("updated_at desc")
|
||||
session = session.Limit(search.PageSize, offset)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
|
|
|
@ -66,7 +66,7 @@ func (rr *reportRepo) GetReportListPage(ctx context.Context, dto schema.GetRepor
|
|||
}
|
||||
|
||||
// order
|
||||
session.OrderBy("created_at desc")
|
||||
session.OrderBy("updated_at desc")
|
||||
|
||||
total, err = pager.Help(dto.Page, dto.PageSize, &reports, cond, session)
|
||||
if err != nil {
|
||||
|
|
|
@ -22,16 +22,16 @@ import (
|
|||
// searchRepo tag repository
|
||||
type searchRepo struct {
|
||||
data *data.Data
|
||||
userRepo usercommon.UserRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
uniqueIDRepo unique.UniqueIDRepo
|
||||
}
|
||||
|
||||
// NewSearchRepo new repository
|
||||
func NewSearchRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo, userRepo usercommon.UserRepo) search_common.SearchRepo {
|
||||
func NewSearchRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo, userCommon *usercommon.UserCommon) search_common.SearchRepo {
|
||||
return &searchRepo{
|
||||
data: data,
|
||||
uniqueIDRepo: uniqueIDRepo,
|
||||
userRepo: userRepo,
|
||||
userCommon: userCommon,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,8 +214,6 @@ func (sr *searchRepo) parseResult(ctx context.Context, res []map[string][]byte)
|
|||
for _, r := range res {
|
||||
var (
|
||||
objectKey string
|
||||
uInfo *schema.UserBasicInfo
|
||||
|
||||
tags []schema.TagResp
|
||||
tagsEntity []entity.Tag
|
||||
object schema.SearchObject
|
||||
|
@ -228,16 +226,12 @@ func (sr *searchRepo) parseResult(ctx context.Context, res []map[string][]byte)
|
|||
tp, _ := time.ParseInLocation("2006-01-02 15:04:05", string(r["created_at"]), time.Local)
|
||||
|
||||
// get user info
|
||||
userInfo, exist, e := sr.userRepo.GetByUserID(ctx, string(r["user_id"]))
|
||||
userInfo, _, e := sr.userCommon.GetUserBasicInfoByID(ctx, string(r["user_id"]))
|
||||
if e != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(e).WithStack()
|
||||
return
|
||||
}
|
||||
|
||||
if exist {
|
||||
uInfo = sr.userBasicInfoFormat(ctx, userInfo)
|
||||
}
|
||||
|
||||
// get tags
|
||||
err = sr.data.DB.
|
||||
Select("`display_name`,`slug_name`,`main_tag_slug_name`").
|
||||
|
@ -258,7 +252,7 @@ func (sr *searchRepo) parseResult(ctx context.Context, res []map[string][]byte)
|
|||
Title: string(r["title"]),
|
||||
Excerpt: cutOutParsedText(string(r["original_text"])),
|
||||
CreatedAtParsed: tp.Unix(),
|
||||
UserInfo: uInfo,
|
||||
UserInfo: userInfo,
|
||||
Tags: tags,
|
||||
VoteCount: converter.StringToInt(string(r["vote_count"])),
|
||||
Accepted: string(r["accepted"]) == "2",
|
||||
|
@ -275,8 +269,8 @@ func (sr *searchRepo) parseResult(ctx context.Context, res []map[string][]byte)
|
|||
// userBasicInfoFormat
|
||||
func (sr *searchRepo) userBasicInfoFormat(ctx context.Context, dbinfo *entity.User) *schema.UserBasicInfo {
|
||||
return &schema.UserBasicInfo{
|
||||
UserId: dbinfo.ID,
|
||||
UserName: dbinfo.Username,
|
||||
ID: dbinfo.ID,
|
||||
Username: dbinfo.Username,
|
||||
Rank: dbinfo.Rank,
|
||||
DisplayName: dbinfo.DisplayName,
|
||||
Avatar: dbinfo.Avatar,
|
||||
|
|
|
@ -87,6 +87,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
r.GET("/comment", a.commentController.GetComment)
|
||||
|
||||
// user
|
||||
r.GET("/user/status", a.userController.GetUserStatus)
|
||||
r.GET("/user/action/record", a.userController.ActionRecord)
|
||||
r.POST("/user/login/email", a.userController.UserEmailLogin)
|
||||
r.POST("/user/register/email", a.userController.UserRegisterByEmail)
|
||||
|
@ -100,7 +101,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
|
||||
//answer
|
||||
r.GET("/answer/info", a.answerController.Get)
|
||||
r.POST("/answer/list", a.answerController.AnswerList)
|
||||
r.GET("/answer/page", a.answerController.AnswerList)
|
||||
r.GET("/personal/answer/page", a.questionController.UserAnswerList)
|
||||
|
||||
//question
|
||||
|
|
|
@ -3,4 +3,4 @@ package router
|
|||
import "github.com/google/wire"
|
||||
|
||||
// ProviderSetRouter is providers.
|
||||
var ProviderSetRouter = wire.NewSet(NewAnswerAPIRouter, NewSwaggerRouter, NewStaticRouter, NewViewRouter)
|
||||
var ProviderSetRouter = wire.NewSet(NewAnswerAPIRouter, NewSwaggerRouter, NewStaticRouter, NewUIRouter)
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/ui"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
const UIIndexFilePath = "build/index.html"
|
||||
const UIStaticPath = "build/static"
|
||||
|
||||
// UIRouter is an interface that provides ui static file routers
|
||||
type UIRouter struct {
|
||||
}
|
||||
|
||||
// NewUIRouter creates a new UIRouter instance with the embed resources
|
||||
func NewUIRouter() *UIRouter {
|
||||
return &UIRouter{}
|
||||
}
|
||||
|
||||
// _resource is an interface that provides static file, it's a private interface
|
||||
type _resource struct {
|
||||
fs embed.FS
|
||||
}
|
||||
|
||||
// Open to implement the interface by http.FS required
|
||||
func (r *_resource) Open(name string) (fs.File, error) {
|
||||
name = fmt.Sprintf(UIStaticPath+"/%s", name)
|
||||
log.Debugf("open static path %s", name)
|
||||
return r.fs.Open(name)
|
||||
}
|
||||
|
||||
// Register a new static resource which generated by ui directory
|
||||
func (a *UIRouter) Register(r *gin.Engine) {
|
||||
staticPath := os.Getenv("ANSWER_STATIC_PATH")
|
||||
|
||||
// if ANSWER_STATIC_PATH is set and not empty, ignore embed resource
|
||||
if staticPath != "" {
|
||||
info, err := os.Stat(staticPath)
|
||||
|
||||
if err != nil || !info.IsDir() {
|
||||
log.Error(err)
|
||||
} else {
|
||||
log.Debugf("registering static path %s", staticPath)
|
||||
|
||||
r.LoadHTMLGlob(staticPath + "/*.html")
|
||||
r.Static("/static", staticPath+"/static")
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{})
|
||||
})
|
||||
|
||||
// return immediately if the static path is set
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handle the static file by default ui static files
|
||||
r.StaticFS("/static", http.FS(&_resource{
|
||||
fs: ui.Build,
|
||||
}))
|
||||
|
||||
// specify the not router for default routes and redirect
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
index, err := ui.Build.ReadFile(UIIndexFilePath)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("content-type", "text/html;charset=utf-8")
|
||||
c.String(http.StatusOK, string(index))
|
||||
})
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUIRouter_Register(t *testing.T) {
|
||||
r := gin.Default()
|
||||
|
||||
NewUIRouter().Register(r)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/", nil)
|
||||
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
func TestUIRouter_Static(t *testing.T) {
|
||||
r := gin.Default()
|
||||
|
||||
NewUIRouter().Register(r)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/static/version.txt", nil)
|
||||
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "OK", w.Body.String())
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/web"
|
||||
)
|
||||
|
||||
// RegisterViewRouter
|
||||
type ViewRouter struct {
|
||||
}
|
||||
|
||||
// NewRegisterViewRouter
|
||||
func NewViewRouter() *ViewRouter {
|
||||
return &ViewRouter{}
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
fs embed.FS
|
||||
path string
|
||||
}
|
||||
|
||||
func NewResource() *Resource {
|
||||
return &Resource{
|
||||
fs: web.Static,
|
||||
path: "html",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Resource) Open(name string) (fs.File, error) {
|
||||
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
|
||||
return nil, errors.New("http: invalid character in file path")
|
||||
}
|
||||
fullName := filepath.Join(r.path, filepath.FromSlash(path.Clean("/static/"+name)))
|
||||
file, err := r.fs.Open(fullName)
|
||||
return file, err
|
||||
}
|
||||
|
||||
func (a *ViewRouter) RegisterViewRouter(r *gin.Engine) {
|
||||
//export answer_html_static_path="../../web/static"
|
||||
//export answer_html_page_path="../../web"
|
||||
static := os.Getenv("answer_html_static_path")
|
||||
index := os.Getenv("answer_html_page_path")
|
||||
if len(static) > 0 && len(index) > 0 {
|
||||
r.LoadHTMLGlob(index + "/*.html")
|
||||
r.Static("/static", static)
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{})
|
||||
})
|
||||
return
|
||||
} else {
|
||||
r.StaticFS("/static", http.FS(NewResource()))
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.Header("content-type", "text/html;charset=utf-8")
|
||||
c.String(200, string(web.Html))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -1,95 +1,13 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RemoveAnswerReq delete answer request
|
||||
type RemoveAnswerReq struct {
|
||||
// answer id
|
||||
ID string `validate:"required" comment:"answer id" json:"id"`
|
||||
ID string `validate:"required" json:"id"`
|
||||
// user id
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
// GetAnswerListReq get answer list all request
|
||||
type GetAnswerListReq struct {
|
||||
// question id
|
||||
QuestionID int64 `validate:"omitempty" comment:"question id" form:"question_id"`
|
||||
// answer user id
|
||||
UserID int64 `validate:"omitempty" comment:"answer user id" form:"user_id"`
|
||||
// content markdown
|
||||
Content string `validate:"omitempty" comment:"content markdown" form:"content"`
|
||||
// content html
|
||||
Html string `validate:"omitempty" comment:"content html" form:"html"`
|
||||
// answer status(available: 1; deleted: 10)
|
||||
Status int `validate:"omitempty" comment:" answer status(available: 1; deleted: 10)" form:"status"`
|
||||
// adopted (1 failed 2 adopted)
|
||||
Adopted int `validate:"omitempty" comment:"adopted (1 failed 2 adopted)" form:"adopted"`
|
||||
// comment count
|
||||
CommentCount int `validate:"omitempty" comment:"comment count" form:"comment_count"`
|
||||
// vote count
|
||||
VoteCount int `validate:"omitempty" comment:"vote count" form:"vote_count"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" form:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" form:"update_time"`
|
||||
}
|
||||
|
||||
// GetAnswerWithPageReq get answer list page request
|
||||
type GetAnswerWithPageReq struct {
|
||||
// page
|
||||
Page int `validate:"omitempty,min=1" form:"page"`
|
||||
// page size
|
||||
PageSize int `validate:"omitempty,min=1" form:"page_size"`
|
||||
// question id
|
||||
QuestionID int64 `validate:"omitempty" comment:"question id" form:"question_id"`
|
||||
// answer user id
|
||||
UserID int64 `validate:"omitempty" comment:"answer user id" form:"user_id"`
|
||||
// content markdown
|
||||
Content string `validate:"omitempty" comment:"content markdown" form:"content"`
|
||||
// content html
|
||||
Html string `validate:"omitempty" comment:"content html" form:"html"`
|
||||
// answer status(available: 1; deleted: 10)
|
||||
Status int `validate:"omitempty" comment:" answer status(available: 1; deleted: 10)" form:"status"`
|
||||
// adopted (1 failed 2 adopted)
|
||||
Adopted int `validate:"omitempty" comment:"adopted (1 failed 2 adopted)" form:"adopted"`
|
||||
// comment count
|
||||
CommentCount int `validate:"omitempty" comment:"comment count" form:"comment_count"`
|
||||
// vote count
|
||||
VoteCount int `validate:"omitempty" comment:"vote count" form:"vote_count"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" form:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" form:"update_time"`
|
||||
}
|
||||
|
||||
// GetAnswerResp get answer response
|
||||
type GetAnswerResp struct {
|
||||
// answer id
|
||||
ID int64 `json:"id"`
|
||||
// question id
|
||||
QuestionID int64 `json:"question_id"`
|
||||
// answer user id
|
||||
UserID int64 `json:"user_id"`
|
||||
// content markdown
|
||||
Content string `json:"content"`
|
||||
// content html
|
||||
Html string `json:"html"`
|
||||
// answer status(available: 1; deleted: 10)
|
||||
Status int `json:"status"`
|
||||
// adopted (1 failed 2 adopted)
|
||||
Adopted int `json:"adopted"`
|
||||
// comment count
|
||||
CommentCount int `json:"comment_count"`
|
||||
// vote count
|
||||
VoteCount int `json:"vote_count"`
|
||||
//
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `json:"update_time"`
|
||||
}
|
||||
|
||||
const (
|
||||
Answer_Adopted_Failed = 1
|
||||
Answer_Adopted_Enable = 2
|
||||
|
@ -113,8 +31,8 @@ type AnswerUpdateReq struct {
|
|||
}
|
||||
|
||||
type AnswerList struct {
|
||||
QuestionId string `json:"question_id" ` // question_id
|
||||
Order string `json:"order" ` // 1 Default 2 time
|
||||
QuestionId string `json:"question_id" form:"question_id"` // question_id
|
||||
Order string `json:"order" form:"order"` // 1 Default 2 time
|
||||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
LoginUserID string `json:"-" `
|
||||
|
|
|
@ -9,16 +9,16 @@ type UpdateUserStatusReq struct {
|
|||
}
|
||||
|
||||
const (
|
||||
Normal = "normal"
|
||||
Suspended = "suspended"
|
||||
Deleted = "deleted"
|
||||
Inactive = "inactive"
|
||||
UserNormal = "normal"
|
||||
UserSuspended = "suspended"
|
||||
UserDeleted = "deleted"
|
||||
UserInactive = "inactive"
|
||||
)
|
||||
|
||||
func (r *UpdateUserStatusReq) IsNormal() bool { return r.Status == Normal }
|
||||
func (r *UpdateUserStatusReq) IsSuspended() bool { return r.Status == Suspended }
|
||||
func (r *UpdateUserStatusReq) IsDeleted() bool { return r.Status == Deleted }
|
||||
func (r *UpdateUserStatusReq) IsInactive() bool { return r.Status == Inactive }
|
||||
func (r *UpdateUserStatusReq) IsNormal() bool { return r.Status == UserNormal }
|
||||
func (r *UpdateUserStatusReq) IsSuspended() bool { return r.Status == UserSuspended }
|
||||
func (r *UpdateUserStatusReq) IsDeleted() bool { return r.Status == UserDeleted }
|
||||
func (r *UpdateUserStatusReq) IsInactive() bool { return r.Status == UserInactive }
|
||||
|
||||
// GetUserPageReq get user list page request
|
||||
type GetUserPageReq struct {
|
||||
|
@ -34,9 +34,9 @@ type GetUserPageReq struct {
|
|||
Status string `validate:"omitempty,oneof=suspended deleted inactive" form:"status"`
|
||||
}
|
||||
|
||||
func (r *GetUserPageReq) IsSuspended() bool { return r.Status == Suspended }
|
||||
func (r *GetUserPageReq) IsDeleted() bool { return r.Status == Deleted }
|
||||
func (r *GetUserPageReq) IsInactive() bool { return r.Status == Inactive }
|
||||
func (r *GetUserPageReq) IsSuspended() bool { return r.Status == UserSuspended }
|
||||
func (r *GetUserPageReq) IsDeleted() bool { return r.Status == UserDeleted }
|
||||
func (r *GetUserPageReq) IsInactive() bool { return r.Status == UserInactive }
|
||||
|
||||
// GetUserPageResp get user response
|
||||
type GetUserPageResp struct {
|
||||
|
|
|
@ -43,12 +43,6 @@ type AddCollectionGroupReq struct {
|
|||
UpdateTime time.Time `validate:"required" comment:"" json:"update_time"`
|
||||
}
|
||||
|
||||
// RemoveCollectionGroupReq delete collection group request
|
||||
type RemoveCollectionGroupReq struct {
|
||||
//
|
||||
ID int64 `validate:"required" comment:"" json:"id"`
|
||||
}
|
||||
|
||||
// UpdateCollectionGroupReq update collection group request
|
||||
type UpdateCollectionGroupReq struct {
|
||||
//
|
||||
|
@ -65,38 +59,6 @@ type UpdateCollectionGroupReq struct {
|
|||
UpdateTime time.Time `validate:"omitempty" comment:"" json:"update_time"`
|
||||
}
|
||||
|
||||
// GetCollectionGroupListReq get collection group list all request
|
||||
type GetCollectionGroupListReq struct {
|
||||
//
|
||||
UserID int64 `validate:"omitempty" comment:"" form:"user_id"`
|
||||
// the collection group name
|
||||
Name string `validate:"omitempty,gt=0,lte=50" comment:"the collection group name" form:"name"`
|
||||
// mark this group is default, default 1
|
||||
DefaultGroup int `validate:"omitempty" comment:"mark this group is default, default 1" form:"default_group"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" form:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" form:"update_time"`
|
||||
}
|
||||
|
||||
// GetCollectionGroupWithPageReq get collection group list page request
|
||||
type GetCollectionGroupWithPageReq struct {
|
||||
// page
|
||||
Page int `validate:"omitempty,min=1" form:"page"`
|
||||
// page size
|
||||
PageSize int `validate:"omitempty,min=1" form:"page_size"`
|
||||
//
|
||||
UserID int64 `validate:"omitempty" comment:"" form:"user_id"`
|
||||
// the collection group name
|
||||
Name string `validate:"omitempty,gt=0,lte=50" comment:"the collection group name" form:"name"`
|
||||
// mark this group is default, default 1
|
||||
DefaultGroup int `validate:"omitempty" comment:"mark this group is default, default 1" form:"default_group"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" form:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" form:"update_time"`
|
||||
}
|
||||
|
||||
// GetCollectionGroupResp get collection group response
|
||||
type GetCollectionGroupResp struct {
|
||||
//
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
package schema
|
||||
|
||||
import "time"
|
||||
|
||||
// AddCollectionReq add collection request
|
||||
type AddCollectionReq struct {
|
||||
// user id
|
||||
UserID int64 `validate:"required" comment:"user id" json:"user_id"`
|
||||
// object id
|
||||
ObjectID int64 `validate:"required" comment:"object id" json:"object_id"`
|
||||
// user collection group id
|
||||
UserCollectionGroupID int64 `validate:"required" comment:"user collection group id" json:"user_collection_group_id"`
|
||||
//
|
||||
CreateTime time.Time `validate:"required" comment:"" json:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"required" comment:"" json:"update_time"`
|
||||
}
|
||||
|
||||
// RemoveCollectionReq delete collection request
|
||||
type RemoveCollectionReq struct {
|
||||
// collection id
|
||||
ID int64 `validate:"required" comment:"collection id" json:"id"`
|
||||
}
|
||||
|
||||
// UpdateCollectionReq update collection request
|
||||
type UpdateCollectionReq struct {
|
||||
// collection id
|
||||
ID int64 `validate:"required" comment:"collection id" json:"id"`
|
||||
// user id
|
||||
UserID int64 `validate:"omitempty" comment:"user id" json:"user_id"`
|
||||
// object id
|
||||
ObjectID int64 `validate:"omitempty" comment:"object id" json:"object_id"`
|
||||
// user collection group id
|
||||
UserCollectionGroupID int64 `validate:"omitempty" comment:"user collection group id" json:"user_collection_group_id"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" json:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" json:"update_time"`
|
||||
}
|
||||
|
||||
// GetCollectionListReq get collection list all request
|
||||
type GetCollectionListReq struct {
|
||||
// user id
|
||||
UserID int64 `validate:"omitempty" comment:"user id" form:"user_id"`
|
||||
// object id
|
||||
ObjectID int64 `validate:"omitempty" comment:"object id" form:"object_id"`
|
||||
// user collection group id
|
||||
UserCollectionGroupID int64 `validate:"omitempty" comment:"user collection group id" form:"user_collection_group_id"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" form:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" form:"update_time"`
|
||||
}
|
||||
|
||||
// GetCollectionWithPageReq get collection list page request
|
||||
type GetCollectionWithPageReq struct {
|
||||
// page
|
||||
Page int `validate:"omitempty,min=1" form:"page"`
|
||||
// page size
|
||||
PageSize int `validate:"omitempty,min=1" form:"page_size"`
|
||||
// user id
|
||||
UserID int64 `validate:"omitempty" comment:"user id" form:"user_id"`
|
||||
// object id
|
||||
ObjectID int64 `validate:"omitempty" comment:"object id" form:"object_id"`
|
||||
// user collection group id
|
||||
UserCollectionGroupID int64 `validate:"omitempty" comment:"user collection group id" form:"user_collection_group_id"`
|
||||
//
|
||||
CreateTime time.Time `validate:"omitempty" comment:"" form:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `validate:"omitempty" comment:"" form:"update_time"`
|
||||
}
|
||||
|
||||
// GetCollectionResp get collection response
|
||||
type GetCollectionResp struct {
|
||||
// collection id
|
||||
ID int64 `json:"id"`
|
||||
// user id
|
||||
UserID int64 `json:"user_id"`
|
||||
// object id
|
||||
ObjectID int64 `json:"object_id"`
|
||||
// user collection group id
|
||||
UserCollectionGroupID int64 `json:"user_collection_group_id"`
|
||||
//
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
//
|
||||
UpdateTime time.Time `json:"update_time"`
|
||||
}
|
|
@ -109,6 +109,8 @@ type GetCommentResp struct {
|
|||
UserDisplayName string `json:"user_display_name"`
|
||||
// user avatar
|
||||
UserAvatar string `json:"user_avatar"`
|
||||
// user status
|
||||
UserStatus string `json:"user_status"`
|
||||
|
||||
// reply user id
|
||||
ReplyUserID string `json:"reply_user_id"`
|
||||
|
@ -118,6 +120,8 @@ type GetCommentResp struct {
|
|||
ReplyUserDisplayName string `json:"reply_user_display_name"`
|
||||
// reply comment id
|
||||
ReplyCommentID string `json:"reply_comment_id"`
|
||||
// reply user status
|
||||
ReplyUserStatus string `json:"reply_user_status"`
|
||||
|
||||
// MemberActions
|
||||
MemberActions []*PermissionMemberAction `json:"member_actions"`
|
||||
|
|
|
@ -166,7 +166,7 @@ type CmsQuestionSearch struct {
|
|||
Page int `json:"page" form:"page"` //Query number of pages
|
||||
PageSize int `json:"page_size" form:"page_size"` //Search page size
|
||||
Status int `json:"-" form:"-"`
|
||||
StatusStr string `json:"status" form:"status"` //Status 1 Available 2 closed 10 Deleted
|
||||
StatusStr string `json:"status" form:"status"` //Status 1 Available 2 closed 10 UserDeleted
|
||||
}
|
||||
|
||||
type AdminSetQuestionStatusRequest struct {
|
||||
|
|
|
@ -76,7 +76,12 @@ func (r *GetUserResp) GetFromUserEntity(userInfo *entity.User) {
|
|||
if ok {
|
||||
r.Status = statusShow
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserStatusResp get user status info
|
||||
type GetUserStatusResp struct {
|
||||
// user status
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// GetOtherUserInfoByUsernameResp get user response
|
||||
|
@ -161,7 +166,7 @@ const (
|
|||
var UserStatusShow = map[int]string{
|
||||
1: "normal",
|
||||
9: "forbidden",
|
||||
10: "delete",
|
||||
10: "deleted",
|
||||
}
|
||||
var UserStatusShowMsg = map[int]string{
|
||||
1: "",
|
||||
|
@ -277,15 +282,15 @@ type ActionRecordResp struct {
|
|||
}
|
||||
|
||||
type UserBasicInfo struct {
|
||||
UserId string `json:"-" ` // user_id
|
||||
UserName string `json:"username" ` // name
|
||||
ID string `json:"-" ` // user_id
|
||||
Username string `json:"username" ` // name
|
||||
Rank int `json:"rank" ` // rank
|
||||
DisplayName string `json:"display_name"` // display_name
|
||||
Avatar string `json:"avatar" ` // avatar
|
||||
Website string `json:"website" ` // website
|
||||
Location string `json:"location" ` // location
|
||||
IpInfo string `json:"ip_info"` // ip info
|
||||
Status int `json:"status"` // status
|
||||
Status string `json:"status"` // status
|
||||
}
|
||||
|
||||
type GetOtherUserInfoByUsernameReq struct {
|
||||
|
|
|
@ -191,17 +191,26 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq
|
|||
|
||||
// UpdateAdopted
|
||||
func (as *AnswerService) UpdateAdopted(ctx context.Context, req *schema.AnswerAdoptedReq) error {
|
||||
if req.AnswerID == "" {
|
||||
req.AnswerID = "0"
|
||||
}
|
||||
if req.UserID == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
newAnswerInfo, exist, err := as.answerRepo.GetByID(ctx, req.AnswerID)
|
||||
newAnswerInfo := &entity.Answer{}
|
||||
newAnswerInfoexist := false
|
||||
var err error
|
||||
|
||||
if req.AnswerID != "0" {
|
||||
newAnswerInfo, newAnswerInfoexist, err = as.answerRepo.GetByID(ctx, req.AnswerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
if !newAnswerInfoexist {
|
||||
return errors.BadRequest(reason.AnswerNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
|
@ -250,12 +259,14 @@ func (as *AnswerService) updateAnswerRank(ctx context.Context, userID string,
|
|||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if newAnswerInfo.ID != "" {
|
||||
err := as.answerActivityService.AcceptAnswer(
|
||||
ctx, newAnswerInfo.ID, questionInfo.UserID, newAnswerInfo.UserID, newAnswerInfo.UserID == userID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (as *AnswerService) Get(ctx context.Context, answerID, loginUserId string) (*schema.AnswerInfo, *schema.QuestionInfo, bool, error) {
|
||||
|
@ -413,7 +424,7 @@ func (as *AnswerService) notificationUpdateAnswer(ctx context.Context, questionU
|
|||
Type: schema.NotificationTypeInbox,
|
||||
ObjectID: answerID,
|
||||
}
|
||||
msg.ObjectType = constant.QuestionObjectType
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.UpdateAnswer
|
||||
notice_queue.AddNotification(msg)
|
||||
}
|
||||
|
@ -425,7 +436,7 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context, ques
|
|||
Type: schema.NotificationTypeInbox,
|
||||
ObjectID: answerID,
|
||||
}
|
||||
msg.ObjectType = constant.QuestionObjectType
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.AnswerTheQuestion
|
||||
notice_queue.AddNotification(msg)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ type CommentRepo interface {
|
|||
type CommentService struct {
|
||||
commentRepo CommentRepo
|
||||
commentCommonRepo comment_common.CommentCommonRepo
|
||||
userRepo usercommon.UserRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
voteCommon activity_common.VoteRepo
|
||||
objectInfoService *object_info.ObjService
|
||||
}
|
||||
|
@ -61,13 +61,13 @@ func (c *CommentQuery) GetOrderBy() string {
|
|||
func NewCommentService(
|
||||
commentRepo CommentRepo,
|
||||
commentCommonRepo comment_common.CommentCommonRepo,
|
||||
userRepo usercommon.UserRepo,
|
||||
userCommon *usercommon.UserCommon,
|
||||
objectInfoService *object_info.ObjService,
|
||||
voteCommon activity_common.VoteRepo) *CommentService {
|
||||
return &CommentService{
|
||||
commentRepo: commentRepo,
|
||||
commentCommonRepo: commentCommonRepo,
|
||||
userRepo: userRepo,
|
||||
userCommon: userCommon,
|
||||
voteCommon: voteCommon,
|
||||
objectInfoService: objectInfoService,
|
||||
}
|
||||
|
@ -124,19 +124,20 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment
|
|||
|
||||
// get reply user info
|
||||
if len(resp.ReplyUserID) > 0 {
|
||||
replyUser, exist, err := cs.userRepo.GetByUserID(ctx, resp.ReplyUserID)
|
||||
replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.ReplyUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
resp.ReplyUsername = replyUser.Username
|
||||
resp.ReplyUserDisplayName = replyUser.DisplayName
|
||||
resp.ReplyUserStatus = replyUser.Status
|
||||
}
|
||||
cs.notificationCommentReply(ctx, replyUser.ID, objInfo.QuestionID, req.UserID)
|
||||
}
|
||||
|
||||
// get user info
|
||||
userInfo, exist, err := cs.userRepo.GetByUserID(ctx, resp.UserID)
|
||||
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -144,6 +145,7 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment
|
|||
resp.Username = userInfo.Username
|
||||
resp.UserDisplayName = userInfo.DisplayName
|
||||
resp.UserAvatar = userInfo.Avatar
|
||||
resp.UserStatus = userInfo.Status
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
@ -191,7 +193,7 @@ func (cs *CommentService) GetComment(ctx context.Context, req *schema.GetComment
|
|||
|
||||
// get comment user info
|
||||
if len(resp.UserID) > 0 {
|
||||
commentUser, exist, err := cs.userRepo.GetByUserID(ctx, resp.UserID)
|
||||
commentUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -199,18 +201,20 @@ func (cs *CommentService) GetComment(ctx context.Context, req *schema.GetComment
|
|||
resp.Username = commentUser.Username
|
||||
resp.UserDisplayName = commentUser.DisplayName
|
||||
resp.UserAvatar = commentUser.Avatar
|
||||
resp.UserStatus = commentUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
// get reply user info
|
||||
if len(resp.ReplyUserID) > 0 {
|
||||
replyUser, exist, err := cs.userRepo.GetByUserID(ctx, resp.ReplyUserID)
|
||||
replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.ReplyUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
resp.ReplyUsername = replyUser.Username
|
||||
resp.ReplyUserDisplayName = replyUser.DisplayName
|
||||
resp.ReplyUserStatus = replyUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +253,7 @@ func (cs *CommentService) GetCommentWithPage(ctx context.Context, req *schema.Ge
|
|||
|
||||
// get comment user info
|
||||
if len(commentResp.UserID) > 0 {
|
||||
commentUser, exist, err := cs.userRepo.GetByUserID(ctx, commentResp.UserID)
|
||||
commentUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, commentResp.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -257,18 +261,20 @@ func (cs *CommentService) GetCommentWithPage(ctx context.Context, req *schema.Ge
|
|||
commentResp.Username = commentUser.Username
|
||||
commentResp.UserDisplayName = commentUser.DisplayName
|
||||
commentResp.UserAvatar = commentUser.Avatar
|
||||
commentResp.UserStatus = commentUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
// get reply user info
|
||||
if len(commentResp.ReplyUserID) > 0 {
|
||||
replyUser, exist, err := cs.userRepo.GetByUserID(ctx, commentResp.ReplyUserID)
|
||||
replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, commentResp.ReplyUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exist {
|
||||
commentResp.ReplyUsername = replyUser.Username
|
||||
commentResp.ReplyUserDisplayName = replyUser.DisplayName
|
||||
commentResp.ReplyUserStatus = replyUser.Status
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,7 +284,7 @@ func (cs *CommentService) GetCommentWithPage(ctx context.Context, req *schema.Ge
|
|||
commentResp.MemberActions = permission.GetCommentPermission(req.UserID, commentResp.UserID)
|
||||
resp = append(resp, commentResp)
|
||||
}
|
||||
return pager.NewPageModel(req.Page, req.PageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
||||
func (cs *CommentService) checkCommentWhetherOwner(ctx context.Context, userID, commentID string) error {
|
||||
|
@ -305,7 +311,7 @@ func (cs *CommentService) checkIsVote(ctx context.Context, userID, commentID str
|
|||
func (cs *CommentService) GetCommentPersonalWithPage(ctx context.Context, req *schema.GetCommentPersonalWithPageReq) (
|
||||
pageModel *pager.PageModel, err error) {
|
||||
if len(req.Username) > 0 {
|
||||
userInfo, exist, err := cs.userRepo.GetByUsername(ctx, req.Username)
|
||||
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByUserName(ctx, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -348,7 +354,7 @@ func (cs *CommentService) GetCommentPersonalWithPage(ctx context.Context, req *s
|
|||
}
|
||||
resp = append(resp, commentResp)
|
||||
}
|
||||
return pager.NewPageModel(req.Page, req.PageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationQuestionComment(ctx context.Context, questionUserID, commentID, commentUserID string) {
|
||||
|
@ -389,7 +395,7 @@ func (cs *CommentService) notificationCommentReply(ctx context.Context, replyUse
|
|||
|
||||
func (cs *CommentService) notificationMention(ctx context.Context, mentionUsernameList []string, commentID, commentUserID string) {
|
||||
for _, username := range mentionUsernameList {
|
||||
userInfo, exist, err := cs.userRepo.GetByUsername(ctx, username)
|
||||
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByUserName(ctx, username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
|
|
|
@ -97,5 +97,5 @@ func (ns *NotificationReadService) GetNotificationReadWithPage(ctx context.Conte
|
|||
resp := &[]schema.GetNotificationReadResp{}
|
||||
_ = copier.Copy(resp, notificationReads)
|
||||
|
||||
return pager.NewPageModel(page, pageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
|
|
@ -5,9 +5,13 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/segmentfault/answer/internal/base/constant"
|
||||
"github.com/segmentfault/answer/internal/base/data"
|
||||
"github.com/segmentfault/answer/internal/base/pager"
|
||||
"github.com/segmentfault/answer/internal/base/translator"
|
||||
"github.com/segmentfault/answer/internal/schema"
|
||||
notficationcommon "github.com/segmentfault/answer/internal/service/notification_common"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
|
@ -91,30 +95,33 @@ func (ns *NotificationService) ClearIDUnRead(ctx context.Context, userID string,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ns *NotificationService) GetList(ctx context.Context, search *schema.NotificationSearch) ([]*schema.NotificationContent, int64, error) {
|
||||
list := make([]*schema.NotificationContent, 0)
|
||||
func (ns *NotificationService) GetList(ctx context.Context, search *schema.NotificationSearch) (
|
||||
pageModel *pager.PageModel, err error) {
|
||||
resp := make([]*schema.NotificationContent, 0)
|
||||
searchType, ok := schema.NotificationType[search.TypeStr]
|
||||
if !ok {
|
||||
return list, 0, nil
|
||||
return pager.NewPageModel(0, resp), nil
|
||||
}
|
||||
search.Type = searchType
|
||||
dblist, count, err := ns.notificationRepo.SearchList(ctx, search)
|
||||
notifications, count, err := ns.notificationRepo.SearchList(ctx, search)
|
||||
if err != nil {
|
||||
return list, count, err
|
||||
return nil, err
|
||||
}
|
||||
for _, dbitem := range dblist {
|
||||
for _, notificationInfo := range notifications {
|
||||
item := &schema.NotificationContent{}
|
||||
err := json.Unmarshal([]byte(dbitem.Content), item)
|
||||
err := json.Unmarshal([]byte(notificationInfo.Content), item)
|
||||
if err != nil {
|
||||
log.Error("NotificationContent Unmarshal Error", err.Error())
|
||||
continue
|
||||
}
|
||||
item.ID = dbitem.ID
|
||||
item.UpdateTime = dbitem.UpdatedAt.Unix()
|
||||
if dbitem.IsRead == schema.NotificationRead {
|
||||
lang, _ := ctx.Value(constant.AcceptLanguageFlag).(i18n.Language)
|
||||
item.NotificationAction = translator.GlobalTrans.Tr(lang, item.NotificationAction)
|
||||
item.ID = notificationInfo.ID
|
||||
item.UpdateTime = notificationInfo.UpdatedAt.Unix()
|
||||
if notificationInfo.IsRead == schema.NotificationRead {
|
||||
item.IsRead = true
|
||||
}
|
||||
list = append(list, item)
|
||||
resp = append(resp, item)
|
||||
}
|
||||
return list, count, nil
|
||||
return pager.NewPageModel(count, resp), nil
|
||||
}
|
||||
|
|
|
@ -3,12 +3,13 @@ package questioncommon
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/segmentfault/answer/internal/base/reason"
|
||||
"github.com/segmentfault/answer/internal/service/activity_common"
|
||||
"github.com/segmentfault/answer/internal/service/config"
|
||||
"github.com/segmentfault/answer/internal/service/meta"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
|
||||
"github.com/segmentfault/answer/internal/entity"
|
||||
"github.com/segmentfault/answer/internal/schema"
|
||||
|
@ -139,7 +140,7 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionId string, loginUser
|
|||
return showinfo, err
|
||||
}
|
||||
if !has {
|
||||
return showinfo, fmt.Errorf("the question could not be found")
|
||||
return showinfo, errors.BadRequest(reason.QuestionNotFound)
|
||||
}
|
||||
showinfo = qs.ShowFormat(ctx, dbinfo)
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ func (qs *QuestionService) SearchUserList(ctx context.Context, userName, order s
|
|||
search.Order = order
|
||||
search.Page = page
|
||||
search.PageSize = pageSize
|
||||
search.UserID = userinfo.UserId
|
||||
search.UserID = userinfo.ID
|
||||
questionlist, count, err := qs.SearchList(ctx, search, loginUserID)
|
||||
if err != nil {
|
||||
return userlist, 0, err
|
||||
|
@ -289,7 +289,7 @@ func (qs *QuestionService) SearchUserAnswerList(ctx context.Context, userName, o
|
|||
return userAnswerlist, 0, nil
|
||||
}
|
||||
answersearch := &entity.AnswerSearch{}
|
||||
answersearch.UserID = userinfo.UserId
|
||||
answersearch.UserID = userinfo.ID
|
||||
answersearch.PageSize = pageSize
|
||||
answersearch.Page = page
|
||||
if order == "newest" {
|
||||
|
@ -337,7 +337,7 @@ func (qs *QuestionService) SearchUserCollectionList(ctx context.Context, page, p
|
|||
return list, 0, nil
|
||||
}
|
||||
collectionSearch := &entity.CollectionSearch{}
|
||||
collectionSearch.UserID = userinfo.UserId
|
||||
collectionSearch.UserID = userinfo.ID
|
||||
collectionSearch.Page = page
|
||||
collectionSearch.PageSize = pageSize
|
||||
collectionlist, count, err := qs.collectionCommon.SearchList(ctx, collectionSearch)
|
||||
|
@ -384,13 +384,13 @@ func (qs *QuestionService) SearchUserTopList(ctx context.Context, userName strin
|
|||
search.Order = "score"
|
||||
search.Page = 0
|
||||
search.PageSize = 5
|
||||
search.UserID = userinfo.UserId
|
||||
search.UserID = userinfo.ID
|
||||
questionlist, _, err := qs.SearchList(ctx, search, loginUserID)
|
||||
if err != nil {
|
||||
return userQuestionlist, userAnswerlist, err
|
||||
}
|
||||
answersearch := &entity.AnswerSearch{}
|
||||
answersearch.UserID = userinfo.UserId
|
||||
answersearch.UserID = userinfo.ID
|
||||
answersearch.PageSize = 5
|
||||
answersearch.Order = entity.Answer_Search_OrderBy_Vote
|
||||
questionIDs := make([]string, 0)
|
||||
|
@ -494,7 +494,7 @@ func (qs *QuestionService) SearchList(ctx context.Context, req *schema.QuestionS
|
|||
if !exist {
|
||||
return list, 0, err
|
||||
}
|
||||
req.UserID = userinfo.UserId
|
||||
req.UserID = userinfo.ID
|
||||
}
|
||||
questionList, count, err := qs.questionRepo.SearchList(ctx, req)
|
||||
if err != nil {
|
||||
|
|
|
@ -47,7 +47,7 @@ type UserRankRepo interface {
|
|||
|
||||
// RankService rank service
|
||||
type RankService struct {
|
||||
userRepo usercommon.UserRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
configRepo config.ConfigRepo
|
||||
userRankRepo UserRankRepo
|
||||
objectInfoService *object_info.ObjService
|
||||
|
@ -55,12 +55,12 @@ type RankService struct {
|
|||
|
||||
// NewRankService new rank service
|
||||
func NewRankService(
|
||||
userRepo usercommon.UserRepo,
|
||||
userCommon *usercommon.UserCommon,
|
||||
userRankRepo UserRankRepo,
|
||||
objectInfoService *object_info.ObjService,
|
||||
configRepo config.ConfigRepo) *RankService {
|
||||
return &RankService{
|
||||
userRepo: userRepo,
|
||||
userCommon: userCommon,
|
||||
configRepo: configRepo,
|
||||
userRankRepo: userRankRepo,
|
||||
objectInfoService: objectInfoService,
|
||||
|
@ -74,7 +74,7 @@ func (rs *RankService) CheckRankPermission(ctx context.Context, userID string, a
|
|||
}
|
||||
|
||||
// get the rank of the current user
|
||||
userInfo, exist, err := rs.userRepo.GetByUserID(ctx, userID)
|
||||
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByID(ctx, userID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func (rs *RankService) CheckRankPermission(ctx context.Context, userID string, a
|
|||
func (rs *RankService) GetRankPersonalWithPage(ctx context.Context, req *schema.GetRankPersonalWithPageReq) (
|
||||
pageModel *pager.PageModel, err error) {
|
||||
if len(req.Username) > 0 {
|
||||
userInfo, exist, err := rs.userRepo.GetByUsername(ctx, req.Username)
|
||||
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByUserName(ctx, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -140,5 +140,5 @@ func (rs *RankService) GetRankPersonalWithPage(ctx context.Context, req *schema.
|
|||
}
|
||||
resp = append(resp, commentResp)
|
||||
}
|
||||
return pager.NewPageModel(req.Page, req.PageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@ package report_backyard
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/segmentfault/answer/internal/service/config"
|
||||
"strings"
|
||||
|
||||
"github.com/segmentfault/answer/internal/service/config"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/segmentfault/answer/internal/base/pager"
|
||||
"github.com/segmentfault/answer/internal/base/reason"
|
||||
|
@ -93,7 +94,7 @@ func (rs *ReportBackyardService) ListReportPage(ctx context.Context, dto schema.
|
|||
}
|
||||
|
||||
rs.parseObject(ctx, &resp)
|
||||
return pager.NewPageModel(dto.Page, dto.PageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
||||
// HandleReported handle the reported object
|
||||
|
|
|
@ -13,25 +13,24 @@ import (
|
|||
"github.com/segmentfault/answer/internal/service/revision"
|
||||
usercommon "github.com/segmentfault/answer/internal/service/user_common"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
// RevisionService user service
|
||||
type RevisionService struct {
|
||||
revisionRepo revision.RevisionRepo
|
||||
userRepo usercommon.UserRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
questionCommon *questioncommon.QuestionCommon
|
||||
answerService *AnswerService
|
||||
}
|
||||
|
||||
func NewRevisionService(
|
||||
revisionRepo revision.RevisionRepo,
|
||||
userRepo usercommon.UserRepo,
|
||||
userCommon *usercommon.UserCommon,
|
||||
questionCommon *questioncommon.QuestionCommon,
|
||||
answerService *AnswerService) *RevisionService {
|
||||
return &RevisionService{
|
||||
revisionRepo: revisionRepo,
|
||||
userRepo: userRepo,
|
||||
userCommon: userCommon,
|
||||
questionCommon: questionCommon,
|
||||
answerService: answerService,
|
||||
}
|
||||
|
@ -70,7 +69,6 @@ func (rs *RevisionService) GetRevisionList(ctx context.Context, req *schema.GetR
|
|||
)
|
||||
|
||||
resp = []schema.GetRevisionResp{}
|
||||
|
||||
_ = copier.Copy(&rev, req)
|
||||
|
||||
revs, err = rs.revisionRepo.GetRevisionList(ctx, &rev)
|
||||
|
@ -80,29 +78,24 @@ func (rs *RevisionService) GetRevisionList(ctx context.Context, req *schema.GetR
|
|||
|
||||
for _, r := range revs {
|
||||
var (
|
||||
userInfo *entity.User
|
||||
uinfo schema.UserBasicInfo
|
||||
item schema.GetRevisionResp
|
||||
exists bool
|
||||
)
|
||||
|
||||
_ = copier.Copy(&item, r)
|
||||
rs.parseItem(ctx, &item)
|
||||
|
||||
// get user info
|
||||
userInfo, exists, err = rs.userRepo.GetByUserID(ctx, item.UserID)
|
||||
if err != nil {
|
||||
return
|
||||
userInfo, exists, e := rs.userCommon.GetUserBasicInfoByID(ctx, item.UserID)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if exists {
|
||||
err = copier.Copy(&uinfo, userInfo)
|
||||
item.UserInfo = uinfo
|
||||
}
|
||||
|
||||
resp = append(resp, item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -125,7 +118,6 @@ func (rs *RevisionService) parseItem(ctx context.Context, item *schema.GetRevisi
|
|||
}
|
||||
questionInfo = rs.questionCommon.ShowFormat(ctx, &question)
|
||||
item.ContentParsed = questionInfo
|
||||
log.Error(item.ContentParsed)
|
||||
case constant.ObjectTypeStrMapping["answer"]:
|
||||
err = json.Unmarshal([]byte(item.Content), &answer)
|
||||
if err != nil {
|
||||
|
@ -156,6 +148,5 @@ func (rs *RevisionService) parseItem(ctx context.Context, item *schema.GetRevisi
|
|||
if err != nil {
|
||||
item.ContentParsed = item.Content
|
||||
}
|
||||
|
||||
item.CreatedAtParsed = item.CreatedAt.Unix()
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/segmentfault/answer/internal/entity"
|
||||
"github.com/segmentfault/answer/internal/schema"
|
||||
"github.com/segmentfault/answer/internal/service/search_common"
|
||||
usercommon "github.com/segmentfault/answer/internal/service/user_common"
|
||||
|
@ -13,17 +12,17 @@ import (
|
|||
|
||||
type AuthorSearch struct {
|
||||
repo search_common.SearchRepo
|
||||
userRepo usercommon.UserRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
exp string
|
||||
w string
|
||||
page int
|
||||
size int
|
||||
}
|
||||
|
||||
func NewAuthorSearch(repo search_common.SearchRepo, userRepo usercommon.UserRepo) *AuthorSearch {
|
||||
func NewAuthorSearch(repo search_common.SearchRepo, userCommon *usercommon.UserCommon) *AuthorSearch {
|
||||
return &AuthorSearch{
|
||||
repo: repo,
|
||||
userRepo: userRepo,
|
||||
userCommon: userCommon,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,9 +36,6 @@ func (s *AuthorSearch) Parse(dto *schema.SearchDTO) (ok bool) {
|
|||
p,
|
||||
me,
|
||||
name string
|
||||
user *entity.User
|
||||
has bool
|
||||
err error
|
||||
)
|
||||
exp = ""
|
||||
q = dto.Query
|
||||
|
@ -51,8 +47,7 @@ func (s *AuthorSearch) Parse(dto *schema.SearchDTO) (ok bool) {
|
|||
res := re.FindStringSubmatch(q)
|
||||
if len(res) == 2 {
|
||||
name = res[1]
|
||||
user, has, err = s.userRepo.GetByUsername(nil, name)
|
||||
|
||||
user, has, err := s.userCommon.GetUserBasicInfoByUserName(nil, name)
|
||||
if err == nil && has {
|
||||
exp = user.ID
|
||||
trimLen := len(res[0])
|
||||
|
|
|
@ -35,14 +35,14 @@ type SearchService struct {
|
|||
func NewSearchService(
|
||||
searchRepo search_common.SearchRepo,
|
||||
tagRepo tagcommon.TagRepo,
|
||||
userRepo usercommon.UserRepo,
|
||||
userCommon *usercommon.UserCommon,
|
||||
followCommon activity_common.FollowRepo,
|
||||
) *SearchService {
|
||||
return &SearchService{
|
||||
searchRepo: searchRepo,
|
||||
tagSearch: search.NewTagSearch(searchRepo, tagRepo, followCommon),
|
||||
withinSearch: search.NewWithinSearch(searchRepo),
|
||||
authorSearch: search.NewAuthorSearch(searchRepo, userRepo),
|
||||
authorSearch: search.NewAuthorSearch(searchRepo, userCommon),
|
||||
scoreSearch: search.NewScoreSearch(searchRepo),
|
||||
answersSearch: search.NewAnswersSearch(searchRepo),
|
||||
acceptedAnswerSearch: search.NewAcceptedAnswerSearch(searchRepo),
|
||||
|
|
|
@ -358,7 +358,7 @@ func (ts *TagService) GetTagWithPage(ctx context.Context, req *schema.GetTagWith
|
|||
UpdatedAt: tag.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
return pager.NewPageModel(page, pageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
||||
// checkTagIsFollow get tag list page
|
||||
|
|
|
@ -108,17 +108,17 @@ func (us *UserBackyardService) GetUserPage(ctx context.Context, req *schema.GetU
|
|||
Avatar: u.Avatar,
|
||||
}
|
||||
if u.Status == entity.UserStatusDeleted {
|
||||
t.Status = schema.Deleted
|
||||
t.Status = schema.UserDeleted
|
||||
t.DeletedAt = u.DeletedAt.Unix()
|
||||
} else if u.Status == entity.UserStatusSuspended {
|
||||
t.Status = schema.Suspended
|
||||
t.Status = schema.UserSuspended
|
||||
t.SuspendedAt = u.SuspendedAt.Unix()
|
||||
} else if u.MailStatus == entity.EmailStatusToBeVerified {
|
||||
t.Status = schema.Inactive
|
||||
t.Status = schema.UserInactive
|
||||
} else {
|
||||
t.Status = schema.Normal
|
||||
t.Status = schema.UserNormal
|
||||
}
|
||||
resp = append(resp, t)
|
||||
}
|
||||
return pager.NewPageModel(req.Page, req.PageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
|
|
@ -35,12 +35,12 @@ func NewUserCommon(userRepo UserRepo) *UserCommon {
|
|||
}
|
||||
|
||||
func (us *UserCommon) GetUserBasicInfoByID(ctx context.Context, ID string) (*schema.UserBasicInfo, bool, error) {
|
||||
dbInfo, has, err := us.userRepo.GetByUserID(ctx, ID)
|
||||
userInfo, exist, err := us.userRepo.GetByUserID(ctx, ID)
|
||||
if err != nil {
|
||||
return nil, has, err
|
||||
return nil, exist, err
|
||||
}
|
||||
info := us.UserBasicInfoFormat(ctx, dbInfo)
|
||||
return info, has, nil
|
||||
info := us.UserBasicInfoFormat(ctx, userInfo)
|
||||
return info, exist, nil
|
||||
}
|
||||
|
||||
func (us *UserCommon) GetUserBasicInfoByUserName(ctx context.Context, username string) (*schema.UserBasicInfo, bool, error) {
|
||||
|
@ -74,16 +74,20 @@ func (us *UserCommon) BatchUserBasicInfoByID(ctx context.Context, IDs []string)
|
|||
}
|
||||
|
||||
// UserBasicInfoFormat
|
||||
func (us *UserCommon) UserBasicInfoFormat(ctx context.Context, dbinfo *entity.User) *schema.UserBasicInfo {
|
||||
info := new(schema.UserBasicInfo)
|
||||
info.UserId = dbinfo.ID
|
||||
info.UserName = dbinfo.Username
|
||||
info.Rank = dbinfo.Rank
|
||||
info.DisplayName = dbinfo.DisplayName
|
||||
info.Avatar = dbinfo.Avatar
|
||||
info.Website = dbinfo.Website
|
||||
info.Location = dbinfo.Location
|
||||
info.IpInfo = dbinfo.IPInfo
|
||||
info.Status = dbinfo.Status
|
||||
return info
|
||||
func (us *UserCommon) UserBasicInfoFormat(ctx context.Context, userInfo *entity.User) *schema.UserBasicInfo {
|
||||
userBasicInfo := &schema.UserBasicInfo{}
|
||||
userBasicInfo.ID = userInfo.ID
|
||||
userBasicInfo.Username = userInfo.Username
|
||||
userBasicInfo.Rank = userInfo.Rank
|
||||
userBasicInfo.DisplayName = userInfo.DisplayName
|
||||
userBasicInfo.Avatar = userInfo.Avatar
|
||||
userBasicInfo.Website = userInfo.Website
|
||||
userBasicInfo.Location = userInfo.Location
|
||||
userBasicInfo.IpInfo = userInfo.IPInfo
|
||||
userBasicInfo.Status = schema.UserStatusShow[userInfo.Status]
|
||||
if userBasicInfo.Status == schema.UserDeleted {
|
||||
userBasicInfo.Avatar = ""
|
||||
userBasicInfo.DisplayName = "Anonymous"
|
||||
}
|
||||
return userBasicInfo
|
||||
}
|
||||
|
|
|
@ -97,5 +97,5 @@ func (us *UserGroupService) GetUserGroupWithPage(ctx context.Context, req *schem
|
|||
resp := &[]schema.GetUserGroupResp{}
|
||||
_ = copier.Copy(resp, userGroups)
|
||||
|
||||
return pager.NewPageModel(page, pageSize, total, resp), nil
|
||||
return pager.NewPageModel(total, resp), nil
|
||||
}
|
||||
|
|
|
@ -63,6 +63,25 @@ func (us *UserService) GetUserInfoByUserID(ctx context.Context, token, userID st
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// GetUserStatus get user info by user id
|
||||
func (us *UserService) GetUserStatus(ctx context.Context, userID string) (resp *schema.GetUserStatusResp, err error) {
|
||||
resp = &schema.GetUserStatusResp{}
|
||||
if len(userID) == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
userInfo, exist, err := us.userRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
resp = &schema.GetUserStatusResp{
|
||||
Status: schema.UserStatusShow[userInfo.Status],
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (us *UserService) GetOtherUserInfoByUsername(ctx context.Context, username string) (
|
||||
resp *schema.GetOtherUserInfoResp, err error) {
|
||||
userInfo, exist, err := us.userRepo.GetByUsername(ctx, username)
|
||||
|
|
|
@ -193,5 +193,5 @@ func (vs *VoteService) ListUserVotes(ctx context.Context, req schema.GetVoteWith
|
|||
resp = append(resp, item)
|
||||
}
|
||||
|
||||
return pager.NewPageModel(req.Page, req.PageSize, total, resp), err
|
||||
return pager.NewPageModel(total, resp), err
|
||||
}
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
package captcha
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"sync"
|
||||
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
var store base64Captcha.Store
|
||||
var once sync.Once
|
||||
|
||||
func NewCaptcha() {
|
||||
once.Do(func() {
|
||||
//var err error
|
||||
//RedisDb, err = arch.App.Cache.GetQuestion("cache")
|
||||
//if err != nil {
|
||||
// store = base64Captcha.DefaultMemStore
|
||||
// return
|
||||
//}
|
||||
//var ctx = context.Background()
|
||||
//_, err = RedisDb.Ping(ctx).Result()
|
||||
//
|
||||
//if err != nil {
|
||||
// store = base64Captcha.DefaultMemStore
|
||||
// return
|
||||
//}
|
||||
store = RedisStore{}
|
||||
})
|
||||
}
|
||||
|
||||
// CaptchaClient
|
||||
type CaptchaClient struct {
|
||||
}
|
||||
|
||||
// NewCaptchaClient
|
||||
func NewCaptchaClient() *CaptchaClient {
|
||||
return &CaptchaClient{}
|
||||
}
|
||||
|
||||
func MakeCaptcha() (id, b64s string, err error) {
|
||||
var driver base64Captcha.Driver
|
||||
//Configure the parameters of the CAPTCHA
|
||||
driverString := base64Captcha.DriverString{
|
||||
Height: 40,
|
||||
Width: 100,
|
||||
NoiseCount: 0,
|
||||
ShowLineOptions: 2 | 4,
|
||||
Length: 4,
|
||||
Source: "1234567890qwertyuioplkjhgfdsazxcvbnm",
|
||||
BgColor: &color.RGBA{R: 3, G: 102, B: 214, A: 125},
|
||||
Fonts: []string{"wqy-microhei.ttc"},
|
||||
}
|
||||
//ConvertFonts Load fonts by name
|
||||
driver = driverString.ConvertFonts()
|
||||
//Create Captcha
|
||||
captcha := base64Captcha.NewCaptcha(driver, store)
|
||||
//Generate
|
||||
id, b64s, err = captcha.Generate()
|
||||
return id, b64s, err
|
||||
|
||||
}
|
||||
|
||||
// VerifyCaptcha Verification code
|
||||
func VerifyCaptcha(id string, VerifyValue string) bool {
|
||||
fmt.Println(id, VerifyValue)
|
||||
if store.Verify(id, VerifyValue, true) {
|
||||
//verify successfully
|
||||
return true
|
||||
} else {
|
||||
//Verification failed
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package captcha
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/segmentfault/pacman/contrib/cache/memory"
|
||||
)
|
||||
|
||||
const CAPTCHA = "captcha:"
|
||||
|
||||
var RedisDb = memory.NewCache()
|
||||
|
||||
type RedisStore struct {
|
||||
}
|
||||
|
||||
func (r RedisStore) Set(id string, value string) error {
|
||||
key := CAPTCHA + id
|
||||
ctx := context.Background()
|
||||
err := RedisDb.SetString(ctx, key, value, 2)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r RedisStore) Get(id string, clear bool) string {
|
||||
key := CAPTCHA + id
|
||||
ctx := context.Background()
|
||||
val, err := RedisDb.GetString(ctx, key)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
if clear {
|
||||
err := RedisDb.Del(ctx, key)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (r RedisStore) Verify(id, answer string, clear bool) bool {
|
||||
v := RedisStore{}.Get(id, clear)
|
||||
fmt.Println("key:" + id + ";value:" + v + ";answer:" + answer)
|
||||
return v == answer
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
package email
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"text/template"
|
||||
|
||||
"github.com/jordan-wright/email"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
// EmailClient
|
||||
type EmailClient struct {
|
||||
email *email.Email
|
||||
config *Config
|
||||
}
|
||||
|
||||
// Config .
|
||||
type Config struct {
|
||||
WebName string `json:"web_name"`
|
||||
WebHost string `json:"web_host"`
|
||||
SecretKey string `json:"secret_key"`
|
||||
UserSessionKey string `json:"user_session_key"`
|
||||
EmailFrom string `json:"email_from"`
|
||||
EmailFromPass string `json:"email_from_pass"`
|
||||
EmailFromHostname string `json:"email_from_hostname"`
|
||||
EmailFromSMTP string `json:"email_from_smtp"`
|
||||
EmailFromName string `json:"email_from_name"`
|
||||
RegisterTitle string `json:"register_title"`
|
||||
RegisterBody string `json:"register_body"`
|
||||
PassResetTitle string `json:"pass_reset_title"`
|
||||
PassResetBody string `json:"pass_reset_body"`
|
||||
}
|
||||
|
||||
// NewEmailClient
|
||||
func NewEmailClient() *EmailClient {
|
||||
return &EmailClient{
|
||||
email: email.NewEmail(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EmailClient) Send(ToEmail, Title, Body string) {
|
||||
from := s.config.EmailFrom
|
||||
fromPass := s.config.EmailFromPass
|
||||
fromName := s.config.EmailFromName
|
||||
fromSmtp := s.config.EmailFromSMTP
|
||||
fromHostName := s.config.EmailFromHostname
|
||||
s.email.From = fmt.Sprintf("%s <%s>", fromName, from)
|
||||
s.email.To = []string{ToEmail}
|
||||
s.email.Subject = Title
|
||||
s.email.HTML = []byte(Body)
|
||||
err := s.email.Send(fromSmtp, smtp.PlainAuth("", from, fromPass, fromHostName))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EmailClient) RegisterTemplate(RegisterUrl string) (Title, Body string, err error) {
|
||||
webName := s.config.WebName
|
||||
templateData := RegisterTemplateData{webName, RegisterUrl}
|
||||
tmpl, err := template.New("register_title").Parse(s.config.RegisterTitle)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
title := new(bytes.Buffer)
|
||||
body := new(bytes.Buffer)
|
||||
err = tmpl.Execute(title, templateData)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
tmpl, err = template.New("register_body").Parse(s.config.RegisterBody)
|
||||
err = tmpl.Execute(body, templateData)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return title.String(), body.String(), nil
|
||||
}
|
||||
|
||||
func (s *EmailClient) PassResetTemplate(PassResetUrl string) (Title, Body string, err error) {
|
||||
webName := s.config.WebName
|
||||
templateData := PassResetTemplateData{webName, PassResetUrl}
|
||||
tmpl, err := template.New("pass_reset_title").Parse(s.config.PassResetTitle)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
title := new(bytes.Buffer)
|
||||
body := new(bytes.Buffer)
|
||||
err = tmpl.Execute(title, templateData)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
tmpl, err = template.New("pass_reset_body").Parse(s.config.PassResetBody)
|
||||
err = tmpl.Execute(body, templateData)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return title.String(), body.String(), nil
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package email
|
||||
|
||||
type RegisterTemplateData struct {
|
||||
SiteName string
|
||||
RegisterUrl string
|
||||
}
|
||||
|
||||
type PassResetTemplateData struct {
|
||||
SiteName string
|
||||
PassResetUrl string
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
if [ ! -f "/data/config.yaml" ]; then
|
||||
/usr/bin/answer init
|
||||
fi
|
||||
/usr/bin/answer run -c /data/config.yaml
|
|
@ -18,7 +18,7 @@ const Index: FC<Props> = ({
|
|||
}) => {
|
||||
return (
|
||||
<div className={`text-secondary ${className}`}>
|
||||
{data.status !== 'deleted' ? (
|
||||
{data?.status !== 'deleted' ? (
|
||||
<Link to={`/users/${data?.username}`}>
|
||||
{showAvatar && (
|
||||
<Avatar avatar={data?.avatar} size={avatarSize} className="me-1" />
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed build
|
||||
var Build embed.FS
|
|
@ -1,9 +0,0 @@
|
|||
package web
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed html/index.html
|
||||
var Html []byte
|
||||
|
||||
//go:embed html/static
|
||||
var Static embed.FS
|
Loading…
Reference in New Issue