Merge pull request #198 from rocboss/feature/lightship

add Lightship feature support
pull/199/head
Michael Li 2 years ago committed by GitHub
commit c459ff997a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -328,8 +328,8 @@ release/paopao-ce --no-default-features --features sqlite3,localoss,loggerfile,r
|`Bot` | 子服务 | WIP | 开启Bot服务|
|`NativeOBS` | 子服务 | WIP | 开启NativeOBS服务|
|`Docs` | 子服务 | WIP | 开启开发者文档服务|
|`Frontend:Web` | 子服务 | 内测 | 开启独立前端服务|
|`Frontend:EmbedWeb` | 子服务 | 内测 | 开启内嵌于后端Web API服务中的前端服务|
|`Frontend:Web` | 子服务 | 稳定 | 开启独立前端服务|
|`Frontend:EmbedWeb` | 子服务 | 稳定 | 开启内嵌于后端Web API服务中的前端服务|
|`Deprecated:Web` | 子服务 | 稳定 | 开启旧的Web服务|
|`Gorm` | 数据库 | 稳定(默认) | 使用[gorm](https://github.com/go-gorm/gorm)作为数据库的ORM默认使用 `Gorm` + `MySQL`组合|
|`Sqlx`| 数据库 | WIP | 使用[sqlx](https://github.com/jmoiron/sqlx)作为数据库的ORM|
@ -345,7 +345,7 @@ release/paopao-ce --no-default-features --features sqlite3,localoss,loggerfile,r
|`OSS:Retention` | 对象存储 | 内测 |基于对象存储系统的对象过期自动删除特性实现 先创建临时对象再持久化的功能|
|`OSS:TempDir` | 对象存储 | 内测 |基于对象存储系统的对象拷贝/移动特性实现 先创建临时对象再持久化的功能|
|`Redis` | 缓存 | 稳定 | Redis缓存功能 |
|`SimpleCacheIndex` | 缓存 | 稳定 | 提供简单的 广场推文列表 的缓存功能 |
|`SimpleCacheIndex` | 缓存 | Deprecated | 提供简单的 广场推文列表 的缓存功能 |
|`BigCacheIndex` | 缓存 | 稳定(推荐) | 使用[BigCache](https://github.com/allegro/bigcache)缓存 广场推文列表,缓存每个用户每一页,简单做到千人千面 |
|`Zinc` | 搜索 | 稳定(推荐) | 基于[Zinc](https://github.com/zinclabs/zinc)搜索引擎提供推文搜索服务 |
|`Meili` | 搜索 | 稳定(推荐) | 基于[Meilisearch](https://github.com/meilisearch/meilisearch)搜索引擎提供推文搜索服务 |
@ -355,6 +355,7 @@ release/paopao-ce --no-default-features --features sqlite3,localoss,loggerfile,r
|`LoggerMeili` | 日志 | 内测 | 使用[Meilisearch](https://github.com/meilisearch/meilisearch)写日志 |
|`Friendship` | 关系模式 | 内测(默认) | 弱关系好友模式,类似微信朋友圈 |
|`Followship` | 关系模式 | WIP | 关注者模式类似Twitter的Follow模式 |
|`Lightship` | 关系模式 | 内测 | 开放模式,所有推文都公开可见 |
|`Alipay` | 支付 | 稳定 | 开启基于[支付宝开放平台](https://open.alipay.com/)的钱包功能 |
|`Sms` | 短信验证 | 稳定 | 开启短信验证码功能,用于手机绑定验证手机是否注册者的;功能如果没有开启,手机绑定时任意短信验证码都可以绑定手机 |
|`Docs:OpenAPI` | 开发文档 | 稳定 | 开启openapi文档功能提供web api文档说明(visit http://127.0.0.1:8008/docs/openapi) |

@ -3,7 +3,7 @@ paopao-ce roadmap.
### v0.2.0
* [x] add `Friendship` feature
* [ ] add `Lightship` feature
* [x] add `Lightship` feature
* [ ] add `Sqlx` feature
* [x] add new `Web` service
* [x] add `Frontend:Web` feature

@ -0,0 +1,46 @@
| 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 |
| ----- | ----- | ----- | ----- | ----- | ----- |
| 011| 北野 | 2022-12-14 | 2022-01-09 | v1.1 | 提议 |
### 关于Lightship功能项的设计
Lightship(开放模式)功能提供完全公开的推文分享服务,有别于[Friendship](002-关于Friendship功能项的设计.md "关于Friendship功能项的设计")、[Followship](003-关于Followship功能项的设计.md "关于Followship功能项的设计")使用Lightship用户模式部署paopao-ce用户发布的所有推文都是公开可访问的广场推文列表展示的是全站所有公开推文的Timeline Tweets。
### 场景
一般用于非常小的站点,或者推文更新不频繁的站点。
* 推文更新不频繁站点;
* 个人推文站点;
* 单纯想要所有推文公开访问;
### 需求
* 广场推文列表只展示公开可访问推文;
* 推文访问权限只能是 `公开/私密`
### 方案
#### 实现细节
* 广场推文列表只展示公开可访问推文 - 前端/后端
* 推文访问权限只能是 `公开/私密` - 前端/后端
#### 参考实现(PR):
[add Lightship feature support #198](https://github.com/rocboss/paopao-ce/pull/198)
### 疑问
1. 公开模式为什么命名为Lightship
Lightship有灯塔的意思灯塔是为航行船只指明方向的公共设施这里取其公有设施的属性指喻 开放模式下paopao-ce不需要授权公开访问推 文的意思。
1. 如何开启这个功能?
在配置文件config.yaml中的`Features`中添加`Lightship`功能项开启该功能:
```yaml
...
# features中加上 Lightship
Features:
Default: ["Meili", "LoggerMeili", "Base", "Sqlite3", "BigCacheIndex", "MinIO", "Lightship"]
Base: ["Redis", "PhoneBind"]
...
```
### 更新记录
#### v1.0(2022-12-14) - 北野
* 初始文档
#### v1.1(2022-01-09) - 北野
* 添加参考实现PR信息

@ -97,7 +97,7 @@
* [ ] 提按文档
* [x] 接口定义
* [x] 业务逻辑实现
* `SimpleCacheIndex` 提供简单的 广场推文列表 的缓存功能能;
* `SimpleCacheIndex` 提供简单的 广场推文列表 的缓存功能能(目前状态: Deprecated)
* [ ] 提按文档
* [x] 接口定义
* [x] 业务逻辑实现
@ -142,6 +142,10 @@
* [ ] 提按文档
* [ ] 接口定义
* [ ] 业务逻辑实现
* `Lightship` 开放模式,所有推文都公开可见(目前状态: WIP);
* [x] 提按文档
* [x] 接口定义
* [x] 业务逻辑实现
### 支付:
* `Alipay` 开启基于[支付宝开放平台](https://open.alipay.com/)的钱包功能;

@ -7,43 +7,41 @@ package jinzhu
import (
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
"github.com/rocboss/paopao-ce/pkg/debug"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
var (
_ core.IndexPostsService = (*indexPostsServant)(nil)
_ core.IndexPostsService = (*friendIndexServant)(nil)
_ core.IndexPostsService = (*followIndexServant)(nil)
_ core.IndexPostsService = (*lightIndexServant)(nil)
_ core.IndexPostsService = (*simpleIndexPostsServant)(nil)
)
type indexPostsServant struct {
type friendIndexServant struct {
ams core.AuthorizationManageService
ths core.TweetHelpService
db *gorm.DB
}
type simpleIndexPostsServant struct {
type followIndexServant struct {
ths core.TweetHelpService
db *gorm.DB
}
func newIndexPostsService(db *gorm.DB) core.IndexPostsService {
return &indexPostsServant{
ams: NewAuthorizationManageService(),
ths: newTweetHelpService(db),
db: db,
}
type lightIndexServant struct {
ths core.TweetHelpService
db *gorm.DB
}
func newSimpleIndexPostsService(db *gorm.DB) core.IndexPostsService {
return &simpleIndexPostsServant{
ths: newTweetHelpService(db),
db: db,
}
type simpleIndexPostsServant struct {
ths core.TweetHelpService
db *gorm.DB
}
// IndexPosts 根据userId查询广场推文列表简单做到不同用户的主页都是不同的
func (s *indexPostsServant) IndexPosts(user *core.User, offset int, limit int) (*core.IndexTweetList, error) {
func (s *friendIndexServant) IndexPosts(user *core.User, offset int, limit int) (*core.IndexTweetList, error) {
predicates := dbr.Predicates{
"ORDER": []any{"is_top DESC, latest_replied_on DESC"},
}
@ -77,6 +75,45 @@ func (s *indexPostsServant) IndexPosts(user *core.User, offset int, limit int) (
}, nil
}
// IndexPosts 根据userId查询广场推文列表
func (s *followIndexServant) IndexPosts(user *core.User, offset int, limit int) (*core.IndexTweetList, error) {
// TODO
return nil, debug.ErrNotImplemented
}
// IndexPosts 根据userId查询广场推文列表获取公开可见Tweet或者所属用户的私有Tweet
func (s *lightIndexServant) IndexPosts(user *core.User, offset int, limit int) (*core.IndexTweetList, error) {
predicates := dbr.Predicates{
"ORDER": []any{"is_top DESC, latest_replied_on DESC"},
}
if user == nil {
predicates["visibility = ?"] = []any{dbr.PostVisitPublic}
} else if !user.IsAdmin {
args := []any{dbr.PostVisitPublic, dbr.PostVisitPrivate, user.ID}
predicates["visibility = ? OR (visibility = ? AND user_id = ?)"] = args
}
posts, err := (&dbr.Post{}).Fetch(s.db, predicates, offset, limit)
if err != nil {
logrus.Debugf("gormIndexPostsServant.IndexPosts err: %v", err)
return nil, err
}
formatPosts, err := s.ths.MergePosts(posts)
if err != nil {
return nil, err
}
total, err := (&dbr.Post{}).CountBy(s.db, predicates)
if err != nil {
return nil, err
}
return &core.IndexTweetList{
Tweets: formatPosts,
Total: total,
}, nil
}
// simpleCacheIndexGetPosts simpleCacheIndex 专属获取广场推文列表函数
func (s *simpleIndexPostsServant) IndexPosts(_user *core.User, offset int, limit int) (*core.IndexTweetList, error) {
predicates := dbr.Predicates{
@ -105,3 +142,32 @@ func (s *simpleIndexPostsServant) IndexPosts(_user *core.User, offset int, limit
Total: total,
}, nil
}
func newFriendIndexService(db *gorm.DB, ams core.AuthorizationManageService, ths core.TweetHelpService) core.IndexPostsService {
return &friendIndexServant{
ams: ams,
ths: ths,
db: db,
}
}
func newFollowIndexService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService {
return &followIndexServant{
ths: ths,
db: db,
}
}
func newLightIndexService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService {
return &lightIndexServant{
ths: ths,
db: db,
}
}
func newSimpleIndexPostsService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService {
return &simpleIndexPostsServant{
ths: ths,
db: db,
}
}

@ -40,33 +40,48 @@ type dataServant struct {
}
func NewDataService() (core.DataService, core.VersionInfo) {
// initialize CacheIndex if needed
var (
c core.CacheIndexService
v core.VersionInfo
v core.VersionInfo
cis core.CacheIndexService
ips core.IndexPostsService
)
db := conf.MustGormDB()
pvs := security.NewPhoneVerifyService()
ams := NewAuthorizationManageService()
ths := newTweetHelpService(db)
i := newIndexPostsService(db)
// initialize core.IndexPostsService
if cfg.If("Friendship") {
ips = newFriendIndexService(db, ams, ths)
} else if cfg.If("Followship") {
ips = newFollowIndexService(db, ths)
} else if cfg.If("Lightship") {
ips = newLightIndexService(db, ths)
} else {
// default use lightship post index service
ips = newLightIndexService(db, ths)
}
// initialize core.CacheIndexService
if cfg.If("SimpleCacheIndex") {
i = newSimpleIndexPostsService(db)
c, v = cache.NewSimpleCacheIndexService(i)
// simpleCache use special post index service
ips = newSimpleIndexPostsService(db, ths)
cis, v = cache.NewSimpleCacheIndexService(ips)
} else if cfg.If("BigCacheIndex") {
a := newAuthorizationManageService(db)
c, v = cache.NewBigCacheIndexService(i, a)
// TODO: make cache index post in different scence like friendship/followship/lightship
cis, v = cache.NewBigCacheIndexService(ips, ams)
} else {
c, v = cache.NewNoneCacheIndexService(i)
cis, v = cache.NewNoneCacheIndexService(ips)
}
logrus.Infof("use %s as cache index service by version: %s", v.Name(), v.Version())
ds := &dataServant{
IndexPostsService: c,
IndexPostsService: cis,
WalletService: newWalletService(db),
MessageService: newMessageService(db),
TopicService: newTopicService(db),
TweetService: newTweetService(db),
TweetManageService: newTweetManageService(db, c),
TweetManageService: newTweetManageService(db, cis),
TweetHelpService: newTweetHelpService(db),
CommentService: newCommentService(db),
CommentManageService: newCommentManageService(db),

@ -0,0 +1,13 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package debug
import (
"errors"
)
var (
ErrNotImplemented = errors.New("not implemented")
)
Loading…
Cancel
Save