merge from dev

pull/196/head
Michael Li 2 years ago
commit dfe59ab947
No known key found for this signature in database

@ -56,7 +56,7 @@ SmsJuhe:
Gateway: https://v.juhe.cn/sms/send
Key:
TplID:
TplVal: "#code#=%d&#m#=%d"
TplVal: "#code#=%s&#m#=%d"
Alipay:
AppID:
InProduction: True

@ -4,3 +4,4 @@
* [openapi](openapi): api相关文档
* [proposal](proposal): 开发/设计 提按相关文档
* [deploy](deploy): 部署相关文档
* [discuss](discuss): 开发者交流

@ -1,2 +1,9 @@
## 部署文档
TODO
本目录包含一些paopao-ce部署相关的帮助文档
* [core](./core) - paopao-ce部署帮助文档
* [aliyun](./aliyun) - Aliyun平台部署文档
* [huawei](./huawei) - Huawei Cloud平台部署文档
* [tencnet](./tencent) - Tencent Cloud平台部署文档
* [local](./local) - 本地部署文档
* [k8s](./k8s) - 使用Kubernetes部署paopao-ce相关文档

@ -0,0 +1,2 @@
### Aliyun平台部署文档
本目录包含一些阿里云平台部署paopao-ce的一些帮助文档。

@ -0,0 +1,95 @@
### 配置文件说明
paopao-ce使用YAML格式的`conf.yml`作为配置文件。[`config.yaml.sample`](../../../config.yaml.sample) 是一份完整的配置文件模版paopao-ce启动时会读取`./custom/config.yaml`、`./config.yaml`任意一份配置文件(优先读取最先找到的文件)。
```sh
cp config.yaml.sample config.yaml
vim config.yaml # 修改参数
paopao-ce
```
配置文件中的 `Features` 小节是声明paopao-ce运行时开启哪些功能项:
```yaml
...
Features:
Default: ["Base", "MySQL", "Option", "LocalOSS", "LoggerFile"]
Develop: ["Base", "MySQL", "Option", "Sms", "AliOSS", "LoggerZinc"]
Demo: ["Base", "MySQL", "Option", "Sms", "MinIO", "LoggerZinc"]
Slim: ["Base", "Sqlite3", "LocalOSS", "LoggerFile"]
Base: ["Zinc", "Redis", "Alipay",]
Option: ["SimpleCacheIndex"]
Sms: "SmsJuhe"
...
```
如上:
Default/Develop/Demo/Slim 是不同 功能集套件(Features Suite) Base/Option 是子功能套件, Sms是关于短信验证码功能的参数选项。
这里 `Default`套件 代表的意思是: 使用`Base/Option` 中的功能,外加 `MySQL/LocalOSS/LoggerFile`功能,也就是说开启了`Zinc/Redis/Alipay/SimpleCacheIndex/MySQL/LocalOSS/LoggerFile` 7项功能
`Develop`套件依例类推。
使用Feautures:
```sh
release/paopao-ce --help
Usage of release/paopao-ce:
-features value
use special features
-no-default-features
whether use default features
# 默认使用 Default 功能套件
release/paopao-ce
# 不包含 default 中的功能集,仅仅使用 develop 中声明的功能集
release/paopao-ce --no-default-features --features develop
# 使用 default 中的功能集,外加 sms 功能
release/paopao-ce --features sms
# 手动指定需要开启的功能集
release/paopao-ce --no-default-features --features sqlite3,localoss,loggerfile,redis
```
目前支持的功能集合:
| 功能项 | 类别 | 状态 | 备注 |
| ----- | ----- | ----- | ----- |
|`OldWeb` | 子服务 | 稳定(默认) | 开启旧的Web服务 |
|`Web` | 子服务 | WIP | 开启Web服务|
|`Admin` | 子服务 | WIP | 开启Admin后台运维服务|
|`SpaceX` | 子服务 | WIP | 开启SpaceX服务|
|`Bot` | 子服务 | WIP | 开启Bot服务|
|`NativeOBS` | 子服务 | WIP | 开启NativeOBS服务|
|`Deprecated:Web` | 子服务 | 稳定 | Deprecated(关闭) OldWeb服务|
|`Gorm` | 数据库 | 稳定(默认) | 使用[gorm](https://github.com/go-gorm/gorm)作为数据库的ORM默认使用 `Gorm` + `MySQL`组合|
|`Sqlx`| 数据库 | WIP | 使用[sqlx](https://github.com/jmoiron/sqlx)作为数据库的ORM|
|`MySQL`| 数据库 | 稳定(默认) | 使用MySQL作为数据库|
|`Postgres`| 数据库 | 稳定 | 使用PostgreSQL作为数据库|
|`Sqlite3`| 数据库 | 稳定 | 使用Sqlite3作为数据库|
|`AliOSS` | 对象存储 | 稳定(推荐) |阿里云对象存储服务|
|`COS` | 对象存储 | 内测 |腾讯云对象存储服务|
|`HuaweiOBS` | 对象存储 | 内测 |华为云对象存储服务|
|`MinIO` | 对象存储 | 稳定 |[MinIO](https://github.com/minio/minio)对象存储服务|
|`S3` | 对象存储 | 内测 |AWS S3兼容的对象存储服务|
|`LocalOSS` | 对象存储 | 内测 |提供使用本地目录文件作为对象存储的功能,仅用于开发调试环境|
|`OSS:Retention` | 对象存储 | 内测 |基于对象存储系统的对象过期自动删除特性实现 先创建临时对象再持久化的功能|
|`OSS:TempDir` | 对象存储 | 内测 |基于对象存储系统的对象拷贝/移动特性实现 先创建临时对象再持久化的功能|
|`Redis` | 缓存 | 稳定 | Redis缓存功能 |
|`SimpleCacheIndex` | 缓存 | 稳定 | 提供简单的 广场推文列表 的缓存功能 |
|`BigCacheIndex` | 缓存 | 稳定(推荐) | 使用[BigCache](https://github.com/allegro/bigcache)缓存 广场推文列表,缓存每个用户每一页,简单做到千人千面 |
|`Zinc` | 搜索 | 稳定(推荐) | 基于[Zinc](https://github.com/zinclabs/zinc)搜索引擎提供推文搜索服务 |
|`Meili` | 搜索 | 稳定(推荐) | 基于[Meilisearch](https://github.com/meilisearch/meilisearch)搜索引擎提供推文搜索服务 |
|`Bleve` | 搜索 | WIP | 基于[Bleve](https://github.com/blevesearch/bleve)搜索引擎提供推文搜索服务 |
|`LoggerFile` | 日志 | 稳定 | 使用文件写日志 |
|`LoggerZinc` | 日志 | 稳定(推荐) | 使用[Zinc](https://github.com/zinclabs/zinc)写日志 |
|`LoggerMeili` | 日志 | 内测 | 使用[Meilisearch](https://github.com/meilisearch/meilisearch)写日志 |
|`Friendship` | 关系模式 | 内测(默认) | 弱关系好友模式,类似微信朋友圈 |
|`Followship` | 关系模式 | WIP | 关注者模式类似Twitter的Follow模式 |
|`Alipay` | 支付 | 稳定 | 开启基于[支付宝开放平台](https://open.alipay.com/)的钱包功能 |
|`Sms` | 短信验证 | 稳定 | 开启短信验证码功能,用于手机绑定验证手机是否注册者的;功能如果没有开启,手机绑定时任意短信验证码都可以绑定手机 |
|`Docs:OpenAPI` | 开发文档 | 稳定 | 开启openapi文档功能提供web api文档说明(visit http://127.0.0.1:8008/docs/openapi) |
|`PhoneBind` | 其他 | 稳定 | 手机绑定功能 |
> 功能项状态详情参考 [features-status](../../../features-status.md).

@ -0,0 +1,4 @@
### paopao-ce部署帮助文档
本目录包含一些部署paopao-ce的一些帮助文档。
* [001-配置文件说明](./001-配置文件说明.md '001-配置文件说明')

@ -0,0 +1,2 @@
### Huawei Cloud平台部署文档
本目录包含一些华为云平台部署paopao-ce的一些帮助文档。

@ -0,0 +1,2 @@
### 使用Kubernetes部署paopao-ce相关文档
本目录包含一些k8s环境部署paopao-ce的一些帮助文档。

@ -0,0 +1,119 @@
### 本地开发依赖环境部署
本地开发依赖的环境部署帮助文档包括Zinc/Meili/Minio的部署。
#### [Zinc](https://github.com/zinclabs/zinc) 搜索引擎:
* Zinc运行
```sh
# 创建用于存放zinc数据的目录
mkdir -p data/zinc/data
# 使用Docker运行zinc
docker run -d --name zinc --user root -v ${PWD}/data/zinc/data:/data -p 4080:4080 -e ZINC_FIRST_ADMIN_USER=admin -e ZINC_FIRST_ADMIN_PASSWORD=admin -e DATA_PATH=/data public.ecr.aws/zinclabs/zinc:latest
# 查看zinc运行状态
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41465feea2ff getmeili/meilisearch:v0.27.0 "tini -- /bin/sh -c …" 20 hours ago Up 20 hours 0.0.0.0:7700->7700/tcp paopao-ce-meili-1
7daf982ca062 public.ecr.aws/prabhat/zinc:latest "/go/bin/zinc" 3 weeks ago Up 6 days 0.0.0.0:4080->4080/tcp zinc
# 使用docker compose运行
docker compose up -d zinc
# visit http://localhost:4080 打开自带的ui管理界面
```
* 修改Zinc配置
```yaml
# features中加上 Zinc 和 LoggerZinc
Features:
Default: ["Zinc", "LoggerZinc", "Base", "Sqlite3", "BigCacheIndex","MinIO"]
...
LoggerZinc: # 使用Zinc写日志
Host: 127.0.0.1:4080 # 这里的host就是paopao-ce能访问到的zinc主机
Index: paopao-log
User: admin
Password: admin
Secure: False # 如果使用https访问zinc就设置为True
...
Zinc: # Zinc搜索配置
Host: 127.0.0.1:4080
Index: paopao-data
User: admin
Password: admin
Secure: False
```
#### [Meilisearch](https://github.com/meilisearch/meilisearch) 搜索引擎:
* Meili运行
```sh
mkdir -p data/meili/data
# 使用Docker运行
docker run -d --name meili -v ${PWD}/data/meili/data:/meili_data -p 7700:7700 -e MEILI_MASTER_KEY=paopao-meilisearch getmeili/meilisearch:v0.29.0
# visit http://localhost:7700 打开自带的搜索前端ui
# 使用docker compose运行需要删除docker-compose.yaml中关于meili的注释
docker compose up -d meili
# 使用docker运行meilisearch的ui管理前端
docker run -d --name uirecord -p 7701:3000 bitriory/uirecord
# visit http://localhost:7701
# 使用docker compose运行meilisearch的ui管理前端需要删除docker-compose.yaml中关于uirecord的注释
docker compose up -d uirecord
# visit http://loclahost:7701
# 查看meili运行状态
docker compose ps
NAME COMMAND SERVICE STATUS PORTS
paopao-ce-meili-1 "tini -- /bin/sh -c …" meili running 0.0.0.0:7700->7700/tcp
paopao-ce-uirecord-1 "docker-entrypoint.s…" uirecord running 0.0.0.0:7701->3000/tcp
```
* 修改Meili配置
```yaml
# features中加上 Meili 和 LoggerMeili
Features:
Default: ["Meili", "LoggerMeili", "Base", "Sqlite3", "BigCacheIndex","MinIO"]
...
LoggerMeili: # 使用Meili写日志
Host: 127.0.0.1:7700
Index: paopao-log
ApiKey: paopao-meilisearch
Secure: False
MinWorker: 5 # 最小后台工作者, 设置范围[5, 100], 默认5
MaxLogBuffer: 100 # 最大log缓存条数, 设置范围[10, 10000], 默认100
...
Meili: # Meili搜索配置
Host: 127.0.0.1:7700 # 这里的host就是paopao-ce能访问到的meili主机
Index: paopao-data
ApiKey: paopao-meilisearch
Secure: False # 如果使用https访问meili就设置为True
```
#### [MinIO](https://github.com/minio/minio) 对象存储服务
* MinIO运行
```sh
mkdir -p data/minio/data
# 使用Docker运行
docker run -d --name minio -v ${PWD}/data/minio/data:/data -p 9000:9000 -p 9001:9001 -e MINIO_ROOT_USER=minio-root-user -e MINIO_ROOT_PASSWORD=minio-root-password -e MINIO_DEFAULT_BUCKETS=paopao:public bitnami/minio:latest
# 使用docker compose运行 需要删除docker-compose.yaml中关于minio的注释
docker compose up -d minio
```
* 修改Minio配置
```yaml
# features中加上 MinIO
Features:
Default: ["MinIO", "Meili", "LoggerMeili", "Base", "Sqlite3", "BigCacheIndex"]
...
MinIO: # MinIO 存储配置
AccessKey: Q3AM3UQ867SPQQA43P2F # AccessKey/SecretKey 需要登入minio管理界面手动创建管理界面地址: http://127.0.0.1:9001
SecretKey: zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG
Secure: False
Endpoint: 127.0.0.1:9000 # 根据部署的minio主机修改对应地址
Bucket: paopao # 如上需要在管理界面创建bucket并赋予外部可读写权限
Domain: 127.0.0.1:9000 # minio外网访问的地址(如果想让外网访问这里需要设置为外网可访问到的minio主机地址)
...
```

@ -0,0 +1,4 @@
### 本地部署文档
本目录包含一些本地开发环境部署paopao-ce的一些帮助文档。
* [001-本地开发依赖环境部署](001-本地开发依赖环境部署.md '001-本地开发依赖环境部署')

@ -0,0 +1,2 @@
### Tencent Cloud平台部署文档
本目录包含一些腾讯云平台部署paopao-ce的一些帮助文档。

@ -0,0 +1,26 @@
### <主题标题>
====== <这里写主题描述> =====
#### <话题标题>
====== <这里写话题描述> =====
* [北野](https://alimy.me) - 2022/12/14 10:07
> 这里就是你的观点论述了
* [北野](https://alimy.me) - 2022/12/14 10:07
> 这里就是你的观点论述了
* [北野](https://alimy.me) - 2022/12/14 10:07
> 这里就是你的观点论述了
* [北野](https://alimy.me) - 2022/12/14 10:07
> 这里就是你的观点论述了
* [北野](https://alimy.me) - 2022/12/14 10:07
> 这里就是你的回复
>> 这里就是你的观点论述了
* [北野](https://alimy.me) - 2022/12/14 10:07
> 你的回复
>> 这里就是你的回复
>>> 这里就是你的观点论述了

@ -0,0 +1,19 @@
### FAQs 常见问题
一些常见问题的解答。
#### 为什么要在代码库[docs](../../docs/)中写开发文档,比如[proposal](../proposal/)提按文档?
* [北野](https://alimy.me) - 2022/12/14 10:20
> 这里有几个原因
> * 开发文档跟随代码库对开发者友好;
> * paopao-ce的开发是离散组织式开发代码寄存在GitHub并没有一个统一的开发平台
> * 为什么没有使用GitHub的Wiki写档这个后续会把一些文档Copy到WiKi。
> * 文档跟随代码将更好的与代码共存而且Markdown足够用于写文档这才是最核心的怎么简单怎么来。
#### 为什么要在代码库[docs](../../docs/)中包含一个[discuss](../discuss/)?难道没有其他可用工具更好完成这种工作吗比瑞slack/discord
* [北野](https://alimy.me) - 2022/12/14 10:32
> discuss目录包含一些关于代码库开发的一些方案讨论偏静态内容代码库内置这些方案讨论也便于git进行跟踪归档。
> 确实有其他一些社交类开发聊天工具可用比如slack/discord但是目前paopao-ce的开发者社区还比较小暂时还没有开通的必要。
* [北野](https://alimy.me) - 2022/12/14 10:50
> 再一个国内访问也不是特别方便,暂时采用目前这种土办法过渡一下,或许后期会选择一个社交平台供开发者交流,比如飞书~

@ -0,0 +1,5 @@
### Discuss 开发者交流
本目录包含一些开发相关的问题交流论述。
* [0000-讨论样式模版](./0000-讨论样式模版.md "讨论样式模版")
* [0001-FAQs](./0001-FAQs.md "FAQs")

@ -5,6 +5,8 @@
package core
import (
"time"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
)
@ -19,7 +21,12 @@ type SecurityService interface {
SendPhoneCaptcha(phone string) error
}
// 附件检测服务
// AttachmentCheckService 附件检测服务
type AttachmentCheckService interface {
CheckAttachment(uri string) error
}
// PhoneVerifyService 手机验证服务
type PhoneVerifyService interface {
SendPhoneCaptcha(phone string, captcha string, expire time.Duration) error
}

@ -46,6 +46,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
v core.VersionInfo
)
db := conf.MustGormDB()
pvs := security.NewPhoneVerifyService()
i := newIndexPostsService(db)
if cfg.If("SimpleCacheIndex") {
@ -71,7 +72,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
CommentManageService: newCommentManageService(db),
UserManageService: newUserManageService(db),
ContactManageService: newContactManageService(db),
SecurityService: newSecurityService(db),
SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(),
}
return ds, ds

@ -5,18 +5,12 @@
package jinzhu
import (
"errors"
"fmt"
"math/rand"
"net/http"
"strconv"
"time"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
"github.com/rocboss/paopao-ce/pkg/json"
"gopkg.in/resty.v1"
"gorm.io/gorm"
)
@ -25,71 +19,46 @@ var (
)
type securityServant struct {
db *gorm.DB
db *gorm.DB
phoneVerify core.PhoneVerifyService
}
func newSecurityService(db *gorm.DB) core.SecurityService {
func newSecurityService(db *gorm.DB, phoneVerify core.PhoneVerifyService) core.SecurityService {
return &securityServant{
db: db,
db: db,
phoneVerify: phoneVerify,
}
}
type juhePhoneCaptchaRsp struct {
ErrorCode int `json:"error_code"`
Reason string `json:"reason"`
}
// 获取最新短信验证码
// GetLatestPhoneCaptcha 获取最新短信验证码
func (s *securityServant) GetLatestPhoneCaptcha(phone string) (*core.Captcha, error) {
return (&dbr.Captcha{
Phone: phone,
}).Get(s.db)
}
// 更新短信验证码
// UsePhoneCaptcha 更新短信验证码
func (s *securityServant) UsePhoneCaptcha(captcha *core.Captcha) error {
captcha.UseTimes++
return captcha.Update(s.db)
}
// 发送短信验证码
// SendPhoneCaptcha 发送短信验证码
func (s *securityServant) SendPhoneCaptcha(phone string) error {
rand.Seed(time.Now().UnixNano())
captcha := rand.Intn(900000) + 100000
m := 5
client := resty.New()
client.DisableWarn = true
resp, err := client.R().
SetFormData(map[string]string{
"mobile": phone,
"tpl_id": conf.SmsJuheSetting.TplID,
"tpl_value": fmt.Sprintf(conf.SmsJuheSetting.TplVal, captcha, m),
"key": conf.SmsJuheSetting.Key,
}).Post(conf.SmsJuheSetting.Gateway)
if err != nil {
return err
}
expire := time.Duration(5)
if resp.StatusCode() != http.StatusOK {
return errors.New(resp.Status())
}
result := &juhePhoneCaptchaRsp{}
err = json.Unmarshal(resp.Body(), result)
if err != nil {
// 发送验证码
rand.Seed(time.Now().UnixNano())
captcha := strconv.Itoa(rand.Intn(900000) + 100000)
if err := s.phoneVerify.SendPhoneCaptcha(phone, captcha, expire); err != nil {
return err
}
if result.ErrorCode != 0 {
return errors.New(result.Reason)
}
// 写入表
captchaModel := &dbr.Captcha{
Phone: phone,
Captcha: strconv.Itoa(captcha),
ExpiredOn: time.Now().Add(time.Minute * time.Duration(m)).Unix(),
Captcha: captcha,
ExpiredOn: time.Now().Add(expire * time.Minute).Unix(),
}
captchaModel.Create(s.db)
return nil

@ -12,6 +12,10 @@ import (
"github.com/rocboss/paopao-ce/internal/core"
)
var (
_ core.AttachmentCheckService = (*attachmentCheckServant)(nil)
)
type attachmentCheckServant struct {
domain string
}

@ -0,0 +1,66 @@
package security
import (
"errors"
"fmt"
"net/http"
"time"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/pkg/json"
"gopkg.in/resty.v1"
)
var (
_ core.PhoneVerifyService = (*juheSmsServant)(nil)
)
type juhePhoneCaptchaRsp struct {
ErrorCode int `json:"error_code"`
Reason string `json:"reason"`
}
type juheSmsServant struct {
gateway string
key string
tplID string
tplVal string
}
// SendPhoneCaptcha 发送短信验证码
func (s *juheSmsServant) SendPhoneCaptcha(phone string, captcha string, expire time.Duration) error {
client := resty.New()
client.DisableWarn = true
resp, err := client.R().
SetFormData(map[string]string{
"mobile": phone,
"tpl_id": s.tplID,
"tpl_value": fmt.Sprintf(s.tplVal, captcha, expire),
"key": s.key,
}).Post(s.gateway)
if err != nil {
return err
}
if resp.StatusCode() != http.StatusOK {
return errors.New(resp.Status())
}
result := &juhePhoneCaptchaRsp{}
if err = json.Unmarshal(resp.Body(), result); err != nil {
return err
}
if result.ErrorCode != 0 {
return errors.New(result.Reason)
}
return nil
}
func newJuheSmsServant() *juheSmsServant {
return &juheSmsServant{
gateway: conf.SmsJuheSetting.Gateway,
key: conf.SmsJuheSetting.Key,
tplID: conf.SmsJuheSetting.TplID,
tplVal: conf.SmsJuheSetting.TplVal,
}
}

@ -0,0 +1,18 @@
package security
import (
"strings"
"github.com/alimy/cfg"
"github.com/rocboss/paopao-ce/internal/core"
)
func NewPhoneVerifyService() core.PhoneVerifyService {
smsVendor, _ := cfg.Val("sms")
switch strings.ToLower(smsVendor) {
case "smsjuhe":
return newJuheSmsServant()
default:
return newJuheSmsServant()
}
}
Loading…
Cancel
Save